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