• 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 "ieee80211.h"
20 #include "dot11d.h"
21 /* FIXME: add A freqs */
22 
23 const long ieee80211_wlan_frequencies[] = {
24 	2412, 2417, 2422, 2427,
25 	2432, 2437, 2442, 2447,
26 	2452, 2457, 2462, 2467,
27 	2472, 2484
28 };
29 EXPORT_SYMBOL(ieee80211_wlan_frequencies);
30 
ieee80211_wx_set_freq(struct ieee80211_device * ieee,struct iw_request_info * a,union iwreq_data * wrqu,char * b)31 int ieee80211_wx_set_freq(struct ieee80211_device *ieee, struct iw_request_info *a,
32 			     union iwreq_data *wrqu, char *b)
33 {
34 	int ret;
35 	struct iw_freq *fwrq = & wrqu->freq;
36 
37 	down(&ieee->wx_sem);
38 
39 	if(ieee->iw_mode == IW_MODE_INFRA){
40 		ret = -EOPNOTSUPP;
41 		goto out;
42 	}
43 
44 	/* if setting by freq convert to channel */
45 	if (fwrq->e == 1) {
46 		if ((fwrq->m >= (int) 2.412e8 &&
47 		     fwrq->m <= (int) 2.487e8)) {
48 			int f = fwrq->m / 100000;
49 			int c = 0;
50 
51 			while ((c < 14) && (f != ieee80211_wlan_frequencies[c]))
52 				c++;
53 
54 			/* hack to fall through */
55 			fwrq->e = 0;
56 			fwrq->m = c + 1;
57 		}
58 	}
59 
60 	if (fwrq->e > 0 || fwrq->m > 14 || fwrq->m < 1 ){
61 		ret = -EOPNOTSUPP;
62 		goto out;
63 
64 	}else { /* Set the channel */
65 
66 		if (!(GET_DOT11D_INFO(ieee)->channel_map)[fwrq->m]) {
67 			ret = -EINVAL;
68 			goto out;
69 		}
70 		ieee->current_network.channel = fwrq->m;
71 		ieee->set_chan(ieee->dev, ieee->current_network.channel);
72 
73 		if(ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER)
74 			if(ieee->state == IEEE80211_LINKED){
75 
76 			ieee80211_stop_send_beacons(ieee);
77 			ieee80211_start_send_beacons(ieee);
78 			}
79 	}
80 
81 	ret = 0;
82 out:
83 	up(&ieee->wx_sem);
84 	return ret;
85 }
86 EXPORT_SYMBOL(ieee80211_wx_set_freq);
87 
ieee80211_wx_get_freq(struct ieee80211_device * ieee,struct iw_request_info * a,union iwreq_data * wrqu,char * b)88 int ieee80211_wx_get_freq(struct ieee80211_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 	//NM 0.7.0 will not accept channel any more.
97 	fwrq->m = ieee80211_wlan_frequencies[ieee->current_network.channel-1] * 100000;
98 	fwrq->e = 1;
99 //	fwrq->m = ieee->current_network.channel;
100 //	fwrq->e = 0;
101 
102 	return 0;
103 }
104 EXPORT_SYMBOL(ieee80211_wx_get_freq);
105 
ieee80211_wx_get_wap(struct ieee80211_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)106 int ieee80211_wx_get_wap(struct ieee80211_device *ieee,
107 			    struct iw_request_info *info,
108 			    union iwreq_data *wrqu, char *extra)
109 {
110 	unsigned long flags;
111 
112 	wrqu->ap_addr.sa_family = ARPHRD_ETHER;
113 
114 	if (ieee->iw_mode == IW_MODE_MONITOR)
115 		return -1;
116 
117 	/* We want avoid to give to the user inconsistent infos*/
118 	spin_lock_irqsave(&ieee->lock, flags);
119 
120 	if (ieee->state != IEEE80211_LINKED &&
121 		ieee->state != IEEE80211_LINKED_SCANNING &&
122 		ieee->wap_set == 0)
123 
124 		memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
125 	else
126 		memcpy(wrqu->ap_addr.sa_data,
127 		       ieee->current_network.bssid, ETH_ALEN);
128 
129 	spin_unlock_irqrestore(&ieee->lock, flags);
130 
131 	return 0;
132 }
133 EXPORT_SYMBOL(ieee80211_wx_get_wap);
134 
ieee80211_wx_set_wap(struct ieee80211_device * ieee,struct iw_request_info * info,union iwreq_data * awrq,char * extra)135 int ieee80211_wx_set_wap(struct ieee80211_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;//dev->flags & IFF_UP;
145 	struct sockaddr *temp = (struct sockaddr *)awrq;
146 
147 	ieee->sync_scan_hurryup = 1;
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 (ifup)
162 		ieee80211_stop_protocol(ieee);
163 
164 	/* just to avoid to give inconsistent infos in the
165 	 * get wx method. not really needed otherwise
166 	 */
167 	spin_lock_irqsave(&ieee->lock, flags);
168 
169 	memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN);
170 	ieee->wap_set = !is_zero_ether_addr(temp->sa_data);
171 
172 	spin_unlock_irqrestore(&ieee->lock, flags);
173 
174 	if (ifup)
175 		ieee80211_start_protocol(ieee);
176 out:
177 	up(&ieee->wx_sem);
178 	return ret;
179 }
180 EXPORT_SYMBOL(ieee80211_wx_set_wap);
181 
ieee80211_wx_get_essid(struct ieee80211_device * ieee,struct iw_request_info * a,union iwreq_data * wrqu,char * b)182  int ieee80211_wx_get_essid(struct ieee80211_device *ieee, struct iw_request_info *a,union iwreq_data *wrqu,char *b)
183 {
184 	int len, ret = 0;
185 	unsigned long flags;
186 
187 	if (ieee->iw_mode == IW_MODE_MONITOR)
188 		return -1;
189 
190 	/* We want avoid to give to the user inconsistent infos*/
191 	spin_lock_irqsave(&ieee->lock, flags);
192 
193 	if (ieee->current_network.ssid[0] == '\0' ||
194 		ieee->current_network.ssid_len == 0){
195 		ret = -1;
196 		goto out;
197 	}
198 
199 	if (ieee->state != IEEE80211_LINKED &&
200 		ieee->state != IEEE80211_LINKED_SCANNING &&
201 		ieee->ssid_set == 0){
202 		ret = -1;
203 		goto out;
204 	}
205 	len = ieee->current_network.ssid_len;
206 	wrqu->essid.length = len;
207 	strncpy(b, ieee->current_network.ssid, len);
208 	wrqu->essid.flags = 1;
209 
210 out:
211 	spin_unlock_irqrestore(&ieee->lock, flags);
212 
213 	return ret;
214 
215 }
216 EXPORT_SYMBOL(ieee80211_wx_get_essid);
217 
ieee80211_wx_set_rate(struct ieee80211_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)218 int ieee80211_wx_set_rate(struct ieee80211_device *ieee,
219 			     struct iw_request_info *info,
220 			     union iwreq_data *wrqu, char *extra)
221 {
222 
223 	u32 target_rate = wrqu->bitrate.value;
224 
225 	ieee->rate = target_rate/100000;
226 	//FIXME: we might want to limit rate also in management protocols.
227 	return 0;
228 }
229 EXPORT_SYMBOL(ieee80211_wx_set_rate);
230 
ieee80211_wx_get_rate(struct ieee80211_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)231 int ieee80211_wx_get_rate(struct ieee80211_device *ieee,
232 			     struct iw_request_info *info,
233 			     union iwreq_data *wrqu, char *extra)
234 {
235 	u32 tmp_rate;
236 	tmp_rate = TxCountToDataRate(ieee, ieee->softmac_stats.CurrentShowTxate);
237 
238 	wrqu->bitrate.value = tmp_rate * 500000;
239 
240 	return 0;
241 }
242 EXPORT_SYMBOL(ieee80211_wx_get_rate);
243 
ieee80211_wx_set_rts(struct ieee80211_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)244 int ieee80211_wx_set_rts(struct ieee80211_device *ieee,
245 			     struct iw_request_info *info,
246 			     union iwreq_data *wrqu, char *extra)
247 {
248 	if (wrqu->rts.disabled || !wrqu->rts.fixed)
249 		ieee->rts = DEFAULT_RTS_THRESHOLD;
250 	else
251 	{
252 		if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
253 				wrqu->rts.value > MAX_RTS_THRESHOLD)
254 			return -EINVAL;
255 		ieee->rts = wrqu->rts.value;
256 	}
257 	return 0;
258 }
259 EXPORT_SYMBOL(ieee80211_wx_set_rts);
260 
ieee80211_wx_get_rts(struct ieee80211_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)261 int ieee80211_wx_get_rts(struct ieee80211_device *ieee,
262 			     struct iw_request_info *info,
263 			     union iwreq_data *wrqu, char *extra)
264 {
265 	wrqu->rts.value = ieee->rts;
266 	wrqu->rts.fixed = 0;	/* no auto select */
267 	wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD);
268 	return 0;
269 }
270 EXPORT_SYMBOL(ieee80211_wx_get_rts);
271 
ieee80211_wx_set_mode(struct ieee80211_device * ieee,struct iw_request_info * a,union iwreq_data * wrqu,char * b)272 int ieee80211_wx_set_mode(struct ieee80211_device *ieee, struct iw_request_info *a,
273 			     union iwreq_data *wrqu, char *b)
274 {
275 
276 	ieee->sync_scan_hurryup = 1;
277 
278 	down(&ieee->wx_sem);
279 
280 	if (wrqu->mode == ieee->iw_mode)
281 		goto out;
282 
283 	if (wrqu->mode == IW_MODE_MONITOR){
284 
285 		ieee->dev->type = ARPHRD_IEEE80211;
286 	}else{
287 		ieee->dev->type = ARPHRD_ETHER;
288 	}
289 
290 	if (!ieee->proto_started){
291 		ieee->iw_mode = wrqu->mode;
292 	}else{
293 		ieee80211_stop_protocol(ieee);
294 		ieee->iw_mode = wrqu->mode;
295 		ieee80211_start_protocol(ieee);
296 	}
297 
298 out:
299 	up(&ieee->wx_sem);
300 	return 0;
301 }
302 EXPORT_SYMBOL(ieee80211_wx_set_mode);
303 
ieee80211_wx_sync_scan_wq(struct work_struct * work)304 void ieee80211_wx_sync_scan_wq(struct work_struct *work)
305 {
306 	struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, wx_sync_scan_wq);
307 	short chan;
308 	HT_EXTCHNL_OFFSET chan_offset=0;
309 	HT_CHANNEL_WIDTH bandwidth=0;
310 	int b40M = 0;
311 	static int count;
312 	chan = ieee->current_network.channel;
313 	netif_carrier_off(ieee->dev);
314 
315 	if (ieee->data_hard_stop)
316 		ieee->data_hard_stop(ieee->dev);
317 
318 	ieee80211_stop_send_beacons(ieee);
319 
320 	ieee->state = IEEE80211_LINKED_SCANNING;
321 	ieee->link_change(ieee->dev);
322 	ieee->InitialGainHandler(ieee->dev, IG_Backup);
323 	if (ieee->pHTInfo->bCurrentHTSupport && ieee->pHTInfo->bEnableHT && ieee->pHTInfo->bCurBW40MHz) {
324 		b40M = 1;
325 		chan_offset = ieee->pHTInfo->CurSTAExtChnlOffset;
326 		bandwidth = (HT_CHANNEL_WIDTH)ieee->pHTInfo->bCurBW40MHz;
327 		printk("Scan in 40M, force to 20M first:%d, %d\n", chan_offset, bandwidth);
328 		ieee->SetBWModeHandler(ieee->dev, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT);
329 		}
330 	ieee80211_start_scan_syncro(ieee);
331 	if (b40M) {
332 		printk("Scan in 20M, back to 40M\n");
333 		if (chan_offset == HT_EXTCHNL_OFFSET_UPPER)
334 			ieee->set_chan(ieee->dev, chan + 2);
335 		else if (chan_offset == HT_EXTCHNL_OFFSET_LOWER)
336 			ieee->set_chan(ieee->dev, chan - 2);
337 		else
338 			ieee->set_chan(ieee->dev, chan);
339 		ieee->SetBWModeHandler(ieee->dev, bandwidth, chan_offset);
340 	} else {
341 		ieee->set_chan(ieee->dev, chan);
342 	}
343 
344 	ieee->InitialGainHandler(ieee->dev, IG_Restore);
345 	ieee->state = IEEE80211_LINKED;
346 	ieee->link_change(ieee->dev);
347 	// To prevent the immediately calling watch_dog after scan.
348 	if(ieee->LinkDetectInfo.NumRecvBcnInPeriod==0||ieee->LinkDetectInfo.NumRecvDataInPeriod==0 )
349 	{
350 		ieee->LinkDetectInfo.NumRecvBcnInPeriod = 1;
351 		ieee->LinkDetectInfo.NumRecvDataInPeriod= 1;
352 	}
353 	if (ieee->data_hard_resume)
354 		ieee->data_hard_resume(ieee->dev);
355 
356 	if(ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER)
357 		ieee80211_start_send_beacons(ieee);
358 
359 	netif_carrier_on(ieee->dev);
360 	count = 0;
361 	up(&ieee->wx_sem);
362 
363 }
364 
ieee80211_wx_set_scan(struct ieee80211_device * ieee,struct iw_request_info * a,union iwreq_data * wrqu,char * b)365 int ieee80211_wx_set_scan(struct ieee80211_device *ieee, struct iw_request_info *a,
366 			     union iwreq_data *wrqu, char *b)
367 {
368 	int ret = 0;
369 
370 	down(&ieee->wx_sem);
371 
372 	if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)){
373 		ret = -1;
374 		goto out;
375 	}
376 
377 	if ( ieee->state == IEEE80211_LINKED){
378 		queue_work(ieee->wq, &ieee->wx_sync_scan_wq);
379 		/* intentionally forget to up sem */
380 		return 0;
381 	}
382 
383 out:
384 	up(&ieee->wx_sem);
385 	return ret;
386 }
387 EXPORT_SYMBOL(ieee80211_wx_set_scan);
388 
ieee80211_wx_set_essid(struct ieee80211_device * ieee,struct iw_request_info * a,union iwreq_data * wrqu,char * extra)389 int ieee80211_wx_set_essid(struct ieee80211_device *ieee,
390 			      struct iw_request_info *a,
391 			      union iwreq_data *wrqu, char *extra)
392 {
393 
394 	int ret=0,len;
395 	short proto_started;
396 	unsigned long flags;
397 
398 	ieee->sync_scan_hurryup = 1;
399 	down(&ieee->wx_sem);
400 
401 	proto_started = ieee->proto_started;
402 
403 	if (wrqu->essid.length > IW_ESSID_MAX_SIZE){
404 		ret= -E2BIG;
405 		goto out;
406 	}
407 
408 	if (ieee->iw_mode == IW_MODE_MONITOR){
409 		ret= -1;
410 		goto out;
411 	}
412 
413 	if(proto_started)
414 		ieee80211_stop_protocol(ieee);
415 
416 
417 	/* this is just to be sure that the GET wx callback
418 	 * has consisten infos. not needed otherwise
419 	 */
420 	spin_lock_irqsave(&ieee->lock, flags);
421 
422 	if (wrqu->essid.flags && wrqu->essid.length) {
423 		//first flush current network.ssid
424 		len = ((wrqu->essid.length-1) < IW_ESSID_MAX_SIZE) ? (wrqu->essid.length-1) : IW_ESSID_MAX_SIZE;
425 		strncpy(ieee->current_network.ssid, extra, len+1);
426 		ieee->current_network.ssid_len = len+1;
427 		ieee->ssid_set = 1;
428 	}
429 	else{
430 		ieee->ssid_set = 0;
431 		ieee->current_network.ssid[0] = '\0';
432 		ieee->current_network.ssid_len = 0;
433 	}
434 	spin_unlock_irqrestore(&ieee->lock, flags);
435 
436 	if (proto_started)
437 		ieee80211_start_protocol(ieee);
438 out:
439 	up(&ieee->wx_sem);
440 	return ret;
441 }
442 EXPORT_SYMBOL(ieee80211_wx_set_essid);
443 
ieee80211_wx_get_mode(struct ieee80211_device * ieee,struct iw_request_info * a,union iwreq_data * wrqu,char * b)444  int ieee80211_wx_get_mode(struct ieee80211_device *ieee, struct iw_request_info *a,
445 			     union iwreq_data *wrqu, char *b)
446 {
447 
448 	wrqu->mode = ieee->iw_mode;
449 	return 0;
450 }
451 EXPORT_SYMBOL(ieee80211_wx_get_mode);
452 
ieee80211_wx_set_rawtx(struct ieee80211_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)453  int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee,
454 			       struct iw_request_info *info,
455 			       union iwreq_data *wrqu, char *extra)
456 {
457 
458 	int *parms = (int *)extra;
459 	int enable = (parms[0] > 0);
460 	short prev = ieee->raw_tx;
461 
462 	down(&ieee->wx_sem);
463 
464 	if(enable)
465 		ieee->raw_tx = 1;
466 	else
467 		ieee->raw_tx = 0;
468 
469 	printk(KERN_INFO"raw TX is %s\n",
470 	      ieee->raw_tx ? "enabled" : "disabled");
471 
472 	if(ieee->iw_mode == IW_MODE_MONITOR)
473 	{
474 		if(prev == 0 && ieee->raw_tx){
475 			if (ieee->data_hard_resume)
476 				ieee->data_hard_resume(ieee->dev);
477 
478 			netif_carrier_on(ieee->dev);
479 		}
480 
481 		if(prev && ieee->raw_tx == 1)
482 			netif_carrier_off(ieee->dev);
483 	}
484 
485 	up(&ieee->wx_sem);
486 
487 	return 0;
488 }
489 EXPORT_SYMBOL(ieee80211_wx_set_rawtx);
490 
ieee80211_wx_get_name(struct ieee80211_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)491 int ieee80211_wx_get_name(struct ieee80211_device *ieee,
492 			     struct iw_request_info *info,
493 			     union iwreq_data *wrqu, char *extra)
494 {
495 	strlcpy(wrqu->name, "802.11", IFNAMSIZ);
496 	if (ieee->modulation & IEEE80211_CCK_MODULATION) {
497 		strlcat(wrqu->name, "b", IFNAMSIZ);
498 		if (ieee->modulation & IEEE80211_OFDM_MODULATION)
499 			strlcat(wrqu->name, "/g", IFNAMSIZ);
500 	} else if (ieee->modulation & IEEE80211_OFDM_MODULATION) {
501 		strlcat(wrqu->name, "g", IFNAMSIZ);
502 	}
503 
504 	if (ieee->mode & (IEEE_N_24G | IEEE_N_5G))
505 		strlcat(wrqu->name, "/n", IFNAMSIZ);
506 
507 	if ((ieee->state == IEEE80211_LINKED) ||
508 	    (ieee->state == IEEE80211_LINKED_SCANNING))
509 		strlcat(wrqu->name, " linked", IFNAMSIZ);
510 	else if (ieee->state != IEEE80211_NOLINK)
511 		strlcat(wrqu->name, " link..", IFNAMSIZ);
512 
513 	return 0;
514 }
515 EXPORT_SYMBOL(ieee80211_wx_get_name);
516 
517 /* this is mostly stolen from hostap */
ieee80211_wx_set_power(struct ieee80211_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)518 int ieee80211_wx_set_power(struct ieee80211_device *ieee,
519 				 struct iw_request_info *info,
520 				 union iwreq_data *wrqu, char *extra)
521 {
522 	int ret = 0;
523 	down(&ieee->wx_sem);
524 
525 	if (wrqu->power.disabled){
526 		ieee->ps = IEEE80211_PS_DISABLED;
527 		goto exit;
528 	}
529 	if (wrqu->power.flags & IW_POWER_TIMEOUT) {
530 		//ieee->ps_period = wrqu->power.value / 1000;
531 		ieee->ps_timeout = wrqu->power.value / 1000;
532 	}
533 
534 	if (wrqu->power.flags & IW_POWER_PERIOD) {
535 
536 		//ieee->ps_timeout = wrqu->power.value / 1000;
537 		ieee->ps_period = wrqu->power.value / 1000;
538 		//wrq->value / 1024;
539 
540 	}
541 	switch (wrqu->power.flags & IW_POWER_MODE) {
542 	case IW_POWER_UNICAST_R:
543 		ieee->ps = IEEE80211_PS_UNICAST;
544 		break;
545 	case IW_POWER_MULTICAST_R:
546 		ieee->ps = IEEE80211_PS_MBCAST;
547 		break;
548 	case IW_POWER_ALL_R:
549 		ieee->ps = IEEE80211_PS_UNICAST | IEEE80211_PS_MBCAST;
550 		break;
551 
552 	case IW_POWER_ON:
553 	//	ieee->ps = IEEE80211_PS_DISABLED;
554 		break;
555 
556 	default:
557 		ret = -EINVAL;
558 		goto exit;
559 
560 	}
561 exit:
562 	up(&ieee->wx_sem);
563 	return ret;
564 
565 }
566 EXPORT_SYMBOL(ieee80211_wx_set_power);
567 
568 /* this is stolen from hostap */
ieee80211_wx_get_power(struct ieee80211_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)569 int ieee80211_wx_get_power(struct ieee80211_device *ieee,
570 				 struct iw_request_info *info,
571 				 union iwreq_data *wrqu, char *extra)
572 {
573 	down(&ieee->wx_sem);
574 
575 	if(ieee->ps == IEEE80211_PS_DISABLED){
576 		wrqu->power.disabled = 1;
577 		goto exit;
578 	}
579 
580 	wrqu->power.disabled = 0;
581 
582 	if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
583 		wrqu->power.flags = IW_POWER_TIMEOUT;
584 		wrqu->power.value = ieee->ps_timeout * 1000;
585 	} else {
586 //		ret = -EOPNOTSUPP;
587 //		goto exit;
588 		wrqu->power.flags = IW_POWER_PERIOD;
589 		wrqu->power.value = ieee->ps_period * 1000;
590 //ieee->current_network.dtim_period * ieee->current_network.beacon_interval * 1024;
591 	}
592 
593        if ((ieee->ps & (IEEE80211_PS_MBCAST | IEEE80211_PS_UNICAST)) == (IEEE80211_PS_MBCAST | IEEE80211_PS_UNICAST))
594 		wrqu->power.flags |= IW_POWER_ALL_R;
595 	else if (ieee->ps & IEEE80211_PS_MBCAST)
596 		wrqu->power.flags |= IW_POWER_MULTICAST_R;
597 	else
598 		wrqu->power.flags |= IW_POWER_UNICAST_R;
599 
600 exit:
601 	up(&ieee->wx_sem);
602 	return 0;
603 
604 }
605 EXPORT_SYMBOL(ieee80211_wx_get_power);
606