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