Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cfg80211.c
Go to the documentation of this file.
1 /* cfg80211 Interface for prism2_usb module */
2 
3 
4 /* Prism2 channel/frequency/bitrate declarations */
5 static const struct ieee80211_channel prism2_channels[] = {
6  { .center_freq = 2412 },
7  { .center_freq = 2417 },
8  { .center_freq = 2422 },
9  { .center_freq = 2427 },
10  { .center_freq = 2432 },
11  { .center_freq = 2437 },
12  { .center_freq = 2442 },
13  { .center_freq = 2447 },
14  { .center_freq = 2452 },
15  { .center_freq = 2457 },
16  { .center_freq = 2462 },
17  { .center_freq = 2467 },
18  { .center_freq = 2472 },
19  { .center_freq = 2484 },
20 };
21 
22 static const struct ieee80211_rate prism2_rates[] = {
23  { .bitrate = 10 },
24  { .bitrate = 20 },
25  { .bitrate = 55 },
26  { .bitrate = 110 }
27 };
28 
29 #define PRISM2_NUM_CIPHER_SUITES 2
30 static const u32 prism2_cipher_suites[PRISM2_NUM_CIPHER_SUITES] = {
33 };
34 
35 
36 /* prism2 device private data */
39 
41  struct ieee80211_channel channels[ARRAY_SIZE(prism2_channels)];
42  struct ieee80211_rate rates[ARRAY_SIZE(prism2_rates)];
43 
45 };
46 
47 static const void * const prism2_wiphy_privid = &prism2_wiphy_privid;
48 
49 
50 /* Helper Functions */
51 static int prism2_result2err(int prism2_result)
52 {
53  int err = 0;
54 
55  switch (prism2_result) {
57  err = -EINVAL;
58  break;
60  err = -EIO;
61  break;
63  err = -EOPNOTSUPP;
64  break;
65  default:
66  err = 0;
67  break;
68  }
69 
70  return err;
71 }
72 
73 static int prism2_domibset_uint32(wlandevice_t *wlandev, u32 did, u32 data)
74 {
76  p80211item_uint32_t *mibitem = (p80211item_uint32_t *) &msg.mibattribute.data;
77 
78  msg.msgcode = DIDmsg_dot11req_mibset;
79  mibitem->did = did;
80  mibitem->data = data;
81 
82  return p80211req_dorequest(wlandev, (u8 *) &msg);
83 }
84 
85 static int prism2_domibset_pstr32(wlandevice_t *wlandev,
86  u32 did, u8 len, u8 *data)
87 {
89  p80211item_pstr32_t *mibitem = (p80211item_pstr32_t *) &msg.mibattribute.data;
90 
91  msg.msgcode = DIDmsg_dot11req_mibset;
92  mibitem->did = did;
93  mibitem->data.len = len;
94  memcpy(mibitem->data.data, data, len);
95 
96  return p80211req_dorequest(wlandev, (u8 *) &msg);
97 }
98 
99 
100 /* The interface functions, called by the cfg80211 layer */
102  struct net_device *dev,
103  enum nl80211_iftype type, u32 *flags,
104  struct vif_params *params)
105 {
106  wlandevice_t *wlandev = dev->ml_priv;
107  u32 data;
108  int result;
109  int err = 0;
110 
111  switch (type) {
113  if (wlandev->macmode == WLAN_MACMODE_IBSS_STA)
114  goto exit;
115  wlandev->macmode = WLAN_MACMODE_IBSS_STA;
116  data = 0;
117  break;
119  if (wlandev->macmode == WLAN_MACMODE_ESS_STA)
120  goto exit;
121  wlandev->macmode = WLAN_MACMODE_ESS_STA;
122  data = 1;
123  break;
124  default:
125  printk(KERN_WARNING "Operation mode: %d not support\n", type);
126  return -EOPNOTSUPP;
127  }
128 
129  /* Set Operation mode to the PORT TYPE RID */
130  result = prism2_domibset_uint32(wlandev,
132  data);
133 
134  if (result)
135  err = -EFAULT;
136 
137  dev->ieee80211_ptr->iftype = type;
138 
139 exit:
140  return err;
141 }
142 
143 int prism2_add_key(struct wiphy *wiphy, struct net_device *dev,
144  u8 key_index, bool pairwise, const u8 *mac_addr,
145  struct key_params *params)
146 {
147  wlandevice_t *wlandev = dev->ml_priv;
148  u32 did;
149 
150  int err = 0;
151  int result = 0;
152 
153  switch (params->cipher) {
156  result = prism2_domibset_uint32(wlandev,
158  key_index);
159  if (result)
160  goto exit;
161 
162  /* send key to driver */
163  switch (key_index) {
164  case 0:
166  break;
167 
168  case 1:
170  break;
171 
172  case 2:
174  break;
175 
176  case 3:
178  break;
179 
180  default:
181  err = -EINVAL;
182  goto exit;
183  }
184 
185  result = prism2_domibset_pstr32(wlandev, did, params->key_len, params->key);
186  if (result)
187  goto exit;
188  break;
189 
190  default:
191  pr_debug("Unsupported cipher suite\n");
192  result = 1;
193  }
194 
195 exit:
196  if (result)
197  err = -EFAULT;
198 
199  return err;
200 }
201 
202 int prism2_get_key(struct wiphy *wiphy, struct net_device *dev,
203  u8 key_index, bool pairwise, const u8 *mac_addr, void *cookie,
204  void (*callback)(void *cookie, struct key_params*))
205 {
206  wlandevice_t *wlandev = dev->ml_priv;
207  struct key_params params;
208  int len;
209 
210  if (key_index >= NUM_WEPKEYS)
211  return -EINVAL;
212 
213  len = wlandev->wep_keylens[key_index];
214  memset(&params, 0, sizeof(params));
215 
216  if (len == 13)
218  else if (len == 5)
220  else
221  return -ENOENT;
222  params.key_len = len;
223  params.key = wlandev->wep_keys[key_index];
224  params.seq_len = 0;
225 
226  callback(cookie, &params);
227 
228  return 0;
229 }
230 
231 int prism2_del_key(struct wiphy *wiphy, struct net_device *dev,
232  u8 key_index, bool pairwise, const u8 *mac_addr)
233 {
234  wlandevice_t *wlandev = dev->ml_priv;
235  u32 did;
236  int err = 0;
237  int result = 0;
238 
239  /* There is no direct way in the hardware (AFAIK) of removing
240  a key, so we will cheat by setting the key to a bogus value */
241  /* send key to driver */
242  switch (key_index) {
243  case 0:
244  did =
246  break;
247 
248  case 1:
249  did =
251  break;
252 
253  case 2:
254  did =
256  break;
257 
258  case 3:
259  did =
261  break;
262 
263  default:
264  err = -EINVAL;
265  goto exit;
266  }
267 
268  result = prism2_domibset_pstr32(wlandev, did, 13, "0000000000000");
269 
270 exit:
271  if (result)
272  err = -EFAULT;
273 
274  return err;
275 }
276 
277 int prism2_set_default_key(struct wiphy *wiphy, struct net_device *dev,
278  u8 key_index, bool unicast, bool multicast)
279 {
280  wlandevice_t *wlandev = dev->ml_priv;
281 
282  int err = 0;
283  int result = 0;
284 
285  result = prism2_domibset_uint32(wlandev,
287  key_index);
288 
289  if (result)
290  err = -EFAULT;
291 
292  return err;
293 }
294 
295 
296 int prism2_get_station(struct wiphy *wiphy, struct net_device *dev,
297  u8 *mac, struct station_info *sinfo)
298 {
299  wlandevice_t *wlandev = dev->ml_priv;
300  struct p80211msg_lnxreq_commsquality quality;
301  int result;
302 
303  memset(sinfo, 0, sizeof(*sinfo));
304 
305  if ((wlandev == NULL) || (wlandev->msdstate != WLAN_MSD_RUNNING))
306  return -EOPNOTSUPP;
307 
308  /* build request message */
310  quality.dbm.data = P80211ENUM_truth_true;
312 
313  /* send message to nsd */
314  if (wlandev->mlmerequest == NULL)
315  return -EOPNOTSUPP;
316 
317  result = wlandev->mlmerequest(wlandev, (struct p80211msg *) &quality);
318 
319 
320  if (result == 0) {
321  sinfo->txrate.legacy = quality.txrate.data;
323  sinfo->signal = quality.level.data;
324  sinfo->filled |= STATION_INFO_SIGNAL;
325  }
326 
327  return result;
328 }
329 
330 int prism2_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
331 {
332  struct net_device *dev;
333  struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
335  struct p80211msg_dot11req_scan msg1;
337  struct cfg80211_bss *bss;
338  int result;
339  int err = 0;
340  int numbss = 0;
341  int i = 0;
342  u8 ie_buf[46];
343  int ie_len;
344 
345  if (!request)
346  return -EINVAL;
347 
348  dev = request->wdev->netdev;
349  wlandev = dev->ml_priv;
350 
351  if (priv->scan_request && priv->scan_request != request)
352  return -EBUSY;
353 
354  if (wlandev->macmode == WLAN_MACMODE_ESS_AP) {
355  printk(KERN_ERR "Can't scan in AP mode\n");
356  return -EOPNOTSUPP;
357  }
358 
359  priv->scan_request = request;
360 
361  memset(&msg1, 0x00, sizeof(struct p80211msg_dot11req_scan));
364 
365  memset(&msg1.bssid.data.data, 0xFF, sizeof(msg1.bssid.data.data));
366  msg1.bssid.data.len = 6;
367 
368  if (request->n_ssids > 0) {
370  msg1.ssid.data.len = request->ssids->ssid_len;
371  memcpy(msg1.ssid.data.data,
372  request->ssids->ssid, request->ssids->ssid_len);
373  } else {
374  msg1.scantype.data = 0;
375  }
376  msg1.probedelay.data = 0;
377 
378  for (i = 0;
379  (i < request->n_channels) && i < ARRAY_SIZE(prism2_channels);
380  i++)
381  msg1.channellist.data.data[i] =
382  ieee80211_frequency_to_channel(request->channels[i]->center_freq);
383  msg1.channellist.data.len = request->n_channels;
384 
385  msg1.maxchanneltime.data = 250;
386  msg1.minchanneltime.data = 200;
387 
388  result = p80211req_dorequest(wlandev, (u8 *) &msg1);
389  if (result) {
390  err = prism2_result2err(msg1.resultcode.data);
391  goto exit;
392  }
393  /* Now retrieve scan results */
394  numbss = msg1.numbss.data;
395 
396  for (i = 0; i < numbss; i++) {
397  memset(&msg2, 0, sizeof(msg2));
399  msg2.bssindex.data = i;
400 
401  result = p80211req_dorequest(wlandev, (u8 *) &msg2);
402  if ((result != 0) ||
404  break;
405  }
406 
407  ie_buf[0] = WLAN_EID_SSID;
408  ie_buf[1] = msg2.ssid.data.len;
409  ie_len = ie_buf[1] + 2;
410  memcpy(&ie_buf[2], &(msg2.ssid.data.data), msg2.ssid.data.len);
411  bss = cfg80211_inform_bss(wiphy,
412  ieee80211_get_channel(wiphy, ieee80211_dsss_chan_to_freq(msg2.dschannel.data)),
413  (const u8 *) &(msg2.bssid.data.data),
414  msg2.timestamp.data, msg2.capinfo.data,
415  msg2.beaconperiod.data,
416  ie_buf,
417  ie_len,
418  (msg2.signal.data - 65536) * 100, /* Conversion to signed type */
419  GFP_KERNEL
420  );
421 
422  if (!bss) {
423  err = -ENOMEM;
424  goto exit;
425  }
426 
427  cfg80211_put_bss(bss);
428  }
429 
430  if (result)
431  err = prism2_result2err(msg2.resultcode.data);
432 
433 exit:
434  cfg80211_scan_done(request, err ? 1 : 0);
435  priv->scan_request = NULL;
436  return err;
437 }
438 
439 int prism2_set_wiphy_params(struct wiphy *wiphy, u32 changed)
440 {
441  struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
442  wlandevice_t *wlandev = priv->wlandev;
443  u32 data;
444  int result;
445  int err = 0;
446 
447  if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
448  if (wiphy->rts_threshold == -1)
449  data = 2347;
450  else
451  data = wiphy->rts_threshold;
452 
453  result = prism2_domibset_uint32(wlandev,
455  data);
456  if (result) {
457  err = -EFAULT;
458  goto exit;
459  }
460  }
461 
462  if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
463  if (wiphy->frag_threshold == -1)
464  data = 2346;
465  else
466  data = wiphy->frag_threshold;
467 
468  result = prism2_domibset_uint32(wlandev,
470  data);
471  if (result) {
472  err = -EFAULT;
473  goto exit;
474  }
475  }
476 
477 exit:
478  return err;
479 }
480 
481 int prism2_connect(struct wiphy *wiphy, struct net_device *dev,
482  struct cfg80211_connect_params *sme)
483 {
484  wlandevice_t *wlandev = dev->ml_priv;
485  struct ieee80211_channel *channel = sme->channel;
486  struct p80211msg_lnxreq_autojoin msg_join;
487  u32 did;
488  int length = sme->ssid_len;
489  int chan = -1;
490  int is_wep = (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP40) ||
491  (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP104);
492  int result;
493  int err = 0;
494 
495  /* Set the channel */
496  if (channel) {
498  result = prism2_domibset_uint32(wlandev,
500  chan);
501  if (result)
502  goto exit;
503  }
504 
505  /* Set the authorization */
506  if ((sme->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) ||
507  ((sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) && !is_wep))
509  else if ((sme->auth_type == NL80211_AUTHTYPE_SHARED_KEY) ||
510  ((sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) && is_wep))
512  else
514  "Unhandled authorisation type for connect (%d)\n",
515  sme->auth_type);
516 
517  /* Set the encryption - we only support wep */
518  if (is_wep) {
519  if (sme->key) {
520  result = prism2_domibset_uint32(wlandev,
522  sme->key_idx);
523  if (result)
524  goto exit;
525 
526  /* send key to driver */
527  switch (sme->key_idx) {
528  case 0:
530  break;
531 
532  case 1:
534  break;
535 
536  case 2:
538  break;
539 
540  case 3:
542  break;
543 
544  default:
545  err = -EINVAL;
546  goto exit;
547  }
548 
549  result = prism2_domibset_pstr32(wlandev,
550  did, sme->key_len,
551  (u8 *)sme->key);
552  if (result)
553  goto exit;
554 
555  }
556 
557  /* Assume we should set privacy invoked and exclude unencrypted
558  We could possibly use sme->privacy here, but the assumption
559  seems reasonable anyway */
560  result = prism2_domibset_uint32(wlandev,
563  if (result)
564  goto exit;
565 
566  result = prism2_domibset_uint32(wlandev,
569  if (result)
570  goto exit;
571 
572  } else {
573  /* Assume we should unset privacy invoked
574  and exclude unencrypted */
575  result = prism2_domibset_uint32(wlandev,
578  if (result)
579  goto exit;
580 
581  result = prism2_domibset_uint32(wlandev,
584  if (result)
585  goto exit;
586 
587  }
588 
589  /* Now do the actual join. Note there is no way that I can
590  see to request a specific bssid */
591  msg_join.msgcode = DIDmsg_lnxreq_autojoin;
592 
593  memcpy(msg_join.ssid.data.data, sme->ssid, length);
594  msg_join.ssid.data.len = length;
595 
596  result = p80211req_dorequest(wlandev, (u8 *) &msg_join);
597 
598 exit:
599  if (result)
600  err = -EFAULT;
601 
602  return err;
603 }
604 
605 int prism2_disconnect(struct wiphy *wiphy, struct net_device *dev,
607 {
608  wlandevice_t *wlandev = dev->ml_priv;
609  struct p80211msg_lnxreq_autojoin msg_join;
610  int result;
611  int err = 0;
612 
613 
614  /* Do a join, with a bogus ssid. Thats the only way I can think of */
615  msg_join.msgcode = DIDmsg_lnxreq_autojoin;
616 
617  memcpy(msg_join.ssid.data.data, "---", 3);
618  msg_join.ssid.data.len = 3;
619 
620  result = p80211req_dorequest(wlandev, (u8 *) &msg_join);
621 
622  if (result)
623  err = -EFAULT;
624 
625  return err;
626 }
627 
628 
629 int prism2_join_ibss(struct wiphy *wiphy, struct net_device *dev,
631 {
632  return -EOPNOTSUPP;
633 }
634 
635 int prism2_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
636 {
637  return -EOPNOTSUPP;
638 }
639 
640 
641 int prism2_set_tx_power(struct wiphy *wiphy, enum nl80211_tx_power_setting type,
642  int mbm)
643 {
644  struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
645  wlandevice_t *wlandev = priv->wlandev;
646  u32 data;
647  int result;
648  int err = 0;
649 
650  if (type == NL80211_TX_POWER_AUTOMATIC)
651  data = 30;
652  else
653  data = MBM_TO_DBM(mbm);
654 
655  result = prism2_domibset_uint32(wlandev,
657  data);
658 
659  if (result) {
660  err = -EFAULT;
661  goto exit;
662  }
663 
664 exit:
665  return err;
666 }
667 
668 int prism2_get_tx_power(struct wiphy *wiphy, int *dbm)
669 {
670  struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
671  wlandevice_t *wlandev = priv->wlandev;
672  struct p80211msg_dot11req_mibget msg;
673  p80211item_uint32_t *mibitem;
674  int result;
675  int err = 0;
676 
677  mibitem = (p80211item_uint32_t *) &msg.mibattribute.data;
679  mibitem->did =
681 
682  result = p80211req_dorequest(wlandev, (u8 *) &msg);
683 
684  if (result) {
685  err = -EFAULT;
686  goto exit;
687  }
688 
689  *dbm = mibitem->data;
690 
691 exit:
692  return err;
693 }
694 
695 
696 
697 
698 /* Interface callback functions, passing data back up to the cfg80211 layer */
699 void prism2_connect_result(wlandevice_t *wlandev, u8 failed)
700 {
701  u16 status = failed ?
703 
704  cfg80211_connect_result(wlandev->netdev, wlandev->bssid,
705  NULL, 0, NULL, 0, status, GFP_KERNEL);
706 }
707 
709 {
710  cfg80211_disconnected(wlandev->netdev, 0, NULL,
711  0, GFP_KERNEL);
712 }
713 
715 {
716  cfg80211_roamed(wlandev->netdev, NULL, wlandev->bssid,
717  NULL, 0, NULL, 0, GFP_KERNEL);
718 }
719 
720 
721 /* Structures for declaring wiphy interface */
722 static const struct cfg80211_ops prism2_usb_cfg_ops = {
723  .change_virtual_intf = prism2_change_virtual_intf,
724  .add_key = prism2_add_key,
725  .get_key = prism2_get_key,
726  .del_key = prism2_del_key,
727  .set_default_key = prism2_set_default_key,
728  .get_station = prism2_get_station,
729  .scan = prism2_scan,
730  .set_wiphy_params = prism2_set_wiphy_params,
731  .connect = prism2_connect,
732  .disconnect = prism2_disconnect,
733  .join_ibss = prism2_join_ibss,
734  .leave_ibss = prism2_leave_ibss,
735  .set_tx_power = prism2_set_tx_power,
736  .get_tx_power = prism2_get_tx_power,
737 };
738 
739 
740 /* Functions to create/free wiphy interface */
741 struct wiphy *wlan_create_wiphy(struct device *dev, wlandevice_t *wlandev)
742 {
743  struct wiphy *wiphy;
744  struct prism2_wiphy_private *priv;
745 
746  wiphy = wiphy_new(&prism2_usb_cfg_ops, sizeof(*priv));
747  if (!wiphy)
748  return NULL;
749 
750  priv = wiphy_priv(wiphy);
751  priv->wlandev = wlandev;
752  memcpy(priv->channels, prism2_channels, sizeof(prism2_channels));
753  memcpy(priv->rates, prism2_rates, sizeof(prism2_rates));
754  priv->band.channels = priv->channels;
755  priv->band.n_channels = ARRAY_SIZE(prism2_channels);
756  priv->band.bitrates = priv->rates;
757  priv->band.n_bitrates = ARRAY_SIZE(prism2_rates);
758  priv->band.band = IEEE80211_BAND_2GHZ;
759  priv->band.ht_cap.ht_supported = false;
760  wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
761 
762  set_wiphy_dev(wiphy, dev);
763  wiphy->privid = prism2_wiphy_privid;
764  wiphy->max_scan_ssids = 1;
769  wiphy->cipher_suites = prism2_cipher_suites;
770 
771  if (wiphy_register(wiphy) < 0)
772  return NULL;
773 
774  return wiphy;
775 }
776 
777 
778 void wlan_free_wiphy(struct wiphy *wiphy)
779 {
780  wiphy_unregister(wiphy);
781  wiphy_free(wiphy);
782 }