p54: include support for 2.13.24.0 USB LM87 Firmwares
[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/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 = netdev_priv(dev);
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 = netdev_priv(dev);
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 = netdev_priv(dev);
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 = netdev_priv(dev);
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 = netdev_priv(dev);
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 = netdev_priv(dev);
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 = netdev_priv(dev);
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 = netdev_priv(dev);
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 = netdev_priv(dev);
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 = netdev_priv(dev);
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 = netdev_priv(dev);
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 = netdev_priv(dev);
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 = netdev_priv(dev);
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 = netdev_priv(dev);
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 = netdev_priv(dev);
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 = netdev_priv(dev);
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 = netdev_priv(dev);
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 = netdev_priv(dev);
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 = netdev_priv(dev);
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 = netdev_priv(dev);
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                 if (priv->fwrelease < 0x09000000) {
1029                         ret = lbs_set_power_adapt_cfg(priv, 0,
1030                                         POW_ADAPT_DEFAULT_P0,
1031                                         POW_ADAPT_DEFAULT_P1,
1032                                         POW_ADAPT_DEFAULT_P2);
1033                         if (ret)
1034                                 goto out;
1035                 }
1036                 ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1,
1037                                 TPC_DEFAULT_P2, 1);
1038                 if (ret)
1039                         goto out;
1040         }
1041
1042         /* Try the newer command first (Firmware Spec 5.1 and above) */
1043         ret = lbs_cmd_802_11_rate_adapt_rateset(priv, CMD_ACT_SET);
1044
1045         /* Fallback to older version */
1046         if (ret)
1047                 ret = lbs_set_data_rate(priv, new_rate);
1048
1049 out:
1050         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1051         return ret;
1052 }
1053
1054 static int lbs_get_rate(struct net_device *dev, struct iw_request_info *info,
1055                   struct iw_param *vwrq, char *extra)
1056 {
1057         struct lbs_private *priv = netdev_priv(dev);
1058
1059         lbs_deb_enter(LBS_DEB_WEXT);
1060
1061         if (priv->connect_status == LBS_CONNECTED) {
1062                 vwrq->value = priv->cur_rate * 500000;
1063
1064                 if (priv->enablehwauto)
1065                         vwrq->fixed = 0;
1066                 else
1067                         vwrq->fixed = 1;
1068
1069         } else {
1070                 vwrq->fixed = 0;
1071                 vwrq->value = 0;
1072         }
1073
1074         lbs_deb_leave(LBS_DEB_WEXT);
1075         return 0;
1076 }
1077
1078 static int lbs_set_mode(struct net_device *dev,
1079                   struct iw_request_info *info, u32 * uwrq, char *extra)
1080 {
1081         int ret = 0;
1082         struct lbs_private *priv = netdev_priv(dev);
1083         struct assoc_request * assoc_req;
1084
1085         lbs_deb_enter(LBS_DEB_WEXT);
1086
1087         if (   (*uwrq != IW_MODE_ADHOC)
1088             && (*uwrq != IW_MODE_INFRA)
1089             && (*uwrq != IW_MODE_AUTO)) {
1090                 lbs_deb_wext("Invalid mode: 0x%x\n", *uwrq);
1091                 ret = -EINVAL;
1092                 goto out;
1093         }
1094
1095         mutex_lock(&priv->lock);
1096         assoc_req = lbs_get_association_request(priv);
1097         if (!assoc_req) {
1098                 ret = -ENOMEM;
1099                 lbs_cancel_association_work(priv);
1100         } else {
1101                 assoc_req->mode = *uwrq;
1102                 set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
1103                 lbs_postpone_association_work(priv);
1104                 lbs_deb_wext("Switching to mode: 0x%x\n", *uwrq);
1105         }
1106         mutex_unlock(&priv->lock);
1107
1108 out:
1109         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1110         return ret;
1111 }
1112
1113
1114 /**
1115  *  @brief Get Encryption key
1116  *
1117  *  @param dev                  A pointer to net_device structure
1118  *  @param info                 A pointer to iw_request_info structure
1119  *  @param vwrq                 A pointer to iw_param structure
1120  *  @param extra                A pointer to extra data buf
1121  *  @return                     0 --success, otherwise fail
1122  */
1123 static int lbs_get_encode(struct net_device *dev,
1124                            struct iw_request_info *info,
1125                            struct iw_point *dwrq, u8 * extra)
1126 {
1127         struct lbs_private *priv = netdev_priv(dev);
1128         int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
1129
1130         lbs_deb_enter(LBS_DEB_WEXT);
1131
1132         lbs_deb_wext("flags 0x%x, index %d, length %d, wep_tx_keyidx %d\n",
1133                dwrq->flags, index, dwrq->length, priv->wep_tx_keyidx);
1134
1135         dwrq->flags = 0;
1136
1137         /* Authentication method */
1138         switch (priv->secinfo.auth_mode) {
1139         case IW_AUTH_ALG_OPEN_SYSTEM:
1140                 dwrq->flags = IW_ENCODE_OPEN;
1141                 break;
1142
1143         case IW_AUTH_ALG_SHARED_KEY:
1144         case IW_AUTH_ALG_LEAP:
1145                 dwrq->flags = IW_ENCODE_RESTRICTED;
1146                 break;
1147         default:
1148                 dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
1149                 break;
1150         }
1151
1152         memset(extra, 0, 16);
1153
1154         mutex_lock(&priv->lock);
1155
1156         /* Default to returning current transmit key */
1157         if (index < 0)
1158                 index = priv->wep_tx_keyidx;
1159
1160         if ((priv->wep_keys[index].len) && priv->secinfo.wep_enabled) {
1161                 memcpy(extra, priv->wep_keys[index].key,
1162                        priv->wep_keys[index].len);
1163                 dwrq->length = priv->wep_keys[index].len;
1164
1165                 dwrq->flags |= (index + 1);
1166                 /* Return WEP enabled */
1167                 dwrq->flags &= ~IW_ENCODE_DISABLED;
1168         } else if ((priv->secinfo.WPAenabled)
1169                    || (priv->secinfo.WPA2enabled)) {
1170                 /* return WPA enabled */
1171                 dwrq->flags &= ~IW_ENCODE_DISABLED;
1172                 dwrq->flags |= IW_ENCODE_NOKEY;
1173         } else {
1174                 dwrq->flags |= IW_ENCODE_DISABLED;
1175         }
1176
1177         mutex_unlock(&priv->lock);
1178
1179         lbs_deb_wext("key: %02x:%02x:%02x:%02x:%02x:%02x, keylen %d\n",
1180                extra[0], extra[1], extra[2],
1181                extra[3], extra[4], extra[5], dwrq->length);
1182
1183         lbs_deb_wext("return flags 0x%x\n", dwrq->flags);
1184
1185         lbs_deb_leave(LBS_DEB_WEXT);
1186         return 0;
1187 }
1188
1189 /**
1190  *  @brief Set Encryption key (internal)
1191  *
1192  *  @param priv                 A pointer to private card structure
1193  *  @param key_material         A pointer to key material
1194  *  @param key_length           length of key material
1195  *  @param index                key index to set
1196  *  @param set_tx_key           Force set TX key (1 = yes, 0 = no)
1197  *  @return                     0 --success, otherwise fail
1198  */
1199 static int lbs_set_wep_key(struct assoc_request *assoc_req,
1200                             const char *key_material,
1201                             u16 key_length,
1202                             u16 index,
1203                             int set_tx_key)
1204 {
1205         int ret = 0;
1206         struct enc_key *pkey;
1207
1208         lbs_deb_enter(LBS_DEB_WEXT);
1209
1210         /* Paranoid validation of key index */
1211         if (index > 3) {
1212                 ret = -EINVAL;
1213                 goto out;
1214         }
1215
1216         /* validate max key length */
1217         if (key_length > KEY_LEN_WEP_104) {
1218                 ret = -EINVAL;
1219                 goto out;
1220         }
1221
1222         pkey = &assoc_req->wep_keys[index];
1223
1224         if (key_length > 0) {
1225                 memset(pkey, 0, sizeof(struct enc_key));
1226                 pkey->type = KEY_TYPE_ID_WEP;
1227
1228                 /* Standardize the key length */
1229                 pkey->len = (key_length > KEY_LEN_WEP_40) ?
1230                                 KEY_LEN_WEP_104 : KEY_LEN_WEP_40;
1231                 memcpy(pkey->key, key_material, key_length);
1232         }
1233
1234         if (set_tx_key) {
1235                 /* Ensure the chosen key is valid */
1236                 if (!pkey->len) {
1237                         lbs_deb_wext("key not set, so cannot enable it\n");
1238                         ret = -EINVAL;
1239                         goto out;
1240                 }
1241                 assoc_req->wep_tx_keyidx = index;
1242         }
1243
1244         assoc_req->secinfo.wep_enabled = 1;
1245
1246 out:
1247         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1248         return ret;
1249 }
1250
1251 static int validate_key_index(u16 def_index, u16 raw_index,
1252                               u16 *out_index, u16 *is_default)
1253 {
1254         if (!out_index || !is_default)
1255                 return -EINVAL;
1256
1257         /* Verify index if present, otherwise use default TX key index */
1258         if (raw_index > 0) {
1259                 if (raw_index > 4)
1260                         return -EINVAL;
1261                 *out_index = raw_index - 1;
1262         } else {
1263                 *out_index = def_index;
1264                 *is_default = 1;
1265         }
1266         return 0;
1267 }
1268
1269 static void disable_wep(struct assoc_request *assoc_req)
1270 {
1271         int i;
1272
1273         lbs_deb_enter(LBS_DEB_WEXT);
1274
1275         /* Set Open System auth mode */
1276         assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
1277
1278         /* Clear WEP keys and mark WEP as disabled */
1279         assoc_req->secinfo.wep_enabled = 0;
1280         for (i = 0; i < 4; i++)
1281                 assoc_req->wep_keys[i].len = 0;
1282
1283         set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1284         set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1285
1286         lbs_deb_leave(LBS_DEB_WEXT);
1287 }
1288
1289 static void disable_wpa(struct assoc_request *assoc_req)
1290 {
1291         lbs_deb_enter(LBS_DEB_WEXT);
1292
1293         memset(&assoc_req->wpa_mcast_key, 0, sizeof (struct enc_key));
1294         assoc_req->wpa_mcast_key.flags = KEY_INFO_WPA_MCAST;
1295         set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
1296
1297         memset(&assoc_req->wpa_unicast_key, 0, sizeof (struct enc_key));
1298         assoc_req->wpa_unicast_key.flags = KEY_INFO_WPA_UNICAST;
1299         set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
1300
1301         assoc_req->secinfo.WPAenabled = 0;
1302         assoc_req->secinfo.WPA2enabled = 0;
1303         set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1304
1305         lbs_deb_leave(LBS_DEB_WEXT);
1306 }
1307
1308 /**
1309  *  @brief Set Encryption key
1310  *
1311  *  @param dev                  A pointer to net_device structure
1312  *  @param info                 A pointer to iw_request_info structure
1313  *  @param vwrq                 A pointer to iw_param structure
1314  *  @param extra                A pointer to extra data buf
1315  *  @return                     0 --success, otherwise fail
1316  */
1317 static int lbs_set_encode(struct net_device *dev,
1318                     struct iw_request_info *info,
1319                     struct iw_point *dwrq, char *extra)
1320 {
1321         int ret = 0;
1322         struct lbs_private *priv = netdev_priv(dev);
1323         struct assoc_request * assoc_req;
1324         u16 is_default = 0, index = 0, set_tx_key = 0;
1325
1326         lbs_deb_enter(LBS_DEB_WEXT);
1327
1328         mutex_lock(&priv->lock);
1329         assoc_req = lbs_get_association_request(priv);
1330         if (!assoc_req) {
1331                 ret = -ENOMEM;
1332                 goto out;
1333         }
1334
1335         if (dwrq->flags & IW_ENCODE_DISABLED) {
1336                 disable_wep (assoc_req);
1337                 disable_wpa (assoc_req);
1338                 goto out;
1339         }
1340
1341         ret = validate_key_index(assoc_req->wep_tx_keyidx,
1342                                  (dwrq->flags & IW_ENCODE_INDEX),
1343                                  &index, &is_default);
1344         if (ret) {
1345                 ret = -EINVAL;
1346                 goto out;
1347         }
1348
1349         /* If WEP isn't enabled, or if there is no key data but a valid
1350          * index, set the TX key.
1351          */
1352         if (!assoc_req->secinfo.wep_enabled || (dwrq->length == 0 && !is_default))
1353                 set_tx_key = 1;
1354
1355         ret = lbs_set_wep_key(assoc_req, extra, dwrq->length, index, set_tx_key);
1356         if (ret)
1357                 goto out;
1358
1359         if (dwrq->length)
1360                 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1361         if (set_tx_key)
1362                 set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
1363
1364         if (dwrq->flags & IW_ENCODE_RESTRICTED) {
1365                 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
1366         } else if (dwrq->flags & IW_ENCODE_OPEN) {
1367                 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
1368         }
1369
1370 out:
1371         if (ret == 0) {
1372                 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1373                 lbs_postpone_association_work(priv);
1374         } else {
1375                 lbs_cancel_association_work(priv);
1376         }
1377         mutex_unlock(&priv->lock);
1378
1379         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1380         return ret;
1381 }
1382
1383 /**
1384  *  @brief Get Extended Encryption key (WPA/802.1x and WEP)
1385  *
1386  *  @param dev                  A pointer to net_device structure
1387  *  @param info                 A pointer to iw_request_info structure
1388  *  @param vwrq                 A pointer to iw_param structure
1389  *  @param extra                A pointer to extra data buf
1390  *  @return                     0 on success, otherwise failure
1391  */
1392 static int lbs_get_encodeext(struct net_device *dev,
1393                               struct iw_request_info *info,
1394                               struct iw_point *dwrq,
1395                               char *extra)
1396 {
1397         int ret = -EINVAL;
1398         struct lbs_private *priv = netdev_priv(dev);
1399         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1400         int index, max_key_len;
1401
1402         lbs_deb_enter(LBS_DEB_WEXT);
1403
1404         max_key_len = dwrq->length - sizeof(*ext);
1405         if (max_key_len < 0)
1406                 goto out;
1407
1408         index = dwrq->flags & IW_ENCODE_INDEX;
1409         if (index) {
1410                 if (index < 1 || index > 4)
1411                         goto out;
1412                 index--;
1413         } else {
1414                 index = priv->wep_tx_keyidx;
1415         }
1416
1417         if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
1418             ext->alg != IW_ENCODE_ALG_WEP) {
1419                 if (index != 0 || priv->mode != IW_MODE_INFRA)
1420                         goto out;
1421         }
1422
1423         dwrq->flags = index + 1;
1424         memset(ext, 0, sizeof(*ext));
1425
1426         if (   !priv->secinfo.wep_enabled
1427             && !priv->secinfo.WPAenabled
1428             && !priv->secinfo.WPA2enabled) {
1429                 ext->alg = IW_ENCODE_ALG_NONE;
1430                 ext->key_len = 0;
1431                 dwrq->flags |= IW_ENCODE_DISABLED;
1432         } else {
1433                 u8 *key = NULL;
1434
1435                 if (   priv->secinfo.wep_enabled
1436                     && !priv->secinfo.WPAenabled
1437                     && !priv->secinfo.WPA2enabled) {
1438                         /* WEP */
1439                         ext->alg = IW_ENCODE_ALG_WEP;
1440                         ext->key_len = priv->wep_keys[index].len;
1441                         key = &priv->wep_keys[index].key[0];
1442                 } else if (   !priv->secinfo.wep_enabled
1443                            && (priv->secinfo.WPAenabled ||
1444                                priv->secinfo.WPA2enabled)) {
1445                         /* WPA */
1446                         struct enc_key * pkey = NULL;
1447
1448                         if (   priv->wpa_mcast_key.len
1449                             && (priv->wpa_mcast_key.flags & KEY_INFO_WPA_ENABLED))
1450                                 pkey = &priv->wpa_mcast_key;
1451                         else if (   priv->wpa_unicast_key.len
1452                                  && (priv->wpa_unicast_key.flags & KEY_INFO_WPA_ENABLED))
1453                                 pkey = &priv->wpa_unicast_key;
1454
1455                         if (pkey) {
1456                                 if (pkey->type == KEY_TYPE_ID_AES) {
1457                                         ext->alg = IW_ENCODE_ALG_CCMP;
1458                                 } else {
1459                                         ext->alg = IW_ENCODE_ALG_TKIP;
1460                                 }
1461                                 ext->key_len = pkey->len;
1462                                 key = &pkey->key[0];
1463                         } else {
1464                                 ext->alg = IW_ENCODE_ALG_TKIP;
1465                                 ext->key_len = 0;
1466                         }
1467                 } else {
1468                         goto out;
1469                 }
1470
1471                 if (ext->key_len > max_key_len) {
1472                         ret = -E2BIG;
1473                         goto out;
1474                 }
1475
1476                 if (ext->key_len)
1477                         memcpy(ext->key, key, ext->key_len);
1478                 else
1479                         dwrq->flags |= IW_ENCODE_NOKEY;
1480                 dwrq->flags |= IW_ENCODE_ENABLED;
1481         }
1482         ret = 0;
1483
1484 out:
1485         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1486         return ret;
1487 }
1488
1489 /**
1490  *  @brief Set Encryption key Extended (WPA/802.1x and WEP)
1491  *
1492  *  @param dev                  A pointer to net_device structure
1493  *  @param info                 A pointer to iw_request_info structure
1494  *  @param vwrq                 A pointer to iw_param structure
1495  *  @param extra                A pointer to extra data buf
1496  *  @return                     0 --success, otherwise fail
1497  */
1498 static int lbs_set_encodeext(struct net_device *dev,
1499                               struct iw_request_info *info,
1500                               struct iw_point *dwrq,
1501                               char *extra)
1502 {
1503         int ret = 0;
1504         struct lbs_private *priv = netdev_priv(dev);
1505         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1506         int alg = ext->alg;
1507         struct assoc_request * assoc_req;
1508
1509         lbs_deb_enter(LBS_DEB_WEXT);
1510
1511         mutex_lock(&priv->lock);
1512         assoc_req = lbs_get_association_request(priv);
1513         if (!assoc_req) {
1514                 ret = -ENOMEM;
1515                 goto out;
1516         }
1517
1518         if ((alg == IW_ENCODE_ALG_NONE) || (dwrq->flags & IW_ENCODE_DISABLED)) {
1519                 disable_wep (assoc_req);
1520                 disable_wpa (assoc_req);
1521         } else if (alg == IW_ENCODE_ALG_WEP) {
1522                 u16 is_default = 0, index, set_tx_key = 0;
1523
1524                 ret = validate_key_index(assoc_req->wep_tx_keyidx,
1525                                          (dwrq->flags & IW_ENCODE_INDEX),
1526                                          &index, &is_default);
1527                 if (ret)
1528                         goto out;
1529
1530                 /* If WEP isn't enabled, or if there is no key data but a valid
1531                  * index, or if the set-TX-key flag was passed, set the TX key.
1532                  */
1533                 if (   !assoc_req->secinfo.wep_enabled
1534                     || (dwrq->length == 0 && !is_default)
1535                     || (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY))
1536                         set_tx_key = 1;
1537
1538                 /* Copy key to driver */
1539                 ret = lbs_set_wep_key(assoc_req, ext->key, ext->key_len, index,
1540                                         set_tx_key);
1541                 if (ret)
1542                         goto out;
1543
1544                 if (dwrq->flags & IW_ENCODE_RESTRICTED) {
1545                         assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
1546                 } else if (dwrq->flags & IW_ENCODE_OPEN) {
1547                         assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
1548                 }
1549
1550                 /* Mark the various WEP bits as modified */
1551                 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1552                 if (dwrq->length)
1553                         set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1554                 if (set_tx_key)
1555                         set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
1556         } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) {
1557                 struct enc_key * pkey;
1558
1559                 /* validate key length */
1560                 if (((alg == IW_ENCODE_ALG_TKIP)
1561                         && (ext->key_len != KEY_LEN_WPA_TKIP))
1562                     || ((alg == IW_ENCODE_ALG_CCMP)
1563                         && (ext->key_len != KEY_LEN_WPA_AES))) {
1564                                 lbs_deb_wext("invalid size %d for key of alg "
1565                                        "type %d\n",
1566                                        ext->key_len,
1567                                        alg);
1568                                 ret = -EINVAL;
1569                                 goto out;
1570                 }
1571
1572                 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
1573                         pkey = &assoc_req->wpa_mcast_key;
1574                         set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
1575                 } else {
1576                         pkey = &assoc_req->wpa_unicast_key;
1577                         set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
1578                 }
1579
1580                 memset(pkey, 0, sizeof (struct enc_key));
1581                 memcpy(pkey->key, ext->key, ext->key_len);
1582                 pkey->len = ext->key_len;
1583                 if (pkey->len)
1584                         pkey->flags |= KEY_INFO_WPA_ENABLED;
1585
1586                 /* Do this after zeroing key structure */
1587                 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
1588                         pkey->flags |= KEY_INFO_WPA_MCAST;
1589                 } else {
1590                         pkey->flags |= KEY_INFO_WPA_UNICAST;
1591                 }
1592
1593                 if (alg == IW_ENCODE_ALG_TKIP) {
1594                         pkey->type = KEY_TYPE_ID_TKIP;
1595                 } else if (alg == IW_ENCODE_ALG_CCMP) {
1596                         pkey->type = KEY_TYPE_ID_AES;
1597                 }
1598
1599                 /* If WPA isn't enabled yet, do that now */
1600                 if (   assoc_req->secinfo.WPAenabled == 0
1601                     && assoc_req->secinfo.WPA2enabled == 0) {
1602                         assoc_req->secinfo.WPAenabled = 1;
1603                         assoc_req->secinfo.WPA2enabled = 1;
1604                         set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1605                 }
1606
1607                 /* Only disable wep if necessary: can't waste time here. */
1608                 if (priv->mac_control & CMD_ACT_MAC_WEP_ENABLE)
1609                         disable_wep(assoc_req);
1610         }
1611
1612 out:
1613         if (ret == 0) {
1614                 /* 802.1x and WPA rekeying must happen as quickly as possible,
1615                  * especially during the 4-way handshake; thus if in
1616                  * infrastructure mode, and either (a) 802.1x is enabled or
1617                  * (b) WPA is being used, set the key right away.
1618                  */
1619                 if (assoc_req->mode == IW_MODE_INFRA &&
1620                     ((assoc_req->secinfo.key_mgmt & IW_AUTH_KEY_MGMT_802_1X) ||
1621                      (assoc_req->secinfo.key_mgmt & IW_AUTH_KEY_MGMT_PSK) ||
1622                       assoc_req->secinfo.WPAenabled ||
1623                       assoc_req->secinfo.WPA2enabled)) {
1624                         lbs_do_association_work(priv);
1625                 } else
1626                         lbs_postpone_association_work(priv);
1627         } else {
1628                 lbs_cancel_association_work(priv);
1629         }
1630         mutex_unlock(&priv->lock);
1631
1632         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1633         return ret;
1634 }
1635
1636
1637 static int lbs_set_genie(struct net_device *dev,
1638                           struct iw_request_info *info,
1639                           struct iw_point *dwrq,
1640                           char *extra)
1641 {
1642         struct lbs_private *priv = netdev_priv(dev);
1643         int ret = 0;
1644         struct assoc_request * assoc_req;
1645
1646         lbs_deb_enter(LBS_DEB_WEXT);
1647
1648         mutex_lock(&priv->lock);
1649         assoc_req = lbs_get_association_request(priv);
1650         if (!assoc_req) {
1651                 ret = -ENOMEM;
1652                 goto out;
1653         }
1654
1655         if (dwrq->length > MAX_WPA_IE_LEN ||
1656             (dwrq->length && extra == NULL)) {
1657                 ret = -EINVAL;
1658                 goto out;
1659         }
1660
1661         if (dwrq->length) {
1662                 memcpy(&assoc_req->wpa_ie[0], extra, dwrq->length);
1663                 assoc_req->wpa_ie_len = dwrq->length;
1664         } else {
1665                 memset(&assoc_req->wpa_ie[0], 0, sizeof(priv->wpa_ie));
1666                 assoc_req->wpa_ie_len = 0;
1667         }
1668
1669 out:
1670         if (ret == 0) {
1671                 set_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags);
1672                 lbs_postpone_association_work(priv);
1673         } else {
1674                 lbs_cancel_association_work(priv);
1675         }
1676         mutex_unlock(&priv->lock);
1677
1678         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1679         return ret;
1680 }
1681
1682 static int lbs_get_genie(struct net_device *dev,
1683                           struct iw_request_info *info,
1684                           struct iw_point *dwrq,
1685                           char *extra)
1686 {
1687         int ret = 0;
1688         struct lbs_private *priv = netdev_priv(dev);
1689
1690         lbs_deb_enter(LBS_DEB_WEXT);
1691
1692         if (priv->wpa_ie_len == 0) {
1693                 dwrq->length = 0;
1694                 goto out;
1695         }
1696
1697         if (dwrq->length < priv->wpa_ie_len) {
1698                 ret = -E2BIG;
1699                 goto out;
1700         }
1701
1702         dwrq->length = priv->wpa_ie_len;
1703         memcpy(extra, &priv->wpa_ie[0], priv->wpa_ie_len);
1704
1705 out:
1706         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1707         return ret;
1708 }
1709
1710
1711 static int lbs_set_auth(struct net_device *dev,
1712                          struct iw_request_info *info,
1713                          struct iw_param *dwrq,
1714                          char *extra)
1715 {
1716         struct lbs_private *priv = netdev_priv(dev);
1717         struct assoc_request * assoc_req;
1718         int ret = 0;
1719         int updated = 0;
1720
1721         lbs_deb_enter(LBS_DEB_WEXT);
1722
1723         mutex_lock(&priv->lock);
1724         assoc_req = lbs_get_association_request(priv);
1725         if (!assoc_req) {
1726                 ret = -ENOMEM;
1727                 goto out;
1728         }
1729
1730         switch (dwrq->flags & IW_AUTH_INDEX) {
1731         case IW_AUTH_TKIP_COUNTERMEASURES:
1732         case IW_AUTH_CIPHER_PAIRWISE:
1733         case IW_AUTH_CIPHER_GROUP:
1734         case IW_AUTH_DROP_UNENCRYPTED:
1735                 /*
1736                  * libertas does not use these parameters
1737                  */
1738                 break;
1739
1740         case IW_AUTH_KEY_MGMT:
1741                 assoc_req->secinfo.key_mgmt = dwrq->value;
1742                 updated = 1;
1743                 break;
1744
1745         case IW_AUTH_WPA_VERSION:
1746                 if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) {
1747                         assoc_req->secinfo.WPAenabled = 0;
1748                         assoc_req->secinfo.WPA2enabled = 0;
1749                         disable_wpa (assoc_req);
1750                 }
1751                 if (dwrq->value & IW_AUTH_WPA_VERSION_WPA) {
1752                         assoc_req->secinfo.WPAenabled = 1;
1753                         assoc_req->secinfo.wep_enabled = 0;
1754                         assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
1755                 }
1756                 if (dwrq->value & IW_AUTH_WPA_VERSION_WPA2) {
1757                         assoc_req->secinfo.WPA2enabled = 1;
1758                         assoc_req->secinfo.wep_enabled = 0;
1759                         assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
1760                 }
1761                 updated = 1;
1762                 break;
1763
1764         case IW_AUTH_80211_AUTH_ALG:
1765                 if (dwrq->value & IW_AUTH_ALG_SHARED_KEY) {
1766                         assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
1767                 } else if (dwrq->value & IW_AUTH_ALG_OPEN_SYSTEM) {
1768                         assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
1769                 } else if (dwrq->value & IW_AUTH_ALG_LEAP) {
1770                         assoc_req->secinfo.auth_mode = IW_AUTH_ALG_LEAP;
1771                 } else {
1772                         ret = -EINVAL;
1773                 }
1774                 updated = 1;
1775                 break;
1776
1777         case IW_AUTH_WPA_ENABLED:
1778                 if (dwrq->value) {
1779                         if (!assoc_req->secinfo.WPAenabled &&
1780                             !assoc_req->secinfo.WPA2enabled) {
1781                                 assoc_req->secinfo.WPAenabled = 1;
1782                                 assoc_req->secinfo.WPA2enabled = 1;
1783                                 assoc_req->secinfo.wep_enabled = 0;
1784                                 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
1785                         }
1786                 } else {
1787                         assoc_req->secinfo.WPAenabled = 0;
1788                         assoc_req->secinfo.WPA2enabled = 0;
1789                         disable_wpa (assoc_req);
1790                 }
1791                 updated = 1;
1792                 break;
1793
1794         default:
1795                 ret = -EOPNOTSUPP;
1796                 break;
1797         }
1798
1799 out:
1800         if (ret == 0) {
1801                 if (updated)
1802                         set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1803                 lbs_postpone_association_work(priv);
1804         } else if (ret != -EOPNOTSUPP) {
1805                 lbs_cancel_association_work(priv);
1806         }
1807         mutex_unlock(&priv->lock);
1808
1809         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1810         return ret;
1811 }
1812
1813 static int lbs_get_auth(struct net_device *dev,
1814                          struct iw_request_info *info,
1815                          struct iw_param *dwrq,
1816                          char *extra)
1817 {
1818         int ret = 0;
1819         struct lbs_private *priv = netdev_priv(dev);
1820
1821         lbs_deb_enter(LBS_DEB_WEXT);
1822
1823         switch (dwrq->flags & IW_AUTH_INDEX) {
1824         case IW_AUTH_KEY_MGMT:
1825                 dwrq->value = priv->secinfo.key_mgmt;
1826                 break;
1827
1828         case IW_AUTH_WPA_VERSION:
1829                 dwrq->value = 0;
1830                 if (priv->secinfo.WPAenabled)
1831                         dwrq->value |= IW_AUTH_WPA_VERSION_WPA;
1832                 if (priv->secinfo.WPA2enabled)
1833                         dwrq->value |= IW_AUTH_WPA_VERSION_WPA2;
1834                 if (!dwrq->value)
1835                         dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED;
1836                 break;
1837
1838         case IW_AUTH_80211_AUTH_ALG:
1839                 dwrq->value = priv->secinfo.auth_mode;
1840                 break;
1841
1842         case IW_AUTH_WPA_ENABLED:
1843                 if (priv->secinfo.WPAenabled && priv->secinfo.WPA2enabled)
1844                         dwrq->value = 1;
1845                 break;
1846
1847         default:
1848                 ret = -EOPNOTSUPP;
1849         }
1850
1851         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1852         return ret;
1853 }
1854
1855
1856 static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info,
1857                    struct iw_param *vwrq, char *extra)
1858 {
1859         int ret = 0;
1860         struct lbs_private *priv = netdev_priv(dev);
1861         s16 dbm = (s16) vwrq->value;
1862
1863         lbs_deb_enter(LBS_DEB_WEXT);
1864
1865         if (vwrq->disabled) {
1866                 lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 0);
1867                 goto out;
1868         }
1869
1870         if (vwrq->fixed == 0) {
1871                 /* User requests automatic tx power control, however there are
1872                  * many auto tx settings.  For now use firmware defaults until
1873                  * we come up with a good way to expose these to the user. */
1874                 if (priv->fwrelease < 0x09000000) {
1875                         ret = lbs_set_power_adapt_cfg(priv, 1,
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                 dbm = priv->txpower_max;
1887         } else {
1888                 /* Userspace check in iwrange if it should use dBm or mW,
1889                  * therefore this should never happen... Jean II */
1890                 if ((vwrq->flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) {
1891                         ret = -EOPNOTSUPP;
1892                         goto out;
1893                 }
1894
1895                 /* Validate requested power level against firmware allowed
1896                  * levels */
1897                 if (priv->txpower_min && (dbm < priv->txpower_min)) {
1898                         ret = -EINVAL;
1899                         goto out;
1900                 }
1901
1902                 if (priv->txpower_max && (dbm > priv->txpower_max)) {
1903                         ret = -EINVAL;
1904                         goto out;
1905                 }
1906                 if (priv->fwrelease < 0x09000000) {
1907                         ret = lbs_set_power_adapt_cfg(priv, 0,
1908                                         POW_ADAPT_DEFAULT_P0,
1909                                         POW_ADAPT_DEFAULT_P1,
1910                                         POW_ADAPT_DEFAULT_P2);
1911                         if (ret)
1912                                 goto out;
1913                 }
1914                 ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1,
1915                                 TPC_DEFAULT_P2, 1);
1916                 if (ret)
1917                         goto out;
1918         }
1919
1920         /* If the radio was off, turn it on */
1921         if (!priv->radio_on) {
1922                 ret = lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 1);
1923                 if (ret)
1924                         goto out;
1925         }
1926
1927         lbs_deb_wext("txpower set %d dBm\n", dbm);
1928
1929         ret = lbs_set_tx_power(priv, dbm);
1930
1931 out:
1932         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1933         return ret;
1934 }
1935
1936 static int lbs_get_essid(struct net_device *dev, struct iw_request_info *info,
1937                    struct iw_point *dwrq, char *extra)
1938 {
1939         struct lbs_private *priv = netdev_priv(dev);
1940
1941         lbs_deb_enter(LBS_DEB_WEXT);
1942
1943         /*
1944          * Note : if dwrq->flags != 0, we should get the relevant SSID from
1945          * the SSID list...
1946          */
1947
1948         /*
1949          * Get the current SSID
1950          */
1951         if (priv->connect_status == LBS_CONNECTED) {
1952                 memcpy(extra, priv->curbssparams.ssid,
1953                        priv->curbssparams.ssid_len);
1954                 extra[priv->curbssparams.ssid_len] = '\0';
1955         } else {
1956                 memset(extra, 0, 32);
1957                 extra[priv->curbssparams.ssid_len] = '\0';
1958         }
1959         /*
1960          * If none, we may want to get the one that was set
1961          */
1962
1963         dwrq->length = priv->curbssparams.ssid_len;
1964
1965         dwrq->flags = 1;        /* active */
1966
1967         lbs_deb_leave(LBS_DEB_WEXT);
1968         return 0;
1969 }
1970
1971 static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info,
1972                    struct iw_point *dwrq, char *extra)
1973 {
1974         struct lbs_private *priv = netdev_priv(dev);
1975         int ret = 0;
1976         u8 ssid[IW_ESSID_MAX_SIZE];
1977         u8 ssid_len = 0;
1978         struct assoc_request * assoc_req;
1979         int in_ssid_len = dwrq->length;
1980         DECLARE_SSID_BUF(ssid_buf);
1981
1982         lbs_deb_enter(LBS_DEB_WEXT);
1983
1984         if (!priv->radio_on) {
1985                 ret = -EINVAL;
1986                 goto out;
1987         }
1988
1989         /* Check the size of the string */
1990         if (in_ssid_len > IW_ESSID_MAX_SIZE) {
1991                 ret = -E2BIG;
1992                 goto out;
1993         }
1994
1995         memset(&ssid, 0, sizeof(ssid));
1996
1997         if (!dwrq->flags || !in_ssid_len) {
1998                 /* "any" SSID requested; leave SSID blank */
1999         } else {
2000                 /* Specific SSID requested */
2001                 memcpy(&ssid, extra, in_ssid_len);
2002                 ssid_len = in_ssid_len;
2003         }
2004
2005         if (!ssid_len) {
2006                 lbs_deb_wext("requested any SSID\n");
2007         } else {
2008                 lbs_deb_wext("requested SSID '%s'\n",
2009                              print_ssid(ssid_buf, ssid, ssid_len));
2010         }
2011
2012 out:
2013         mutex_lock(&priv->lock);
2014         if (ret == 0) {
2015                 /* Get or create the current association request */
2016                 assoc_req = lbs_get_association_request(priv);
2017                 if (!assoc_req) {
2018                         ret = -ENOMEM;
2019                 } else {
2020                         /* Copy the SSID to the association request */
2021                         memcpy(&assoc_req->ssid, &ssid, IW_ESSID_MAX_SIZE);
2022                         assoc_req->ssid_len = ssid_len;
2023                         set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
2024                         lbs_postpone_association_work(priv);
2025                 }
2026         }
2027
2028         /* Cancel the association request if there was an error */
2029         if (ret != 0) {
2030                 lbs_cancel_association_work(priv);
2031         }
2032
2033         mutex_unlock(&priv->lock);
2034
2035         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
2036         return ret;
2037 }
2038
2039 static int lbs_mesh_get_essid(struct net_device *dev,
2040                               struct iw_request_info *info,
2041                               struct iw_point *dwrq, char *extra)
2042 {
2043         struct lbs_private *priv = netdev_priv(dev);
2044
2045         lbs_deb_enter(LBS_DEB_WEXT);
2046
2047         memcpy(extra, priv->mesh_ssid, priv->mesh_ssid_len);
2048
2049         dwrq->length = priv->mesh_ssid_len;
2050
2051         dwrq->flags = 1;        /* active */
2052
2053         lbs_deb_leave(LBS_DEB_WEXT);
2054         return 0;
2055 }
2056
2057 static int lbs_mesh_set_essid(struct net_device *dev,
2058                               struct iw_request_info *info,
2059                               struct iw_point *dwrq, char *extra)
2060 {
2061         struct lbs_private *priv = netdev_priv(dev);
2062         int ret = 0;
2063
2064         lbs_deb_enter(LBS_DEB_WEXT);
2065
2066         if (!priv->radio_on) {
2067                 ret = -EINVAL;
2068                 goto out;
2069         }
2070
2071         /* Check the size of the string */
2072         if (dwrq->length > IW_ESSID_MAX_SIZE) {
2073                 ret = -E2BIG;
2074                 goto out;
2075         }
2076
2077         if (!dwrq->flags || !dwrq->length) {
2078                 ret = -EINVAL;
2079                 goto out;
2080         } else {
2081                 /* Specific SSID requested */
2082                 memcpy(priv->mesh_ssid, extra, dwrq->length);
2083                 priv->mesh_ssid_len = dwrq->length;
2084         }
2085
2086         lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
2087                         priv->curbssparams.channel);
2088  out:
2089         lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
2090         return ret;
2091 }
2092
2093 /**
2094  *  @brief Connect to the AP or Ad-hoc Network with specific bssid
2095  *
2096  *  @param dev          A pointer to net_device structure
2097  *  @param info         A pointer to iw_request_info structure
2098  *  @param awrq         A pointer to iw_param structure
2099  *  @param extra        A pointer to extra data buf
2100  *  @return             0 --success, otherwise fail
2101  */
2102 static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info,
2103                  struct sockaddr *awrq, char *extra)
2104 {
2105         struct lbs_private *priv = netdev_priv(dev);
2106         struct assoc_request * assoc_req;
2107         int ret = 0;
2108
2109         lbs_deb_enter(LBS_DEB_WEXT);
2110
2111         if (!priv->radio_on)
2112                 return -EINVAL;
2113
2114         if (awrq->sa_family != ARPHRD_ETHER)
2115                 return -EINVAL;
2116
2117         lbs_deb_wext("ASSOC: WAP: sa_data %pM\n", awrq->sa_data);
2118
2119         mutex_lock(&priv->lock);
2120
2121         /* Get or create the current association request */
2122         assoc_req = lbs_get_association_request(priv);
2123         if (!assoc_req) {
2124                 lbs_cancel_association_work(priv);
2125                 ret = -ENOMEM;
2126         } else {
2127                 /* Copy the BSSID to the association request */
2128                 memcpy(&assoc_req->bssid, awrq->sa_data, ETH_ALEN);
2129                 set_bit(ASSOC_FLAG_BSSID, &assoc_req->flags);
2130                 lbs_postpone_association_work(priv);
2131         }
2132
2133         mutex_unlock(&priv->lock);
2134
2135         return ret;
2136 }
2137
2138 /*
2139  * iwconfig settable callbacks
2140  */
2141 static const iw_handler lbs_handler[] = {
2142         (iw_handler) NULL,      /* SIOCSIWCOMMIT */
2143         (iw_handler) lbs_get_name,      /* SIOCGIWNAME */
2144         (iw_handler) NULL,      /* SIOCSIWNWID */
2145         (iw_handler) NULL,      /* SIOCGIWNWID */
2146         (iw_handler) lbs_set_freq,      /* SIOCSIWFREQ */
2147         (iw_handler) lbs_get_freq,      /* SIOCGIWFREQ */
2148         (iw_handler) lbs_set_mode,      /* SIOCSIWMODE */
2149         (iw_handler) lbs_get_mode,      /* SIOCGIWMODE */
2150         (iw_handler) NULL,      /* SIOCSIWSENS */
2151         (iw_handler) NULL,      /* SIOCGIWSENS */
2152         (iw_handler) NULL,      /* SIOCSIWRANGE */
2153         (iw_handler) lbs_get_range,     /* SIOCGIWRANGE */
2154         (iw_handler) NULL,      /* SIOCSIWPRIV */
2155         (iw_handler) NULL,      /* SIOCGIWPRIV */
2156         (iw_handler) NULL,      /* SIOCSIWSTATS */
2157         (iw_handler) NULL,      /* SIOCGIWSTATS */
2158         iw_handler_set_spy,     /* SIOCSIWSPY */
2159         iw_handler_get_spy,     /* SIOCGIWSPY */
2160         iw_handler_set_thrspy,  /* SIOCSIWTHRSPY */
2161         iw_handler_get_thrspy,  /* SIOCGIWTHRSPY */
2162         (iw_handler) lbs_set_wap,       /* SIOCSIWAP */
2163         (iw_handler) lbs_get_wap,       /* SIOCGIWAP */
2164         (iw_handler) NULL,      /* SIOCSIWMLME */
2165         (iw_handler) NULL,      /* SIOCGIWAPLIST - deprecated */
2166         (iw_handler) lbs_set_scan,      /* SIOCSIWSCAN */
2167         (iw_handler) lbs_get_scan,      /* SIOCGIWSCAN */
2168         (iw_handler) lbs_set_essid,     /* SIOCSIWESSID */
2169         (iw_handler) lbs_get_essid,     /* SIOCGIWESSID */
2170         (iw_handler) lbs_set_nick,      /* SIOCSIWNICKN */
2171         (iw_handler) lbs_get_nick,      /* SIOCGIWNICKN */
2172         (iw_handler) NULL,      /* -- hole -- */
2173         (iw_handler) NULL,      /* -- hole -- */
2174         (iw_handler) lbs_set_rate,      /* SIOCSIWRATE */
2175         (iw_handler) lbs_get_rate,      /* SIOCGIWRATE */
2176         (iw_handler) lbs_set_rts,       /* SIOCSIWRTS */
2177         (iw_handler) lbs_get_rts,       /* SIOCGIWRTS */
2178         (iw_handler) lbs_set_frag,      /* SIOCSIWFRAG */
2179         (iw_handler) lbs_get_frag,      /* SIOCGIWFRAG */
2180         (iw_handler) lbs_set_txpow,     /* SIOCSIWTXPOW */
2181         (iw_handler) lbs_get_txpow,     /* SIOCGIWTXPOW */
2182         (iw_handler) lbs_set_retry,     /* SIOCSIWRETRY */
2183         (iw_handler) lbs_get_retry,     /* SIOCGIWRETRY */
2184         (iw_handler) lbs_set_encode,    /* SIOCSIWENCODE */
2185         (iw_handler) lbs_get_encode,    /* SIOCGIWENCODE */
2186         (iw_handler) lbs_set_power,     /* SIOCSIWPOWER */
2187         (iw_handler) lbs_get_power,     /* SIOCGIWPOWER */
2188         (iw_handler) NULL,      /* -- hole -- */
2189         (iw_handler) NULL,      /* -- hole -- */
2190         (iw_handler) lbs_set_genie,     /* SIOCSIWGENIE */
2191         (iw_handler) lbs_get_genie,     /* SIOCGIWGENIE */
2192         (iw_handler) lbs_set_auth,      /* SIOCSIWAUTH */
2193         (iw_handler) lbs_get_auth,      /* SIOCGIWAUTH */
2194         (iw_handler) lbs_set_encodeext,/* SIOCSIWENCODEEXT */
2195         (iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */
2196         (iw_handler) NULL,              /* SIOCSIWPMKSA */
2197 };
2198
2199 static const iw_handler mesh_wlan_handler[] = {
2200         (iw_handler) NULL,      /* SIOCSIWCOMMIT */
2201         (iw_handler) lbs_get_name,      /* SIOCGIWNAME */
2202         (iw_handler) NULL,      /* SIOCSIWNWID */
2203         (iw_handler) NULL,      /* SIOCGIWNWID */
2204         (iw_handler) lbs_mesh_set_freq, /* SIOCSIWFREQ */
2205         (iw_handler) lbs_get_freq,      /* SIOCGIWFREQ */
2206         (iw_handler) NULL,              /* SIOCSIWMODE */
2207         (iw_handler) mesh_wlan_get_mode,        /* SIOCGIWMODE */
2208         (iw_handler) NULL,      /* SIOCSIWSENS */
2209         (iw_handler) NULL,      /* SIOCGIWSENS */
2210         (iw_handler) NULL,      /* SIOCSIWRANGE */
2211         (iw_handler) lbs_get_range,     /* SIOCGIWRANGE */
2212         (iw_handler) NULL,      /* SIOCSIWPRIV */
2213         (iw_handler) NULL,      /* SIOCGIWPRIV */
2214         (iw_handler) NULL,      /* SIOCSIWSTATS */
2215         (iw_handler) NULL,      /* SIOCGIWSTATS */
2216         iw_handler_set_spy,     /* SIOCSIWSPY */
2217         iw_handler_get_spy,     /* SIOCGIWSPY */
2218         iw_handler_set_thrspy,  /* SIOCSIWTHRSPY */
2219         iw_handler_get_thrspy,  /* SIOCGIWTHRSPY */
2220         (iw_handler) NULL,      /* SIOCSIWAP */
2221         (iw_handler) NULL,      /* SIOCGIWAP */
2222         (iw_handler) NULL,      /* SIOCSIWMLME */
2223         (iw_handler) NULL,      /* SIOCGIWAPLIST - deprecated */
2224         (iw_handler) lbs_set_scan,      /* SIOCSIWSCAN */
2225         (iw_handler) lbs_get_scan,      /* SIOCGIWSCAN */
2226         (iw_handler) lbs_mesh_set_essid,/* SIOCSIWESSID */
2227         (iw_handler) lbs_mesh_get_essid,/* SIOCGIWESSID */
2228         (iw_handler) NULL,              /* SIOCSIWNICKN */
2229         (iw_handler) mesh_get_nick,     /* SIOCGIWNICKN */
2230         (iw_handler) NULL,      /* -- hole -- */
2231         (iw_handler) NULL,      /* -- hole -- */
2232         (iw_handler) lbs_set_rate,      /* SIOCSIWRATE */
2233         (iw_handler) lbs_get_rate,      /* SIOCGIWRATE */
2234         (iw_handler) lbs_set_rts,       /* SIOCSIWRTS */
2235         (iw_handler) lbs_get_rts,       /* SIOCGIWRTS */
2236         (iw_handler) lbs_set_frag,      /* SIOCSIWFRAG */
2237         (iw_handler) lbs_get_frag,      /* SIOCGIWFRAG */
2238         (iw_handler) lbs_set_txpow,     /* SIOCSIWTXPOW */
2239         (iw_handler) lbs_get_txpow,     /* SIOCGIWTXPOW */
2240         (iw_handler) lbs_set_retry,     /* SIOCSIWRETRY */
2241         (iw_handler) lbs_get_retry,     /* SIOCGIWRETRY */
2242         (iw_handler) lbs_set_encode,    /* SIOCSIWENCODE */
2243         (iw_handler) lbs_get_encode,    /* SIOCGIWENCODE */
2244         (iw_handler) lbs_set_power,     /* SIOCSIWPOWER */
2245         (iw_handler) lbs_get_power,     /* SIOCGIWPOWER */
2246         (iw_handler) NULL,      /* -- hole -- */
2247         (iw_handler) NULL,      /* -- hole -- */
2248         (iw_handler) lbs_set_genie,     /* SIOCSIWGENIE */
2249         (iw_handler) lbs_get_genie,     /* SIOCGIWGENIE */
2250         (iw_handler) lbs_set_auth,      /* SIOCSIWAUTH */
2251         (iw_handler) lbs_get_auth,      /* SIOCGIWAUTH */
2252         (iw_handler) lbs_set_encodeext,/* SIOCSIWENCODEEXT */
2253         (iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */
2254         (iw_handler) NULL,              /* SIOCSIWPMKSA */
2255 };
2256 struct iw_handler_def lbs_handler_def = {
2257         .num_standard   = ARRAY_SIZE(lbs_handler),
2258         .standard       = (iw_handler *) lbs_handler,
2259         .get_wireless_stats = lbs_get_wireless_stats,
2260 };
2261
2262 struct iw_handler_def mesh_handler_def = {
2263         .num_standard   = ARRAY_SIZE(mesh_wlan_handler),
2264         .standard       = (iw_handler *) mesh_wlan_handler,
2265         .get_wireless_stats = lbs_get_wireless_stats,
2266 };