blob: 1bc2fbfe730f84f705857e5143673623b7a07260 [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"},
1069 /* FWT Management */
1070 {
1071 WLAN_SUBCMD_FWT_ADD,
1072 IW_PRIV_TYPE_CHAR | 128,
1073 IW_PRIV_TYPE_CHAR | 128,
1074 "fwt_add"},
1075 {
1076 WLAN_SUBCMD_FWT_DEL,
1077 IW_PRIV_TYPE_CHAR | 128,
1078 IW_PRIV_TYPE_CHAR | 128,
1079 "fwt_del"},
1080 {
1081 WLAN_SUBCMD_FWT_LOOKUP,
1082 IW_PRIV_TYPE_CHAR | 128,
1083 IW_PRIV_TYPE_CHAR | 128,
1084 "fwt_lookup"},
1085 {
1086 WLAN_SUBCMD_FWT_LIST_NEIGHBOR,
1087 IW_PRIV_TYPE_CHAR | 128,
1088 IW_PRIV_TYPE_CHAR | 128,
1089 "fwt_list_neigh"},
1090 {
1091 WLAN_SUBCMD_FWT_LIST,
1092 IW_PRIV_TYPE_CHAR | 128,
1093 IW_PRIV_TYPE_CHAR | 128,
1094 "fwt_list"},
1095 {
1096 WLAN_SUBCMD_FWT_LIST_ROUTE,
1097 IW_PRIV_TYPE_CHAR | 128,
1098 IW_PRIV_TYPE_CHAR | 128,
1099 "fwt_list_route"},
1100 {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001101 WLAN_SET_GET_SIXTEEN_INT,
1102 IW_PRIV_TYPE_INT | 16,
1103 IW_PRIV_TYPE_INT | 16,
1104 ""},
1105 {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001106 WLAN_LED_GPIO_CTRL,
1107 IW_PRIV_TYPE_INT | 16,
1108 IW_PRIV_TYPE_INT | 16,
1109 "ledgpio"},
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001110};
1111
1112static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev)
1113{
1114 enum {
1115 POOR = 30,
1116 FAIR = 60,
1117 GOOD = 80,
1118 VERY_GOOD = 90,
1119 EXCELLENT = 95,
1120 PERFECT = 100
1121 };
1122 wlan_private *priv = dev->priv;
1123 wlan_adapter *adapter = priv->adapter;
1124 u32 rssi_qual;
1125 u32 tx_qual;
1126 u32 quality = 0;
1127 int stats_valid = 0;
1128 u8 rssi;
1129 u32 tx_retries;
1130
Holger Schurig9012b282007-05-25 11:27:16 -04001131 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001132
Dan Williams0dc5a292007-05-10 22:58:02 -04001133 priv->wstats.status = adapter->mode;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001134
1135 /* If we're not associated, all quality values are meaningless */
1136 if (adapter->connect_status != libertas_connected)
1137 goto out;
1138
1139 /* Quality by RSSI */
1140 priv->wstats.qual.level =
1141 CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
1142 adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
1143
1144 if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
1145 priv->wstats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
1146 } else {
1147 priv->wstats.qual.noise =
1148 CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
1149 }
1150
Holger Schurig9012b282007-05-25 11:27:16 -04001151 lbs_deb_wext("signal level %#x\n", priv->wstats.qual.level);
1152 lbs_deb_wext("noise %#x\n", priv->wstats.qual.noise);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001153
1154 rssi = priv->wstats.qual.level - priv->wstats.qual.noise;
1155 if (rssi < 15)
1156 rssi_qual = rssi * POOR / 10;
1157 else if (rssi < 20)
1158 rssi_qual = (rssi - 15) * (FAIR - POOR) / 5 + POOR;
1159 else if (rssi < 30)
1160 rssi_qual = (rssi - 20) * (GOOD - FAIR) / 5 + FAIR;
1161 else if (rssi < 40)
1162 rssi_qual = (rssi - 30) * (VERY_GOOD - GOOD) /
1163 10 + GOOD;
1164 else
1165 rssi_qual = (rssi - 40) * (PERFECT - VERY_GOOD) /
1166 10 + VERY_GOOD;
1167 quality = rssi_qual;
1168
1169 /* Quality by TX errors */
1170 priv->wstats.discard.retries = priv->stats.tx_errors;
1171
1172 tx_retries = adapter->logmsg.retry;
1173
1174 if (tx_retries > 75)
1175 tx_qual = (90 - tx_retries) * POOR / 15;
1176 else if (tx_retries > 70)
1177 tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR;
1178 else if (tx_retries > 65)
1179 tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;
1180 else if (tx_retries > 50)
1181 tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) /
1182 15 + GOOD;
1183 else
1184 tx_qual = (50 - tx_retries) *
1185 (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
1186 quality = min(quality, tx_qual);
1187
1188 priv->wstats.discard.code = adapter->logmsg.wepundecryptable;
Luis Carlos Cobo60045132007-05-25 13:08:33 -04001189 priv->wstats.discard.fragment = adapter->logmsg.rxfrag;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001190 priv->wstats.discard.retries = tx_retries;
1191 priv->wstats.discard.misc = adapter->logmsg.ackfailure;
1192
1193 /* Calculate quality */
1194 priv->wstats.qual.qual = max(quality, (u32)100);
1195 priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
1196 stats_valid = 1;
1197
1198 /* update stats asynchronously for future calls */
1199 libertas_prepare_and_send_command(priv, cmd_802_11_rssi, 0,
1200 0, 0, NULL);
1201 libertas_prepare_and_send_command(priv, cmd_802_11_get_log, 0,
1202 0, 0, NULL);
1203out:
1204 if (!stats_valid) {
1205 priv->wstats.miss.beacon = 0;
1206 priv->wstats.discard.retries = 0;
1207 priv->wstats.qual.qual = 0;
1208 priv->wstats.qual.level = 0;
1209 priv->wstats.qual.noise = 0;
1210 priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED;
1211 priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID |
1212 IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
1213 }
1214
Holger Schurig9012b282007-05-25 11:27:16 -04001215 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001216 return &priv->wstats;
1217
1218
1219}
1220
1221static int wlan_set_freq(struct net_device *dev, struct iw_request_info *info,
1222 struct iw_freq *fwrq, char *extra)
1223{
1224 int ret = 0;
1225 wlan_private *priv = dev->priv;
1226 wlan_adapter *adapter = priv->adapter;
1227 int rc = -EINPROGRESS; /* Call commit handler */
1228 struct chan_freq_power *cfp;
1229
Holger Schurig9012b282007-05-25 11:27:16 -04001230 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001231
1232 /*
1233 * If setting by frequency, convert to a channel
1234 */
1235 if (fwrq->e == 1) {
1236
1237 long f = fwrq->m / 100000;
1238 int c = 0;
1239
1240 cfp = find_cfp_by_band_and_freq(adapter, 0, f);
1241 if (!cfp) {
Holger Schurig9012b282007-05-25 11:27:16 -04001242 lbs_deb_wext("invalid freq %ld\n", f);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001243 return -EINVAL;
1244 }
1245
1246 c = (int)cfp->channel;
1247
1248 if (c < 0)
1249 return -EINVAL;
1250
1251 fwrq->e = 0;
1252 fwrq->m = c;
1253 }
1254
1255 /*
1256 * Setting by channel number
1257 */
1258 if (fwrq->m > 1000 || fwrq->e > 0) {
1259 rc = -EOPNOTSUPP;
1260 } else {
1261 int channel = fwrq->m;
1262
1263 cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, channel);
1264 if (!cfp) {
1265 rc = -EINVAL;
1266 } else {
Dan Williams0dc5a292007-05-10 22:58:02 -04001267 if (adapter->mode == IW_MODE_ADHOC) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001268 rc = changeadhocchannel(priv, channel);
1269 /* If station is WEP enabled, send the
1270 * command to set WEP in firmware
1271 */
Dan Williams889c05b2007-05-10 22:57:23 -04001272 if (adapter->secinfo.wep_enabled) {
Holger Schurig9012b282007-05-25 11:27:16 -04001273 lbs_deb_wext("set_freq: WEP enabled\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001274 ret = libertas_prepare_and_send_command(priv,
1275 cmd_802_11_set_wep,
1276 cmd_act_add,
1277 cmd_option_waitforrsp,
1278 0,
1279 NULL);
1280
1281 if (ret) {
Holger Schurig9012b282007-05-25 11:27:16 -04001282 rc = ret;
1283 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001284 }
1285
1286 adapter->currentpacketfilter |=
1287 cmd_act_mac_wep_enable;
1288
1289 libertas_set_mac_packet_filter(priv);
1290 }
1291 } else {
1292 rc = -EOPNOTSUPP;
1293 }
1294 }
1295 }
1296
Holger Schurig9012b282007-05-25 11:27:16 -04001297out:
1298 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", rc);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001299 return rc;
1300}
1301
1302/**
1303 * @brief use index to get the data rate
1304 *
1305 * @param index The index of data rate
1306 * @return data rate or 0
1307 */
1308u32 libertas_index_to_data_rate(u8 index)
1309{
1310 if (index >= sizeof(libertas_wlan_data_rates))
1311 index = 0;
1312
1313 return libertas_wlan_data_rates[index];
1314}
1315
1316/**
1317 * @brief use rate to get the index
1318 *
1319 * @param rate data rate
1320 * @return index or 0
1321 */
1322u8 libertas_data_rate_to_index(u32 rate)
1323{
1324 u8 *ptr;
1325
1326 if (rate)
1327 if ((ptr = memchr(libertas_wlan_data_rates, (u8) rate,
1328 sizeof(libertas_wlan_data_rates))))
1329 return (ptr - libertas_wlan_data_rates);
1330
1331 return 0;
1332}
1333
1334static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info,
1335 struct iw_param *vwrq, char *extra)
1336{
1337 wlan_private *priv = dev->priv;
1338 wlan_adapter *adapter = priv->adapter;
1339 u32 data_rate;
1340 u16 action;
1341 int ret = 0;
1342 u8 rates[WLAN_SUPPORTED_RATES];
1343 u8 *rate;
1344
Holger Schurig9012b282007-05-25 11:27:16 -04001345 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001346
Holger Schurig9012b282007-05-25 11:27:16 -04001347 lbs_deb_wext("vwrq->value %d\n", vwrq->value);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001348
1349 if (vwrq->value == -1) {
1350 action = cmd_act_set_tx_auto; // Auto
1351 adapter->is_datarate_auto = 1;
1352 adapter->datarate = 0;
1353 } else {
1354 if (vwrq->value % 100000) {
1355 return -EINVAL;
1356 }
1357
1358 data_rate = vwrq->value / 500000;
1359
1360 memset(rates, 0, sizeof(rates));
1361 get_active_data_rates(adapter, rates);
1362 rate = rates;
1363 while (*rate) {
Holger Schurig9012b282007-05-25 11:27:16 -04001364 lbs_deb_wext("rate=0x%X, wanted data_rate 0x%X\n", *rate,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001365 data_rate);
1366 if ((*rate & 0x7f) == (data_rate & 0x7f))
1367 break;
1368 rate++;
1369 }
1370 if (!*rate) {
Holger Schurig9012b282007-05-25 11:27:16 -04001371 lbs_pr_alert("fixed data rate 0x%X out "
1372 "of range\n", data_rate);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001373 return -EINVAL;
1374 }
1375
1376 adapter->datarate = data_rate;
1377 action = cmd_act_set_tx_fix_rate;
1378 adapter->is_datarate_auto = 0;
1379 }
1380
1381 ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate,
1382 action, cmd_option_waitforrsp, 0, NULL);
1383
Holger Schurig9012b282007-05-25 11:27:16 -04001384 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001385 return ret;
1386}
1387
1388static int wlan_get_rate(struct net_device *dev, struct iw_request_info *info,
1389 struct iw_param *vwrq, char *extra)
1390{
1391 wlan_private *priv = dev->priv;
1392 wlan_adapter *adapter = priv->adapter;
1393
Holger Schurig9012b282007-05-25 11:27:16 -04001394 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001395
1396 if (adapter->is_datarate_auto) {
1397 vwrq->fixed = 0;
1398 } else {
1399 vwrq->fixed = 1;
1400 }
1401
1402 vwrq->value = adapter->datarate * 500000;
1403
Holger Schurig9012b282007-05-25 11:27:16 -04001404 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001405 return 0;
1406}
1407
1408static int wlan_set_mode(struct net_device *dev,
1409 struct iw_request_info *info, u32 * uwrq, char *extra)
1410{
1411 int ret = 0;
1412 wlan_private *priv = dev->priv;
1413 wlan_adapter *adapter = priv->adapter;
1414 struct assoc_request * assoc_req;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001415
Holger Schurig9012b282007-05-25 11:27:16 -04001416 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001417
Dan Williams0dc5a292007-05-10 22:58:02 -04001418 if ( (*uwrq != IW_MODE_ADHOC)
1419 && (*uwrq != IW_MODE_INFRA)
1420 && (*uwrq != IW_MODE_AUTO)) {
Holger Schurig9012b282007-05-25 11:27:16 -04001421 lbs_deb_wext("Invalid mode: 0x%x\n", *uwrq);
Dan Williams0dc5a292007-05-10 22:58:02 -04001422 ret = -EINVAL;
1423 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001424 }
1425
1426 mutex_lock(&adapter->lock);
1427 assoc_req = wlan_get_association_request(adapter);
1428 if (!assoc_req) {
1429 ret = -ENOMEM;
Dan Williams0dc5a292007-05-10 22:58:02 -04001430 wlan_cancel_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001431 } else {
Dan Williams0dc5a292007-05-10 22:58:02 -04001432 assoc_req->mode = *uwrq;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001433 set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
1434 wlan_postpone_association_work(priv);
Holger Schurig9012b282007-05-25 11:27:16 -04001435 lbs_deb_wext("Switching to mode: 0x%x\n", *uwrq);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001436 }
1437 mutex_unlock(&adapter->lock);
1438
Dan Williams0dc5a292007-05-10 22:58:02 -04001439out:
Holger Schurig9012b282007-05-25 11:27:16 -04001440 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001441 return ret;
1442}
1443
1444
1445/**
1446 * @brief Get Encryption key
1447 *
1448 * @param dev A pointer to net_device structure
1449 * @param info A pointer to iw_request_info structure
1450 * @param vwrq A pointer to iw_param structure
1451 * @param extra A pointer to extra data buf
1452 * @return 0 --success, otherwise fail
1453 */
1454static int wlan_get_encode(struct net_device *dev,
1455 struct iw_request_info *info,
1456 struct iw_point *dwrq, u8 * extra)
1457{
1458 wlan_private *priv = dev->priv;
1459 wlan_adapter *adapter = priv->adapter;
1460 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
1461
Holger Schurig9012b282007-05-25 11:27:16 -04001462 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001463
Holger Schurig9012b282007-05-25 11:27:16 -04001464 lbs_deb_wext("flags 0x%x, index %d, length %d, wep_tx_keyidx %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001465 dwrq->flags, index, dwrq->length, adapter->wep_tx_keyidx);
1466
1467 dwrq->flags = 0;
1468
1469 /* Authentication method */
Dan Williams6affe782007-05-10 22:56:42 -04001470 switch (adapter->secinfo.auth_mode) {
1471 case IW_AUTH_ALG_OPEN_SYSTEM:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001472 dwrq->flags = IW_ENCODE_OPEN;
1473 break;
1474
Dan Williams6affe782007-05-10 22:56:42 -04001475 case IW_AUTH_ALG_SHARED_KEY:
1476 case IW_AUTH_ALG_LEAP:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001477 dwrq->flags = IW_ENCODE_RESTRICTED;
1478 break;
1479 default:
1480 dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
1481 break;
1482 }
1483
Dan Williams889c05b2007-05-10 22:57:23 -04001484 if ( adapter->secinfo.wep_enabled
1485 || adapter->secinfo.WPAenabled
1486 || adapter->secinfo.WPA2enabled) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001487 dwrq->flags &= ~IW_ENCODE_DISABLED;
1488 } else {
1489 dwrq->flags |= IW_ENCODE_DISABLED;
1490 }
1491
1492 memset(extra, 0, 16);
1493
1494 mutex_lock(&adapter->lock);
1495
1496 /* Default to returning current transmit key */
1497 if (index < 0)
1498 index = adapter->wep_tx_keyidx;
1499
Dan Williams889c05b2007-05-10 22:57:23 -04001500 if ((adapter->wep_keys[index].len) && adapter->secinfo.wep_enabled) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001501 memcpy(extra, adapter->wep_keys[index].key,
1502 adapter->wep_keys[index].len);
1503 dwrq->length = adapter->wep_keys[index].len;
1504
1505 dwrq->flags |= (index + 1);
1506 /* Return WEP enabled */
1507 dwrq->flags &= ~IW_ENCODE_DISABLED;
1508 } else if ((adapter->secinfo.WPAenabled)
1509 || (adapter->secinfo.WPA2enabled)) {
1510 /* return WPA enabled */
1511 dwrq->flags &= ~IW_ENCODE_DISABLED;
1512 } else {
1513 dwrq->flags |= IW_ENCODE_DISABLED;
1514 }
1515
1516 mutex_unlock(&adapter->lock);
1517
1518 dwrq->flags |= IW_ENCODE_NOKEY;
1519
Holger Schurig9012b282007-05-25 11:27:16 -04001520 lbs_deb_wext("key: " MAC_FMT ", keylen %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001521 extra[0], extra[1], extra[2],
1522 extra[3], extra[4], extra[5], dwrq->length);
1523
Holger Schurig9012b282007-05-25 11:27:16 -04001524 lbs_deb_wext("return flags 0x%x\n", dwrq->flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001525
Holger Schurig9012b282007-05-25 11:27:16 -04001526 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001527 return 0;
1528}
1529
1530/**
1531 * @brief Set Encryption key (internal)
1532 *
1533 * @param priv A pointer to private card structure
1534 * @param key_material A pointer to key material
1535 * @param key_length length of key material
1536 * @param index key index to set
1537 * @param set_tx_key Force set TX key (1 = yes, 0 = no)
1538 * @return 0 --success, otherwise fail
1539 */
1540static int wlan_set_wep_key(struct assoc_request *assoc_req,
1541 const char *key_material,
1542 u16 key_length,
1543 u16 index,
1544 int set_tx_key)
1545{
Holger Schurig9012b282007-05-25 11:27:16 -04001546 int ret = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001547 struct WLAN_802_11_KEY *pkey;
1548
Holger Schurig9012b282007-05-25 11:27:16 -04001549 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001550
1551 /* Paranoid validation of key index */
1552 if (index > 3) {
Holger Schurig9012b282007-05-25 11:27:16 -04001553 ret = -EINVAL;
1554 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001555 }
1556
1557 /* validate max key length */
1558 if (key_length > KEY_LEN_WEP_104) {
Holger Schurig9012b282007-05-25 11:27:16 -04001559 ret = -EINVAL;
1560 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001561 }
1562
1563 pkey = &assoc_req->wep_keys[index];
1564
1565 if (key_length > 0) {
1566 memset(pkey, 0, sizeof(struct WLAN_802_11_KEY));
1567 pkey->type = KEY_TYPE_ID_WEP;
1568
1569 /* Standardize the key length */
1570 pkey->len = (key_length > KEY_LEN_WEP_40) ?
1571 KEY_LEN_WEP_104 : KEY_LEN_WEP_40;
1572 memcpy(pkey->key, key_material, key_length);
1573 }
1574
1575 if (set_tx_key) {
1576 /* Ensure the chosen key is valid */
1577 if (!pkey->len) {
Holger Schurig9012b282007-05-25 11:27:16 -04001578 lbs_deb_wext("key not set, so cannot enable it\n");
1579 ret = -EINVAL;
1580 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001581 }
1582 assoc_req->wep_tx_keyidx = index;
1583 }
1584
Dan Williams889c05b2007-05-10 22:57:23 -04001585 assoc_req->secinfo.wep_enabled = 1;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001586
Holger Schurig9012b282007-05-25 11:27:16 -04001587out:
1588 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1589 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001590}
1591
1592static int validate_key_index(u16 def_index, u16 raw_index,
1593 u16 *out_index, u16 *is_default)
1594{
1595 if (!out_index || !is_default)
1596 return -EINVAL;
1597
1598 /* Verify index if present, otherwise use default TX key index */
1599 if (raw_index > 0) {
1600 if (raw_index > 4)
1601 return -EINVAL;
1602 *out_index = raw_index - 1;
1603 } else {
1604 *out_index = def_index;
1605 *is_default = 1;
1606 }
1607 return 0;
1608}
1609
1610static void disable_wep(struct assoc_request *assoc_req)
1611{
1612 int i;
1613
1614 /* Set Open System auth mode */
Dan Williams6affe782007-05-10 22:56:42 -04001615 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001616
1617 /* Clear WEP keys and mark WEP as disabled */
Dan Williams889c05b2007-05-10 22:57:23 -04001618 assoc_req->secinfo.wep_enabled = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001619 for (i = 0; i < 4; i++)
1620 assoc_req->wep_keys[i].len = 0;
1621
1622 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1623 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1624}
1625
1626/**
1627 * @brief Set Encryption key
1628 *
1629 * @param dev A pointer to net_device structure
1630 * @param info A pointer to iw_request_info structure
1631 * @param vwrq A pointer to iw_param structure
1632 * @param extra A pointer to extra data buf
1633 * @return 0 --success, otherwise fail
1634 */
1635static int wlan_set_encode(struct net_device *dev,
1636 struct iw_request_info *info,
1637 struct iw_point *dwrq, char *extra)
1638{
1639 int ret = 0;
1640 wlan_private *priv = dev->priv;
1641 wlan_adapter *adapter = priv->adapter;
1642 struct assoc_request * assoc_req;
1643 u16 is_default = 0, index = 0, set_tx_key = 0;
1644
Holger Schurig9012b282007-05-25 11:27:16 -04001645 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001646
1647 mutex_lock(&adapter->lock);
1648 assoc_req = wlan_get_association_request(adapter);
1649 if (!assoc_req) {
1650 ret = -ENOMEM;
1651 goto out;
1652 }
1653
1654 if (dwrq->flags & IW_ENCODE_DISABLED) {
1655 disable_wep (assoc_req);
1656 goto out;
1657 }
1658
1659 ret = validate_key_index(assoc_req->wep_tx_keyidx,
1660 (dwrq->flags & IW_ENCODE_INDEX),
1661 &index, &is_default);
1662 if (ret) {
1663 ret = -EINVAL;
1664 goto out;
1665 }
1666
1667 /* If WEP isn't enabled, or if there is no key data but a valid
1668 * index, set the TX key.
1669 */
Dan Williams889c05b2007-05-10 22:57:23 -04001670 if (!assoc_req->secinfo.wep_enabled || (dwrq->length == 0 && !is_default))
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001671 set_tx_key = 1;
1672
1673 ret = wlan_set_wep_key(assoc_req, extra, dwrq->length, index, set_tx_key);
1674 if (ret)
1675 goto out;
1676
1677 if (dwrq->length)
1678 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1679 if (set_tx_key)
1680 set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
1681
1682 if (dwrq->flags & IW_ENCODE_RESTRICTED) {
Dan Williams6affe782007-05-10 22:56:42 -04001683 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001684 } else if (dwrq->flags & IW_ENCODE_OPEN) {
Dan Williams6affe782007-05-10 22:56:42 -04001685 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001686 }
1687
1688out:
1689 if (ret == 0) {
1690 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1691 wlan_postpone_association_work(priv);
1692 } else {
1693 wlan_cancel_association_work(priv);
1694 }
1695 mutex_unlock(&adapter->lock);
1696
Holger Schurig9012b282007-05-25 11:27:16 -04001697 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001698 return ret;
1699}
1700
1701/**
1702 * @brief Get Extended Encryption key (WPA/802.1x and WEP)
1703 *
1704 * @param dev A pointer to net_device structure
1705 * @param info A pointer to iw_request_info structure
1706 * @param vwrq A pointer to iw_param structure
1707 * @param extra A pointer to extra data buf
1708 * @return 0 on success, otherwise failure
1709 */
1710static int wlan_get_encodeext(struct net_device *dev,
1711 struct iw_request_info *info,
1712 struct iw_point *dwrq,
1713 char *extra)
1714{
1715 int ret = -EINVAL;
1716 wlan_private *priv = dev->priv;
1717 wlan_adapter *adapter = priv->adapter;
1718 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1719 int index, max_key_len;
1720
Holger Schurig9012b282007-05-25 11:27:16 -04001721 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001722
1723 max_key_len = dwrq->length - sizeof(*ext);
1724 if (max_key_len < 0)
1725 goto out;
1726
1727 index = dwrq->flags & IW_ENCODE_INDEX;
1728 if (index) {
1729 if (index < 1 || index > 4)
1730 goto out;
1731 index--;
1732 } else {
1733 index = adapter->wep_tx_keyidx;
1734 }
1735
1736 if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY &&
1737 ext->alg != IW_ENCODE_ALG_WEP) {
Dan Williams0dc5a292007-05-10 22:58:02 -04001738 if (index != 0 || adapter->mode != IW_MODE_INFRA)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001739 goto out;
1740 }
1741
1742 dwrq->flags = index + 1;
1743 memset(ext, 0, sizeof(*ext));
1744
Dan Williams889c05b2007-05-10 22:57:23 -04001745 if ( !adapter->secinfo.wep_enabled
1746 && !adapter->secinfo.WPAenabled
1747 && !adapter->secinfo.WPA2enabled) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001748 ext->alg = IW_ENCODE_ALG_NONE;
1749 ext->key_len = 0;
1750 dwrq->flags |= IW_ENCODE_DISABLED;
1751 } else {
1752 u8 *key = NULL;
1753
Dan Williams889c05b2007-05-10 22:57:23 -04001754 if ( adapter->secinfo.wep_enabled
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001755 && !adapter->secinfo.WPAenabled
1756 && !adapter->secinfo.WPA2enabled) {
1757 ext->alg = IW_ENCODE_ALG_WEP;
1758 ext->key_len = adapter->wep_keys[index].len;
1759 key = &adapter->wep_keys[index].key[0];
Dan Williams889c05b2007-05-10 22:57:23 -04001760 } else if ( !adapter->secinfo.wep_enabled
1761 && (adapter->secinfo.WPAenabled ||
1762 adapter->secinfo.WPA2enabled)) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001763 /* WPA */
1764 ext->alg = IW_ENCODE_ALG_TKIP;
1765 ext->key_len = 0;
1766 } else {
1767 goto out;
1768 }
1769
1770 if (ext->key_len > max_key_len) {
1771 ret = -E2BIG;
1772 goto out;
1773 }
1774
1775 if (ext->key_len)
1776 memcpy(ext->key, key, ext->key_len);
1777 else
1778 dwrq->flags |= IW_ENCODE_NOKEY;
1779 dwrq->flags |= IW_ENCODE_ENABLED;
1780 }
1781 ret = 0;
1782
1783out:
Holger Schurig9012b282007-05-25 11:27:16 -04001784 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001785 return ret;
1786}
1787
1788/**
1789 * @brief Set Encryption key Extended (WPA/802.1x and WEP)
1790 *
1791 * @param dev A pointer to net_device structure
1792 * @param info A pointer to iw_request_info structure
1793 * @param vwrq A pointer to iw_param structure
1794 * @param extra A pointer to extra data buf
1795 * @return 0 --success, otherwise fail
1796 */
1797static int wlan_set_encodeext(struct net_device *dev,
1798 struct iw_request_info *info,
1799 struct iw_point *dwrq,
1800 char *extra)
1801{
1802 int ret = 0;
1803 wlan_private *priv = dev->priv;
1804 wlan_adapter *adapter = priv->adapter;
1805 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1806 int alg = ext->alg;
1807 struct assoc_request * assoc_req;
1808
Holger Schurig9012b282007-05-25 11:27:16 -04001809 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001810
1811 mutex_lock(&adapter->lock);
1812 assoc_req = wlan_get_association_request(adapter);
1813 if (!assoc_req) {
1814 ret = -ENOMEM;
1815 goto out;
1816 }
1817
1818 if ((alg == IW_ENCODE_ALG_NONE) || (dwrq->flags & IW_ENCODE_DISABLED)) {
1819 disable_wep (assoc_req);
1820 } else if (alg == IW_ENCODE_ALG_WEP) {
1821 u16 is_default = 0, index, set_tx_key = 0;
1822
1823 ret = validate_key_index(assoc_req->wep_tx_keyidx,
1824 (dwrq->flags & IW_ENCODE_INDEX),
1825 &index, &is_default);
1826 if (ret)
1827 goto out;
1828
1829 /* If WEP isn't enabled, or if there is no key data but a valid
1830 * index, or if the set-TX-key flag was passed, set the TX key.
1831 */
Dan Williams889c05b2007-05-10 22:57:23 -04001832 if ( !assoc_req->secinfo.wep_enabled
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001833 || (dwrq->length == 0 && !is_default)
1834 || (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY))
1835 set_tx_key = 1;
1836
1837 /* Copy key to driver */
1838 ret = wlan_set_wep_key (assoc_req, ext->key, ext->key_len, index,
1839 set_tx_key);
1840 if (ret)
1841 goto out;
1842
1843 if (dwrq->flags & IW_ENCODE_RESTRICTED) {
Dan Williams6affe782007-05-10 22:56:42 -04001844 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001845 } else if (dwrq->flags & IW_ENCODE_OPEN) {
Dan Williams6affe782007-05-10 22:56:42 -04001846 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001847 }
1848
1849 /* Mark the various WEP bits as modified */
1850 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1851 if (dwrq->length)
1852 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1853 if (set_tx_key)
1854 set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
1855
1856 } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) {
1857 struct WLAN_802_11_KEY * pkey;
1858
1859 /* validate key length */
1860 if (((alg == IW_ENCODE_ALG_TKIP)
1861 && (ext->key_len != KEY_LEN_WPA_TKIP))
1862 || ((alg == IW_ENCODE_ALG_CCMP)
1863 && (ext->key_len != KEY_LEN_WPA_AES))) {
Holger Schurig9012b282007-05-25 11:27:16 -04001864 lbs_deb_wext("invalid size %d for key of alg"
1865 "type %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001866 ext->key_len,
1867 alg);
1868 ret = -EINVAL;
1869 goto out;
1870 }
1871
1872 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
1873 pkey = &assoc_req->wpa_mcast_key;
1874 else
1875 pkey = &assoc_req->wpa_unicast_key;
1876
1877 memset(pkey, 0, sizeof (struct WLAN_802_11_KEY));
1878 memcpy(pkey->key, ext->key, ext->key_len);
1879 pkey->len = ext->key_len;
1880 pkey->flags = KEY_INFO_WPA_ENABLED;
1881
1882 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
1883 pkey->flags |= KEY_INFO_WPA_MCAST;
1884 set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
1885 } else {
1886 pkey->flags |= KEY_INFO_WPA_UNICAST;
1887 set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
1888 }
1889
1890 if (alg == IW_ENCODE_ALG_TKIP)
1891 pkey->type = KEY_TYPE_ID_TKIP;
1892 else if (alg == IW_ENCODE_ALG_CCMP)
1893 pkey->type = KEY_TYPE_ID_AES;
1894
1895 /* If WPA isn't enabled yet, do that now */
1896 if ( assoc_req->secinfo.WPAenabled == 0
1897 && assoc_req->secinfo.WPA2enabled == 0) {
1898 assoc_req->secinfo.WPAenabled = 1;
1899 assoc_req->secinfo.WPA2enabled = 1;
1900 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1901 }
1902
1903 disable_wep (assoc_req);
1904 }
1905
1906out:
1907 if (ret == 0) {
1908 wlan_postpone_association_work(priv);
1909 } else {
1910 wlan_cancel_association_work(priv);
1911 }
1912 mutex_unlock(&adapter->lock);
1913
Holger Schurig9012b282007-05-25 11:27:16 -04001914 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001915 return ret;
1916}
1917
1918
1919static int wlan_set_genie(struct net_device *dev,
1920 struct iw_request_info *info,
1921 struct iw_point *dwrq,
1922 char *extra)
1923{
1924 wlan_private *priv = dev->priv;
1925 wlan_adapter *adapter = priv->adapter;
1926 int ret = 0;
1927 struct assoc_request * assoc_req;
1928
Holger Schurig9012b282007-05-25 11:27:16 -04001929 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001930
1931 mutex_lock(&adapter->lock);
1932 assoc_req = wlan_get_association_request(adapter);
1933 if (!assoc_req) {
1934 ret = -ENOMEM;
1935 goto out;
1936 }
1937
1938 if (dwrq->length > MAX_WPA_IE_LEN ||
1939 (dwrq->length && extra == NULL)) {
1940 ret = -EINVAL;
1941 goto out;
1942 }
1943
1944 if (dwrq->length) {
1945 memcpy(&assoc_req->wpa_ie[0], extra, dwrq->length);
1946 assoc_req->wpa_ie_len = dwrq->length;
1947 } else {
1948 memset(&assoc_req->wpa_ie[0], 0, sizeof(adapter->wpa_ie));
1949 assoc_req->wpa_ie_len = 0;
1950 }
1951
1952out:
1953 if (ret == 0) {
1954 set_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags);
1955 wlan_postpone_association_work(priv);
1956 } else {
1957 wlan_cancel_association_work(priv);
1958 }
1959 mutex_unlock(&adapter->lock);
1960
Holger Schurig9012b282007-05-25 11:27:16 -04001961 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001962 return ret;
1963}
1964
1965static int wlan_get_genie(struct net_device *dev,
1966 struct iw_request_info *info,
1967 struct iw_point *dwrq,
1968 char *extra)
1969{
Holger Schurig9012b282007-05-25 11:27:16 -04001970 int ret = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001971 wlan_private *priv = dev->priv;
1972 wlan_adapter *adapter = priv->adapter;
1973
Holger Schurig9012b282007-05-25 11:27:16 -04001974 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001975
1976 if (adapter->wpa_ie_len == 0) {
1977 dwrq->length = 0;
Holger Schurig9012b282007-05-25 11:27:16 -04001978 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001979 }
1980
1981 if (dwrq->length < adapter->wpa_ie_len) {
Holger Schurig9012b282007-05-25 11:27:16 -04001982 ret = -E2BIG;
1983 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001984 }
1985
1986 dwrq->length = adapter->wpa_ie_len;
1987 memcpy(extra, &adapter->wpa_ie[0], adapter->wpa_ie_len);
1988
Holger Schurig9012b282007-05-25 11:27:16 -04001989out:
1990 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1991 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001992}
1993
1994
1995static int wlan_set_auth(struct net_device *dev,
1996 struct iw_request_info *info,
1997 struct iw_param *dwrq,
1998 char *extra)
1999{
2000 wlan_private *priv = dev->priv;
2001 wlan_adapter *adapter = priv->adapter;
2002 struct assoc_request * assoc_req;
2003 int ret = 0;
2004 int updated = 0;
2005
Holger Schurig9012b282007-05-25 11:27:16 -04002006 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002007
2008 mutex_lock(&adapter->lock);
2009 assoc_req = wlan_get_association_request(adapter);
2010 if (!assoc_req) {
2011 ret = -ENOMEM;
2012 goto out;
2013 }
2014
2015 switch (dwrq->flags & IW_AUTH_INDEX) {
2016 case IW_AUTH_TKIP_COUNTERMEASURES:
2017 case IW_AUTH_CIPHER_PAIRWISE:
2018 case IW_AUTH_CIPHER_GROUP:
2019 case IW_AUTH_KEY_MGMT:
2020 /*
2021 * libertas does not use these parameters
2022 */
2023 break;
2024
2025 case IW_AUTH_WPA_VERSION:
2026 if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) {
2027 assoc_req->secinfo.WPAenabled = 0;
2028 assoc_req->secinfo.WPA2enabled = 0;
2029 }
2030 if (dwrq->value & IW_AUTH_WPA_VERSION_WPA) {
2031 assoc_req->secinfo.WPAenabled = 1;
Dan Williams889c05b2007-05-10 22:57:23 -04002032 assoc_req->secinfo.wep_enabled = 0;
Dan Williams6affe782007-05-10 22:56:42 -04002033 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002034 }
2035 if (dwrq->value & IW_AUTH_WPA_VERSION_WPA2) {
2036 assoc_req->secinfo.WPA2enabled = 1;
Dan Williams889c05b2007-05-10 22:57:23 -04002037 assoc_req->secinfo.wep_enabled = 0;
Dan Williams6affe782007-05-10 22:56:42 -04002038 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002039 }
2040 updated = 1;
2041 break;
2042
2043 case IW_AUTH_DROP_UNENCRYPTED:
2044 if (dwrq->value) {
2045 adapter->currentpacketfilter |=
2046 cmd_act_mac_strict_protection_enable;
2047 } else {
2048 adapter->currentpacketfilter &=
2049 ~cmd_act_mac_strict_protection_enable;
2050 }
2051 updated = 1;
2052 break;
2053
2054 case IW_AUTH_80211_AUTH_ALG:
2055 if (dwrq->value & IW_AUTH_ALG_SHARED_KEY) {
Dan Williams6affe782007-05-10 22:56:42 -04002056 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002057 } else if (dwrq->value & IW_AUTH_ALG_OPEN_SYSTEM) {
Dan Williams6affe782007-05-10 22:56:42 -04002058 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002059 } else if (dwrq->value & IW_AUTH_ALG_LEAP) {
Dan Williams6affe782007-05-10 22:56:42 -04002060 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_LEAP;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002061 } else {
2062 ret = -EINVAL;
2063 }
2064 updated = 1;
2065 break;
2066
2067 case IW_AUTH_WPA_ENABLED:
2068 if (dwrq->value) {
2069 if (!assoc_req->secinfo.WPAenabled &&
2070 !assoc_req->secinfo.WPA2enabled) {
2071 assoc_req->secinfo.WPAenabled = 1;
2072 assoc_req->secinfo.WPA2enabled = 1;
Dan Williams889c05b2007-05-10 22:57:23 -04002073 assoc_req->secinfo.wep_enabled = 0;
Dan Williams6affe782007-05-10 22:56:42 -04002074 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002075 }
2076 } else {
2077 assoc_req->secinfo.WPAenabled = 0;
2078 assoc_req->secinfo.WPA2enabled = 0;
2079 }
2080 updated = 1;
2081 break;
2082
2083 default:
2084 ret = -EOPNOTSUPP;
2085 break;
2086 }
2087
2088out:
2089 if (ret == 0) {
2090 if (updated)
2091 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
2092 wlan_postpone_association_work(priv);
2093 } else if (ret != -EOPNOTSUPP) {
2094 wlan_cancel_association_work(priv);
2095 }
2096 mutex_unlock(&adapter->lock);
2097
Holger Schurig9012b282007-05-25 11:27:16 -04002098 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002099 return ret;
2100}
2101
2102static int wlan_get_auth(struct net_device *dev,
2103 struct iw_request_info *info,
2104 struct iw_param *dwrq,
2105 char *extra)
2106{
Holger Schurig9012b282007-05-25 11:27:16 -04002107 int ret = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002108 wlan_private *priv = dev->priv;
2109 wlan_adapter *adapter = priv->adapter;
2110
Holger Schurig9012b282007-05-25 11:27:16 -04002111 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002112
2113 switch (dwrq->flags & IW_AUTH_INDEX) {
2114 case IW_AUTH_WPA_VERSION:
2115 dwrq->value = 0;
2116 if (adapter->secinfo.WPAenabled)
2117 dwrq->value |= IW_AUTH_WPA_VERSION_WPA;
2118 if (adapter->secinfo.WPA2enabled)
2119 dwrq->value |= IW_AUTH_WPA_VERSION_WPA2;
2120 if (!dwrq->value)
2121 dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED;
2122 break;
2123
2124 case IW_AUTH_DROP_UNENCRYPTED:
2125 dwrq->value = 0;
2126 if (adapter->currentpacketfilter &
2127 cmd_act_mac_strict_protection_enable)
2128 dwrq->value = 1;
2129 break;
2130
2131 case IW_AUTH_80211_AUTH_ALG:
Dan Williams6affe782007-05-10 22:56:42 -04002132 dwrq->value = adapter->secinfo.auth_mode;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002133 break;
2134
2135 case IW_AUTH_WPA_ENABLED:
2136 if (adapter->secinfo.WPAenabled && adapter->secinfo.WPA2enabled)
2137 dwrq->value = 1;
2138 break;
2139
2140 default:
Holger Schurig9012b282007-05-25 11:27:16 -04002141 ret = -EOPNOTSUPP;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002142 }
2143
Holger Schurig9012b282007-05-25 11:27:16 -04002144 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
2145 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002146}
2147
2148
2149static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info,
2150 struct iw_param *vwrq, char *extra)
2151{
2152 int ret = 0;
2153 wlan_private *priv = dev->priv;
2154 wlan_adapter *adapter = priv->adapter;
2155
2156 u16 dbm;
2157
Holger Schurig9012b282007-05-25 11:27:16 -04002158 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002159
2160 if (vwrq->disabled) {
2161 wlan_radio_ioctl(priv, RADIO_OFF);
2162 return 0;
2163 }
2164
2165 adapter->preamble = cmd_type_auto_preamble;
2166
2167 wlan_radio_ioctl(priv, RADIO_ON);
2168
2169 if ((vwrq->flags & IW_TXPOW_TYPE) == IW_TXPOW_MWATT) {
2170 dbm = (u16) mw_to_dbm(vwrq->value);
2171 } else
2172 dbm = (u16) vwrq->value;
2173
2174 /* auto tx power control */
2175
2176 if (vwrq->fixed == 0)
2177 dbm = 0xffff;
2178
Holger Schurig9012b282007-05-25 11:27:16 -04002179 lbs_deb_wext("txpower set %d dbm\n", dbm);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002180
2181 ret = libertas_prepare_and_send_command(priv,
2182 cmd_802_11_rf_tx_power,
2183 cmd_act_tx_power_opt_set_low,
2184 cmd_option_waitforrsp, 0, (void *)&dbm);
2185
Holger Schurig9012b282007-05-25 11:27:16 -04002186 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002187 return ret;
2188}
2189
2190static int wlan_get_essid(struct net_device *dev, struct iw_request_info *info,
2191 struct iw_point *dwrq, char *extra)
2192{
2193 wlan_private *priv = dev->priv;
2194 wlan_adapter *adapter = priv->adapter;
2195
Holger Schurig9012b282007-05-25 11:27:16 -04002196 lbs_deb_enter(LBS_DEB_WEXT);
2197
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002198 /*
2199 * Note : if dwrq->flags != 0, we should get the relevant SSID from
2200 * the SSID list...
2201 */
2202
2203 /*
2204 * Get the current SSID
2205 */
2206 if (adapter->connect_status == libertas_connected) {
2207 memcpy(extra, adapter->curbssparams.ssid.ssid,
2208 adapter->curbssparams.ssid.ssidlength);
2209 extra[adapter->curbssparams.ssid.ssidlength] = '\0';
2210 } else {
2211 memset(extra, 0, 32);
2212 extra[adapter->curbssparams.ssid.ssidlength] = '\0';
2213 }
2214 /*
2215 * If none, we may want to get the one that was set
2216 */
2217
2218 /* To make the driver backward compatible with WPA supplicant v0.2.4 */
2219 if (dwrq->length == 32) /* check with WPA supplicant buffer size */
2220 dwrq->length = min_t(size_t, adapter->curbssparams.ssid.ssidlength,
2221 IW_ESSID_MAX_SIZE);
2222 else
2223 dwrq->length = adapter->curbssparams.ssid.ssidlength + 1;
2224
2225 dwrq->flags = 1; /* active */
2226
Holger Schurig9012b282007-05-25 11:27:16 -04002227 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002228 return 0;
2229}
2230
2231static int wlan_set_essid(struct net_device *dev, struct iw_request_info *info,
2232 struct iw_point *dwrq, char *extra)
2233{
2234 wlan_private *priv = dev->priv;
2235 wlan_adapter *adapter = priv->adapter;
2236 int ret = 0;
2237 struct WLAN_802_11_SSID ssid;
2238 struct assoc_request * assoc_req;
2239 int ssid_len = dwrq->length;
2240
Holger Schurig9012b282007-05-25 11:27:16 -04002241 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002242
2243 /*
2244 * WE-20 and earlier NULL pad the end of the SSID and increment
2245 * SSID length so it can be used like a string. WE-21 and later don't,
2246 * but some userspace tools aren't able to cope with the change.
2247 */
2248 if ((ssid_len > 0) && (extra[ssid_len - 1] == '\0'))
2249 ssid_len--;
2250
2251 /* Check the size of the string */
2252 if (ssid_len > IW_ESSID_MAX_SIZE) {
2253 ret = -E2BIG;
2254 goto out;
2255 }
2256
2257 memset(&ssid, 0, sizeof(struct WLAN_802_11_SSID));
2258
2259 if (!dwrq->flags || !ssid_len) {
2260 /* "any" SSID requested; leave SSID blank */
2261 } else {
2262 /* Specific SSID requested */
2263 memcpy(&ssid.ssid, extra, ssid_len);
2264 ssid.ssidlength = ssid_len;
2265 }
2266
Holger Schurig9012b282007-05-25 11:27:16 -04002267 lbs_deb_wext("requested new SSID '%s'\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002268 (ssid.ssidlength > 0) ? (char *)ssid.ssid : "any");
2269
2270out:
2271 mutex_lock(&adapter->lock);
2272 if (ret == 0) {
2273 /* Get or create the current association request */
2274 assoc_req = wlan_get_association_request(adapter);
2275 if (!assoc_req) {
2276 ret = -ENOMEM;
2277 } else {
2278 /* Copy the SSID to the association request */
2279 memcpy(&assoc_req->ssid, &ssid, sizeof(struct WLAN_802_11_SSID));
2280 set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
2281 wlan_postpone_association_work(priv);
2282 }
2283 }
2284
2285 /* Cancel the association request if there was an error */
2286 if (ret != 0) {
2287 wlan_cancel_association_work(priv);
2288 }
2289
2290 mutex_unlock(&adapter->lock);
2291
Holger Schurig9012b282007-05-25 11:27:16 -04002292 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002293 return ret;
2294}
2295
2296/**
2297 * @brief Connect to the AP or Ad-hoc Network with specific bssid
2298 *
2299 * @param dev A pointer to net_device structure
2300 * @param info A pointer to iw_request_info structure
2301 * @param awrq A pointer to iw_param structure
2302 * @param extra A pointer to extra data buf
2303 * @return 0 --success, otherwise fail
2304 */
2305static int wlan_set_wap(struct net_device *dev, struct iw_request_info *info,
2306 struct sockaddr *awrq, char *extra)
2307{
2308 wlan_private *priv = dev->priv;
2309 wlan_adapter *adapter = priv->adapter;
2310 struct assoc_request * assoc_req;
2311 int ret = 0;
2312
Holger Schurig9012b282007-05-25 11:27:16 -04002313 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002314
2315 if (awrq->sa_family != ARPHRD_ETHER)
2316 return -EINVAL;
2317
Holger Schurig9012b282007-05-25 11:27:16 -04002318 lbs_deb_wext("ASSOC: WAP: sa_data " MAC_FMT "\n", MAC_ARG(awrq->sa_data));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002319
2320 mutex_lock(&adapter->lock);
2321
2322 /* Get or create the current association request */
2323 assoc_req = wlan_get_association_request(adapter);
2324 if (!assoc_req) {
2325 wlan_cancel_association_work(priv);
2326 ret = -ENOMEM;
2327 } else {
2328 /* Copy the BSSID to the association request */
2329 memcpy(&assoc_req->bssid, awrq->sa_data, ETH_ALEN);
2330 set_bit(ASSOC_FLAG_BSSID, &assoc_req->flags);
2331 wlan_postpone_association_work(priv);
2332 }
2333
2334 mutex_unlock(&adapter->lock);
2335
2336 return ret;
2337}
2338
2339void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen)
2340{
2341 union {
2342 u32 l;
2343 u8 c[4];
2344 } ver;
2345 char fwver[32];
2346
2347 mutex_lock(&adapter->lock);
2348 ver.l = adapter->fwreleasenumber;
2349 mutex_unlock(&adapter->lock);
2350
2351 if (ver.c[3] == 0)
2352 sprintf(fwver, "%u.%u.%u", ver.c[2], ver.c[1], ver.c[0]);
2353 else
2354 sprintf(fwver, "%u.%u.%u.p%u",
2355 ver.c[2], ver.c[1], ver.c[0], ver.c[3]);
2356
2357 snprintf(fwversion, maxlen, fwver);
2358}
2359
2360
2361/*
2362 * iwconfig settable callbacks
2363 */
2364static const iw_handler wlan_handler[] = {
2365 (iw_handler) NULL, /* SIOCSIWCOMMIT */
2366 (iw_handler) wlan_get_name, /* SIOCGIWNAME */
2367 (iw_handler) NULL, /* SIOCSIWNWID */
2368 (iw_handler) NULL, /* SIOCGIWNWID */
2369 (iw_handler) wlan_set_freq, /* SIOCSIWFREQ */
2370 (iw_handler) wlan_get_freq, /* SIOCGIWFREQ */
2371 (iw_handler) wlan_set_mode, /* SIOCSIWMODE */
2372 (iw_handler) wlan_get_mode, /* SIOCGIWMODE */
2373 (iw_handler) NULL, /* SIOCSIWSENS */
2374 (iw_handler) NULL, /* SIOCGIWSENS */
2375 (iw_handler) NULL, /* SIOCSIWRANGE */
2376 (iw_handler) wlan_get_range, /* SIOCGIWRANGE */
2377 (iw_handler) NULL, /* SIOCSIWPRIV */
2378 (iw_handler) NULL, /* SIOCGIWPRIV */
2379 (iw_handler) NULL, /* SIOCSIWSTATS */
2380 (iw_handler) NULL, /* SIOCGIWSTATS */
2381 iw_handler_set_spy, /* SIOCSIWSPY */
2382 iw_handler_get_spy, /* SIOCGIWSPY */
2383 iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
2384 iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
2385 (iw_handler) wlan_set_wap, /* SIOCSIWAP */
2386 (iw_handler) wlan_get_wap, /* SIOCGIWAP */
2387 (iw_handler) NULL, /* SIOCSIWMLME */
2388 (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */
2389 (iw_handler) libertas_set_scan, /* SIOCSIWSCAN */
2390 (iw_handler) libertas_get_scan, /* SIOCGIWSCAN */
2391 (iw_handler) wlan_set_essid, /* SIOCSIWESSID */
2392 (iw_handler) wlan_get_essid, /* SIOCGIWESSID */
2393 (iw_handler) wlan_set_nick, /* SIOCSIWNICKN */
2394 (iw_handler) wlan_get_nick, /* SIOCGIWNICKN */
2395 (iw_handler) NULL, /* -- hole -- */
2396 (iw_handler) NULL, /* -- hole -- */
2397 (iw_handler) wlan_set_rate, /* SIOCSIWRATE */
2398 (iw_handler) wlan_get_rate, /* SIOCGIWRATE */
2399 (iw_handler) wlan_set_rts, /* SIOCSIWRTS */
2400 (iw_handler) wlan_get_rts, /* SIOCGIWRTS */
2401 (iw_handler) wlan_set_frag, /* SIOCSIWFRAG */
2402 (iw_handler) wlan_get_frag, /* SIOCGIWFRAG */
2403 (iw_handler) wlan_set_txpow, /* SIOCSIWTXPOW */
2404 (iw_handler) wlan_get_txpow, /* SIOCGIWTXPOW */
2405 (iw_handler) wlan_set_retry, /* SIOCSIWRETRY */
2406 (iw_handler) wlan_get_retry, /* SIOCGIWRETRY */
2407 (iw_handler) wlan_set_encode, /* SIOCSIWENCODE */
2408 (iw_handler) wlan_get_encode, /* SIOCGIWENCODE */
2409 (iw_handler) wlan_set_power, /* SIOCSIWPOWER */
2410 (iw_handler) wlan_get_power, /* SIOCGIWPOWER */
2411 (iw_handler) NULL, /* -- hole -- */
2412 (iw_handler) NULL, /* -- hole -- */
2413 (iw_handler) wlan_set_genie, /* SIOCSIWGENIE */
2414 (iw_handler) wlan_get_genie, /* SIOCGIWGENIE */
2415 (iw_handler) wlan_set_auth, /* SIOCSIWAUTH */
2416 (iw_handler) wlan_get_auth, /* SIOCGIWAUTH */
2417 (iw_handler) wlan_set_encodeext,/* SIOCSIWENCODEEXT */
2418 (iw_handler) wlan_get_encodeext,/* SIOCGIWENCODEEXT */
2419 (iw_handler) NULL, /* SIOCSIWPMKSA */
2420};
2421
2422struct iw_handler_def libertas_handler_def = {
2423 .num_standard = sizeof(wlan_handler) / sizeof(iw_handler),
2424 .num_private = sizeof(wlan_private_handler) / sizeof(iw_handler),
2425 .num_private_args = sizeof(wlan_private_args) /
2426 sizeof(struct iw_priv_args),
2427 .standard = (iw_handler *) wlan_handler,
2428 .private = (iw_handler *) wlan_private_handler,
2429 .private_args = (struct iw_priv_args *)wlan_private_args,
2430 .get_wireless_stats = wlan_get_wireless_stats,
2431};