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