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