blob: 22988fbd444babc9d8d4ee15f331ad8ea01b5430 [file] [log] [blame]
Larry Finger94a79942011-08-23 19:00:42 -05001/* IEEE 802.11 SoftMAC layer
2 * Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it>
3 *
4 * Mostly extracted from the rtl8180-sa2400 driver for the
5 * in-kernel generic ieee802.11 stack.
6 *
7 * Some pieces of code might be stolen from ipw2100 driver
8 * copyright of who own it's copyright ;-)
9 *
10 * PS wx handler mostly stolen from hostap, copyright who
11 * own it's copyright ;-)
12 *
13 * released under the GPL
14 */
15
16
17#include "rtllib.h"
18#include "rtl_core.h"
Larry Finger94a79942011-08-23 19:00:42 -050019#include "dot11d.h"
Larry Finger94a79942011-08-23 19:00:42 -050020/* FIXME: add A freqs */
21
22const long rtllib_wlan_frequencies[] = {
23 2412, 2417, 2422, 2427,
24 2432, 2437, 2442, 2447,
25 2452, 2457, 2462, 2467,
26 2472, 2484
27};
28
29
30int rtllib_wx_set_freq(struct rtllib_device *ieee, struct iw_request_info *a,
31 union iwreq_data *wrqu, char *b)
32{
33 int ret;
Larry Fingera44be772011-08-25 11:48:27 -050034 struct iw_freq *fwrq = &wrqu->freq;
Larry Finger94a79942011-08-23 19:00:42 -050035
36 down(&ieee->wx_sem);
37
Larry Fingera44be772011-08-25 11:48:27 -050038 if (ieee->iw_mode == IW_MODE_INFRA) {
Larry Finger94a79942011-08-23 19:00:42 -050039 ret = 0;
40 goto out;
41 }
42
43 /* if setting by freq convert to channel */
44 if (fwrq->e == 1) {
45 if ((fwrq->m >= (int) 2.412e8 &&
46 fwrq->m <= (int) 2.487e8)) {
47 int f = fwrq->m / 100000;
48 int c = 0;
49
50 while ((c < 14) && (f != rtllib_wlan_frequencies[c]))
51 c++;
52
53 /* hack to fall through */
54 fwrq->e = 0;
55 fwrq->m = c + 1;
56 }
57 }
58
Larry Fingera44be772011-08-25 11:48:27 -050059 if (fwrq->e > 0 || fwrq->m > 14 || fwrq->m < 1) {
Larry Finger94a79942011-08-23 19:00:42 -050060 ret = -EOPNOTSUPP;
61 goto out;
62
Larry Fingera44be772011-08-25 11:48:27 -050063 } else { /* Set the channel */
Larry Finger94a79942011-08-23 19:00:42 -050064
Larry Finger94a79942011-08-23 19:00:42 -050065 if (ieee->active_channel_map[fwrq->m] != 1) {
66 ret = -EINVAL;
67 goto out;
68 }
Larry Finger94a79942011-08-23 19:00:42 -050069 ieee->current_network.channel = fwrq->m;
70 ieee->set_chan(ieee->dev, ieee->current_network.channel);
71
Larry Fingera44be772011-08-25 11:48:27 -050072 if (ieee->iw_mode == IW_MODE_ADHOC ||
73 ieee->iw_mode == IW_MODE_MASTER)
74 if (ieee->state == RTLLIB_LINKED) {
75 rtllib_stop_send_beacons(ieee);
76 rtllib_start_send_beacons(ieee);
Larry Finger94a79942011-08-23 19:00:42 -050077 }
78 }
79
80 ret = 0;
81out:
82 up(&ieee->wx_sem);
83 return ret;
84}
85
86
87int rtllib_wx_get_freq(struct rtllib_device *ieee,
88 struct iw_request_info *a,
89 union iwreq_data *wrqu, char *b)
90{
Larry Fingera44be772011-08-25 11:48:27 -050091 struct iw_freq *fwrq = &wrqu->freq;
Larry Finger94a79942011-08-23 19:00:42 -050092
93 if (ieee->current_network.channel == 0)
94 return -1;
Larry Fingera44be772011-08-25 11:48:27 -050095 fwrq->m = rtllib_wlan_frequencies[ieee->current_network.channel-1] *
96 100000;
Larry Finger94a79942011-08-23 19:00:42 -050097 fwrq->e = 1;
98 return 0;
99}
100
101int rtllib_wx_get_wap(struct rtllib_device *ieee,
102 struct iw_request_info *info,
103 union iwreq_data *wrqu, char *extra)
104{
105 unsigned long flags;
106
107 wrqu->ap_addr.sa_family = ARPHRD_ETHER;
108
109 if (ieee->iw_mode == IW_MODE_MONITOR)
110 return -1;
111
112 /* We want avoid to give to the user inconsistent infos*/
113 spin_lock_irqsave(&ieee->lock, flags);
114
115 if (ieee->state != RTLLIB_LINKED &&
116 ieee->state != RTLLIB_LINKED_SCANNING &&
117 ieee->wap_set == 0)
118
119 memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
120 else
121 memcpy(wrqu->ap_addr.sa_data,
122 ieee->current_network.bssid, ETH_ALEN);
123
124 spin_unlock_irqrestore(&ieee->lock, flags);
125
126 return 0;
127}
128
129
130int rtllib_wx_set_wap(struct rtllib_device *ieee,
131 struct iw_request_info *info,
132 union iwreq_data *awrq,
133 char *extra)
134{
135
136 int ret = 0;
Larry Fingera44be772011-08-25 11:48:27 -0500137 u8 zero[] = {0, 0, 0, 0, 0, 0};
Larry Finger94a79942011-08-23 19:00:42 -0500138 unsigned long flags;
139
140 short ifup = ieee->proto_started;
141 struct sockaddr *temp = (struct sockaddr *)awrq;
142
143 rtllib_stop_scan_syncro(ieee);
144
145 down(&ieee->wx_sem);
146 /* use ifconfig hw ether */
Larry Fingera44be772011-08-25 11:48:27 -0500147 if (ieee->iw_mode == IW_MODE_MASTER) {
Larry Finger94a79942011-08-23 19:00:42 -0500148 ret = -1;
149 goto out;
150 }
151
Larry Fingera44be772011-08-25 11:48:27 -0500152 if (temp->sa_family != ARPHRD_ETHER) {
Larry Finger94a79942011-08-23 19:00:42 -0500153 ret = -EINVAL;
154 goto out;
155 }
156
Larry Fingera44be772011-08-25 11:48:27 -0500157 if (memcmp(temp->sa_data, zero, ETH_ALEN) == 0) {
158 spin_lock_irqsave(&ieee->lock, flags);
159 memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN);
160 ieee->wap_set = 0;
161 spin_unlock_irqrestore(&ieee->lock, flags);
162 ret = -1;
163 goto out;
164 }
Larry Finger94a79942011-08-23 19:00:42 -0500165
166
167 if (ifup)
Larry Fingera44be772011-08-25 11:48:27 -0500168 rtllib_stop_protocol(ieee, true);
Larry Finger94a79942011-08-23 19:00:42 -0500169
170 /* just to avoid to give inconsistent infos in the
171 * get wx method. not really needed otherwise
172 */
173 spin_lock_irqsave(&ieee->lock, flags);
174
175 ieee->cannot_notify = false;
176 memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN);
Larry Fingera44be772011-08-25 11:48:27 -0500177 ieee->wap_set = (memcmp(temp->sa_data, zero, ETH_ALEN) != 0);
Larry Finger94a79942011-08-23 19:00:42 -0500178
179 spin_unlock_irqrestore(&ieee->lock, flags);
180
181 if (ifup)
182 rtllib_start_protocol(ieee);
183out:
184 up(&ieee->wx_sem);
185 return ret;
186}
187
Larry Fingera44be772011-08-25 11:48:27 -0500188int rtllib_wx_get_essid(struct rtllib_device *ieee, struct iw_request_info *a,
189 union iwreq_data *wrqu, char *b)
Larry Finger94a79942011-08-23 19:00:42 -0500190{
Larry Fingera44be772011-08-25 11:48:27 -0500191 int len, ret = 0;
Larry Finger94a79942011-08-23 19:00:42 -0500192 unsigned long flags;
193
194 if (ieee->iw_mode == IW_MODE_MONITOR)
195 return -1;
196
197 /* We want avoid to give to the user inconsistent infos*/
198 spin_lock_irqsave(&ieee->lock, flags);
199
200 if (ieee->current_network.ssid[0] == '\0' ||
Larry Fingera44be772011-08-25 11:48:27 -0500201 ieee->current_network.ssid_len == 0) {
Larry Finger94a79942011-08-23 19:00:42 -0500202 ret = -1;
203 goto out;
204 }
205
206 if (ieee->state != RTLLIB_LINKED &&
207 ieee->state != RTLLIB_LINKED_SCANNING &&
Larry Fingera44be772011-08-25 11:48:27 -0500208 ieee->ssid_set == 0) {
Larry Finger94a79942011-08-23 19:00:42 -0500209 ret = -1;
210 goto out;
211 }
212 len = ieee->current_network.ssid_len;
213 wrqu->essid.length = len;
Larry Fingera44be772011-08-25 11:48:27 -0500214 strncpy(b, ieee->current_network.ssid, len);
Larry Finger94a79942011-08-23 19:00:42 -0500215 wrqu->essid.flags = 1;
216
217out:
218 spin_unlock_irqrestore(&ieee->lock, flags);
219
220 return ret;
221
222}
223
224int rtllib_wx_set_rate(struct rtllib_device *ieee,
225 struct iw_request_info *info,
226 union iwreq_data *wrqu, char *extra)
227{
228
229 u32 target_rate = wrqu->bitrate.value;
230
231 ieee->rate = target_rate/100000;
232 return 0;
233}
234
235int rtllib_wx_get_rate(struct rtllib_device *ieee,
236 struct iw_request_info *info,
237 union iwreq_data *wrqu, char *extra)
238{
239 u32 tmp_rate = 0;
Larry Fingera44be772011-08-25 11:48:27 -0500240 tmp_rate = TxCountToDataRate(ieee,
241 ieee->softmac_stats.CurrentShowTxate);
Larry Finger94a79942011-08-23 19:00:42 -0500242 wrqu->bitrate.value = tmp_rate * 500000;
243
244 return 0;
245}
246
247
248int rtllib_wx_set_rts(struct rtllib_device *ieee,
249 struct iw_request_info *info,
250 union iwreq_data *wrqu, char *extra)
251{
252 if (wrqu->rts.disabled || !wrqu->rts.fixed)
253 ieee->rts = DEFAULT_RTS_THRESHOLD;
Larry Fingera44be772011-08-25 11:48:27 -0500254 else {
Larry Finger94a79942011-08-23 19:00:42 -0500255 if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
256 wrqu->rts.value > MAX_RTS_THRESHOLD)
257 return -EINVAL;
258 ieee->rts = wrqu->rts.value;
259 }
260 return 0;
261}
262
263int rtllib_wx_get_rts(struct rtllib_device *ieee,
264 struct iw_request_info *info,
265 union iwreq_data *wrqu, char *extra)
266{
267 wrqu->rts.value = ieee->rts;
268 wrqu->rts.fixed = 0; /* no auto select */
269 wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD);
270 return 0;
271}
272
273int rtllib_wx_set_mode(struct rtllib_device *ieee, struct iw_request_info *a,
274 union iwreq_data *wrqu, char *b)
275{
276 int set_mode_status = 0;
277
278 rtllib_stop_scan_syncro(ieee);
279 down(&ieee->wx_sem);
280 switch (wrqu->mode) {
281 case IW_MODE_MONITOR:
282 case IW_MODE_ADHOC:
283 case IW_MODE_INFRA:
284 break;
285 case IW_MODE_AUTO:
286 wrqu->mode = IW_MODE_INFRA;
287 break;
288 default:
289 set_mode_status = -EINVAL;
290 goto out;
291 }
292
293 if (wrqu->mode == ieee->iw_mode)
294 goto out;
295
296 if (wrqu->mode == IW_MODE_MONITOR) {
Larry Finger94a79942011-08-23 19:00:42 -0500297 ieee->dev->type = ARPHRD_IEEE80211;
Larry Fingera44be772011-08-25 11:48:27 -0500298 rtllib_EnableNetMonitorMode(ieee->dev, false);
Larry Finger94a79942011-08-23 19:00:42 -0500299 } else {
300 ieee->dev->type = ARPHRD_ETHER;
301 if (ieee->iw_mode == IW_MODE_MONITOR)
Larry Fingera44be772011-08-25 11:48:27 -0500302 rtllib_DisableNetMonitorMode(ieee->dev, false);
Larry Finger94a79942011-08-23 19:00:42 -0500303 }
304
305 if (!ieee->proto_started) {
306 ieee->iw_mode = wrqu->mode;
307 } else {
Larry Fingera44be772011-08-25 11:48:27 -0500308 rtllib_stop_protocol(ieee, true);
Larry Finger94a79942011-08-23 19:00:42 -0500309 ieee->iw_mode = wrqu->mode;
310 rtllib_start_protocol(ieee);
311 }
312
313out:
314 up(&ieee->wx_sem);
315 return set_mode_status;
316}
317
318void rtllib_wx_sync_scan_wq(void *data)
319{
Larry Fingera44be772011-08-25 11:48:27 -0500320 struct rtllib_device *ieee = container_of_work_rsl(data,
321 struct rtllib_device, wx_sync_scan_wq);
Larry Finger94a79942011-08-23 19:00:42 -0500322 short chan;
Larry Fingera44be772011-08-25 11:48:27 -0500323 enum ht_extchnl_offset chan_offset = 0;
324 enum ht_channel_width bandwidth = 0;
Larry Finger94a79942011-08-23 19:00:42 -0500325 int b40M = 0;
Larry Fingera44be772011-08-25 11:48:27 -0500326 static int count;
Larry Finger94a79942011-08-23 19:00:42 -0500327
Larry Fingera44be772011-08-25 11:48:27 -0500328 if (!(ieee->softmac_features & IEEE_SOFTMAC_SCAN)) {
Larry Finger94a79942011-08-23 19:00:42 -0500329 rtllib_start_scan_syncro(ieee, 0);
330 goto out;
331 }
332
333 chan = ieee->current_network.channel;
334
335 if (ieee->LeisurePSLeave)
336 ieee->LeisurePSLeave(ieee->dev);
337 /* notify AP to be in PS mode */
338 rtllib_sta_ps_send_null_frame(ieee, 1);
339 rtllib_sta_ps_send_null_frame(ieee, 1);
340
341 rtllib_stop_all_queues(ieee);
342
343 if (ieee->data_hard_stop)
344 ieee->data_hard_stop(ieee->dev);
345 rtllib_stop_send_beacons(ieee);
346 ieee->state = RTLLIB_LINKED_SCANNING;
347 ieee->link_change(ieee->dev);
348 /* wait for ps packet to be kicked out successfully */
349 msleep(50);
350
351 if (ieee->ScanOperationBackupHandler)
Larry Fingera44be772011-08-25 11:48:27 -0500352 ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_BACKUP);
Larry Finger94a79942011-08-23 19:00:42 -0500353
Larry Fingera44be772011-08-25 11:48:27 -0500354 if (ieee->pHTInfo->bCurrentHTSupport && ieee->pHTInfo->bEnableHT &&
355 ieee->pHTInfo->bCurBW40MHz) {
Larry Finger94a79942011-08-23 19:00:42 -0500356 b40M = 1;
357 chan_offset = ieee->pHTInfo->CurSTAExtChnlOffset;
Larry Finger6e579112011-07-19 18:20:30 -0500358 bandwidth = (enum ht_channel_width)ieee->pHTInfo->bCurBW40MHz;
Larry Fingera44be772011-08-25 11:48:27 -0500359 RT_TRACE(COMP_DBG, "Scan in 40M, force to 20M first:%d, %d\n",
360 chan_offset, bandwidth);
361 ieee->SetBWModeHandler(ieee->dev, HT_CHANNEL_WIDTH_20,
362 HT_EXTCHNL_OFFSET_NO_EXT);
363 }
Larry Finger94a79942011-08-23 19:00:42 -0500364
365 rtllib_start_scan_syncro(ieee, 0);
366
367 if (b40M) {
368 RT_TRACE(COMP_DBG, "Scan in 20M, back to 40M\n");
369 if (chan_offset == HT_EXTCHNL_OFFSET_UPPER)
370 ieee->set_chan(ieee->dev, chan + 2);
371 else if (chan_offset == HT_EXTCHNL_OFFSET_LOWER)
372 ieee->set_chan(ieee->dev, chan - 2);
373 else
374 ieee->set_chan(ieee->dev, chan);
375 ieee->SetBWModeHandler(ieee->dev, bandwidth, chan_offset);
376 } else {
377 ieee->set_chan(ieee->dev, chan);
378 }
379
380 if (ieee->ScanOperationBackupHandler)
Larry Fingera44be772011-08-25 11:48:27 -0500381 ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_RESTORE);
Larry Finger94a79942011-08-23 19:00:42 -0500382
383 ieee->state = RTLLIB_LINKED;
384 ieee->link_change(ieee->dev);
385
386 /* Notify AP that I wake up again */
387 rtllib_sta_ps_send_null_frame(ieee, 0);
388
389 if (ieee->LinkDetectInfo.NumRecvBcnInPeriod == 0 ||
Larry Fingera44be772011-08-25 11:48:27 -0500390 ieee->LinkDetectInfo.NumRecvDataInPeriod == 0) {
Larry Finger94a79942011-08-23 19:00:42 -0500391 ieee->LinkDetectInfo.NumRecvBcnInPeriod = 1;
Larry Fingera44be772011-08-25 11:48:27 -0500392 ieee->LinkDetectInfo.NumRecvDataInPeriod = 1;
Larry Finger94a79942011-08-23 19:00:42 -0500393 }
394
395 if (ieee->data_hard_resume)
396 ieee->data_hard_resume(ieee->dev);
397
398 if (ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER)
399 rtllib_start_send_beacons(ieee);
400
401 rtllib_wake_all_queues(ieee);
402
403 count = 0;
404out:
405 up(&ieee->wx_sem);
406
407}
408
409int rtllib_wx_set_scan(struct rtllib_device *ieee, struct iw_request_info *a,
410 union iwreq_data *wrqu, char *b)
411{
412 int ret = 0;
413
414 down(&ieee->wx_sem);
415
Larry Fingera44be772011-08-25 11:48:27 -0500416 if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)) {
Larry Finger94a79942011-08-23 19:00:42 -0500417 ret = -1;
418 goto out;
419 }
420
Larry Fingera44be772011-08-25 11:48:27 -0500421 if (ieee->state == RTLLIB_LINKED) {
Larry Finger94a79942011-08-23 19:00:42 -0500422 queue_work_rsl(ieee->wq, &ieee->wx_sync_scan_wq);
423 /* intentionally forget to up sem */
424 return 0;
425 }
426
427out:
428 up(&ieee->wx_sem);
429 return ret;
430}
431
432int rtllib_wx_set_essid(struct rtllib_device *ieee,
Larry Fingera44be772011-08-25 11:48:27 -0500433 struct iw_request_info *a,
434 union iwreq_data *wrqu, char *extra)
Larry Finger94a79942011-08-23 19:00:42 -0500435{
436
Larry Fingera44be772011-08-25 11:48:27 -0500437 int ret = 0, len, i;
Larry Finger94a79942011-08-23 19:00:42 -0500438 short proto_started;
439 unsigned long flags;
440
441 rtllib_stop_scan_syncro(ieee);
442 down(&ieee->wx_sem);
443
444 proto_started = ieee->proto_started;
445
Larry Fingera44be772011-08-25 11:48:27 -0500446 len = (wrqu->essid.length < IW_ESSID_MAX_SIZE) ? wrqu->essid.length :
447 IW_ESSID_MAX_SIZE;
Larry Finger94a79942011-08-23 19:00:42 -0500448
Larry Fingera44be772011-08-25 11:48:27 -0500449 if (len > IW_ESSID_MAX_SIZE) {
450 ret = -E2BIG;
Larry Finger94a79942011-08-23 19:00:42 -0500451 goto out;
452 }
453
Larry Fingera44be772011-08-25 11:48:27 -0500454 if (ieee->iw_mode == IW_MODE_MONITOR) {
455 ret = -1;
Larry Finger94a79942011-08-23 19:00:42 -0500456 goto out;
457 }
458
Larry Fingera44be772011-08-25 11:48:27 -0500459 for (i = 0; i < len; i++) {
460 if (extra[i] < 0) {
461 ret = -1;
Larry Finger94a79942011-08-23 19:00:42 -0500462 goto out;
463 }
464 }
465
466 if (proto_started)
Larry Fingera44be772011-08-25 11:48:27 -0500467 rtllib_stop_protocol(ieee, true);
Larry Finger94a79942011-08-23 19:00:42 -0500468
469
470 /* this is just to be sure that the GET wx callback
471 * has consisten infos. not needed otherwise
472 */
473 spin_lock_irqsave(&ieee->lock, flags);
474
475 if (wrqu->essid.flags && wrqu->essid.length) {
476 strncpy(ieee->current_network.ssid, extra, len);
477 ieee->current_network.ssid_len = len;
478 ieee->cannot_notify = false;
479 ieee->ssid_set = 1;
Larry Fingera44be772011-08-25 11:48:27 -0500480 } else {
Larry Finger94a79942011-08-23 19:00:42 -0500481 ieee->ssid_set = 0;
482 ieee->current_network.ssid[0] = '\0';
483 ieee->current_network.ssid_len = 0;
484 }
485 spin_unlock_irqrestore(&ieee->lock, flags);
486
487 if (proto_started)
488 rtllib_start_protocol(ieee);
489out:
490 up(&ieee->wx_sem);
491 return ret;
492}
493
Larry Fingera44be772011-08-25 11:48:27 -0500494int rtllib_wx_get_mode(struct rtllib_device *ieee, struct iw_request_info *a,
495 union iwreq_data *wrqu, char *b)
Larry Finger94a79942011-08-23 19:00:42 -0500496{
497 wrqu->mode = ieee->iw_mode;
498 return 0;
499}
500
Larry Fingera44be772011-08-25 11:48:27 -0500501int rtllib_wx_set_rawtx(struct rtllib_device *ieee,
502 struct iw_request_info *info,
503 union iwreq_data *wrqu, char *extra)
Larry Finger94a79942011-08-23 19:00:42 -0500504{
505
506 int *parms = (int *)extra;
507 int enable = (parms[0] > 0);
508 short prev = ieee->raw_tx;
509
510 down(&ieee->wx_sem);
511
512 if (enable)
513 ieee->raw_tx = 1;
514 else
515 ieee->raw_tx = 0;
516
517 printk(KERN_INFO"raw TX is %s\n",
518 ieee->raw_tx ? "enabled" : "disabled");
519
Larry Fingera44be772011-08-25 11:48:27 -0500520 if (ieee->iw_mode == IW_MODE_MONITOR) {
521 if (prev == 0 && ieee->raw_tx) {
Larry Finger94a79942011-08-23 19:00:42 -0500522 if (ieee->data_hard_resume)
523 ieee->data_hard_resume(ieee->dev);
524
525 netif_carrier_on(ieee->dev);
526 }
527
528 if (prev && ieee->raw_tx == 1)
529 netif_carrier_off(ieee->dev);
530 }
531
532 up(&ieee->wx_sem);
533
534 return 0;
535}
536
537int rtllib_wx_get_name(struct rtllib_device *ieee,
538 struct iw_request_info *info,
539 union iwreq_data *wrqu, char *extra)
540{
541 strcpy(wrqu->name, "802.11");
542
543 if (ieee->modulation & RTLLIB_CCK_MODULATION)
544 strcat(wrqu->name, "b");
545 if (ieee->modulation & RTLLIB_OFDM_MODULATION)
546 strcat(wrqu->name, "g");
547 if (ieee->mode & (IEEE_N_24G | IEEE_N_5G))
548 strcat(wrqu->name, "n");
549 return 0;
550}
551
552
553/* this is mostly stolen from hostap */
554int rtllib_wx_set_power(struct rtllib_device *ieee,
555 struct iw_request_info *info,
556 union iwreq_data *wrqu, char *extra)
557{
558 int ret = 0;
Mike McCormack4f6807e2011-07-11 08:56:20 +0900559
Larry Fingera44be772011-08-25 11:48:27 -0500560 if ((!ieee->sta_wake_up) ||
561 (!ieee->enter_sleep_state) ||
562 (!ieee->ps_is_queue_empty)) {
563 RTLLIB_DEBUG(RTLLIB_DL_ERR, "%s(): PS mode is tryied to be use "
564 "but driver missed a callback\n\n", __func__);
Larry Finger94a79942011-08-23 19:00:42 -0500565 return -1;
566 }
Mike McCormack4f6807e2011-07-11 08:56:20 +0900567
Larry Finger94a79942011-08-23 19:00:42 -0500568 down(&ieee->wx_sem);
569
Larry Fingera44be772011-08-25 11:48:27 -0500570 if (wrqu->power.disabled) {
571 RT_TRACE(COMP_DBG, "===>%s(): power disable\n", __func__);
Larry Finger94a79942011-08-23 19:00:42 -0500572 ieee->ps = RTLLIB_PS_DISABLED;
573 goto exit;
574 }
575 if (wrqu->power.flags & IW_POWER_TIMEOUT) {
576 ieee->ps_timeout = wrqu->power.value / 1000;
Larry Fingera44be772011-08-25 11:48:27 -0500577 RT_TRACE(COMP_DBG, "===>%s():ps_timeout is %d\n", __func__,
578 ieee->ps_timeout);
Larry Finger94a79942011-08-23 19:00:42 -0500579 }
580
Larry Fingera44be772011-08-25 11:48:27 -0500581 if (wrqu->power.flags & IW_POWER_PERIOD)
Larry Finger94a79942011-08-23 19:00:42 -0500582 ieee->ps_period = wrqu->power.value / 1000;
583
Larry Finger94a79942011-08-23 19:00:42 -0500584 switch (wrqu->power.flags & IW_POWER_MODE) {
585 case IW_POWER_UNICAST_R:
586 ieee->ps = RTLLIB_PS_UNICAST;
587 break;
588 case IW_POWER_MULTICAST_R:
589 ieee->ps = RTLLIB_PS_MBCAST;
590 break;
591 case IW_POWER_ALL_R:
592 ieee->ps = RTLLIB_PS_UNICAST | RTLLIB_PS_MBCAST;
593 break;
594
595 case IW_POWER_ON:
596 break;
597
598 default:
599 ret = -EINVAL;
600 goto exit;
601
602 }
603exit:
604 up(&ieee->wx_sem);
605 return ret;
606
607}
608
609/* this is stolen from hostap */
610int rtllib_wx_get_power(struct rtllib_device *ieee,
611 struct iw_request_info *info,
612 union iwreq_data *wrqu, char *extra)
613{
Larry Fingera44be772011-08-25 11:48:27 -0500614 int ret = 0;
Larry Finger94a79942011-08-23 19:00:42 -0500615
616 down(&ieee->wx_sem);
617
618 if (ieee->ps == RTLLIB_PS_DISABLED) {
619 wrqu->power.disabled = 1;
620 goto exit;
621 }
622
623 wrqu->power.disabled = 0;
624
625 if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
626 wrqu->power.flags = IW_POWER_TIMEOUT;
627 wrqu->power.value = ieee->ps_timeout * 1000;
628 } else {
629 wrqu->power.flags = IW_POWER_PERIOD;
630 wrqu->power.value = ieee->ps_period * 1000;
631 }
632
Larry Fingera44be772011-08-25 11:48:27 -0500633 if ((ieee->ps & (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST)) ==
634 (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST))
Larry Finger94a79942011-08-23 19:00:42 -0500635 wrqu->power.flags |= IW_POWER_ALL_R;
636 else if (ieee->ps & RTLLIB_PS_MBCAST)
637 wrqu->power.flags |= IW_POWER_MULTICAST_R;
638 else
639 wrqu->power.flags |= IW_POWER_UNICAST_R;
640
641exit:
642 up(&ieee->wx_sem);
643 return ret;
644
645}