Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ieee80211_softmac_wx.c
Go to the documentation of this file.
1 /* IEEE 802.11 SoftMAC layer
2  * Copyright (c) 2005 Andrea Merello <[email protected]>
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 
24  2412, 2417, 2422, 2427,
25  2432, 2437, 2442, 2447,
26  2452, 2457, 2462, 2467,
27  2472, 2484
28 };
29 
30 
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 
78  }
79  }
80 
81  ret = 0;
82 out:
83  up(&ieee->wx_sem);
84  return ret;
85 }
86 
87 
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 
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 != IEEE80211_LINKED &&
120  ieee->state != IEEE80211_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 
133 
135  struct iw_request_info *info,
136  union iwreq_data *awrq,
137  char *extra)
138 {
139 
140  int ret = 0;
141  unsigned long flags;
142 
143  short ifup = ieee->proto_started;//dev->flags & IFF_UP;
144  struct sockaddr *temp = (struct sockaddr *)awrq;
145 
146  ieee->sync_scan_hurryup = 1;
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 (ifup)
162 
163  /* just to avoid to give inconsistent infos in the
164  * get wx method. not really needed otherwise
165  */
166  spin_lock_irqsave(&ieee->lock, flags);
167 
168  memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN);
169  ieee->wap_set = !is_zero_ether_addr(temp->sa_data);
170 
171  spin_unlock_irqrestore(&ieee->lock, flags);
172 
173  if (ifup)
175 out:
176  up(&ieee->wx_sem);
177  return ret;
178 }
179 
180  int ieee80211_wx_get_essid(struct ieee80211_device *ieee, struct iw_request_info *a,union iwreq_data *wrqu,char *b)
181 {
182  int len,ret = 0;
183  unsigned long flags;
184 
185  if (ieee->iw_mode == IW_MODE_MONITOR)
186  return -1;
187 
188  /* We want avoid to give to the user inconsistent infos*/
189  spin_lock_irqsave(&ieee->lock, flags);
190 
191  if (ieee->current_network.ssid[0] == '\0' ||
192  ieee->current_network.ssid_len == 0){
193  ret = -1;
194  goto out;
195  }
196 
197  if (ieee->state != IEEE80211_LINKED &&
198  ieee->state != IEEE80211_LINKED_SCANNING &&
199  ieee->ssid_set == 0){
200  ret = -1;
201  goto out;
202  }
203  len = ieee->current_network.ssid_len;
204  wrqu->essid.length = len;
205  strncpy(b,ieee->current_network.ssid,len);
206  wrqu->essid.flags = 1;
207 
208 out:
209  spin_unlock_irqrestore(&ieee->lock, flags);
210 
211  return ret;
212 
213 }
214 
216  struct iw_request_info *info,
217  union iwreq_data *wrqu, char *extra)
218 {
219 
220  u32 target_rate = wrqu->bitrate.value;
221 
222  ieee->rate = target_rate/100000;
223  //FIXME: we might want to limit rate also in management protocols.
224  return 0;
225 }
226 
227 
228 
230  struct iw_request_info *info,
231  union iwreq_data *wrqu, char *extra)
232 {
233  u32 tmp_rate;
234  tmp_rate = TxCountToDataRate(ieee, ieee->softmac_stats.CurrentShowTxate);
235 
236  wrqu->bitrate.value = tmp_rate * 500000;
237 
238  return 0;
239 }
240 
241 
243  struct iw_request_info *info,
244  union iwreq_data *wrqu, char *extra)
245 {
246  if (wrqu->rts.disabled || !wrqu->rts.fixed)
247  ieee->rts = DEFAULT_RTS_THRESHOLD;
248  else
249  {
250  if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
251  wrqu->rts.value > MAX_RTS_THRESHOLD)
252  return -EINVAL;
253  ieee->rts = wrqu->rts.value;
254  }
255  return 0;
256 }
257 
259  struct iw_request_info *info,
260  union iwreq_data *wrqu, char *extra)
261 {
262  wrqu->rts.value = ieee->rts;
263  wrqu->rts.fixed = 0; /* no auto select */
264  wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD);
265  return 0;
266 }
268  union iwreq_data *wrqu, char *b)
269 {
270 
271  ieee->sync_scan_hurryup = 1;
272 
273  down(&ieee->wx_sem);
274 
275  if (wrqu->mode == ieee->iw_mode)
276  goto out;
277 
278  if (wrqu->mode == IW_MODE_MONITOR){
279 
280  ieee->dev->type = ARPHRD_IEEE80211;
281  }else{
282  ieee->dev->type = ARPHRD_ETHER;
283  }
284 
285  if (!ieee->proto_started){
286  ieee->iw_mode = wrqu->mode;
287  }else{
289  ieee->iw_mode = wrqu->mode;
291  }
292 
293 out:
294  up(&ieee->wx_sem);
295  return 0;
296 }
297 
299 {
300  struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, wx_sync_scan_wq);
301  short chan;
302  HT_EXTCHNL_OFFSET chan_offset=0;
304  int b40M = 0;
305  static int count = 0;
306  chan = ieee->current_network.channel;
307  netif_carrier_off(ieee->dev);
308 
309  if (ieee->data_hard_stop)
310  ieee->data_hard_stop(ieee->dev);
311 
313 
315  ieee->link_change(ieee->dev);
316  ieee->InitialGainHandler(ieee->dev,IG_Backup);
317  if (ieee->pHTInfo->bCurrentHTSupport && ieee->pHTInfo->bEnableHT && ieee->pHTInfo->bCurBW40MHz) {
318  b40M = 1;
319  chan_offset = ieee->pHTInfo->CurSTAExtChnlOffset;
320  bandwidth = (HT_CHANNEL_WIDTH)ieee->pHTInfo->bCurBW40MHz;
321  printk("Scan in 40M, force to 20M first:%d, %d\n", chan_offset, bandwidth);
323  }
325  if (b40M) {
326  printk("Scan in 20M, back to 40M\n");
327  if (chan_offset == HT_EXTCHNL_OFFSET_UPPER)
328  ieee->set_chan(ieee->dev, chan + 2);
329  else if (chan_offset == HT_EXTCHNL_OFFSET_LOWER)
330  ieee->set_chan(ieee->dev, chan - 2);
331  else
332  ieee->set_chan(ieee->dev, chan);
333  ieee->SetBWModeHandler(ieee->dev, bandwidth, chan_offset);
334  } else {
335  ieee->set_chan(ieee->dev, chan);
336  }
337 
338  ieee->InitialGainHandler(ieee->dev,IG_Restore);
339  ieee->state = IEEE80211_LINKED;
340  ieee->link_change(ieee->dev);
341  // To prevent the immediately calling watch_dog after scan.
343  {
346  }
347  if (ieee->data_hard_resume)
348  ieee->data_hard_resume(ieee->dev);
349 
350  if(ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER)
352 
353  netif_carrier_on(ieee->dev);
354  count = 0;
355  up(&ieee->wx_sem);
356 
357 }
358 
360  union iwreq_data *wrqu, char *b)
361 {
362  int ret = 0;
363 
364  down(&ieee->wx_sem);
365 
366  if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)){
367  ret = -1;
368  goto out;
369  }
370 
371  if ( ieee->state == IEEE80211_LINKED){
372  queue_work(ieee->wq, &ieee->wx_sync_scan_wq);
373  /* intentionally forget to up sem */
374  return 0;
375  }
376 
377 out:
378  up(&ieee->wx_sem);
379  return ret;
380 }
381 
383  struct iw_request_info *a,
384  union iwreq_data *wrqu, char *extra)
385 {
386 
387  int ret=0,len;
388  short proto_started;
389  unsigned long flags;
390 
391  ieee->sync_scan_hurryup = 1;
392  down(&ieee->wx_sem);
393 
394  proto_started = ieee->proto_started;
395 
396  if (wrqu->essid.length > IW_ESSID_MAX_SIZE){
397  ret= -E2BIG;
398  goto out;
399  }
400 
401  if (ieee->iw_mode == IW_MODE_MONITOR){
402  ret= -1;
403  goto out;
404  }
405 
406  if(proto_started)
408 
409 
410  /* this is just to be sure that the GET wx callback
411  * has consisten infos. not needed otherwise
412  */
413  spin_lock_irqsave(&ieee->lock, flags);
414 
415  if (wrqu->essid.flags && wrqu->essid.length) {
416  //first flush current network.ssid
417  len = ((wrqu->essid.length-1) < IW_ESSID_MAX_SIZE) ? (wrqu->essid.length-1) : IW_ESSID_MAX_SIZE;
418  strncpy(ieee->current_network.ssid, extra, len+1);
419  ieee->current_network.ssid_len = len+1;
420  ieee->ssid_set = 1;
421  }
422  else{
423  ieee->ssid_set = 0;
424  ieee->current_network.ssid[0] = '\0';
425  ieee->current_network.ssid_len = 0;
426  }
427  spin_unlock_irqrestore(&ieee->lock, flags);
428 
429  if (proto_started)
431 out:
432  up(&ieee->wx_sem);
433  return ret;
434 }
435 
437  union iwreq_data *wrqu, char *b)
438 {
439 
440  wrqu->mode = ieee->iw_mode;
441  return 0;
442 }
443 
445  struct iw_request_info *info,
446  union iwreq_data *wrqu, char *extra)
447 {
448 
449  int *parms = (int *)extra;
450  int enable = (parms[0] > 0);
451  short prev = ieee->raw_tx;
452 
453  down(&ieee->wx_sem);
454 
455  if(enable)
456  ieee->raw_tx = 1;
457  else
458  ieee->raw_tx = 0;
459 
460  printk(KERN_INFO"raw TX is %s\n",
461  ieee->raw_tx ? "enabled" : "disabled");
462 
463  if(ieee->iw_mode == IW_MODE_MONITOR)
464  {
465  if(prev == 0 && ieee->raw_tx){
466  if (ieee->data_hard_resume)
467  ieee->data_hard_resume(ieee->dev);
468 
469  netif_carrier_on(ieee->dev);
470  }
471 
472  if(prev && ieee->raw_tx == 1)
473  netif_carrier_off(ieee->dev);
474  }
475 
476  up(&ieee->wx_sem);
477 
478  return 0;
479 }
480 
482  struct iw_request_info *info,
483  union iwreq_data *wrqu, char *extra)
484 {
485  strcpy(wrqu->name, "802.11");
487  strcat(wrqu->name, "b");
489  strcat(wrqu->name, "/g");
490  }else if(ieee->modulation & IEEE80211_OFDM_MODULATION)
491  strcat(wrqu->name, "g");
492  if (ieee->mode & (IEEE_N_24G | IEEE_N_5G))
493  strcat(wrqu->name, "/n");
494 
495  if((ieee->state == IEEE80211_LINKED) ||
496  (ieee->state == IEEE80211_LINKED_SCANNING))
497  strcat(wrqu->name," linked");
498  else if(ieee->state != IEEE80211_NOLINK)
499  strcat(wrqu->name," link..");
500 
501 
502  return 0;
503 }
504 
505 
506 /* this is mostly stolen from hostap */
508  struct iw_request_info *info,
509  union iwreq_data *wrqu, char *extra)
510 {
511  int ret = 0;
512  down(&ieee->wx_sem);
513 
514  if (wrqu->power.disabled){
515  ieee->ps = IEEE80211_PS_DISABLED;
516  goto exit;
517  }
518  if (wrqu->power.flags & IW_POWER_TIMEOUT) {
519  //ieee->ps_period = wrqu->power.value / 1000;
520  ieee->ps_timeout = wrqu->power.value / 1000;
521  }
522 
523  if (wrqu->power.flags & IW_POWER_PERIOD) {
524 
525  //ieee->ps_timeout = wrqu->power.value / 1000;
526  ieee->ps_period = wrqu->power.value / 1000;
527  //wrq->value / 1024;
528 
529  }
530  switch (wrqu->power.flags & IW_POWER_MODE) {
531  case IW_POWER_UNICAST_R:
532  ieee->ps = IEEE80211_PS_UNICAST;
533  break;
535  ieee->ps = IEEE80211_PS_MBCAST;
536  break;
537  case IW_POWER_ALL_R:
539  break;
540 
541  case IW_POWER_ON:
542  // ieee->ps = IEEE80211_PS_DISABLED;
543  break;
544 
545  default:
546  ret = -EINVAL;
547  goto exit;
548 
549  }
550 exit:
551  up(&ieee->wx_sem);
552  return ret;
553 
554 }
555 
556 /* this is stolen from hostap */
558  struct iw_request_info *info,
559  union iwreq_data *wrqu, char *extra)
560 {
561  int ret =0;
562 
563  down(&ieee->wx_sem);
564 
565  if(ieee->ps == IEEE80211_PS_DISABLED){
566  wrqu->power.disabled = 1;
567  goto exit;
568  }
569 
570  wrqu->power.disabled = 0;
571 
572  if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
573  wrqu->power.flags = IW_POWER_TIMEOUT;
574  wrqu->power.value = ieee->ps_timeout * 1000;
575  } else {
576 // ret = -EOPNOTSUPP;
577 // goto exit;
578  wrqu->power.flags = IW_POWER_PERIOD;
579  wrqu->power.value = ieee->ps_period * 1000;
580 //ieee->current_network.dtim_period * ieee->current_network.beacon_interval * 1024;
581  }
582 
584  wrqu->power.flags |= IW_POWER_ALL_R;
585  else if (ieee->ps & IEEE80211_PS_MBCAST)
586  wrqu->power.flags |= IW_POWER_MULTICAST_R;
587  else
588  wrqu->power.flags |= IW_POWER_UNICAST_R;
589 
590 exit:
591  up(&ieee->wx_sem);
592  return ret;
593 
594 }