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