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