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