• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* 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 <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 	tmp_rate = TxCountToDataRate(ieee,
248 				     ieee->softmac_stats.CurrentShowTxate);
249 	wrqu->bitrate.value = tmp_rate * 500000;
250 
251 	return 0;
252 }
253 EXPORT_SYMBOL(rtllib_wx_get_rate);
254 
255 
rtllib_wx_set_rts(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)256 int rtllib_wx_set_rts(struct rtllib_device *ieee,
257 			     struct iw_request_info *info,
258 			     union iwreq_data *wrqu, char *extra)
259 {
260 	if (wrqu->rts.disabled || !wrqu->rts.fixed)
261 		ieee->rts = DEFAULT_RTS_THRESHOLD;
262 	else {
263 		if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
264 				wrqu->rts.value > MAX_RTS_THRESHOLD)
265 			return -EINVAL;
266 		ieee->rts = wrqu->rts.value;
267 	}
268 	return 0;
269 }
270 EXPORT_SYMBOL(rtllib_wx_set_rts);
271 
rtllib_wx_get_rts(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)272 int rtllib_wx_get_rts(struct rtllib_device *ieee,
273 			     struct iw_request_info *info,
274 			     union iwreq_data *wrqu, char *extra)
275 {
276 	wrqu->rts.value = ieee->rts;
277 	wrqu->rts.fixed = 0;	/* no auto select */
278 	wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD);
279 	return 0;
280 }
281 EXPORT_SYMBOL(rtllib_wx_get_rts);
282 
rtllib_wx_set_mode(struct rtllib_device * ieee,struct iw_request_info * a,union iwreq_data * wrqu,char * b)283 int rtllib_wx_set_mode(struct rtllib_device *ieee, struct iw_request_info *a,
284 			     union iwreq_data *wrqu, char *b)
285 {
286 	int set_mode_status = 0;
287 
288 	rtllib_stop_scan_syncro(ieee);
289 	down(&ieee->wx_sem);
290 	switch (wrqu->mode) {
291 	case IW_MODE_MONITOR:
292 	case IW_MODE_ADHOC:
293 	case IW_MODE_INFRA:
294 		break;
295 	case IW_MODE_AUTO:
296 		wrqu->mode = IW_MODE_INFRA;
297 		break;
298 	default:
299 		set_mode_status = -EINVAL;
300 		goto out;
301 	}
302 
303 	if (wrqu->mode == ieee->iw_mode)
304 		goto out;
305 
306 	if (wrqu->mode == IW_MODE_MONITOR) {
307 		ieee->dev->type = ARPHRD_IEEE80211;
308 		rtllib_EnableNetMonitorMode(ieee->dev, false);
309 	} else {
310 		ieee->dev->type = ARPHRD_ETHER;
311 		if (ieee->iw_mode == IW_MODE_MONITOR)
312 			rtllib_DisableNetMonitorMode(ieee->dev, false);
313 	}
314 
315 	if (!ieee->proto_started) {
316 		ieee->iw_mode = wrqu->mode;
317 	} else {
318 		rtllib_stop_protocol(ieee, true);
319 		ieee->iw_mode = wrqu->mode;
320 		rtllib_start_protocol(ieee);
321 	}
322 
323 out:
324 	up(&ieee->wx_sem);
325 	return set_mode_status;
326 }
327 EXPORT_SYMBOL(rtllib_wx_set_mode);
328 
rtllib_wx_sync_scan_wq(void * data)329 void rtllib_wx_sync_scan_wq(void *data)
330 {
331 	struct rtllib_device *ieee = container_of_work_rsl(data,
332 				     struct rtllib_device, wx_sync_scan_wq);
333 	short chan;
334 	enum ht_extchnl_offset chan_offset = 0;
335 	enum ht_channel_width bandwidth = 0;
336 	int b40M = 0;
337 	static int count;
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 	count = 0;
415 out:
416 	up(&ieee->wx_sem);
417 
418 }
419 
rtllib_wx_set_scan(struct rtllib_device * ieee,struct iw_request_info * a,union iwreq_data * wrqu,char * b)420 int rtllib_wx_set_scan(struct rtllib_device *ieee, struct iw_request_info *a,
421 			     union iwreq_data *wrqu, char *b)
422 {
423 	int ret = 0;
424 
425 	down(&ieee->wx_sem);
426 
427 	if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)) {
428 		ret = -1;
429 		goto out;
430 	}
431 
432 	if (ieee->state == RTLLIB_LINKED) {
433 		queue_work_rsl(ieee->wq, &ieee->wx_sync_scan_wq);
434 		/* intentionally forget to up sem */
435 		return 0;
436 	}
437 
438 out:
439 	up(&ieee->wx_sem);
440 	return ret;
441 }
442 EXPORT_SYMBOL(rtllib_wx_set_scan);
443 
rtllib_wx_set_essid(struct rtllib_device * ieee,struct iw_request_info * a,union iwreq_data * wrqu,char * extra)444 int rtllib_wx_set_essid(struct rtllib_device *ieee,
445 			struct iw_request_info *a,
446 			union iwreq_data *wrqu, char *extra)
447 {
448 
449 	int ret = 0, len, i;
450 	short proto_started;
451 	unsigned long flags;
452 
453 	rtllib_stop_scan_syncro(ieee);
454 	down(&ieee->wx_sem);
455 
456 	proto_started = ieee->proto_started;
457 
458 	len = (wrqu->essid.length < IW_ESSID_MAX_SIZE) ? wrqu->essid.length :
459 	       IW_ESSID_MAX_SIZE;
460 
461 	if (len > IW_ESSID_MAX_SIZE) {
462 		ret = -E2BIG;
463 		goto out;
464 	}
465 
466 	if (ieee->iw_mode == IW_MODE_MONITOR) {
467 		ret = -1;
468 		goto out;
469 	}
470 
471 	for (i = 0; i < len; i++) {
472 		if (extra[i] < 0) {
473 			ret = -1;
474 			goto out;
475 		}
476 	}
477 
478 	if (proto_started)
479 		rtllib_stop_protocol(ieee, true);
480 
481 
482 	/* this is just to be sure that the GET wx callback
483 	 * has consistent infos. not needed otherwise
484 	 */
485 	spin_lock_irqsave(&ieee->lock, flags);
486 
487 	if (wrqu->essid.flags && wrqu->essid.length) {
488 		strncpy(ieee->current_network.ssid, extra, len);
489 		ieee->current_network.ssid_len = len;
490 		ieee->cannot_notify = false;
491 		ieee->ssid_set = 1;
492 	} else {
493 		ieee->ssid_set = 0;
494 		ieee->current_network.ssid[0] = '\0';
495 		ieee->current_network.ssid_len = 0;
496 	}
497 	spin_unlock_irqrestore(&ieee->lock, flags);
498 
499 	if (proto_started)
500 		rtllib_start_protocol(ieee);
501 out:
502 	up(&ieee->wx_sem);
503 	return ret;
504 }
505 EXPORT_SYMBOL(rtllib_wx_set_essid);
506 
rtllib_wx_get_mode(struct rtllib_device * ieee,struct iw_request_info * a,union iwreq_data * wrqu,char * b)507 int rtllib_wx_get_mode(struct rtllib_device *ieee, struct iw_request_info *a,
508 		       union iwreq_data *wrqu, char *b)
509 {
510 	wrqu->mode = ieee->iw_mode;
511 	return 0;
512 }
513 EXPORT_SYMBOL(rtllib_wx_get_mode);
514 
rtllib_wx_set_rawtx(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)515 int rtllib_wx_set_rawtx(struct rtllib_device *ieee,
516 			struct iw_request_info *info,
517 			union iwreq_data *wrqu, char *extra)
518 {
519 
520 	int *parms = (int *)extra;
521 	int enable = (parms[0] > 0);
522 	short prev = ieee->raw_tx;
523 
524 	down(&ieee->wx_sem);
525 
526 	if (enable)
527 		ieee->raw_tx = 1;
528 	else
529 		ieee->raw_tx = 0;
530 
531 	printk(KERN_INFO"raw TX is %s\n",
532 	      ieee->raw_tx ? "enabled" : "disabled");
533 
534 	if (ieee->iw_mode == IW_MODE_MONITOR) {
535 		if (prev == 0 && ieee->raw_tx) {
536 			if (ieee->data_hard_resume)
537 				ieee->data_hard_resume(ieee->dev);
538 
539 			netif_carrier_on(ieee->dev);
540 		}
541 
542 		if (prev && ieee->raw_tx == 1)
543 			netif_carrier_off(ieee->dev);
544 	}
545 
546 	up(&ieee->wx_sem);
547 
548 	return 0;
549 }
550 EXPORT_SYMBOL(rtllib_wx_set_rawtx);
551 
rtllib_wx_get_name(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)552 int rtllib_wx_get_name(struct rtllib_device *ieee,
553 			     struct iw_request_info *info,
554 			     union iwreq_data *wrqu, char *extra)
555 {
556 	strcpy(wrqu->name, "802.11");
557 
558 	if (ieee->modulation & RTLLIB_CCK_MODULATION)
559 		strcat(wrqu->name, "b");
560 	if (ieee->modulation & RTLLIB_OFDM_MODULATION)
561 		strcat(wrqu->name, "g");
562 	if (ieee->mode & (IEEE_N_24G | IEEE_N_5G))
563 		strcat(wrqu->name, "n");
564 	return 0;
565 }
566 EXPORT_SYMBOL(rtllib_wx_get_name);
567 
568 
569 /* 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)570 int rtllib_wx_set_power(struct rtllib_device *ieee,
571 				 struct iw_request_info *info,
572 				 union iwreq_data *wrqu, char *extra)
573 {
574 	int ret = 0;
575 
576 	if ((!ieee->sta_wake_up) ||
577 	    (!ieee->enter_sleep_state) ||
578 	    (!ieee->ps_is_queue_empty)) {
579 		RTLLIB_DEBUG(RTLLIB_DL_ERR, "%s(): PS mode is tried to be use "
580 			     "but driver missed a callback\n\n", __func__);
581 		return -1;
582 	}
583 
584 	down(&ieee->wx_sem);
585 
586 	if (wrqu->power.disabled) {
587 		RT_TRACE(COMP_DBG, "===>%s(): power disable\n", __func__);
588 		ieee->ps = RTLLIB_PS_DISABLED;
589 		goto exit;
590 	}
591 	if (wrqu->power.flags & IW_POWER_TIMEOUT) {
592 		ieee->ps_timeout = wrqu->power.value / 1000;
593 		RT_TRACE(COMP_DBG, "===>%s():ps_timeout is %d\n", __func__,
594 			 ieee->ps_timeout);
595 	}
596 
597 	if (wrqu->power.flags & IW_POWER_PERIOD)
598 		ieee->ps_period = wrqu->power.value / 1000;
599 
600 	switch (wrqu->power.flags & IW_POWER_MODE) {
601 	case IW_POWER_UNICAST_R:
602 		ieee->ps = RTLLIB_PS_UNICAST;
603 		break;
604 	case IW_POWER_MULTICAST_R:
605 		ieee->ps = RTLLIB_PS_MBCAST;
606 		break;
607 	case IW_POWER_ALL_R:
608 		ieee->ps = RTLLIB_PS_UNICAST | RTLLIB_PS_MBCAST;
609 		break;
610 
611 	case IW_POWER_ON:
612 		break;
613 
614 	default:
615 		ret = -EINVAL;
616 		goto exit;
617 
618 	}
619 exit:
620 	up(&ieee->wx_sem);
621 	return ret;
622 
623 }
624 EXPORT_SYMBOL(rtllib_wx_set_power);
625 
626 /* this is stolen from hostap */
rtllib_wx_get_power(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)627 int rtllib_wx_get_power(struct rtllib_device *ieee,
628 				 struct iw_request_info *info,
629 				 union iwreq_data *wrqu, char *extra)
630 {
631 	int ret = 0;
632 
633 	down(&ieee->wx_sem);
634 
635 	if (ieee->ps == RTLLIB_PS_DISABLED) {
636 		wrqu->power.disabled = 1;
637 		goto exit;
638 	}
639 
640 	wrqu->power.disabled = 0;
641 
642 	if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
643 		wrqu->power.flags = IW_POWER_TIMEOUT;
644 		wrqu->power.value = ieee->ps_timeout * 1000;
645 	} else {
646 		wrqu->power.flags = IW_POWER_PERIOD;
647 		wrqu->power.value = ieee->ps_period * 1000;
648 	}
649 
650 	if ((ieee->ps & (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST)) ==
651 	    (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST))
652 		wrqu->power.flags |= IW_POWER_ALL_R;
653 	else if (ieee->ps & RTLLIB_PS_MBCAST)
654 		wrqu->power.flags |= IW_POWER_MULTICAST_R;
655 	else
656 		wrqu->power.flags |= IW_POWER_UNICAST_R;
657 
658 exit:
659 	up(&ieee->wx_sem);
660 	return ret;
661 
662 }
663 EXPORT_SYMBOL(rtllib_wx_get_power);
664