• 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 	down(&ieee->wx_sem);
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 	up(&ieee->wx_sem);
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 		memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
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 	down(&ieee->wx_sem);
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 		memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN);
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 	memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN);
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 	up(&ieee->wx_sem);
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 = 0;
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 	down(&ieee->wx_sem);
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 	up(&ieee->wx_sem);
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 	up(&ieee->wx_sem);
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 	down(&ieee->wx_sem);
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 		queue_work_rsl(ieee->wq, &ieee->wx_sync_scan_wq);
433 		/* intentionally forget to up sem */
434 		return 0;
435 	}
436 
437 out:
438 	up(&ieee->wx_sem);
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 	down(&ieee->wx_sem);
454 
455 	proto_started = ieee->proto_started;
456 
457 	len = (wrqu->essid.length < IW_ESSID_MAX_SIZE) ? wrqu->essid.length :
458 	       IW_ESSID_MAX_SIZE;
459 
460 	if (len > IW_ESSID_MAX_SIZE) {
461 		ret = -E2BIG;
462 		goto out;
463 	}
464 
465 	if (ieee->iw_mode == IW_MODE_MONITOR) {
466 		ret = -1;
467 		goto out;
468 	}
469 
470 	for (i = 0; i < len; i++) {
471 		if (extra[i] < 0) {
472 			ret = -1;
473 			goto out;
474 		}
475 	}
476 
477 	if (proto_started)
478 		rtllib_stop_protocol(ieee, true);
479 
480 
481 	/* this is just to be sure that the GET wx callback
482 	 * has consistent infos. not needed otherwise
483 	 */
484 	spin_lock_irqsave(&ieee->lock, flags);
485 
486 	if (wrqu->essid.flags && wrqu->essid.length) {
487 		strncpy(ieee->current_network.ssid, extra, len);
488 		ieee->current_network.ssid_len = len;
489 		ieee->cannot_notify = false;
490 		ieee->ssid_set = 1;
491 	} else {
492 		ieee->ssid_set = 0;
493 		ieee->current_network.ssid[0] = '\0';
494 		ieee->current_network.ssid_len = 0;
495 	}
496 	spin_unlock_irqrestore(&ieee->lock, flags);
497 
498 	if (proto_started)
499 		rtllib_start_protocol(ieee);
500 out:
501 	up(&ieee->wx_sem);
502 	return ret;
503 }
504 EXPORT_SYMBOL(rtllib_wx_set_essid);
505 
rtllib_wx_get_mode(struct rtllib_device * ieee,struct iw_request_info * a,union iwreq_data * wrqu,char * b)506 int rtllib_wx_get_mode(struct rtllib_device *ieee, struct iw_request_info *a,
507 		       union iwreq_data *wrqu, char *b)
508 {
509 	wrqu->mode = ieee->iw_mode;
510 	return 0;
511 }
512 EXPORT_SYMBOL(rtllib_wx_get_mode);
513 
rtllib_wx_set_rawtx(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)514 int rtllib_wx_set_rawtx(struct rtllib_device *ieee,
515 			struct iw_request_info *info,
516 			union iwreq_data *wrqu, char *extra)
517 {
518 
519 	int *parms = (int *)extra;
520 	int enable = (parms[0] > 0);
521 	short prev = ieee->raw_tx;
522 
523 	down(&ieee->wx_sem);
524 
525 	if (enable)
526 		ieee->raw_tx = 1;
527 	else
528 		ieee->raw_tx = 0;
529 
530 	printk(KERN_INFO"raw TX is %s\n",
531 	      ieee->raw_tx ? "enabled" : "disabled");
532 
533 	if (ieee->iw_mode == IW_MODE_MONITOR) {
534 		if (prev == 0 && ieee->raw_tx) {
535 			if (ieee->data_hard_resume)
536 				ieee->data_hard_resume(ieee->dev);
537 
538 			netif_carrier_on(ieee->dev);
539 		}
540 
541 		if (prev && ieee->raw_tx == 1)
542 			netif_carrier_off(ieee->dev);
543 	}
544 
545 	up(&ieee->wx_sem);
546 
547 	return 0;
548 }
549 EXPORT_SYMBOL(rtllib_wx_set_rawtx);
550 
rtllib_wx_get_name(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)551 int rtllib_wx_get_name(struct rtllib_device *ieee,
552 			     struct iw_request_info *info,
553 			     union iwreq_data *wrqu, char *extra)
554 {
555 	strcpy(wrqu->name, "802.11");
556 
557 	if (ieee->modulation & RTLLIB_CCK_MODULATION)
558 		strcat(wrqu->name, "b");
559 	if (ieee->modulation & RTLLIB_OFDM_MODULATION)
560 		strcat(wrqu->name, "g");
561 	if (ieee->mode & (IEEE_N_24G | IEEE_N_5G))
562 		strcat(wrqu->name, "n");
563 	return 0;
564 }
565 EXPORT_SYMBOL(rtllib_wx_get_name);
566 
567 
568 /* 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)569 int rtllib_wx_set_power(struct rtllib_device *ieee,
570 				 struct iw_request_info *info,
571 				 union iwreq_data *wrqu, char *extra)
572 {
573 	int ret = 0;
574 
575 	if ((!ieee->sta_wake_up) ||
576 	    (!ieee->enter_sleep_state) ||
577 	    (!ieee->ps_is_queue_empty)) {
578 		RTLLIB_DEBUG(RTLLIB_DL_ERR, "%s(): PS mode is tried to be use "
579 			     "but driver missed a callback\n\n", __func__);
580 		return -1;
581 	}
582 
583 	down(&ieee->wx_sem);
584 
585 	if (wrqu->power.disabled) {
586 		RT_TRACE(COMP_DBG, "===>%s(): power disable\n", __func__);
587 		ieee->ps = RTLLIB_PS_DISABLED;
588 		goto exit;
589 	}
590 	if (wrqu->power.flags & IW_POWER_TIMEOUT) {
591 		ieee->ps_timeout = wrqu->power.value / 1000;
592 		RT_TRACE(COMP_DBG, "===>%s():ps_timeout is %d\n", __func__,
593 			 ieee->ps_timeout);
594 	}
595 
596 	if (wrqu->power.flags & IW_POWER_PERIOD)
597 		ieee->ps_period = wrqu->power.value / 1000;
598 
599 	switch (wrqu->power.flags & IW_POWER_MODE) {
600 	case IW_POWER_UNICAST_R:
601 		ieee->ps = RTLLIB_PS_UNICAST;
602 		break;
603 	case IW_POWER_MULTICAST_R:
604 		ieee->ps = RTLLIB_PS_MBCAST;
605 		break;
606 	case IW_POWER_ALL_R:
607 		ieee->ps = RTLLIB_PS_UNICAST | RTLLIB_PS_MBCAST;
608 		break;
609 
610 	case IW_POWER_ON:
611 		break;
612 
613 	default:
614 		ret = -EINVAL;
615 		goto exit;
616 
617 	}
618 exit:
619 	up(&ieee->wx_sem);
620 	return ret;
621 
622 }
623 EXPORT_SYMBOL(rtllib_wx_set_power);
624 
625 /* this is stolen from hostap */
rtllib_wx_get_power(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)626 int rtllib_wx_get_power(struct rtllib_device *ieee,
627 				 struct iw_request_info *info,
628 				 union iwreq_data *wrqu, char *extra)
629 {
630 	down(&ieee->wx_sem);
631 
632 	if (ieee->ps == RTLLIB_PS_DISABLED) {
633 		wrqu->power.disabled = 1;
634 		goto exit;
635 	}
636 
637 	wrqu->power.disabled = 0;
638 
639 	if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
640 		wrqu->power.flags = IW_POWER_TIMEOUT;
641 		wrqu->power.value = ieee->ps_timeout * 1000;
642 	} else {
643 		wrqu->power.flags = IW_POWER_PERIOD;
644 		wrqu->power.value = ieee->ps_period * 1000;
645 	}
646 
647 	if ((ieee->ps & (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST)) ==
648 	    (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST))
649 		wrqu->power.flags |= IW_POWER_ALL_R;
650 	else if (ieee->ps & RTLLIB_PS_MBCAST)
651 		wrqu->power.flags |= IW_POWER_MULTICAST_R;
652 	else
653 		wrqu->power.flags |= IW_POWER_UNICAST_R;
654 
655 exit:
656 	up(&ieee->wx_sem);
657 	return 0;
658 
659 }
660 EXPORT_SYMBOL(rtllib_wx_get_power);
661