blob: 408bc0aa9567425a2e293c8eaa8603b72c7bf310 [file] [log] [blame]
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001/**
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"
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020020#include "wext.h"
21#include "assoc.h"
22
23
24/**
Holger Schurigbf68dac2007-05-25 00:14:38 -040025 * the rates supported by the card
26 */
27static u8 libertas_wlan_data_rates[WLAN_SUPPORTED_RATES] =
28 { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12,
29 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00
30};
31
32/**
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020033 * @brief Convert mw value to dbm value
34 *
35 * @param mw the value of mw
36 * @return the value of dbm
37 */
38static int mw_to_dbm(int mw)
39{
40 if (mw < 2)
41 return 0;
42 else if (mw < 3)
43 return 3;
44 else if (mw < 4)
45 return 5;
46 else if (mw < 6)
47 return 7;
48 else if (mw < 7)
49 return 8;
50 else if (mw < 8)
51 return 9;
52 else if (mw < 10)
53 return 10;
54 else if (mw < 13)
55 return 11;
56 else if (mw < 16)
57 return 12;
58 else if (mw < 20)
59 return 13;
60 else if (mw < 25)
61 return 14;
62 else if (mw < 32)
63 return 15;
64 else if (mw < 40)
65 return 16;
66 else if (mw < 50)
67 return 17;
68 else if (mw < 63)
69 return 18;
70 else if (mw < 79)
71 return 19;
72 else if (mw < 100)
73 return 20;
74 else
75 return 21;
76}
77
78/**
79 * @brief Find the channel frequency power info with specific channel
80 *
81 * @param adapter A pointer to wlan_adapter structure
82 * @param band it can be BAND_A, BAND_G or BAND_B
83 * @param channel the channel for looking
84 * @return A pointer to struct chan_freq_power structure or NULL if not find.
85 */
86struct chan_freq_power *libertas_find_cfp_by_band_and_channel(wlan_adapter * adapter,
87 u8 band, u16 channel)
88{
89 struct chan_freq_power *cfp = NULL;
90 struct region_channel *rc;
91 int count = sizeof(adapter->region_channel) /
92 sizeof(adapter->region_channel[0]);
93 int i, j;
94
95 for (j = 0; !cfp && (j < count); j++) {
96 rc = &adapter->region_channel[j];
97
98 if (adapter->enable11d)
99 rc = &adapter->universal_channel[j];
100 if (!rc->valid || !rc->CFP)
101 continue;
102 if (rc->band != band)
103 continue;
104 for (i = 0; i < rc->nrcfp; i++) {
105 if (rc->CFP[i].channel == channel) {
106 cfp = &rc->CFP[i];
107 break;
108 }
109 }
110 }
111
112 if (!cfp && channel)
113 lbs_pr_debug(1, "libertas_find_cfp_by_band_and_channel(): cannot find "
114 "cfp by band %d & channel %d\n", band, channel);
115
116 return cfp;
117}
118
119/**
120 * @brief Find the channel frequency power info with specific frequency
121 *
122 * @param adapter A pointer to wlan_adapter structure
123 * @param band it can be BAND_A, BAND_G or BAND_B
124 * @param freq the frequency for looking
125 * @return A pointer to struct chan_freq_power structure or NULL if not find.
126 */
127static struct chan_freq_power *find_cfp_by_band_and_freq(wlan_adapter * adapter,
128 u8 band, u32 freq)
129{
130 struct chan_freq_power *cfp = NULL;
131 struct region_channel *rc;
132 int count = sizeof(adapter->region_channel) /
133 sizeof(adapter->region_channel[0]);
134 int i, j;
135
136 for (j = 0; !cfp && (j < count); j++) {
137 rc = &adapter->region_channel[j];
138
139 if (adapter->enable11d)
140 rc = &adapter->universal_channel[j];
141 if (!rc->valid || !rc->CFP)
142 continue;
143 if (rc->band != band)
144 continue;
145 for (i = 0; i < rc->nrcfp; i++) {
146 if (rc->CFP[i].freq == freq) {
147 cfp = &rc->CFP[i];
148 break;
149 }
150 }
151 }
152
153 if (!cfp && freq)
154 lbs_pr_debug(1, "find_cfp_by_band_and_freql(): cannot find cfp by "
155 "band %d & freq %d\n", band, freq);
156
157 return cfp;
158}
159
160static int updatecurrentchannel(wlan_private * priv)
161{
162 int ret;
163
164 /*
165 ** the channel in f/w could be out of sync, get the current channel
166 */
167 ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
168 cmd_opt_802_11_rf_channel_get,
169 cmd_option_waitforrsp, 0, NULL);
170
171 lbs_pr_debug(1, "Current channel = %d\n",
172 priv->adapter->curbssparams.channel);
173
174 return ret;
175}
176
177static int setcurrentchannel(wlan_private * priv, int channel)
178{
179 lbs_pr_debug(1, "Set channel = %d\n", channel);
180
181 /*
182 ** Current channel is not set to adhocchannel requested, set channel
183 */
184 return (libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
185 cmd_opt_802_11_rf_channel_set,
186 cmd_option_waitforrsp, 0, &channel));
187}
188
189static int changeadhocchannel(wlan_private * priv, int channel)
190{
191 int ret = 0;
192 wlan_adapter *adapter = priv->adapter;
193
194 adapter->adhocchannel = channel;
195
196 updatecurrentchannel(priv);
197
198 if (adapter->curbssparams.channel == adapter->adhocchannel) {
199 /* adhocchannel is set to the current channel already */
200 LEAVE();
201 return 0;
202 }
203
204 lbs_pr_debug(1, "Updating channel from %d to %d\n",
205 adapter->curbssparams.channel, adapter->adhocchannel);
206
207 setcurrentchannel(priv, adapter->adhocchannel);
208
209 updatecurrentchannel(priv);
210
211 if (adapter->curbssparams.channel != adapter->adhocchannel) {
212 lbs_pr_debug(1, "failed to updated channel to %d, channel = %d\n",
213 adapter->adhocchannel, adapter->curbssparams.channel);
214 LEAVE();
215 return -1;
216 }
217
218 if (adapter->connect_status == libertas_connected) {
219 int i;
220 struct WLAN_802_11_SSID curadhocssid;
221
222 lbs_pr_debug(1, "channel Changed while in an IBSS\n");
223
224 /* Copy the current ssid */
225 memcpy(&curadhocssid, &adapter->curbssparams.ssid,
226 sizeof(struct WLAN_802_11_SSID));
227
228 /* Exit Adhoc mode */
229 lbs_pr_debug(1, "In changeadhocchannel(): Sending Adhoc Stop\n");
230 ret = libertas_stop_adhoc_network(priv);
231
232 if (ret) {
233 LEAVE();
234 return ret;
235 }
236 /* Scan for the network, do not save previous results. Stale
237 * scan data will cause us to join a non-existant adhoc network
238 */
239 libertas_send_specific_SSID_scan(priv, &curadhocssid, 0);
240
241 // find out the BSSID that matches the current SSID
242 i = libertas_find_SSID_in_list(adapter, &curadhocssid, NULL,
Dan Williams0dc5a292007-05-10 22:58:02 -0400243 IW_MODE_ADHOC);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200244
245 if (i >= 0) {
246 lbs_pr_debug(1, "SSID found at %d in List,"
247 "so join\n", i);
248 libertas_join_adhoc_network(priv, &adapter->scantable[i]);
249 } else {
250 // else send START command
251 lbs_pr_debug(1, "SSID not found in list, "
252 "so creating adhoc with ssid = %s\n",
253 curadhocssid.ssid);
254 libertas_start_adhoc_network(priv, &curadhocssid);
255 } // end of else (START command)
256 }
257
258 LEAVE();
259 return 0;
260}
261
262/**
263 * @brief Set Radio On/OFF
264 *
265 * @param priv A pointer to wlan_private structure
266 * @option Radio Option
267 * @return 0 --success, otherwise fail
268 */
269int wlan_radio_ioctl(wlan_private * priv, u8 option)
270{
271 int ret = 0;
272 wlan_adapter *adapter = priv->adapter;
273
274 ENTER();
275
276 if (adapter->radioon != option) {
277 lbs_pr_debug(1, "Switching %s the Radio\n", option ? "On" : "Off");
278 adapter->radioon = option;
279
280 ret = libertas_prepare_and_send_command(priv,
281 cmd_802_11_radio_control,
282 cmd_act_set,
283 cmd_option_waitforrsp, 0, NULL);
284 }
285
286 LEAVE();
287 return ret;
288}
289
290/**
291 * @brief Copy rates
292 *
293 * @param dest A pointer to Dest Buf
294 * @param src A pointer to Src Buf
295 * @param len The len of Src Buf
296 * @return Number of rates copyed
297 */
298static inline int copyrates(u8 * dest, int pos, u8 * src, int len)
299{
300 int i;
301
302 for (i = 0; i < len && src[i]; i++, pos++) {
303 if (pos >= sizeof(u8) * WLAN_SUPPORTED_RATES)
304 break;
305 dest[pos] = src[i];
306 }
307
308 return pos;
309}
310
311/**
312 * @brief Get active data rates
313 *
314 * @param adapter A pointer to wlan_adapter structure
315 * @param rate The buf to return the active rates
316 * @return The number of rates
317 */
318static int get_active_data_rates(wlan_adapter * adapter,
319 u8* rates)
320{
321 int k = 0;
322
323 ENTER();
324
325 if (adapter->connect_status != libertas_connected) {
Dan Williams0dc5a292007-05-10 22:58:02 -0400326 if (adapter->mode == IW_MODE_INFRA) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200327 lbs_pr_debug(1, "Infra\n");
328 k = copyrates(rates, k, libertas_supported_rates,
329 sizeof(libertas_supported_rates));
330 } else {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200331 lbs_pr_debug(1, "Adhoc G\n");
332 k = copyrates(rates, k, libertas_adhoc_rates_g,
333 sizeof(libertas_adhoc_rates_g));
334 }
335 } else {
336 k = copyrates(rates, 0, adapter->curbssparams.datarates,
337 adapter->curbssparams.numofrates);
338 }
339
340 LEAVE();
341
342 return k;
343}
344
345static int wlan_get_name(struct net_device *dev, struct iw_request_info *info,
346 char *cwrq, char *extra)
347{
348 const char *cp;
349 char comm[6] = { "COMM-" };
350 char mrvl[6] = { "MRVL-" };
351 int cnt;
352
353 ENTER();
354
355 strcpy(cwrq, mrvl);
356
357 cp = strstr(libertas_driver_version, comm);
358 if (cp == libertas_driver_version) //skip leading "COMM-"
359 cp = libertas_driver_version + strlen(comm);
360 else
361 cp = libertas_driver_version;
362
363 cnt = strlen(mrvl);
364 cwrq += cnt;
365 while (cnt < 16 && (*cp != '-')) {
366 *cwrq++ = toupper(*cp++);
367 cnt++;
368 }
369 *cwrq = '\0';
370
371 LEAVE();
372
373 return 0;
374}
375
376static int wlan_get_freq(struct net_device *dev, struct iw_request_info *info,
377 struct iw_freq *fwrq, char *extra)
378{
379 wlan_private *priv = dev->priv;
380 wlan_adapter *adapter = priv->adapter;
381 struct chan_freq_power *cfp;
382
383 ENTER();
384
385 cfp = libertas_find_cfp_by_band_and_channel(adapter, 0,
386 adapter->curbssparams.channel);
387
388 if (!cfp) {
389 if (adapter->curbssparams.channel)
390 lbs_pr_debug(1, "Invalid channel=%d\n",
391 adapter->curbssparams.channel);
392 return -EINVAL;
393 }
394
395 fwrq->m = (long)cfp->freq * 100000;
396 fwrq->e = 1;
397
398 lbs_pr_debug(1, "freq=%u\n", fwrq->m);
399
400 LEAVE();
401 return 0;
402}
403
404static int wlan_get_wap(struct net_device *dev, struct iw_request_info *info,
405 struct sockaddr *awrq, char *extra)
406{
407 wlan_private *priv = dev->priv;
408 wlan_adapter *adapter = priv->adapter;
409
410 ENTER();
411
412 if (adapter->connect_status == libertas_connected) {
413 memcpy(awrq->sa_data, adapter->curbssparams.bssid, ETH_ALEN);
414 } else {
415 memset(awrq->sa_data, 0, ETH_ALEN);
416 }
417 awrq->sa_family = ARPHRD_ETHER;
418
419 LEAVE();
420 return 0;
421}
422
423static int wlan_set_nick(struct net_device *dev, struct iw_request_info *info,
424 struct iw_point *dwrq, char *extra)
425{
426 wlan_private *priv = dev->priv;
427 wlan_adapter *adapter = priv->adapter;
428
429 ENTER();
430
431 /*
432 * Check the size of the string
433 */
434
435 if (dwrq->length > 16) {
436 return -E2BIG;
437 }
438
439 mutex_lock(&adapter->lock);
440 memset(adapter->nodename, 0, sizeof(adapter->nodename));
441 memcpy(adapter->nodename, extra, dwrq->length);
442 mutex_unlock(&adapter->lock);
443
444 LEAVE();
445 return 0;
446}
447
448static int wlan_get_nick(struct net_device *dev, struct iw_request_info *info,
449 struct iw_point *dwrq, char *extra)
450{
451 wlan_private *priv = dev->priv;
452 wlan_adapter *adapter = priv->adapter;
453
454 ENTER();
455
456 /*
457 * Get the Nick Name saved
458 */
459
460 mutex_lock(&adapter->lock);
461 strncpy(extra, adapter->nodename, 16);
462 mutex_unlock(&adapter->lock);
463
464 extra[16] = '\0';
465
466 /*
467 * If none, we may want to get the one that was set
468 */
469
470 /*
471 * Push it out !
472 */
473 dwrq->length = strlen(extra) + 1;
474
475 LEAVE();
476 return 0;
477}
478
479static int wlan_set_rts(struct net_device *dev, struct iw_request_info *info,
480 struct iw_param *vwrq, char *extra)
481{
482 int ret = 0;
483 wlan_private *priv = dev->priv;
484 wlan_adapter *adapter = priv->adapter;
485 int rthr = vwrq->value;
486
487 ENTER();
488
489 if (vwrq->disabled) {
490 adapter->rtsthsd = rthr = MRVDRV_RTS_MAX_VALUE;
491 } else {
492 if (rthr < MRVDRV_RTS_MIN_VALUE || rthr > MRVDRV_RTS_MAX_VALUE)
493 return -EINVAL;
494 adapter->rtsthsd = rthr;
495 }
496
497 ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
498 cmd_act_set, cmd_option_waitforrsp,
499 OID_802_11_RTS_THRESHOLD, &rthr);
500
501 LEAVE();
502 return ret;
503}
504
505static int wlan_get_rts(struct net_device *dev, struct iw_request_info *info,
506 struct iw_param *vwrq, char *extra)
507{
508 int ret = 0;
509 wlan_private *priv = dev->priv;
510 wlan_adapter *adapter = priv->adapter;
511
512 ENTER();
513
514 adapter->rtsthsd = 0;
515 ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
516 cmd_act_get, cmd_option_waitforrsp,
517 OID_802_11_RTS_THRESHOLD, NULL);
518 if (ret) {
519 LEAVE();
520 return ret;
521 }
522
523 vwrq->value = adapter->rtsthsd;
524 vwrq->disabled = ((vwrq->value < MRVDRV_RTS_MIN_VALUE)
525 || (vwrq->value > MRVDRV_RTS_MAX_VALUE));
526 vwrq->fixed = 1;
527
528 LEAVE();
529 return 0;
530}
531
532static int wlan_set_frag(struct net_device *dev, struct iw_request_info *info,
533 struct iw_param *vwrq, char *extra)
534{
535 int ret = 0;
536 int fthr = vwrq->value;
537 wlan_private *priv = dev->priv;
538 wlan_adapter *adapter = priv->adapter;
539
540 ENTER();
541
542 if (vwrq->disabled) {
543 adapter->fragthsd = fthr = MRVDRV_FRAG_MAX_VALUE;
544 } else {
545 if (fthr < MRVDRV_FRAG_MIN_VALUE
546 || fthr > MRVDRV_FRAG_MAX_VALUE)
547 return -EINVAL;
548 adapter->fragthsd = fthr;
549 }
550
551 ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
552 cmd_act_set, cmd_option_waitforrsp,
553 OID_802_11_FRAGMENTATION_THRESHOLD, &fthr);
554 LEAVE();
555 return ret;
556}
557
558static int wlan_get_frag(struct net_device *dev, struct iw_request_info *info,
559 struct iw_param *vwrq, char *extra)
560{
561 int ret = 0;
562 wlan_private *priv = dev->priv;
563 wlan_adapter *adapter = priv->adapter;
564
565 ENTER();
566
567 adapter->fragthsd = 0;
568 ret = libertas_prepare_and_send_command(priv,
569 cmd_802_11_snmp_mib,
570 cmd_act_get, cmd_option_waitforrsp,
571 OID_802_11_FRAGMENTATION_THRESHOLD, NULL);
572 if (ret) {
573 LEAVE();
574 return ret;
575 }
576
577 vwrq->value = adapter->fragthsd;
578 vwrq->disabled = ((vwrq->value < MRVDRV_FRAG_MIN_VALUE)
579 || (vwrq->value > MRVDRV_FRAG_MAX_VALUE));
580 vwrq->fixed = 1;
581
582 LEAVE();
583 return ret;
584}
585
586static int wlan_get_mode(struct net_device *dev,
587 struct iw_request_info *info, u32 * uwrq, char *extra)
588{
589 wlan_private *priv = dev->priv;
590 wlan_adapter *adapter = priv->adapter;
591
592 ENTER();
593
Dan Williams0dc5a292007-05-10 22:58:02 -0400594 *uwrq = adapter->mode;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200595
596 LEAVE();
597 return 0;
598}
599
600static int wlan_get_txpow(struct net_device *dev,
601 struct iw_request_info *info,
602 struct iw_param *vwrq, char *extra)
603{
604 int ret = 0;
605 wlan_private *priv = dev->priv;
606 wlan_adapter *adapter = priv->adapter;
607
608 ENTER();
609
610 ret = libertas_prepare_and_send_command(priv,
611 cmd_802_11_rf_tx_power,
612 cmd_act_tx_power_opt_get,
613 cmd_option_waitforrsp, 0, NULL);
614
615 if (ret) {
616 LEAVE();
617 return ret;
618 }
619
620 lbs_pr_debug(1, "TXPOWER GET %d dbm.\n", adapter->txpowerlevel);
621 vwrq->value = adapter->txpowerlevel;
622 vwrq->fixed = 1;
623 if (adapter->radioon) {
624 vwrq->disabled = 0;
625 vwrq->flags = IW_TXPOW_DBM;
626 } else {
627 vwrq->disabled = 1;
628 }
629
630 LEAVE();
631 return 0;
632}
633
634static int wlan_set_retry(struct net_device *dev, struct iw_request_info *info,
635 struct iw_param *vwrq, char *extra)
636{
637 int ret = 0;
638 wlan_private *priv = dev->priv;
639 wlan_adapter *adapter = priv->adapter;
640
641 ENTER();
642
643 if (vwrq->flags == IW_RETRY_LIMIT) {
644 /* The MAC has a 4-bit Total_Tx_Count register
645 Total_Tx_Count = 1 + Tx_Retry_Count */
646#define TX_RETRY_MIN 0
647#define TX_RETRY_MAX 14
648 if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX)
649 return -EINVAL;
650
651 /* Adding 1 to convert retry count to try count */
652 adapter->txretrycount = vwrq->value + 1;
653
654 ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
655 cmd_act_set,
656 cmd_option_waitforrsp,
657 OID_802_11_TX_RETRYCOUNT, NULL);
658
659 if (ret) {
660 LEAVE();
661 return ret;
662 }
663 } else {
664 return -EOPNOTSUPP;
665 }
666
667 LEAVE();
668 return 0;
669}
670
671static int wlan_get_retry(struct net_device *dev, struct iw_request_info *info,
672 struct iw_param *vwrq, char *extra)
673{
674 wlan_private *priv = dev->priv;
675 wlan_adapter *adapter = priv->adapter;
676 int ret = 0;
677
678 ENTER();
679 adapter->txretrycount = 0;
680 ret = libertas_prepare_and_send_command(priv,
681 cmd_802_11_snmp_mib,
682 cmd_act_get, cmd_option_waitforrsp,
683 OID_802_11_TX_RETRYCOUNT, NULL);
684 if (ret) {
685 LEAVE();
686 return ret;
687 }
688 vwrq->disabled = 0;
689 if (!vwrq->flags) {
690 vwrq->flags = IW_RETRY_LIMIT;
691 /* Subtract 1 to convert try count to retry count */
692 vwrq->value = adapter->txretrycount - 1;
693 }
694
695 LEAVE();
696 return 0;
697}
698
699static inline void sort_channels(struct iw_freq *freq, int num)
700{
701 int i, j;
702 struct iw_freq temp;
703
704 for (i = 0; i < num; i++)
705 for (j = i + 1; j < num; j++)
706 if (freq[i].i > freq[j].i) {
707 temp.i = freq[i].i;
708 temp.m = freq[i].m;
709
710 freq[i].i = freq[j].i;
711 freq[i].m = freq[j].m;
712
713 freq[j].i = temp.i;
714 freq[j].m = temp.m;
715 }
716}
717
718/* data rate listing
719 MULTI_BANDS:
720 abg a b b/g
721 Infra G(12) A(8) B(4) G(12)
722 Adhoc A+B(12) A(8) B(4) B(4)
723
724 non-MULTI_BANDS:
725 b b/g
726 Infra B(4) G(12)
727 Adhoc B(4) B(4)
728 */
729/**
730 * @brief Get Range Info
731 *
732 * @param dev A pointer to net_device structure
733 * @param info A pointer to iw_request_info structure
734 * @param vwrq A pointer to iw_param structure
735 * @param extra A pointer to extra data buf
736 * @return 0 --success, otherwise fail
737 */
738static int wlan_get_range(struct net_device *dev, struct iw_request_info *info,
739 struct iw_point *dwrq, char *extra)
740{
741 int i, j;
742 wlan_private *priv = dev->priv;
743 wlan_adapter *adapter = priv->adapter;
744 struct iw_range *range = (struct iw_range *)extra;
745 struct chan_freq_power *cfp;
746 u8 rates[WLAN_SUPPORTED_RATES];
747
748 u8 flag = 0;
749
750 ENTER();
751
752 dwrq->length = sizeof(struct iw_range);
753 memset(range, 0, sizeof(struct iw_range));
754
755 range->min_nwid = 0;
756 range->max_nwid = 0;
757
758 memset(rates, 0, sizeof(rates));
759 range->num_bitrates = get_active_data_rates(adapter, rates);
760
761 for (i = 0; i < min_t(__u8, range->num_bitrates, IW_MAX_BITRATES) && rates[i];
762 i++) {
763 range->bitrate[i] = (rates[i] & 0x7f) * 500000;
764 }
765 range->num_bitrates = i;
766 lbs_pr_debug(1, "IW_MAX_BITRATES=%d num_bitrates=%d\n", IW_MAX_BITRATES,
767 range->num_bitrates);
768
769 range->num_frequency = 0;
770 if (priv->adapter->enable11d &&
771 adapter->connect_status == libertas_connected) {
772 u8 chan_no;
773 u8 band;
774
775 struct parsed_region_chan_11d *parsed_region_chan =
776 &adapter->parsed_region_chan;
777
778 if (parsed_region_chan == NULL) {
779 lbs_pr_debug(1, "11D:parsed_region_chan is NULL\n");
780 LEAVE();
781 return 0;
782 }
783 band = parsed_region_chan->band;
784 lbs_pr_debug(1, "band=%d NoOfChan=%d\n", band,
785 parsed_region_chan->nr_chan);
786
787 for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
788 && (i < parsed_region_chan->nr_chan); i++) {
789 chan_no = parsed_region_chan->chanpwr[i].chan;
790 lbs_pr_debug(1, "chan_no=%d\n", chan_no);
791 range->freq[range->num_frequency].i = (long)chan_no;
792 range->freq[range->num_frequency].m =
793 (long)libertas_chan_2_freq(chan_no, band) * 100000;
794 range->freq[range->num_frequency].e = 1;
795 range->num_frequency++;
796 }
797 flag = 1;
798 }
799 if (!flag) {
800 for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
801 && (j < sizeof(adapter->region_channel)
802 / sizeof(adapter->region_channel[0])); j++) {
803 cfp = adapter->region_channel[j].CFP;
804 for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
805 && adapter->region_channel[j].valid
806 && cfp
807 && (i < adapter->region_channel[j].nrcfp); i++) {
808 range->freq[range->num_frequency].i =
809 (long)cfp->channel;
810 range->freq[range->num_frequency].m =
811 (long)cfp->freq * 100000;
812 range->freq[range->num_frequency].e = 1;
813 cfp++;
814 range->num_frequency++;
815 }
816 }
817 }
818
819 lbs_pr_debug(1, "IW_MAX_FREQUENCIES=%d num_frequency=%d\n",
820 IW_MAX_FREQUENCIES, range->num_frequency);
821
822 range->num_channels = range->num_frequency;
823
824 sort_channels(&range->freq[0], range->num_frequency);
825
826 /*
827 * Set an indication of the max TCP throughput in bit/s that we can
828 * expect using this interface
829 */
830 if (i > 2)
831 range->throughput = 5000 * 1000;
832 else
833 range->throughput = 1500 * 1000;
834
835 range->min_rts = MRVDRV_RTS_MIN_VALUE;
836 range->max_rts = MRVDRV_RTS_MAX_VALUE;
837 range->min_frag = MRVDRV_FRAG_MIN_VALUE;
838 range->max_frag = MRVDRV_FRAG_MAX_VALUE;
839
840 range->encoding_size[0] = 5;
841 range->encoding_size[1] = 13;
842 range->num_encoding_sizes = 2;
843 range->max_encoding_tokens = 4;
844
845 range->min_pmp = 1000000;
846 range->max_pmp = 120000000;
847 range->min_pmt = 1000;
848 range->max_pmt = 1000000;
849 range->pmp_flags = IW_POWER_PERIOD;
850 range->pmt_flags = IW_POWER_TIMEOUT;
851 range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
852
853 /*
854 * Minimum version we recommend
855 */
856 range->we_version_source = 15;
857
858 /*
859 * Version we are compiled with
860 */
861 range->we_version_compiled = WIRELESS_EXT;
862
863 range->retry_capa = IW_RETRY_LIMIT;
864 range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
865
866 range->min_retry = TX_RETRY_MIN;
867 range->max_retry = TX_RETRY_MAX;
868
869 /*
870 * Set the qual, level and noise range values
871 */
872 range->max_qual.qual = 100;
873 range->max_qual.level = 0;
874 range->max_qual.noise = 0;
875 range->max_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
876
877 range->avg_qual.qual = 70;
878 /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
879 range->avg_qual.level = 0;
880 range->avg_qual.noise = 0;
881 range->avg_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
882
883 range->sensitivity = 0;
884
885 /*
886 * Setup the supported power level ranges
887 */
888 memset(range->txpower, 0, sizeof(range->txpower));
889 range->txpower[0] = 5;
890 range->txpower[1] = 7;
891 range->txpower[2] = 9;
892 range->txpower[3] = 11;
893 range->txpower[4] = 13;
894 range->txpower[5] = 15;
895 range->txpower[6] = 17;
896 range->txpower[7] = 19;
897
898 range->num_txpower = 8;
899 range->txpower_capa = IW_TXPOW_DBM;
900 range->txpower_capa |= IW_TXPOW_RANGE;
901
902 range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
903 IW_EVENT_CAPA_MASK(SIOCGIWAP) |
904 IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
905 range->event_capa[1] = IW_EVENT_CAPA_K_1;
906
907 if (adapter->fwcapinfo & FW_CAPINFO_WPA) {
908 range->enc_capa = IW_ENC_CAPA_WPA
909 | IW_ENC_CAPA_WPA2
910 | IW_ENC_CAPA_CIPHER_TKIP
911 | IW_ENC_CAPA_CIPHER_CCMP;
912 }
913
914 LEAVE();
915 return 0;
916}
917
918static int wlan_set_power(struct net_device *dev, struct iw_request_info *info,
919 struct iw_param *vwrq, char *extra)
920{
921 wlan_private *priv = dev->priv;
922 wlan_adapter *adapter = priv->adapter;
923
924 ENTER();
925
926 /* PS is currently supported only in Infrastructure mode
927 * Remove this check if it is to be supported in IBSS mode also
928 */
929
930 if (vwrq->disabled) {
931 adapter->psmode = wlan802_11powermodecam;
932 if (adapter->psstate != PS_STATE_FULL_POWER) {
933 libertas_ps_wakeup(priv, cmd_option_waitforrsp);
934 }
935
936 return 0;
937 }
938
939 if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
940 lbs_pr_debug(1,
941 "Setting power timeout command is not supported\n");
942 return -EINVAL;
943 } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
944 lbs_pr_debug(1, "Setting power period command is not supported\n");
945 return -EINVAL;
946 }
947
948 if (adapter->psmode != wlan802_11powermodecam) {
949 return 0;
950 }
951
952 adapter->psmode = wlan802_11powermodemax_psp;
953
954 if (adapter->connect_status == libertas_connected) {
955 libertas_ps_sleep(priv, cmd_option_waitforrsp);
956 }
957
958 LEAVE();
959 return 0;
960}
961
962static int wlan_get_power(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 int mode;
968
969 ENTER();
970
971 mode = adapter->psmode;
972
973 if ((vwrq->disabled = (mode == wlan802_11powermodecam))
974 || adapter->connect_status == libertas_disconnected) {
975 LEAVE();
976 return 0;
977 }
978
979 vwrq->value = 0;
980
981 LEAVE();
982 return 0;
983}
984
985/*
986 * iwpriv settable callbacks
987 */
988
989static const iw_handler wlan_private_handler[] = {
990 NULL, /* SIOCIWFIRSTPRIV */
991};
992
993static const struct iw_priv_args wlan_private_args[] = {
994 /*
995 * { cmd, set_args, get_args, name }
996 */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200997 /* Using iwpriv sub-command feature */
998 {
999 WLAN_SETONEINT_GETNONE, /* IOCTL: 24 */
1000 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1001 IW_PRIV_TYPE_NONE,
1002 ""},
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001003 {
1004 WLANSETREGION,
1005 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1006 IW_PRIV_TYPE_NONE,
1007 "setregioncode"},
1008 {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001009 WLAN_SUBCMD_MESH_SET_TTL,
1010 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1011 IW_PRIV_TYPE_NONE,
1012 "mesh_set_ttl"},
1013 {
1014 WLAN_SETNONE_GETONEINT,
1015 IW_PRIV_TYPE_NONE,
1016 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1017 ""},
1018 {
1019 WLANGETREGION,
1020 IW_PRIV_TYPE_NONE,
1021 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1022 "getregioncode"},
1023 {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001024 WLAN_SUBCMD_FWT_CLEANUP,
1025 IW_PRIV_TYPE_NONE,
1026 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1027 "fwt_cleanup"},
1028 {
1029 WLAN_SUBCMD_FWT_TIME,
1030 IW_PRIV_TYPE_NONE,
1031 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1032 "fwt_time"},
1033 {
1034 WLAN_SUBCMD_MESH_GET_TTL,
1035 IW_PRIV_TYPE_NONE,
1036 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1037 "mesh_get_ttl"},
1038 {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001039 WLAN_SETNONE_GETNONE,
1040 IW_PRIV_TYPE_NONE,
1041 IW_PRIV_TYPE_NONE,
1042 ""},
1043 {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001044 WLAN_SUBCMD_FWT_RESET,
1045 IW_PRIV_TYPE_NONE,
1046 IW_PRIV_TYPE_NONE,
1047 "fwt_reset"},
1048 {
1049 WLAN_SUBCMD_BT_RESET,
1050 IW_PRIV_TYPE_NONE,
1051 IW_PRIV_TYPE_NONE,
1052 "bt_reset"},
1053 {
1054 WLAN_SET128CHAR_GET128CHAR,
1055 IW_PRIV_TYPE_CHAR | 128,
1056 IW_PRIV_TYPE_CHAR | 128,
1057 ""},
1058 /* BT Management */
1059 {
1060 WLAN_SUBCMD_BT_ADD,
1061 IW_PRIV_TYPE_CHAR | 128,
1062 IW_PRIV_TYPE_CHAR | 128,
1063 "bt_add"},
1064 {
1065 WLAN_SUBCMD_BT_DEL,
1066 IW_PRIV_TYPE_CHAR | 128,
1067 IW_PRIV_TYPE_CHAR | 128,
1068 "bt_del"},
1069 {
1070 WLAN_SUBCMD_BT_LIST,
1071 IW_PRIV_TYPE_CHAR | 128,
1072 IW_PRIV_TYPE_CHAR | 128,
1073 "bt_list"},
1074 /* FWT Management */
1075 {
1076 WLAN_SUBCMD_FWT_ADD,
1077 IW_PRIV_TYPE_CHAR | 128,
1078 IW_PRIV_TYPE_CHAR | 128,
1079 "fwt_add"},
1080 {
1081 WLAN_SUBCMD_FWT_DEL,
1082 IW_PRIV_TYPE_CHAR | 128,
1083 IW_PRIV_TYPE_CHAR | 128,
1084 "fwt_del"},
1085 {
1086 WLAN_SUBCMD_FWT_LOOKUP,
1087 IW_PRIV_TYPE_CHAR | 128,
1088 IW_PRIV_TYPE_CHAR | 128,
1089 "fwt_lookup"},
1090 {
1091 WLAN_SUBCMD_FWT_LIST_NEIGHBOR,
1092 IW_PRIV_TYPE_CHAR | 128,
1093 IW_PRIV_TYPE_CHAR | 128,
1094 "fwt_list_neigh"},
1095 {
1096 WLAN_SUBCMD_FWT_LIST,
1097 IW_PRIV_TYPE_CHAR | 128,
1098 IW_PRIV_TYPE_CHAR | 128,
1099 "fwt_list"},
1100 {
1101 WLAN_SUBCMD_FWT_LIST_ROUTE,
1102 IW_PRIV_TYPE_CHAR | 128,
1103 IW_PRIV_TYPE_CHAR | 128,
1104 "fwt_list_route"},
1105 {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001106 WLAN_SET_GET_SIXTEEN_INT,
1107 IW_PRIV_TYPE_INT | 16,
1108 IW_PRIV_TYPE_INT | 16,
1109 ""},
1110 {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001111 WLAN_LED_GPIO_CTRL,
1112 IW_PRIV_TYPE_INT | 16,
1113 IW_PRIV_TYPE_INT | 16,
1114 "ledgpio"},
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001115};
1116
1117static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev)
1118{
1119 enum {
1120 POOR = 30,
1121 FAIR = 60,
1122 GOOD = 80,
1123 VERY_GOOD = 90,
1124 EXCELLENT = 95,
1125 PERFECT = 100
1126 };
1127 wlan_private *priv = dev->priv;
1128 wlan_adapter *adapter = priv->adapter;
1129 u32 rssi_qual;
1130 u32 tx_qual;
1131 u32 quality = 0;
1132 int stats_valid = 0;
1133 u8 rssi;
1134 u32 tx_retries;
1135
1136 ENTER();
1137
Dan Williams0dc5a292007-05-10 22:58:02 -04001138 priv->wstats.status = adapter->mode;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001139
1140 /* If we're not associated, all quality values are meaningless */
1141 if (adapter->connect_status != libertas_connected)
1142 goto out;
1143
1144 /* Quality by RSSI */
1145 priv->wstats.qual.level =
1146 CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
1147 adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
1148
1149 if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
1150 priv->wstats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
1151 } else {
1152 priv->wstats.qual.noise =
1153 CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
1154 }
1155
1156 lbs_pr_debug(1, "Signal Level = %#x\n", priv->wstats.qual.level);
1157 lbs_pr_debug(1, "Noise = %#x\n", priv->wstats.qual.noise);
1158
1159 rssi = priv->wstats.qual.level - priv->wstats.qual.noise;
1160 if (rssi < 15)
1161 rssi_qual = rssi * POOR / 10;
1162 else if (rssi < 20)
1163 rssi_qual = (rssi - 15) * (FAIR - POOR) / 5 + POOR;
1164 else if (rssi < 30)
1165 rssi_qual = (rssi - 20) * (GOOD - FAIR) / 5 + FAIR;
1166 else if (rssi < 40)
1167 rssi_qual = (rssi - 30) * (VERY_GOOD - GOOD) /
1168 10 + GOOD;
1169 else
1170 rssi_qual = (rssi - 40) * (PERFECT - VERY_GOOD) /
1171 10 + VERY_GOOD;
1172 quality = rssi_qual;
1173
1174 /* Quality by TX errors */
1175 priv->wstats.discard.retries = priv->stats.tx_errors;
1176
1177 tx_retries = adapter->logmsg.retry;
1178
1179 if (tx_retries > 75)
1180 tx_qual = (90 - tx_retries) * POOR / 15;
1181 else if (tx_retries > 70)
1182 tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR;
1183 else if (tx_retries > 65)
1184 tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;
1185 else if (tx_retries > 50)
1186 tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) /
1187 15 + GOOD;
1188 else
1189 tx_qual = (50 - tx_retries) *
1190 (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
1191 quality = min(quality, tx_qual);
1192
1193 priv->wstats.discard.code = adapter->logmsg.wepundecryptable;
1194 priv->wstats.discard.fragment = adapter->logmsg.fcserror;
1195 priv->wstats.discard.retries = tx_retries;
1196 priv->wstats.discard.misc = adapter->logmsg.ackfailure;
1197
1198 /* Calculate quality */
1199 priv->wstats.qual.qual = max(quality, (u32)100);
1200 priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
1201 stats_valid = 1;
1202
1203 /* update stats asynchronously for future calls */
1204 libertas_prepare_and_send_command(priv, cmd_802_11_rssi, 0,
1205 0, 0, NULL);
1206 libertas_prepare_and_send_command(priv, cmd_802_11_get_log, 0,
1207 0, 0, NULL);
1208out:
1209 if (!stats_valid) {
1210 priv->wstats.miss.beacon = 0;
1211 priv->wstats.discard.retries = 0;
1212 priv->wstats.qual.qual = 0;
1213 priv->wstats.qual.level = 0;
1214 priv->wstats.qual.noise = 0;
1215 priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED;
1216 priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID |
1217 IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
1218 }
1219
1220 LEAVE ();
1221 return &priv->wstats;
1222
1223
1224}
1225
1226static int wlan_set_freq(struct net_device *dev, struct iw_request_info *info,
1227 struct iw_freq *fwrq, char *extra)
1228{
1229 int ret = 0;
1230 wlan_private *priv = dev->priv;
1231 wlan_adapter *adapter = priv->adapter;
1232 int rc = -EINPROGRESS; /* Call commit handler */
1233 struct chan_freq_power *cfp;
1234
1235 ENTER();
1236
1237 /*
1238 * If setting by frequency, convert to a channel
1239 */
1240 if (fwrq->e == 1) {
1241
1242 long f = fwrq->m / 100000;
1243 int c = 0;
1244
1245 cfp = find_cfp_by_band_and_freq(adapter, 0, f);
1246 if (!cfp) {
1247 lbs_pr_debug(1, "Invalid freq=%ld\n", f);
1248 return -EINVAL;
1249 }
1250
1251 c = (int)cfp->channel;
1252
1253 if (c < 0)
1254 return -EINVAL;
1255
1256 fwrq->e = 0;
1257 fwrq->m = c;
1258 }
1259
1260 /*
1261 * Setting by channel number
1262 */
1263 if (fwrq->m > 1000 || fwrq->e > 0) {
1264 rc = -EOPNOTSUPP;
1265 } else {
1266 int channel = fwrq->m;
1267
1268 cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, channel);
1269 if (!cfp) {
1270 rc = -EINVAL;
1271 } else {
Dan Williams0dc5a292007-05-10 22:58:02 -04001272 if (adapter->mode == IW_MODE_ADHOC) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001273 rc = changeadhocchannel(priv, channel);
1274 /* If station is WEP enabled, send the
1275 * command to set WEP in firmware
1276 */
Dan Williams889c05b2007-05-10 22:57:23 -04001277 if (adapter->secinfo.wep_enabled) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001278 lbs_pr_debug(1, "set_freq: WEP enabled\n");
1279 ret = libertas_prepare_and_send_command(priv,
1280 cmd_802_11_set_wep,
1281 cmd_act_add,
1282 cmd_option_waitforrsp,
1283 0,
1284 NULL);
1285
1286 if (ret) {
1287 LEAVE();
1288 return ret;
1289 }
1290
1291 adapter->currentpacketfilter |=
1292 cmd_act_mac_wep_enable;
1293
1294 libertas_set_mac_packet_filter(priv);
1295 }
1296 } else {
1297 rc = -EOPNOTSUPP;
1298 }
1299 }
1300 }
1301
1302 LEAVE();
1303 return rc;
1304}
1305
1306/**
1307 * @brief use index to get the data rate
1308 *
1309 * @param index The index of data rate
1310 * @return data rate or 0
1311 */
1312u32 libertas_index_to_data_rate(u8 index)
1313{
1314 if (index >= sizeof(libertas_wlan_data_rates))
1315 index = 0;
1316
1317 return libertas_wlan_data_rates[index];
1318}
1319
1320/**
1321 * @brief use rate to get the index
1322 *
1323 * @param rate data rate
1324 * @return index or 0
1325 */
1326u8 libertas_data_rate_to_index(u32 rate)
1327{
1328 u8 *ptr;
1329
1330 if (rate)
1331 if ((ptr = memchr(libertas_wlan_data_rates, (u8) rate,
1332 sizeof(libertas_wlan_data_rates))))
1333 return (ptr - libertas_wlan_data_rates);
1334
1335 return 0;
1336}
1337
1338static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info,
1339 struct iw_param *vwrq, char *extra)
1340{
1341 wlan_private *priv = dev->priv;
1342 wlan_adapter *adapter = priv->adapter;
1343 u32 data_rate;
1344 u16 action;
1345 int ret = 0;
1346 u8 rates[WLAN_SUPPORTED_RATES];
1347 u8 *rate;
1348
1349 ENTER();
1350
1351 lbs_pr_debug(1, "Vwrq->value = %d\n", vwrq->value);
1352
1353 if (vwrq->value == -1) {
1354 action = cmd_act_set_tx_auto; // Auto
1355 adapter->is_datarate_auto = 1;
1356 adapter->datarate = 0;
1357 } else {
1358 if (vwrq->value % 100000) {
1359 return -EINVAL;
1360 }
1361
1362 data_rate = vwrq->value / 500000;
1363
1364 memset(rates, 0, sizeof(rates));
1365 get_active_data_rates(adapter, rates);
1366 rate = rates;
1367 while (*rate) {
1368 lbs_pr_debug(1, "Rate=0x%X Wanted=0x%X\n", *rate,
1369 data_rate);
1370 if ((*rate & 0x7f) == (data_rate & 0x7f))
1371 break;
1372 rate++;
1373 }
1374 if (!*rate) {
1375 lbs_pr_alert( "The fixed data rate 0x%X is out "
1376 "of range.\n", data_rate);
1377 return -EINVAL;
1378 }
1379
1380 adapter->datarate = data_rate;
1381 action = cmd_act_set_tx_fix_rate;
1382 adapter->is_datarate_auto = 0;
1383 }
1384
1385 ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate,
1386 action, cmd_option_waitforrsp, 0, NULL);
1387
1388 LEAVE();
1389 return ret;
1390}
1391
1392static int wlan_get_rate(struct net_device *dev, struct iw_request_info *info,
1393 struct iw_param *vwrq, char *extra)
1394{
1395 wlan_private *priv = dev->priv;
1396 wlan_adapter *adapter = priv->adapter;
1397
1398 ENTER();
1399
1400 if (adapter->is_datarate_auto) {
1401 vwrq->fixed = 0;
1402 } else {
1403 vwrq->fixed = 1;
1404 }
1405
1406 vwrq->value = adapter->datarate * 500000;
1407
1408 LEAVE();
1409 return 0;
1410}
1411
1412static int wlan_set_mode(struct net_device *dev,
1413 struct iw_request_info *info, u32 * uwrq, char *extra)
1414{
1415 int ret = 0;
1416 wlan_private *priv = dev->priv;
1417 wlan_adapter *adapter = priv->adapter;
1418 struct assoc_request * assoc_req;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001419
1420 ENTER();
1421
Dan Williams0dc5a292007-05-10 22:58:02 -04001422 if ( (*uwrq != IW_MODE_ADHOC)
1423 && (*uwrq != IW_MODE_INFRA)
1424 && (*uwrq != IW_MODE_AUTO)) {
1425 lbs_pr_debug(1, "Invalid mode: 0x%x\n", *uwrq);
1426 ret = -EINVAL;
1427 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001428 }
1429
1430 mutex_lock(&adapter->lock);
1431 assoc_req = wlan_get_association_request(adapter);
1432 if (!assoc_req) {
1433 ret = -ENOMEM;
Dan Williams0dc5a292007-05-10 22:58:02 -04001434 wlan_cancel_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001435 } else {
Dan Williams0dc5a292007-05-10 22:58:02 -04001436 assoc_req->mode = *uwrq;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001437 set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
1438 wlan_postpone_association_work(priv);
Dan Williams0dc5a292007-05-10 22:58:02 -04001439 lbs_pr_debug(1, "Switching to mode: 0x%x\n", *uwrq);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001440 }
1441 mutex_unlock(&adapter->lock);
1442
Dan Williams0dc5a292007-05-10 22:58:02 -04001443out:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001444 LEAVE();
1445 return ret;
1446}
1447
1448
1449/**
1450 * @brief Get Encryption key
1451 *
1452 * @param dev A pointer to net_device structure
1453 * @param info A pointer to iw_request_info structure
1454 * @param vwrq A pointer to iw_param structure
1455 * @param extra A pointer to extra data buf
1456 * @return 0 --success, otherwise fail
1457 */
1458static int wlan_get_encode(struct net_device *dev,
1459 struct iw_request_info *info,
1460 struct iw_point *dwrq, u8 * extra)
1461{
1462 wlan_private *priv = dev->priv;
1463 wlan_adapter *adapter = priv->adapter;
1464 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
1465
1466 ENTER();
1467
1468 lbs_pr_debug(1, "flags=0x%x index=%d length=%d wep_tx_keyidx=%d\n",
1469 dwrq->flags, index, dwrq->length, adapter->wep_tx_keyidx);
1470
1471 dwrq->flags = 0;
1472
1473 /* Authentication method */
Dan Williams6affe782007-05-10 22:56:42 -04001474 switch (adapter->secinfo.auth_mode) {
1475 case IW_AUTH_ALG_OPEN_SYSTEM:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001476 dwrq->flags = IW_ENCODE_OPEN;
1477 break;
1478
Dan Williams6affe782007-05-10 22:56:42 -04001479 case IW_AUTH_ALG_SHARED_KEY:
1480 case IW_AUTH_ALG_LEAP:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001481 dwrq->flags = IW_ENCODE_RESTRICTED;
1482 break;
1483 default:
1484 dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
1485 break;
1486 }
1487
Dan Williams889c05b2007-05-10 22:57:23 -04001488 if ( adapter->secinfo.wep_enabled
1489 || adapter->secinfo.WPAenabled
1490 || adapter->secinfo.WPA2enabled) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001491 dwrq->flags &= ~IW_ENCODE_DISABLED;
1492 } else {
1493 dwrq->flags |= IW_ENCODE_DISABLED;
1494 }
1495
1496 memset(extra, 0, 16);
1497
1498 mutex_lock(&adapter->lock);
1499
1500 /* Default to returning current transmit key */
1501 if (index < 0)
1502 index = adapter->wep_tx_keyidx;
1503
Dan Williams889c05b2007-05-10 22:57:23 -04001504 if ((adapter->wep_keys[index].len) && adapter->secinfo.wep_enabled) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001505 memcpy(extra, adapter->wep_keys[index].key,
1506 adapter->wep_keys[index].len);
1507 dwrq->length = adapter->wep_keys[index].len;
1508
1509 dwrq->flags |= (index + 1);
1510 /* Return WEP enabled */
1511 dwrq->flags &= ~IW_ENCODE_DISABLED;
1512 } else if ((adapter->secinfo.WPAenabled)
1513 || (adapter->secinfo.WPA2enabled)) {
1514 /* return WPA enabled */
1515 dwrq->flags &= ~IW_ENCODE_DISABLED;
1516 } else {
1517 dwrq->flags |= IW_ENCODE_DISABLED;
1518 }
1519
1520 mutex_unlock(&adapter->lock);
1521
1522 dwrq->flags |= IW_ENCODE_NOKEY;
1523
1524 lbs_pr_debug(1, "key:%02x:%02x:%02x:%02x:%02x:%02x keylen=%d\n",
1525 extra[0], extra[1], extra[2],
1526 extra[3], extra[4], extra[5], dwrq->length);
1527
1528 lbs_pr_debug(1, "Return flags=0x%x\n", dwrq->flags);
1529
1530 LEAVE();
1531 return 0;
1532}
1533
1534/**
1535 * @brief Set Encryption key (internal)
1536 *
1537 * @param priv A pointer to private card structure
1538 * @param key_material A pointer to key material
1539 * @param key_length length of key material
1540 * @param index key index to set
1541 * @param set_tx_key Force set TX key (1 = yes, 0 = no)
1542 * @return 0 --success, otherwise fail
1543 */
1544static int wlan_set_wep_key(struct assoc_request *assoc_req,
1545 const char *key_material,
1546 u16 key_length,
1547 u16 index,
1548 int set_tx_key)
1549{
1550 struct WLAN_802_11_KEY *pkey;
1551
1552 ENTER();
1553
1554 /* Paranoid validation of key index */
1555 if (index > 3) {
1556 LEAVE();
1557 return -EINVAL;
1558 }
1559
1560 /* validate max key length */
1561 if (key_length > KEY_LEN_WEP_104) {
1562 LEAVE();
1563 return -EINVAL;
1564 }
1565
1566 pkey = &assoc_req->wep_keys[index];
1567
1568 if (key_length > 0) {
1569 memset(pkey, 0, sizeof(struct WLAN_802_11_KEY));
1570 pkey->type = KEY_TYPE_ID_WEP;
1571
1572 /* Standardize the key length */
1573 pkey->len = (key_length > KEY_LEN_WEP_40) ?
1574 KEY_LEN_WEP_104 : KEY_LEN_WEP_40;
1575 memcpy(pkey->key, key_material, key_length);
1576 }
1577
1578 if (set_tx_key) {
1579 /* Ensure the chosen key is valid */
1580 if (!pkey->len) {
1581 lbs_pr_debug(1, "key not set, so cannot enable it\n");
1582 LEAVE();
1583 return -EINVAL;
1584 }
1585 assoc_req->wep_tx_keyidx = index;
1586 }
1587
Dan Williams889c05b2007-05-10 22:57:23 -04001588 assoc_req->secinfo.wep_enabled = 1;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001589
1590 LEAVE();
1591 return 0;
1592}
1593
1594static int validate_key_index(u16 def_index, u16 raw_index,
1595 u16 *out_index, u16 *is_default)
1596{
1597 if (!out_index || !is_default)
1598 return -EINVAL;
1599
1600 /* Verify index if present, otherwise use default TX key index */
1601 if (raw_index > 0) {
1602 if (raw_index > 4)
1603 return -EINVAL;
1604 *out_index = raw_index - 1;
1605 } else {
1606 *out_index = def_index;
1607 *is_default = 1;
1608 }
1609 return 0;
1610}
1611
1612static void disable_wep(struct assoc_request *assoc_req)
1613{
1614 int i;
1615
1616 /* Set Open System auth mode */
Dan Williams6affe782007-05-10 22:56:42 -04001617 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001618
1619 /* Clear WEP keys and mark WEP as disabled */
Dan Williams889c05b2007-05-10 22:57:23 -04001620 assoc_req->secinfo.wep_enabled = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001621 for (i = 0; i < 4; i++)
1622 assoc_req->wep_keys[i].len = 0;
1623
1624 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1625 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1626}
1627
1628/**
1629 * @brief Set Encryption key
1630 *
1631 * @param dev A pointer to net_device structure
1632 * @param info A pointer to iw_request_info structure
1633 * @param vwrq A pointer to iw_param structure
1634 * @param extra A pointer to extra data buf
1635 * @return 0 --success, otherwise fail
1636 */
1637static int wlan_set_encode(struct net_device *dev,
1638 struct iw_request_info *info,
1639 struct iw_point *dwrq, char *extra)
1640{
1641 int ret = 0;
1642 wlan_private *priv = dev->priv;
1643 wlan_adapter *adapter = priv->adapter;
1644 struct assoc_request * assoc_req;
1645 u16 is_default = 0, index = 0, set_tx_key = 0;
1646
1647 ENTER();
1648
1649 mutex_lock(&adapter->lock);
1650 assoc_req = wlan_get_association_request(adapter);
1651 if (!assoc_req) {
1652 ret = -ENOMEM;
1653 goto out;
1654 }
1655
1656 if (dwrq->flags & IW_ENCODE_DISABLED) {
1657 disable_wep (assoc_req);
1658 goto out;
1659 }
1660
1661 ret = validate_key_index(assoc_req->wep_tx_keyidx,
1662 (dwrq->flags & IW_ENCODE_INDEX),
1663 &index, &is_default);
1664 if (ret) {
1665 ret = -EINVAL;
1666 goto out;
1667 }
1668
1669 /* If WEP isn't enabled, or if there is no key data but a valid
1670 * index, set the TX key.
1671 */
Dan Williams889c05b2007-05-10 22:57:23 -04001672 if (!assoc_req->secinfo.wep_enabled || (dwrq->length == 0 && !is_default))
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001673 set_tx_key = 1;
1674
1675 ret = wlan_set_wep_key(assoc_req, extra, dwrq->length, index, set_tx_key);
1676 if (ret)
1677 goto out;
1678
1679 if (dwrq->length)
1680 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1681 if (set_tx_key)
1682 set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
1683
1684 if (dwrq->flags & IW_ENCODE_RESTRICTED) {
Dan Williams6affe782007-05-10 22:56:42 -04001685 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001686 } else if (dwrq->flags & IW_ENCODE_OPEN) {
Dan Williams6affe782007-05-10 22:56:42 -04001687 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001688 }
1689
1690out:
1691 if (ret == 0) {
1692 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1693 wlan_postpone_association_work(priv);
1694 } else {
1695 wlan_cancel_association_work(priv);
1696 }
1697 mutex_unlock(&adapter->lock);
1698
1699 LEAVE();
1700 return ret;
1701}
1702
1703/**
1704 * @brief Get Extended Encryption key (WPA/802.1x and WEP)
1705 *
1706 * @param dev A pointer to net_device structure
1707 * @param info A pointer to iw_request_info structure
1708 * @param vwrq A pointer to iw_param structure
1709 * @param extra A pointer to extra data buf
1710 * @return 0 on success, otherwise failure
1711 */
1712static int wlan_get_encodeext(struct net_device *dev,
1713 struct iw_request_info *info,
1714 struct iw_point *dwrq,
1715 char *extra)
1716{
1717 int ret = -EINVAL;
1718 wlan_private *priv = dev->priv;
1719 wlan_adapter *adapter = priv->adapter;
1720 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1721 int index, max_key_len;
1722
1723 ENTER();
1724
1725 max_key_len = dwrq->length - sizeof(*ext);
1726 if (max_key_len < 0)
1727 goto out;
1728
1729 index = dwrq->flags & IW_ENCODE_INDEX;
1730 if (index) {
1731 if (index < 1 || index > 4)
1732 goto out;
1733 index--;
1734 } else {
1735 index = adapter->wep_tx_keyidx;
1736 }
1737
1738 if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY &&
1739 ext->alg != IW_ENCODE_ALG_WEP) {
Dan Williams0dc5a292007-05-10 22:58:02 -04001740 if (index != 0 || adapter->mode != IW_MODE_INFRA)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001741 goto out;
1742 }
1743
1744 dwrq->flags = index + 1;
1745 memset(ext, 0, sizeof(*ext));
1746
Dan Williams889c05b2007-05-10 22:57:23 -04001747 if ( !adapter->secinfo.wep_enabled
1748 && !adapter->secinfo.WPAenabled
1749 && !adapter->secinfo.WPA2enabled) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001750 ext->alg = IW_ENCODE_ALG_NONE;
1751 ext->key_len = 0;
1752 dwrq->flags |= IW_ENCODE_DISABLED;
1753 } else {
1754 u8 *key = NULL;
1755
Dan Williams889c05b2007-05-10 22:57:23 -04001756 if ( adapter->secinfo.wep_enabled
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001757 && !adapter->secinfo.WPAenabled
1758 && !adapter->secinfo.WPA2enabled) {
1759 ext->alg = IW_ENCODE_ALG_WEP;
1760 ext->key_len = adapter->wep_keys[index].len;
1761 key = &adapter->wep_keys[index].key[0];
Dan Williams889c05b2007-05-10 22:57:23 -04001762 } else if ( !adapter->secinfo.wep_enabled
1763 && (adapter->secinfo.WPAenabled ||
1764 adapter->secinfo.WPA2enabled)) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001765 /* WPA */
1766 ext->alg = IW_ENCODE_ALG_TKIP;
1767 ext->key_len = 0;
1768 } else {
1769 goto out;
1770 }
1771
1772 if (ext->key_len > max_key_len) {
1773 ret = -E2BIG;
1774 goto out;
1775 }
1776
1777 if (ext->key_len)
1778 memcpy(ext->key, key, ext->key_len);
1779 else
1780 dwrq->flags |= IW_ENCODE_NOKEY;
1781 dwrq->flags |= IW_ENCODE_ENABLED;
1782 }
1783 ret = 0;
1784
1785out:
1786 LEAVE();
1787 return ret;
1788}
1789
1790/**
1791 * @brief Set Encryption key Extended (WPA/802.1x and WEP)
1792 *
1793 * @param dev A pointer to net_device structure
1794 * @param info A pointer to iw_request_info structure
1795 * @param vwrq A pointer to iw_param structure
1796 * @param extra A pointer to extra data buf
1797 * @return 0 --success, otherwise fail
1798 */
1799static int wlan_set_encodeext(struct net_device *dev,
1800 struct iw_request_info *info,
1801 struct iw_point *dwrq,
1802 char *extra)
1803{
1804 int ret = 0;
1805 wlan_private *priv = dev->priv;
1806 wlan_adapter *adapter = priv->adapter;
1807 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1808 int alg = ext->alg;
1809 struct assoc_request * assoc_req;
1810
1811 ENTER();
1812
1813 mutex_lock(&adapter->lock);
1814 assoc_req = wlan_get_association_request(adapter);
1815 if (!assoc_req) {
1816 ret = -ENOMEM;
1817 goto out;
1818 }
1819
1820 if ((alg == IW_ENCODE_ALG_NONE) || (dwrq->flags & IW_ENCODE_DISABLED)) {
1821 disable_wep (assoc_req);
1822 } else if (alg == IW_ENCODE_ALG_WEP) {
1823 u16 is_default = 0, index, set_tx_key = 0;
1824
1825 ret = validate_key_index(assoc_req->wep_tx_keyidx,
1826 (dwrq->flags & IW_ENCODE_INDEX),
1827 &index, &is_default);
1828 if (ret)
1829 goto out;
1830
1831 /* If WEP isn't enabled, or if there is no key data but a valid
1832 * index, or if the set-TX-key flag was passed, set the TX key.
1833 */
Dan Williams889c05b2007-05-10 22:57:23 -04001834 if ( !assoc_req->secinfo.wep_enabled
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001835 || (dwrq->length == 0 && !is_default)
1836 || (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY))
1837 set_tx_key = 1;
1838
1839 /* Copy key to driver */
1840 ret = wlan_set_wep_key (assoc_req, ext->key, ext->key_len, index,
1841 set_tx_key);
1842 if (ret)
1843 goto out;
1844
1845 if (dwrq->flags & IW_ENCODE_RESTRICTED) {
Dan Williams6affe782007-05-10 22:56:42 -04001846 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001847 } else if (dwrq->flags & IW_ENCODE_OPEN) {
Dan Williams6affe782007-05-10 22:56:42 -04001848 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001849 }
1850
1851 /* Mark the various WEP bits as modified */
1852 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1853 if (dwrq->length)
1854 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1855 if (set_tx_key)
1856 set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
1857
1858 } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) {
1859 struct WLAN_802_11_KEY * pkey;
1860
1861 /* validate key length */
1862 if (((alg == IW_ENCODE_ALG_TKIP)
1863 && (ext->key_len != KEY_LEN_WPA_TKIP))
1864 || ((alg == IW_ENCODE_ALG_CCMP)
1865 && (ext->key_len != KEY_LEN_WPA_AES))) {
1866 lbs_pr_debug(1, "Invalid size %d for key of alg"
1867 "type %d.\n",
1868 ext->key_len,
1869 alg);
1870 ret = -EINVAL;
1871 goto out;
1872 }
1873
1874 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
1875 pkey = &assoc_req->wpa_mcast_key;
1876 else
1877 pkey = &assoc_req->wpa_unicast_key;
1878
1879 memset(pkey, 0, sizeof (struct WLAN_802_11_KEY));
1880 memcpy(pkey->key, ext->key, ext->key_len);
1881 pkey->len = ext->key_len;
1882 pkey->flags = KEY_INFO_WPA_ENABLED;
1883
1884 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
1885 pkey->flags |= KEY_INFO_WPA_MCAST;
1886 set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
1887 } else {
1888 pkey->flags |= KEY_INFO_WPA_UNICAST;
1889 set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
1890 }
1891
1892 if (alg == IW_ENCODE_ALG_TKIP)
1893 pkey->type = KEY_TYPE_ID_TKIP;
1894 else if (alg == IW_ENCODE_ALG_CCMP)
1895 pkey->type = KEY_TYPE_ID_AES;
1896
1897 /* If WPA isn't enabled yet, do that now */
1898 if ( assoc_req->secinfo.WPAenabled == 0
1899 && assoc_req->secinfo.WPA2enabled == 0) {
1900 assoc_req->secinfo.WPAenabled = 1;
1901 assoc_req->secinfo.WPA2enabled = 1;
1902 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1903 }
1904
1905 disable_wep (assoc_req);
1906 }
1907
1908out:
1909 if (ret == 0) {
1910 wlan_postpone_association_work(priv);
1911 } else {
1912 wlan_cancel_association_work(priv);
1913 }
1914 mutex_unlock(&adapter->lock);
1915
1916 LEAVE();
1917 return ret;
1918}
1919
1920
1921static int wlan_set_genie(struct net_device *dev,
1922 struct iw_request_info *info,
1923 struct iw_point *dwrq,
1924 char *extra)
1925{
1926 wlan_private *priv = dev->priv;
1927 wlan_adapter *adapter = priv->adapter;
1928 int ret = 0;
1929 struct assoc_request * assoc_req;
1930
1931 ENTER();
1932
1933 mutex_lock(&adapter->lock);
1934 assoc_req = wlan_get_association_request(adapter);
1935 if (!assoc_req) {
1936 ret = -ENOMEM;
1937 goto out;
1938 }
1939
1940 if (dwrq->length > MAX_WPA_IE_LEN ||
1941 (dwrq->length && extra == NULL)) {
1942 ret = -EINVAL;
1943 goto out;
1944 }
1945
1946 if (dwrq->length) {
1947 memcpy(&assoc_req->wpa_ie[0], extra, dwrq->length);
1948 assoc_req->wpa_ie_len = dwrq->length;
1949 } else {
1950 memset(&assoc_req->wpa_ie[0], 0, sizeof(adapter->wpa_ie));
1951 assoc_req->wpa_ie_len = 0;
1952 }
1953
1954out:
1955 if (ret == 0) {
1956 set_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags);
1957 wlan_postpone_association_work(priv);
1958 } else {
1959 wlan_cancel_association_work(priv);
1960 }
1961 mutex_unlock(&adapter->lock);
1962
1963 LEAVE();
1964 return ret;
1965}
1966
1967static int wlan_get_genie(struct net_device *dev,
1968 struct iw_request_info *info,
1969 struct iw_point *dwrq,
1970 char *extra)
1971{
1972 wlan_private *priv = dev->priv;
1973 wlan_adapter *adapter = priv->adapter;
1974
1975 ENTER();
1976
1977 if (adapter->wpa_ie_len == 0) {
1978 dwrq->length = 0;
1979 LEAVE();
1980 return 0;
1981 }
1982
1983 if (dwrq->length < adapter->wpa_ie_len) {
1984 LEAVE();
1985 return -E2BIG;
1986 }
1987
1988 dwrq->length = adapter->wpa_ie_len;
1989 memcpy(extra, &adapter->wpa_ie[0], adapter->wpa_ie_len);
1990
1991 LEAVE();
1992 return 0;
1993}
1994
1995
1996static int wlan_set_auth(struct net_device *dev,
1997 struct iw_request_info *info,
1998 struct iw_param *dwrq,
1999 char *extra)
2000{
2001 wlan_private *priv = dev->priv;
2002 wlan_adapter *adapter = priv->adapter;
2003 struct assoc_request * assoc_req;
2004 int ret = 0;
2005 int updated = 0;
2006
2007 ENTER();
2008
2009 mutex_lock(&adapter->lock);
2010 assoc_req = wlan_get_association_request(adapter);
2011 if (!assoc_req) {
2012 ret = -ENOMEM;
2013 goto out;
2014 }
2015
2016 switch (dwrq->flags & IW_AUTH_INDEX) {
2017 case IW_AUTH_TKIP_COUNTERMEASURES:
2018 case IW_AUTH_CIPHER_PAIRWISE:
2019 case IW_AUTH_CIPHER_GROUP:
2020 case IW_AUTH_KEY_MGMT:
2021 /*
2022 * libertas does not use these parameters
2023 */
2024 break;
2025
2026 case IW_AUTH_WPA_VERSION:
2027 if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) {
2028 assoc_req->secinfo.WPAenabled = 0;
2029 assoc_req->secinfo.WPA2enabled = 0;
2030 }
2031 if (dwrq->value & IW_AUTH_WPA_VERSION_WPA) {
2032 assoc_req->secinfo.WPAenabled = 1;
Dan Williams889c05b2007-05-10 22:57:23 -04002033 assoc_req->secinfo.wep_enabled = 0;
Dan Williams6affe782007-05-10 22:56:42 -04002034 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002035 }
2036 if (dwrq->value & IW_AUTH_WPA_VERSION_WPA2) {
2037 assoc_req->secinfo.WPA2enabled = 1;
Dan Williams889c05b2007-05-10 22:57:23 -04002038 assoc_req->secinfo.wep_enabled = 0;
Dan Williams6affe782007-05-10 22:56:42 -04002039 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002040 }
2041 updated = 1;
2042 break;
2043
2044 case IW_AUTH_DROP_UNENCRYPTED:
2045 if (dwrq->value) {
2046 adapter->currentpacketfilter |=
2047 cmd_act_mac_strict_protection_enable;
2048 } else {
2049 adapter->currentpacketfilter &=
2050 ~cmd_act_mac_strict_protection_enable;
2051 }
2052 updated = 1;
2053 break;
2054
2055 case IW_AUTH_80211_AUTH_ALG:
2056 if (dwrq->value & IW_AUTH_ALG_SHARED_KEY) {
Dan Williams6affe782007-05-10 22:56:42 -04002057 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002058 } else if (dwrq->value & IW_AUTH_ALG_OPEN_SYSTEM) {
Dan Williams6affe782007-05-10 22:56:42 -04002059 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002060 } else if (dwrq->value & IW_AUTH_ALG_LEAP) {
Dan Williams6affe782007-05-10 22:56:42 -04002061 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_LEAP;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002062 } else {
2063 ret = -EINVAL;
2064 }
2065 updated = 1;
2066 break;
2067
2068 case IW_AUTH_WPA_ENABLED:
2069 if (dwrq->value) {
2070 if (!assoc_req->secinfo.WPAenabled &&
2071 !assoc_req->secinfo.WPA2enabled) {
2072 assoc_req->secinfo.WPAenabled = 1;
2073 assoc_req->secinfo.WPA2enabled = 1;
Dan Williams889c05b2007-05-10 22:57:23 -04002074 assoc_req->secinfo.wep_enabled = 0;
Dan Williams6affe782007-05-10 22:56:42 -04002075 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002076 }
2077 } else {
2078 assoc_req->secinfo.WPAenabled = 0;
2079 assoc_req->secinfo.WPA2enabled = 0;
2080 }
2081 updated = 1;
2082 break;
2083
2084 default:
2085 ret = -EOPNOTSUPP;
2086 break;
2087 }
2088
2089out:
2090 if (ret == 0) {
2091 if (updated)
2092 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
2093 wlan_postpone_association_work(priv);
2094 } else if (ret != -EOPNOTSUPP) {
2095 wlan_cancel_association_work(priv);
2096 }
2097 mutex_unlock(&adapter->lock);
2098
2099 LEAVE();
2100 return ret;
2101}
2102
2103static int wlan_get_auth(struct net_device *dev,
2104 struct iw_request_info *info,
2105 struct iw_param *dwrq,
2106 char *extra)
2107{
2108 wlan_private *priv = dev->priv;
2109 wlan_adapter *adapter = priv->adapter;
2110
2111 ENTER();
2112
2113 switch (dwrq->flags & IW_AUTH_INDEX) {
2114 case IW_AUTH_WPA_VERSION:
2115 dwrq->value = 0;
2116 if (adapter->secinfo.WPAenabled)
2117 dwrq->value |= IW_AUTH_WPA_VERSION_WPA;
2118 if (adapter->secinfo.WPA2enabled)
2119 dwrq->value |= IW_AUTH_WPA_VERSION_WPA2;
2120 if (!dwrq->value)
2121 dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED;
2122 break;
2123
2124 case IW_AUTH_DROP_UNENCRYPTED:
2125 dwrq->value = 0;
2126 if (adapter->currentpacketfilter &
2127 cmd_act_mac_strict_protection_enable)
2128 dwrq->value = 1;
2129 break;
2130
2131 case IW_AUTH_80211_AUTH_ALG:
Dan Williams6affe782007-05-10 22:56:42 -04002132 dwrq->value = adapter->secinfo.auth_mode;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002133 break;
2134
2135 case IW_AUTH_WPA_ENABLED:
2136 if (adapter->secinfo.WPAenabled && adapter->secinfo.WPA2enabled)
2137 dwrq->value = 1;
2138 break;
2139
2140 default:
2141 LEAVE();
2142 return -EOPNOTSUPP;
2143 }
2144
2145 LEAVE();
2146 return 0;
2147}
2148
2149
2150static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info,
2151 struct iw_param *vwrq, char *extra)
2152{
2153 int ret = 0;
2154 wlan_private *priv = dev->priv;
2155 wlan_adapter *adapter = priv->adapter;
2156
2157 u16 dbm;
2158
2159 ENTER();
2160
2161 if (vwrq->disabled) {
2162 wlan_radio_ioctl(priv, RADIO_OFF);
2163 return 0;
2164 }
2165
2166 adapter->preamble = cmd_type_auto_preamble;
2167
2168 wlan_radio_ioctl(priv, RADIO_ON);
2169
2170 if ((vwrq->flags & IW_TXPOW_TYPE) == IW_TXPOW_MWATT) {
2171 dbm = (u16) mw_to_dbm(vwrq->value);
2172 } else
2173 dbm = (u16) vwrq->value;
2174
2175 /* auto tx power control */
2176
2177 if (vwrq->fixed == 0)
2178 dbm = 0xffff;
2179
2180 lbs_pr_debug(1, "<1>TXPOWER SET %d dbm.\n", dbm);
2181
2182 ret = libertas_prepare_and_send_command(priv,
2183 cmd_802_11_rf_tx_power,
2184 cmd_act_tx_power_opt_set_low,
2185 cmd_option_waitforrsp, 0, (void *)&dbm);
2186
2187 LEAVE();
2188 return ret;
2189}
2190
2191static int wlan_get_essid(struct net_device *dev, struct iw_request_info *info,
2192 struct iw_point *dwrq, char *extra)
2193{
2194 wlan_private *priv = dev->priv;
2195 wlan_adapter *adapter = priv->adapter;
2196
2197 ENTER();
2198 /*
2199 * Note : if dwrq->flags != 0, we should get the relevant SSID from
2200 * the SSID list...
2201 */
2202
2203 /*
2204 * Get the current SSID
2205 */
2206 if (adapter->connect_status == libertas_connected) {
2207 memcpy(extra, adapter->curbssparams.ssid.ssid,
2208 adapter->curbssparams.ssid.ssidlength);
2209 extra[adapter->curbssparams.ssid.ssidlength] = '\0';
2210 } else {
2211 memset(extra, 0, 32);
2212 extra[adapter->curbssparams.ssid.ssidlength] = '\0';
2213 }
2214 /*
2215 * If none, we may want to get the one that was set
2216 */
2217
2218 /* To make the driver backward compatible with WPA supplicant v0.2.4 */
2219 if (dwrq->length == 32) /* check with WPA supplicant buffer size */
2220 dwrq->length = min_t(size_t, adapter->curbssparams.ssid.ssidlength,
2221 IW_ESSID_MAX_SIZE);
2222 else
2223 dwrq->length = adapter->curbssparams.ssid.ssidlength + 1;
2224
2225 dwrq->flags = 1; /* active */
2226
2227 LEAVE();
2228 return 0;
2229}
2230
2231static int wlan_set_essid(struct net_device *dev, struct iw_request_info *info,
2232 struct iw_point *dwrq, char *extra)
2233{
2234 wlan_private *priv = dev->priv;
2235 wlan_adapter *adapter = priv->adapter;
2236 int ret = 0;
2237 struct WLAN_802_11_SSID ssid;
2238 struct assoc_request * assoc_req;
2239 int ssid_len = dwrq->length;
2240
2241 ENTER();
2242
2243 /*
2244 * WE-20 and earlier NULL pad the end of the SSID and increment
2245 * SSID length so it can be used like a string. WE-21 and later don't,
2246 * but some userspace tools aren't able to cope with the change.
2247 */
2248 if ((ssid_len > 0) && (extra[ssid_len - 1] == '\0'))
2249 ssid_len--;
2250
2251 /* Check the size of the string */
2252 if (ssid_len > IW_ESSID_MAX_SIZE) {
2253 ret = -E2BIG;
2254 goto out;
2255 }
2256
2257 memset(&ssid, 0, sizeof(struct WLAN_802_11_SSID));
2258
2259 if (!dwrq->flags || !ssid_len) {
2260 /* "any" SSID requested; leave SSID blank */
2261 } else {
2262 /* Specific SSID requested */
2263 memcpy(&ssid.ssid, extra, ssid_len);
2264 ssid.ssidlength = ssid_len;
2265 }
2266
2267 lbs_pr_debug(1, "Requested new SSID = %s\n",
2268 (ssid.ssidlength > 0) ? (char *)ssid.ssid : "any");
2269
2270out:
2271 mutex_lock(&adapter->lock);
2272 if (ret == 0) {
2273 /* Get or create the current association request */
2274 assoc_req = wlan_get_association_request(adapter);
2275 if (!assoc_req) {
2276 ret = -ENOMEM;
2277 } else {
2278 /* Copy the SSID to the association request */
2279 memcpy(&assoc_req->ssid, &ssid, sizeof(struct WLAN_802_11_SSID));
2280 set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
2281 wlan_postpone_association_work(priv);
2282 }
2283 }
2284
2285 /* Cancel the association request if there was an error */
2286 if (ret != 0) {
2287 wlan_cancel_association_work(priv);
2288 }
2289
2290 mutex_unlock(&adapter->lock);
2291
2292 LEAVE();
2293 return ret;
2294}
2295
2296/**
2297 * @brief Connect to the AP or Ad-hoc Network with specific bssid
2298 *
2299 * @param dev A pointer to net_device structure
2300 * @param info A pointer to iw_request_info structure
2301 * @param awrq A pointer to iw_param structure
2302 * @param extra A pointer to extra data buf
2303 * @return 0 --success, otherwise fail
2304 */
2305static int wlan_set_wap(struct net_device *dev, struct iw_request_info *info,
2306 struct sockaddr *awrq, char *extra)
2307{
2308 wlan_private *priv = dev->priv;
2309 wlan_adapter *adapter = priv->adapter;
2310 struct assoc_request * assoc_req;
2311 int ret = 0;
2312
2313 ENTER();
2314
2315 if (awrq->sa_family != ARPHRD_ETHER)
2316 return -EINVAL;
2317
2318 lbs_pr_debug(1, "ASSOC: WAP: sa_data: " MAC_FMT "\n", MAC_ARG(awrq->sa_data));
2319
2320 mutex_lock(&adapter->lock);
2321
2322 /* Get or create the current association request */
2323 assoc_req = wlan_get_association_request(adapter);
2324 if (!assoc_req) {
2325 wlan_cancel_association_work(priv);
2326 ret = -ENOMEM;
2327 } else {
2328 /* Copy the BSSID to the association request */
2329 memcpy(&assoc_req->bssid, awrq->sa_data, ETH_ALEN);
2330 set_bit(ASSOC_FLAG_BSSID, &assoc_req->flags);
2331 wlan_postpone_association_work(priv);
2332 }
2333
2334 mutex_unlock(&adapter->lock);
2335
2336 return ret;
2337}
2338
2339void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen)
2340{
2341 union {
2342 u32 l;
2343 u8 c[4];
2344 } ver;
2345 char fwver[32];
2346
2347 mutex_lock(&adapter->lock);
2348 ver.l = adapter->fwreleasenumber;
2349 mutex_unlock(&adapter->lock);
2350
2351 if (ver.c[3] == 0)
2352 sprintf(fwver, "%u.%u.%u", ver.c[2], ver.c[1], ver.c[0]);
2353 else
2354 sprintf(fwver, "%u.%u.%u.p%u",
2355 ver.c[2], ver.c[1], ver.c[0], ver.c[3]);
2356
2357 snprintf(fwversion, maxlen, fwver);
2358}
2359
2360
2361/*
2362 * iwconfig settable callbacks
2363 */
2364static const iw_handler wlan_handler[] = {
2365 (iw_handler) NULL, /* SIOCSIWCOMMIT */
2366 (iw_handler) wlan_get_name, /* SIOCGIWNAME */
2367 (iw_handler) NULL, /* SIOCSIWNWID */
2368 (iw_handler) NULL, /* SIOCGIWNWID */
2369 (iw_handler) wlan_set_freq, /* SIOCSIWFREQ */
2370 (iw_handler) wlan_get_freq, /* SIOCGIWFREQ */
2371 (iw_handler) wlan_set_mode, /* SIOCSIWMODE */
2372 (iw_handler) wlan_get_mode, /* SIOCGIWMODE */
2373 (iw_handler) NULL, /* SIOCSIWSENS */
2374 (iw_handler) NULL, /* SIOCGIWSENS */
2375 (iw_handler) NULL, /* SIOCSIWRANGE */
2376 (iw_handler) wlan_get_range, /* SIOCGIWRANGE */
2377 (iw_handler) NULL, /* SIOCSIWPRIV */
2378 (iw_handler) NULL, /* SIOCGIWPRIV */
2379 (iw_handler) NULL, /* SIOCSIWSTATS */
2380 (iw_handler) NULL, /* SIOCGIWSTATS */
2381 iw_handler_set_spy, /* SIOCSIWSPY */
2382 iw_handler_get_spy, /* SIOCGIWSPY */
2383 iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
2384 iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
2385 (iw_handler) wlan_set_wap, /* SIOCSIWAP */
2386 (iw_handler) wlan_get_wap, /* SIOCGIWAP */
2387 (iw_handler) NULL, /* SIOCSIWMLME */
2388 (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */
2389 (iw_handler) libertas_set_scan, /* SIOCSIWSCAN */
2390 (iw_handler) libertas_get_scan, /* SIOCGIWSCAN */
2391 (iw_handler) wlan_set_essid, /* SIOCSIWESSID */
2392 (iw_handler) wlan_get_essid, /* SIOCGIWESSID */
2393 (iw_handler) wlan_set_nick, /* SIOCSIWNICKN */
2394 (iw_handler) wlan_get_nick, /* SIOCGIWNICKN */
2395 (iw_handler) NULL, /* -- hole -- */
2396 (iw_handler) NULL, /* -- hole -- */
2397 (iw_handler) wlan_set_rate, /* SIOCSIWRATE */
2398 (iw_handler) wlan_get_rate, /* SIOCGIWRATE */
2399 (iw_handler) wlan_set_rts, /* SIOCSIWRTS */
2400 (iw_handler) wlan_get_rts, /* SIOCGIWRTS */
2401 (iw_handler) wlan_set_frag, /* SIOCSIWFRAG */
2402 (iw_handler) wlan_get_frag, /* SIOCGIWFRAG */
2403 (iw_handler) wlan_set_txpow, /* SIOCSIWTXPOW */
2404 (iw_handler) wlan_get_txpow, /* SIOCGIWTXPOW */
2405 (iw_handler) wlan_set_retry, /* SIOCSIWRETRY */
2406 (iw_handler) wlan_get_retry, /* SIOCGIWRETRY */
2407 (iw_handler) wlan_set_encode, /* SIOCSIWENCODE */
2408 (iw_handler) wlan_get_encode, /* SIOCGIWENCODE */
2409 (iw_handler) wlan_set_power, /* SIOCSIWPOWER */
2410 (iw_handler) wlan_get_power, /* SIOCGIWPOWER */
2411 (iw_handler) NULL, /* -- hole -- */
2412 (iw_handler) NULL, /* -- hole -- */
2413 (iw_handler) wlan_set_genie, /* SIOCSIWGENIE */
2414 (iw_handler) wlan_get_genie, /* SIOCGIWGENIE */
2415 (iw_handler) wlan_set_auth, /* SIOCSIWAUTH */
2416 (iw_handler) wlan_get_auth, /* SIOCGIWAUTH */
2417 (iw_handler) wlan_set_encodeext,/* SIOCSIWENCODEEXT */
2418 (iw_handler) wlan_get_encodeext,/* SIOCGIWENCODEEXT */
2419 (iw_handler) NULL, /* SIOCSIWPMKSA */
2420};
2421
2422struct iw_handler_def libertas_handler_def = {
2423 .num_standard = sizeof(wlan_handler) / sizeof(iw_handler),
2424 .num_private = sizeof(wlan_private_handler) / sizeof(iw_handler),
2425 .num_private_args = sizeof(wlan_private_args) /
2426 sizeof(struct iw_priv_args),
2427 .standard = (iw_handler *) wlan_handler,
2428 .private = (iw_handler *) wlan_private_handler,
2429 .private_args = (struct iw_priv_args *)wlan_private_args,
2430 .get_wireless_stats = wlan_get_wireless_stats,
2431};