blob: 4f0ae8026b0ec400f875a9303e4fa49458d492c3 [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)
Holger Schurig9012b282007-05-25 11:27:16 -0400113 lbs_deb_wext("libertas_find_cfp_by_band_and_channel: can't find "
114 "cfp by band %d / channel %d\n", band, channel);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200115
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)
Holger Schurig9012b282007-05-25 11:27:16 -0400154 lbs_deb_wext("find_cfp_by_band_and_freql: can't find cfp by "
155 "band %d / freq %d\n", band, freq);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200156
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
Holger Schurig9012b282007-05-25 11:27:16 -0400171 lbs_deb_wext("current channel %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200172 priv->adapter->curbssparams.channel);
173
174 return ret;
175}
176
177static int setcurrentchannel(wlan_private * priv, int channel)
178{
Holger Schurig9012b282007-05-25 11:27:16 -0400179 lbs_deb_wext("set channel %d\n", channel);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200180
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 */
Holger Schurig9012b282007-05-25 11:27:16 -0400200 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200201 }
202
Holger Schurig9012b282007-05-25 11:27:16 -0400203 lbs_deb_wext("updating channel from %d to %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200204 adapter->curbssparams.channel, adapter->adhocchannel);
205
206 setcurrentchannel(priv, adapter->adhocchannel);
207
208 updatecurrentchannel(priv);
209
210 if (adapter->curbssparams.channel != adapter->adhocchannel) {
Holger Schurig9012b282007-05-25 11:27:16 -0400211 lbs_deb_wext("failed to updated channel to %d, channel = %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200212 adapter->adhocchannel, adapter->curbssparams.channel);
Holger Schurig9012b282007-05-25 11:27:16 -0400213 ret = -1;
214 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200215 }
216
217 if (adapter->connect_status == libertas_connected) {
218 int i;
219 struct WLAN_802_11_SSID curadhocssid;
220
Holger Schurig9012b282007-05-25 11:27:16 -0400221 lbs_deb_wext("channel changed while in IBSS\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200222
223 /* Copy the current ssid */
224 memcpy(&curadhocssid, &adapter->curbssparams.ssid,
225 sizeof(struct WLAN_802_11_SSID));
226
227 /* Exit Adhoc mode */
Holger Schurig9012b282007-05-25 11:27:16 -0400228 lbs_deb_wext("in changeadhocchannel(): sending Adhoc stop\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200229 ret = libertas_stop_adhoc_network(priv);
230
Holger Schurig9012b282007-05-25 11:27:16 -0400231 if (ret)
232 goto out;
233
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200234 /* Scan for the network, do not save previous results. Stale
235 * scan data will cause us to join a non-existant adhoc network
236 */
237 libertas_send_specific_SSID_scan(priv, &curadhocssid, 0);
238
239 // find out the BSSID that matches the current SSID
240 i = libertas_find_SSID_in_list(adapter, &curadhocssid, NULL,
Dan Williams0dc5a292007-05-10 22:58:02 -0400241 IW_MODE_ADHOC);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200242
243 if (i >= 0) {
Holger Schurig9012b282007-05-25 11:27:16 -0400244 lbs_deb_wext("SSID found at %d in list,"
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200245 "so join\n", i);
246 libertas_join_adhoc_network(priv, &adapter->scantable[i]);
247 } else {
248 // else send START command
Holger Schurig9012b282007-05-25 11:27:16 -0400249 lbs_deb_wext("SSID not found in list, "
250 "creating AdHoc with SSID '%s'\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200251 curadhocssid.ssid);
252 libertas_start_adhoc_network(priv, &curadhocssid);
253 } // end of else (START command)
254 }
255
Holger Schurig9012b282007-05-25 11:27:16 -0400256out:
257 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
258 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200259}
260
261/**
262 * @brief Set Radio On/OFF
263 *
264 * @param priv A pointer to wlan_private structure
265 * @option Radio Option
266 * @return 0 --success, otherwise fail
267 */
268int wlan_radio_ioctl(wlan_private * priv, u8 option)
269{
270 int ret = 0;
271 wlan_adapter *adapter = priv->adapter;
272
Holger Schurig9012b282007-05-25 11:27:16 -0400273 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200274
275 if (adapter->radioon != option) {
Holger Schurig9012b282007-05-25 11:27:16 -0400276 lbs_deb_wext("switching radio %s\n", option ? "on" : "off");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200277 adapter->radioon = option;
278
279 ret = libertas_prepare_and_send_command(priv,
280 cmd_802_11_radio_control,
281 cmd_act_set,
282 cmd_option_waitforrsp, 0, NULL);
283 }
284
Holger Schurig9012b282007-05-25 11:27:16 -0400285 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200286 return ret;
287}
288
289/**
290 * @brief Copy rates
291 *
292 * @param dest A pointer to Dest Buf
293 * @param src A pointer to Src Buf
294 * @param len The len of Src Buf
295 * @return Number of rates copyed
296 */
297static inline int copyrates(u8 * dest, int pos, u8 * src, int len)
298{
299 int i;
300
301 for (i = 0; i < len && src[i]; i++, pos++) {
302 if (pos >= sizeof(u8) * WLAN_SUPPORTED_RATES)
303 break;
304 dest[pos] = src[i];
305 }
306
307 return pos;
308}
309
310/**
311 * @brief Get active data rates
312 *
313 * @param adapter A pointer to wlan_adapter structure
314 * @param rate The buf to return the active rates
315 * @return The number of rates
316 */
317static int get_active_data_rates(wlan_adapter * adapter,
318 u8* rates)
319{
320 int k = 0;
321
Holger Schurig9012b282007-05-25 11:27:16 -0400322 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200323
324 if (adapter->connect_status != libertas_connected) {
Dan Williams0dc5a292007-05-10 22:58:02 -0400325 if (adapter->mode == IW_MODE_INFRA) {
Holger Schurig9012b282007-05-25 11:27:16 -0400326 lbs_deb_wext("infra\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200327 k = copyrates(rates, k, libertas_supported_rates,
328 sizeof(libertas_supported_rates));
329 } else {
Holger Schurig9012b282007-05-25 11:27:16 -0400330 lbs_deb_wext("Adhoc G\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200331 k = copyrates(rates, k, libertas_adhoc_rates_g,
332 sizeof(libertas_adhoc_rates_g));
333 }
334 } else {
335 k = copyrates(rates, 0, adapter->curbssparams.datarates,
336 adapter->curbssparams.numofrates);
337 }
338
Holger Schurig9012b282007-05-25 11:27:16 -0400339 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", k);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200340 return k;
341}
342
343static int wlan_get_name(struct net_device *dev, struct iw_request_info *info,
344 char *cwrq, char *extra)
345{
346 const char *cp;
347 char comm[6] = { "COMM-" };
348 char mrvl[6] = { "MRVL-" };
349 int cnt;
350
Holger Schurig9012b282007-05-25 11:27:16 -0400351 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200352
353 strcpy(cwrq, mrvl);
354
355 cp = strstr(libertas_driver_version, comm);
356 if (cp == libertas_driver_version) //skip leading "COMM-"
357 cp = libertas_driver_version + strlen(comm);
358 else
359 cp = libertas_driver_version;
360
361 cnt = strlen(mrvl);
362 cwrq += cnt;
363 while (cnt < 16 && (*cp != '-')) {
364 *cwrq++ = toupper(*cp++);
365 cnt++;
366 }
367 *cwrq = '\0';
368
Holger Schurig9012b282007-05-25 11:27:16 -0400369 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200370 return 0;
371}
372
373static int wlan_get_freq(struct net_device *dev, struct iw_request_info *info,
374 struct iw_freq *fwrq, char *extra)
375{
376 wlan_private *priv = dev->priv;
377 wlan_adapter *adapter = priv->adapter;
378 struct chan_freq_power *cfp;
379
Holger Schurig9012b282007-05-25 11:27:16 -0400380 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200381
382 cfp = libertas_find_cfp_by_band_and_channel(adapter, 0,
383 adapter->curbssparams.channel);
384
385 if (!cfp) {
386 if (adapter->curbssparams.channel)
Holger Schurig9012b282007-05-25 11:27:16 -0400387 lbs_deb_wext("invalid channel %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200388 adapter->curbssparams.channel);
389 return -EINVAL;
390 }
391
392 fwrq->m = (long)cfp->freq * 100000;
393 fwrq->e = 1;
394
Holger Schurig9012b282007-05-25 11:27:16 -0400395 lbs_deb_wext("freq %u\n", fwrq->m);
396 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200397 return 0;
398}
399
400static int wlan_get_wap(struct net_device *dev, struct iw_request_info *info,
401 struct sockaddr *awrq, char *extra)
402{
403 wlan_private *priv = dev->priv;
404 wlan_adapter *adapter = priv->adapter;
405
Holger Schurig9012b282007-05-25 11:27:16 -0400406 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200407
408 if (adapter->connect_status == libertas_connected) {
409 memcpy(awrq->sa_data, adapter->curbssparams.bssid, ETH_ALEN);
410 } else {
411 memset(awrq->sa_data, 0, ETH_ALEN);
412 }
413 awrq->sa_family = ARPHRD_ETHER;
414
Holger Schurig9012b282007-05-25 11:27:16 -0400415 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200416 return 0;
417}
418
419static int wlan_set_nick(struct net_device *dev, struct iw_request_info *info,
420 struct iw_point *dwrq, char *extra)
421{
422 wlan_private *priv = dev->priv;
423 wlan_adapter *adapter = priv->adapter;
424
Holger Schurig9012b282007-05-25 11:27:16 -0400425 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200426
427 /*
428 * Check the size of the string
429 */
430
431 if (dwrq->length > 16) {
432 return -E2BIG;
433 }
434
435 mutex_lock(&adapter->lock);
436 memset(adapter->nodename, 0, sizeof(adapter->nodename));
437 memcpy(adapter->nodename, extra, dwrq->length);
438 mutex_unlock(&adapter->lock);
439
Holger Schurig9012b282007-05-25 11:27:16 -0400440 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200441 return 0;
442}
443
444static int wlan_get_nick(struct net_device *dev, struct iw_request_info *info,
445 struct iw_point *dwrq, char *extra)
446{
447 wlan_private *priv = dev->priv;
448 wlan_adapter *adapter = priv->adapter;
449
Holger Schurig9012b282007-05-25 11:27:16 -0400450 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200451
452 /*
453 * Get the Nick Name saved
454 */
455
456 mutex_lock(&adapter->lock);
457 strncpy(extra, adapter->nodename, 16);
458 mutex_unlock(&adapter->lock);
459
460 extra[16] = '\0';
461
462 /*
463 * If none, we may want to get the one that was set
464 */
465
466 /*
467 * Push it out !
468 */
469 dwrq->length = strlen(extra) + 1;
470
Holger Schurig9012b282007-05-25 11:27:16 -0400471 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200472 return 0;
473}
474
475static int wlan_set_rts(struct net_device *dev, struct iw_request_info *info,
476 struct iw_param *vwrq, char *extra)
477{
478 int ret = 0;
479 wlan_private *priv = dev->priv;
480 wlan_adapter *adapter = priv->adapter;
481 int rthr = vwrq->value;
482
Holger Schurig9012b282007-05-25 11:27:16 -0400483 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200484
485 if (vwrq->disabled) {
486 adapter->rtsthsd = rthr = MRVDRV_RTS_MAX_VALUE;
487 } else {
488 if (rthr < MRVDRV_RTS_MIN_VALUE || rthr > MRVDRV_RTS_MAX_VALUE)
489 return -EINVAL;
490 adapter->rtsthsd = rthr;
491 }
492
493 ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
494 cmd_act_set, cmd_option_waitforrsp,
495 OID_802_11_RTS_THRESHOLD, &rthr);
496
Holger Schurig9012b282007-05-25 11:27:16 -0400497 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200498 return ret;
499}
500
501static int wlan_get_rts(struct net_device *dev, struct iw_request_info *info,
502 struct iw_param *vwrq, char *extra)
503{
504 int ret = 0;
505 wlan_private *priv = dev->priv;
506 wlan_adapter *adapter = priv->adapter;
507
Holger Schurig9012b282007-05-25 11:27:16 -0400508 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200509
510 adapter->rtsthsd = 0;
511 ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
512 cmd_act_get, cmd_option_waitforrsp,
513 OID_802_11_RTS_THRESHOLD, NULL);
Holger Schurig9012b282007-05-25 11:27:16 -0400514 if (ret)
515 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200516
517 vwrq->value = adapter->rtsthsd;
518 vwrq->disabled = ((vwrq->value < MRVDRV_RTS_MIN_VALUE)
519 || (vwrq->value > MRVDRV_RTS_MAX_VALUE));
520 vwrq->fixed = 1;
521
Holger Schurig9012b282007-05-25 11:27:16 -0400522out:
523 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
524 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200525}
526
527static int wlan_set_frag(struct net_device *dev, struct iw_request_info *info,
528 struct iw_param *vwrq, char *extra)
529{
530 int ret = 0;
531 int fthr = vwrq->value;
532 wlan_private *priv = dev->priv;
533 wlan_adapter *adapter = priv->adapter;
534
Holger Schurig9012b282007-05-25 11:27:16 -0400535 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200536
537 if (vwrq->disabled) {
538 adapter->fragthsd = fthr = MRVDRV_FRAG_MAX_VALUE;
539 } else {
540 if (fthr < MRVDRV_FRAG_MIN_VALUE
541 || fthr > MRVDRV_FRAG_MAX_VALUE)
542 return -EINVAL;
543 adapter->fragthsd = fthr;
544 }
545
546 ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
547 cmd_act_set, cmd_option_waitforrsp,
548 OID_802_11_FRAGMENTATION_THRESHOLD, &fthr);
Holger Schurig9012b282007-05-25 11:27:16 -0400549
550 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200551 return ret;
552}
553
554static int wlan_get_frag(struct net_device *dev, struct iw_request_info *info,
555 struct iw_param *vwrq, char *extra)
556{
557 int ret = 0;
558 wlan_private *priv = dev->priv;
559 wlan_adapter *adapter = priv->adapter;
560
Holger Schurig9012b282007-05-25 11:27:16 -0400561 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200562
563 adapter->fragthsd = 0;
564 ret = libertas_prepare_and_send_command(priv,
565 cmd_802_11_snmp_mib,
566 cmd_act_get, cmd_option_waitforrsp,
567 OID_802_11_FRAGMENTATION_THRESHOLD, NULL);
Holger Schurig9012b282007-05-25 11:27:16 -0400568 if (ret)
569 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200570
571 vwrq->value = adapter->fragthsd;
572 vwrq->disabled = ((vwrq->value < MRVDRV_FRAG_MIN_VALUE)
573 || (vwrq->value > MRVDRV_FRAG_MAX_VALUE));
574 vwrq->fixed = 1;
575
Holger Schurig9012b282007-05-25 11:27:16 -0400576out:
577 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200578 return ret;
579}
580
581static int wlan_get_mode(struct net_device *dev,
582 struct iw_request_info *info, u32 * uwrq, char *extra)
583{
584 wlan_private *priv = dev->priv;
585 wlan_adapter *adapter = priv->adapter;
586
Holger Schurig9012b282007-05-25 11:27:16 -0400587 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200588
Dan Williams0dc5a292007-05-10 22:58:02 -0400589 *uwrq = adapter->mode;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200590
Holger Schurig9012b282007-05-25 11:27:16 -0400591 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200592 return 0;
593}
594
595static int wlan_get_txpow(struct net_device *dev,
596 struct iw_request_info *info,
597 struct iw_param *vwrq, char *extra)
598{
599 int ret = 0;
600 wlan_private *priv = dev->priv;
601 wlan_adapter *adapter = priv->adapter;
602
Holger Schurig9012b282007-05-25 11:27:16 -0400603 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200604
605 ret = libertas_prepare_and_send_command(priv,
606 cmd_802_11_rf_tx_power,
607 cmd_act_tx_power_opt_get,
608 cmd_option_waitforrsp, 0, NULL);
609
Holger Schurig9012b282007-05-25 11:27:16 -0400610 if (ret)
611 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200612
Holger Schurig9012b282007-05-25 11:27:16 -0400613 lbs_deb_wext("tx power level %d dbm\n", adapter->txpowerlevel);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200614 vwrq->value = adapter->txpowerlevel;
615 vwrq->fixed = 1;
616 if (adapter->radioon) {
617 vwrq->disabled = 0;
618 vwrq->flags = IW_TXPOW_DBM;
619 } else {
620 vwrq->disabled = 1;
621 }
622
Holger Schurig9012b282007-05-25 11:27:16 -0400623out:
624 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
625 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200626}
627
628static int wlan_set_retry(struct net_device *dev, struct iw_request_info *info,
629 struct iw_param *vwrq, char *extra)
630{
631 int ret = 0;
632 wlan_private *priv = dev->priv;
633 wlan_adapter *adapter = priv->adapter;
634
Holger Schurig9012b282007-05-25 11:27:16 -0400635 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200636
637 if (vwrq->flags == IW_RETRY_LIMIT) {
638 /* The MAC has a 4-bit Total_Tx_Count register
639 Total_Tx_Count = 1 + Tx_Retry_Count */
640#define TX_RETRY_MIN 0
641#define TX_RETRY_MAX 14
642 if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX)
643 return -EINVAL;
644
645 /* Adding 1 to convert retry count to try count */
646 adapter->txretrycount = vwrq->value + 1;
647
648 ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
649 cmd_act_set,
650 cmd_option_waitforrsp,
651 OID_802_11_TX_RETRYCOUNT, NULL);
652
Holger Schurig9012b282007-05-25 11:27:16 -0400653 if (ret)
654 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200655 } else {
656 return -EOPNOTSUPP;
657 }
658
Holger Schurig9012b282007-05-25 11:27:16 -0400659out:
660 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
661 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200662}
663
664static int wlan_get_retry(struct net_device *dev, struct iw_request_info *info,
665 struct iw_param *vwrq, char *extra)
666{
667 wlan_private *priv = dev->priv;
668 wlan_adapter *adapter = priv->adapter;
669 int ret = 0;
670
Holger Schurig9012b282007-05-25 11:27:16 -0400671 lbs_deb_enter(LBS_DEB_WEXT);
672
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200673 adapter->txretrycount = 0;
674 ret = libertas_prepare_and_send_command(priv,
675 cmd_802_11_snmp_mib,
676 cmd_act_get, cmd_option_waitforrsp,
677 OID_802_11_TX_RETRYCOUNT, NULL);
Holger Schurig9012b282007-05-25 11:27:16 -0400678 if (ret)
679 goto out;
680
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200681 vwrq->disabled = 0;
682 if (!vwrq->flags) {
683 vwrq->flags = IW_RETRY_LIMIT;
684 /* Subtract 1 to convert try count to retry count */
685 vwrq->value = adapter->txretrycount - 1;
686 }
687
Holger Schurig9012b282007-05-25 11:27:16 -0400688out:
689 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
690 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200691}
692
693static inline void sort_channels(struct iw_freq *freq, int num)
694{
695 int i, j;
696 struct iw_freq temp;
697
698 for (i = 0; i < num; i++)
699 for (j = i + 1; j < num; j++)
700 if (freq[i].i > freq[j].i) {
701 temp.i = freq[i].i;
702 temp.m = freq[i].m;
703
704 freq[i].i = freq[j].i;
705 freq[i].m = freq[j].m;
706
707 freq[j].i = temp.i;
708 freq[j].m = temp.m;
709 }
710}
711
712/* data rate listing
713 MULTI_BANDS:
714 abg a b b/g
715 Infra G(12) A(8) B(4) G(12)
716 Adhoc A+B(12) A(8) B(4) B(4)
717
718 non-MULTI_BANDS:
719 b b/g
720 Infra B(4) G(12)
721 Adhoc B(4) B(4)
722 */
723/**
724 * @brief Get Range Info
725 *
726 * @param dev A pointer to net_device structure
727 * @param info A pointer to iw_request_info structure
728 * @param vwrq A pointer to iw_param structure
729 * @param extra A pointer to extra data buf
730 * @return 0 --success, otherwise fail
731 */
732static int wlan_get_range(struct net_device *dev, struct iw_request_info *info,
733 struct iw_point *dwrq, char *extra)
734{
735 int i, j;
736 wlan_private *priv = dev->priv;
737 wlan_adapter *adapter = priv->adapter;
738 struct iw_range *range = (struct iw_range *)extra;
739 struct chan_freq_power *cfp;
740 u8 rates[WLAN_SUPPORTED_RATES];
741
742 u8 flag = 0;
743
Holger Schurig9012b282007-05-25 11:27:16 -0400744 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200745
746 dwrq->length = sizeof(struct iw_range);
747 memset(range, 0, sizeof(struct iw_range));
748
749 range->min_nwid = 0;
750 range->max_nwid = 0;
751
752 memset(rates, 0, sizeof(rates));
753 range->num_bitrates = get_active_data_rates(adapter, rates);
754
755 for (i = 0; i < min_t(__u8, range->num_bitrates, IW_MAX_BITRATES) && rates[i];
756 i++) {
757 range->bitrate[i] = (rates[i] & 0x7f) * 500000;
758 }
759 range->num_bitrates = i;
Holger Schurig9012b282007-05-25 11:27:16 -0400760 lbs_deb_wext("IW_MAX_BITRATES %d, num_bitrates %d\n", IW_MAX_BITRATES,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200761 range->num_bitrates);
762
763 range->num_frequency = 0;
764 if (priv->adapter->enable11d &&
765 adapter->connect_status == libertas_connected) {
766 u8 chan_no;
767 u8 band;
768
769 struct parsed_region_chan_11d *parsed_region_chan =
770 &adapter->parsed_region_chan;
771
772 if (parsed_region_chan == NULL) {
Holger Schurig9012b282007-05-25 11:27:16 -0400773 lbs_deb_wext("11d: parsed_region_chan is NULL\n");
774 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200775 }
776 band = parsed_region_chan->band;
Holger Schurig9012b282007-05-25 11:27:16 -0400777 lbs_deb_wext("band %d, nr_char %d\n", band,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200778 parsed_region_chan->nr_chan);
779
780 for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
781 && (i < parsed_region_chan->nr_chan); i++) {
782 chan_no = parsed_region_chan->chanpwr[i].chan;
Holger Schurig9012b282007-05-25 11:27:16 -0400783 lbs_deb_wext("chan_no %d\n", chan_no);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200784 range->freq[range->num_frequency].i = (long)chan_no;
785 range->freq[range->num_frequency].m =
786 (long)libertas_chan_2_freq(chan_no, band) * 100000;
787 range->freq[range->num_frequency].e = 1;
788 range->num_frequency++;
789 }
790 flag = 1;
791 }
792 if (!flag) {
793 for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
794 && (j < sizeof(adapter->region_channel)
795 / sizeof(adapter->region_channel[0])); j++) {
796 cfp = adapter->region_channel[j].CFP;
797 for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
798 && adapter->region_channel[j].valid
799 && cfp
800 && (i < adapter->region_channel[j].nrcfp); i++) {
801 range->freq[range->num_frequency].i =
802 (long)cfp->channel;
803 range->freq[range->num_frequency].m =
804 (long)cfp->freq * 100000;
805 range->freq[range->num_frequency].e = 1;
806 cfp++;
807 range->num_frequency++;
808 }
809 }
810 }
811
Holger Schurig9012b282007-05-25 11:27:16 -0400812 lbs_deb_wext("IW_MAX_FREQUENCIES %d, num_frequency %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200813 IW_MAX_FREQUENCIES, range->num_frequency);
814
815 range->num_channels = range->num_frequency;
816
817 sort_channels(&range->freq[0], range->num_frequency);
818
819 /*
820 * Set an indication of the max TCP throughput in bit/s that we can
821 * expect using this interface
822 */
823 if (i > 2)
824 range->throughput = 5000 * 1000;
825 else
826 range->throughput = 1500 * 1000;
827
828 range->min_rts = MRVDRV_RTS_MIN_VALUE;
829 range->max_rts = MRVDRV_RTS_MAX_VALUE;
830 range->min_frag = MRVDRV_FRAG_MIN_VALUE;
831 range->max_frag = MRVDRV_FRAG_MAX_VALUE;
832
833 range->encoding_size[0] = 5;
834 range->encoding_size[1] = 13;
835 range->num_encoding_sizes = 2;
836 range->max_encoding_tokens = 4;
837
838 range->min_pmp = 1000000;
839 range->max_pmp = 120000000;
840 range->min_pmt = 1000;
841 range->max_pmt = 1000000;
842 range->pmp_flags = IW_POWER_PERIOD;
843 range->pmt_flags = IW_POWER_TIMEOUT;
844 range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
845
846 /*
847 * Minimum version we recommend
848 */
849 range->we_version_source = 15;
850
851 /*
852 * Version we are compiled with
853 */
854 range->we_version_compiled = WIRELESS_EXT;
855
856 range->retry_capa = IW_RETRY_LIMIT;
857 range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
858
859 range->min_retry = TX_RETRY_MIN;
860 range->max_retry = TX_RETRY_MAX;
861
862 /*
863 * Set the qual, level and noise range values
864 */
865 range->max_qual.qual = 100;
866 range->max_qual.level = 0;
867 range->max_qual.noise = 0;
868 range->max_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
869
870 range->avg_qual.qual = 70;
871 /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
872 range->avg_qual.level = 0;
873 range->avg_qual.noise = 0;
874 range->avg_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
875
876 range->sensitivity = 0;
877
878 /*
879 * Setup the supported power level ranges
880 */
881 memset(range->txpower, 0, sizeof(range->txpower));
882 range->txpower[0] = 5;
883 range->txpower[1] = 7;
884 range->txpower[2] = 9;
885 range->txpower[3] = 11;
886 range->txpower[4] = 13;
887 range->txpower[5] = 15;
888 range->txpower[6] = 17;
889 range->txpower[7] = 19;
890
891 range->num_txpower = 8;
892 range->txpower_capa = IW_TXPOW_DBM;
893 range->txpower_capa |= IW_TXPOW_RANGE;
894
895 range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
896 IW_EVENT_CAPA_MASK(SIOCGIWAP) |
897 IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
898 range->event_capa[1] = IW_EVENT_CAPA_K_1;
899
900 if (adapter->fwcapinfo & FW_CAPINFO_WPA) {
901 range->enc_capa = IW_ENC_CAPA_WPA
902 | IW_ENC_CAPA_WPA2
903 | IW_ENC_CAPA_CIPHER_TKIP
904 | IW_ENC_CAPA_CIPHER_CCMP;
905 }
906
Holger Schurig9012b282007-05-25 11:27:16 -0400907out:
908 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200909 return 0;
910}
911
912static int wlan_set_power(struct net_device *dev, struct iw_request_info *info,
913 struct iw_param *vwrq, char *extra)
914{
915 wlan_private *priv = dev->priv;
916 wlan_adapter *adapter = priv->adapter;
917
Holger Schurig9012b282007-05-25 11:27:16 -0400918 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200919
920 /* PS is currently supported only in Infrastructure mode
921 * Remove this check if it is to be supported in IBSS mode also
922 */
923
924 if (vwrq->disabled) {
925 adapter->psmode = wlan802_11powermodecam;
926 if (adapter->psstate != PS_STATE_FULL_POWER) {
927 libertas_ps_wakeup(priv, cmd_option_waitforrsp);
928 }
929
930 return 0;
931 }
932
933 if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
Holger Schurig9012b282007-05-25 11:27:16 -0400934 lbs_deb_wext(
935 "setting power timeout is not supported\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200936 return -EINVAL;
937 } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
Holger Schurig9012b282007-05-25 11:27:16 -0400938 lbs_deb_wext("setting power period not supported\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200939 return -EINVAL;
940 }
941
942 if (adapter->psmode != wlan802_11powermodecam) {
943 return 0;
944 }
945
946 adapter->psmode = wlan802_11powermodemax_psp;
947
948 if (adapter->connect_status == libertas_connected) {
949 libertas_ps_sleep(priv, cmd_option_waitforrsp);
950 }
951
Holger Schurig9012b282007-05-25 11:27:16 -0400952 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200953 return 0;
954}
955
956static int wlan_get_power(struct net_device *dev, struct iw_request_info *info,
957 struct iw_param *vwrq, char *extra)
958{
959 wlan_private *priv = dev->priv;
960 wlan_adapter *adapter = priv->adapter;
961 int mode;
962
Holger Schurig9012b282007-05-25 11:27:16 -0400963 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200964
965 mode = adapter->psmode;
966
967 if ((vwrq->disabled = (mode == wlan802_11powermodecam))
Holger Schurig9012b282007-05-25 11:27:16 -0400968 || adapter->connect_status == libertas_disconnected)
969 {
970 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200971 }
972
973 vwrq->value = 0;
974
Holger Schurig9012b282007-05-25 11:27:16 -0400975out:
976 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200977 return 0;
978}
979
980/*
981 * iwpriv settable callbacks
982 */
983
984static const iw_handler wlan_private_handler[] = {
985 NULL, /* SIOCIWFIRSTPRIV */
986};
987
988static const struct iw_priv_args wlan_private_args[] = {
989 /*
990 * { cmd, set_args, get_args, name }
991 */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200992 /* Using iwpriv sub-command feature */
993 {
994 WLAN_SETONEINT_GETNONE, /* IOCTL: 24 */
995 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
996 IW_PRIV_TYPE_NONE,
997 ""},
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200998 {
999 WLANSETREGION,
1000 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1001 IW_PRIV_TYPE_NONE,
1002 "setregioncode"},
1003 {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001004 WLAN_SUBCMD_MESH_SET_TTL,
1005 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1006 IW_PRIV_TYPE_NONE,
1007 "mesh_set_ttl"},
1008 {
1009 WLAN_SETNONE_GETONEINT,
1010 IW_PRIV_TYPE_NONE,
1011 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1012 ""},
1013 {
1014 WLANGETREGION,
1015 IW_PRIV_TYPE_NONE,
1016 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1017 "getregioncode"},
1018 {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001019 WLAN_SUBCMD_FWT_CLEANUP,
1020 IW_PRIV_TYPE_NONE,
1021 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1022 "fwt_cleanup"},
1023 {
1024 WLAN_SUBCMD_FWT_TIME,
1025 IW_PRIV_TYPE_NONE,
1026 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1027 "fwt_time"},
1028 {
1029 WLAN_SUBCMD_MESH_GET_TTL,
1030 IW_PRIV_TYPE_NONE,
1031 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1032 "mesh_get_ttl"},
1033 {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001034 WLAN_SETNONE_GETNONE,
1035 IW_PRIV_TYPE_NONE,
1036 IW_PRIV_TYPE_NONE,
1037 ""},
1038 {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001039 WLAN_SUBCMD_FWT_RESET,
1040 IW_PRIV_TYPE_NONE,
1041 IW_PRIV_TYPE_NONE,
1042 "fwt_reset"},
1043 {
1044 WLAN_SUBCMD_BT_RESET,
1045 IW_PRIV_TYPE_NONE,
1046 IW_PRIV_TYPE_NONE,
1047 "bt_reset"},
1048 {
1049 WLAN_SET128CHAR_GET128CHAR,
1050 IW_PRIV_TYPE_CHAR | 128,
1051 IW_PRIV_TYPE_CHAR | 128,
1052 ""},
1053 /* BT Management */
1054 {
1055 WLAN_SUBCMD_BT_ADD,
1056 IW_PRIV_TYPE_CHAR | 128,
1057 IW_PRIV_TYPE_CHAR | 128,
1058 "bt_add"},
1059 {
1060 WLAN_SUBCMD_BT_DEL,
1061 IW_PRIV_TYPE_CHAR | 128,
1062 IW_PRIV_TYPE_CHAR | 128,
1063 "bt_del"},
1064 {
1065 WLAN_SUBCMD_BT_LIST,
1066 IW_PRIV_TYPE_CHAR | 128,
1067 IW_PRIV_TYPE_CHAR | 128,
1068 "bt_list"},
Luis Carlos Cobo90e8eaf2007-05-25 13:53:26 -04001069 {
1070 WLAN_SUBCMD_BT_SET_INVERT,
1071 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1072 IW_PRIV_TYPE_NONE,
1073 "bt_set_invert"},
1074 {
1075 WLAN_SUBCMD_BT_GET_INVERT,
1076 IW_PRIV_TYPE_NONE,
1077 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1078 "bt_get_invert"},
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001079 /* FWT Management */
1080 {
1081 WLAN_SUBCMD_FWT_ADD,
1082 IW_PRIV_TYPE_CHAR | 128,
1083 IW_PRIV_TYPE_CHAR | 128,
1084 "fwt_add"},
1085 {
1086 WLAN_SUBCMD_FWT_DEL,
1087 IW_PRIV_TYPE_CHAR | 128,
1088 IW_PRIV_TYPE_CHAR | 128,
1089 "fwt_del"},
1090 {
1091 WLAN_SUBCMD_FWT_LOOKUP,
1092 IW_PRIV_TYPE_CHAR | 128,
1093 IW_PRIV_TYPE_CHAR | 128,
1094 "fwt_lookup"},
1095 {
1096 WLAN_SUBCMD_FWT_LIST_NEIGHBOR,
1097 IW_PRIV_TYPE_CHAR | 128,
1098 IW_PRIV_TYPE_CHAR | 128,
1099 "fwt_list_neigh"},
1100 {
1101 WLAN_SUBCMD_FWT_LIST,
1102 IW_PRIV_TYPE_CHAR | 128,
1103 IW_PRIV_TYPE_CHAR | 128,
1104 "fwt_list"},
1105 {
1106 WLAN_SUBCMD_FWT_LIST_ROUTE,
1107 IW_PRIV_TYPE_CHAR | 128,
1108 IW_PRIV_TYPE_CHAR | 128,
1109 "fwt_list_route"},
1110 {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001111 WLAN_SET_GET_SIXTEEN_INT,
1112 IW_PRIV_TYPE_INT | 16,
1113 IW_PRIV_TYPE_INT | 16,
1114 ""},
1115 {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001116 WLAN_LED_GPIO_CTRL,
1117 IW_PRIV_TYPE_INT | 16,
1118 IW_PRIV_TYPE_INT | 16,
1119 "ledgpio"},
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001120};
1121
1122static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev)
1123{
1124 enum {
1125 POOR = 30,
1126 FAIR = 60,
1127 GOOD = 80,
1128 VERY_GOOD = 90,
1129 EXCELLENT = 95,
1130 PERFECT = 100
1131 };
1132 wlan_private *priv = dev->priv;
1133 wlan_adapter *adapter = priv->adapter;
1134 u32 rssi_qual;
1135 u32 tx_qual;
1136 u32 quality = 0;
1137 int stats_valid = 0;
1138 u8 rssi;
1139 u32 tx_retries;
1140
Holger Schurig9012b282007-05-25 11:27:16 -04001141 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001142
Dan Williams0dc5a292007-05-10 22:58:02 -04001143 priv->wstats.status = adapter->mode;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001144
1145 /* If we're not associated, all quality values are meaningless */
1146 if (adapter->connect_status != libertas_connected)
1147 goto out;
1148
1149 /* Quality by RSSI */
1150 priv->wstats.qual.level =
1151 CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
1152 adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
1153
1154 if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
1155 priv->wstats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
1156 } else {
1157 priv->wstats.qual.noise =
1158 CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
1159 }
1160
Holger Schurig9012b282007-05-25 11:27:16 -04001161 lbs_deb_wext("signal level %#x\n", priv->wstats.qual.level);
1162 lbs_deb_wext("noise %#x\n", priv->wstats.qual.noise);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001163
1164 rssi = priv->wstats.qual.level - priv->wstats.qual.noise;
1165 if (rssi < 15)
1166 rssi_qual = rssi * POOR / 10;
1167 else if (rssi < 20)
1168 rssi_qual = (rssi - 15) * (FAIR - POOR) / 5 + POOR;
1169 else if (rssi < 30)
1170 rssi_qual = (rssi - 20) * (GOOD - FAIR) / 5 + FAIR;
1171 else if (rssi < 40)
1172 rssi_qual = (rssi - 30) * (VERY_GOOD - GOOD) /
1173 10 + GOOD;
1174 else
1175 rssi_qual = (rssi - 40) * (PERFECT - VERY_GOOD) /
1176 10 + VERY_GOOD;
1177 quality = rssi_qual;
1178
1179 /* Quality by TX errors */
1180 priv->wstats.discard.retries = priv->stats.tx_errors;
1181
1182 tx_retries = adapter->logmsg.retry;
1183
1184 if (tx_retries > 75)
1185 tx_qual = (90 - tx_retries) * POOR / 15;
1186 else if (tx_retries > 70)
1187 tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR;
1188 else if (tx_retries > 65)
1189 tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;
1190 else if (tx_retries > 50)
1191 tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) /
1192 15 + GOOD;
1193 else
1194 tx_qual = (50 - tx_retries) *
1195 (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
1196 quality = min(quality, tx_qual);
1197
1198 priv->wstats.discard.code = adapter->logmsg.wepundecryptable;
Luis Carlos Cobo60045132007-05-25 13:08:33 -04001199 priv->wstats.discard.fragment = adapter->logmsg.rxfrag;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001200 priv->wstats.discard.retries = tx_retries;
1201 priv->wstats.discard.misc = adapter->logmsg.ackfailure;
1202
1203 /* Calculate quality */
1204 priv->wstats.qual.qual = max(quality, (u32)100);
1205 priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
1206 stats_valid = 1;
1207
1208 /* update stats asynchronously for future calls */
1209 libertas_prepare_and_send_command(priv, cmd_802_11_rssi, 0,
1210 0, 0, NULL);
1211 libertas_prepare_and_send_command(priv, cmd_802_11_get_log, 0,
1212 0, 0, NULL);
1213out:
1214 if (!stats_valid) {
1215 priv->wstats.miss.beacon = 0;
1216 priv->wstats.discard.retries = 0;
1217 priv->wstats.qual.qual = 0;
1218 priv->wstats.qual.level = 0;
1219 priv->wstats.qual.noise = 0;
1220 priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED;
1221 priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID |
1222 IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
1223 }
1224
Holger Schurig9012b282007-05-25 11:27:16 -04001225 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001226 return &priv->wstats;
1227
1228
1229}
1230
1231static int wlan_set_freq(struct net_device *dev, struct iw_request_info *info,
1232 struct iw_freq *fwrq, char *extra)
1233{
1234 int ret = 0;
1235 wlan_private *priv = dev->priv;
1236 wlan_adapter *adapter = priv->adapter;
1237 int rc = -EINPROGRESS; /* Call commit handler */
1238 struct chan_freq_power *cfp;
1239
Holger Schurig9012b282007-05-25 11:27:16 -04001240 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001241
1242 /*
1243 * If setting by frequency, convert to a channel
1244 */
1245 if (fwrq->e == 1) {
1246
1247 long f = fwrq->m / 100000;
1248 int c = 0;
1249
1250 cfp = find_cfp_by_band_and_freq(adapter, 0, f);
1251 if (!cfp) {
Holger Schurig9012b282007-05-25 11:27:16 -04001252 lbs_deb_wext("invalid freq %ld\n", f);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001253 return -EINVAL;
1254 }
1255
1256 c = (int)cfp->channel;
1257
1258 if (c < 0)
1259 return -EINVAL;
1260
1261 fwrq->e = 0;
1262 fwrq->m = c;
1263 }
1264
1265 /*
1266 * Setting by channel number
1267 */
1268 if (fwrq->m > 1000 || fwrq->e > 0) {
1269 rc = -EOPNOTSUPP;
1270 } else {
1271 int channel = fwrq->m;
1272
1273 cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, channel);
1274 if (!cfp) {
1275 rc = -EINVAL;
1276 } else {
Dan Williams0dc5a292007-05-10 22:58:02 -04001277 if (adapter->mode == IW_MODE_ADHOC) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001278 rc = changeadhocchannel(priv, channel);
1279 /* If station is WEP enabled, send the
1280 * command to set WEP in firmware
1281 */
Dan Williams889c05b2007-05-10 22:57:23 -04001282 if (adapter->secinfo.wep_enabled) {
Holger Schurig9012b282007-05-25 11:27:16 -04001283 lbs_deb_wext("set_freq: WEP enabled\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001284 ret = libertas_prepare_and_send_command(priv,
1285 cmd_802_11_set_wep,
1286 cmd_act_add,
1287 cmd_option_waitforrsp,
1288 0,
1289 NULL);
1290
1291 if (ret) {
Holger Schurig9012b282007-05-25 11:27:16 -04001292 rc = ret;
1293 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001294 }
1295
1296 adapter->currentpacketfilter |=
1297 cmd_act_mac_wep_enable;
1298
1299 libertas_set_mac_packet_filter(priv);
1300 }
1301 } else {
1302 rc = -EOPNOTSUPP;
1303 }
1304 }
1305 }
1306
Holger Schurig9012b282007-05-25 11:27:16 -04001307out:
1308 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", rc);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001309 return rc;
1310}
1311
1312/**
1313 * @brief use index to get the data rate
1314 *
1315 * @param index The index of data rate
1316 * @return data rate or 0
1317 */
1318u32 libertas_index_to_data_rate(u8 index)
1319{
1320 if (index >= sizeof(libertas_wlan_data_rates))
1321 index = 0;
1322
1323 return libertas_wlan_data_rates[index];
1324}
1325
1326/**
1327 * @brief use rate to get the index
1328 *
1329 * @param rate data rate
1330 * @return index or 0
1331 */
1332u8 libertas_data_rate_to_index(u32 rate)
1333{
1334 u8 *ptr;
1335
1336 if (rate)
1337 if ((ptr = memchr(libertas_wlan_data_rates, (u8) rate,
1338 sizeof(libertas_wlan_data_rates))))
1339 return (ptr - libertas_wlan_data_rates);
1340
1341 return 0;
1342}
1343
1344static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info,
1345 struct iw_param *vwrq, char *extra)
1346{
1347 wlan_private *priv = dev->priv;
1348 wlan_adapter *adapter = priv->adapter;
1349 u32 data_rate;
1350 u16 action;
1351 int ret = 0;
1352 u8 rates[WLAN_SUPPORTED_RATES];
1353 u8 *rate;
1354
Holger Schurig9012b282007-05-25 11:27:16 -04001355 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001356
Holger Schurig9012b282007-05-25 11:27:16 -04001357 lbs_deb_wext("vwrq->value %d\n", vwrq->value);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001358
1359 if (vwrq->value == -1) {
1360 action = cmd_act_set_tx_auto; // Auto
1361 adapter->is_datarate_auto = 1;
1362 adapter->datarate = 0;
1363 } else {
1364 if (vwrq->value % 100000) {
1365 return -EINVAL;
1366 }
1367
1368 data_rate = vwrq->value / 500000;
1369
1370 memset(rates, 0, sizeof(rates));
1371 get_active_data_rates(adapter, rates);
1372 rate = rates;
1373 while (*rate) {
Holger Schurig9012b282007-05-25 11:27:16 -04001374 lbs_deb_wext("rate=0x%X, wanted data_rate 0x%X\n", *rate,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001375 data_rate);
1376 if ((*rate & 0x7f) == (data_rate & 0x7f))
1377 break;
1378 rate++;
1379 }
1380 if (!*rate) {
Holger Schurig9012b282007-05-25 11:27:16 -04001381 lbs_pr_alert("fixed data rate 0x%X out "
1382 "of range\n", data_rate);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001383 return -EINVAL;
1384 }
1385
1386 adapter->datarate = data_rate;
1387 action = cmd_act_set_tx_fix_rate;
1388 adapter->is_datarate_auto = 0;
1389 }
1390
1391 ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate,
1392 action, cmd_option_waitforrsp, 0, NULL);
1393
Holger Schurig9012b282007-05-25 11:27:16 -04001394 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001395 return ret;
1396}
1397
1398static int wlan_get_rate(struct net_device *dev, struct iw_request_info *info,
1399 struct iw_param *vwrq, char *extra)
1400{
1401 wlan_private *priv = dev->priv;
1402 wlan_adapter *adapter = priv->adapter;
1403
Holger Schurig9012b282007-05-25 11:27:16 -04001404 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001405
1406 if (adapter->is_datarate_auto) {
1407 vwrq->fixed = 0;
1408 } else {
1409 vwrq->fixed = 1;
1410 }
1411
1412 vwrq->value = adapter->datarate * 500000;
1413
Holger Schurig9012b282007-05-25 11:27:16 -04001414 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001415 return 0;
1416}
1417
1418static int wlan_set_mode(struct net_device *dev,
1419 struct iw_request_info *info, u32 * uwrq, char *extra)
1420{
1421 int ret = 0;
1422 wlan_private *priv = dev->priv;
1423 wlan_adapter *adapter = priv->adapter;
1424 struct assoc_request * assoc_req;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001425
Holger Schurig9012b282007-05-25 11:27:16 -04001426 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001427
Dan Williams0dc5a292007-05-10 22:58:02 -04001428 if ( (*uwrq != IW_MODE_ADHOC)
1429 && (*uwrq != IW_MODE_INFRA)
1430 && (*uwrq != IW_MODE_AUTO)) {
Holger Schurig9012b282007-05-25 11:27:16 -04001431 lbs_deb_wext("Invalid mode: 0x%x\n", *uwrq);
Dan Williams0dc5a292007-05-10 22:58:02 -04001432 ret = -EINVAL;
1433 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001434 }
1435
1436 mutex_lock(&adapter->lock);
1437 assoc_req = wlan_get_association_request(adapter);
1438 if (!assoc_req) {
1439 ret = -ENOMEM;
Dan Williams0dc5a292007-05-10 22:58:02 -04001440 wlan_cancel_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001441 } else {
Dan Williams0dc5a292007-05-10 22:58:02 -04001442 assoc_req->mode = *uwrq;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001443 set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
1444 wlan_postpone_association_work(priv);
Holger Schurig9012b282007-05-25 11:27:16 -04001445 lbs_deb_wext("Switching to mode: 0x%x\n", *uwrq);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001446 }
1447 mutex_unlock(&adapter->lock);
1448
Dan Williams0dc5a292007-05-10 22:58:02 -04001449out:
Holger Schurig9012b282007-05-25 11:27:16 -04001450 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001451 return ret;
1452}
1453
1454
1455/**
1456 * @brief Get Encryption key
1457 *
1458 * @param dev A pointer to net_device structure
1459 * @param info A pointer to iw_request_info structure
1460 * @param vwrq A pointer to iw_param structure
1461 * @param extra A pointer to extra data buf
1462 * @return 0 --success, otherwise fail
1463 */
1464static int wlan_get_encode(struct net_device *dev,
1465 struct iw_request_info *info,
1466 struct iw_point *dwrq, u8 * extra)
1467{
1468 wlan_private *priv = dev->priv;
1469 wlan_adapter *adapter = priv->adapter;
1470 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
1471
Holger Schurig9012b282007-05-25 11:27:16 -04001472 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001473
Holger Schurig9012b282007-05-25 11:27:16 -04001474 lbs_deb_wext("flags 0x%x, index %d, length %d, wep_tx_keyidx %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001475 dwrq->flags, index, dwrq->length, adapter->wep_tx_keyidx);
1476
1477 dwrq->flags = 0;
1478
1479 /* Authentication method */
Dan Williams6affe782007-05-10 22:56:42 -04001480 switch (adapter->secinfo.auth_mode) {
1481 case IW_AUTH_ALG_OPEN_SYSTEM:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001482 dwrq->flags = IW_ENCODE_OPEN;
1483 break;
1484
Dan Williams6affe782007-05-10 22:56:42 -04001485 case IW_AUTH_ALG_SHARED_KEY:
1486 case IW_AUTH_ALG_LEAP:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001487 dwrq->flags = IW_ENCODE_RESTRICTED;
1488 break;
1489 default:
1490 dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
1491 break;
1492 }
1493
Dan Williams889c05b2007-05-10 22:57:23 -04001494 if ( adapter->secinfo.wep_enabled
1495 || adapter->secinfo.WPAenabled
1496 || adapter->secinfo.WPA2enabled) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001497 dwrq->flags &= ~IW_ENCODE_DISABLED;
1498 } else {
1499 dwrq->flags |= IW_ENCODE_DISABLED;
1500 }
1501
1502 memset(extra, 0, 16);
1503
1504 mutex_lock(&adapter->lock);
1505
1506 /* Default to returning current transmit key */
1507 if (index < 0)
1508 index = adapter->wep_tx_keyidx;
1509
Dan Williams889c05b2007-05-10 22:57:23 -04001510 if ((adapter->wep_keys[index].len) && adapter->secinfo.wep_enabled) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001511 memcpy(extra, adapter->wep_keys[index].key,
1512 adapter->wep_keys[index].len);
1513 dwrq->length = adapter->wep_keys[index].len;
1514
1515 dwrq->flags |= (index + 1);
1516 /* Return WEP enabled */
1517 dwrq->flags &= ~IW_ENCODE_DISABLED;
1518 } else if ((adapter->secinfo.WPAenabled)
1519 || (adapter->secinfo.WPA2enabled)) {
1520 /* return WPA enabled */
1521 dwrq->flags &= ~IW_ENCODE_DISABLED;
1522 } else {
1523 dwrq->flags |= IW_ENCODE_DISABLED;
1524 }
1525
1526 mutex_unlock(&adapter->lock);
1527
1528 dwrq->flags |= IW_ENCODE_NOKEY;
1529
Holger Schurig9012b282007-05-25 11:27:16 -04001530 lbs_deb_wext("key: " MAC_FMT ", keylen %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001531 extra[0], extra[1], extra[2],
1532 extra[3], extra[4], extra[5], dwrq->length);
1533
Holger Schurig9012b282007-05-25 11:27:16 -04001534 lbs_deb_wext("return flags 0x%x\n", dwrq->flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001535
Holger Schurig9012b282007-05-25 11:27:16 -04001536 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001537 return 0;
1538}
1539
1540/**
1541 * @brief Set Encryption key (internal)
1542 *
1543 * @param priv A pointer to private card structure
1544 * @param key_material A pointer to key material
1545 * @param key_length length of key material
1546 * @param index key index to set
1547 * @param set_tx_key Force set TX key (1 = yes, 0 = no)
1548 * @return 0 --success, otherwise fail
1549 */
1550static int wlan_set_wep_key(struct assoc_request *assoc_req,
1551 const char *key_material,
1552 u16 key_length,
1553 u16 index,
1554 int set_tx_key)
1555{
Holger Schurig9012b282007-05-25 11:27:16 -04001556 int ret = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001557 struct WLAN_802_11_KEY *pkey;
1558
Holger Schurig9012b282007-05-25 11:27:16 -04001559 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001560
1561 /* Paranoid validation of key index */
1562 if (index > 3) {
Holger Schurig9012b282007-05-25 11:27:16 -04001563 ret = -EINVAL;
1564 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001565 }
1566
1567 /* validate max key length */
1568 if (key_length > KEY_LEN_WEP_104) {
Holger Schurig9012b282007-05-25 11:27:16 -04001569 ret = -EINVAL;
1570 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001571 }
1572
1573 pkey = &assoc_req->wep_keys[index];
1574
1575 if (key_length > 0) {
1576 memset(pkey, 0, sizeof(struct WLAN_802_11_KEY));
1577 pkey->type = KEY_TYPE_ID_WEP;
1578
1579 /* Standardize the key length */
1580 pkey->len = (key_length > KEY_LEN_WEP_40) ?
1581 KEY_LEN_WEP_104 : KEY_LEN_WEP_40;
1582 memcpy(pkey->key, key_material, key_length);
1583 }
1584
1585 if (set_tx_key) {
1586 /* Ensure the chosen key is valid */
1587 if (!pkey->len) {
Holger Schurig9012b282007-05-25 11:27:16 -04001588 lbs_deb_wext("key not set, so cannot enable it\n");
1589 ret = -EINVAL;
1590 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001591 }
1592 assoc_req->wep_tx_keyidx = index;
1593 }
1594
Dan Williams889c05b2007-05-10 22:57:23 -04001595 assoc_req->secinfo.wep_enabled = 1;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001596
Holger Schurig9012b282007-05-25 11:27:16 -04001597out:
1598 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1599 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001600}
1601
1602static int validate_key_index(u16 def_index, u16 raw_index,
1603 u16 *out_index, u16 *is_default)
1604{
1605 if (!out_index || !is_default)
1606 return -EINVAL;
1607
1608 /* Verify index if present, otherwise use default TX key index */
1609 if (raw_index > 0) {
1610 if (raw_index > 4)
1611 return -EINVAL;
1612 *out_index = raw_index - 1;
1613 } else {
1614 *out_index = def_index;
1615 *is_default = 1;
1616 }
1617 return 0;
1618}
1619
1620static void disable_wep(struct assoc_request *assoc_req)
1621{
1622 int i;
1623
1624 /* Set Open System auth mode */
Dan Williams6affe782007-05-10 22:56:42 -04001625 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001626
1627 /* Clear WEP keys and mark WEP as disabled */
Dan Williams889c05b2007-05-10 22:57:23 -04001628 assoc_req->secinfo.wep_enabled = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001629 for (i = 0; i < 4; i++)
1630 assoc_req->wep_keys[i].len = 0;
1631
1632 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1633 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1634}
1635
1636/**
1637 * @brief Set Encryption key
1638 *
1639 * @param dev A pointer to net_device structure
1640 * @param info A pointer to iw_request_info structure
1641 * @param vwrq A pointer to iw_param structure
1642 * @param extra A pointer to extra data buf
1643 * @return 0 --success, otherwise fail
1644 */
1645static int wlan_set_encode(struct net_device *dev,
1646 struct iw_request_info *info,
1647 struct iw_point *dwrq, char *extra)
1648{
1649 int ret = 0;
1650 wlan_private *priv = dev->priv;
1651 wlan_adapter *adapter = priv->adapter;
1652 struct assoc_request * assoc_req;
1653 u16 is_default = 0, index = 0, set_tx_key = 0;
1654
Holger Schurig9012b282007-05-25 11:27:16 -04001655 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001656
1657 mutex_lock(&adapter->lock);
1658 assoc_req = wlan_get_association_request(adapter);
1659 if (!assoc_req) {
1660 ret = -ENOMEM;
1661 goto out;
1662 }
1663
1664 if (dwrq->flags & IW_ENCODE_DISABLED) {
1665 disable_wep (assoc_req);
1666 goto out;
1667 }
1668
1669 ret = validate_key_index(assoc_req->wep_tx_keyidx,
1670 (dwrq->flags & IW_ENCODE_INDEX),
1671 &index, &is_default);
1672 if (ret) {
1673 ret = -EINVAL;
1674 goto out;
1675 }
1676
1677 /* If WEP isn't enabled, or if there is no key data but a valid
1678 * index, set the TX key.
1679 */
Dan Williams889c05b2007-05-10 22:57:23 -04001680 if (!assoc_req->secinfo.wep_enabled || (dwrq->length == 0 && !is_default))
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001681 set_tx_key = 1;
1682
1683 ret = wlan_set_wep_key(assoc_req, extra, dwrq->length, index, set_tx_key);
1684 if (ret)
1685 goto out;
1686
1687 if (dwrq->length)
1688 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1689 if (set_tx_key)
1690 set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
1691
1692 if (dwrq->flags & IW_ENCODE_RESTRICTED) {
Dan Williams6affe782007-05-10 22:56:42 -04001693 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001694 } else if (dwrq->flags & IW_ENCODE_OPEN) {
Dan Williams6affe782007-05-10 22:56:42 -04001695 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001696 }
1697
1698out:
1699 if (ret == 0) {
1700 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1701 wlan_postpone_association_work(priv);
1702 } else {
1703 wlan_cancel_association_work(priv);
1704 }
1705 mutex_unlock(&adapter->lock);
1706
Holger Schurig9012b282007-05-25 11:27:16 -04001707 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001708 return ret;
1709}
1710
1711/**
1712 * @brief Get Extended Encryption key (WPA/802.1x and WEP)
1713 *
1714 * @param dev A pointer to net_device structure
1715 * @param info A pointer to iw_request_info structure
1716 * @param vwrq A pointer to iw_param structure
1717 * @param extra A pointer to extra data buf
1718 * @return 0 on success, otherwise failure
1719 */
1720static int wlan_get_encodeext(struct net_device *dev,
1721 struct iw_request_info *info,
1722 struct iw_point *dwrq,
1723 char *extra)
1724{
1725 int ret = -EINVAL;
1726 wlan_private *priv = dev->priv;
1727 wlan_adapter *adapter = priv->adapter;
1728 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1729 int index, max_key_len;
1730
Holger Schurig9012b282007-05-25 11:27:16 -04001731 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001732
1733 max_key_len = dwrq->length - sizeof(*ext);
1734 if (max_key_len < 0)
1735 goto out;
1736
1737 index = dwrq->flags & IW_ENCODE_INDEX;
1738 if (index) {
1739 if (index < 1 || index > 4)
1740 goto out;
1741 index--;
1742 } else {
1743 index = adapter->wep_tx_keyidx;
1744 }
1745
1746 if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY &&
1747 ext->alg != IW_ENCODE_ALG_WEP) {
Dan Williams0dc5a292007-05-10 22:58:02 -04001748 if (index != 0 || adapter->mode != IW_MODE_INFRA)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001749 goto out;
1750 }
1751
1752 dwrq->flags = index + 1;
1753 memset(ext, 0, sizeof(*ext));
1754
Dan Williams889c05b2007-05-10 22:57:23 -04001755 if ( !adapter->secinfo.wep_enabled
1756 && !adapter->secinfo.WPAenabled
1757 && !adapter->secinfo.WPA2enabled) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001758 ext->alg = IW_ENCODE_ALG_NONE;
1759 ext->key_len = 0;
1760 dwrq->flags |= IW_ENCODE_DISABLED;
1761 } else {
1762 u8 *key = NULL;
1763
Dan Williams889c05b2007-05-10 22:57:23 -04001764 if ( adapter->secinfo.wep_enabled
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001765 && !adapter->secinfo.WPAenabled
1766 && !adapter->secinfo.WPA2enabled) {
1767 ext->alg = IW_ENCODE_ALG_WEP;
1768 ext->key_len = adapter->wep_keys[index].len;
1769 key = &adapter->wep_keys[index].key[0];
Dan Williams889c05b2007-05-10 22:57:23 -04001770 } else if ( !adapter->secinfo.wep_enabled
1771 && (adapter->secinfo.WPAenabled ||
1772 adapter->secinfo.WPA2enabled)) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001773 /* WPA */
1774 ext->alg = IW_ENCODE_ALG_TKIP;
1775 ext->key_len = 0;
1776 } else {
1777 goto out;
1778 }
1779
1780 if (ext->key_len > max_key_len) {
1781 ret = -E2BIG;
1782 goto out;
1783 }
1784
1785 if (ext->key_len)
1786 memcpy(ext->key, key, ext->key_len);
1787 else
1788 dwrq->flags |= IW_ENCODE_NOKEY;
1789 dwrq->flags |= IW_ENCODE_ENABLED;
1790 }
1791 ret = 0;
1792
1793out:
Holger Schurig9012b282007-05-25 11:27:16 -04001794 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001795 return ret;
1796}
1797
1798/**
1799 * @brief Set Encryption key Extended (WPA/802.1x and WEP)
1800 *
1801 * @param dev A pointer to net_device structure
1802 * @param info A pointer to iw_request_info structure
1803 * @param vwrq A pointer to iw_param structure
1804 * @param extra A pointer to extra data buf
1805 * @return 0 --success, otherwise fail
1806 */
1807static int wlan_set_encodeext(struct net_device *dev,
1808 struct iw_request_info *info,
1809 struct iw_point *dwrq,
1810 char *extra)
1811{
1812 int ret = 0;
1813 wlan_private *priv = dev->priv;
1814 wlan_adapter *adapter = priv->adapter;
1815 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1816 int alg = ext->alg;
1817 struct assoc_request * assoc_req;
1818
Holger Schurig9012b282007-05-25 11:27:16 -04001819 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001820
1821 mutex_lock(&adapter->lock);
1822 assoc_req = wlan_get_association_request(adapter);
1823 if (!assoc_req) {
1824 ret = -ENOMEM;
1825 goto out;
1826 }
1827
1828 if ((alg == IW_ENCODE_ALG_NONE) || (dwrq->flags & IW_ENCODE_DISABLED)) {
1829 disable_wep (assoc_req);
1830 } else if (alg == IW_ENCODE_ALG_WEP) {
1831 u16 is_default = 0, index, set_tx_key = 0;
1832
1833 ret = validate_key_index(assoc_req->wep_tx_keyidx,
1834 (dwrq->flags & IW_ENCODE_INDEX),
1835 &index, &is_default);
1836 if (ret)
1837 goto out;
1838
1839 /* If WEP isn't enabled, or if there is no key data but a valid
1840 * index, or if the set-TX-key flag was passed, set the TX key.
1841 */
Dan Williams889c05b2007-05-10 22:57:23 -04001842 if ( !assoc_req->secinfo.wep_enabled
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001843 || (dwrq->length == 0 && !is_default)
1844 || (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY))
1845 set_tx_key = 1;
1846
1847 /* Copy key to driver */
1848 ret = wlan_set_wep_key (assoc_req, ext->key, ext->key_len, index,
1849 set_tx_key);
1850 if (ret)
1851 goto out;
1852
1853 if (dwrq->flags & IW_ENCODE_RESTRICTED) {
Dan Williams6affe782007-05-10 22:56:42 -04001854 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001855 } else if (dwrq->flags & IW_ENCODE_OPEN) {
Dan Williams6affe782007-05-10 22:56:42 -04001856 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001857 }
1858
1859 /* Mark the various WEP bits as modified */
1860 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1861 if (dwrq->length)
1862 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1863 if (set_tx_key)
1864 set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
1865
1866 } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) {
1867 struct WLAN_802_11_KEY * pkey;
1868
1869 /* validate key length */
1870 if (((alg == IW_ENCODE_ALG_TKIP)
1871 && (ext->key_len != KEY_LEN_WPA_TKIP))
1872 || ((alg == IW_ENCODE_ALG_CCMP)
1873 && (ext->key_len != KEY_LEN_WPA_AES))) {
Holger Schurig9012b282007-05-25 11:27:16 -04001874 lbs_deb_wext("invalid size %d for key of alg"
1875 "type %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001876 ext->key_len,
1877 alg);
1878 ret = -EINVAL;
1879 goto out;
1880 }
1881
1882 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
1883 pkey = &assoc_req->wpa_mcast_key;
1884 else
1885 pkey = &assoc_req->wpa_unicast_key;
1886
1887 memset(pkey, 0, sizeof (struct WLAN_802_11_KEY));
1888 memcpy(pkey->key, ext->key, ext->key_len);
1889 pkey->len = ext->key_len;
1890 pkey->flags = KEY_INFO_WPA_ENABLED;
1891
1892 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
1893 pkey->flags |= KEY_INFO_WPA_MCAST;
1894 set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
1895 } else {
1896 pkey->flags |= KEY_INFO_WPA_UNICAST;
1897 set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
1898 }
1899
1900 if (alg == IW_ENCODE_ALG_TKIP)
1901 pkey->type = KEY_TYPE_ID_TKIP;
1902 else if (alg == IW_ENCODE_ALG_CCMP)
1903 pkey->type = KEY_TYPE_ID_AES;
1904
1905 /* If WPA isn't enabled yet, do that now */
1906 if ( assoc_req->secinfo.WPAenabled == 0
1907 && assoc_req->secinfo.WPA2enabled == 0) {
1908 assoc_req->secinfo.WPAenabled = 1;
1909 assoc_req->secinfo.WPA2enabled = 1;
1910 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1911 }
1912
1913 disable_wep (assoc_req);
1914 }
1915
1916out:
1917 if (ret == 0) {
1918 wlan_postpone_association_work(priv);
1919 } else {
1920 wlan_cancel_association_work(priv);
1921 }
1922 mutex_unlock(&adapter->lock);
1923
Holger Schurig9012b282007-05-25 11:27:16 -04001924 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001925 return ret;
1926}
1927
1928
1929static int wlan_set_genie(struct net_device *dev,
1930 struct iw_request_info *info,
1931 struct iw_point *dwrq,
1932 char *extra)
1933{
1934 wlan_private *priv = dev->priv;
1935 wlan_adapter *adapter = priv->adapter;
1936 int ret = 0;
1937 struct assoc_request * assoc_req;
1938
Holger Schurig9012b282007-05-25 11:27:16 -04001939 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001940
1941 mutex_lock(&adapter->lock);
1942 assoc_req = wlan_get_association_request(adapter);
1943 if (!assoc_req) {
1944 ret = -ENOMEM;
1945 goto out;
1946 }
1947
1948 if (dwrq->length > MAX_WPA_IE_LEN ||
1949 (dwrq->length && extra == NULL)) {
1950 ret = -EINVAL;
1951 goto out;
1952 }
1953
1954 if (dwrq->length) {
1955 memcpy(&assoc_req->wpa_ie[0], extra, dwrq->length);
1956 assoc_req->wpa_ie_len = dwrq->length;
1957 } else {
1958 memset(&assoc_req->wpa_ie[0], 0, sizeof(adapter->wpa_ie));
1959 assoc_req->wpa_ie_len = 0;
1960 }
1961
1962out:
1963 if (ret == 0) {
1964 set_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags);
1965 wlan_postpone_association_work(priv);
1966 } else {
1967 wlan_cancel_association_work(priv);
1968 }
1969 mutex_unlock(&adapter->lock);
1970
Holger Schurig9012b282007-05-25 11:27:16 -04001971 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001972 return ret;
1973}
1974
1975static int wlan_get_genie(struct net_device *dev,
1976 struct iw_request_info *info,
1977 struct iw_point *dwrq,
1978 char *extra)
1979{
Holger Schurig9012b282007-05-25 11:27:16 -04001980 int ret = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001981 wlan_private *priv = dev->priv;
1982 wlan_adapter *adapter = priv->adapter;
1983
Holger Schurig9012b282007-05-25 11:27:16 -04001984 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001985
1986 if (adapter->wpa_ie_len == 0) {
1987 dwrq->length = 0;
Holger Schurig9012b282007-05-25 11:27:16 -04001988 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001989 }
1990
1991 if (dwrq->length < adapter->wpa_ie_len) {
Holger Schurig9012b282007-05-25 11:27:16 -04001992 ret = -E2BIG;
1993 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001994 }
1995
1996 dwrq->length = adapter->wpa_ie_len;
1997 memcpy(extra, &adapter->wpa_ie[0], adapter->wpa_ie_len);
1998
Holger Schurig9012b282007-05-25 11:27:16 -04001999out:
2000 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
2001 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002002}
2003
2004
2005static int wlan_set_auth(struct net_device *dev,
2006 struct iw_request_info *info,
2007 struct iw_param *dwrq,
2008 char *extra)
2009{
2010 wlan_private *priv = dev->priv;
2011 wlan_adapter *adapter = priv->adapter;
2012 struct assoc_request * assoc_req;
2013 int ret = 0;
2014 int updated = 0;
2015
Holger Schurig9012b282007-05-25 11:27:16 -04002016 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002017
2018 mutex_lock(&adapter->lock);
2019 assoc_req = wlan_get_association_request(adapter);
2020 if (!assoc_req) {
2021 ret = -ENOMEM;
2022 goto out;
2023 }
2024
2025 switch (dwrq->flags & IW_AUTH_INDEX) {
2026 case IW_AUTH_TKIP_COUNTERMEASURES:
2027 case IW_AUTH_CIPHER_PAIRWISE:
2028 case IW_AUTH_CIPHER_GROUP:
2029 case IW_AUTH_KEY_MGMT:
2030 /*
2031 * libertas does not use these parameters
2032 */
2033 break;
2034
2035 case IW_AUTH_WPA_VERSION:
2036 if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) {
2037 assoc_req->secinfo.WPAenabled = 0;
2038 assoc_req->secinfo.WPA2enabled = 0;
2039 }
2040 if (dwrq->value & IW_AUTH_WPA_VERSION_WPA) {
2041 assoc_req->secinfo.WPAenabled = 1;
Dan Williams889c05b2007-05-10 22:57:23 -04002042 assoc_req->secinfo.wep_enabled = 0;
Dan Williams6affe782007-05-10 22:56:42 -04002043 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002044 }
2045 if (dwrq->value & IW_AUTH_WPA_VERSION_WPA2) {
2046 assoc_req->secinfo.WPA2enabled = 1;
Dan Williams889c05b2007-05-10 22:57:23 -04002047 assoc_req->secinfo.wep_enabled = 0;
Dan Williams6affe782007-05-10 22:56:42 -04002048 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002049 }
2050 updated = 1;
2051 break;
2052
2053 case IW_AUTH_DROP_UNENCRYPTED:
2054 if (dwrq->value) {
2055 adapter->currentpacketfilter |=
2056 cmd_act_mac_strict_protection_enable;
2057 } else {
2058 adapter->currentpacketfilter &=
2059 ~cmd_act_mac_strict_protection_enable;
2060 }
2061 updated = 1;
2062 break;
2063
2064 case IW_AUTH_80211_AUTH_ALG:
2065 if (dwrq->value & IW_AUTH_ALG_SHARED_KEY) {
Dan Williams6affe782007-05-10 22:56:42 -04002066 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002067 } else if (dwrq->value & IW_AUTH_ALG_OPEN_SYSTEM) {
Dan Williams6affe782007-05-10 22:56:42 -04002068 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002069 } else if (dwrq->value & IW_AUTH_ALG_LEAP) {
Dan Williams6affe782007-05-10 22:56:42 -04002070 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_LEAP;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002071 } else {
2072 ret = -EINVAL;
2073 }
2074 updated = 1;
2075 break;
2076
2077 case IW_AUTH_WPA_ENABLED:
2078 if (dwrq->value) {
2079 if (!assoc_req->secinfo.WPAenabled &&
2080 !assoc_req->secinfo.WPA2enabled) {
2081 assoc_req->secinfo.WPAenabled = 1;
2082 assoc_req->secinfo.WPA2enabled = 1;
Dan Williams889c05b2007-05-10 22:57:23 -04002083 assoc_req->secinfo.wep_enabled = 0;
Dan Williams6affe782007-05-10 22:56:42 -04002084 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002085 }
2086 } else {
2087 assoc_req->secinfo.WPAenabled = 0;
2088 assoc_req->secinfo.WPA2enabled = 0;
2089 }
2090 updated = 1;
2091 break;
2092
2093 default:
2094 ret = -EOPNOTSUPP;
2095 break;
2096 }
2097
2098out:
2099 if (ret == 0) {
2100 if (updated)
2101 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
2102 wlan_postpone_association_work(priv);
2103 } else if (ret != -EOPNOTSUPP) {
2104 wlan_cancel_association_work(priv);
2105 }
2106 mutex_unlock(&adapter->lock);
2107
Holger Schurig9012b282007-05-25 11:27:16 -04002108 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002109 return ret;
2110}
2111
2112static int wlan_get_auth(struct net_device *dev,
2113 struct iw_request_info *info,
2114 struct iw_param *dwrq,
2115 char *extra)
2116{
Holger Schurig9012b282007-05-25 11:27:16 -04002117 int ret = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002118 wlan_private *priv = dev->priv;
2119 wlan_adapter *adapter = priv->adapter;
2120
Holger Schurig9012b282007-05-25 11:27:16 -04002121 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002122
2123 switch (dwrq->flags & IW_AUTH_INDEX) {
2124 case IW_AUTH_WPA_VERSION:
2125 dwrq->value = 0;
2126 if (adapter->secinfo.WPAenabled)
2127 dwrq->value |= IW_AUTH_WPA_VERSION_WPA;
2128 if (adapter->secinfo.WPA2enabled)
2129 dwrq->value |= IW_AUTH_WPA_VERSION_WPA2;
2130 if (!dwrq->value)
2131 dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED;
2132 break;
2133
2134 case IW_AUTH_DROP_UNENCRYPTED:
2135 dwrq->value = 0;
2136 if (adapter->currentpacketfilter &
2137 cmd_act_mac_strict_protection_enable)
2138 dwrq->value = 1;
2139 break;
2140
2141 case IW_AUTH_80211_AUTH_ALG:
Dan Williams6affe782007-05-10 22:56:42 -04002142 dwrq->value = adapter->secinfo.auth_mode;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002143 break;
2144
2145 case IW_AUTH_WPA_ENABLED:
2146 if (adapter->secinfo.WPAenabled && adapter->secinfo.WPA2enabled)
2147 dwrq->value = 1;
2148 break;
2149
2150 default:
Holger Schurig9012b282007-05-25 11:27:16 -04002151 ret = -EOPNOTSUPP;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002152 }
2153
Holger Schurig9012b282007-05-25 11:27:16 -04002154 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
2155 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002156}
2157
2158
2159static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info,
2160 struct iw_param *vwrq, char *extra)
2161{
2162 int ret = 0;
2163 wlan_private *priv = dev->priv;
2164 wlan_adapter *adapter = priv->adapter;
2165
2166 u16 dbm;
2167
Holger Schurig9012b282007-05-25 11:27:16 -04002168 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002169
2170 if (vwrq->disabled) {
2171 wlan_radio_ioctl(priv, RADIO_OFF);
2172 return 0;
2173 }
2174
2175 adapter->preamble = cmd_type_auto_preamble;
2176
2177 wlan_radio_ioctl(priv, RADIO_ON);
2178
2179 if ((vwrq->flags & IW_TXPOW_TYPE) == IW_TXPOW_MWATT) {
2180 dbm = (u16) mw_to_dbm(vwrq->value);
2181 } else
2182 dbm = (u16) vwrq->value;
2183
2184 /* auto tx power control */
2185
2186 if (vwrq->fixed == 0)
2187 dbm = 0xffff;
2188
Holger Schurig9012b282007-05-25 11:27:16 -04002189 lbs_deb_wext("txpower set %d dbm\n", dbm);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002190
2191 ret = libertas_prepare_and_send_command(priv,
2192 cmd_802_11_rf_tx_power,
2193 cmd_act_tx_power_opt_set_low,
2194 cmd_option_waitforrsp, 0, (void *)&dbm);
2195
Holger Schurig9012b282007-05-25 11:27:16 -04002196 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002197 return ret;
2198}
2199
2200static int wlan_get_essid(struct net_device *dev, struct iw_request_info *info,
2201 struct iw_point *dwrq, char *extra)
2202{
2203 wlan_private *priv = dev->priv;
2204 wlan_adapter *adapter = priv->adapter;
2205
Holger Schurig9012b282007-05-25 11:27:16 -04002206 lbs_deb_enter(LBS_DEB_WEXT);
2207
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002208 /*
2209 * Note : if dwrq->flags != 0, we should get the relevant SSID from
2210 * the SSID list...
2211 */
2212
2213 /*
2214 * Get the current SSID
2215 */
2216 if (adapter->connect_status == libertas_connected) {
2217 memcpy(extra, adapter->curbssparams.ssid.ssid,
2218 adapter->curbssparams.ssid.ssidlength);
2219 extra[adapter->curbssparams.ssid.ssidlength] = '\0';
2220 } else {
2221 memset(extra, 0, 32);
2222 extra[adapter->curbssparams.ssid.ssidlength] = '\0';
2223 }
2224 /*
2225 * If none, we may want to get the one that was set
2226 */
2227
2228 /* To make the driver backward compatible with WPA supplicant v0.2.4 */
2229 if (dwrq->length == 32) /* check with WPA supplicant buffer size */
2230 dwrq->length = min_t(size_t, adapter->curbssparams.ssid.ssidlength,
2231 IW_ESSID_MAX_SIZE);
2232 else
2233 dwrq->length = adapter->curbssparams.ssid.ssidlength + 1;
2234
2235 dwrq->flags = 1; /* active */
2236
Holger Schurig9012b282007-05-25 11:27:16 -04002237 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002238 return 0;
2239}
2240
2241static int wlan_set_essid(struct net_device *dev, struct iw_request_info *info,
2242 struct iw_point *dwrq, char *extra)
2243{
2244 wlan_private *priv = dev->priv;
2245 wlan_adapter *adapter = priv->adapter;
2246 int ret = 0;
2247 struct WLAN_802_11_SSID ssid;
2248 struct assoc_request * assoc_req;
2249 int ssid_len = dwrq->length;
2250
Holger Schurig9012b282007-05-25 11:27:16 -04002251 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002252
2253 /*
2254 * WE-20 and earlier NULL pad the end of the SSID and increment
2255 * SSID length so it can be used like a string. WE-21 and later don't,
2256 * but some userspace tools aren't able to cope with the change.
2257 */
2258 if ((ssid_len > 0) && (extra[ssid_len - 1] == '\0'))
2259 ssid_len--;
2260
2261 /* Check the size of the string */
2262 if (ssid_len > IW_ESSID_MAX_SIZE) {
2263 ret = -E2BIG;
2264 goto out;
2265 }
2266
2267 memset(&ssid, 0, sizeof(struct WLAN_802_11_SSID));
2268
2269 if (!dwrq->flags || !ssid_len) {
2270 /* "any" SSID requested; leave SSID blank */
2271 } else {
2272 /* Specific SSID requested */
2273 memcpy(&ssid.ssid, extra, ssid_len);
2274 ssid.ssidlength = ssid_len;
2275 }
2276
Holger Schurig9012b282007-05-25 11:27:16 -04002277 lbs_deb_wext("requested new SSID '%s'\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002278 (ssid.ssidlength > 0) ? (char *)ssid.ssid : "any");
2279
2280out:
2281 mutex_lock(&adapter->lock);
2282 if (ret == 0) {
2283 /* Get or create the current association request */
2284 assoc_req = wlan_get_association_request(adapter);
2285 if (!assoc_req) {
2286 ret = -ENOMEM;
2287 } else {
2288 /* Copy the SSID to the association request */
2289 memcpy(&assoc_req->ssid, &ssid, sizeof(struct WLAN_802_11_SSID));
2290 set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
2291 wlan_postpone_association_work(priv);
2292 }
2293 }
2294
2295 /* Cancel the association request if there was an error */
2296 if (ret != 0) {
2297 wlan_cancel_association_work(priv);
2298 }
2299
2300 mutex_unlock(&adapter->lock);
2301
Holger Schurig9012b282007-05-25 11:27:16 -04002302 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002303 return ret;
2304}
2305
2306/**
2307 * @brief Connect to the AP or Ad-hoc Network with specific bssid
2308 *
2309 * @param dev A pointer to net_device structure
2310 * @param info A pointer to iw_request_info structure
2311 * @param awrq A pointer to iw_param structure
2312 * @param extra A pointer to extra data buf
2313 * @return 0 --success, otherwise fail
2314 */
2315static int wlan_set_wap(struct net_device *dev, struct iw_request_info *info,
2316 struct sockaddr *awrq, char *extra)
2317{
2318 wlan_private *priv = dev->priv;
2319 wlan_adapter *adapter = priv->adapter;
2320 struct assoc_request * assoc_req;
2321 int ret = 0;
2322
Holger Schurig9012b282007-05-25 11:27:16 -04002323 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002324
2325 if (awrq->sa_family != ARPHRD_ETHER)
2326 return -EINVAL;
2327
Holger Schurig9012b282007-05-25 11:27:16 -04002328 lbs_deb_wext("ASSOC: WAP: sa_data " MAC_FMT "\n", MAC_ARG(awrq->sa_data));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002329
2330 mutex_lock(&adapter->lock);
2331
2332 /* Get or create the current association request */
2333 assoc_req = wlan_get_association_request(adapter);
2334 if (!assoc_req) {
2335 wlan_cancel_association_work(priv);
2336 ret = -ENOMEM;
2337 } else {
2338 /* Copy the BSSID to the association request */
2339 memcpy(&assoc_req->bssid, awrq->sa_data, ETH_ALEN);
2340 set_bit(ASSOC_FLAG_BSSID, &assoc_req->flags);
2341 wlan_postpone_association_work(priv);
2342 }
2343
2344 mutex_unlock(&adapter->lock);
2345
2346 return ret;
2347}
2348
2349void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen)
2350{
2351 union {
2352 u32 l;
2353 u8 c[4];
2354 } ver;
2355 char fwver[32];
2356
2357 mutex_lock(&adapter->lock);
2358 ver.l = adapter->fwreleasenumber;
2359 mutex_unlock(&adapter->lock);
2360
2361 if (ver.c[3] == 0)
2362 sprintf(fwver, "%u.%u.%u", ver.c[2], ver.c[1], ver.c[0]);
2363 else
2364 sprintf(fwver, "%u.%u.%u.p%u",
2365 ver.c[2], ver.c[1], ver.c[0], ver.c[3]);
2366
2367 snprintf(fwversion, maxlen, fwver);
2368}
2369
2370
2371/*
2372 * iwconfig settable callbacks
2373 */
2374static const iw_handler wlan_handler[] = {
2375 (iw_handler) NULL, /* SIOCSIWCOMMIT */
2376 (iw_handler) wlan_get_name, /* SIOCGIWNAME */
2377 (iw_handler) NULL, /* SIOCSIWNWID */
2378 (iw_handler) NULL, /* SIOCGIWNWID */
2379 (iw_handler) wlan_set_freq, /* SIOCSIWFREQ */
2380 (iw_handler) wlan_get_freq, /* SIOCGIWFREQ */
2381 (iw_handler) wlan_set_mode, /* SIOCSIWMODE */
2382 (iw_handler) wlan_get_mode, /* SIOCGIWMODE */
2383 (iw_handler) NULL, /* SIOCSIWSENS */
2384 (iw_handler) NULL, /* SIOCGIWSENS */
2385 (iw_handler) NULL, /* SIOCSIWRANGE */
2386 (iw_handler) wlan_get_range, /* SIOCGIWRANGE */
2387 (iw_handler) NULL, /* SIOCSIWPRIV */
2388 (iw_handler) NULL, /* SIOCGIWPRIV */
2389 (iw_handler) NULL, /* SIOCSIWSTATS */
2390 (iw_handler) NULL, /* SIOCGIWSTATS */
2391 iw_handler_set_spy, /* SIOCSIWSPY */
2392 iw_handler_get_spy, /* SIOCGIWSPY */
2393 iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
2394 iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
2395 (iw_handler) wlan_set_wap, /* SIOCSIWAP */
2396 (iw_handler) wlan_get_wap, /* SIOCGIWAP */
2397 (iw_handler) NULL, /* SIOCSIWMLME */
2398 (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */
2399 (iw_handler) libertas_set_scan, /* SIOCSIWSCAN */
2400 (iw_handler) libertas_get_scan, /* SIOCGIWSCAN */
2401 (iw_handler) wlan_set_essid, /* SIOCSIWESSID */
2402 (iw_handler) wlan_get_essid, /* SIOCGIWESSID */
2403 (iw_handler) wlan_set_nick, /* SIOCSIWNICKN */
2404 (iw_handler) wlan_get_nick, /* SIOCGIWNICKN */
2405 (iw_handler) NULL, /* -- hole -- */
2406 (iw_handler) NULL, /* -- hole -- */
2407 (iw_handler) wlan_set_rate, /* SIOCSIWRATE */
2408 (iw_handler) wlan_get_rate, /* SIOCGIWRATE */
2409 (iw_handler) wlan_set_rts, /* SIOCSIWRTS */
2410 (iw_handler) wlan_get_rts, /* SIOCGIWRTS */
2411 (iw_handler) wlan_set_frag, /* SIOCSIWFRAG */
2412 (iw_handler) wlan_get_frag, /* SIOCGIWFRAG */
2413 (iw_handler) wlan_set_txpow, /* SIOCSIWTXPOW */
2414 (iw_handler) wlan_get_txpow, /* SIOCGIWTXPOW */
2415 (iw_handler) wlan_set_retry, /* SIOCSIWRETRY */
2416 (iw_handler) wlan_get_retry, /* SIOCGIWRETRY */
2417 (iw_handler) wlan_set_encode, /* SIOCSIWENCODE */
2418 (iw_handler) wlan_get_encode, /* SIOCGIWENCODE */
2419 (iw_handler) wlan_set_power, /* SIOCSIWPOWER */
2420 (iw_handler) wlan_get_power, /* SIOCGIWPOWER */
2421 (iw_handler) NULL, /* -- hole -- */
2422 (iw_handler) NULL, /* -- hole -- */
2423 (iw_handler) wlan_set_genie, /* SIOCSIWGENIE */
2424 (iw_handler) wlan_get_genie, /* SIOCGIWGENIE */
2425 (iw_handler) wlan_set_auth, /* SIOCSIWAUTH */
2426 (iw_handler) wlan_get_auth, /* SIOCGIWAUTH */
2427 (iw_handler) wlan_set_encodeext,/* SIOCSIWENCODEEXT */
2428 (iw_handler) wlan_get_encodeext,/* SIOCGIWENCODEEXT */
2429 (iw_handler) NULL, /* SIOCSIWPMKSA */
2430};
2431
2432struct iw_handler_def libertas_handler_def = {
2433 .num_standard = sizeof(wlan_handler) / sizeof(iw_handler),
2434 .num_private = sizeof(wlan_private_handler) / sizeof(iw_handler),
2435 .num_private_args = sizeof(wlan_private_args) /
2436 sizeof(struct iw_priv_args),
2437 .standard = (iw_handler *) wlan_handler,
2438 .private = (iw_handler *) wlan_private_handler,
2439 .private_args = (struct iw_priv_args *)wlan_private_args,
2440 .get_wireless_stats = wlan_get_wireless_stats,
2441};