4759aa2bba5df535978f8b55d4d4358c4b704ec0
[pandora-kernel.git] / drivers / net / wireless / libertas / wext.c
1 /**
2   * This file contains ioctl functions
3   */
4 #include <linux/ctype.h>
5 #include <linux/delay.h>
6 #include <linux/if.h>
7 #include <linux/if_arp.h>
8 #include <linux/wireless.h>
9 #include <linux/bitops.h>
10
11 #include <net/ieee80211.h>
12 #include <net/iw_handler.h>
13
14 #include "host.h"
15 #include "radiotap.h"
16 #include "decl.h"
17 #include "defs.h"
18 #include "dev.h"
19 #include "join.h"
20 #include "wext.h"
21 #include "assoc.h"
22
23
24 /**
25  * the rates supported by the card
26  */
27 static u8 libertas_wlan_data_rates[WLAN_SUPPORTED_RATES] =
28     { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12,
29       0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00
30 };
31
32 /**
33  *  @brief Convert mw value to dbm value
34  *
35  *  @param mw      the value of mw
36  *  @return        the value of dbm
37  */
38 static int mw_to_dbm(int mw)
39 {
40         if (mw < 2)
41                 return 0;
42         else if (mw < 3)
43                 return 3;
44         else if (mw < 4)
45                 return 5;
46         else if (mw < 6)
47                 return 7;
48         else if (mw < 7)
49                 return 8;
50         else if (mw < 8)
51                 return 9;
52         else if (mw < 10)
53                 return 10;
54         else if (mw < 13)
55                 return 11;
56         else if (mw < 16)
57                 return 12;
58         else if (mw < 20)
59                 return 13;
60         else if (mw < 25)
61                 return 14;
62         else if (mw < 32)
63                 return 15;
64         else if (mw < 40)
65                 return 16;
66         else if (mw < 50)
67                 return 17;
68         else if (mw < 63)
69                 return 18;
70         else if (mw < 79)
71                 return 19;
72         else if (mw < 100)
73                 return 20;
74         else
75                 return 21;
76 }
77
78 /**
79  *  @brief Find the channel frequency power info with specific channel
80  *
81  *  @param adapter      A pointer to wlan_adapter structure
82  *  @param band         it can be BAND_A, BAND_G or BAND_B
83  *  @param channel      the channel for looking
84  *  @return             A pointer to struct chan_freq_power structure or NULL if not find.
85  */
86 struct chan_freq_power *libertas_find_cfp_by_band_and_channel(wlan_adapter * adapter,
87                                                  u8 band, u16 channel)
88 {
89         struct chan_freq_power *cfp = NULL;
90         struct region_channel *rc;
91         int count = sizeof(adapter->region_channel) /
92             sizeof(adapter->region_channel[0]);
93         int i, j;
94
95         for (j = 0; !cfp && (j < count); j++) {
96                 rc = &adapter->region_channel[j];
97
98                 if (adapter->enable11d)
99                         rc = &adapter->universal_channel[j];
100                 if (!rc->valid || !rc->CFP)
101                         continue;
102                 if (rc->band != band)
103                         continue;
104                 for (i = 0; i < rc->nrcfp; i++) {
105                         if (rc->CFP[i].channel == channel) {
106                                 cfp = &rc->CFP[i];
107                                 break;
108                         }
109                 }
110         }
111
112         if (!cfp && channel)
113                 lbs_deb_wext("libertas_find_cfp_by_band_and_channel: can't find "
114                        "cfp by band %d / channel %d\n", band, channel);
115
116         return cfp;
117 }
118
119 /**
120  *  @brief Find the channel frequency power info with specific frequency
121  *
122  *  @param adapter      A pointer to wlan_adapter structure
123  *  @param band         it can be BAND_A, BAND_G or BAND_B
124  *  @param freq         the frequency for looking
125  *  @return             A pointer to struct chan_freq_power structure or NULL if not find.
126  */
127 static struct chan_freq_power *find_cfp_by_band_and_freq(wlan_adapter * adapter,
128                                                      u8 band, u32 freq)
129 {
130         struct chan_freq_power *cfp = NULL;
131         struct region_channel *rc;
132         int count = sizeof(adapter->region_channel) /
133             sizeof(adapter->region_channel[0]);
134         int i, j;
135
136         for (j = 0; !cfp && (j < count); j++) {
137                 rc = &adapter->region_channel[j];
138
139                 if (adapter->enable11d)
140                         rc = &adapter->universal_channel[j];
141                 if (!rc->valid || !rc->CFP)
142                         continue;
143                 if (rc->band != band)
144                         continue;
145                 for (i = 0; i < rc->nrcfp; i++) {
146                         if (rc->CFP[i].freq == freq) {
147                                 cfp = &rc->CFP[i];
148                                 break;
149                         }
150                 }
151         }
152
153         if (!cfp && freq)
154                 lbs_deb_wext("find_cfp_by_band_and_freql: can't find cfp by "
155                        "band %d / freq %d\n", band, freq);
156
157         return cfp;
158 }
159
160 static int updatecurrentchannel(wlan_private * priv)
161 {
162         int ret;
163
164         /*
165          ** the channel in f/w could be out of sync, get the current channel
166          */
167         ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
168                                     cmd_opt_802_11_rf_channel_get,
169                                     cmd_option_waitforrsp, 0, NULL);
170
171         lbs_deb_wext("current channel %d\n",
172                priv->adapter->curbssparams.channel);
173
174         return ret;
175 }
176
177 static int setcurrentchannel(wlan_private * priv, int channel)
178 {
179         lbs_deb_wext("set channel %d\n", channel);
180
181         /*
182          **  Current channel is not set to adhocchannel requested, set channel
183          */
184         return (libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
185                                       cmd_opt_802_11_rf_channel_set,
186                                       cmd_option_waitforrsp, 0, &channel));
187 }
188
189 static int changeadhocchannel(wlan_private * priv, int channel)
190 {
191         int ret = 0;
192         struct WLAN_802_11_SSID curadhocssid;
193         struct bss_descriptor * join_bss = NULL;
194         wlan_adapter *adapter = priv->adapter;
195
196         adapter->adhocchannel = channel;
197
198         updatecurrentchannel(priv);
199
200         if (adapter->curbssparams.channel == adapter->adhocchannel) {
201                 /* adhocchannel is set to the current channel already */
202                 goto out;
203         }
204
205         lbs_deb_wext("updating channel from %d to %d\n",
206                adapter->curbssparams.channel, adapter->adhocchannel);
207
208         setcurrentchannel(priv, adapter->adhocchannel);
209
210         updatecurrentchannel(priv);
211
212         if (adapter->curbssparams.channel != adapter->adhocchannel) {
213                 lbs_deb_wext("failed to updated channel to %d, channel = %d\n",
214                        adapter->adhocchannel, adapter->curbssparams.channel);
215                 ret = -1;
216                 goto out;
217         }
218
219         if (adapter->connect_status != libertas_connected)
220                 goto out;
221
222         lbs_deb_wext("channel changed while in IBSS\n");
223
224         /* Copy the current ssid */
225         memcpy(&curadhocssid, &adapter->curbssparams.ssid,
226                sizeof(struct WLAN_802_11_SSID));
227
228         /* Exit Adhoc mode */
229         lbs_deb_wext("in changeadhocchannel(): sending Adhoc stop\n");
230         ret = libertas_stop_adhoc_network(priv);
231         if (ret)
232                 goto out;
233
234         /* Scan for the network, do not save previous results.  Stale
235          *   scan data will cause us to join a non-existant adhoc network
236          */
237         libertas_send_specific_SSID_scan(priv, &curadhocssid, 0);
238
239         /* find out the BSSID that matches the current SSID */
240         join_bss = libertas_find_SSID_in_list(adapter, &curadhocssid, NULL,
241                            IW_MODE_ADHOC);
242
243         if (join_bss) {
244                 lbs_deb_wext("SSID found in list, so join\n");
245                 libertas_join_adhoc_network(priv, join_bss);
246         } else {
247                 lbs_deb_wext("SSID not found in list, "
248                        "creating AdHoc with SSID '%s'\n",
249                        curadhocssid.ssid);
250                 libertas_start_adhoc_network(priv, &curadhocssid);
251         }
252
253 out:
254         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
255         return ret;
256 }
257
258 /**
259  *  @brief Set Radio On/OFF
260  *
261  *  @param priv                 A pointer to wlan_private structure
262  *  @option                     Radio Option
263  *  @return                     0 --success, otherwise fail
264  */
265 int wlan_radio_ioctl(wlan_private * priv, u8 option)
266 {
267         int ret = 0;
268         wlan_adapter *adapter = priv->adapter;
269
270         lbs_deb_enter(LBS_DEB_WEXT);
271
272         if (adapter->radioon != option) {
273                 lbs_deb_wext("switching radio %s\n", option ? "on" : "off");
274                 adapter->radioon = option;
275
276                 ret = libertas_prepare_and_send_command(priv,
277                                             cmd_802_11_radio_control,
278                                             cmd_act_set,
279                                             cmd_option_waitforrsp, 0, NULL);
280         }
281
282         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
283         return ret;
284 }
285
286 /**
287  *  @brief Copy rates
288  *
289  *  @param dest                 A pointer to Dest Buf
290  *  @param src                  A pointer to Src Buf
291  *  @param len                  The len of Src Buf
292  *  @return                     Number of rates copyed
293  */
294 static inline int copyrates(u8 * dest, int pos, u8 * src, int len)
295 {
296         int i;
297
298         for (i = 0; i < len && src[i]; i++, pos++) {
299                 if (pos >= sizeof(u8) * WLAN_SUPPORTED_RATES)
300                         break;
301                 dest[pos] = src[i];
302         }
303
304         return pos;
305 }
306
307 /**
308  *  @brief Get active data rates
309  *
310  *  @param adapter              A pointer to wlan_adapter structure
311  *  @param rate                 The buf to return the active rates
312  *  @return                     The number of rates
313  */
314 static int get_active_data_rates(wlan_adapter * adapter,
315                                  u8* rates)
316 {
317         int k = 0;
318
319         lbs_deb_enter(LBS_DEB_WEXT);
320
321         if (adapter->connect_status != libertas_connected) {
322                 if (adapter->mode == IW_MODE_INFRA) {
323                         lbs_deb_wext("infra\n");
324                         k = copyrates(rates, k, libertas_supported_rates,
325                                       sizeof(libertas_supported_rates));
326                 } else {
327                         lbs_deb_wext("Adhoc G\n");
328                         k = copyrates(rates, k, libertas_adhoc_rates_g,
329                                       sizeof(libertas_adhoc_rates_g));
330                 }
331         } else {
332                 k = copyrates(rates, 0, adapter->curbssparams.datarates,
333                               adapter->curbssparams.numofrates);
334         }
335
336         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", k);
337         return k;
338 }
339
340 static int wlan_get_name(struct net_device *dev, struct iw_request_info *info,
341                          char *cwrq, char *extra)
342 {
343         const char *cp;
344         char comm[6] = { "COMM-" };
345         char mrvl[6] = { "MRVL-" };
346         int cnt;
347
348         lbs_deb_enter(LBS_DEB_WEXT);
349
350         strcpy(cwrq, mrvl);
351
352         cp = strstr(libertas_driver_version, comm);
353         if (cp == libertas_driver_version)      //skip leading "COMM-"
354                 cp = libertas_driver_version + strlen(comm);
355         else
356                 cp = libertas_driver_version;
357
358         cnt = strlen(mrvl);
359         cwrq += cnt;
360         while (cnt < 16 && (*cp != '-')) {
361                 *cwrq++ = toupper(*cp++);
362                 cnt++;
363         }
364         *cwrq = '\0';
365
366         lbs_deb_leave(LBS_DEB_WEXT);
367         return 0;
368 }
369
370 static int wlan_get_freq(struct net_device *dev, struct iw_request_info *info,
371                          struct iw_freq *fwrq, char *extra)
372 {
373         wlan_private *priv = dev->priv;
374         wlan_adapter *adapter = priv->adapter;
375         struct chan_freq_power *cfp;
376
377         lbs_deb_enter(LBS_DEB_WEXT);
378
379         cfp = libertas_find_cfp_by_band_and_channel(adapter, 0,
380                                            adapter->curbssparams.channel);
381
382         if (!cfp) {
383                 if (adapter->curbssparams.channel)
384                         lbs_deb_wext("invalid channel %d\n",
385                                adapter->curbssparams.channel);
386                 return -EINVAL;
387         }
388
389         fwrq->m = (long)cfp->freq * 100000;
390         fwrq->e = 1;
391
392         lbs_deb_wext("freq %u\n", fwrq->m);
393         lbs_deb_leave(LBS_DEB_WEXT);
394         return 0;
395 }
396
397 static int wlan_get_wap(struct net_device *dev, struct iw_request_info *info,
398                         struct sockaddr *awrq, char *extra)
399 {
400         wlan_private *priv = dev->priv;
401         wlan_adapter *adapter = priv->adapter;
402
403         lbs_deb_enter(LBS_DEB_WEXT);
404
405         if (adapter->connect_status == libertas_connected) {
406                 memcpy(awrq->sa_data, adapter->curbssparams.bssid, ETH_ALEN);
407         } else {
408                 memset(awrq->sa_data, 0, ETH_ALEN);
409         }
410         awrq->sa_family = ARPHRD_ETHER;
411
412         lbs_deb_leave(LBS_DEB_WEXT);
413         return 0;
414 }
415
416 static int wlan_set_nick(struct net_device *dev, struct iw_request_info *info,
417                          struct iw_point *dwrq, char *extra)
418 {
419         wlan_private *priv = dev->priv;
420         wlan_adapter *adapter = priv->adapter;
421
422         lbs_deb_enter(LBS_DEB_WEXT);
423
424         /*
425          * Check the size of the string
426          */
427
428         if (dwrq->length > 16) {
429                 return -E2BIG;
430         }
431
432         mutex_lock(&adapter->lock);
433         memset(adapter->nodename, 0, sizeof(adapter->nodename));
434         memcpy(adapter->nodename, extra, dwrq->length);
435         mutex_unlock(&adapter->lock);
436
437         lbs_deb_leave(LBS_DEB_WEXT);
438         return 0;
439 }
440
441 static int wlan_get_nick(struct net_device *dev, struct iw_request_info *info,
442                          struct iw_point *dwrq, char *extra)
443 {
444         wlan_private *priv = dev->priv;
445         wlan_adapter *adapter = priv->adapter;
446
447         lbs_deb_enter(LBS_DEB_WEXT);
448
449         /*
450          * Get the Nick Name saved
451          */
452
453         mutex_lock(&adapter->lock);
454         strncpy(extra, adapter->nodename, 16);
455         mutex_unlock(&adapter->lock);
456
457         extra[16] = '\0';
458
459         /*
460          * If none, we may want to get the one that was set
461          */
462
463         /*
464          * Push it out !
465          */
466         dwrq->length = strlen(extra) + 1;
467
468         lbs_deb_leave(LBS_DEB_WEXT);
469         return 0;
470 }
471
472 static int wlan_set_rts(struct net_device *dev, struct iw_request_info *info,
473                         struct iw_param *vwrq, char *extra)
474 {
475         int ret = 0;
476         wlan_private *priv = dev->priv;
477         wlan_adapter *adapter = priv->adapter;
478         int rthr = vwrq->value;
479
480         lbs_deb_enter(LBS_DEB_WEXT);
481
482         if (vwrq->disabled) {
483                 adapter->rtsthsd = rthr = MRVDRV_RTS_MAX_VALUE;
484         } else {
485                 if (rthr < MRVDRV_RTS_MIN_VALUE || rthr > MRVDRV_RTS_MAX_VALUE)
486                         return -EINVAL;
487                 adapter->rtsthsd = rthr;
488         }
489
490         ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
491                                     cmd_act_set, cmd_option_waitforrsp,
492                                     OID_802_11_RTS_THRESHOLD, &rthr);
493
494         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
495         return ret;
496 }
497
498 static int wlan_get_rts(struct net_device *dev, struct iw_request_info *info,
499                         struct iw_param *vwrq, char *extra)
500 {
501         int ret = 0;
502         wlan_private *priv = dev->priv;
503         wlan_adapter *adapter = priv->adapter;
504
505         lbs_deb_enter(LBS_DEB_WEXT);
506
507         adapter->rtsthsd = 0;
508         ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
509                                     cmd_act_get, cmd_option_waitforrsp,
510                                     OID_802_11_RTS_THRESHOLD, NULL);
511         if (ret)
512                 goto out;
513
514         vwrq->value = adapter->rtsthsd;
515         vwrq->disabled = ((vwrq->value < MRVDRV_RTS_MIN_VALUE)
516                           || (vwrq->value > MRVDRV_RTS_MAX_VALUE));
517         vwrq->fixed = 1;
518
519 out:
520         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
521         return ret;
522 }
523
524 static int wlan_set_frag(struct net_device *dev, struct iw_request_info *info,
525                          struct iw_param *vwrq, char *extra)
526 {
527         int ret = 0;
528         int fthr = vwrq->value;
529         wlan_private *priv = dev->priv;
530         wlan_adapter *adapter = priv->adapter;
531
532         lbs_deb_enter(LBS_DEB_WEXT);
533
534         if (vwrq->disabled) {
535                 adapter->fragthsd = fthr = MRVDRV_FRAG_MAX_VALUE;
536         } else {
537                 if (fthr < MRVDRV_FRAG_MIN_VALUE
538                     || fthr > MRVDRV_FRAG_MAX_VALUE)
539                         return -EINVAL;
540                 adapter->fragthsd = fthr;
541         }
542
543         ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
544                                     cmd_act_set, cmd_option_waitforrsp,
545                                     OID_802_11_FRAGMENTATION_THRESHOLD, &fthr);
546
547         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
548         return ret;
549 }
550
551 static int wlan_get_frag(struct net_device *dev, struct iw_request_info *info,
552                          struct iw_param *vwrq, char *extra)
553 {
554         int ret = 0;
555         wlan_private *priv = dev->priv;
556         wlan_adapter *adapter = priv->adapter;
557
558         lbs_deb_enter(LBS_DEB_WEXT);
559
560         adapter->fragthsd = 0;
561         ret = libertas_prepare_and_send_command(priv,
562                                     cmd_802_11_snmp_mib,
563                                     cmd_act_get, cmd_option_waitforrsp,
564                                     OID_802_11_FRAGMENTATION_THRESHOLD, NULL);
565         if (ret)
566                 goto out;
567
568         vwrq->value = adapter->fragthsd;
569         vwrq->disabled = ((vwrq->value < MRVDRV_FRAG_MIN_VALUE)
570                           || (vwrq->value > MRVDRV_FRAG_MAX_VALUE));
571         vwrq->fixed = 1;
572
573 out:
574         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
575         return ret;
576 }
577
578 static int wlan_get_mode(struct net_device *dev,
579                          struct iw_request_info *info, u32 * uwrq, char *extra)
580 {
581         wlan_private *priv = dev->priv;
582         wlan_adapter *adapter = priv->adapter;
583
584         lbs_deb_enter(LBS_DEB_WEXT);
585
586         *uwrq = adapter->mode;
587
588         lbs_deb_leave(LBS_DEB_WEXT);
589         return 0;
590 }
591
592 static int wlan_get_txpow(struct net_device *dev,
593                           struct iw_request_info *info,
594                           struct iw_param *vwrq, char *extra)
595 {
596         int ret = 0;
597         wlan_private *priv = dev->priv;
598         wlan_adapter *adapter = priv->adapter;
599
600         lbs_deb_enter(LBS_DEB_WEXT);
601
602         ret = libertas_prepare_and_send_command(priv,
603                                     cmd_802_11_rf_tx_power,
604                                     cmd_act_tx_power_opt_get,
605                                     cmd_option_waitforrsp, 0, NULL);
606
607         if (ret)
608                 goto out;
609
610         lbs_deb_wext("tx power level %d dbm\n", adapter->txpowerlevel);
611         vwrq->value = adapter->txpowerlevel;
612         vwrq->fixed = 1;
613         if (adapter->radioon) {
614                 vwrq->disabled = 0;
615                 vwrq->flags = IW_TXPOW_DBM;
616         } else {
617                 vwrq->disabled = 1;
618         }
619
620 out:
621         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
622         return ret;
623 }
624
625 static int wlan_set_retry(struct net_device *dev, struct iw_request_info *info,
626                           struct iw_param *vwrq, char *extra)
627 {
628         int ret = 0;
629         wlan_private *priv = dev->priv;
630         wlan_adapter *adapter = priv->adapter;
631
632         lbs_deb_enter(LBS_DEB_WEXT);
633
634         if (vwrq->flags == IW_RETRY_LIMIT) {
635                 /* The MAC has a 4-bit Total_Tx_Count register
636                    Total_Tx_Count = 1 + Tx_Retry_Count */
637 #define TX_RETRY_MIN 0
638 #define TX_RETRY_MAX 14
639                 if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX)
640                         return -EINVAL;
641
642                 /* Adding 1 to convert retry count to try count */
643                 adapter->txretrycount = vwrq->value + 1;
644
645                 ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
646                                             cmd_act_set,
647                                             cmd_option_waitforrsp,
648                                             OID_802_11_TX_RETRYCOUNT, NULL);
649
650                 if (ret)
651                         goto out;
652         } else {
653                 return -EOPNOTSUPP;
654         }
655
656 out:
657         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
658         return ret;
659 }
660
661 static int wlan_get_retry(struct net_device *dev, struct iw_request_info *info,
662                           struct iw_param *vwrq, char *extra)
663 {
664         wlan_private *priv = dev->priv;
665         wlan_adapter *adapter = priv->adapter;
666         int ret = 0;
667
668         lbs_deb_enter(LBS_DEB_WEXT);
669
670         adapter->txretrycount = 0;
671         ret = libertas_prepare_and_send_command(priv,
672                                     cmd_802_11_snmp_mib,
673                                     cmd_act_get, cmd_option_waitforrsp,
674                                     OID_802_11_TX_RETRYCOUNT, NULL);
675         if (ret)
676                 goto out;
677
678         vwrq->disabled = 0;
679         if (!vwrq->flags) {
680                 vwrq->flags = IW_RETRY_LIMIT;
681                 /* Subtract 1 to convert try count to retry count */
682                 vwrq->value = adapter->txretrycount - 1;
683         }
684
685 out:
686         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
687         return ret;
688 }
689
690 static inline void sort_channels(struct iw_freq *freq, int num)
691 {
692         int i, j;
693         struct iw_freq temp;
694
695         for (i = 0; i < num; i++)
696                 for (j = i + 1; j < num; j++)
697                         if (freq[i].i > freq[j].i) {
698                                 temp.i = freq[i].i;
699                                 temp.m = freq[i].m;
700
701                                 freq[i].i = freq[j].i;
702                                 freq[i].m = freq[j].m;
703
704                                 freq[j].i = temp.i;
705                                 freq[j].m = temp.m;
706                         }
707 }
708
709 /* data rate listing
710         MULTI_BANDS:
711                 abg             a       b       b/g
712    Infra        G(12)           A(8)    B(4)    G(12)
713    Adhoc        A+B(12)         A(8)    B(4)    B(4)
714
715         non-MULTI_BANDS:
716                                         b       b/g
717    Infra                                B(4)    G(12)
718    Adhoc                                B(4)    B(4)
719  */
720 /**
721  *  @brief Get Range Info
722  *
723  *  @param dev                  A pointer to net_device structure
724  *  @param info                 A pointer to iw_request_info structure
725  *  @param vwrq                 A pointer to iw_param structure
726  *  @param extra                A pointer to extra data buf
727  *  @return                     0 --success, otherwise fail
728  */
729 static int wlan_get_range(struct net_device *dev, struct iw_request_info *info,
730                           struct iw_point *dwrq, char *extra)
731 {
732         int i, j;
733         wlan_private *priv = dev->priv;
734         wlan_adapter *adapter = priv->adapter;
735         struct iw_range *range = (struct iw_range *)extra;
736         struct chan_freq_power *cfp;
737         u8 rates[WLAN_SUPPORTED_RATES];
738
739         u8 flag = 0;
740
741         lbs_deb_enter(LBS_DEB_WEXT);
742
743         dwrq->length = sizeof(struct iw_range);
744         memset(range, 0, sizeof(struct iw_range));
745
746         range->min_nwid = 0;
747         range->max_nwid = 0;
748
749         memset(rates, 0, sizeof(rates));
750         range->num_bitrates = get_active_data_rates(adapter, rates);
751
752         for (i = 0; i < min_t(__u8, range->num_bitrates, IW_MAX_BITRATES) && rates[i];
753              i++) {
754                 range->bitrate[i] = (rates[i] & 0x7f) * 500000;
755         }
756         range->num_bitrates = i;
757         lbs_deb_wext("IW_MAX_BITRATES %d, num_bitrates %d\n", IW_MAX_BITRATES,
758                range->num_bitrates);
759
760         range->num_frequency = 0;
761         if (priv->adapter->enable11d &&
762             adapter->connect_status == libertas_connected) {
763                 u8 chan_no;
764                 u8 band;
765
766                 struct parsed_region_chan_11d *parsed_region_chan =
767                     &adapter->parsed_region_chan;
768
769                 if (parsed_region_chan == NULL) {
770                         lbs_deb_wext("11d: parsed_region_chan is NULL\n");
771                         goto out;
772                 }
773                 band = parsed_region_chan->band;
774                 lbs_deb_wext("band %d, nr_char %d\n", band,
775                        parsed_region_chan->nr_chan);
776
777                 for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
778                      && (i < parsed_region_chan->nr_chan); i++) {
779                         chan_no = parsed_region_chan->chanpwr[i].chan;
780                         lbs_deb_wext("chan_no %d\n", chan_no);
781                         range->freq[range->num_frequency].i = (long)chan_no;
782                         range->freq[range->num_frequency].m =
783                             (long)libertas_chan_2_freq(chan_no, band) * 100000;
784                         range->freq[range->num_frequency].e = 1;
785                         range->num_frequency++;
786                 }
787                 flag = 1;
788         }
789         if (!flag) {
790                 for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
791                      && (j < sizeof(adapter->region_channel)
792                          / sizeof(adapter->region_channel[0])); j++) {
793                         cfp = adapter->region_channel[j].CFP;
794                         for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
795                              && adapter->region_channel[j].valid
796                              && cfp
797                              && (i < adapter->region_channel[j].nrcfp); i++) {
798                                 range->freq[range->num_frequency].i =
799                                     (long)cfp->channel;
800                                 range->freq[range->num_frequency].m =
801                                     (long)cfp->freq * 100000;
802                                 range->freq[range->num_frequency].e = 1;
803                                 cfp++;
804                                 range->num_frequency++;
805                         }
806                 }
807         }
808
809         lbs_deb_wext("IW_MAX_FREQUENCIES %d, num_frequency %d\n",
810                IW_MAX_FREQUENCIES, range->num_frequency);
811
812         range->num_channels = range->num_frequency;
813
814         sort_channels(&range->freq[0], range->num_frequency);
815
816         /*
817          * Set an indication of the max TCP throughput in bit/s that we can
818          * expect using this interface
819          */
820         if (i > 2)
821                 range->throughput = 5000 * 1000;
822         else
823                 range->throughput = 1500 * 1000;
824
825         range->min_rts = MRVDRV_RTS_MIN_VALUE;
826         range->max_rts = MRVDRV_RTS_MAX_VALUE;
827         range->min_frag = MRVDRV_FRAG_MIN_VALUE;
828         range->max_frag = MRVDRV_FRAG_MAX_VALUE;
829
830         range->encoding_size[0] = 5;
831         range->encoding_size[1] = 13;
832         range->num_encoding_sizes = 2;
833         range->max_encoding_tokens = 4;
834
835         range->min_pmp = 1000000;
836         range->max_pmp = 120000000;
837         range->min_pmt = 1000;
838         range->max_pmt = 1000000;
839         range->pmp_flags = IW_POWER_PERIOD;
840         range->pmt_flags = IW_POWER_TIMEOUT;
841         range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
842
843         /*
844          * Minimum version we recommend
845          */
846         range->we_version_source = 15;
847
848         /*
849          * Version we are compiled with
850          */
851         range->we_version_compiled = WIRELESS_EXT;
852
853         range->retry_capa = IW_RETRY_LIMIT;
854         range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
855
856         range->min_retry = TX_RETRY_MIN;
857         range->max_retry = TX_RETRY_MAX;
858
859         /*
860          * Set the qual, level and noise range values
861          */
862         range->max_qual.qual = 100;
863         range->max_qual.level = 0;
864         range->max_qual.noise = 0;
865         range->max_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
866
867         range->avg_qual.qual = 70;
868         /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
869         range->avg_qual.level = 0;
870         range->avg_qual.noise = 0;
871         range->avg_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
872
873         range->sensitivity = 0;
874
875         /*
876          * Setup the supported power level ranges
877          */
878         memset(range->txpower, 0, sizeof(range->txpower));
879         range->txpower[0] = 5;
880         range->txpower[1] = 7;
881         range->txpower[2] = 9;
882         range->txpower[3] = 11;
883         range->txpower[4] = 13;
884         range->txpower[5] = 15;
885         range->txpower[6] = 17;
886         range->txpower[7] = 19;
887
888         range->num_txpower = 8;
889         range->txpower_capa = IW_TXPOW_DBM;
890         range->txpower_capa |= IW_TXPOW_RANGE;
891
892         range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
893                                 IW_EVENT_CAPA_MASK(SIOCGIWAP) |
894                                 IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
895         range->event_capa[1] = IW_EVENT_CAPA_K_1;
896
897         if (adapter->fwcapinfo & FW_CAPINFO_WPA) {
898                 range->enc_capa =   IW_ENC_CAPA_WPA
899                                   | IW_ENC_CAPA_WPA2
900                                   | IW_ENC_CAPA_CIPHER_TKIP
901                                   | IW_ENC_CAPA_CIPHER_CCMP;
902         }
903
904 out:
905         lbs_deb_leave(LBS_DEB_WEXT);
906         return 0;
907 }
908
909 static int wlan_set_power(struct net_device *dev, struct iw_request_info *info,
910                           struct iw_param *vwrq, char *extra)
911 {
912         wlan_private *priv = dev->priv;
913         wlan_adapter *adapter = priv->adapter;
914
915         lbs_deb_enter(LBS_DEB_WEXT);
916
917         /* PS is currently supported only in Infrastructure mode
918          * Remove this check if it is to be supported in IBSS mode also
919          */
920
921         if (vwrq->disabled) {
922                 adapter->psmode = wlan802_11powermodecam;
923                 if (adapter->psstate != PS_STATE_FULL_POWER) {
924                         libertas_ps_wakeup(priv, cmd_option_waitforrsp);
925                 }
926
927                 return 0;
928         }
929
930         if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
931                 lbs_deb_wext(
932                        "setting power timeout is not supported\n");
933                 return -EINVAL;
934         } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
935                 lbs_deb_wext("setting power period not supported\n");
936                 return -EINVAL;
937         }
938
939         if (adapter->psmode != wlan802_11powermodecam) {
940                 return 0;
941         }
942
943         adapter->psmode = wlan802_11powermodemax_psp;
944
945         if (adapter->connect_status == libertas_connected) {
946                 libertas_ps_sleep(priv, cmd_option_waitforrsp);
947         }
948
949         lbs_deb_leave(LBS_DEB_WEXT);
950         return 0;
951 }
952
953 static int wlan_get_power(struct net_device *dev, struct iw_request_info *info,
954                           struct iw_param *vwrq, char *extra)
955 {
956         wlan_private *priv = dev->priv;
957         wlan_adapter *adapter = priv->adapter;
958         int mode;
959
960         lbs_deb_enter(LBS_DEB_WEXT);
961
962         mode = adapter->psmode;
963
964         if ((vwrq->disabled = (mode == wlan802_11powermodecam))
965             || adapter->connect_status == libertas_disconnected)
966         {
967                 goto out;
968         }
969
970         vwrq->value = 0;
971
972 out:
973         lbs_deb_leave(LBS_DEB_WEXT);
974         return 0;
975 }
976
977 /*
978  * iwpriv settable callbacks
979  */
980
981 static const iw_handler wlan_private_handler[] = {
982         NULL,                   /* SIOCIWFIRSTPRIV */
983 };
984
985 static const struct iw_priv_args wlan_private_args[] = {
986         /*
987          * { cmd, set_args, get_args, name }
988          */
989         /* Using iwpriv sub-command feature */
990         {
991          WLAN_SETONEINT_GETNONE,        /* IOCTL: 24 */
992          IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
993          IW_PRIV_TYPE_NONE,
994          ""},
995         {
996          WLANSETREGION,
997          IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
998          IW_PRIV_TYPE_NONE,
999          "setregioncode"},
1000         {
1001          WLAN_SUBCMD_MESH_SET_TTL,
1002          IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1003          IW_PRIV_TYPE_NONE,
1004          "mesh_set_ttl"},
1005         {
1006          WLAN_SETNONE_GETONEINT,
1007          IW_PRIV_TYPE_NONE,
1008          IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1009          ""},
1010         {
1011          WLANGETREGION,
1012          IW_PRIV_TYPE_NONE,
1013          IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1014          "getregioncode"},
1015         {
1016          WLAN_SUBCMD_FWT_CLEANUP,
1017          IW_PRIV_TYPE_NONE,
1018          IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1019          "fwt_cleanup"},
1020         {
1021          WLAN_SUBCMD_FWT_TIME,
1022          IW_PRIV_TYPE_NONE,
1023          IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1024          "fwt_time"},
1025         {
1026          WLAN_SUBCMD_MESH_GET_TTL,
1027          IW_PRIV_TYPE_NONE,
1028          IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1029          "mesh_get_ttl"},
1030         {
1031          WLAN_SETNONE_GETNONE,
1032          IW_PRIV_TYPE_NONE,
1033          IW_PRIV_TYPE_NONE,
1034          ""},
1035         {
1036          WLAN_SUBCMD_FWT_RESET,
1037          IW_PRIV_TYPE_NONE,
1038          IW_PRIV_TYPE_NONE,
1039          "fwt_reset"},
1040         {
1041          WLAN_SUBCMD_BT_RESET,
1042          IW_PRIV_TYPE_NONE,
1043          IW_PRIV_TYPE_NONE,
1044          "bt_reset"},
1045         {
1046          WLAN_SET128CHAR_GET128CHAR,
1047          IW_PRIV_TYPE_CHAR | 128,
1048          IW_PRIV_TYPE_CHAR | 128,
1049          ""},
1050         /* BT Management */
1051         {
1052          WLAN_SUBCMD_BT_ADD,
1053          IW_PRIV_TYPE_CHAR | 128,
1054          IW_PRIV_TYPE_CHAR | 128,
1055          "bt_add"},
1056         {
1057          WLAN_SUBCMD_BT_DEL,
1058          IW_PRIV_TYPE_CHAR | 128,
1059          IW_PRIV_TYPE_CHAR | 128,
1060          "bt_del"},
1061         {
1062          WLAN_SUBCMD_BT_LIST,
1063          IW_PRIV_TYPE_CHAR | 128,
1064          IW_PRIV_TYPE_CHAR | 128,
1065          "bt_list"},
1066         {
1067          WLAN_SUBCMD_BT_SET_INVERT,
1068          IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1069          IW_PRIV_TYPE_NONE,
1070          "bt_set_invert"},
1071         {
1072          WLAN_SUBCMD_BT_GET_INVERT,
1073          IW_PRIV_TYPE_NONE,
1074          IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1075          "bt_get_invert"},
1076         /* FWT Management */
1077         {
1078          WLAN_SUBCMD_FWT_ADD,
1079          IW_PRIV_TYPE_CHAR | 128,
1080          IW_PRIV_TYPE_CHAR | 128,
1081          "fwt_add"},
1082         {
1083          WLAN_SUBCMD_FWT_DEL,
1084          IW_PRIV_TYPE_CHAR | 128,
1085          IW_PRIV_TYPE_CHAR | 128,
1086          "fwt_del"},
1087         {
1088          WLAN_SUBCMD_FWT_LOOKUP,
1089          IW_PRIV_TYPE_CHAR | 128,
1090          IW_PRIV_TYPE_CHAR | 128,
1091          "fwt_lookup"},
1092         {
1093          WLAN_SUBCMD_FWT_LIST_NEIGHBOR,
1094          IW_PRIV_TYPE_CHAR | 128,
1095          IW_PRIV_TYPE_CHAR | 128,
1096          "fwt_list_neigh"},
1097         {
1098          WLAN_SUBCMD_FWT_LIST,
1099          IW_PRIV_TYPE_CHAR | 128,
1100          IW_PRIV_TYPE_CHAR | 128,
1101          "fwt_list"},
1102         {
1103          WLAN_SUBCMD_FWT_LIST_ROUTE,
1104          IW_PRIV_TYPE_CHAR | 128,
1105          IW_PRIV_TYPE_CHAR | 128,
1106          "fwt_list_route"},
1107         {
1108          WLAN_SET_GET_SIXTEEN_INT,
1109          IW_PRIV_TYPE_INT | 16,
1110          IW_PRIV_TYPE_INT | 16,
1111          ""},
1112         {
1113          WLAN_LED_GPIO_CTRL,
1114          IW_PRIV_TYPE_INT | 16,
1115          IW_PRIV_TYPE_INT | 16,
1116          "ledgpio"},
1117 };
1118
1119 static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev)
1120 {
1121         enum {
1122                 POOR = 30,
1123                 FAIR = 60,
1124                 GOOD = 80,
1125                 VERY_GOOD = 90,
1126                 EXCELLENT = 95,
1127                 PERFECT = 100
1128         };
1129         wlan_private *priv = dev->priv;
1130         wlan_adapter *adapter = priv->adapter;
1131         u32 rssi_qual;
1132         u32 tx_qual;
1133         u32 quality = 0;
1134         int stats_valid = 0;
1135         u8 rssi;
1136         u32 tx_retries;
1137
1138         lbs_deb_enter(LBS_DEB_WEXT);
1139
1140         priv->wstats.status = adapter->mode;
1141
1142         /* If we're not associated, all quality values are meaningless */
1143         if (adapter->connect_status != libertas_connected)
1144                 goto out;
1145
1146         /* Quality by RSSI */
1147         priv->wstats.qual.level =
1148             CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
1149              adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
1150
1151         if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
1152                 priv->wstats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
1153         } else {
1154                 priv->wstats.qual.noise =
1155                     CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
1156         }
1157
1158         lbs_deb_wext("signal level %#x\n", priv->wstats.qual.level);
1159         lbs_deb_wext("noise %#x\n", priv->wstats.qual.noise);
1160
1161         rssi = priv->wstats.qual.level - priv->wstats.qual.noise;
1162         if (rssi < 15)
1163                 rssi_qual = rssi * POOR / 10;
1164         else if (rssi < 20)
1165                 rssi_qual = (rssi - 15) * (FAIR - POOR) / 5 + POOR;
1166         else if (rssi < 30)
1167                 rssi_qual = (rssi - 20) * (GOOD - FAIR) / 5 + FAIR;
1168         else if (rssi < 40)
1169                 rssi_qual = (rssi - 30) * (VERY_GOOD - GOOD) /
1170                     10 + GOOD;
1171         else
1172                 rssi_qual = (rssi - 40) * (PERFECT - VERY_GOOD) /
1173                     10 + VERY_GOOD;
1174         quality = rssi_qual;
1175
1176         /* Quality by TX errors */
1177         priv->wstats.discard.retries = priv->stats.tx_errors;
1178
1179         tx_retries = adapter->logmsg.retry;
1180
1181         if (tx_retries > 75)
1182                 tx_qual = (90 - tx_retries) * POOR / 15;
1183         else if (tx_retries > 70)
1184                 tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR;
1185         else if (tx_retries > 65)
1186                 tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;
1187         else if (tx_retries > 50)
1188                 tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) /
1189                     15 + GOOD;
1190         else
1191                 tx_qual = (50 - tx_retries) *
1192                     (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
1193         quality = min(quality, tx_qual);
1194
1195         priv->wstats.discard.code = adapter->logmsg.wepundecryptable;
1196         priv->wstats.discard.fragment = adapter->logmsg.rxfrag;
1197         priv->wstats.discard.retries = tx_retries;
1198         priv->wstats.discard.misc = adapter->logmsg.ackfailure;
1199
1200         /* Calculate quality */
1201         priv->wstats.qual.qual = max(quality, (u32)100);
1202         priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
1203         stats_valid = 1;
1204
1205         /* update stats asynchronously for future calls */
1206         libertas_prepare_and_send_command(priv, cmd_802_11_rssi, 0,
1207                                         0, 0, NULL);
1208         libertas_prepare_and_send_command(priv, cmd_802_11_get_log, 0,
1209                                         0, 0, NULL);
1210 out:
1211         if (!stats_valid) {
1212                 priv->wstats.miss.beacon = 0;
1213                 priv->wstats.discard.retries = 0;
1214                 priv->wstats.qual.qual = 0;
1215                 priv->wstats.qual.level = 0;
1216                 priv->wstats.qual.noise = 0;
1217                 priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED;
1218                 priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID |
1219                     IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
1220         }
1221
1222         lbs_deb_leave(LBS_DEB_WEXT);
1223         return &priv->wstats;
1224
1225
1226 }
1227
1228 static int wlan_set_freq(struct net_device *dev, struct iw_request_info *info,
1229                   struct iw_freq *fwrq, char *extra)
1230 {
1231         int ret = 0;
1232         wlan_private *priv = dev->priv;
1233         wlan_adapter *adapter = priv->adapter;
1234         int rc = -EINPROGRESS;  /* Call commit handler */
1235         struct chan_freq_power *cfp;
1236
1237         lbs_deb_enter(LBS_DEB_WEXT);
1238
1239         /*
1240          * If setting by frequency, convert to a channel
1241          */
1242         if (fwrq->e == 1) {
1243
1244                 long f = fwrq->m / 100000;
1245                 int c = 0;
1246
1247                 cfp = find_cfp_by_band_and_freq(adapter, 0, f);
1248                 if (!cfp) {
1249                         lbs_deb_wext("invalid freq %ld\n", f);
1250                         return -EINVAL;
1251                 }
1252
1253                 c = (int)cfp->channel;
1254
1255                 if (c < 0)
1256                         return -EINVAL;
1257
1258                 fwrq->e = 0;
1259                 fwrq->m = c;
1260         }
1261
1262         /*
1263          * Setting by channel number
1264          */
1265         if (fwrq->m > 1000 || fwrq->e > 0) {
1266                 rc = -EOPNOTSUPP;
1267         } else {
1268                 int channel = fwrq->m;
1269
1270                 cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, channel);
1271                 if (!cfp) {
1272                         rc = -EINVAL;
1273                 } else {
1274                         if (adapter->mode == IW_MODE_ADHOC) {
1275                                 rc = changeadhocchannel(priv, channel);
1276                                 /*  If station is WEP enabled, send the
1277                                  *  command to set WEP in firmware
1278                                  */
1279                                 if (adapter->secinfo.wep_enabled) {
1280                                         lbs_deb_wext("set_freq: WEP enabled\n");
1281                                         ret = libertas_prepare_and_send_command(priv,
1282                                                                     cmd_802_11_set_wep,
1283                                                                     cmd_act_add,
1284                                                                     cmd_option_waitforrsp,
1285                                                                     0,
1286                                                                     NULL);
1287
1288                                         if (ret) {
1289                                                 rc = ret;
1290                                                 goto out;
1291                                         }
1292
1293                                         adapter->currentpacketfilter |=
1294                                             cmd_act_mac_wep_enable;
1295
1296                                         libertas_set_mac_packet_filter(priv);
1297                                 }
1298                         } else {
1299                                 rc = -EOPNOTSUPP;
1300                         }
1301                 }
1302         }
1303
1304 out:
1305         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", rc);
1306         return rc;
1307 }
1308
1309 /**
1310  *  @brief use index to get the data rate
1311  *
1312  *  @param index                The index of data rate
1313  *  @return                     data rate or 0
1314  */
1315 u32 libertas_index_to_data_rate(u8 index)
1316 {
1317         if (index >= sizeof(libertas_wlan_data_rates))
1318                 index = 0;
1319
1320         return libertas_wlan_data_rates[index];
1321 }
1322
1323 /**
1324  *  @brief use rate to get the index
1325  *
1326  *  @param rate                 data rate
1327  *  @return                     index or 0
1328  */
1329 u8 libertas_data_rate_to_index(u32 rate)
1330 {
1331         u8 *ptr;
1332
1333         if (rate)
1334                 if ((ptr = memchr(libertas_wlan_data_rates, (u8) rate,
1335                                   sizeof(libertas_wlan_data_rates))))
1336                         return (ptr - libertas_wlan_data_rates);
1337
1338         return 0;
1339 }
1340
1341 static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info,
1342                   struct iw_param *vwrq, char *extra)
1343 {
1344         wlan_private *priv = dev->priv;
1345         wlan_adapter *adapter = priv->adapter;
1346         u32 data_rate;
1347         u16 action;
1348         int ret = 0;
1349         u8 rates[WLAN_SUPPORTED_RATES];
1350         u8 *rate;
1351
1352         lbs_deb_enter(LBS_DEB_WEXT);
1353
1354         lbs_deb_wext("vwrq->value %d\n", vwrq->value);
1355
1356         if (vwrq->value == -1) {
1357                 action = cmd_act_set_tx_auto;   // Auto
1358                 adapter->is_datarate_auto = 1;
1359                 adapter->datarate = 0;
1360         } else {
1361                 if (vwrq->value % 100000) {
1362                         return -EINVAL;
1363                 }
1364
1365                 data_rate = vwrq->value / 500000;
1366
1367                 memset(rates, 0, sizeof(rates));
1368                 get_active_data_rates(adapter, rates);
1369                 rate = rates;
1370                 while (*rate) {
1371                         lbs_deb_wext("rate=0x%X, wanted data_rate 0x%X\n", *rate,
1372                                data_rate);
1373                         if ((*rate & 0x7f) == (data_rate & 0x7f))
1374                                 break;
1375                         rate++;
1376                 }
1377                 if (!*rate) {
1378                         lbs_pr_alert("fixed data rate 0x%X out "
1379                                "of range\n", data_rate);
1380                         return -EINVAL;
1381                 }
1382
1383                 adapter->datarate = data_rate;
1384                 action = cmd_act_set_tx_fix_rate;
1385                 adapter->is_datarate_auto = 0;
1386         }
1387
1388         ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate,
1389                                     action, cmd_option_waitforrsp, 0, NULL);
1390
1391         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1392         return ret;
1393 }
1394
1395 static int wlan_get_rate(struct net_device *dev, struct iw_request_info *info,
1396                   struct iw_param *vwrq, char *extra)
1397 {
1398         wlan_private *priv = dev->priv;
1399         wlan_adapter *adapter = priv->adapter;
1400
1401         lbs_deb_enter(LBS_DEB_WEXT);
1402
1403         if (adapter->is_datarate_auto) {
1404                 vwrq->fixed = 0;
1405         } else {
1406                 vwrq->fixed = 1;
1407         }
1408
1409         vwrq->value = adapter->datarate * 500000;
1410
1411         lbs_deb_leave(LBS_DEB_WEXT);
1412         return 0;
1413 }
1414
1415 static int wlan_set_mode(struct net_device *dev,
1416                   struct iw_request_info *info, u32 * uwrq, char *extra)
1417 {
1418         int ret = 0;
1419         wlan_private *priv = dev->priv;
1420         wlan_adapter *adapter = priv->adapter;
1421         struct assoc_request * assoc_req;
1422
1423         lbs_deb_enter(LBS_DEB_WEXT);
1424
1425         if (   (*uwrq != IW_MODE_ADHOC)
1426             && (*uwrq != IW_MODE_INFRA)
1427             && (*uwrq != IW_MODE_AUTO)) {
1428                 lbs_deb_wext("Invalid mode: 0x%x\n", *uwrq);
1429                 ret = -EINVAL;
1430                 goto out;
1431         }
1432
1433         mutex_lock(&adapter->lock);
1434         assoc_req = wlan_get_association_request(adapter);
1435         if (!assoc_req) {
1436                 ret = -ENOMEM;
1437                 wlan_cancel_association_work(priv);
1438         } else {
1439                 assoc_req->mode = *uwrq;
1440                 set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
1441                 wlan_postpone_association_work(priv);
1442                 lbs_deb_wext("Switching to mode: 0x%x\n", *uwrq);
1443         }
1444         mutex_unlock(&adapter->lock);
1445
1446 out:
1447         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1448         return ret;
1449 }
1450
1451
1452 /**
1453  *  @brief Get Encryption key
1454  *
1455  *  @param dev                  A pointer to net_device structure
1456  *  @param info                 A pointer to iw_request_info structure
1457  *  @param vwrq                 A pointer to iw_param structure
1458  *  @param extra                A pointer to extra data buf
1459  *  @return                     0 --success, otherwise fail
1460  */
1461 static int wlan_get_encode(struct net_device *dev,
1462                            struct iw_request_info *info,
1463                            struct iw_point *dwrq, u8 * extra)
1464 {
1465         wlan_private *priv = dev->priv;
1466         wlan_adapter *adapter = priv->adapter;
1467         int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
1468
1469         lbs_deb_enter(LBS_DEB_WEXT);
1470
1471         lbs_deb_wext("flags 0x%x, index %d, length %d, wep_tx_keyidx %d\n",
1472                dwrq->flags, index, dwrq->length, adapter->wep_tx_keyidx);
1473
1474         dwrq->flags = 0;
1475
1476         /* Authentication method */
1477         switch (adapter->secinfo.auth_mode) {
1478         case IW_AUTH_ALG_OPEN_SYSTEM:
1479                 dwrq->flags = IW_ENCODE_OPEN;
1480                 break;
1481
1482         case IW_AUTH_ALG_SHARED_KEY:
1483         case IW_AUTH_ALG_LEAP:
1484                 dwrq->flags = IW_ENCODE_RESTRICTED;
1485                 break;
1486         default:
1487                 dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
1488                 break;
1489         }
1490
1491         if (   adapter->secinfo.wep_enabled
1492             || adapter->secinfo.WPAenabled
1493             || adapter->secinfo.WPA2enabled) {
1494                 dwrq->flags &= ~IW_ENCODE_DISABLED;
1495         } else {
1496                 dwrq->flags |= IW_ENCODE_DISABLED;
1497         }
1498
1499         memset(extra, 0, 16);
1500
1501         mutex_lock(&adapter->lock);
1502
1503         /* Default to returning current transmit key */
1504         if (index < 0)
1505                 index = adapter->wep_tx_keyidx;
1506
1507         if ((adapter->wep_keys[index].len) && adapter->secinfo.wep_enabled) {
1508                 memcpy(extra, adapter->wep_keys[index].key,
1509                        adapter->wep_keys[index].len);
1510                 dwrq->length = adapter->wep_keys[index].len;
1511
1512                 dwrq->flags |= (index + 1);
1513                 /* Return WEP enabled */
1514                 dwrq->flags &= ~IW_ENCODE_DISABLED;
1515         } else if ((adapter->secinfo.WPAenabled)
1516                    || (adapter->secinfo.WPA2enabled)) {
1517                 /* return WPA enabled */
1518                 dwrq->flags &= ~IW_ENCODE_DISABLED;
1519         } else {
1520                 dwrq->flags |= IW_ENCODE_DISABLED;
1521         }
1522
1523         mutex_unlock(&adapter->lock);
1524
1525         dwrq->flags |= IW_ENCODE_NOKEY;
1526
1527         lbs_deb_wext("key: " MAC_FMT ", keylen %d\n",
1528                extra[0], extra[1], extra[2],
1529                extra[3], extra[4], extra[5], dwrq->length);
1530
1531         lbs_deb_wext("return flags 0x%x\n", dwrq->flags);
1532
1533         lbs_deb_leave(LBS_DEB_WEXT);
1534         return 0;
1535 }
1536
1537 /**
1538  *  @brief Set Encryption key (internal)
1539  *
1540  *  @param priv                 A pointer to private card structure
1541  *  @param key_material         A pointer to key material
1542  *  @param key_length           length of key material
1543  *  @param index                key index to set
1544  *  @param set_tx_key           Force set TX key (1 = yes, 0 = no)
1545  *  @return                     0 --success, otherwise fail
1546  */
1547 static int wlan_set_wep_key(struct assoc_request *assoc_req,
1548                             const char *key_material,
1549                             u16 key_length,
1550                             u16 index,
1551                             int set_tx_key)
1552 {
1553         int ret = 0;
1554         struct WLAN_802_11_KEY *pkey;
1555
1556         lbs_deb_enter(LBS_DEB_WEXT);
1557
1558         /* Paranoid validation of key index */
1559         if (index > 3) {
1560                 ret = -EINVAL;
1561                 goto out;
1562         }
1563
1564         /* validate max key length */
1565         if (key_length > KEY_LEN_WEP_104) {
1566                 ret = -EINVAL;
1567                 goto out;
1568         }
1569
1570         pkey = &assoc_req->wep_keys[index];
1571
1572         if (key_length > 0) {
1573                 memset(pkey, 0, sizeof(struct WLAN_802_11_KEY));
1574                 pkey->type = KEY_TYPE_ID_WEP;
1575
1576                 /* Standardize the key length */
1577                 pkey->len = (key_length > KEY_LEN_WEP_40) ?
1578                                 KEY_LEN_WEP_104 : KEY_LEN_WEP_40;
1579                 memcpy(pkey->key, key_material, key_length);
1580         }
1581
1582         if (set_tx_key) {
1583                 /* Ensure the chosen key is valid */
1584                 if (!pkey->len) {
1585                         lbs_deb_wext("key not set, so cannot enable it\n");
1586                         ret = -EINVAL;
1587                         goto out;
1588                 }
1589                 assoc_req->wep_tx_keyidx = index;
1590         }
1591
1592         assoc_req->secinfo.wep_enabled = 1;
1593
1594 out:
1595         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1596         return ret;
1597 }
1598
1599 static int validate_key_index(u16 def_index, u16 raw_index,
1600                               u16 *out_index, u16 *is_default)
1601 {
1602         if (!out_index || !is_default)
1603                 return -EINVAL;
1604
1605         /* Verify index if present, otherwise use default TX key index */
1606         if (raw_index > 0) {
1607                 if (raw_index > 4)
1608                         return -EINVAL;
1609                 *out_index = raw_index - 1;
1610         } else {
1611                 *out_index = def_index;
1612                 *is_default = 1;
1613         }
1614         return 0;
1615 }
1616
1617 static void disable_wep(struct assoc_request *assoc_req)
1618 {
1619         int i;
1620
1621         /* Set Open System auth mode */
1622         assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
1623
1624         /* Clear WEP keys and mark WEP as disabled */
1625         assoc_req->secinfo.wep_enabled = 0;
1626         for (i = 0; i < 4; i++)
1627                 assoc_req->wep_keys[i].len = 0;
1628
1629         set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1630         set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1631 }
1632
1633 /**
1634  *  @brief Set Encryption key
1635  *
1636  *  @param dev                  A pointer to net_device structure
1637  *  @param info                 A pointer to iw_request_info structure
1638  *  @param vwrq                 A pointer to iw_param structure
1639  *  @param extra                A pointer to extra data buf
1640  *  @return                     0 --success, otherwise fail
1641  */
1642 static int wlan_set_encode(struct net_device *dev,
1643                     struct iw_request_info *info,
1644                     struct iw_point *dwrq, char *extra)
1645 {
1646         int ret = 0;
1647         wlan_private *priv = dev->priv;
1648         wlan_adapter *adapter = priv->adapter;
1649         struct assoc_request * assoc_req;
1650         u16 is_default = 0, index = 0, set_tx_key = 0;
1651
1652         lbs_deb_enter(LBS_DEB_WEXT);
1653
1654         mutex_lock(&adapter->lock);
1655         assoc_req = wlan_get_association_request(adapter);
1656         if (!assoc_req) {
1657                 ret = -ENOMEM;
1658                 goto out;
1659         }
1660
1661         if (dwrq->flags & IW_ENCODE_DISABLED) {
1662                 disable_wep (assoc_req);
1663                 goto out;
1664         }
1665
1666         ret = validate_key_index(assoc_req->wep_tx_keyidx,
1667                                  (dwrq->flags & IW_ENCODE_INDEX),
1668                                  &index, &is_default);
1669         if (ret) {
1670                 ret = -EINVAL;
1671                 goto out;
1672         }
1673
1674         /* If WEP isn't enabled, or if there is no key data but a valid
1675          * index, set the TX key.
1676          */
1677         if (!assoc_req->secinfo.wep_enabled || (dwrq->length == 0 && !is_default))
1678                 set_tx_key = 1;
1679
1680         ret = wlan_set_wep_key(assoc_req, extra, dwrq->length, index, set_tx_key);
1681         if (ret)
1682                 goto out;
1683
1684         if (dwrq->length)
1685                 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1686         if (set_tx_key)
1687                 set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
1688
1689         if (dwrq->flags & IW_ENCODE_RESTRICTED) {
1690                 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
1691         } else if (dwrq->flags & IW_ENCODE_OPEN) {
1692                 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
1693         }
1694
1695 out:
1696         if (ret == 0) {
1697                 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1698                 wlan_postpone_association_work(priv);
1699         } else {
1700                 wlan_cancel_association_work(priv);
1701         }
1702         mutex_unlock(&adapter->lock);
1703
1704         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1705         return ret;
1706 }
1707
1708 /**
1709  *  @brief Get Extended Encryption key (WPA/802.1x and WEP)
1710  *
1711  *  @param dev                  A pointer to net_device structure
1712  *  @param info                 A pointer to iw_request_info structure
1713  *  @param vwrq                 A pointer to iw_param structure
1714  *  @param extra                A pointer to extra data buf
1715  *  @return                     0 on success, otherwise failure
1716  */
1717 static int wlan_get_encodeext(struct net_device *dev,
1718                               struct iw_request_info *info,
1719                               struct iw_point *dwrq,
1720                               char *extra)
1721 {
1722         int ret = -EINVAL;
1723         wlan_private *priv = dev->priv;
1724         wlan_adapter *adapter = priv->adapter;
1725         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1726         int index, max_key_len;
1727
1728         lbs_deb_enter(LBS_DEB_WEXT);
1729
1730         max_key_len = dwrq->length - sizeof(*ext);
1731         if (max_key_len < 0)
1732                 goto out;
1733
1734         index = dwrq->flags & IW_ENCODE_INDEX;
1735         if (index) {
1736                 if (index < 1 || index > 4)
1737                         goto out;
1738                 index--;
1739         } else {
1740                 index = adapter->wep_tx_keyidx;
1741         }
1742
1743         if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY &&
1744             ext->alg != IW_ENCODE_ALG_WEP) {
1745                 if (index != 0 || adapter->mode != IW_MODE_INFRA)
1746                         goto out;
1747         }
1748
1749         dwrq->flags = index + 1;
1750         memset(ext, 0, sizeof(*ext));
1751
1752         if (   !adapter->secinfo.wep_enabled
1753             && !adapter->secinfo.WPAenabled
1754             && !adapter->secinfo.WPA2enabled) {
1755                 ext->alg = IW_ENCODE_ALG_NONE;
1756                 ext->key_len = 0;
1757                 dwrq->flags |= IW_ENCODE_DISABLED;
1758         } else {
1759                 u8 *key = NULL;
1760
1761                 if (   adapter->secinfo.wep_enabled
1762                     && !adapter->secinfo.WPAenabled
1763                     && !adapter->secinfo.WPA2enabled) {
1764                         ext->alg = IW_ENCODE_ALG_WEP;
1765                         ext->key_len = adapter->wep_keys[index].len;
1766                         key = &adapter->wep_keys[index].key[0];
1767                 } else if (   !adapter->secinfo.wep_enabled
1768                            && (adapter->secinfo.WPAenabled ||
1769                                adapter->secinfo.WPA2enabled)) {
1770                         /* WPA */
1771                         ext->alg = IW_ENCODE_ALG_TKIP;
1772                         ext->key_len = 0;
1773                 } else {
1774                         goto out;
1775                 }
1776
1777                 if (ext->key_len > max_key_len) {
1778                         ret = -E2BIG;
1779                         goto out;
1780                 }
1781
1782                 if (ext->key_len)
1783                         memcpy(ext->key, key, ext->key_len);
1784                 else
1785                         dwrq->flags |= IW_ENCODE_NOKEY;
1786                 dwrq->flags |= IW_ENCODE_ENABLED;
1787         }
1788         ret = 0;
1789
1790 out:
1791         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1792         return ret;
1793 }
1794
1795 /**
1796  *  @brief Set Encryption key Extended (WPA/802.1x and WEP)
1797  *
1798  *  @param dev                  A pointer to net_device structure
1799  *  @param info                 A pointer to iw_request_info structure
1800  *  @param vwrq                 A pointer to iw_param structure
1801  *  @param extra                A pointer to extra data buf
1802  *  @return                     0 --success, otherwise fail
1803  */
1804 static int wlan_set_encodeext(struct net_device *dev,
1805                               struct iw_request_info *info,
1806                               struct iw_point *dwrq,
1807                               char *extra)
1808 {
1809         int ret = 0;
1810         wlan_private *priv = dev->priv;
1811         wlan_adapter *adapter = priv->adapter;
1812         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1813         int alg = ext->alg;
1814         struct assoc_request * assoc_req;
1815
1816         lbs_deb_enter(LBS_DEB_WEXT);
1817
1818         mutex_lock(&adapter->lock);
1819         assoc_req = wlan_get_association_request(adapter);
1820         if (!assoc_req) {
1821                 ret = -ENOMEM;
1822                 goto out;
1823         }
1824
1825         if ((alg == IW_ENCODE_ALG_NONE) || (dwrq->flags & IW_ENCODE_DISABLED)) {
1826                 disable_wep (assoc_req);
1827         } else if (alg == IW_ENCODE_ALG_WEP) {
1828                 u16 is_default = 0, index, set_tx_key = 0;
1829
1830                 ret = validate_key_index(assoc_req->wep_tx_keyidx,
1831                                          (dwrq->flags & IW_ENCODE_INDEX),
1832                                          &index, &is_default);
1833                 if (ret)
1834                         goto out;
1835
1836                 /* If WEP isn't enabled, or if there is no key data but a valid
1837                  * index, or if the set-TX-key flag was passed, set the TX key.
1838                  */
1839                 if (   !assoc_req->secinfo.wep_enabled
1840                     || (dwrq->length == 0 && !is_default)
1841                     || (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY))
1842                         set_tx_key = 1;
1843
1844                 /* Copy key to driver */
1845                 ret = wlan_set_wep_key (assoc_req, ext->key, ext->key_len, index,
1846                                         set_tx_key);
1847                 if (ret)
1848                         goto out;
1849
1850                 if (dwrq->flags & IW_ENCODE_RESTRICTED) {
1851                         assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
1852                 } else if (dwrq->flags & IW_ENCODE_OPEN) {
1853                         assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
1854                 }
1855
1856                 /* Mark the various WEP bits as modified */
1857                 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1858                 if (dwrq->length)
1859                         set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1860                 if (set_tx_key)
1861                         set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
1862
1863         } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) {
1864                 struct WLAN_802_11_KEY * pkey;
1865
1866                 /* validate key length */
1867                 if (((alg == IW_ENCODE_ALG_TKIP)
1868                         && (ext->key_len != KEY_LEN_WPA_TKIP))
1869                     || ((alg == IW_ENCODE_ALG_CCMP)
1870                         && (ext->key_len != KEY_LEN_WPA_AES))) {
1871                                 lbs_deb_wext("invalid size %d for key of alg"
1872                                        "type %d\n",
1873                                        ext->key_len,
1874                                        alg);
1875                                 ret = -EINVAL;
1876                                 goto out;
1877                 }
1878
1879                 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
1880                         pkey = &assoc_req->wpa_mcast_key;
1881                 else
1882                         pkey = &assoc_req->wpa_unicast_key;
1883
1884                 memset(pkey, 0, sizeof (struct WLAN_802_11_KEY));
1885                 memcpy(pkey->key, ext->key, ext->key_len);
1886                 pkey->len = ext->key_len;
1887                 pkey->flags = KEY_INFO_WPA_ENABLED;
1888
1889                 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
1890                         pkey->flags |= KEY_INFO_WPA_MCAST;
1891                         set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
1892                 } else {
1893                         pkey->flags |= KEY_INFO_WPA_UNICAST;
1894                         set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
1895                 }
1896
1897                 if (alg == IW_ENCODE_ALG_TKIP)
1898                         pkey->type = KEY_TYPE_ID_TKIP;
1899                 else if (alg == IW_ENCODE_ALG_CCMP)
1900                         pkey->type = KEY_TYPE_ID_AES;
1901
1902                 /* If WPA isn't enabled yet, do that now */
1903                 if (   assoc_req->secinfo.WPAenabled == 0
1904                     && assoc_req->secinfo.WPA2enabled == 0) {
1905                         assoc_req->secinfo.WPAenabled = 1;
1906                         assoc_req->secinfo.WPA2enabled = 1;
1907                         set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1908                 }
1909
1910                 disable_wep (assoc_req);
1911         }
1912
1913 out:
1914         if (ret == 0) {
1915                 wlan_postpone_association_work(priv);
1916         } else {
1917                 wlan_cancel_association_work(priv);
1918         }
1919         mutex_unlock(&adapter->lock);
1920
1921         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1922         return ret;
1923 }
1924
1925
1926 static int wlan_set_genie(struct net_device *dev,
1927                           struct iw_request_info *info,
1928                           struct iw_point *dwrq,
1929                           char *extra)
1930 {
1931         wlan_private *priv = dev->priv;
1932         wlan_adapter *adapter = priv->adapter;
1933         int ret = 0;
1934         struct assoc_request * assoc_req;
1935
1936         lbs_deb_enter(LBS_DEB_WEXT);
1937
1938         mutex_lock(&adapter->lock);
1939         assoc_req = wlan_get_association_request(adapter);
1940         if (!assoc_req) {
1941                 ret = -ENOMEM;
1942                 goto out;
1943         }
1944
1945         if (dwrq->length > MAX_WPA_IE_LEN ||
1946             (dwrq->length && extra == NULL)) {
1947                 ret = -EINVAL;
1948                 goto out;
1949         }
1950
1951         if (dwrq->length) {
1952                 memcpy(&assoc_req->wpa_ie[0], extra, dwrq->length);
1953                 assoc_req->wpa_ie_len = dwrq->length;
1954         } else {
1955                 memset(&assoc_req->wpa_ie[0], 0, sizeof(adapter->wpa_ie));
1956                 assoc_req->wpa_ie_len = 0;
1957         }
1958
1959 out:
1960         if (ret == 0) {
1961                 set_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags);
1962                 wlan_postpone_association_work(priv);
1963         } else {
1964                 wlan_cancel_association_work(priv);
1965         }
1966         mutex_unlock(&adapter->lock);
1967
1968         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1969         return ret;
1970 }
1971
1972 static int wlan_get_genie(struct net_device *dev,
1973                           struct iw_request_info *info,
1974                           struct iw_point *dwrq,
1975                           char *extra)
1976 {
1977         int ret = 0;
1978         wlan_private *priv = dev->priv;
1979         wlan_adapter *adapter = priv->adapter;
1980
1981         lbs_deb_enter(LBS_DEB_WEXT);
1982
1983         if (adapter->wpa_ie_len == 0) {
1984                 dwrq->length = 0;
1985                 goto out;
1986         }
1987
1988         if (dwrq->length < adapter->wpa_ie_len) {
1989                 ret = -E2BIG;
1990                 goto out;
1991         }
1992
1993         dwrq->length = adapter->wpa_ie_len;
1994         memcpy(extra, &adapter->wpa_ie[0], adapter->wpa_ie_len);
1995
1996 out:
1997         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1998         return ret;
1999 }
2000
2001
2002 static int wlan_set_auth(struct net_device *dev,
2003                          struct iw_request_info *info,
2004                          struct iw_param *dwrq,
2005                          char *extra)
2006 {
2007         wlan_private *priv = dev->priv;
2008         wlan_adapter *adapter = priv->adapter;
2009         struct assoc_request * assoc_req;
2010         int ret = 0;
2011         int updated = 0;
2012
2013         lbs_deb_enter(LBS_DEB_WEXT);
2014
2015         mutex_lock(&adapter->lock);
2016         assoc_req = wlan_get_association_request(adapter);
2017         if (!assoc_req) {
2018                 ret = -ENOMEM;
2019                 goto out;
2020         }
2021
2022         switch (dwrq->flags & IW_AUTH_INDEX) {
2023         case IW_AUTH_TKIP_COUNTERMEASURES:
2024         case IW_AUTH_CIPHER_PAIRWISE:
2025         case IW_AUTH_CIPHER_GROUP:
2026         case IW_AUTH_KEY_MGMT:
2027                 /*
2028                  * libertas does not use these parameters
2029                  */
2030                 break;
2031
2032         case IW_AUTH_WPA_VERSION:
2033                 if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) {
2034                         assoc_req->secinfo.WPAenabled = 0;
2035                         assoc_req->secinfo.WPA2enabled = 0;
2036                 }
2037                 if (dwrq->value & IW_AUTH_WPA_VERSION_WPA) {
2038                         assoc_req->secinfo.WPAenabled = 1;
2039                         assoc_req->secinfo.wep_enabled = 0;
2040                         assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
2041                 }
2042                 if (dwrq->value & IW_AUTH_WPA_VERSION_WPA2) {
2043                         assoc_req->secinfo.WPA2enabled = 1;
2044                         assoc_req->secinfo.wep_enabled = 0;
2045                         assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
2046                 }
2047                 updated = 1;
2048                 break;
2049
2050         case IW_AUTH_DROP_UNENCRYPTED:
2051                 if (dwrq->value) {
2052                         adapter->currentpacketfilter |=
2053                             cmd_act_mac_strict_protection_enable;
2054                 } else {
2055                         adapter->currentpacketfilter &=
2056                             ~cmd_act_mac_strict_protection_enable;
2057                 }
2058                 updated = 1;
2059                 break;
2060
2061         case IW_AUTH_80211_AUTH_ALG:
2062                 if (dwrq->value & IW_AUTH_ALG_SHARED_KEY) {
2063                         assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
2064                 } else if (dwrq->value & IW_AUTH_ALG_OPEN_SYSTEM) {
2065                         assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
2066                 } else if (dwrq->value & IW_AUTH_ALG_LEAP) {
2067                         assoc_req->secinfo.auth_mode = IW_AUTH_ALG_LEAP;
2068                 } else {
2069                         ret = -EINVAL;
2070                 }
2071                 updated = 1;
2072                 break;
2073
2074         case IW_AUTH_WPA_ENABLED:
2075                 if (dwrq->value) {
2076                         if (!assoc_req->secinfo.WPAenabled &&
2077                             !assoc_req->secinfo.WPA2enabled) {
2078                                 assoc_req->secinfo.WPAenabled = 1;
2079                                 assoc_req->secinfo.WPA2enabled = 1;
2080                                 assoc_req->secinfo.wep_enabled = 0;
2081                                 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
2082                         }
2083                 } else {
2084                         assoc_req->secinfo.WPAenabled = 0;
2085                         assoc_req->secinfo.WPA2enabled = 0;
2086                 }
2087                 updated = 1;
2088                 break;
2089
2090         default:
2091                 ret = -EOPNOTSUPP;
2092                 break;
2093         }
2094
2095 out:
2096         if (ret == 0) {
2097                 if (updated)
2098                         set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
2099                 wlan_postpone_association_work(priv);
2100         } else if (ret != -EOPNOTSUPP) {
2101                 wlan_cancel_association_work(priv);
2102         }
2103         mutex_unlock(&adapter->lock);
2104
2105         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
2106         return ret;
2107 }
2108
2109 static int wlan_get_auth(struct net_device *dev,
2110                          struct iw_request_info *info,
2111                          struct iw_param *dwrq,
2112                          char *extra)
2113 {
2114         int ret = 0;
2115         wlan_private *priv = dev->priv;
2116         wlan_adapter *adapter = priv->adapter;
2117
2118         lbs_deb_enter(LBS_DEB_WEXT);
2119
2120         switch (dwrq->flags & IW_AUTH_INDEX) {
2121         case IW_AUTH_WPA_VERSION:
2122                 dwrq->value = 0;
2123                 if (adapter->secinfo.WPAenabled)
2124                         dwrq->value |= IW_AUTH_WPA_VERSION_WPA;
2125                 if (adapter->secinfo.WPA2enabled)
2126                         dwrq->value |= IW_AUTH_WPA_VERSION_WPA2;
2127                 if (!dwrq->value)
2128                         dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED;
2129                 break;
2130
2131         case IW_AUTH_DROP_UNENCRYPTED:
2132                 dwrq->value = 0;
2133                 if (adapter->currentpacketfilter &
2134                     cmd_act_mac_strict_protection_enable)
2135                         dwrq->value = 1;
2136                 break;
2137
2138         case IW_AUTH_80211_AUTH_ALG:
2139                 dwrq->value = adapter->secinfo.auth_mode;
2140                 break;
2141
2142         case IW_AUTH_WPA_ENABLED:
2143                 if (adapter->secinfo.WPAenabled && adapter->secinfo.WPA2enabled)
2144                         dwrq->value = 1;
2145                 break;
2146
2147         default:
2148                 ret = -EOPNOTSUPP;
2149         }
2150
2151         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
2152         return ret;
2153 }
2154
2155
2156 static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info,
2157                    struct iw_param *vwrq, char *extra)
2158 {
2159         int ret = 0;
2160         wlan_private *priv = dev->priv;
2161         wlan_adapter *adapter = priv->adapter;
2162
2163         u16 dbm;
2164
2165         lbs_deb_enter(LBS_DEB_WEXT);
2166
2167         if (vwrq->disabled) {
2168                 wlan_radio_ioctl(priv, RADIO_OFF);
2169                 return 0;
2170         }
2171
2172         adapter->preamble = cmd_type_auto_preamble;
2173
2174         wlan_radio_ioctl(priv, RADIO_ON);
2175
2176         if ((vwrq->flags & IW_TXPOW_TYPE) == IW_TXPOW_MWATT) {
2177                 dbm = (u16) mw_to_dbm(vwrq->value);
2178         } else
2179                 dbm = (u16) vwrq->value;
2180
2181         /* auto tx power control */
2182
2183         if (vwrq->fixed == 0)
2184                 dbm = 0xffff;
2185
2186         lbs_deb_wext("txpower set %d dbm\n", dbm);
2187
2188         ret = libertas_prepare_and_send_command(priv,
2189                                     cmd_802_11_rf_tx_power,
2190                                     cmd_act_tx_power_opt_set_low,
2191                                     cmd_option_waitforrsp, 0, (void *)&dbm);
2192
2193         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
2194         return ret;
2195 }
2196
2197 static int wlan_get_essid(struct net_device *dev, struct iw_request_info *info,
2198                    struct iw_point *dwrq, char *extra)
2199 {
2200         wlan_private *priv = dev->priv;
2201         wlan_adapter *adapter = priv->adapter;
2202
2203         lbs_deb_enter(LBS_DEB_WEXT);
2204
2205         /*
2206          * Note : if dwrq->flags != 0, we should get the relevant SSID from
2207          * the SSID list...
2208          */
2209
2210         /*
2211          * Get the current SSID
2212          */
2213         if (adapter->connect_status == libertas_connected) {
2214                 memcpy(extra, adapter->curbssparams.ssid.ssid,
2215                        adapter->curbssparams.ssid.ssidlength);
2216                 extra[adapter->curbssparams.ssid.ssidlength] = '\0';
2217         } else {
2218                 memset(extra, 0, 32);
2219                 extra[adapter->curbssparams.ssid.ssidlength] = '\0';
2220         }
2221         /*
2222          * If none, we may want to get the one that was set
2223          */
2224
2225         /* To make the driver backward compatible with WPA supplicant v0.2.4 */
2226         if (dwrq->length == 32) /* check with WPA supplicant buffer size */
2227                 dwrq->length = min_t(size_t, adapter->curbssparams.ssid.ssidlength,
2228                                    IW_ESSID_MAX_SIZE);
2229         else
2230                 dwrq->length = adapter->curbssparams.ssid.ssidlength + 1;
2231
2232         dwrq->flags = 1;        /* active */
2233
2234         lbs_deb_leave(LBS_DEB_WEXT);
2235         return 0;
2236 }
2237
2238 static int wlan_set_essid(struct net_device *dev, struct iw_request_info *info,
2239                    struct iw_point *dwrq, char *extra)
2240 {
2241         wlan_private *priv = dev->priv;
2242         wlan_adapter *adapter = priv->adapter;
2243         int ret = 0;
2244         struct WLAN_802_11_SSID ssid;
2245         struct assoc_request * assoc_req;
2246         int ssid_len = dwrq->length;
2247
2248         lbs_deb_enter(LBS_DEB_WEXT);
2249
2250         /*
2251          * WE-20 and earlier NULL pad the end of the SSID and increment
2252          * SSID length so it can be used like a string.  WE-21 and later don't,
2253          * but some userspace tools aren't able to cope with the change.
2254          */
2255         if ((ssid_len > 0) && (extra[ssid_len - 1] == '\0'))
2256                 ssid_len--;
2257
2258         /* Check the size of the string */
2259         if (ssid_len > IW_ESSID_MAX_SIZE) {
2260                 ret = -E2BIG;
2261                 goto out;
2262         }
2263
2264         memset(&ssid, 0, sizeof(struct WLAN_802_11_SSID));
2265
2266         if (!dwrq->flags || !ssid_len) {
2267                 /* "any" SSID requested; leave SSID blank */
2268         } else {
2269                 /* Specific SSID requested */
2270                 memcpy(&ssid.ssid, extra, ssid_len);
2271                 ssid.ssidlength = ssid_len;
2272         }
2273
2274         lbs_deb_wext("requested new SSID '%s'\n",
2275                (ssid.ssidlength > 0) ? (char *)ssid.ssid : "any");
2276
2277 out:
2278         mutex_lock(&adapter->lock);
2279         if (ret == 0) {
2280                 /* Get or create the current association request */
2281                 assoc_req = wlan_get_association_request(adapter);
2282                 if (!assoc_req) {
2283                         ret = -ENOMEM;
2284                 } else {
2285                         /* Copy the SSID to the association request */
2286                         memcpy(&assoc_req->ssid, &ssid, sizeof(struct WLAN_802_11_SSID));
2287                         set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
2288                         wlan_postpone_association_work(priv);
2289                 }
2290         }
2291
2292         /* Cancel the association request if there was an error */
2293         if (ret != 0) {
2294                 wlan_cancel_association_work(priv);
2295         }
2296
2297         mutex_unlock(&adapter->lock);
2298
2299         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
2300         return ret;
2301 }
2302
2303 /**
2304  *  @brief Connect to the AP or Ad-hoc Network with specific bssid
2305  *
2306  *  @param dev          A pointer to net_device structure
2307  *  @param info         A pointer to iw_request_info structure
2308  *  @param awrq         A pointer to iw_param structure
2309  *  @param extra        A pointer to extra data buf
2310  *  @return             0 --success, otherwise fail
2311  */
2312 static int wlan_set_wap(struct net_device *dev, struct iw_request_info *info,
2313                  struct sockaddr *awrq, char *extra)
2314 {
2315         wlan_private *priv = dev->priv;
2316         wlan_adapter *adapter = priv->adapter;
2317         struct assoc_request * assoc_req;
2318         int ret = 0;
2319
2320         lbs_deb_enter(LBS_DEB_WEXT);
2321
2322         if (awrq->sa_family != ARPHRD_ETHER)
2323                 return -EINVAL;
2324
2325         lbs_deb_wext("ASSOC: WAP: sa_data " MAC_FMT "\n", MAC_ARG(awrq->sa_data));
2326
2327         mutex_lock(&adapter->lock);
2328
2329         /* Get or create the current association request */
2330         assoc_req = wlan_get_association_request(adapter);
2331         if (!assoc_req) {
2332                 wlan_cancel_association_work(priv);
2333                 ret = -ENOMEM;
2334         } else {
2335                 /* Copy the BSSID to the association request */
2336                 memcpy(&assoc_req->bssid, awrq->sa_data, ETH_ALEN);
2337                 set_bit(ASSOC_FLAG_BSSID, &assoc_req->flags);
2338                 wlan_postpone_association_work(priv);
2339         }
2340
2341         mutex_unlock(&adapter->lock);
2342
2343         return ret;
2344 }
2345
2346 void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen)
2347 {
2348         union {
2349                 u32 l;
2350                 u8 c[4];
2351         } ver;
2352         char fwver[32];
2353
2354         mutex_lock(&adapter->lock);
2355         ver.l = adapter->fwreleasenumber;
2356         mutex_unlock(&adapter->lock);
2357
2358         if (ver.c[3] == 0)
2359                 sprintf(fwver, "%u.%u.%u", ver.c[2], ver.c[1], ver.c[0]);
2360         else
2361                 sprintf(fwver, "%u.%u.%u.p%u",
2362                         ver.c[2], ver.c[1], ver.c[0], ver.c[3]);
2363
2364         snprintf(fwversion, maxlen, fwver);
2365 }
2366
2367
2368 /*
2369  * iwconfig settable callbacks
2370  */
2371 static const iw_handler wlan_handler[] = {
2372         (iw_handler) NULL,      /* SIOCSIWCOMMIT */
2373         (iw_handler) wlan_get_name,     /* SIOCGIWNAME */
2374         (iw_handler) NULL,      /* SIOCSIWNWID */
2375         (iw_handler) NULL,      /* SIOCGIWNWID */
2376         (iw_handler) wlan_set_freq,     /* SIOCSIWFREQ */
2377         (iw_handler) wlan_get_freq,     /* SIOCGIWFREQ */
2378         (iw_handler) wlan_set_mode,     /* SIOCSIWMODE */
2379         (iw_handler) wlan_get_mode,     /* SIOCGIWMODE */
2380         (iw_handler) NULL,      /* SIOCSIWSENS */
2381         (iw_handler) NULL,      /* SIOCGIWSENS */
2382         (iw_handler) NULL,      /* SIOCSIWRANGE */
2383         (iw_handler) wlan_get_range,    /* SIOCGIWRANGE */
2384         (iw_handler) NULL,      /* SIOCSIWPRIV */
2385         (iw_handler) NULL,      /* SIOCGIWPRIV */
2386         (iw_handler) NULL,      /* SIOCSIWSTATS */
2387         (iw_handler) NULL,      /* SIOCGIWSTATS */
2388         iw_handler_set_spy,     /* SIOCSIWSPY */
2389         iw_handler_get_spy,     /* SIOCGIWSPY */
2390         iw_handler_set_thrspy,  /* SIOCSIWTHRSPY */
2391         iw_handler_get_thrspy,  /* SIOCGIWTHRSPY */
2392         (iw_handler) wlan_set_wap,      /* SIOCSIWAP */
2393         (iw_handler) wlan_get_wap,      /* SIOCGIWAP */
2394         (iw_handler) NULL,      /* SIOCSIWMLME */
2395         (iw_handler) NULL,      /* SIOCGIWAPLIST - deprecated */
2396         (iw_handler) libertas_set_scan, /* SIOCSIWSCAN */
2397         (iw_handler) libertas_get_scan, /* SIOCGIWSCAN */
2398         (iw_handler) wlan_set_essid,    /* SIOCSIWESSID */
2399         (iw_handler) wlan_get_essid,    /* SIOCGIWESSID */
2400         (iw_handler) wlan_set_nick,     /* SIOCSIWNICKN */
2401         (iw_handler) wlan_get_nick,     /* SIOCGIWNICKN */
2402         (iw_handler) NULL,      /* -- hole -- */
2403         (iw_handler) NULL,      /* -- hole -- */
2404         (iw_handler) wlan_set_rate,     /* SIOCSIWRATE */
2405         (iw_handler) wlan_get_rate,     /* SIOCGIWRATE */
2406         (iw_handler) wlan_set_rts,      /* SIOCSIWRTS */
2407         (iw_handler) wlan_get_rts,      /* SIOCGIWRTS */
2408         (iw_handler) wlan_set_frag,     /* SIOCSIWFRAG */
2409         (iw_handler) wlan_get_frag,     /* SIOCGIWFRAG */
2410         (iw_handler) wlan_set_txpow,    /* SIOCSIWTXPOW */
2411         (iw_handler) wlan_get_txpow,    /* SIOCGIWTXPOW */
2412         (iw_handler) wlan_set_retry,    /* SIOCSIWRETRY */
2413         (iw_handler) wlan_get_retry,    /* SIOCGIWRETRY */
2414         (iw_handler) wlan_set_encode,   /* SIOCSIWENCODE */
2415         (iw_handler) wlan_get_encode,   /* SIOCGIWENCODE */
2416         (iw_handler) wlan_set_power,    /* SIOCSIWPOWER */
2417         (iw_handler) wlan_get_power,    /* SIOCGIWPOWER */
2418         (iw_handler) NULL,      /* -- hole -- */
2419         (iw_handler) NULL,      /* -- hole -- */
2420         (iw_handler) wlan_set_genie,    /* SIOCSIWGENIE */
2421         (iw_handler) wlan_get_genie,    /* SIOCGIWGENIE */
2422         (iw_handler) wlan_set_auth,     /* SIOCSIWAUTH */
2423         (iw_handler) wlan_get_auth,     /* SIOCGIWAUTH */
2424         (iw_handler) wlan_set_encodeext,/* SIOCSIWENCODEEXT */
2425         (iw_handler) wlan_get_encodeext,/* SIOCGIWENCODEEXT */
2426         (iw_handler) NULL,              /* SIOCSIWPMKSA */
2427 };
2428
2429 struct iw_handler_def libertas_handler_def = {
2430         .num_standard   = sizeof(wlan_handler) / sizeof(iw_handler),
2431         .num_private    = sizeof(wlan_private_handler) / sizeof(iw_handler),
2432         .num_private_args = sizeof(wlan_private_args) /
2433                 sizeof(struct iw_priv_args),
2434         .standard       = (iw_handler *) wlan_handler,
2435         .private        = (iw_handler *) wlan_private_handler,
2436         .private_args   = (struct iw_priv_args *)wlan_private_args,
2437         .get_wireless_stats = wlan_get_wireless_stats,
2438 };