1 // SPDX-License-Identifier: GPL-2.0
2 /* IEEE 802.11 SoftMAC layer
3 * Copyright (c) 2005 Andrea Merello <andrea.merello@gmail.com>
4 *
5 * Mostly extracted from the rtl8180-sa2400 driver for the
6 * in-kernel generic ieee802.11 stack.
7 *
8 * Some pieces of code might be stolen from ipw2100 driver
9 * copyright of who own it's copyright ;-)
10 *
11 * PS wx handler mostly stolen from hostap, copyright who
12 * own it's copyright ;-)
13 */
14 #include <linux/etherdevice.h>
15
16 #include "rtllib.h"
17 #include "dot11d.h"
18 /* FIXME: add A freqs */
19
20 const long rtllib_wlan_frequencies[] = {
21 2412, 2417, 2422, 2427,
22 2432, 2437, 2442, 2447,
23 2452, 2457, 2462, 2467,
24 2472, 2484
25 };
26 EXPORT_SYMBOL(rtllib_wlan_frequencies);
27
28
rtllib_wx_set_freq(struct rtllib_device * ieee,struct iw_request_info * a,union iwreq_data * wrqu,char * b)29 int rtllib_wx_set_freq(struct rtllib_device *ieee, struct iw_request_info *a,
30 union iwreq_data *wrqu, char *b)
31 {
32 int ret;
33 struct iw_freq *fwrq = &wrqu->freq;
34
35 mutex_lock(&ieee->wx_mutex);
36
37 if (ieee->iw_mode == IW_MODE_INFRA) {
38 ret = 0;
39 goto out;
40 }
41
42 /* if setting by freq convert to channel */
43 if (fwrq->e == 1) {
44 if ((fwrq->m >= (int) 2.412e8 &&
45 fwrq->m <= (int) 2.487e8)) {
46 int f = fwrq->m / 100000;
47 int c = 0;
48
49 while ((c < 14) && (f != rtllib_wlan_frequencies[c]))
50 c++;
51
52 /* hack to fall through */
53 fwrq->e = 0;
54 fwrq->m = c + 1;
55 }
56 }
57
58 if (fwrq->e > 0 || fwrq->m > 14 || fwrq->m < 1) {
59 ret = -EOPNOTSUPP;
60 goto out;
61
62 } else { /* Set the channel */
63
64 if (ieee->active_channel_map[fwrq->m] != 1) {
65 ret = -EINVAL;
66 goto out;
67 }
68 ieee->current_network.channel = fwrq->m;
69 ieee->set_chan(ieee->dev, ieee->current_network.channel);
70
71 if (ieee->iw_mode == IW_MODE_ADHOC ||
72 ieee->iw_mode == IW_MODE_MASTER)
73 if (ieee->state == RTLLIB_LINKED) {
74 rtllib_stop_send_beacons(ieee);
75 rtllib_start_send_beacons(ieee);
76 }
77 }
78
79 ret = 0;
80 out:
81 mutex_unlock(&ieee->wx_mutex);
82 return ret;
83 }
84 EXPORT_SYMBOL(rtllib_wx_set_freq);
85
86
rtllib_wx_get_freq(struct rtllib_device * ieee,struct iw_request_info * a,union iwreq_data * wrqu,char * b)87 int rtllib_wx_get_freq(struct rtllib_device *ieee,
88 struct iw_request_info *a,
89 union iwreq_data *wrqu, char *b)
90 {
91 struct iw_freq *fwrq = &wrqu->freq;
92
93 if (ieee->current_network.channel == 0)
94 return -1;
95 fwrq->m = rtllib_wlan_frequencies[ieee->current_network.channel-1] *
96 100000;
97 fwrq->e = 1;
98 return 0;
99 }
100 EXPORT_SYMBOL(rtllib_wx_get_freq);
101
rtllib_wx_get_wap(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)102 int rtllib_wx_get_wap(struct rtllib_device *ieee,
103 struct iw_request_info *info,
104 union iwreq_data *wrqu, char *extra)
105 {
106 unsigned long flags;
107
108 wrqu->ap_addr.sa_family = ARPHRD_ETHER;
109
110 if (ieee->iw_mode == IW_MODE_MONITOR)
111 return -1;
112
113 /* We want avoid to give to the user inconsistent infos*/
114 spin_lock_irqsave(&ieee->lock, flags);
115
116 if (ieee->state != RTLLIB_LINKED &&
117 ieee->state != RTLLIB_LINKED_SCANNING &&
118 ieee->wap_set == 0)
119
120 eth_zero_addr(wrqu->ap_addr.sa_data);
121 else
122 memcpy(wrqu->ap_addr.sa_data,
123 ieee->current_network.bssid, ETH_ALEN);
124
125 spin_unlock_irqrestore(&ieee->lock, flags);
126
127 return 0;
128 }
129 EXPORT_SYMBOL(rtllib_wx_get_wap);
130
131
rtllib_wx_set_wap(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * awrq,char * extra)132 int rtllib_wx_set_wap(struct rtllib_device *ieee,
133 struct iw_request_info *info,
134 union iwreq_data *awrq,
135 char *extra)
136 {
137
138 int ret = 0;
139 unsigned long flags;
140
141 short ifup = ieee->proto_started;
142 struct sockaddr *temp = (struct sockaddr *)awrq;
143
144 rtllib_stop_scan_syncro(ieee);
145
146 mutex_lock(&ieee->wx_mutex);
147 /* use ifconfig hw ether */
148 if (ieee->iw_mode == IW_MODE_MASTER) {
149 ret = -1;
150 goto out;
151 }
152
153 if (temp->sa_family != ARPHRD_ETHER) {
154 ret = -EINVAL;
155 goto out;
156 }
157
158 if (is_zero_ether_addr(temp->sa_data)) {
159 spin_lock_irqsave(&ieee->lock, flags);
160 ether_addr_copy(ieee->current_network.bssid, temp->sa_data);
161 ieee->wap_set = 0;
162 spin_unlock_irqrestore(&ieee->lock, flags);
163 ret = -1;
164 goto out;
165 }
166
167
168 if (ifup)
169 rtllib_stop_protocol(ieee, true);
170
171 /* just to avoid to give inconsistent infos in the
172 * get wx method. not really needed otherwise
173 */
174 spin_lock_irqsave(&ieee->lock, flags);
175
176 ieee->cannot_notify = false;
177 ether_addr_copy(ieee->current_network.bssid, temp->sa_data);
178 ieee->wap_set = !is_zero_ether_addr(temp->sa_data);
179
180 spin_unlock_irqrestore(&ieee->lock, flags);
181
182 if (ifup)
183 rtllib_start_protocol(ieee);
184 out:
185 mutex_unlock(&ieee->wx_mutex);
186 return ret;
187 }
188 EXPORT_SYMBOL(rtllib_wx_set_wap);
189
rtllib_wx_get_essid(struct rtllib_device * ieee,struct iw_request_info * a,union iwreq_data * wrqu,char * b)190 int rtllib_wx_get_essid(struct rtllib_device *ieee, struct iw_request_info *a,
191 union iwreq_data *wrqu, char *b)
192 {
193 int len, ret = 0;
194 unsigned long flags;
195
196 if (ieee->iw_mode == IW_MODE_MONITOR)
197 return -1;
198
199 /* We want avoid to give to the user inconsistent infos*/
200 spin_lock_irqsave(&ieee->lock, flags);
201
202 if (ieee->current_network.ssid[0] == '\0' ||
203 ieee->current_network.ssid_len == 0) {
204 ret = -1;
205 goto out;
206 }
207
208 if (ieee->state != RTLLIB_LINKED &&
209 ieee->state != RTLLIB_LINKED_SCANNING &&
210 ieee->ssid_set == 0) {
211 ret = -1;
212 goto out;
213 }
214 len = ieee->current_network.ssid_len;
215 wrqu->essid.length = len;
216 strncpy(b, ieee->current_network.ssid, len);
217 wrqu->essid.flags = 1;
218
219 out:
220 spin_unlock_irqrestore(&ieee->lock, flags);
221
222 return ret;
223
224 }
225 EXPORT_SYMBOL(rtllib_wx_get_essid);
226
rtllib_wx_set_rate(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)227 int rtllib_wx_set_rate(struct rtllib_device *ieee,
228 struct iw_request_info *info,
229 union iwreq_data *wrqu, char *extra)
230 {
231
232 u32 target_rate = wrqu->bitrate.value;
233
234 ieee->rate = target_rate/100000;
235 return 0;
236 }
237 EXPORT_SYMBOL(rtllib_wx_set_rate);
238
rtllib_wx_get_rate(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)239 int rtllib_wx_get_rate(struct rtllib_device *ieee,
240 struct iw_request_info *info,
241 union iwreq_data *wrqu, char *extra)
242 {
243 u32 tmp_rate;
244
245 tmp_rate = TxCountToDataRate(ieee,
246 ieee->softmac_stats.CurrentShowTxate);
247 wrqu->bitrate.value = tmp_rate * 500000;
248
249 return 0;
250 }
251 EXPORT_SYMBOL(rtllib_wx_get_rate);
252
253
rtllib_wx_set_rts(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)254 int rtllib_wx_set_rts(struct rtllib_device *ieee,
255 struct iw_request_info *info,
256 union iwreq_data *wrqu, char *extra)
257 {
258 if (wrqu->rts.disabled || !wrqu->rts.fixed)
259 ieee->rts = DEFAULT_RTS_THRESHOLD;
260 else {
261 if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
262 wrqu->rts.value > MAX_RTS_THRESHOLD)
263 return -EINVAL;
264 ieee->rts = wrqu->rts.value;
265 }
266 return 0;
267 }
268 EXPORT_SYMBOL(rtllib_wx_set_rts);
269
rtllib_wx_get_rts(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)270 int rtllib_wx_get_rts(struct rtllib_device *ieee,
271 struct iw_request_info *info,
272 union iwreq_data *wrqu, char *extra)
273 {
274 wrqu->rts.value = ieee->rts;
275 wrqu->rts.fixed = 0; /* no auto select */
276 wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD);
277 return 0;
278 }
279 EXPORT_SYMBOL(rtllib_wx_get_rts);
280
rtllib_wx_set_mode(struct rtllib_device * ieee,struct iw_request_info * a,union iwreq_data * wrqu,char * b)281 int rtllib_wx_set_mode(struct rtllib_device *ieee, struct iw_request_info *a,
282 union iwreq_data *wrqu, char *b)
283 {
284 int set_mode_status = 0;
285
286 rtllib_stop_scan_syncro(ieee);
287 mutex_lock(&ieee->wx_mutex);
288 switch (wrqu->mode) {
289 case IW_MODE_MONITOR:
290 case IW_MODE_ADHOC:
291 case IW_MODE_INFRA:
292 break;
293 case IW_MODE_AUTO:
294 wrqu->mode = IW_MODE_INFRA;
295 break;
296 default:
297 set_mode_status = -EINVAL;
298 goto out;
299 }
300
301 if (wrqu->mode == ieee->iw_mode)
302 goto out;
303
304 if (wrqu->mode == IW_MODE_MONITOR) {
305 ieee->dev->type = ARPHRD_IEEE80211;
306 rtllib_EnableNetMonitorMode(ieee->dev, false);
307 } else {
308 ieee->dev->type = ARPHRD_ETHER;
309 if (ieee->iw_mode == IW_MODE_MONITOR)
310 rtllib_DisableNetMonitorMode(ieee->dev, false);
311 }
312
313 if (!ieee->proto_started) {
314 ieee->iw_mode = wrqu->mode;
315 } else {
316 rtllib_stop_protocol(ieee, true);
317 ieee->iw_mode = wrqu->mode;
318 rtllib_start_protocol(ieee);
319 }
320
321 out:
322 mutex_unlock(&ieee->wx_mutex);
323 return set_mode_status;
324 }
325 EXPORT_SYMBOL(rtllib_wx_set_mode);
326
rtllib_wx_sync_scan_wq(void * data)327 void rtllib_wx_sync_scan_wq(void *data)
328 {
329 struct rtllib_device *ieee = container_of_work_rsl(data,
330 struct rtllib_device, wx_sync_scan_wq);
331 short chan;
332 enum ht_extchnl_offset chan_offset = 0;
333 enum ht_channel_width bandwidth = 0;
334 int b40M = 0;
335
336 if (!(ieee->softmac_features & IEEE_SOFTMAC_SCAN)) {
337 rtllib_start_scan_syncro(ieee, 0);
338 goto out;
339 }
340
341 chan = ieee->current_network.channel;
342
343 if (ieee->LeisurePSLeave)
344 ieee->LeisurePSLeave(ieee->dev);
345 /* notify AP to be in PS mode */
346 rtllib_sta_ps_send_null_frame(ieee, 1);
347 rtllib_sta_ps_send_null_frame(ieee, 1);
348
349 rtllib_stop_all_queues(ieee);
350
351 if (ieee->data_hard_stop)
352 ieee->data_hard_stop(ieee->dev);
353 rtllib_stop_send_beacons(ieee);
354 ieee->state = RTLLIB_LINKED_SCANNING;
355 ieee->link_change(ieee->dev);
356 /* wait for ps packet to be kicked out successfully */
357 msleep(50);
358
359 if (ieee->ScanOperationBackupHandler)
360 ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_BACKUP);
361
362 if (ieee->pHTInfo->bCurrentHTSupport && ieee->pHTInfo->bEnableHT &&
363 ieee->pHTInfo->bCurBW40MHz) {
364 b40M = 1;
365 chan_offset = ieee->pHTInfo->CurSTAExtChnlOffset;
366 bandwidth = (enum ht_channel_width)ieee->pHTInfo->bCurBW40MHz;
367 RT_TRACE(COMP_DBG, "Scan in 40M, force to 20M first:%d, %d\n",
368 chan_offset, bandwidth);
369 ieee->SetBWModeHandler(ieee->dev, HT_CHANNEL_WIDTH_20,
370 HT_EXTCHNL_OFFSET_NO_EXT);
371 }
372
373 rtllib_start_scan_syncro(ieee, 0);
374
375 if (b40M) {
376 RT_TRACE(COMP_DBG, "Scan in 20M, back to 40M\n");
377 if (chan_offset == HT_EXTCHNL_OFFSET_UPPER)
378 ieee->set_chan(ieee->dev, chan + 2);
379 else if (chan_offset == HT_EXTCHNL_OFFSET_LOWER)
380 ieee->set_chan(ieee->dev, chan - 2);
381 else
382 ieee->set_chan(ieee->dev, chan);
383 ieee->SetBWModeHandler(ieee->dev, bandwidth, chan_offset);
384 } else {
385 ieee->set_chan(ieee->dev, chan);
386 }
387
388 if (ieee->ScanOperationBackupHandler)
389 ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_RESTORE);
390
391 ieee->state = RTLLIB_LINKED;
392 ieee->link_change(ieee->dev);
393
394 /* Notify AP that I wake up again */
395 rtllib_sta_ps_send_null_frame(ieee, 0);
396
397 if (ieee->LinkDetectInfo.NumRecvBcnInPeriod == 0 ||
398 ieee->LinkDetectInfo.NumRecvDataInPeriod == 0) {
399 ieee->LinkDetectInfo.NumRecvBcnInPeriod = 1;
400 ieee->LinkDetectInfo.NumRecvDataInPeriod = 1;
401 }
402
403 if (ieee->data_hard_resume)
404 ieee->data_hard_resume(ieee->dev);
405
406 if (ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER)
407 rtllib_start_send_beacons(ieee);
408
409 rtllib_wake_all_queues(ieee);
410
411 out:
412 mutex_unlock(&ieee->wx_mutex);
413
414 }
415
rtllib_wx_set_scan(struct rtllib_device * ieee,struct iw_request_info * a,union iwreq_data * wrqu,char * b)416 int rtllib_wx_set_scan(struct rtllib_device *ieee, struct iw_request_info *a,
417 union iwreq_data *wrqu, char *b)
418 {
419 int ret = 0;
420
421 mutex_lock(&ieee->wx_mutex);
422
423 if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)) {
424 ret = -1;
425 goto out;
426 }
427
428 if (ieee->state == RTLLIB_LINKED) {
429 schedule_work(&ieee->wx_sync_scan_wq);
430 /* intentionally forget to up sem */
431 return 0;
432 }
433
434 out:
435 mutex_unlock(&ieee->wx_mutex);
436 return ret;
437 }
438 EXPORT_SYMBOL(rtllib_wx_set_scan);
439
rtllib_wx_set_essid(struct rtllib_device * ieee,struct iw_request_info * a,union iwreq_data * wrqu,char * extra)440 int rtllib_wx_set_essid(struct rtllib_device *ieee,
441 struct iw_request_info *a,
442 union iwreq_data *wrqu, char *extra)
443 {
444
445 int ret = 0, len, i;
446 short proto_started;
447 unsigned long flags;
448
449 rtllib_stop_scan_syncro(ieee);
450 mutex_lock(&ieee->wx_mutex);
451
452 proto_started = ieee->proto_started;
453
454 len = min_t(__u16, wrqu->essid.length, IW_ESSID_MAX_SIZE);
455
456 if (ieee->iw_mode == IW_MODE_MONITOR) {
457 ret = -1;
458 goto out;
459 }
460
461 for (i = 0; i < len; i++) {
462 if (extra[i] < 0) {
463 ret = -1;
464 goto out;
465 }
466 }
467
468 if (proto_started)
469 rtllib_stop_protocol(ieee, true);
470
471
472 /* this is just to be sure that the GET wx callback
473 * has consistent infos. not needed otherwise
474 */
475 spin_lock_irqsave(&ieee->lock, flags);
476
477 if (wrqu->essid.flags && wrqu->essid.length) {
478 strncpy(ieee->current_network.ssid, extra, len);
479 ieee->current_network.ssid_len = len;
480 ieee->cannot_notify = false;
481 ieee->ssid_set = 1;
482 } else {
483 ieee->ssid_set = 0;
484 ieee->current_network.ssid[0] = '\0';
485 ieee->current_network.ssid_len = 0;
486 }
487 spin_unlock_irqrestore(&ieee->lock, flags);
488
489 if (proto_started)
490 rtllib_start_protocol(ieee);
491 out:
492 mutex_unlock(&ieee->wx_mutex);
493 return ret;
494 }
495 EXPORT_SYMBOL(rtllib_wx_set_essid);
496
rtllib_wx_get_mode(struct rtllib_device * ieee,struct iw_request_info * a,union iwreq_data * wrqu,char * b)497 int rtllib_wx_get_mode(struct rtllib_device *ieee, struct iw_request_info *a,
498 union iwreq_data *wrqu, char *b)
499 {
500 wrqu->mode = ieee->iw_mode;
501 return 0;
502 }
503 EXPORT_SYMBOL(rtllib_wx_get_mode);
504
rtllib_wx_set_rawtx(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)505 int rtllib_wx_set_rawtx(struct rtllib_device *ieee,
506 struct iw_request_info *info,
507 union iwreq_data *wrqu, char *extra)
508 {
509
510 int *parms = (int *)extra;
511 int enable = (parms[0] > 0);
512 short prev = ieee->raw_tx;
513
514 mutex_lock(&ieee->wx_mutex);
515
516 if (enable)
517 ieee->raw_tx = 1;
518 else
519 ieee->raw_tx = 0;
520
521 netdev_info(ieee->dev, "raw TX is %s\n",
522 ieee->raw_tx ? "enabled" : "disabled");
523
524 if (ieee->iw_mode == IW_MODE_MONITOR) {
525 if (prev == 0 && ieee->raw_tx) {
526 if (ieee->data_hard_resume)
527 ieee->data_hard_resume(ieee->dev);
528
529 netif_carrier_on(ieee->dev);
530 }
531
532 if (prev && ieee->raw_tx == 1)
533 netif_carrier_off(ieee->dev);
534 }
535
536 mutex_unlock(&ieee->wx_mutex);
537
538 return 0;
539 }
540 EXPORT_SYMBOL(rtllib_wx_set_rawtx);
541
rtllib_wx_get_name(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)542 int rtllib_wx_get_name(struct rtllib_device *ieee,
543 struct iw_request_info *info,
544 union iwreq_data *wrqu, char *extra)
545 {
546 strcpy(wrqu->name, "802.11");
547
548 if (ieee->modulation & RTLLIB_CCK_MODULATION)
549 strcat(wrqu->name, "b");
550 if (ieee->modulation & RTLLIB_OFDM_MODULATION)
551 strcat(wrqu->name, "g");
552 if (ieee->mode & (IEEE_N_24G | IEEE_N_5G))
553 strcat(wrqu->name, "n");
554 return 0;
555 }
556 EXPORT_SYMBOL(rtllib_wx_get_name);
557
558
559 /* this is mostly stolen from hostap */
rtllib_wx_set_power(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)560 int rtllib_wx_set_power(struct rtllib_device *ieee,
561 struct iw_request_info *info,
562 union iwreq_data *wrqu, char *extra)
563 {
564 int ret = 0;
565
566 if ((!ieee->sta_wake_up) ||
567 (!ieee->enter_sleep_state) ||
568 (!ieee->ps_is_queue_empty)) {
569 netdev_warn(ieee->dev,
570 "%s(): PS mode is tried to be use but driver missed a callback\n",
571 __func__);
572 return -1;
573 }
574
575 mutex_lock(&ieee->wx_mutex);
576
577 if (wrqu->power.disabled) {
578 RT_TRACE(COMP_DBG, "===>%s(): power disable\n", __func__);
579 ieee->ps = RTLLIB_PS_DISABLED;
580 goto exit;
581 }
582 if (wrqu->power.flags & IW_POWER_TIMEOUT) {
583 ieee->ps_timeout = wrqu->power.value / 1000;
584 RT_TRACE(COMP_DBG, "===>%s():ps_timeout is %d\n", __func__,
585 ieee->ps_timeout);
586 }
587
588 if (wrqu->power.flags & IW_POWER_PERIOD)
589 ieee->ps_period = wrqu->power.value / 1000;
590
591 switch (wrqu->power.flags & IW_POWER_MODE) {
592 case IW_POWER_UNICAST_R:
593 ieee->ps = RTLLIB_PS_UNICAST;
594 break;
595 case IW_POWER_MULTICAST_R:
596 ieee->ps = RTLLIB_PS_MBCAST;
597 break;
598 case IW_POWER_ALL_R:
599 ieee->ps = RTLLIB_PS_UNICAST | RTLLIB_PS_MBCAST;
600 break;
601
602 case IW_POWER_ON:
603 break;
604
605 default:
606 ret = -EINVAL;
607 goto exit;
608
609 }
610 exit:
611 mutex_unlock(&ieee->wx_mutex);
612 return ret;
613
614 }
615 EXPORT_SYMBOL(rtllib_wx_set_power);
616
617 /* this is stolen from hostap */
rtllib_wx_get_power(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)618 int rtllib_wx_get_power(struct rtllib_device *ieee,
619 struct iw_request_info *info,
620 union iwreq_data *wrqu, char *extra)
621 {
622 mutex_lock(&ieee->wx_mutex);
623
624 if (ieee->ps == RTLLIB_PS_DISABLED) {
625 wrqu->power.disabled = 1;
626 goto exit;
627 }
628
629 wrqu->power.disabled = 0;
630
631 if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
632 wrqu->power.flags = IW_POWER_TIMEOUT;
633 wrqu->power.value = ieee->ps_timeout * 1000;
634 } else {
635 wrqu->power.flags = IW_POWER_PERIOD;
636 wrqu->power.value = ieee->ps_period * 1000;
637 }
638
639 if ((ieee->ps & (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST)) ==
640 (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST))
641 wrqu->power.flags |= IW_POWER_ALL_R;
642 else if (ieee->ps & RTLLIB_PS_MBCAST)
643 wrqu->power.flags |= IW_POWER_MULTICAST_R;
644 else
645 wrqu->power.flags |= IW_POWER_UNICAST_R;
646
647 exit:
648 mutex_unlock(&ieee->wx_mutex);
649 return 0;
650
651 }
652 EXPORT_SYMBOL(rtllib_wx_get_power);
653