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