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