GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / linux / linux-2.6.36 / drivers / staging / rtl8192u / ieee80211 / ieee80211_softmac_wx.c
blob7051d7488ad70129c1ce98c2f5ff343d0437d96a
1 /* IEEE 802.11 SoftMAC layer
2 * Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it>
4 * Mostly extracted from the rtl8180-sa2400 driver for the
5 * in-kernel generic ieee802.11 stack.
7 * Some pieces of code might be stolen from ipw2100 driver
8 * copyright of who own it's copyright ;-)
10 * PS wx handler mostly stolen from hostap, copyright who
11 * own it's copyright ;-)
13 * released under the GPL
17 #include "ieee80211.h"
18 #ifdef ENABLE_DOT11D
19 #include "dot11d.h"
20 #endif
22 const long ieee80211_wlan_frequencies[] = {
23 2412, 2417, 2422, 2427,
24 2432, 2437, 2442, 2447,
25 2452, 2457, 2462, 2467,
26 2472, 2484
30 int ieee80211_wx_set_freq(struct ieee80211_device *ieee, struct iw_request_info *a,
31 union iwreq_data *wrqu, char *b)
33 int ret;
34 struct iw_freq *fwrq = & wrqu->freq;
36 down(&ieee->wx_sem);
38 if(ieee->iw_mode == IW_MODE_INFRA){
39 ret = -EOPNOTSUPP;
40 goto out;
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;
50 while ((c < 14) && (f != ieee80211_wlan_frequencies[c]))
51 c++;
53 /* hack to fall through */
54 fwrq->e = 0;
55 fwrq->m = c + 1;
59 if (fwrq->e > 0 || fwrq->m > 14 || fwrq->m < 1 ){
60 ret = -EOPNOTSUPP;
61 goto out;
63 }else { /* Set the channel */
65 #ifdef ENABLE_DOT11D
66 if (!(GET_DOT11D_INFO(ieee)->channel_map)[fwrq->m]) {
67 ret = -EINVAL;
68 goto out;
70 #endif
71 ieee->current_network.channel = fwrq->m;
72 ieee->set_chan(ieee->dev, ieee->current_network.channel);
74 if(ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER)
75 if(ieee->state == IEEE80211_LINKED){
77 ieee80211_stop_send_beacons(ieee);
78 ieee80211_start_send_beacons(ieee);
82 ret = 0;
83 out:
84 up(&ieee->wx_sem);
85 return ret;
89 int ieee80211_wx_get_freq(struct ieee80211_device *ieee,
90 struct iw_request_info *a,
91 union iwreq_data *wrqu, char *b)
93 struct iw_freq *fwrq = & wrqu->freq;
95 if (ieee->current_network.channel == 0)
96 return -1;
97 //NM 0.7.0 will not accept channel any more.
98 fwrq->m = ieee80211_wlan_frequencies[ieee->current_network.channel-1] * 100000;
99 fwrq->e = 1;
100 // fwrq->m = ieee->current_network.channel;
101 // fwrq->e = 0;
103 return 0;
106 int ieee80211_wx_get_wap(struct ieee80211_device *ieee,
107 struct iw_request_info *info,
108 union iwreq_data *wrqu, char *extra)
110 unsigned long flags;
112 wrqu->ap_addr.sa_family = ARPHRD_ETHER;
114 if (ieee->iw_mode == IW_MODE_MONITOR)
115 return -1;
117 /* We want avoid to give to the user inconsistent infos*/
118 spin_lock_irqsave(&ieee->lock, flags);
120 if (ieee->state != IEEE80211_LINKED &&
121 ieee->state != IEEE80211_LINKED_SCANNING &&
122 ieee->wap_set == 0)
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);
129 spin_unlock_irqrestore(&ieee->lock, flags);
131 return 0;
135 int ieee80211_wx_set_wap(struct ieee80211_device *ieee,
136 struct iw_request_info *info,
137 union iwreq_data *awrq,
138 char *extra)
141 int ret = 0;
142 u8 zero[] = {0,0,0,0,0,0};
143 unsigned long flags;
145 short ifup = ieee->proto_started;//dev->flags & IFF_UP;
146 struct sockaddr *temp = (struct sockaddr *)awrq;
148 ieee->sync_scan_hurryup = 1;
150 down(&ieee->wx_sem);
151 /* use ifconfig hw ether */
152 if (ieee->iw_mode == IW_MODE_MASTER){
153 ret = -1;
154 goto out;
157 if (temp->sa_family != ARPHRD_ETHER){
158 ret = -EINVAL;
159 goto out;
162 if (ifup)
163 ieee80211_stop_protocol(ieee);
165 /* just to avoid to give inconsistent infos in the
166 * get wx method. not really needed otherwise
168 spin_lock_irqsave(&ieee->lock, flags);
170 memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN);
171 ieee->wap_set = memcmp(temp->sa_data, zero,ETH_ALEN)!=0;
173 spin_unlock_irqrestore(&ieee->lock, flags);
175 if (ifup)
176 ieee80211_start_protocol(ieee);
177 out:
178 up(&ieee->wx_sem);
179 return ret;
182 int ieee80211_wx_get_essid(struct ieee80211_device *ieee, struct iw_request_info *a,union iwreq_data *wrqu,char *b)
184 int len,ret = 0;
185 unsigned long flags;
187 if (ieee->iw_mode == IW_MODE_MONITOR)
188 return -1;
190 /* We want avoid to give to the user inconsistent infos*/
191 spin_lock_irqsave(&ieee->lock, flags);
193 if (ieee->current_network.ssid[0] == '\0' ||
194 ieee->current_network.ssid_len == 0){
195 ret = -1;
196 goto out;
199 if (ieee->state != IEEE80211_LINKED &&
200 ieee->state != IEEE80211_LINKED_SCANNING &&
201 ieee->ssid_set == 0){
202 ret = -1;
203 goto out;
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;
210 out:
211 spin_unlock_irqrestore(&ieee->lock, flags);
213 return ret;
217 int ieee80211_wx_set_rate(struct ieee80211_device *ieee,
218 struct iw_request_info *info,
219 union iwreq_data *wrqu, char *extra)
222 u32 target_rate = wrqu->bitrate.value;
224 ieee->rate = target_rate/100000;
225 return 0;
230 int ieee80211_wx_get_rate(struct ieee80211_device *ieee,
231 struct iw_request_info *info,
232 union iwreq_data *wrqu, char *extra)
234 u32 tmp_rate;
235 tmp_rate = TxCountToDataRate(ieee, ieee->softmac_stats.CurrentShowTxate);
237 wrqu->bitrate.value = tmp_rate * 500000;
239 return 0;
243 int ieee80211_wx_set_rts(struct ieee80211_device *ieee,
244 struct iw_request_info *info,
245 union iwreq_data *wrqu, char *extra)
247 if (wrqu->rts.disabled || !wrqu->rts.fixed)
248 ieee->rts = DEFAULT_RTS_THRESHOLD;
249 else
251 if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
252 wrqu->rts.value > MAX_RTS_THRESHOLD)
253 return -EINVAL;
254 ieee->rts = wrqu->rts.value;
256 return 0;
259 int ieee80211_wx_get_rts(struct ieee80211_device *ieee,
260 struct iw_request_info *info,
261 union iwreq_data *wrqu, char *extra)
263 wrqu->rts.value = ieee->rts;
264 wrqu->rts.fixed = 0; /* no auto select */
265 wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD);
266 return 0;
268 int ieee80211_wx_set_mode(struct ieee80211_device *ieee, struct iw_request_info *a,
269 union iwreq_data *wrqu, char *b)
272 ieee->sync_scan_hurryup = 1;
274 down(&ieee->wx_sem);
276 if (wrqu->mode == ieee->iw_mode)
277 goto out;
279 if (wrqu->mode == IW_MODE_MONITOR){
281 ieee->dev->type = ARPHRD_IEEE80211;
282 }else{
283 ieee->dev->type = ARPHRD_ETHER;
286 if (!ieee->proto_started){
287 ieee->iw_mode = wrqu->mode;
288 }else{
289 ieee80211_stop_protocol(ieee);
290 ieee->iw_mode = wrqu->mode;
291 ieee80211_start_protocol(ieee);
294 out:
295 up(&ieee->wx_sem);
296 return 0;
299 void ieee80211_wx_sync_scan_wq(struct work_struct *work)
301 struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, wx_sync_scan_wq);
302 short chan;
303 HT_EXTCHNL_OFFSET chan_offset=0;
304 HT_CHANNEL_WIDTH bandwidth=0;
305 int b40M = 0;
306 static int count = 0;
307 chan = ieee->current_network.channel;
308 netif_carrier_off(ieee->dev);
310 if (ieee->data_hard_stop)
311 ieee->data_hard_stop(ieee->dev);
313 ieee80211_stop_send_beacons(ieee);
315 ieee->state = IEEE80211_LINKED_SCANNING;
316 ieee->link_change(ieee->dev);
317 ieee->InitialGainHandler(ieee->dev,IG_Backup);
318 if (ieee->pHTInfo->bCurrentHTSupport && ieee->pHTInfo->bEnableHT && ieee->pHTInfo->bCurBW40MHz) {
319 b40M = 1;
320 chan_offset = ieee->pHTInfo->CurSTAExtChnlOffset;
321 bandwidth = (HT_CHANNEL_WIDTH)ieee->pHTInfo->bCurBW40MHz;
322 printk("Scan in 40M, force to 20M first:%d, %d\n", chan_offset, bandwidth);
323 ieee->SetBWModeHandler(ieee->dev, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT);
325 ieee80211_start_scan_syncro(ieee);
326 if (b40M) {
327 printk("Scan in 20M, back to 40M\n");
328 if (chan_offset == HT_EXTCHNL_OFFSET_UPPER)
329 ieee->set_chan(ieee->dev, chan + 2);
330 else if (chan_offset == HT_EXTCHNL_OFFSET_LOWER)
331 ieee->set_chan(ieee->dev, chan - 2);
332 else
333 ieee->set_chan(ieee->dev, chan);
334 ieee->SetBWModeHandler(ieee->dev, bandwidth, chan_offset);
335 } else {
336 ieee->set_chan(ieee->dev, chan);
339 ieee->InitialGainHandler(ieee->dev,IG_Restore);
340 ieee->state = IEEE80211_LINKED;
341 ieee->link_change(ieee->dev);
342 // To prevent the immediately calling watch_dog after scan.
343 if(ieee->LinkDetectInfo.NumRecvBcnInPeriod==0||ieee->LinkDetectInfo.NumRecvDataInPeriod==0 )
345 ieee->LinkDetectInfo.NumRecvBcnInPeriod = 1;
346 ieee->LinkDetectInfo.NumRecvDataInPeriod= 1;
348 if (ieee->data_hard_resume)
349 ieee->data_hard_resume(ieee->dev);
351 if(ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER)
352 ieee80211_start_send_beacons(ieee);
354 netif_carrier_on(ieee->dev);
355 count = 0;
356 up(&ieee->wx_sem);
360 int ieee80211_wx_set_scan(struct ieee80211_device *ieee, struct iw_request_info *a,
361 union iwreq_data *wrqu, char *b)
363 int ret = 0;
365 down(&ieee->wx_sem);
367 if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)){
368 ret = -1;
369 goto out;
372 if ( ieee->state == IEEE80211_LINKED){
373 queue_work(ieee->wq, &ieee->wx_sync_scan_wq);
374 /* intentionally forget to up sem */
375 return 0;
378 out:
379 up(&ieee->wx_sem);
380 return ret;
383 int ieee80211_wx_set_essid(struct ieee80211_device *ieee,
384 struct iw_request_info *a,
385 union iwreq_data *wrqu, char *extra)
388 int ret=0,len;
389 short proto_started;
390 unsigned long flags;
392 ieee->sync_scan_hurryup = 1;
393 down(&ieee->wx_sem);
395 proto_started = ieee->proto_started;
397 if (wrqu->essid.length > IW_ESSID_MAX_SIZE){
398 ret= -E2BIG;
399 goto out;
402 if (ieee->iw_mode == IW_MODE_MONITOR){
403 ret= -1;
404 goto out;
407 if(proto_started)
408 ieee80211_stop_protocol(ieee);
411 /* this is just to be sure that the GET wx callback
412 * has consisten infos. not needed otherwise
414 spin_lock_irqsave(&ieee->lock, flags);
416 if (wrqu->essid.flags && wrqu->essid.length) {
417 //first flush current network.ssid
418 len = ((wrqu->essid.length-1) < IW_ESSID_MAX_SIZE) ? (wrqu->essid.length-1) : IW_ESSID_MAX_SIZE;
419 strncpy(ieee->current_network.ssid, extra, len+1);
420 ieee->current_network.ssid_len = len+1;
421 ieee->ssid_set = 1;
423 else{
424 ieee->ssid_set = 0;
425 ieee->current_network.ssid[0] = '\0';
426 ieee->current_network.ssid_len = 0;
428 spin_unlock_irqrestore(&ieee->lock, flags);
430 if (proto_started)
431 ieee80211_start_protocol(ieee);
432 out:
433 up(&ieee->wx_sem);
434 return ret;
437 int ieee80211_wx_get_mode(struct ieee80211_device *ieee, struct iw_request_info *a,
438 union iwreq_data *wrqu, char *b)
441 wrqu->mode = ieee->iw_mode;
442 return 0;
445 int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee,
446 struct iw_request_info *info,
447 union iwreq_data *wrqu, char *extra)
450 int *parms = (int *)extra;
451 int enable = (parms[0] > 0);
452 short prev = ieee->raw_tx;
454 down(&ieee->wx_sem);
456 if(enable)
457 ieee->raw_tx = 1;
458 else
459 ieee->raw_tx = 0;
461 printk(KERN_INFO"raw TX is %s\n",
462 ieee->raw_tx ? "enabled" : "disabled");
464 if(ieee->iw_mode == IW_MODE_MONITOR)
466 if(prev == 0 && ieee->raw_tx){
467 if (ieee->data_hard_resume)
468 ieee->data_hard_resume(ieee->dev);
470 netif_carrier_on(ieee->dev);
473 if(prev && ieee->raw_tx == 1)
474 netif_carrier_off(ieee->dev);
477 up(&ieee->wx_sem);
479 return 0;
482 int ieee80211_wx_get_name(struct ieee80211_device *ieee,
483 struct iw_request_info *info,
484 union iwreq_data *wrqu, char *extra)
486 strcpy(wrqu->name, "802.11");
487 if(ieee->modulation & IEEE80211_CCK_MODULATION){
488 strcat(wrqu->name, "b");
489 if(ieee->modulation & IEEE80211_OFDM_MODULATION)
490 strcat(wrqu->name, "/g");
491 }else if(ieee->modulation & IEEE80211_OFDM_MODULATION)
492 strcat(wrqu->name, "g");
493 if (ieee->mode & (IEEE_N_24G | IEEE_N_5G))
494 strcat(wrqu->name, "/n");
496 if((ieee->state == IEEE80211_LINKED) ||
497 (ieee->state == IEEE80211_LINKED_SCANNING))
498 strcat(wrqu->name," linked");
499 else if(ieee->state != IEEE80211_NOLINK)
500 strcat(wrqu->name," link..");
503 return 0;
507 /* this is mostly stolen from hostap */
508 int ieee80211_wx_set_power(struct ieee80211_device *ieee,
509 struct iw_request_info *info,
510 union iwreq_data *wrqu, char *extra)
512 int ret = 0;
513 down(&ieee->wx_sem);
515 if (wrqu->power.disabled){
516 ieee->ps = IEEE80211_PS_DISABLED;
517 goto exit;
519 if (wrqu->power.flags & IW_POWER_TIMEOUT) {
520 //ieee->ps_period = wrqu->power.value / 1000;
521 ieee->ps_timeout = wrqu->power.value / 1000;
524 if (wrqu->power.flags & IW_POWER_PERIOD) {
526 //ieee->ps_timeout = wrqu->power.value / 1000;
527 ieee->ps_period = wrqu->power.value / 1000;
528 //wrq->value / 1024;
531 switch (wrqu->power.flags & IW_POWER_MODE) {
532 case IW_POWER_UNICAST_R:
533 ieee->ps = IEEE80211_PS_UNICAST;
534 break;
535 case IW_POWER_MULTICAST_R:
536 ieee->ps = IEEE80211_PS_MBCAST;
537 break;
538 case IW_POWER_ALL_R:
539 ieee->ps = IEEE80211_PS_UNICAST | IEEE80211_PS_MBCAST;
540 break;
542 case IW_POWER_ON:
543 // ieee->ps = IEEE80211_PS_DISABLED;
544 break;
546 default:
547 ret = -EINVAL;
548 goto exit;
551 exit:
552 up(&ieee->wx_sem);
553 return ret;
557 /* this is stolen from hostap */
558 int ieee80211_wx_get_power(struct ieee80211_device *ieee,
559 struct iw_request_info *info,
560 union iwreq_data *wrqu, char *extra)
562 int ret =0;
564 down(&ieee->wx_sem);
566 if(ieee->ps == IEEE80211_PS_DISABLED){
567 wrqu->power.disabled = 1;
568 goto exit;
571 wrqu->power.disabled = 0;
573 if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
574 wrqu->power.flags = IW_POWER_TIMEOUT;
575 wrqu->power.value = ieee->ps_timeout * 1000;
576 } else {
577 // ret = -EOPNOTSUPP;
578 // goto exit;
579 wrqu->power.flags = IW_POWER_PERIOD;
580 wrqu->power.value = ieee->ps_period * 1000;
581 //ieee->current_network.dtim_period * ieee->current_network.beacon_interval * 1024;
584 if ((ieee->ps & (IEEE80211_PS_MBCAST | IEEE80211_PS_UNICAST)) == (IEEE80211_PS_MBCAST | IEEE80211_PS_UNICAST))
585 wrqu->power.flags |= IW_POWER_ALL_R;
586 else if (ieee->ps & IEEE80211_PS_MBCAST)
587 wrqu->power.flags |= IW_POWER_MULTICAST_R;
588 else
589 wrqu->power.flags |= IW_POWER_UNICAST_R;
591 exit:
592 up(&ieee->wx_sem);
593 return ret;
596 EXPORT_SYMBOL(ieee80211_wx_get_essid);
597 EXPORT_SYMBOL(ieee80211_wx_set_essid);
598 EXPORT_SYMBOL(ieee80211_wx_set_rate);
599 EXPORT_SYMBOL(ieee80211_wx_get_rate);
600 EXPORT_SYMBOL(ieee80211_wx_set_wap);
601 EXPORT_SYMBOL(ieee80211_wx_get_wap);
602 EXPORT_SYMBOL(ieee80211_wx_set_mode);
603 EXPORT_SYMBOL(ieee80211_wx_get_mode);
604 EXPORT_SYMBOL(ieee80211_wx_set_scan);
605 EXPORT_SYMBOL(ieee80211_wx_get_freq);
606 EXPORT_SYMBOL(ieee80211_wx_set_freq);
607 EXPORT_SYMBOL(ieee80211_wx_set_rawtx);
608 EXPORT_SYMBOL(ieee80211_wx_get_name);
609 EXPORT_SYMBOL(ieee80211_wx_set_power);
610 EXPORT_SYMBOL(ieee80211_wx_get_power);
611 EXPORT_SYMBOL(ieee80211_wlan_frequencies);
612 EXPORT_SYMBOL(ieee80211_wx_set_rts);
613 EXPORT_SYMBOL(ieee80211_wx_get_rts);