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 
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 // printk("in %s\n",__func__);
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 
67  ieee->current_network.channel = fwrq->m;
68  ieee->set_chan(ieee->dev, ieee->current_network.channel);
69 
70  if(ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER)
71  if(ieee->state == IEEE80211_LINKED){
72 
75  }
76  }
77 
78  ret = 0;
79 out:
80  up(&ieee->wx_sem);
81  return ret;
82 }
83 
84 
86  struct iw_request_info *a,
87  union iwreq_data *wrqu, char *b)
88 {
89  struct iw_freq *fwrq = & wrqu->freq;
90 
91  if (ieee->current_network.channel == 0)
92  return -1;
93 
94  fwrq->m = ieee->current_network.channel;
95  fwrq->e = 0;
96 
97  return 0;
98 }
99 
101  struct iw_request_info *info,
102  union iwreq_data *wrqu, char *extra)
103 {
104  unsigned long flags;
105 
106  wrqu->ap_addr.sa_family = ARPHRD_ETHER;
107 
108  if (ieee->iw_mode == IW_MODE_MONITOR)
109  return -1;
110 
111  /* We want avoid to give to the user inconsistent infos*/
112  spin_lock_irqsave(&ieee->lock, flags);
113 
114  if (ieee->state != IEEE80211_LINKED &&
115  ieee->state != IEEE80211_LINKED_SCANNING &&
116  ieee->wap_set == 0)
117 
118  memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
119  else
120  memcpy(wrqu->ap_addr.sa_data,
121  ieee->current_network.bssid, ETH_ALEN);
122 
123  spin_unlock_irqrestore(&ieee->lock, flags);
124 
125  return 0;
126 }
127 
128 
130  struct iw_request_info *info,
131  union iwreq_data *awrq,
132  char *extra)
133 {
134 
135  int ret = 0;
136  unsigned long flags;
137 
138  short ifup = ieee->proto_started;//dev->flags & IFF_UP;
139  struct sockaddr *temp = (struct sockaddr *)awrq;
140 
141  //printk("=======Set WAP:");
142  ieee->sync_scan_hurryup = 1;
143 
144  down(&ieee->wx_sem);
145  /* use ifconfig hw ether */
146  if (ieee->iw_mode == IW_MODE_MASTER){
147  ret = -1;
148  goto out;
149  }
150 
151  if (temp->sa_family != ARPHRD_ETHER){
152  ret = -EINVAL;
153  goto out;
154  }
155 
156  if (ifup)
158 
159  /* just to avoid to give inconsistent infos in the
160  * get wx method. not really needed otherwise
161  */
162  spin_lock_irqsave(&ieee->lock, flags);
163 
164  memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN);
165  ieee->wap_set = !is_zero_ether_addr(temp->sa_data);
166  //printk(" %x:%x:%x:%x:%x:%x\n", ieee->current_network.bssid[0],ieee->current_network.bssid[1],ieee->current_network.bssid[2],ieee->current_network.bssid[3],ieee->current_network.bssid[4],ieee->current_network.bssid[5]);
167 
168  spin_unlock_irqrestore(&ieee->lock, flags);
169 
170  if (ifup)
172 
173 out:
174  up(&ieee->wx_sem);
175  return ret;
176 }
177 
178  int ieee80211_wx_get_essid(struct ieee80211_device *ieee, struct iw_request_info *a,union iwreq_data *wrqu,char *b)
179 {
180  int len,ret = 0;
181  unsigned long flags;
182 
183  if (ieee->iw_mode == IW_MODE_MONITOR)
184  return -1;
185 
186  /* We want avoid to give to the user inconsistent infos*/
187  spin_lock_irqsave(&ieee->lock, flags);
188 
189  if (ieee->current_network.ssid[0] == '\0' ||
190  ieee->current_network.ssid_len == 0){
191  ret = -1;
192  goto out;
193  }
194 
195  if (ieee->state != IEEE80211_LINKED &&
196  ieee->state != IEEE80211_LINKED_SCANNING &&
197  ieee->ssid_set == 0){
198  ret = -1;
199  goto out;
200  }
201  len = ieee->current_network.ssid_len;
202  wrqu->essid.length = len;
203  strncpy(b,ieee->current_network.ssid,len);
204  wrqu->essid.flags = 1;
205 
206 out:
207  spin_unlock_irqrestore(&ieee->lock, flags);
208 
209  return ret;
210 
211 }
212 
214  struct iw_request_info *info,
215  union iwreq_data *wrqu, char *extra)
216 {
217 
218  u32 target_rate = wrqu->bitrate.value;
219 
220  //added by lizhaoming for auto mode
221  if(target_rate == -1){
222  ieee->rate = 110;
223  } else {
224  ieee->rate = target_rate/100000;
225  }
226  //FIXME: we might want to limit rate also in management protocols.
227  return 0;
228 }
229 
230 
231 
233  struct iw_request_info *info,
234  union iwreq_data *wrqu, char *extra)
235 {
236 
237  wrqu->bitrate.value = ieee->rate * 100000;
238 
239  return 0;
240 }
241 
243  union iwreq_data *wrqu, char *b)
244 {
245 
246  ieee->sync_scan_hurryup = 1;
247 
248  down(&ieee->wx_sem);
249 
250  if (wrqu->mode == ieee->iw_mode)
251  goto out;
252 
253  if (wrqu->mode == IW_MODE_MONITOR){
254 
255  ieee->dev->type = ARPHRD_IEEE80211;
256  }else{
257  ieee->dev->type = ARPHRD_ETHER;
258  }
259 
260  if (!ieee->proto_started){
261  ieee->iw_mode = wrqu->mode;
262  }else{
264  ieee->iw_mode = wrqu->mode;
266  }
267 
268 out:
269  up(&ieee->wx_sem);
270  return 0;
271 }
272 
273 
275 {
276  struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, wx_sync_scan_wq);
277  short chan;
278 
279  chan = ieee->current_network.channel;
280 
281  if (ieee->data_hard_stop)
282  ieee->data_hard_stop(ieee->dev);
283 
285 
287  ieee->link_change(ieee->dev);
288 
290 
291  ieee->set_chan(ieee->dev, chan);
292 
293  ieee->state = IEEE80211_LINKED;
294  ieee->link_change(ieee->dev);
295 
296  if (ieee->data_hard_resume)
297  ieee->data_hard_resume(ieee->dev);
298 
299  if(ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER)
301 
302  //YJ,add,080828, In prevent of lossing ping packet during scanning
303  //ieee80211_sta_ps_send_null_frame(ieee, false);
304  //YJ,add,080828,end
305 
306  up(&ieee->wx_sem);
307 
308 }
309 
311  union iwreq_data *wrqu, char *b)
312 {
313  int ret = 0;
314 
315  down(&ieee->wx_sem);
316 
317  if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)){
318  ret = -1;
319  goto out;
320  }
321  //YJ,add,080828
322  //In prevent of lossing ping packet during scanning
323  //ieee80211_sta_ps_send_null_frame(ieee, true);
324  //YJ,add,080828,end
325 
326  if ( ieee->state == IEEE80211_LINKED){
327  queue_work(ieee->wq, &ieee->wx_sync_scan_wq);
328  /* intentionally forget to up sem */
329  return 0;
330  }
331 
332 out:
333  up(&ieee->wx_sem);
334  return ret;
335 }
336 
338  struct iw_request_info *a,
339  union iwreq_data *wrqu, char *extra)
340 {
341 
342  int ret=0,len;
343  short proto_started;
344  unsigned long flags;
345 
346  ieee->sync_scan_hurryup = 1;
347 
348  down(&ieee->wx_sem);
349 
350  proto_started = ieee->proto_started;
351 
352  if (wrqu->essid.length > IW_ESSID_MAX_SIZE){
353  ret= -E2BIG;
354  goto out;
355  }
356 
357  if (ieee->iw_mode == IW_MODE_MONITOR){
358  ret= -1;
359  goto out;
360  }
361 
362  if(proto_started)
364 
365  /* this is just to be sure that the GET wx callback
366  * has consistent infos. not needed otherwise
367  */
368  spin_lock_irqsave(&ieee->lock, flags);
369 
370  if (wrqu->essid.flags && wrqu->essid.length) {
371 //YJ,modified,080819
372  len = (wrqu->essid.length < IW_ESSID_MAX_SIZE) ? (wrqu->essid.length) : IW_ESSID_MAX_SIZE;
373  memset(ieee->current_network.ssid, 0, ieee->current_network.ssid_len); //YJ,add,080819
374  strncpy(ieee->current_network.ssid, extra, len);
375  ieee->current_network.ssid_len = len;
376  ieee->ssid_set = 1;
377 //YJ,modified,080819,end
378 
379  //YJ,add,080819,for hidden ap
380  if(len == 0){
381  memset(ieee->current_network.bssid, 0, ETH_ALEN);
382  ieee->current_network.capability = 0;
383  }
384  //YJ,add,080819,for hidden ap,end
385  }
386  else{
387  ieee->ssid_set = 0;
388  ieee->current_network.ssid[0] = '\0';
389  ieee->current_network.ssid_len = 0;
390  }
391  //printk("==========set essid %s!\n",ieee->current_network.ssid);
392  spin_unlock_irqrestore(&ieee->lock, flags);
393 
394  if (proto_started)
396 out:
397  up(&ieee->wx_sem);
398  return ret;
399 }
400 
402  union iwreq_data *wrqu, char *b)
403 {
404 
405  wrqu->mode = ieee->iw_mode;
406  return 0;
407 }
408 
410  struct iw_request_info *info,
411  union iwreq_data *wrqu, char *extra)
412 {
413 
414  int *parms = (int *)extra;
415  int enable = (parms[0] > 0);
416  short prev = ieee->raw_tx;
417 
418  down(&ieee->wx_sem);
419 
420  if(enable)
421  ieee->raw_tx = 1;
422  else
423  ieee->raw_tx = 0;
424 
425  printk(KERN_INFO"raw TX is %s\n",
426  ieee->raw_tx ? "enabled" : "disabled");
427 
428  if(ieee->iw_mode == IW_MODE_MONITOR)
429  {
430  if(prev == 0 && ieee->raw_tx){
431  if (ieee->data_hard_resume)
432  ieee->data_hard_resume(ieee->dev);
433 
434  netif_carrier_on(ieee->dev);
435  }
436 
437  if(prev && ieee->raw_tx == 1)
438  netif_carrier_off(ieee->dev);
439  }
440 
441  up(&ieee->wx_sem);
442 
443  return 0;
444 }
445 
447  struct iw_request_info *info,
448  union iwreq_data *wrqu, char *extra)
449 {
450  strlcpy(wrqu->name, "802.11", IFNAMSIZ);
452  strlcat(wrqu->name, "b", IFNAMSIZ);
454  strlcat(wrqu->name, "/g", IFNAMSIZ);
455  }else if(ieee->modulation & IEEE80211_OFDM_MODULATION)
456  strlcat(wrqu->name, "g", IFNAMSIZ);
457 
458  if((ieee->state == IEEE80211_LINKED) ||
459  (ieee->state == IEEE80211_LINKED_SCANNING))
460  strlcat(wrqu->name," link", IFNAMSIZ);
461  else if(ieee->state != IEEE80211_NOLINK)
462  strlcat(wrqu->name," .....", IFNAMSIZ);
463 
464 
465  return 0;
466 }
467 
468 
469 /* this is mostly stolen from hostap */
471  struct iw_request_info *info,
472  union iwreq_data *wrqu, char *extra)
473 {
474  int ret = 0;
475 
476  if(
477  (!ieee->sta_wake_up) ||
478  (!ieee->ps_request_tx_ack) ||
479  (!ieee->enter_sleep_state) ||
480  (!ieee->ps_is_queue_empty)){
481 
482  printk("ERROR. PS mode tried to be use but driver missed a callback\n\n");
483 
484  return -1;
485  }
486 
487  down(&ieee->wx_sem);
488 
489  if (wrqu->power.disabled){
490  ieee->ps = IEEE80211_PS_DISABLED;
491 
492  goto exit;
493  }
494  switch (wrqu->power.flags & IW_POWER_MODE) {
495  case IW_POWER_UNICAST_R:
496  ieee->ps = IEEE80211_PS_UNICAST;
497 
498  break;
499  case IW_POWER_ALL_R:
501  break;
502 
503  case IW_POWER_ON:
504  ieee->ps = IEEE80211_PS_DISABLED;
505  break;
506 
507  default:
508  ret = -EINVAL;
509  goto exit;
510  }
511 
512  if (wrqu->power.flags & IW_POWER_TIMEOUT) {
513 
514  ieee->ps_timeout = wrqu->power.value / 1000;
515  printk("Timeout %d\n",ieee->ps_timeout);
516  }
517 
518  if (wrqu->power.flags & IW_POWER_PERIOD) {
519 
520  ret = -EOPNOTSUPP;
521  goto exit;
522  //wrq->value / 1024;
523 
524  }
525 exit:
526  up(&ieee->wx_sem);
527  return ret;
528 
529 }
530 
531 /* this is stolen from hostap */
533  struct iw_request_info *info,
534  union iwreq_data *wrqu, char *extra)
535 {
536  int ret =0;
537 
538  down(&ieee->wx_sem);
539 
540  if(ieee->ps == IEEE80211_PS_DISABLED){
541  wrqu->power.disabled = 1;
542  goto exit;
543  }
544 
545  wrqu->power.disabled = 0;
546 
547 // if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
548  wrqu->power.flags = IW_POWER_TIMEOUT;
549  wrqu->power.value = ieee->ps_timeout * 1000;
550 // } else {
551 // ret = -EOPNOTSUPP;
552 // goto exit;
553  //wrqu->power.flags = IW_POWER_PERIOD;
554  //wrqu->power.value = ieee->current_network.dtim_period *
555  // ieee->current_network.beacon_interval * 1024;
556 // }
557 
558 
559  if (ieee->ps & IEEE80211_PS_MBCAST)
560  wrqu->power.flags |= IW_POWER_ALL_R;
561  else
562  wrqu->power.flags |= IW_POWER_UNICAST_R;
563 
564 exit:
565  up(&ieee->wx_sem);
566  return ret;
567 
568 }