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