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