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, struct iw_request_info *info,
543 		       union iwreq_data *wrqu, char *extra)
544 {
545 	const char *b = ieee->modulation & RTLLIB_CCK_MODULATION ? "b" : "";
546 	const char *g = ieee->modulation & RTLLIB_OFDM_MODULATION ? "g" : "";
547 	const char *n = ieee->mode & (IEEE_N_24G | IEEE_N_5G) ? "n" : "";
548 
549 	scnprintf(wrqu->name, sizeof(wrqu->name), "802.11%s%s%s", b, g, n);
550 	return 0;
551 }
552 EXPORT_SYMBOL(rtllib_wx_get_name);
553 
554 
555 /* 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)556 int rtllib_wx_set_power(struct rtllib_device *ieee,
557 				 struct iw_request_info *info,
558 				 union iwreq_data *wrqu, char *extra)
559 {
560 	int ret = 0;
561 
562 	if ((!ieee->sta_wake_up) ||
563 	    (!ieee->enter_sleep_state) ||
564 	    (!ieee->ps_is_queue_empty)) {
565 		netdev_warn(ieee->dev,
566 			    "%s(): PS mode is tried to be use but driver missed a callback\n",
567 			    __func__);
568 		return -1;
569 	}
570 
571 	mutex_lock(&ieee->wx_mutex);
572 
573 	if (wrqu->power.disabled) {
574 		RT_TRACE(COMP_DBG, "===>%s(): power disable\n", __func__);
575 		ieee->ps = RTLLIB_PS_DISABLED;
576 		goto exit;
577 	}
578 	if (wrqu->power.flags & IW_POWER_TIMEOUT) {
579 		ieee->ps_timeout = wrqu->power.value / 1000;
580 		RT_TRACE(COMP_DBG, "===>%s():ps_timeout is %d\n", __func__,
581 			 ieee->ps_timeout);
582 	}
583 
584 	if (wrqu->power.flags & IW_POWER_PERIOD)
585 		ieee->ps_period = wrqu->power.value / 1000;
586 
587 	switch (wrqu->power.flags & IW_POWER_MODE) {
588 	case IW_POWER_UNICAST_R:
589 		ieee->ps = RTLLIB_PS_UNICAST;
590 		break;
591 	case IW_POWER_MULTICAST_R:
592 		ieee->ps = RTLLIB_PS_MBCAST;
593 		break;
594 	case IW_POWER_ALL_R:
595 		ieee->ps = RTLLIB_PS_UNICAST | RTLLIB_PS_MBCAST;
596 		break;
597 
598 	case IW_POWER_ON:
599 		break;
600 
601 	default:
602 		ret = -EINVAL;
603 		goto exit;
604 
605 	}
606 exit:
607 	mutex_unlock(&ieee->wx_mutex);
608 	return ret;
609 
610 }
611 EXPORT_SYMBOL(rtllib_wx_set_power);
612 
613 /* this is stolen from hostap */
rtllib_wx_get_power(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)614 int rtllib_wx_get_power(struct rtllib_device *ieee,
615 				 struct iw_request_info *info,
616 				 union iwreq_data *wrqu, char *extra)
617 {
618 	mutex_lock(&ieee->wx_mutex);
619 
620 	if (ieee->ps == RTLLIB_PS_DISABLED) {
621 		wrqu->power.disabled = 1;
622 		goto exit;
623 	}
624 
625 	wrqu->power.disabled = 0;
626 
627 	if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
628 		wrqu->power.flags = IW_POWER_TIMEOUT;
629 		wrqu->power.value = ieee->ps_timeout * 1000;
630 	} else {
631 		wrqu->power.flags = IW_POWER_PERIOD;
632 		wrqu->power.value = ieee->ps_period * 1000;
633 	}
634 
635 	if ((ieee->ps & (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST)) ==
636 	    (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST))
637 		wrqu->power.flags |= IW_POWER_ALL_R;
638 	else if (ieee->ps & RTLLIB_PS_MBCAST)
639 		wrqu->power.flags |= IW_POWER_MULTICAST_R;
640 	else
641 		wrqu->power.flags |= IW_POWER_UNICAST_R;
642 
643 exit:
644 	mutex_unlock(&ieee->wx_mutex);
645 	return 0;
646 
647 }
648 EXPORT_SYMBOL(rtllib_wx_get_power);
649