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