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