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