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 "rtllib.h"
18 #include "dot11d.h"
19 /* FIXME: add A freqs */
20 
21 const long rtllib_wlan_frequencies[] = {
22 	2412, 2417, 2422, 2427,
23 	2432, 2437, 2442, 2447,
24 	2452, 2457, 2462, 2467,
25 	2472, 2484
26 };
27 EXPORT_SYMBOL(rtllib_wlan_frequencies);
28 
29 
rtllib_wx_set_freq(struct rtllib_device * ieee,struct iw_request_info * a,union iwreq_data * wrqu,char * b)30 int rtllib_wx_set_freq(struct rtllib_device *ieee, struct iw_request_info *a,
31 			     union iwreq_data *wrqu, char *b)
32 {
33 	int ret;
34 	struct iw_freq *fwrq = &wrqu->freq;
35 
36 	down(&ieee->wx_sem);
37 
38 	if (ieee->iw_mode == IW_MODE_INFRA) {
39 		ret = 0;
40 		goto out;
41 	}
42 
43 	/* if setting by freq convert to channel */
44 	if (fwrq->e == 1) {
45 		if ((fwrq->m >= (int) 2.412e8 &&
46 		     fwrq->m <= (int) 2.487e8)) {
47 			int f = fwrq->m / 100000;
48 			int c = 0;
49 
50 			while ((c < 14) && (f != rtllib_wlan_frequencies[c]))
51 				c++;
52 
53 			/* hack to fall through */
54 			fwrq->e = 0;
55 			fwrq->m = c + 1;
56 		}
57 	}
58 
59 	if (fwrq->e > 0 || fwrq->m > 14 || fwrq->m < 1) {
60 		ret = -EOPNOTSUPP;
61 		goto out;
62 
63 	} else { /* Set the channel */
64 
65 		if (ieee->active_channel_map[fwrq->m] != 1) {
66 			ret = -EINVAL;
67 			goto out;
68 		}
69 		ieee->current_network.channel = fwrq->m;
70 		ieee->set_chan(ieee->dev, ieee->current_network.channel);
71 
72 		if (ieee->iw_mode == IW_MODE_ADHOC ||
73 		    ieee->iw_mode == IW_MODE_MASTER)
74 			if (ieee->state == RTLLIB_LINKED) {
75 				rtllib_stop_send_beacons(ieee);
76 				rtllib_start_send_beacons(ieee);
77 			}
78 	}
79 
80 	ret = 0;
81 out:
82 	up(&ieee->wx_sem);
83 	return ret;
84 }
85 EXPORT_SYMBOL(rtllib_wx_set_freq);
86 
87 
rtllib_wx_get_freq(struct rtllib_device * ieee,struct iw_request_info * a,union iwreq_data * wrqu,char * b)88 int rtllib_wx_get_freq(struct rtllib_device *ieee,
89 			     struct iw_request_info *a,
90 			     union iwreq_data *wrqu, char *b)
91 {
92 	struct iw_freq *fwrq = &wrqu->freq;
93 
94 	if (ieee->current_network.channel == 0)
95 		return -1;
96 	fwrq->m = rtllib_wlan_frequencies[ieee->current_network.channel-1] *
97 		  100000;
98 	fwrq->e = 1;
99 	return 0;
100 }
101 EXPORT_SYMBOL(rtllib_wx_get_freq);
102 
rtllib_wx_get_wap(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)103 int rtllib_wx_get_wap(struct rtllib_device *ieee,
104 			    struct iw_request_info *info,
105 			    union iwreq_data *wrqu, char *extra)
106 {
107 	unsigned long flags;
108 
109 	wrqu->ap_addr.sa_family = ARPHRD_ETHER;
110 
111 	if (ieee->iw_mode == IW_MODE_MONITOR)
112 		return -1;
113 
114 	/* We want avoid to give to the user inconsistent infos*/
115 	spin_lock_irqsave(&ieee->lock, flags);
116 
117 	if (ieee->state != RTLLIB_LINKED &&
118 		ieee->state != RTLLIB_LINKED_SCANNING &&
119 		ieee->wap_set == 0)
120 
121 		memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
122 	else
123 		memcpy(wrqu->ap_addr.sa_data,
124 		       ieee->current_network.bssid, ETH_ALEN);
125 
126 	spin_unlock_irqrestore(&ieee->lock, flags);
127 
128 	return 0;
129 }
130 EXPORT_SYMBOL(rtllib_wx_get_wap);
131 
132 
rtllib_wx_set_wap(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * awrq,char * extra)133 int rtllib_wx_set_wap(struct rtllib_device *ieee,
134 			 struct iw_request_info *info,
135 			 union iwreq_data *awrq,
136 			 char *extra)
137 {
138 
139 	int ret = 0;
140 	u8 zero[] = {0, 0, 0, 0, 0, 0};
141 	unsigned long flags;
142 
143 	short ifup = ieee->proto_started;
144 	struct sockaddr *temp = (struct sockaddr *)awrq;
145 
146 	rtllib_stop_scan_syncro(ieee);
147 
148 	down(&ieee->wx_sem);
149 	/* use ifconfig hw ether */
150 	if (ieee->iw_mode == IW_MODE_MASTER) {
151 		ret = -1;
152 		goto out;
153 	}
154 
155 	if (temp->sa_family != ARPHRD_ETHER) {
156 		ret = -EINVAL;
157 		goto out;
158 	}
159 
160 	if (memcmp(temp->sa_data, zero, ETH_ALEN) == 0) {
161 		spin_lock_irqsave(&ieee->lock, flags);
162 		memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN);
163 		ieee->wap_set = 0;
164 		spin_unlock_irqrestore(&ieee->lock, flags);
165 		ret = -1;
166 		goto out;
167 	}
168 
169 
170 	if (ifup)
171 		rtllib_stop_protocol(ieee, true);
172 
173 	/* just to avoid to give inconsistent infos in the
174 	 * get wx method. not really needed otherwise
175 	 */
176 	spin_lock_irqsave(&ieee->lock, flags);
177 
178 	ieee->cannot_notify = false;
179 	memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN);
180 	ieee->wap_set = (memcmp(temp->sa_data, zero, ETH_ALEN) != 0);
181 
182 	spin_unlock_irqrestore(&ieee->lock, flags);
183 
184 	if (ifup)
185 		rtllib_start_protocol(ieee);
186 out:
187 	up(&ieee->wx_sem);
188 	return ret;
189 }
190 EXPORT_SYMBOL(rtllib_wx_set_wap);
191 
rtllib_wx_get_essid(struct rtllib_device * ieee,struct iw_request_info * a,union iwreq_data * wrqu,char * b)192 int rtllib_wx_get_essid(struct rtllib_device *ieee, struct iw_request_info *a,
193 			 union iwreq_data *wrqu, char *b)
194 {
195 	int len, ret = 0;
196 	unsigned long flags;
197 
198 	if (ieee->iw_mode == IW_MODE_MONITOR)
199 		return -1;
200 
201 	/* We want avoid to give to the user inconsistent infos*/
202 	spin_lock_irqsave(&ieee->lock, flags);
203 
204 	if (ieee->current_network.ssid[0] == '\0' ||
205 		ieee->current_network.ssid_len == 0) {
206 		ret = -1;
207 		goto out;
208 	}
209 
210 	if (ieee->state != RTLLIB_LINKED &&
211 		ieee->state != RTLLIB_LINKED_SCANNING &&
212 		ieee->ssid_set == 0) {
213 		ret = -1;
214 		goto out;
215 	}
216 	len = ieee->current_network.ssid_len;
217 	wrqu->essid.length = len;
218 	strncpy(b, ieee->current_network.ssid, len);
219 	wrqu->essid.flags = 1;
220 
221 out:
222 	spin_unlock_irqrestore(&ieee->lock, flags);
223 
224 	return ret;
225 
226 }
227 EXPORT_SYMBOL(rtllib_wx_get_essid);
228 
rtllib_wx_set_rate(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)229 int rtllib_wx_set_rate(struct rtllib_device *ieee,
230 			     struct iw_request_info *info,
231 			     union iwreq_data *wrqu, char *extra)
232 {
233 
234 	u32 target_rate = wrqu->bitrate.value;
235 
236 	ieee->rate = target_rate/100000;
237 	return 0;
238 }
239 EXPORT_SYMBOL(rtllib_wx_set_rate);
240 
rtllib_wx_get_rate(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)241 int rtllib_wx_get_rate(struct rtllib_device *ieee,
242 			     struct iw_request_info *info,
243 			     union iwreq_data *wrqu, char *extra)
244 {
245 	u32 tmp_rate = 0;
246 	tmp_rate = TxCountToDataRate(ieee,
247 				     ieee->softmac_stats.CurrentShowTxate);
248 	wrqu->bitrate.value = tmp_rate * 500000;
249 
250 	return 0;
251 }
252 EXPORT_SYMBOL(rtllib_wx_get_rate);
253 
254 
rtllib_wx_set_rts(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)255 int rtllib_wx_set_rts(struct rtllib_device *ieee,
256 			     struct iw_request_info *info,
257 			     union iwreq_data *wrqu, char *extra)
258 {
259 	if (wrqu->rts.disabled || !wrqu->rts.fixed)
260 		ieee->rts = DEFAULT_RTS_THRESHOLD;
261 	else {
262 		if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
263 				wrqu->rts.value > MAX_RTS_THRESHOLD)
264 			return -EINVAL;
265 		ieee->rts = wrqu->rts.value;
266 	}
267 	return 0;
268 }
269 EXPORT_SYMBOL(rtllib_wx_set_rts);
270 
rtllib_wx_get_rts(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)271 int rtllib_wx_get_rts(struct rtllib_device *ieee,
272 			     struct iw_request_info *info,
273 			     union iwreq_data *wrqu, char *extra)
274 {
275 	wrqu->rts.value = ieee->rts;
276 	wrqu->rts.fixed = 0;	/* no auto select */
277 	wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD);
278 	return 0;
279 }
280 EXPORT_SYMBOL(rtllib_wx_get_rts);
281 
rtllib_wx_set_mode(struct rtllib_device * ieee,struct iw_request_info * a,union iwreq_data * wrqu,char * b)282 int rtllib_wx_set_mode(struct rtllib_device *ieee, struct iw_request_info *a,
283 			     union iwreq_data *wrqu, char *b)
284 {
285 	int set_mode_status = 0;
286 
287 	rtllib_stop_scan_syncro(ieee);
288 	down(&ieee->wx_sem);
289 	switch (wrqu->mode) {
290 	case IW_MODE_MONITOR:
291 	case IW_MODE_ADHOC:
292 	case IW_MODE_INFRA:
293 		break;
294 	case IW_MODE_AUTO:
295 		wrqu->mode = IW_MODE_INFRA;
296 		break;
297 	default:
298 		set_mode_status = -EINVAL;
299 		goto out;
300 	}
301 
302 	if (wrqu->mode == ieee->iw_mode)
303 		goto out;
304 
305 	if (wrqu->mode == IW_MODE_MONITOR) {
306 		ieee->dev->type = ARPHRD_IEEE80211;
307 		rtllib_EnableNetMonitorMode(ieee->dev, false);
308 	} else {
309 		ieee->dev->type = ARPHRD_ETHER;
310 		if (ieee->iw_mode == IW_MODE_MONITOR)
311 			rtllib_DisableNetMonitorMode(ieee->dev, false);
312 	}
313 
314 	if (!ieee->proto_started) {
315 		ieee->iw_mode = wrqu->mode;
316 	} else {
317 		rtllib_stop_protocol(ieee, true);
318 		ieee->iw_mode = wrqu->mode;
319 		rtllib_start_protocol(ieee);
320 	}
321 
322 out:
323 	up(&ieee->wx_sem);
324 	return set_mode_status;
325 }
326 EXPORT_SYMBOL(rtllib_wx_set_mode);
327 
rtllib_wx_sync_scan_wq(void * data)328 void rtllib_wx_sync_scan_wq(void *data)
329 {
330 	struct rtllib_device *ieee = container_of_work_rsl(data,
331 				     struct rtllib_device, wx_sync_scan_wq);
332 	short chan;
333 	enum ht_extchnl_offset chan_offset = 0;
334 	enum ht_channel_width bandwidth = 0;
335 	int b40M = 0;
336 	static int count;
337 
338 	if (!(ieee->softmac_features & IEEE_SOFTMAC_SCAN)) {
339 		rtllib_start_scan_syncro(ieee, 0);
340 		goto out;
341 	}
342 
343 	chan = ieee->current_network.channel;
344 
345 	if (ieee->LeisurePSLeave)
346 		ieee->LeisurePSLeave(ieee->dev);
347 	/* notify AP to be in PS mode */
348 	rtllib_sta_ps_send_null_frame(ieee, 1);
349 	rtllib_sta_ps_send_null_frame(ieee, 1);
350 
351 	rtllib_stop_all_queues(ieee);
352 
353 	if (ieee->data_hard_stop)
354 		ieee->data_hard_stop(ieee->dev);
355 	rtllib_stop_send_beacons(ieee);
356 	ieee->state = RTLLIB_LINKED_SCANNING;
357 	ieee->link_change(ieee->dev);
358 	/* wait for ps packet to be kicked out successfully */
359 	msleep(50);
360 
361 	if (ieee->ScanOperationBackupHandler)
362 		ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_BACKUP);
363 
364 	if (ieee->pHTInfo->bCurrentHTSupport && ieee->pHTInfo->bEnableHT &&
365 	    ieee->pHTInfo->bCurBW40MHz) {
366 		b40M = 1;
367 		chan_offset = ieee->pHTInfo->CurSTAExtChnlOffset;
368 		bandwidth = (enum ht_channel_width)ieee->pHTInfo->bCurBW40MHz;
369 		RT_TRACE(COMP_DBG, "Scan in 40M, force to 20M first:%d, %d\n",
370 			 chan_offset, bandwidth);
371 		ieee->SetBWModeHandler(ieee->dev, HT_CHANNEL_WIDTH_20,
372 				       HT_EXTCHNL_OFFSET_NO_EXT);
373 	}
374 
375 	rtllib_start_scan_syncro(ieee, 0);
376 
377 	if (b40M) {
378 		RT_TRACE(COMP_DBG, "Scan in 20M, back to 40M\n");
379 		if (chan_offset == HT_EXTCHNL_OFFSET_UPPER)
380 			ieee->set_chan(ieee->dev, chan + 2);
381 		else if (chan_offset == HT_EXTCHNL_OFFSET_LOWER)
382 			ieee->set_chan(ieee->dev, chan - 2);
383 		else
384 			ieee->set_chan(ieee->dev, chan);
385 		ieee->SetBWModeHandler(ieee->dev, bandwidth, chan_offset);
386 	} else {
387 		ieee->set_chan(ieee->dev, chan);
388 	}
389 
390 	if (ieee->ScanOperationBackupHandler)
391 		ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_RESTORE);
392 
393 	ieee->state = RTLLIB_LINKED;
394 	ieee->link_change(ieee->dev);
395 
396 	/* Notify AP that I wake up again */
397 	rtllib_sta_ps_send_null_frame(ieee, 0);
398 
399 	if (ieee->LinkDetectInfo.NumRecvBcnInPeriod == 0 ||
400 	    ieee->LinkDetectInfo.NumRecvDataInPeriod == 0) {
401 		ieee->LinkDetectInfo.NumRecvBcnInPeriod = 1;
402 		ieee->LinkDetectInfo.NumRecvDataInPeriod = 1;
403 	}
404 
405 	if (ieee->data_hard_resume)
406 		ieee->data_hard_resume(ieee->dev);
407 
408 	if (ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER)
409 		rtllib_start_send_beacons(ieee);
410 
411 	rtllib_wake_all_queues(ieee);
412 
413 	count = 0;
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 consisten 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 tryied 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 	int ret = 0;
631 
632 	down(&ieee->wx_sem);
633 
634 	if (ieee->ps == RTLLIB_PS_DISABLED) {
635 		wrqu->power.disabled = 1;
636 		goto exit;
637 	}
638 
639 	wrqu->power.disabled = 0;
640 
641 	if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
642 		wrqu->power.flags = IW_POWER_TIMEOUT;
643 		wrqu->power.value = ieee->ps_timeout * 1000;
644 	} else {
645 		wrqu->power.flags = IW_POWER_PERIOD;
646 		wrqu->power.value = ieee->ps_period * 1000;
647 	}
648 
649 	if ((ieee->ps & (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST)) ==
650 	    (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST))
651 		wrqu->power.flags |= IW_POWER_ALL_R;
652 	else if (ieee->ps & RTLLIB_PS_MBCAST)
653 		wrqu->power.flags |= IW_POWER_MULTICAST_R;
654 	else
655 		wrqu->power.flags |= IW_POWER_UNICAST_R;
656 
657 exit:
658 	up(&ieee->wx_sem);
659 	return ret;
660 
661 }
662 EXPORT_SYMBOL(rtllib_wx_get_power);
663