aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/libertas
diff options
context:
space:
mode:
authorKiran Divekar <dkiran@marvell.com>2010-06-14 12:31:26 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-06-23 15:13:11 -0400
commite86dc1ca4676445d9f0dfe35104efe0eb8a2f566 (patch)
treebd39d0d4403899fb438a2e983e1b97c1ccd9b1ad /drivers/net/wireless/libertas
parentf90754c15f47063671aea55268a9dd6a37b51492 (diff)
Libertas: cfg80211 support
Holger Schurig's patch (https://patchwork.kernel.org/patch/64286/) is rebased to latest wireless-testing tree. (Includes patches from me originally posted as "libertas: fix build error due to undefined symbol" and "libertas: unmangle capability value". -- JWL) Signed-off-by: Amitkumar Karwar <akarwar@marvell.com> Signed-off-by: Kiran Divekar <dkiran@marvell.com> Tested-by: Amitkumar Karwar <akarwar@marvell.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/libertas')
-rw-r--r--drivers/net/wireless/libertas/Makefile3
-rw-r--r--drivers/net/wireless/libertas/assoc.c2264
-rw-r--r--drivers/net/wireless/libertas/assoc.h155
-rw-r--r--drivers/net/wireless/libertas/cfg.c1941
-rw-r--r--drivers/net/wireless/libertas/cfg.h16
-rw-r--r--drivers/net/wireless/libertas/cmd.c22
-rw-r--r--drivers/net/wireless/libertas/cmdresp.c29
-rw-r--r--drivers/net/wireless/libertas/debugfs.c54
-rw-r--r--drivers/net/wireless/libertas/decl.h3
-rw-r--r--drivers/net/wireless/libertas/dev.h59
-rw-r--r--drivers/net/wireless/libertas/ethtool.c5
-rw-r--r--drivers/net/wireless/libertas/main.c221
-rw-r--r--drivers/net/wireless/libertas/mesh.c6
-rw-r--r--drivers/net/wireless/libertas/mesh.h5
-rw-r--r--drivers/net/wireless/libertas/rx.c121
-rw-r--r--drivers/net/wireless/libertas/scan.c1354
-rw-r--r--drivers/net/wireless/libertas/scan.h63
-rw-r--r--drivers/net/wireless/libertas/tx.c12
-rw-r--r--drivers/net/wireless/libertas/wext.c2353
-rw-r--r--drivers/net/wireless/libertas/wext.h17
20 files changed, 1981 insertions, 6722 deletions
diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile
index 45e870e33117..f7d01bfa2e4a 100644
--- a/drivers/net/wireless/libertas/Makefile
+++ b/drivers/net/wireless/libertas/Makefile
@@ -1,4 +1,3 @@
1libertas-y += assoc.o
2libertas-y += cfg.o 1libertas-y += cfg.o
3libertas-y += cmd.o 2libertas-y += cmd.o
4libertas-y += cmdresp.o 3libertas-y += cmdresp.o
@@ -6,9 +5,7 @@ libertas-y += debugfs.o
6libertas-y += ethtool.o 5libertas-y += ethtool.o
7libertas-y += main.o 6libertas-y += main.o
8libertas-y += rx.o 7libertas-y += rx.o
9libertas-y += scan.o
10libertas-y += tx.o 8libertas-y += tx.o
11libertas-y += wext.o
12libertas-$(CONFIG_LIBERTAS_MESH) += mesh.o 9libertas-$(CONFIG_LIBERTAS_MESH) += mesh.o
13 10
14usb8xxx-objs += if_usb.o 11usb8xxx-objs += if_usb.o
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
deleted file mode 100644
index aa06070e5eab..000000000000
--- a/drivers/net/wireless/libertas/assoc.c
+++ /dev/null
@@ -1,2264 +0,0 @@
1/* Copyright (C) 2006, Red Hat, Inc. */
2
3#include <linux/types.h>
4#include <linux/etherdevice.h>
5#include <linux/ieee80211.h>
6#include <linux/if_arp.h>
7#include <linux/slab.h>
8#include <net/lib80211.h>
9
10#include "assoc.h"
11#include "decl.h"
12#include "host.h"
13#include "scan.h"
14#include "cmd.h"
15
16static const u8 bssid_any[ETH_ALEN] __attribute__ ((aligned (2))) =
17 { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
18static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) =
19 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
20
21/* The firmware needs the following bits masked out of the beacon-derived
22 * capability field when associating/joining to a BSS:
23 * 9 (QoS), 11 (APSD), 12 (unused), 14 (unused), 15 (unused)
24 */
25#define CAPINFO_MASK (~(0xda00))
26
27/**
28 * 802.11b/g supported bitrates (in 500Kb/s units)
29 */
30u8 lbs_bg_rates[MAX_RATES] =
31 { 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
320x00, 0x00 };
33
34
35static int assoc_helper_wep_keys(struct lbs_private *priv,
36 struct assoc_request *assoc_req);
37
38/**
39 * @brief This function finds common rates between rates and card rates.
40 *
41 * It will fill common rates in rates as output if found.
42 *
43 * NOTE: Setting the MSB of the basic rates need to be taken
44 * care, either before or after calling this function
45 *
46 * @param priv A pointer to struct lbs_private structure
47 * @param rates the buffer which keeps input and output
48 * @param rates_size the size of rates buffer; new size of buffer on return,
49 * which will be less than or equal to original rates_size
50 *
51 * @return 0 on success, or -1 on error
52 */
53static int get_common_rates(struct lbs_private *priv,
54 u8 *rates,
55 u16 *rates_size)
56{
57 int i, j;
58 u8 intersection[MAX_RATES];
59 u16 intersection_size;
60 u16 num_rates = 0;
61
62 intersection_size = min_t(u16, *rates_size, ARRAY_SIZE(intersection));
63
64 /* Allow each rate from 'rates' that is supported by the hardware */
65 for (i = 0; i < ARRAY_SIZE(lbs_bg_rates) && lbs_bg_rates[i]; i++) {
66 for (j = 0; j < intersection_size && rates[j]; j++) {
67 if (rates[j] == lbs_bg_rates[i])
68 intersection[num_rates++] = rates[j];
69 }
70 }
71
72 lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size);
73 lbs_deb_hex(LBS_DEB_JOIN, "card rates ", lbs_bg_rates,
74 ARRAY_SIZE(lbs_bg_rates));
75 lbs_deb_hex(LBS_DEB_JOIN, "common rates", intersection, num_rates);
76 lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate);
77
78 if (!priv->enablehwauto) {
79 for (i = 0; i < num_rates; i++) {
80 if (intersection[i] == priv->cur_rate)
81 goto done;
82 }
83 lbs_pr_alert("Previously set fixed data rate %#x isn't "
84 "compatible with the network.\n", priv->cur_rate);
85 return -1;
86 }
87
88done:
89 memset(rates, 0, *rates_size);
90 *rates_size = num_rates;
91 memcpy(rates, intersection, num_rates);
92 return 0;
93}
94
95
96/**
97 * @brief Sets the MSB on basic rates as the firmware requires
98 *
99 * Scan through an array and set the MSB for basic data rates.
100 *
101 * @param rates buffer of data rates
102 * @param len size of buffer
103 */
104static void lbs_set_basic_rate_flags(u8 *rates, size_t len)
105{
106 int i;
107
108 for (i = 0; i < len; i++) {
109 if (rates[i] == 0x02 || rates[i] == 0x04 ||
110 rates[i] == 0x0b || rates[i] == 0x16)
111 rates[i] |= 0x80;
112 }
113}
114
115
116static u8 iw_auth_to_ieee_auth(u8 auth)
117{
118 if (auth == IW_AUTH_ALG_OPEN_SYSTEM)
119 return 0x00;
120 else if (auth == IW_AUTH_ALG_SHARED_KEY)
121 return 0x01;
122 else if (auth == IW_AUTH_ALG_LEAP)
123 return 0x80;
124
125 lbs_deb_join("%s: invalid auth alg 0x%X\n", __func__, auth);
126 return 0;
127}
128
129/**
130 * @brief This function prepares the authenticate command. AUTHENTICATE only
131 * sets the authentication suite for future associations, as the firmware
132 * handles authentication internally during the ASSOCIATE command.
133 *
134 * @param priv A pointer to struct lbs_private structure
135 * @param bssid The peer BSSID with which to authenticate
136 * @param auth The authentication mode to use (from wireless.h)
137 *
138 * @return 0 or -1
139 */
140static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth)
141{
142 struct cmd_ds_802_11_authenticate cmd;
143 int ret = -1;
144
145 lbs_deb_enter(LBS_DEB_JOIN);
146
147 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
148 memcpy(cmd.bssid, bssid, ETH_ALEN);
149
150 cmd.authtype = iw_auth_to_ieee_auth(auth);
151
152 lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n", bssid, cmd.authtype);
153
154 ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd);
155
156 lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
157 return ret;
158}
159
160
161int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
162 struct assoc_request *assoc)
163{
164 struct cmd_ds_802_11_set_wep cmd;
165 int ret = 0;
166
167 lbs_deb_enter(LBS_DEB_CMD);
168
169 memset(&cmd, 0, sizeof(cmd));
170 cmd.hdr.command = cpu_to_le16(CMD_802_11_SET_WEP);
171 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
172
173 cmd.action = cpu_to_le16(cmd_action);
174
175 if (cmd_action == CMD_ACT_ADD) {
176 int i;
177
178 /* default tx key index */
179 cmd.keyindex = cpu_to_le16(assoc->wep_tx_keyidx &
180 CMD_WEP_KEY_INDEX_MASK);
181
182 /* Copy key types and material to host command structure */
183 for (i = 0; i < 4; i++) {
184 struct enc_key *pkey = &assoc->wep_keys[i];
185
186 switch (pkey->len) {
187 case KEY_LEN_WEP_40:
188 cmd.keytype[i] = CMD_TYPE_WEP_40_BIT;
189 memmove(cmd.keymaterial[i], pkey->key, pkey->len);
190 lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i);
191 break;
192 case KEY_LEN_WEP_104:
193 cmd.keytype[i] = CMD_TYPE_WEP_104_BIT;
194 memmove(cmd.keymaterial[i], pkey->key, pkey->len);
195 lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i);
196 break;
197 case 0:
198 break;
199 default:
200 lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n",
201 i, pkey->len);
202 ret = -1;
203 goto done;
204 break;
205 }
206 }
207 } else if (cmd_action == CMD_ACT_REMOVE) {
208 /* ACT_REMOVE clears _all_ WEP keys */
209
210 /* default tx key index */
211 cmd.keyindex = cpu_to_le16(priv->wep_tx_keyidx &
212 CMD_WEP_KEY_INDEX_MASK);
213 lbs_deb_cmd("SET_WEP: remove key %d\n", priv->wep_tx_keyidx);
214 }
215
216 ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd);
217done:
218 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
219 return ret;
220}
221
222int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
223 uint16_t *enable)
224{
225 struct cmd_ds_802_11_enable_rsn cmd;
226 int ret;
227
228 lbs_deb_enter(LBS_DEB_CMD);
229
230 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
231 cmd.action = cpu_to_le16(cmd_action);
232
233 if (cmd_action == CMD_ACT_GET)
234 cmd.enable = 0;
235 else {
236 if (*enable)
237 cmd.enable = cpu_to_le16(CMD_ENABLE_RSN);
238 else
239 cmd.enable = cpu_to_le16(CMD_DISABLE_RSN);
240 lbs_deb_cmd("ENABLE_RSN: %d\n", *enable);
241 }
242
243 ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd);
244 if (!ret && cmd_action == CMD_ACT_GET)
245 *enable = le16_to_cpu(cmd.enable);
246
247 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
248 return ret;
249}
250
251static void set_one_wpa_key(struct MrvlIEtype_keyParamSet *keyparam,
252 struct enc_key *key)
253{
254 lbs_deb_enter(LBS_DEB_CMD);
255
256 if (key->flags & KEY_INFO_WPA_ENABLED)
257 keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED);
258 if (key->flags & KEY_INFO_WPA_UNICAST)
259 keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
260 if (key->flags & KEY_INFO_WPA_MCAST)
261 keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
262
263 keyparam->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
264 keyparam->keytypeid = cpu_to_le16(key->type);
265 keyparam->keylen = cpu_to_le16(key->len);
266 memcpy(keyparam->key, key->key, key->len);
267
268 /* Length field doesn't include the {type,length} header */
269 keyparam->length = cpu_to_le16(sizeof(*keyparam) - 4);
270 lbs_deb_leave(LBS_DEB_CMD);
271}
272
273int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
274 struct assoc_request *assoc)
275{
276 struct cmd_ds_802_11_key_material cmd;
277 int ret = 0;
278 int index = 0;
279
280 lbs_deb_enter(LBS_DEB_CMD);
281
282 cmd.action = cpu_to_le16(cmd_action);
283 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
284
285 if (cmd_action == CMD_ACT_GET) {
286 cmd.hdr.size = cpu_to_le16(sizeof(struct cmd_header) + 2);
287 } else {
288 memset(cmd.keyParamSet, 0, sizeof(cmd.keyParamSet));
289
290 if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc->flags)) {
291 set_one_wpa_key(&cmd.keyParamSet[index],
292 &assoc->wpa_unicast_key);
293 index++;
294 }
295
296 if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc->flags)) {
297 set_one_wpa_key(&cmd.keyParamSet[index],
298 &assoc->wpa_mcast_key);
299 index++;
300 }
301
302 /* The common header and as many keys as we included */
303 cmd.hdr.size = cpu_to_le16(offsetof(typeof(cmd),
304 keyParamSet[index]));
305 }
306 ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd);
307 /* Copy the returned key to driver private data */
308 if (!ret && cmd_action == CMD_ACT_GET) {
309 void *buf_ptr = cmd.keyParamSet;
310 void *resp_end = &(&cmd)[1];
311
312 while (buf_ptr < resp_end) {
313 struct MrvlIEtype_keyParamSet *keyparam = buf_ptr;
314 struct enc_key *key;
315 uint16_t param_set_len = le16_to_cpu(keyparam->length);
316 uint16_t key_len = le16_to_cpu(keyparam->keylen);
317 uint16_t key_flags = le16_to_cpu(keyparam->keyinfo);
318 uint16_t key_type = le16_to_cpu(keyparam->keytypeid);
319 void *end;
320
321 end = (void *)keyparam + sizeof(keyparam->type)
322 + sizeof(keyparam->length) + param_set_len;
323
324 /* Make sure we don't access past the end of the IEs */
325 if (end > resp_end)
326 break;
327
328 if (key_flags & KEY_INFO_WPA_UNICAST)
329 key = &priv->wpa_unicast_key;
330 else if (key_flags & KEY_INFO_WPA_MCAST)
331 key = &priv->wpa_mcast_key;
332 else
333 break;
334
335 /* Copy returned key into driver */
336 memset(key, 0, sizeof(struct enc_key));
337 if (key_len > sizeof(key->key))
338 break;
339 key->type = key_type;
340 key->flags = key_flags;
341 key->len = key_len;
342 memcpy(key->key, keyparam->key, key->len);
343
344 buf_ptr = end + 1;
345 }
346 }
347
348 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
349 return ret;
350}
351
352static __le16 lbs_rate_to_fw_bitmap(int rate, int lower_rates_ok)
353{
354/* Bit Rate
355* 15:13 Reserved
356* 12 54 Mbps
357* 11 48 Mbps
358* 10 36 Mbps
359* 9 24 Mbps
360* 8 18 Mbps
361* 7 12 Mbps
362* 6 9 Mbps
363* 5 6 Mbps
364* 4 Reserved
365* 3 11 Mbps
366* 2 5.5 Mbps
367* 1 2 Mbps
368* 0 1 Mbps
369**/
370
371 uint16_t ratemask;
372 int i = lbs_data_rate_to_fw_index(rate);
373 if (lower_rates_ok)
374 ratemask = (0x1fef >> (12 - i));
375 else
376 ratemask = (1 << i);
377 return cpu_to_le16(ratemask);
378}
379
380int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
381 uint16_t cmd_action)
382{
383 struct cmd_ds_802_11_rate_adapt_rateset cmd;
384 int ret;
385
386 lbs_deb_enter(LBS_DEB_CMD);
387
388 if (!priv->cur_rate && !priv->enablehwauto)
389 return -EINVAL;
390
391 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
392
393 cmd.action = cpu_to_le16(cmd_action);
394 cmd.enablehwauto = cpu_to_le16(priv->enablehwauto);
395 cmd.bitmap = lbs_rate_to_fw_bitmap(priv->cur_rate, priv->enablehwauto);
396 ret = lbs_cmd_with_response(priv, CMD_802_11_RATE_ADAPT_RATESET, &cmd);
397 if (!ret && cmd_action == CMD_ACT_GET)
398 priv->enablehwauto = le16_to_cpu(cmd.enablehwauto);
399
400 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
401 return ret;
402}
403
404/**
405 * @brief Set the data rate
406 *
407 * @param priv A pointer to struct lbs_private structure
408 * @param rate The desired data rate, or 0 to clear a locked rate
409 *
410 * @return 0 on success, error on failure
411 */
412int lbs_set_data_rate(struct lbs_private *priv, u8 rate)
413{
414 struct cmd_ds_802_11_data_rate cmd;
415 int ret = 0;
416
417 lbs_deb_enter(LBS_DEB_CMD);
418
419 memset(&cmd, 0, sizeof(cmd));
420 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
421
422 if (rate > 0) {
423 cmd.action = cpu_to_le16(CMD_ACT_SET_TX_FIX_RATE);
424 cmd.rates[0] = lbs_data_rate_to_fw_index(rate);
425 if (cmd.rates[0] == 0) {
426 lbs_deb_cmd("DATA_RATE: invalid requested rate of"
427 " 0x%02X\n", rate);
428 ret = 0;
429 goto out;
430 }
431 lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n", cmd.rates[0]);
432 } else {
433 cmd.action = cpu_to_le16(CMD_ACT_SET_TX_AUTO);
434 lbs_deb_cmd("DATA_RATE: setting auto\n");
435 }
436
437 ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd);
438 if (ret)
439 goto out;
440
441 lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof(cmd));
442
443 /* FIXME: get actual rates FW can do if this command actually returns
444 * all data rates supported.
445 */
446 priv->cur_rate = lbs_fw_index_to_data_rate(cmd.rates[0]);
447 lbs_deb_cmd("DATA_RATE: current rate is 0x%02x\n", priv->cur_rate);
448
449out:
450 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
451 return ret;
452}
453
454
455int lbs_cmd_802_11_rssi(struct lbs_private *priv,
456 struct cmd_ds_command *cmd)
457{
458
459 lbs_deb_enter(LBS_DEB_CMD);
460 cmd->command = cpu_to_le16(CMD_802_11_RSSI);
461 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) +
462 sizeof(struct cmd_header));
463 cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR);
464
465 /* reset Beacon SNR/NF/RSSI values */
466 priv->SNR[TYPE_BEACON][TYPE_NOAVG] = 0;
467 priv->SNR[TYPE_BEACON][TYPE_AVG] = 0;
468 priv->NF[TYPE_BEACON][TYPE_NOAVG] = 0;
469 priv->NF[TYPE_BEACON][TYPE_AVG] = 0;
470 priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0;
471 priv->RSSI[TYPE_BEACON][TYPE_AVG] = 0;
472
473 lbs_deb_leave(LBS_DEB_CMD);
474 return 0;
475}
476
477int lbs_ret_802_11_rssi(struct lbs_private *priv,
478 struct cmd_ds_command *resp)
479{
480 struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp;
481
482 lbs_deb_enter(LBS_DEB_CMD);
483
484 /* store the non average value */
485 priv->SNR[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->SNR);
486 priv->NF[TYPE_BEACON][TYPE_NOAVG] =
487 get_unaligned_le16(&rssirsp->noisefloor);
488
489 priv->SNR[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgSNR);
490 priv->NF[TYPE_BEACON][TYPE_AVG] =
491 get_unaligned_le16(&rssirsp->avgnoisefloor);
492
493 priv->RSSI[TYPE_BEACON][TYPE_NOAVG] =
494 CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],
495 priv->NF[TYPE_BEACON][TYPE_NOAVG]);
496
497 priv->RSSI[TYPE_BEACON][TYPE_AVG] =
498 CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
499 priv->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
500
501 lbs_deb_cmd("RSSI: beacon %d, avg %d\n",
502 priv->RSSI[TYPE_BEACON][TYPE_NOAVG],
503 priv->RSSI[TYPE_BEACON][TYPE_AVG]);
504
505 lbs_deb_leave(LBS_DEB_CMD);
506 return 0;
507}
508
509
510int lbs_cmd_bcn_ctrl(struct lbs_private *priv,
511 struct cmd_ds_command *cmd,
512 u16 cmd_action)
513{
514 struct cmd_ds_802_11_beacon_control
515 *bcn_ctrl = &cmd->params.bcn_ctrl;
516
517 lbs_deb_enter(LBS_DEB_CMD);
518 cmd->size =
519 cpu_to_le16(sizeof(struct cmd_ds_802_11_beacon_control)
520 + sizeof(struct cmd_header));
521 cmd->command = cpu_to_le16(CMD_802_11_BEACON_CTRL);
522
523 bcn_ctrl->action = cpu_to_le16(cmd_action);
524 bcn_ctrl->beacon_enable = cpu_to_le16(priv->beacon_enable);
525 bcn_ctrl->beacon_period = cpu_to_le16(priv->beacon_period);
526
527 lbs_deb_leave(LBS_DEB_CMD);
528 return 0;
529}
530
531int lbs_ret_802_11_bcn_ctrl(struct lbs_private *priv,
532 struct cmd_ds_command *resp)
533{
534 struct cmd_ds_802_11_beacon_control *bcn_ctrl =
535 &resp->params.bcn_ctrl;
536
537 lbs_deb_enter(LBS_DEB_CMD);
538
539 if (bcn_ctrl->action == CMD_ACT_GET) {
540 priv->beacon_enable = (u8) le16_to_cpu(bcn_ctrl->beacon_enable);
541 priv->beacon_period = le16_to_cpu(bcn_ctrl->beacon_period);
542 }
543
544 lbs_deb_enter(LBS_DEB_CMD);
545 return 0;
546}
547
548
549
550static int lbs_assoc_post(struct lbs_private *priv,
551 struct cmd_ds_802_11_associate_response *resp)
552{
553 int ret = 0;
554 union iwreq_data wrqu;
555 struct bss_descriptor *bss;
556 u16 status_code;
557
558 lbs_deb_enter(LBS_DEB_ASSOC);
559
560 if (!priv->in_progress_assoc_req) {
561 lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n");
562 ret = -1;
563 goto done;
564 }
565 bss = &priv->in_progress_assoc_req->bss;
566
567 /*
568 * Older FW versions map the IEEE 802.11 Status Code in the association
569 * response to the following values returned in resp->statuscode:
570 *
571 * IEEE Status Code Marvell Status Code
572 * 0 -> 0x0000 ASSOC_RESULT_SUCCESS
573 * 13 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
574 * 14 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
575 * 15 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
576 * 16 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
577 * others -> 0x0003 ASSOC_RESULT_REFUSED
578 *
579 * Other response codes:
580 * 0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused)
581 * 0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for
582 * association response from the AP)
583 */
584
585 status_code = le16_to_cpu(resp->statuscode);
586 if (priv->fwrelease < 0x09000000) {
587 switch (status_code) {
588 case 0x00:
589 break;
590 case 0x01:
591 lbs_deb_assoc("ASSOC_RESP: invalid parameters\n");
592 break;
593 case 0x02:
594 lbs_deb_assoc("ASSOC_RESP: internal timer "
595 "expired while waiting for the AP\n");
596 break;
597 case 0x03:
598 lbs_deb_assoc("ASSOC_RESP: association "
599 "refused by AP\n");
600 break;
601 case 0x04:
602 lbs_deb_assoc("ASSOC_RESP: authentication "
603 "refused by AP\n");
604 break;
605 default:
606 lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x "
607 " unknown\n", status_code);
608 break;
609 }
610 } else {
611 /* v9+ returns the AP's association response */
612 lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x\n", status_code);
613 }
614
615 if (status_code) {
616 lbs_mac_event_disconnected(priv);
617 ret = status_code;
618 goto done;
619 }
620
621 lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_RESP",
622 (void *) (resp + sizeof (resp->hdr)),
623 le16_to_cpu(resp->hdr.size) - sizeof (resp->hdr));
624
625 /* Send a Media Connected event, according to the Spec */
626 priv->connect_status = LBS_CONNECTED;
627
628 /* Update current SSID and BSSID */
629 memcpy(&priv->curbssparams.ssid, &bss->ssid, IEEE80211_MAX_SSID_LEN);
630 priv->curbssparams.ssid_len = bss->ssid_len;
631 memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
632
633 priv->SNR[TYPE_RXPD][TYPE_AVG] = 0;
634 priv->NF[TYPE_RXPD][TYPE_AVG] = 0;
635
636 memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR));
637 memset(priv->rawNF, 0x00, sizeof(priv->rawNF));
638 priv->nextSNRNF = 0;
639 priv->numSNRNF = 0;
640
641 netif_carrier_on(priv->dev);
642 if (!priv->tx_pending_len)
643 netif_wake_queue(priv->dev);
644
645 memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
646 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
647 wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
648
649done:
650 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
651 return ret;
652}
653
654/**
655 * @brief This function prepares an association-class command.
656 *
657 * @param priv A pointer to struct lbs_private structure
658 * @param assoc_req The association request describing the BSS to associate
659 * or reassociate with
660 * @param command The actual command, either CMD_802_11_ASSOCIATE or
661 * CMD_802_11_REASSOCIATE
662 *
663 * @return 0 or -1
664 */
665static int lbs_associate(struct lbs_private *priv,
666 struct assoc_request *assoc_req,
667 u16 command)
668{
669 struct cmd_ds_802_11_associate cmd;
670 int ret = 0;
671 struct bss_descriptor *bss = &assoc_req->bss;
672 u8 *pos = &(cmd.iebuf[0]);
673 u16 tmpcap, tmplen, tmpauth;
674 struct mrvl_ie_ssid_param_set *ssid;
675 struct mrvl_ie_ds_param_set *ds;
676 struct mrvl_ie_cf_param_set *cf;
677 struct mrvl_ie_rates_param_set *rates;
678 struct mrvl_ie_rsn_param_set *rsn;
679 struct mrvl_ie_auth_type *auth;
680
681 lbs_deb_enter(LBS_DEB_ASSOC);
682
683 BUG_ON((command != CMD_802_11_ASSOCIATE) &&
684 (command != CMD_802_11_REASSOCIATE));
685
686 memset(&cmd, 0, sizeof(cmd));
687 cmd.hdr.command = cpu_to_le16(command);
688
689 /* Fill in static fields */
690 memcpy(cmd.bssid, bss->bssid, ETH_ALEN);
691 cmd.listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL);
692
693 /* Capability info */
694 tmpcap = (bss->capability & CAPINFO_MASK);
695 if (bss->mode == IW_MODE_INFRA)
696 tmpcap |= WLAN_CAPABILITY_ESS;
697 cmd.capability = cpu_to_le16(tmpcap);
698 lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap);
699
700 /* SSID */
701 ssid = (struct mrvl_ie_ssid_param_set *) pos;
702 ssid->header.type = cpu_to_le16(TLV_TYPE_SSID);
703 tmplen = bss->ssid_len;
704 ssid->header.len = cpu_to_le16(tmplen);
705 memcpy(ssid->ssid, bss->ssid, tmplen);
706 pos += sizeof(ssid->header) + tmplen;
707
708 ds = (struct mrvl_ie_ds_param_set *) pos;
709 ds->header.type = cpu_to_le16(TLV_TYPE_PHY_DS);
710 ds->header.len = cpu_to_le16(1);
711 ds->channel = bss->phy.ds.channel;
712 pos += sizeof(ds->header) + 1;
713
714 cf = (struct mrvl_ie_cf_param_set *) pos;
715 cf->header.type = cpu_to_le16(TLV_TYPE_CF);
716 tmplen = sizeof(*cf) - sizeof (cf->header);
717 cf->header.len = cpu_to_le16(tmplen);
718 /* IE payload should be zeroed, firmware fills it in for us */
719 pos += sizeof(*cf);
720
721 rates = (struct mrvl_ie_rates_param_set *) pos;
722 rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
723 tmplen = min_t(u16, ARRAY_SIZE(bss->rates), MAX_RATES);
724 memcpy(&rates->rates, &bss->rates, tmplen);
725 if (get_common_rates(priv, rates->rates, &tmplen)) {
726 ret = -1;
727 goto done;
728 }
729 pos += sizeof(rates->header) + tmplen;
730 rates->header.len = cpu_to_le16(tmplen);
731 lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen);
732
733 /* Copy the infra. association rates into Current BSS state structure */
734 memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
735 memcpy(&priv->curbssparams.rates, &rates->rates, tmplen);
736
737 /* Set MSB on basic rates as the firmware requires, but _after_
738 * copying to current bss rates.
739 */
740 lbs_set_basic_rate_flags(rates->rates, tmplen);
741
742 /* Firmware v9+ indicate authentication suites as a TLV */
743 if (priv->fwrelease >= 0x09000000) {
744 auth = (struct mrvl_ie_auth_type *) pos;
745 auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
746 auth->header.len = cpu_to_le16(2);
747 tmpauth = iw_auth_to_ieee_auth(priv->secinfo.auth_mode);
748 auth->auth = cpu_to_le16(tmpauth);
749 pos += sizeof(auth->header) + 2;
750
751 lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n",
752 bss->bssid, priv->secinfo.auth_mode);
753 }
754
755 /* WPA/WPA2 IEs */
756 if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
757 rsn = (struct mrvl_ie_rsn_param_set *) pos;
758 /* WPA_IE or WPA2_IE */
759 rsn->header.type = cpu_to_le16((u16) assoc_req->wpa_ie[0]);
760 tmplen = (u16) assoc_req->wpa_ie[1];
761 rsn->header.len = cpu_to_le16(tmplen);
762 memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen);
763 lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: WPA/RSN IE", (u8 *) rsn,
764 sizeof(rsn->header) + tmplen);
765 pos += sizeof(rsn->header) + tmplen;
766 }
767
768 cmd.hdr.size = cpu_to_le16((sizeof(cmd) - sizeof(cmd.iebuf)) +
769 (u16)(pos - (u8 *) &cmd.iebuf));
770
771 /* update curbssparams */
772 priv->channel = bss->phy.ds.channel;
773
774 ret = lbs_cmd_with_response(priv, command, &cmd);
775 if (ret == 0) {
776 ret = lbs_assoc_post(priv,
777 (struct cmd_ds_802_11_associate_response *) &cmd);
778 }
779
780done:
781 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
782 return ret;
783}
784
785/**
786 * @brief Associate to a specific BSS discovered in a scan
787 *
788 * @param priv A pointer to struct lbs_private structure
789 * @param assoc_req The association request describing the BSS to associate with
790 *
791 * @return 0-success, otherwise fail
792 */
793static int lbs_try_associate(struct lbs_private *priv,
794 struct assoc_request *assoc_req)
795{
796 int ret;
797 u8 preamble = RADIO_PREAMBLE_LONG;
798
799 lbs_deb_enter(LBS_DEB_ASSOC);
800
801 /* FW v9 and higher indicate authentication suites as a TLV in the
802 * association command, not as a separate authentication command.
803 */
804 if (priv->fwrelease < 0x09000000) {
805 ret = lbs_set_authentication(priv, assoc_req->bss.bssid,
806 priv->secinfo.auth_mode);
807 if (ret)
808 goto out;
809 }
810
811 /* Use short preamble only when both the BSS and firmware support it */
812 if (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
813 preamble = RADIO_PREAMBLE_SHORT;
814
815 ret = lbs_set_radio(priv, preamble, 1);
816 if (ret)
817 goto out;
818
819 ret = lbs_associate(priv, assoc_req, CMD_802_11_ASSOCIATE);
820 /* If the association fails with current auth mode, let's
821 * try by changing the auth mode
822 */
823 if ((priv->authtype_auto) &&
824 (ret == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) &&
825 (assoc_req->secinfo.wep_enabled) &&
826 (priv->connect_status != LBS_CONNECTED)) {
827 if (priv->secinfo.auth_mode == IW_AUTH_ALG_OPEN_SYSTEM)
828 priv->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
829 else
830 priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
831 if (!assoc_helper_wep_keys(priv, assoc_req))
832 ret = lbs_associate(priv, assoc_req,
833 CMD_802_11_ASSOCIATE);
834 }
835
836 if (ret)
837 ret = -1;
838out:
839 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
840 return ret;
841}
842
843static int lbs_adhoc_post(struct lbs_private *priv,
844 struct cmd_ds_802_11_ad_hoc_result *resp)
845{
846 int ret = 0;
847 u16 command = le16_to_cpu(resp->hdr.command);
848 u16 result = le16_to_cpu(resp->hdr.result);
849 union iwreq_data wrqu;
850 struct bss_descriptor *bss;
851 DECLARE_SSID_BUF(ssid);
852
853 lbs_deb_enter(LBS_DEB_JOIN);
854
855 if (!priv->in_progress_assoc_req) {
856 lbs_deb_join("ADHOC_RESP: no in-progress association "
857 "request\n");
858 ret = -1;
859 goto done;
860 }
861 bss = &priv->in_progress_assoc_req->bss;
862
863 /*
864 * Join result code 0 --> SUCCESS
865 */
866 if (result) {
867 lbs_deb_join("ADHOC_RESP: failed (result 0x%X)\n", result);
868 if (priv->connect_status == LBS_CONNECTED)
869 lbs_mac_event_disconnected(priv);
870 ret = -1;
871 goto done;
872 }
873
874 /* Send a Media Connected event, according to the Spec */
875 priv->connect_status = LBS_CONNECTED;
876
877 if (command == CMD_RET(CMD_802_11_AD_HOC_START)) {
878 /* Update the created network descriptor with the new BSSID */
879 memcpy(bss->bssid, resp->bssid, ETH_ALEN);
880 }
881
882 /* Set the BSSID from the joined/started descriptor */
883 memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
884
885 /* Set the new SSID to current SSID */
886 memcpy(&priv->curbssparams.ssid, &bss->ssid, IEEE80211_MAX_SSID_LEN);
887 priv->curbssparams.ssid_len = bss->ssid_len;
888
889 netif_carrier_on(priv->dev);
890 if (!priv->tx_pending_len)
891 netif_wake_queue(priv->dev);
892
893 memset(&wrqu, 0, sizeof(wrqu));
894 memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
895 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
896 wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
897
898 lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n",
899 print_ssid(ssid, bss->ssid, bss->ssid_len),
900 priv->curbssparams.bssid,
901 priv->channel);
902
903done:
904 lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
905 return ret;
906}
907
908/**
909 * @brief Join an adhoc network found in a previous scan
910 *
911 * @param priv A pointer to struct lbs_private structure
912 * @param assoc_req The association request describing the BSS to join
913 *
914 * @return 0 on success, error on failure
915 */
916static int lbs_adhoc_join(struct lbs_private *priv,
917 struct assoc_request *assoc_req)
918{
919 struct cmd_ds_802_11_ad_hoc_join cmd;
920 struct bss_descriptor *bss = &assoc_req->bss;
921 u8 preamble = RADIO_PREAMBLE_LONG;
922 DECLARE_SSID_BUF(ssid);
923 u16 ratesize = 0;
924 int ret = 0;
925
926 lbs_deb_enter(LBS_DEB_ASSOC);
927
928 lbs_deb_join("current SSID '%s', ssid length %u\n",
929 print_ssid(ssid, priv->curbssparams.ssid,
930 priv->curbssparams.ssid_len),
931 priv->curbssparams.ssid_len);
932 lbs_deb_join("requested ssid '%s', ssid length %u\n",
933 print_ssid(ssid, bss->ssid, bss->ssid_len),
934 bss->ssid_len);
935
936 /* check if the requested SSID is already joined */
937 if (priv->curbssparams.ssid_len &&
938 !lbs_ssid_cmp(priv->curbssparams.ssid,
939 priv->curbssparams.ssid_len,
940 bss->ssid, bss->ssid_len) &&
941 (priv->mode == IW_MODE_ADHOC) &&
942 (priv->connect_status == LBS_CONNECTED)) {
943 union iwreq_data wrqu;
944
945 lbs_deb_join("ADHOC_J_CMD: New ad-hoc SSID is the same as "
946 "current, not attempting to re-join");
947
948 /* Send the re-association event though, because the association
949 * request really was successful, even if just a null-op.
950 */
951 memset(&wrqu, 0, sizeof(wrqu));
952 memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid,
953 ETH_ALEN);
954 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
955 wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
956 goto out;
957 }
958
959 /* Use short preamble only when both the BSS and firmware support it */
960 if (bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) {
961 lbs_deb_join("AdhocJoin: Short preamble\n");
962 preamble = RADIO_PREAMBLE_SHORT;
963 }
964
965 ret = lbs_set_radio(priv, preamble, 1);
966 if (ret)
967 goto out;
968
969 lbs_deb_join("AdhocJoin: channel = %d\n", assoc_req->channel);
970 lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band);
971
972 priv->adhoccreate = 0;
973 priv->channel = bss->channel;
974
975 /* Build the join command */
976 memset(&cmd, 0, sizeof(cmd));
977 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
978
979 cmd.bss.type = CMD_BSS_TYPE_IBSS;
980 cmd.bss.beaconperiod = cpu_to_le16(bss->beaconperiod);
981
982 memcpy(&cmd.bss.bssid, &bss->bssid, ETH_ALEN);
983 memcpy(&cmd.bss.ssid, &bss->ssid, bss->ssid_len);
984
985 memcpy(&cmd.bss.ds, &bss->phy.ds, sizeof(struct ieee_ie_ds_param_set));
986
987 memcpy(&cmd.bss.ibss, &bss->ss.ibss,
988 sizeof(struct ieee_ie_ibss_param_set));
989
990 cmd.bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK);
991 lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
992 bss->capability, CAPINFO_MASK);
993
994 /* information on BSSID descriptor passed to FW */
995 lbs_deb_join("ADHOC_J_CMD: BSSID = %pM, SSID = '%s'\n",
996 cmd.bss.bssid, cmd.bss.ssid);
997
998 /* Only v8 and below support setting these */
999 if (priv->fwrelease < 0x09000000) {
1000 /* failtimeout */
1001 cmd.failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
1002 /* probedelay */
1003 cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
1004 }
1005
1006 /* Copy Data rates from the rates recorded in scan response */
1007 memset(cmd.bss.rates, 0, sizeof(cmd.bss.rates));
1008 ratesize = min_t(u16, ARRAY_SIZE(cmd.bss.rates), ARRAY_SIZE (bss->rates));
1009 memcpy(cmd.bss.rates, bss->rates, ratesize);
1010 if (get_common_rates(priv, cmd.bss.rates, &ratesize)) {
1011 lbs_deb_join("ADHOC_JOIN: get_common_rates returned error.\n");
1012 ret = -1;
1013 goto out;
1014 }
1015
1016 /* Copy the ad-hoc creation rates into Current BSS state structure */
1017 memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
1018 memcpy(&priv->curbssparams.rates, cmd.bss.rates, ratesize);
1019
1020 /* Set MSB on basic rates as the firmware requires, but _after_
1021 * copying to current bss rates.
1022 */
1023 lbs_set_basic_rate_flags(cmd.bss.rates, ratesize);
1024
1025 cmd.bss.ibss.atimwindow = bss->atimwindow;
1026
1027 if (assoc_req->secinfo.wep_enabled) {
1028 u16 tmp = le16_to_cpu(cmd.bss.capability);
1029 tmp |= WLAN_CAPABILITY_PRIVACY;
1030 cmd.bss.capability = cpu_to_le16(tmp);
1031 }
1032
1033 if (priv->psmode == LBS802_11POWERMODEMAX_PSP) {
1034 __le32 local_ps_mode = cpu_to_le32(LBS802_11POWERMODECAM);
1035
1036 /* wake up first */
1037 ret = lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
1038 CMD_ACT_SET, 0, 0,
1039 &local_ps_mode);
1040 if (ret) {
1041 ret = -1;
1042 goto out;
1043 }
1044 }
1045
1046 ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd);
1047 if (ret == 0) {
1048 ret = lbs_adhoc_post(priv,
1049 (struct cmd_ds_802_11_ad_hoc_result *)&cmd);
1050 }
1051
1052out:
1053 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
1054 return ret;
1055}
1056
1057/**
1058 * @brief Start an Adhoc Network
1059 *
1060 * @param priv A pointer to struct lbs_private structure
1061 * @param assoc_req The association request describing the BSS to start
1062 *
1063 * @return 0 on success, error on failure
1064 */
1065static int lbs_adhoc_start(struct lbs_private *priv,
1066 struct assoc_request *assoc_req)
1067{
1068 struct cmd_ds_802_11_ad_hoc_start cmd;
1069 u8 preamble = RADIO_PREAMBLE_SHORT;
1070 size_t ratesize = 0;
1071 u16 tmpcap = 0;
1072 int ret = 0;
1073 DECLARE_SSID_BUF(ssid);
1074
1075 lbs_deb_enter(LBS_DEB_ASSOC);
1076
1077 ret = lbs_set_radio(priv, preamble, 1);
1078 if (ret)
1079 goto out;
1080
1081 /* Build the start command */
1082 memset(&cmd, 0, sizeof(cmd));
1083 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
1084
1085 memcpy(cmd.ssid, assoc_req->ssid, assoc_req->ssid_len);
1086
1087 lbs_deb_join("ADHOC_START: SSID '%s', ssid length %u\n",
1088 print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len),
1089 assoc_req->ssid_len);
1090
1091 cmd.bsstype = CMD_BSS_TYPE_IBSS;
1092
1093 if (priv->beacon_period == 0)
1094 priv->beacon_period = MRVDRV_BEACON_INTERVAL;
1095 cmd.beaconperiod = cpu_to_le16(priv->beacon_period);
1096
1097 WARN_ON(!assoc_req->channel);
1098
1099 /* set Physical parameter set */
1100 cmd.ds.header.id = WLAN_EID_DS_PARAMS;
1101 cmd.ds.header.len = 1;
1102 cmd.ds.channel = assoc_req->channel;
1103
1104 /* set IBSS parameter set */
1105 cmd.ibss.header.id = WLAN_EID_IBSS_PARAMS;
1106 cmd.ibss.header.len = 2;
1107 cmd.ibss.atimwindow = cpu_to_le16(0);
1108
1109 /* set capability info */
1110 tmpcap = WLAN_CAPABILITY_IBSS;
1111 if (assoc_req->secinfo.wep_enabled ||
1112 assoc_req->secinfo.WPAenabled ||
1113 assoc_req->secinfo.WPA2enabled) {
1114 lbs_deb_join("ADHOC_START: WEP/WPA enabled, privacy on\n");
1115 tmpcap |= WLAN_CAPABILITY_PRIVACY;
1116 } else
1117 lbs_deb_join("ADHOC_START: WEP disabled, privacy off\n");
1118
1119 cmd.capability = cpu_to_le16(tmpcap);
1120
1121 /* Only v8 and below support setting probe delay */
1122 if (priv->fwrelease < 0x09000000)
1123 cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
1124
1125 ratesize = min(sizeof(cmd.rates), sizeof(lbs_bg_rates));
1126 memcpy(cmd.rates, lbs_bg_rates, ratesize);
1127
1128 /* Copy the ad-hoc creating rates into Current BSS state structure */
1129 memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
1130 memcpy(&priv->curbssparams.rates, &cmd.rates, ratesize);
1131
1132 /* Set MSB on basic rates as the firmware requires, but _after_
1133 * copying to current bss rates.
1134 */
1135 lbs_set_basic_rate_flags(cmd.rates, ratesize);
1136
1137 lbs_deb_join("ADHOC_START: rates=%02x %02x %02x %02x\n",
1138 cmd.rates[0], cmd.rates[1], cmd.rates[2], cmd.rates[3]);
1139
1140 lbs_deb_join("ADHOC_START: Starting Ad-Hoc BSS on channel %d, band %d\n",
1141 assoc_req->channel, assoc_req->band);
1142
1143 priv->adhoccreate = 1;
1144 priv->mode = IW_MODE_ADHOC;
1145
1146 ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_START, &cmd);
1147 if (ret == 0)
1148 ret = lbs_adhoc_post(priv,
1149 (struct cmd_ds_802_11_ad_hoc_result *)&cmd);
1150
1151out:
1152 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
1153 return ret;
1154}
1155
1156/**
1157 * @brief Stop and Ad-Hoc network and exit Ad-Hoc mode
1158 *
1159 * @param priv A pointer to struct lbs_private structure
1160 * @return 0 on success, or an error
1161 */
1162int lbs_adhoc_stop(struct lbs_private *priv)
1163{
1164 struct cmd_ds_802_11_ad_hoc_stop cmd;
1165 int ret;
1166
1167 lbs_deb_enter(LBS_DEB_JOIN);
1168
1169 memset(&cmd, 0, sizeof (cmd));
1170 cmd.hdr.size = cpu_to_le16 (sizeof (cmd));
1171
1172 ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_STOP, &cmd);
1173
1174 /* Clean up everything even if there was an error */
1175 lbs_mac_event_disconnected(priv);
1176
1177 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
1178 return ret;
1179}
1180
1181static inline int match_bss_no_security(struct lbs_802_11_security *secinfo,
1182 struct bss_descriptor *match_bss)
1183{
1184 if (!secinfo->wep_enabled &&
1185 !secinfo->WPAenabled && !secinfo->WPA2enabled &&
1186 match_bss->wpa_ie[0] != WLAN_EID_GENERIC &&
1187 match_bss->rsn_ie[0] != WLAN_EID_RSN &&
1188 !(match_bss->capability & WLAN_CAPABILITY_PRIVACY))
1189 return 1;
1190 else
1191 return 0;
1192}
1193
1194static inline int match_bss_static_wep(struct lbs_802_11_security *secinfo,
1195 struct bss_descriptor *match_bss)
1196{
1197 if (secinfo->wep_enabled &&
1198 !secinfo->WPAenabled && !secinfo->WPA2enabled &&
1199 (match_bss->capability & WLAN_CAPABILITY_PRIVACY))
1200 return 1;
1201 else
1202 return 0;
1203}
1204
1205static inline int match_bss_wpa(struct lbs_802_11_security *secinfo,
1206 struct bss_descriptor *match_bss)
1207{
1208 if (!secinfo->wep_enabled && secinfo->WPAenabled &&
1209 (match_bss->wpa_ie[0] == WLAN_EID_GENERIC)
1210 /* privacy bit may NOT be set in some APs like LinkSys WRT54G
1211 && (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */
1212 )
1213 return 1;
1214 else
1215 return 0;
1216}
1217
1218static inline int match_bss_wpa2(struct lbs_802_11_security *secinfo,
1219 struct bss_descriptor *match_bss)
1220{
1221 if (!secinfo->wep_enabled && secinfo->WPA2enabled &&
1222 (match_bss->rsn_ie[0] == WLAN_EID_RSN)
1223 /* privacy bit may NOT be set in some APs like LinkSys WRT54G
1224 (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */
1225 )
1226 return 1;
1227 else
1228 return 0;
1229}
1230
1231static inline int match_bss_dynamic_wep(struct lbs_802_11_security *secinfo,
1232 struct bss_descriptor *match_bss)
1233{
1234 if (!secinfo->wep_enabled &&
1235 !secinfo->WPAenabled && !secinfo->WPA2enabled &&
1236 (match_bss->wpa_ie[0] != WLAN_EID_GENERIC) &&
1237 (match_bss->rsn_ie[0] != WLAN_EID_RSN) &&
1238 (match_bss->capability & WLAN_CAPABILITY_PRIVACY))
1239 return 1;
1240 else
1241 return 0;
1242}
1243
1244/**
1245 * @brief Check if a scanned network compatible with the driver settings
1246 *
1247 * WEP WPA WPA2 ad-hoc encrypt Network
1248 * enabled enabled enabled AES mode privacy WPA WPA2 Compatible
1249 * 0 0 0 0 NONE 0 0 0 yes No security
1250 * 1 0 0 0 NONE 1 0 0 yes Static WEP
1251 * 0 1 0 0 x 1x 1 x yes WPA
1252 * 0 0 1 0 x 1x x 1 yes WPA2
1253 * 0 0 0 1 NONE 1 0 0 yes Ad-hoc AES
1254 * 0 0 0 0 !=NONE 1 0 0 yes Dynamic WEP
1255 *
1256 *
1257 * @param priv A pointer to struct lbs_private
1258 * @param index Index in scantable to check against current driver settings
1259 * @param mode Network mode: Infrastructure or IBSS
1260 *
1261 * @return Index in scantable, or error code if negative
1262 */
1263static int is_network_compatible(struct lbs_private *priv,
1264 struct bss_descriptor *bss, uint8_t mode)
1265{
1266 int matched = 0;
1267
1268 lbs_deb_enter(LBS_DEB_SCAN);
1269
1270 if (bss->mode != mode)
1271 goto done;
1272
1273 matched = match_bss_no_security(&priv->secinfo, bss);
1274 if (matched)
1275 goto done;
1276 matched = match_bss_static_wep(&priv->secinfo, bss);
1277 if (matched)
1278 goto done;
1279 matched = match_bss_wpa(&priv->secinfo, bss);
1280 if (matched) {
1281 lbs_deb_scan("is_network_compatible() WPA: wpa_ie 0x%x "
1282 "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s "
1283 "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0],
1284 priv->secinfo.wep_enabled ? "e" : "d",
1285 priv->secinfo.WPAenabled ? "e" : "d",
1286 priv->secinfo.WPA2enabled ? "e" : "d",
1287 (bss->capability & WLAN_CAPABILITY_PRIVACY));
1288 goto done;
1289 }
1290 matched = match_bss_wpa2(&priv->secinfo, bss);
1291 if (matched) {
1292 lbs_deb_scan("is_network_compatible() WPA2: wpa_ie 0x%x "
1293 "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s "
1294 "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0],
1295 priv->secinfo.wep_enabled ? "e" : "d",
1296 priv->secinfo.WPAenabled ? "e" : "d",
1297 priv->secinfo.WPA2enabled ? "e" : "d",
1298 (bss->capability & WLAN_CAPABILITY_PRIVACY));
1299 goto done;
1300 }
1301 matched = match_bss_dynamic_wep(&priv->secinfo, bss);
1302 if (matched) {
1303 lbs_deb_scan("is_network_compatible() dynamic WEP: "
1304 "wpa_ie 0x%x wpa2_ie 0x%x privacy 0x%x\n",
1305 bss->wpa_ie[0], bss->rsn_ie[0],
1306 (bss->capability & WLAN_CAPABILITY_PRIVACY));
1307 goto done;
1308 }
1309
1310 /* bss security settings don't match those configured on card */
1311 lbs_deb_scan("is_network_compatible() FAILED: wpa_ie 0x%x "
1312 "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s privacy 0x%x\n",
1313 bss->wpa_ie[0], bss->rsn_ie[0],
1314 priv->secinfo.wep_enabled ? "e" : "d",
1315 priv->secinfo.WPAenabled ? "e" : "d",
1316 priv->secinfo.WPA2enabled ? "e" : "d",
1317 (bss->capability & WLAN_CAPABILITY_PRIVACY));
1318
1319done:
1320 lbs_deb_leave_args(LBS_DEB_SCAN, "matched: %d", matched);
1321 return matched;
1322}
1323
1324/**
1325 * @brief This function finds a specific compatible BSSID in the scan list
1326 *
1327 * Used in association code
1328 *
1329 * @param priv A pointer to struct lbs_private
1330 * @param bssid BSSID to find in the scan list
1331 * @param mode Network mode: Infrastructure or IBSS
1332 *
1333 * @return index in BSSID list, or error return code (< 0)
1334 */
1335static struct bss_descriptor *lbs_find_bssid_in_list(struct lbs_private *priv,
1336 uint8_t *bssid, uint8_t mode)
1337{
1338 struct bss_descriptor *iter_bss;
1339 struct bss_descriptor *found_bss = NULL;
1340
1341 lbs_deb_enter(LBS_DEB_SCAN);
1342
1343 if (!bssid)
1344 goto out;
1345
1346 lbs_deb_hex(LBS_DEB_SCAN, "looking for", bssid, ETH_ALEN);
1347
1348 /* Look through the scan table for a compatible match. The loop will
1349 * continue past a matched bssid that is not compatible in case there
1350 * is an AP with multiple SSIDs assigned to the same BSSID
1351 */
1352 mutex_lock(&priv->lock);
1353 list_for_each_entry(iter_bss, &priv->network_list, list) {
1354 if (compare_ether_addr(iter_bss->bssid, bssid))
1355 continue; /* bssid doesn't match */
1356 switch (mode) {
1357 case IW_MODE_INFRA:
1358 case IW_MODE_ADHOC:
1359 if (!is_network_compatible(priv, iter_bss, mode))
1360 break;
1361 found_bss = iter_bss;
1362 break;
1363 default:
1364 found_bss = iter_bss;
1365 break;
1366 }
1367 }
1368 mutex_unlock(&priv->lock);
1369
1370out:
1371 lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss);
1372 return found_bss;
1373}
1374
1375/**
1376 * @brief This function finds ssid in ssid list.
1377 *
1378 * Used in association code
1379 *
1380 * @param priv A pointer to struct lbs_private
1381 * @param ssid SSID to find in the list
1382 * @param bssid BSSID to qualify the SSID selection (if provided)
1383 * @param mode Network mode: Infrastructure or IBSS
1384 *
1385 * @return index in BSSID list
1386 */
1387static struct bss_descriptor *lbs_find_ssid_in_list(struct lbs_private *priv,
1388 uint8_t *ssid, uint8_t ssid_len,
1389 uint8_t *bssid, uint8_t mode,
1390 int channel)
1391{
1392 u32 bestrssi = 0;
1393 struct bss_descriptor *iter_bss = NULL;
1394 struct bss_descriptor *found_bss = NULL;
1395 struct bss_descriptor *tmp_oldest = NULL;
1396
1397 lbs_deb_enter(LBS_DEB_SCAN);
1398
1399 mutex_lock(&priv->lock);
1400
1401 list_for_each_entry(iter_bss, &priv->network_list, list) {
1402 if (!tmp_oldest ||
1403 (iter_bss->last_scanned < tmp_oldest->last_scanned))
1404 tmp_oldest = iter_bss;
1405
1406 if (lbs_ssid_cmp(iter_bss->ssid, iter_bss->ssid_len,
1407 ssid, ssid_len) != 0)
1408 continue; /* ssid doesn't match */
1409 if (bssid && compare_ether_addr(iter_bss->bssid, bssid) != 0)
1410 continue; /* bssid doesn't match */
1411 if ((channel > 0) && (iter_bss->channel != channel))
1412 continue; /* channel doesn't match */
1413
1414 switch (mode) {
1415 case IW_MODE_INFRA:
1416 case IW_MODE_ADHOC:
1417 if (!is_network_compatible(priv, iter_bss, mode))
1418 break;
1419
1420 if (bssid) {
1421 /* Found requested BSSID */
1422 found_bss = iter_bss;
1423 goto out;
1424 }
1425
1426 if (SCAN_RSSI(iter_bss->rssi) > bestrssi) {
1427 bestrssi = SCAN_RSSI(iter_bss->rssi);
1428 found_bss = iter_bss;
1429 }
1430 break;
1431 case IW_MODE_AUTO:
1432 default:
1433 if (SCAN_RSSI(iter_bss->rssi) > bestrssi) {
1434 bestrssi = SCAN_RSSI(iter_bss->rssi);
1435 found_bss = iter_bss;
1436 }
1437 break;
1438 }
1439 }
1440
1441out:
1442 mutex_unlock(&priv->lock);
1443 lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss);
1444 return found_bss;
1445}
1446
1447static int assoc_helper_essid(struct lbs_private *priv,
1448 struct assoc_request * assoc_req)
1449{
1450 int ret = 0;
1451 struct bss_descriptor * bss;
1452 int channel = -1;
1453 DECLARE_SSID_BUF(ssid);
1454
1455 lbs_deb_enter(LBS_DEB_ASSOC);
1456
1457 /* FIXME: take channel into account when picking SSIDs if a channel
1458 * is set.
1459 */
1460
1461 if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
1462 channel = assoc_req->channel;
1463
1464 lbs_deb_assoc("SSID '%s' requested\n",
1465 print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len));
1466 if (assoc_req->mode == IW_MODE_INFRA) {
1467 lbs_send_specific_ssid_scan(priv, assoc_req->ssid,
1468 assoc_req->ssid_len);
1469
1470 bss = lbs_find_ssid_in_list(priv, assoc_req->ssid,
1471 assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel);
1472 if (bss != NULL) {
1473 memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
1474 ret = lbs_try_associate(priv, assoc_req);
1475 } else {
1476 lbs_deb_assoc("SSID not found; cannot associate\n");
1477 }
1478 } else if (assoc_req->mode == IW_MODE_ADHOC) {
1479 /* Scan for the network, do not save previous results. Stale
1480 * scan data will cause us to join a non-existant adhoc network
1481 */
1482 lbs_send_specific_ssid_scan(priv, assoc_req->ssid,
1483 assoc_req->ssid_len);
1484
1485 /* Search for the requested SSID in the scan table */
1486 bss = lbs_find_ssid_in_list(priv, assoc_req->ssid,
1487 assoc_req->ssid_len, NULL, IW_MODE_ADHOC, channel);
1488 if (bss != NULL) {
1489 lbs_deb_assoc("SSID found, will join\n");
1490 memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
1491 lbs_adhoc_join(priv, assoc_req);
1492 } else {
1493 /* else send START command */
1494 lbs_deb_assoc("SSID not found, creating adhoc network\n");
1495 memcpy(&assoc_req->bss.ssid, &assoc_req->ssid,
1496 IEEE80211_MAX_SSID_LEN);
1497 assoc_req->bss.ssid_len = assoc_req->ssid_len;
1498 lbs_adhoc_start(priv, assoc_req);
1499 }
1500 }
1501
1502 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
1503 return ret;
1504}
1505
1506
1507static int assoc_helper_bssid(struct lbs_private *priv,
1508 struct assoc_request * assoc_req)
1509{
1510 int ret = 0;
1511 struct bss_descriptor * bss;
1512
1513 lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID %pM", assoc_req->bssid);
1514
1515 /* Search for index position in list for requested MAC */
1516 bss = lbs_find_bssid_in_list(priv, assoc_req->bssid,
1517 assoc_req->mode);
1518 if (bss == NULL) {
1519 lbs_deb_assoc("ASSOC: WAP: BSSID %pM not found, "
1520 "cannot associate.\n", assoc_req->bssid);
1521 goto out;
1522 }
1523
1524 memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
1525 if (assoc_req->mode == IW_MODE_INFRA) {
1526 ret = lbs_try_associate(priv, assoc_req);
1527 lbs_deb_assoc("ASSOC: lbs_try_associate(bssid) returned %d\n",
1528 ret);
1529 } else if (assoc_req->mode == IW_MODE_ADHOC) {
1530 lbs_adhoc_join(priv, assoc_req);
1531 }
1532
1533out:
1534 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
1535 return ret;
1536}
1537
1538
1539static int assoc_helper_associate(struct lbs_private *priv,
1540 struct assoc_request * assoc_req)
1541{
1542 int ret = 0, done = 0;
1543
1544 lbs_deb_enter(LBS_DEB_ASSOC);
1545
1546 /* If we're given and 'any' BSSID, try associating based on SSID */
1547
1548 if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
1549 if (compare_ether_addr(bssid_any, assoc_req->bssid) &&
1550 compare_ether_addr(bssid_off, assoc_req->bssid)) {
1551 ret = assoc_helper_bssid(priv, assoc_req);
1552 done = 1;
1553 }
1554 }
1555
1556 if (!done && test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
1557 ret = assoc_helper_essid(priv, assoc_req);
1558 }
1559
1560 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
1561 return ret;
1562}
1563
1564
1565static int assoc_helper_mode(struct lbs_private *priv,
1566 struct assoc_request * assoc_req)
1567{
1568 int ret = 0;
1569
1570 lbs_deb_enter(LBS_DEB_ASSOC);
1571
1572 if (assoc_req->mode == priv->mode)
1573 goto done;
1574
1575 if (assoc_req->mode == IW_MODE_INFRA) {
1576 if (priv->psstate != PS_STATE_FULL_POWER)
1577 lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
1578 priv->psmode = LBS802_11POWERMODECAM;
1579 }
1580
1581 priv->mode = assoc_req->mode;
1582 ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE,
1583 assoc_req->mode == IW_MODE_ADHOC ? 2 : 1);
1584
1585done:
1586 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
1587 return ret;
1588}
1589
1590static int assoc_helper_channel(struct lbs_private *priv,
1591 struct assoc_request * assoc_req)
1592{
1593 int ret = 0;
1594
1595 lbs_deb_enter(LBS_DEB_ASSOC);
1596
1597 ret = lbs_update_channel(priv);
1598 if (ret) {
1599 lbs_deb_assoc("ASSOC: channel: error getting channel.\n");
1600 goto done;
1601 }
1602
1603 if (assoc_req->channel == priv->channel)
1604 goto done;
1605
1606 if (priv->mesh_dev) {
1607 /* Change mesh channel first; 21.p21 firmware won't let
1608 you change channel otherwise (even though it'll return
1609 an error to this */
1610 lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP,
1611 assoc_req->channel);
1612 }
1613
1614 lbs_deb_assoc("ASSOC: channel: %d -> %d\n",
1615 priv->channel, assoc_req->channel);
1616
1617 ret = lbs_set_channel(priv, assoc_req->channel);
1618 if (ret < 0)
1619 lbs_deb_assoc("ASSOC: channel: error setting channel.\n");
1620
1621 /* FIXME: shouldn't need to grab the channel _again_ after setting
1622 * it since the firmware is supposed to return the new channel, but
1623 * whatever... */
1624 ret = lbs_update_channel(priv);
1625 if (ret) {
1626 lbs_deb_assoc("ASSOC: channel: error getting channel.\n");
1627 goto done;
1628 }
1629
1630 if (assoc_req->channel != priv->channel) {
1631 lbs_deb_assoc("ASSOC: channel: failed to update channel to %d\n",
1632 assoc_req->channel);
1633 goto restore_mesh;
1634 }
1635
1636 if (assoc_req->secinfo.wep_enabled &&
1637 (assoc_req->wep_keys[0].len || assoc_req->wep_keys[1].len ||
1638 assoc_req->wep_keys[2].len || assoc_req->wep_keys[3].len)) {
1639 /* Make sure WEP keys are re-sent to firmware */
1640 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1641 }
1642
1643 /* Must restart/rejoin adhoc networks after channel change */
1644 set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
1645
1646 restore_mesh:
1647 if (priv->mesh_dev)
1648 lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
1649 priv->channel);
1650
1651 done:
1652 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
1653 return ret;
1654}
1655
1656
1657static int assoc_helper_wep_keys(struct lbs_private *priv,
1658 struct assoc_request *assoc_req)
1659{
1660 int i;
1661 int ret = 0;
1662
1663 lbs_deb_enter(LBS_DEB_ASSOC);
1664
1665 /* Set or remove WEP keys */
1666 if (assoc_req->wep_keys[0].len || assoc_req->wep_keys[1].len ||
1667 assoc_req->wep_keys[2].len || assoc_req->wep_keys[3].len)
1668 ret = lbs_cmd_802_11_set_wep(priv, CMD_ACT_ADD, assoc_req);
1669 else
1670 ret = lbs_cmd_802_11_set_wep(priv, CMD_ACT_REMOVE, assoc_req);
1671
1672 if (ret)
1673 goto out;
1674
1675 /* enable/disable the MAC's WEP packet filter */
1676 if (assoc_req->secinfo.wep_enabled)
1677 priv->mac_control |= CMD_ACT_MAC_WEP_ENABLE;
1678 else
1679 priv->mac_control &= ~CMD_ACT_MAC_WEP_ENABLE;
1680
1681 lbs_set_mac_control(priv);
1682
1683 mutex_lock(&priv->lock);
1684
1685 /* Copy WEP keys into priv wep key fields */
1686 for (i = 0; i < 4; i++) {
1687 memcpy(&priv->wep_keys[i], &assoc_req->wep_keys[i],
1688 sizeof(struct enc_key));
1689 }
1690 priv->wep_tx_keyidx = assoc_req->wep_tx_keyidx;
1691
1692 mutex_unlock(&priv->lock);
1693
1694out:
1695 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
1696 return ret;
1697}
1698
1699static int assoc_helper_secinfo(struct lbs_private *priv,
1700 struct assoc_request * assoc_req)
1701{
1702 int ret = 0;
1703 uint16_t do_wpa;
1704 uint16_t rsn = 0;
1705
1706 lbs_deb_enter(LBS_DEB_ASSOC);
1707
1708 memcpy(&priv->secinfo, &assoc_req->secinfo,
1709 sizeof(struct lbs_802_11_security));
1710
1711 lbs_set_mac_control(priv);
1712
1713 /* If RSN is already enabled, don't try to enable it again, since
1714 * ENABLE_RSN resets internal state machines and will clobber the
1715 * 4-way WPA handshake.
1716 */
1717
1718 /* Get RSN enabled/disabled */
1719 ret = lbs_cmd_802_11_enable_rsn(priv, CMD_ACT_GET, &rsn);
1720 if (ret) {
1721 lbs_deb_assoc("Failed to get RSN status: %d\n", ret);
1722 goto out;
1723 }
1724
1725 /* Don't re-enable RSN if it's already enabled */
1726 do_wpa = assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled;
1727 if (do_wpa == rsn)
1728 goto out;
1729
1730 /* Set RSN enabled/disabled */
1731 ret = lbs_cmd_802_11_enable_rsn(priv, CMD_ACT_SET, &do_wpa);
1732
1733out:
1734 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
1735 return ret;
1736}
1737
1738
1739static int assoc_helper_wpa_keys(struct lbs_private *priv,
1740 struct assoc_request * assoc_req)
1741{
1742 int ret = 0;
1743 unsigned int flags = assoc_req->flags;
1744
1745 lbs_deb_enter(LBS_DEB_ASSOC);
1746
1747 /* Work around older firmware bug where WPA unicast and multicast
1748 * keys must be set independently. Seen in SDIO parts with firmware
1749 * version 5.0.11p0.
1750 */
1751
1752 if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
1753 clear_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
1754 ret = lbs_cmd_802_11_key_material(priv, CMD_ACT_SET, assoc_req);
1755 assoc_req->flags = flags;
1756 }
1757
1758 if (ret)
1759 goto out;
1760
1761 memcpy(&priv->wpa_unicast_key, &assoc_req->wpa_unicast_key,
1762 sizeof(struct enc_key));
1763
1764 if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
1765 clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
1766
1767 ret = lbs_cmd_802_11_key_material(priv, CMD_ACT_SET, assoc_req);
1768 assoc_req->flags = flags;
1769
1770 memcpy(&priv->wpa_mcast_key, &assoc_req->wpa_mcast_key,
1771 sizeof(struct enc_key));
1772 }
1773
1774out:
1775 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
1776 return ret;
1777}
1778
1779
1780static int assoc_helper_wpa_ie(struct lbs_private *priv,
1781 struct assoc_request * assoc_req)
1782{
1783 int ret = 0;
1784
1785 lbs_deb_enter(LBS_DEB_ASSOC);
1786
1787 if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
1788 memcpy(&priv->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len);
1789 priv->wpa_ie_len = assoc_req->wpa_ie_len;
1790 } else {
1791 memset(&priv->wpa_ie, 0, MAX_WPA_IE_LEN);
1792 priv->wpa_ie_len = 0;
1793 }
1794
1795 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
1796 return ret;
1797}
1798
1799
1800static int should_deauth_infrastructure(struct lbs_private *priv,
1801 struct assoc_request * assoc_req)
1802{
1803 int ret = 0;
1804
1805 if (priv->connect_status != LBS_CONNECTED)
1806 return 0;
1807
1808 lbs_deb_enter(LBS_DEB_ASSOC);
1809 if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
1810 lbs_deb_assoc("Deauthenticating due to new SSID\n");
1811 ret = 1;
1812 goto out;
1813 }
1814
1815 if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
1816 if (priv->secinfo.auth_mode != assoc_req->secinfo.auth_mode) {
1817 lbs_deb_assoc("Deauthenticating due to new security\n");
1818 ret = 1;
1819 goto out;
1820 }
1821 }
1822
1823 if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
1824 lbs_deb_assoc("Deauthenticating due to new BSSID\n");
1825 ret = 1;
1826 goto out;
1827 }
1828
1829 if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
1830 lbs_deb_assoc("Deauthenticating due to channel switch\n");
1831 ret = 1;
1832 goto out;
1833 }
1834
1835 /* FIXME: deal with 'auto' mode somehow */
1836 if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
1837 if (assoc_req->mode != IW_MODE_INFRA) {
1838 lbs_deb_assoc("Deauthenticating due to leaving "
1839 "infra mode\n");
1840 ret = 1;
1841 goto out;
1842 }
1843 }
1844
1845out:
1846 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
1847 return ret;
1848}
1849
1850
1851static int should_stop_adhoc(struct lbs_private *priv,
1852 struct assoc_request * assoc_req)
1853{
1854 lbs_deb_enter(LBS_DEB_ASSOC);
1855
1856 if (priv->connect_status != LBS_CONNECTED)
1857 return 0;
1858
1859 if (lbs_ssid_cmp(priv->curbssparams.ssid,
1860 priv->curbssparams.ssid_len,
1861 assoc_req->ssid, assoc_req->ssid_len) != 0)
1862 return 1;
1863
1864 /* FIXME: deal with 'auto' mode somehow */
1865 if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
1866 if (assoc_req->mode != IW_MODE_ADHOC)
1867 return 1;
1868 }
1869
1870 if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
1871 if (assoc_req->channel != priv->channel)
1872 return 1;
1873 }
1874
1875 lbs_deb_leave(LBS_DEB_ASSOC);
1876 return 0;
1877}
1878
1879
1880/**
1881 * @brief This function finds the best SSID in the Scan List
1882 *
1883 * Search the scan table for the best SSID that also matches the current
1884 * adapter network preference (infrastructure or adhoc)
1885 *
1886 * @param priv A pointer to struct lbs_private
1887 *
1888 * @return index in BSSID list
1889 */
1890static struct bss_descriptor *lbs_find_best_ssid_in_list(
1891 struct lbs_private *priv, uint8_t mode)
1892{
1893 uint8_t bestrssi = 0;
1894 struct bss_descriptor *iter_bss;
1895 struct bss_descriptor *best_bss = NULL;
1896
1897 lbs_deb_enter(LBS_DEB_SCAN);
1898
1899 mutex_lock(&priv->lock);
1900
1901 list_for_each_entry(iter_bss, &priv->network_list, list) {
1902 switch (mode) {
1903 case IW_MODE_INFRA:
1904 case IW_MODE_ADHOC:
1905 if (!is_network_compatible(priv, iter_bss, mode))
1906 break;
1907 if (SCAN_RSSI(iter_bss->rssi) <= bestrssi)
1908 break;
1909 bestrssi = SCAN_RSSI(iter_bss->rssi);
1910 best_bss = iter_bss;
1911 break;
1912 case IW_MODE_AUTO:
1913 default:
1914 if (SCAN_RSSI(iter_bss->rssi) <= bestrssi)
1915 break;
1916 bestrssi = SCAN_RSSI(iter_bss->rssi);
1917 best_bss = iter_bss;
1918 break;
1919 }
1920 }
1921
1922 mutex_unlock(&priv->lock);
1923 lbs_deb_leave_args(LBS_DEB_SCAN, "best_bss %p", best_bss);
1924 return best_bss;
1925}
1926
1927/**
1928 * @brief Find the best AP
1929 *
1930 * Used from association worker.
1931 *
1932 * @param priv A pointer to struct lbs_private structure
1933 * @param pSSID A pointer to AP's ssid
1934 *
1935 * @return 0--success, otherwise--fail
1936 */
1937static int lbs_find_best_network_ssid(struct lbs_private *priv,
1938 uint8_t *out_ssid, uint8_t *out_ssid_len, uint8_t preferred_mode,
1939 uint8_t *out_mode)
1940{
1941 int ret = -1;
1942 struct bss_descriptor *found;
1943
1944 lbs_deb_enter(LBS_DEB_SCAN);
1945
1946 priv->scan_ssid_len = 0;
1947 lbs_scan_networks(priv, 1);
1948 if (priv->surpriseremoved)
1949 goto out;
1950
1951 found = lbs_find_best_ssid_in_list(priv, preferred_mode);
1952 if (found && (found->ssid_len > 0)) {
1953 memcpy(out_ssid, &found->ssid, IEEE80211_MAX_SSID_LEN);
1954 *out_ssid_len = found->ssid_len;
1955 *out_mode = found->mode;
1956 ret = 0;
1957 }
1958
1959out:
1960 lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
1961 return ret;
1962}
1963
1964
1965void lbs_association_worker(struct work_struct *work)
1966{
1967 struct lbs_private *priv = container_of(work, struct lbs_private,
1968 assoc_work.work);
1969 struct assoc_request * assoc_req = NULL;
1970 int ret = 0;
1971 int find_any_ssid = 0;
1972 DECLARE_SSID_BUF(ssid);
1973
1974 lbs_deb_enter(LBS_DEB_ASSOC);
1975
1976 mutex_lock(&priv->lock);
1977 assoc_req = priv->pending_assoc_req;
1978 priv->pending_assoc_req = NULL;
1979 priv->in_progress_assoc_req = assoc_req;
1980 mutex_unlock(&priv->lock);
1981
1982 if (!assoc_req)
1983 goto done;
1984
1985 lbs_deb_assoc(
1986 "Association Request:\n"
1987 " flags: 0x%08lx\n"
1988 " SSID: '%s'\n"
1989 " chann: %d\n"
1990 " band: %d\n"
1991 " mode: %d\n"
1992 " BSSID: %pM\n"
1993 " secinfo: %s%s%s\n"
1994 " auth_mode: %d\n",
1995 assoc_req->flags,
1996 print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len),
1997 assoc_req->channel, assoc_req->band, assoc_req->mode,
1998 assoc_req->bssid,
1999 assoc_req->secinfo.WPAenabled ? " WPA" : "",
2000 assoc_req->secinfo.WPA2enabled ? " WPA2" : "",
2001 assoc_req->secinfo.wep_enabled ? " WEP" : "",
2002 assoc_req->secinfo.auth_mode);
2003
2004 /* If 'any' SSID was specified, find an SSID to associate with */
2005 if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags) &&
2006 !assoc_req->ssid_len)
2007 find_any_ssid = 1;
2008
2009 /* But don't use 'any' SSID if there's a valid locked BSSID to use */
2010 if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
2011 if (compare_ether_addr(assoc_req->bssid, bssid_any) &&
2012 compare_ether_addr(assoc_req->bssid, bssid_off))
2013 find_any_ssid = 0;
2014 }
2015
2016 if (find_any_ssid) {
2017 u8 new_mode = assoc_req->mode;
2018
2019 ret = lbs_find_best_network_ssid(priv, assoc_req->ssid,
2020 &assoc_req->ssid_len, assoc_req->mode, &new_mode);
2021 if (ret) {
2022 lbs_deb_assoc("Could not find best network\n");
2023 ret = -ENETUNREACH;
2024 goto out;
2025 }
2026
2027 /* Ensure we switch to the mode of the AP */
2028 if (assoc_req->mode == IW_MODE_AUTO) {
2029 set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
2030 assoc_req->mode = new_mode;
2031 }
2032 }
2033
2034 /*
2035 * Check if the attributes being changing require deauthentication
2036 * from the currently associated infrastructure access point.
2037 */
2038 if (priv->mode == IW_MODE_INFRA) {
2039 if (should_deauth_infrastructure(priv, assoc_req)) {
2040 ret = lbs_cmd_80211_deauthenticate(priv,
2041 priv->curbssparams.bssid,
2042 WLAN_REASON_DEAUTH_LEAVING);
2043 if (ret) {
2044 lbs_deb_assoc("Deauthentication due to new "
2045 "configuration request failed: %d\n",
2046 ret);
2047 }
2048 }
2049 } else if (priv->mode == IW_MODE_ADHOC) {
2050 if (should_stop_adhoc(priv, assoc_req)) {
2051 ret = lbs_adhoc_stop(priv);
2052 if (ret) {
2053 lbs_deb_assoc("Teardown of AdHoc network due to "
2054 "new configuration request failed: %d\n",
2055 ret);
2056 }
2057
2058 }
2059 }
2060
2061 /* Send the various configuration bits to the firmware */
2062 if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
2063 ret = assoc_helper_mode(priv, assoc_req);
2064 if (ret)
2065 goto out;
2066 }
2067
2068 if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
2069 ret = assoc_helper_channel(priv, assoc_req);
2070 if (ret)
2071 goto out;
2072 }
2073
2074 if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
2075 ret = assoc_helper_secinfo(priv, assoc_req);
2076 if (ret)
2077 goto out;
2078 }
2079
2080 if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
2081 ret = assoc_helper_wpa_ie(priv, assoc_req);
2082 if (ret)
2083 goto out;
2084 }
2085
2086 /*
2087 * v10 FW wants WPA keys to be set/cleared before WEP key operations,
2088 * otherwise it will fail to correctly associate to WEP networks.
2089 * Other firmware versions don't appear to care.
2090 */
2091 if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags) ||
2092 test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
2093 ret = assoc_helper_wpa_keys(priv, assoc_req);
2094 if (ret)
2095 goto out;
2096 }
2097
2098 if (test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags) ||
2099 test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) {
2100 ret = assoc_helper_wep_keys(priv, assoc_req);
2101 if (ret)
2102 goto out;
2103 }
2104
2105
2106 /* SSID/BSSID should be the _last_ config option set, because they
2107 * trigger the association attempt.
2108 */
2109 if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags) ||
2110 test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
2111 int success = 1;
2112
2113 ret = assoc_helper_associate(priv, assoc_req);
2114 if (ret) {
2115 lbs_deb_assoc("ASSOC: association unsuccessful: %d\n",
2116 ret);
2117 success = 0;
2118 }
2119
2120 if (priv->connect_status != LBS_CONNECTED) {
2121 lbs_deb_assoc("ASSOC: association unsuccessful, "
2122 "not connected\n");
2123 success = 0;
2124 }
2125
2126 if (success) {
2127 lbs_deb_assoc("associated to %pM\n",
2128 priv->curbssparams.bssid);
2129 lbs_prepare_and_send_command(priv,
2130 CMD_802_11_RSSI,
2131 0, CMD_OPTION_WAITFORRSP, 0, NULL);
2132 } else {
2133 ret = -1;
2134 }
2135 }
2136
2137out:
2138 if (ret) {
2139 lbs_deb_assoc("ASSOC: reconfiguration attempt unsuccessful: %d\n",
2140 ret);
2141 }
2142
2143 mutex_lock(&priv->lock);
2144 priv->in_progress_assoc_req = NULL;
2145 mutex_unlock(&priv->lock);
2146 kfree(assoc_req);
2147
2148done:
2149 lbs_deb_leave(LBS_DEB_ASSOC);
2150}
2151
2152
2153/*
2154 * Caller MUST hold any necessary locks
2155 */
2156struct assoc_request *lbs_get_association_request(struct lbs_private *priv)
2157{
2158 struct assoc_request * assoc_req;
2159
2160 lbs_deb_enter(LBS_DEB_ASSOC);
2161 if (!priv->pending_assoc_req) {
2162 priv->pending_assoc_req = kzalloc(sizeof(struct assoc_request),
2163 GFP_KERNEL);
2164 if (!priv->pending_assoc_req) {
2165 lbs_pr_info("Not enough memory to allocate association"
2166 " request!\n");
2167 return NULL;
2168 }
2169 }
2170
2171 /* Copy current configuration attributes to the association request,
2172 * but don't overwrite any that are already set.
2173 */
2174 assoc_req = priv->pending_assoc_req;
2175 if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
2176 memcpy(&assoc_req->ssid, &priv->curbssparams.ssid,
2177 IEEE80211_MAX_SSID_LEN);
2178 assoc_req->ssid_len = priv->curbssparams.ssid_len;
2179 }
2180
2181 if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
2182 assoc_req->channel = priv->channel;
2183
2184 if (!test_bit(ASSOC_FLAG_BAND, &assoc_req->flags))
2185 assoc_req->band = priv->curbssparams.band;
2186
2187 if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags))
2188 assoc_req->mode = priv->mode;
2189
2190 if (!test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
2191 memcpy(&assoc_req->bssid, priv->curbssparams.bssid,
2192 ETH_ALEN);
2193 }
2194
2195 if (!test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)) {
2196 int i;
2197 for (i = 0; i < 4; i++) {
2198 memcpy(&assoc_req->wep_keys[i], &priv->wep_keys[i],
2199 sizeof(struct enc_key));
2200 }
2201 }
2202
2203 if (!test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags))
2204 assoc_req->wep_tx_keyidx = priv->wep_tx_keyidx;
2205
2206 if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
2207 memcpy(&assoc_req->wpa_mcast_key, &priv->wpa_mcast_key,
2208 sizeof(struct enc_key));
2209 }
2210
2211 if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
2212 memcpy(&assoc_req->wpa_unicast_key, &priv->wpa_unicast_key,
2213 sizeof(struct enc_key));
2214 }
2215
2216 if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
2217 memcpy(&assoc_req->secinfo, &priv->secinfo,
2218 sizeof(struct lbs_802_11_security));
2219 }
2220
2221 if (!test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
2222 memcpy(&assoc_req->wpa_ie, &priv->wpa_ie,
2223 MAX_WPA_IE_LEN);
2224 assoc_req->wpa_ie_len = priv->wpa_ie_len;
2225 }
2226
2227 lbs_deb_leave(LBS_DEB_ASSOC);
2228 return assoc_req;
2229}
2230
2231
2232/**
2233 * @brief Deauthenticate from a specific BSS
2234 *
2235 * @param priv A pointer to struct lbs_private structure
2236 * @param bssid The specific BSS to deauthenticate from
2237 * @param reason The 802.11 sec. 7.3.1.7 Reason Code for deauthenticating
2238 *
2239 * @return 0 on success, error on failure
2240 */
2241int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, u8 bssid[ETH_ALEN],
2242 u16 reason)
2243{
2244 struct cmd_ds_802_11_deauthenticate cmd;
2245 int ret;
2246
2247 lbs_deb_enter(LBS_DEB_JOIN);
2248
2249 memset(&cmd, 0, sizeof(cmd));
2250 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
2251 memcpy(cmd.macaddr, &bssid[0], ETH_ALEN);
2252 cmd.reasoncode = cpu_to_le16(reason);
2253
2254 ret = lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd);
2255
2256 /* Clean up everything even if there was an error; can't assume that
2257 * we're still authenticated to the AP after trying to deauth.
2258 */
2259 lbs_mac_event_disconnected(priv);
2260
2261 lbs_deb_leave(LBS_DEB_JOIN);
2262 return ret;
2263}
2264
diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h
deleted file mode 100644
index 40621b789fc5..000000000000
--- a/drivers/net/wireless/libertas/assoc.h
+++ /dev/null
@@ -1,155 +0,0 @@
1/* Copyright (C) 2006, Red Hat, Inc. */
2
3#ifndef _LBS_ASSOC_H_
4#define _LBS_ASSOC_H_
5
6
7#include "defs.h"
8#include "host.h"
9
10
11struct lbs_private;
12
13/*
14 * In theory, the IE is limited to the IE length, 255,
15 * but in practice 64 bytes are enough.
16 */
17#define MAX_WPA_IE_LEN 64
18
19
20
21struct lbs_802_11_security {
22 u8 WPAenabled;
23 u8 WPA2enabled;
24 u8 wep_enabled;
25 u8 auth_mode;
26 u32 key_mgmt;
27};
28
29/** Current Basic Service Set State Structure */
30struct current_bss_params {
31 /** bssid */
32 u8 bssid[ETH_ALEN];
33 /** ssid */
34 u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
35 u8 ssid_len;
36
37 /** band */
38 u8 band;
39 /** channel is directly in priv->channel */
40 /** zero-terminated array of supported data rates */
41 u8 rates[MAX_RATES + 1];
42};
43
44/**
45 * @brief Structure used to store information for each beacon/probe response
46 */
47struct bss_descriptor {
48 u8 bssid[ETH_ALEN];
49
50 u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
51 u8 ssid_len;
52
53 u16 capability;
54 u32 rssi;
55 u32 channel;
56 u16 beaconperiod;
57 __le16 atimwindow;
58
59 /* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */
60 u8 mode;
61
62 /* zero-terminated array of supported data rates */
63 u8 rates[MAX_RATES + 1];
64
65 unsigned long last_scanned;
66
67 union ieee_phy_param_set phy;
68 union ieee_ss_param_set ss;
69
70 u8 wpa_ie[MAX_WPA_IE_LEN];
71 size_t wpa_ie_len;
72 u8 rsn_ie[MAX_WPA_IE_LEN];
73 size_t rsn_ie_len;
74
75 u8 mesh;
76
77 struct list_head list;
78};
79
80/** Association request
81 *
82 * Encapsulates all the options that describe a specific assocation request
83 * or configuration of the wireless card's radio, mode, and security settings.
84 */
85struct assoc_request {
86#define ASSOC_FLAG_SSID 1
87#define ASSOC_FLAG_CHANNEL 2
88#define ASSOC_FLAG_BAND 3
89#define ASSOC_FLAG_MODE 4
90#define ASSOC_FLAG_BSSID 5
91#define ASSOC_FLAG_WEP_KEYS 6
92#define ASSOC_FLAG_WEP_TX_KEYIDX 7
93#define ASSOC_FLAG_WPA_MCAST_KEY 8
94#define ASSOC_FLAG_WPA_UCAST_KEY 9
95#define ASSOC_FLAG_SECINFO 10
96#define ASSOC_FLAG_WPA_IE 11
97 unsigned long flags;
98
99 u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
100 u8 ssid_len;
101 u8 channel;
102 u8 band;
103 u8 mode;
104 u8 bssid[ETH_ALEN] __attribute__ ((aligned (2)));
105
106 /** WEP keys */
107 struct enc_key wep_keys[4];
108 u16 wep_tx_keyidx;
109
110 /** WPA keys */
111 struct enc_key wpa_mcast_key;
112 struct enc_key wpa_unicast_key;
113
114 struct lbs_802_11_security secinfo;
115
116 /** WPA Information Elements*/
117 u8 wpa_ie[MAX_WPA_IE_LEN];
118 u8 wpa_ie_len;
119
120 /* BSS to associate with for infrastructure of Ad-Hoc join */
121 struct bss_descriptor bss;
122};
123
124
125extern u8 lbs_bg_rates[MAX_RATES];
126
127void lbs_association_worker(struct work_struct *work);
128struct assoc_request *lbs_get_association_request(struct lbs_private *priv);
129
130int lbs_adhoc_stop(struct lbs_private *priv);
131
132int lbs_cmd_80211_deauthenticate(struct lbs_private *priv,
133 u8 bssid[ETH_ALEN], u16 reason);
134
135int lbs_cmd_802_11_rssi(struct lbs_private *priv,
136 struct cmd_ds_command *cmd);
137int lbs_ret_802_11_rssi(struct lbs_private *priv,
138 struct cmd_ds_command *resp);
139
140int lbs_cmd_bcn_ctrl(struct lbs_private *priv,
141 struct cmd_ds_command *cmd,
142 u16 cmd_action);
143int lbs_ret_802_11_bcn_ctrl(struct lbs_private *priv,
144 struct cmd_ds_command *resp);
145
146int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
147 struct assoc_request *assoc);
148
149int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
150 uint16_t *enable);
151
152int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
153 struct assoc_request *assoc);
154
155#endif /* _LBS_ASSOC_H */
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index 9d5d3ccf08c8..682b276f06f9 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -7,8 +7,11 @@
7 */ 7 */
8 8
9#include <linux/slab.h> 9#include <linux/slab.h>
10#include <linux/if_arp.h>
10#include <net/cfg80211.h> 11#include <net/cfg80211.h>
12#include <asm/unaligned.h>
11 13
14#include "decl.h"
12#include "cfg.h" 15#include "cfg.h"
13#include "cmd.h" 16#include "cmd.h"
14 17
@@ -39,26 +42,27 @@ static struct ieee80211_channel lbs_2ghz_channels[] = {
39 CHAN2G(14, 2484, 0), 42 CHAN2G(14, 2484, 0),
40}; 43};
41 44
42#define RATETAB_ENT(_rate, _rateid, _flags) { \ 45#define RATETAB_ENT(_rate, _hw_value, _flags) { \
43 .bitrate = (_rate), \ 46 .bitrate = (_rate), \
44 .hw_value = (_rateid), \ 47 .hw_value = (_hw_value), \
45 .flags = (_flags), \ 48 .flags = (_flags), \
46} 49}
47 50
48 51
52/* Table 6 in section 3.2.1.1 */
49static struct ieee80211_rate lbs_rates[] = { 53static struct ieee80211_rate lbs_rates[] = {
50 RATETAB_ENT(10, 0x1, 0), 54 RATETAB_ENT(10, 0, 0),
51 RATETAB_ENT(20, 0x2, 0), 55 RATETAB_ENT(20, 1, 0),
52 RATETAB_ENT(55, 0x4, 0), 56 RATETAB_ENT(55, 2, 0),
53 RATETAB_ENT(110, 0x8, 0), 57 RATETAB_ENT(110, 3, 0),
54 RATETAB_ENT(60, 0x10, 0), 58 RATETAB_ENT(60, 9, 0),
55 RATETAB_ENT(90, 0x20, 0), 59 RATETAB_ENT(90, 6, 0),
56 RATETAB_ENT(120, 0x40, 0), 60 RATETAB_ENT(120, 7, 0),
57 RATETAB_ENT(180, 0x80, 0), 61 RATETAB_ENT(180, 8, 0),
58 RATETAB_ENT(240, 0x100, 0), 62 RATETAB_ENT(240, 9, 0),
59 RATETAB_ENT(360, 0x200, 0), 63 RATETAB_ENT(360, 10, 0),
60 RATETAB_ENT(480, 0x400, 0), 64 RATETAB_ENT(480, 11, 0),
61 RATETAB_ENT(540, 0x800, 0), 65 RATETAB_ENT(540, 12, 0),
62}; 66};
63 67
64static struct ieee80211_supported_band lbs_band_2ghz = { 68static struct ieee80211_supported_band lbs_band_2ghz = {
@@ -76,22 +80,1799 @@ static const u32 cipher_suites[] = {
76 WLAN_CIPHER_SUITE_CCMP, 80 WLAN_CIPHER_SUITE_CCMP,
77}; 81};
78 82
83/* Time to stay on the channel */
84#define LBS_DWELL_PASSIVE 100
85#define LBS_DWELL_ACTIVE 40
79 86
80 87
88/***************************************************************************
89 * Misc utility functions
90 *
91 * TLVs are Marvell specific. They are very similar to IEs, they have the
92 * same structure: type, length, data*. The only difference: for IEs, the
93 * type and length are u8, but for TLVs they're __le16.
94 */
95
96/*
97 * Convert NL80211's auth_type to the one from Libertas, see chapter 5.9.1
98 * in the firmware spec
99 */
100static u8 lbs_auth_to_authtype(enum nl80211_auth_type auth_type)
101{
102 int ret = -ENOTSUPP;
103
104 switch (auth_type) {
105 case NL80211_AUTHTYPE_OPEN_SYSTEM:
106 case NL80211_AUTHTYPE_SHARED_KEY:
107 ret = auth_type;
108 break;
109 case NL80211_AUTHTYPE_AUTOMATIC:
110 ret = NL80211_AUTHTYPE_OPEN_SYSTEM;
111 break;
112 case NL80211_AUTHTYPE_NETWORK_EAP:
113 ret = 0x80;
114 break;
115 default:
116 /* silence compiler */
117 break;
118 }
119 return ret;
120}
121
122
123/* Various firmware commands need the list of supported rates, but with
124 the hight-bit set for basic rates */
125static int lbs_add_rates(u8 *rates)
126{
127 size_t i;
128
129 for (i = 0; i < ARRAY_SIZE(lbs_rates); i++) {
130 u8 rate = lbs_rates[i].bitrate / 5;
131 if (rate == 0x02 || rate == 0x04 ||
132 rate == 0x0b || rate == 0x16)
133 rate |= 0x80;
134 rates[i] = rate;
135 }
136 return ARRAY_SIZE(lbs_rates);
137}
138
139
140/***************************************************************************
141 * TLV utility functions
142 *
143 * TLVs are Marvell specific. They are very similar to IEs, they have the
144 * same structure: type, length, data*. The only difference: for IEs, the
145 * type and length are u8, but for TLVs they're __le16.
146 */
147
148
149/*
150 * Add ssid TLV
151 */
152#define LBS_MAX_SSID_TLV_SIZE \
153 (sizeof(struct mrvl_ie_header) \
154 + IEEE80211_MAX_SSID_LEN)
155
156static int lbs_add_ssid_tlv(u8 *tlv, const u8 *ssid, int ssid_len)
157{
158 struct mrvl_ie_ssid_param_set *ssid_tlv = (void *)tlv;
159
160 /*
161 * TLV-ID SSID 00 00
162 * length 06 00
163 * ssid 4d 4e 54 45 53 54
164 */
165 ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID);
166 ssid_tlv->header.len = cpu_to_le16(ssid_len);
167 memcpy(ssid_tlv->ssid, ssid, ssid_len);
168 return sizeof(ssid_tlv->header) + ssid_len;
169}
170
171
172/*
173 * Add channel list TLV (section 8.4.2)
174 *
175 * Actual channel data comes from priv->wdev->wiphy->channels.
176 */
177#define LBS_MAX_CHANNEL_LIST_TLV_SIZE \
178 (sizeof(struct mrvl_ie_header) \
179 + (LBS_SCAN_BEFORE_NAP * sizeof(struct chanscanparamset)))
180
181static int lbs_add_channel_list_tlv(struct lbs_private *priv, u8 *tlv,
182 int last_channel, int active_scan)
183{
184 int chanscanparamsize = sizeof(struct chanscanparamset) *
185 (last_channel - priv->scan_channel);
186
187 struct mrvl_ie_header *header = (void *) tlv;
188
189 /*
190 * TLV-ID CHANLIST 01 01
191 * length 0e 00
192 * channel 00 01 00 00 00 64 00
193 * radio type 00
194 * channel 01
195 * scan type 00
196 * min scan time 00 00
197 * max scan time 64 00
198 * channel 2 00 02 00 00 00 64 00
199 *
200 */
201
202 header->type = cpu_to_le16(TLV_TYPE_CHANLIST);
203 header->len = cpu_to_le16(chanscanparamsize);
204 tlv += sizeof(struct mrvl_ie_header);
205
206 /* lbs_deb_scan("scan: channels %d to %d\n", priv->scan_channel,
207 last_channel); */
208 memset(tlv, 0, chanscanparamsize);
209
210 while (priv->scan_channel < last_channel) {
211 struct chanscanparamset *param = (void *) tlv;
212
213 param->radiotype = CMD_SCAN_RADIO_TYPE_BG;
214 param->channumber =
215 priv->scan_req->channels[priv->scan_channel]->hw_value;
216 if (active_scan) {
217 param->maxscantime = cpu_to_le16(LBS_DWELL_ACTIVE);
218 } else {
219 param->chanscanmode.passivescan = 1;
220 param->maxscantime = cpu_to_le16(LBS_DWELL_PASSIVE);
221 }
222 tlv += sizeof(struct chanscanparamset);
223 priv->scan_channel++;
224 }
225 return sizeof(struct mrvl_ie_header) + chanscanparamsize;
226}
227
228
229/*
230 * Add rates TLV
231 *
232 * The rates are in lbs_bg_rates[], but for the 802.11b
233 * rates the high bit is set. We add this TLV only because
234 * there's a firmware which otherwise doesn't report all
235 * APs in range.
236 */
237#define LBS_MAX_RATES_TLV_SIZE \
238 (sizeof(struct mrvl_ie_header) \
239 + (ARRAY_SIZE(lbs_rates)))
240
241/* Adds a TLV with all rates the hardware supports */
242static int lbs_add_supported_rates_tlv(u8 *tlv)
243{
244 size_t i;
245 struct mrvl_ie_rates_param_set *rate_tlv = (void *)tlv;
246
247 /*
248 * TLV-ID RATES 01 00
249 * length 0e 00
250 * rates 82 84 8b 96 0c 12 18 24 30 48 60 6c
251 */
252 rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES);
253 tlv += sizeof(rate_tlv->header);
254 i = lbs_add_rates(tlv);
255 tlv += i;
256 rate_tlv->header.len = cpu_to_le16(i);
257 return sizeof(rate_tlv->header) + i;
258}
259
260
261/*
262 * Adds a TLV with all rates the hardware *and* BSS supports.
263 */
264static int lbs_add_common_rates_tlv(u8 *tlv, struct cfg80211_bss *bss)
265{
266 struct mrvl_ie_rates_param_set *rate_tlv = (void *)tlv;
267 const u8 *rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
268 int n;
269
270 /*
271 * 01 00 TLV_TYPE_RATES
272 * 04 00 len
273 * 82 84 8b 96 rates
274 */
275 rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES);
276 tlv += sizeof(rate_tlv->header);
277
278 if (!rates_eid) {
279 /* Fallback: add basic 802.11b rates */
280 *tlv++ = 0x82;
281 *tlv++ = 0x84;
282 *tlv++ = 0x8b;
283 *tlv++ = 0x96;
284 n = 4;
285 } else {
286 int hw, ap;
287 u8 ap_max = rates_eid[1];
288 n = 0;
289 for (hw = 0; hw < ARRAY_SIZE(lbs_rates); hw++) {
290 u8 hw_rate = lbs_rates[hw].bitrate / 5;
291 for (ap = 0; ap < ap_max; ap++) {
292 if (hw_rate == (rates_eid[ap+2] & 0x7f)) {
293 *tlv++ = rates_eid[ap+2];
294 n++;
295 }
296 }
297 }
298 }
299
300 rate_tlv->header.len = cpu_to_le16(n);
301 return sizeof(rate_tlv->header) + n;
302}
303
304
305/*
306 * Add auth type TLV.
307 *
308 * This is only needed for newer firmware (V9 and up).
309 */
310#define LBS_MAX_AUTH_TYPE_TLV_SIZE \
311 sizeof(struct mrvl_ie_auth_type)
312
313static int lbs_add_auth_type_tlv(u8 *tlv, enum nl80211_auth_type auth_type)
314{
315 struct mrvl_ie_auth_type *auth = (void *) tlv;
316
317 /*
318 * 1f 01 TLV_TYPE_AUTH_TYPE
319 * 01 00 len
320 * 01 auth type
321 */
322 auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
323 auth->header.len = cpu_to_le16(sizeof(*auth)-sizeof(auth->header));
324 auth->auth = cpu_to_le16(lbs_auth_to_authtype(auth_type));
325 return sizeof(*auth);
326}
327
328
329/*
330 * Add channel (phy ds) TLV
331 */
332#define LBS_MAX_CHANNEL_TLV_SIZE \
333 sizeof(struct mrvl_ie_header)
334
335static int lbs_add_channel_tlv(u8 *tlv, u8 channel)
336{
337 struct mrvl_ie_ds_param_set *ds = (void *) tlv;
338
339 /*
340 * 03 00 TLV_TYPE_PHY_DS
341 * 01 00 len
342 * 06 channel
343 */
344 ds->header.type = cpu_to_le16(TLV_TYPE_PHY_DS);
345 ds->header.len = cpu_to_le16(sizeof(*ds)-sizeof(ds->header));
346 ds->channel = channel;
347 return sizeof(*ds);
348}
349
350
351/*
352 * Add (empty) CF param TLV of the form:
353 */
354#define LBS_MAX_CF_PARAM_TLV_SIZE \
355 sizeof(struct mrvl_ie_header)
356
357static int lbs_add_cf_param_tlv(u8 *tlv)
358{
359 struct mrvl_ie_cf_param_set *cf = (void *)tlv;
360
361 /*
362 * 04 00 TLV_TYPE_CF
363 * 06 00 len
364 * 00 cfpcnt
365 * 00 cfpperiod
366 * 00 00 cfpmaxduration
367 * 00 00 cfpdurationremaining
368 */
369 cf->header.type = cpu_to_le16(TLV_TYPE_CF);
370 cf->header.len = cpu_to_le16(sizeof(*cf)-sizeof(cf->header));
371 return sizeof(*cf);
372}
373
374/*
375 * Add WPA TLV
376 */
377#define LBS_MAX_WPA_TLV_SIZE \
378 (sizeof(struct mrvl_ie_header) \
379 + 128 /* TODO: I guessed the size */)
380
381static int lbs_add_wpa_tlv(u8 *tlv, const u8 *ie, u8 ie_len)
382{
383 size_t tlv_len;
384
385 /*
386 * We need just convert an IE to an TLV. IEs use u8 for the header,
387 * u8 type
388 * u8 len
389 * u8[] data
390 * but TLVs use __le16 instead:
391 * __le16 type
392 * __le16 len
393 * u8[] data
394 */
395 *tlv++ = *ie++;
396 *tlv++ = 0;
397 tlv_len = *tlv++ = *ie++;
398 *tlv++ = 0;
399 while (tlv_len--)
400 *tlv++ = *ie++;
401 /* the TLV is two bytes larger than the IE */
402 return ie_len + 2;
403}
404
405/***************************************************************************
406 * Set Channel
407 */
408
81static int lbs_cfg_set_channel(struct wiphy *wiphy, 409static int lbs_cfg_set_channel(struct wiphy *wiphy,
82 struct net_device *netdev, 410 struct net_device *netdev,
83 struct ieee80211_channel *chan, 411 struct ieee80211_channel *channel,
84 enum nl80211_channel_type channel_type) 412 enum nl80211_channel_type channel_type)
85{ 413{
86 struct lbs_private *priv = wiphy_priv(wiphy); 414 struct lbs_private *priv = wiphy_priv(wiphy);
87 int ret = -ENOTSUPP; 415 int ret = -ENOTSUPP;
88 416
89 lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d", chan->center_freq, channel_type); 417 lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d",
418 channel->center_freq, channel_type);
90 419
91 if (channel_type != NL80211_CHAN_NO_HT) 420 if (channel_type != NL80211_CHAN_NO_HT)
92 goto out; 421 goto out;
93 422
94 ret = lbs_set_channel(priv, chan->hw_value); 423 ret = lbs_set_channel(priv, channel->hw_value);
424
425 out:
426 lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
427 return ret;
428}
429
430
431
432/***************************************************************************
433 * Scanning
434 */
435
436/*
437 * When scanning, the firmware doesn't send a nul packet with the power-safe
438 * bit to the AP. So we cannot stay away from our current channel too long,
439 * otherwise we loose data. So take a "nap" while scanning every other
440 * while.
441 */
442#define LBS_SCAN_BEFORE_NAP 4
443
444
445/*
446 * When the firmware reports back a scan-result, it gives us an "u8 rssi",
447 * which isn't really an RSSI, as it becomes larger when moving away from
448 * the AP. Anyway, we need to convert that into mBm.
449 */
450#define LBS_SCAN_RSSI_TO_MBM(rssi) \
451 ((-(int)rssi + 3)*100)
452
453static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
454 struct cmd_header *resp)
455{
456 struct cmd_ds_802_11_scan_rsp *scanresp = (void *)resp;
457 int bsssize;
458 const u8 *pos;
459 u16 nr_sets;
460 const u8 *tsfdesc;
461 int tsfsize;
462 int i;
463 int ret = -EILSEQ;
464
465 lbs_deb_enter(LBS_DEB_CFG80211);
466
467 bsssize = get_unaligned_le16(&scanresp->bssdescriptsize);
468 nr_sets = le16_to_cpu(resp->size);
469
470 /*
471 * The general layout of the scan response is described in chapter
472 * 5.7.1. Basically we have a common part, then any number of BSS
473 * descriptor sections. Finally we have section with the same number
474 * of TSFs.
475 *
476 * cmd_ds_802_11_scan_rsp
477 * cmd_header
478 * pos_size
479 * nr_sets
480 * bssdesc 1
481 * bssid
482 * rssi
483 * timestamp
484 * intvl
485 * capa
486 * IEs
487 * bssdesc 2
488 * bssdesc n
489 * MrvlIEtypes_TsfFimestamp_t
490 * TSF for BSS 1
491 * TSF for BSS 2
492 * TSF for BSS n
493 */
494
495 pos = scanresp->bssdesc_and_tlvbuffer;
496
497 tsfdesc = pos + bsssize;
498 tsfsize = 4 + 8 * scanresp->nr_sets;
499
500 /* Validity check: we expect a Marvell-Local TLV */
501 i = get_unaligned_le16(tsfdesc);
502 tsfdesc += 2;
503 if (i != TLV_TYPE_TSFTIMESTAMP)
504 goto done;
505 /* Validity check: the TLV holds TSF values with 8 bytes each, so
506 * the size in the TLV must match the nr_sets value */
507 i = get_unaligned_le16(tsfdesc);
508 tsfdesc += 2;
509 if (i / 8 != scanresp->nr_sets)
510 goto done;
511
512 for (i = 0; i < scanresp->nr_sets; i++) {
513 const u8 *bssid;
514 const u8 *ie;
515 int left;
516 int ielen;
517 int rssi;
518 u16 intvl;
519 u16 capa;
520 int chan_no = -1;
521 const u8 *ssid = NULL;
522 u8 ssid_len = 0;
523 DECLARE_SSID_BUF(ssid_buf);
524
525 int len = get_unaligned_le16(pos);
526 pos += 2;
527
528 /* BSSID */
529 bssid = pos;
530 pos += ETH_ALEN;
531 /* RSSI */
532 rssi = *pos++;
533 /* Packet time stamp */
534 pos += 8;
535 /* Beacon interval */
536 intvl = get_unaligned_le16(pos);
537 pos += 2;
538 /* Capabilities */
539 capa = get_unaligned_le16(pos);
540 pos += 2;
541
542 /* To find out the channel, we must parse the IEs */
543 ie = pos;
544 /* 6+1+8+2+2: size of BSSID, RSSI, time stamp, beacon
545 interval, capabilities */
546 ielen = left = len - (6 + 1 + 8 + 2 + 2);
547 while (left >= 2) {
548 u8 id, elen;
549 id = *pos++;
550 elen = *pos++;
551 left -= 2;
552 if (elen > left || elen == 0)
553 goto done;
554 if (id == WLAN_EID_DS_PARAMS)
555 chan_no = *pos;
556 if (id == WLAN_EID_SSID) {
557 ssid = pos;
558 ssid_len = elen;
559 }
560 left -= elen;
561 pos += elen;
562 }
563
564 /* No channel, no luck */
565 if (chan_no != -1) {
566 struct wiphy *wiphy = priv->wdev->wiphy;
567 int freq = ieee80211_channel_to_frequency(chan_no);
568 struct ieee80211_channel *channel =
569 ieee80211_get_channel(wiphy, freq);
570
571 lbs_deb_scan("scan: %pM, capa %04x, chan %2d, %s, "
572 "%d dBm\n",
573 bssid, capa, chan_no,
574 print_ssid(ssid_buf, ssid, ssid_len),
575 LBS_SCAN_RSSI_TO_MBM(rssi)/100);
576
577 if (channel ||
578 !(channel->flags & IEEE80211_CHAN_DISABLED))
579 cfg80211_inform_bss(wiphy, channel,
580 bssid, le64_to_cpu(*(__le64 *)tsfdesc),
581 capa, intvl, ie, ielen,
582 LBS_SCAN_RSSI_TO_MBM(rssi),
583 GFP_KERNEL);
584 }
585 tsfdesc += 8;
586 }
587 ret = 0;
588
589 done:
590 lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
591 return ret;
592}
593
594
595/*
596 * Our scan command contains a TLV, consting of a SSID TLV, a channel list
597 * TLV and a rates TLV. Determine the maximum size of them:
598 */
599#define LBS_SCAN_MAX_CMD_SIZE \
600 (sizeof(struct cmd_ds_802_11_scan) \
601 + LBS_MAX_SSID_TLV_SIZE \
602 + LBS_MAX_CHANNEL_LIST_TLV_SIZE \
603 + LBS_MAX_RATES_TLV_SIZE)
604
605/*
606 * Assumes priv->scan_req is initialized and valid
607 * Assumes priv->scan_channel is initialized
608 */
609static void lbs_scan_worker(struct work_struct *work)
610{
611 struct lbs_private *priv =
612 container_of(work, struct lbs_private, scan_work.work);
613 struct cmd_ds_802_11_scan *scan_cmd;
614 u8 *tlv; /* pointer into our current, growing TLV storage area */
615 int last_channel;
616 int running, carrier;
617
618 lbs_deb_enter(LBS_DEB_SCAN);
619
620 scan_cmd = kzalloc(LBS_SCAN_MAX_CMD_SIZE, GFP_KERNEL);
621 if (scan_cmd == NULL)
622 goto out_no_scan_cmd;
623
624 /* prepare fixed part of scan command */
625 scan_cmd->bsstype = CMD_BSS_TYPE_ANY;
626
627 /* stop network while we're away from our main channel */
628 running = !netif_queue_stopped(priv->dev);
629 carrier = netif_carrier_ok(priv->dev);
630 if (running)
631 netif_stop_queue(priv->dev);
632 if (carrier)
633 netif_carrier_off(priv->dev);
634
635 /* prepare fixed part of scan command */
636 tlv = scan_cmd->tlvbuffer;
637
638 /* add SSID TLV */
639 if (priv->scan_req->n_ssids)
640 tlv += lbs_add_ssid_tlv(tlv,
641 priv->scan_req->ssids[0].ssid,
642 priv->scan_req->ssids[0].ssid_len);
643
644 /* add channel TLVs */
645 last_channel = priv->scan_channel + LBS_SCAN_BEFORE_NAP;
646 if (last_channel > priv->scan_req->n_channels)
647 last_channel = priv->scan_req->n_channels;
648 tlv += lbs_add_channel_list_tlv(priv, tlv, last_channel,
649 priv->scan_req->n_ssids);
650
651 /* add rates TLV */
652 tlv += lbs_add_supported_rates_tlv(tlv);
653
654 if (priv->scan_channel < priv->scan_req->n_channels) {
655 cancel_delayed_work(&priv->scan_work);
656 queue_delayed_work(priv->work_thread, &priv->scan_work,
657 msecs_to_jiffies(300));
658 }
659
660 /* This is the final data we are about to send */
661 scan_cmd->hdr.size = cpu_to_le16(tlv - (u8 *)scan_cmd);
662 lbs_deb_hex(LBS_DEB_SCAN, "SCAN_CMD", (void *)scan_cmd,
663 sizeof(*scan_cmd));
664 lbs_deb_hex(LBS_DEB_SCAN, "SCAN_TLV", scan_cmd->tlvbuffer,
665 tlv - scan_cmd->tlvbuffer);
666
667 __lbs_cmd(priv, CMD_802_11_SCAN, &scan_cmd->hdr,
668 le16_to_cpu(scan_cmd->hdr.size),
669 lbs_ret_scan, 0);
670
671 if (priv->scan_channel >= priv->scan_req->n_channels) {
672 /* Mark scan done */
673 cfg80211_scan_done(priv->scan_req, false);
674 priv->scan_req = NULL;
675 }
676
677 /* Restart network */
678 if (carrier)
679 netif_carrier_on(priv->dev);
680 if (running && !priv->tx_pending_len)
681 netif_wake_queue(priv->dev);
682
683 kfree(scan_cmd);
684
685 out_no_scan_cmd:
686 lbs_deb_leave(LBS_DEB_SCAN);
687}
688
689
690static int lbs_cfg_scan(struct wiphy *wiphy,
691 struct net_device *dev,
692 struct cfg80211_scan_request *request)
693{
694 struct lbs_private *priv = wiphy_priv(wiphy);
695 int ret = 0;
696
697 lbs_deb_enter(LBS_DEB_CFG80211);
698
699 if (priv->scan_req || delayed_work_pending(&priv->scan_work)) {
700 /* old scan request not yet processed */
701 ret = -EAGAIN;
702 goto out;
703 }
704
705 lbs_deb_scan("scan: ssids %d, channels %d, ie_len %zd\n",
706 request->n_ssids, request->n_channels, request->ie_len);
707
708 priv->scan_channel = 0;
709 queue_delayed_work(priv->work_thread, &priv->scan_work,
710 msecs_to_jiffies(50));
711
712 if (priv->surpriseremoved)
713 ret = -EIO;
714
715 priv->scan_req = request;
716
717 out:
718 lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
719 return ret;
720}
721
722
723
724
725/***************************************************************************
726 * Events
727 */
728
729void lbs_send_disconnect_notification(struct lbs_private *priv)
730{
731 lbs_deb_enter(LBS_DEB_CFG80211);
732
733 cfg80211_disconnected(priv->dev,
734 0,
735 NULL, 0,
736 GFP_KERNEL);
737
738 lbs_deb_leave(LBS_DEB_CFG80211);
739}
740
741void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event)
742{
743 lbs_deb_enter(LBS_DEB_CFG80211);
744
745 cfg80211_michael_mic_failure(priv->dev,
746 priv->assoc_bss,
747 event == MACREG_INT_CODE_MIC_ERR_MULTICAST ?
748 NL80211_KEYTYPE_GROUP :
749 NL80211_KEYTYPE_PAIRWISE,
750 -1,
751 NULL,
752 GFP_KERNEL);
753
754 lbs_deb_leave(LBS_DEB_CFG80211);
755}
756
757
758
759
760/***************************************************************************
761 * Connect/disconnect
762 */
763
764
765/*
766 * This removes all WEP keys
767 */
768static int lbs_remove_wep_keys(struct lbs_private *priv)
769{
770 struct cmd_ds_802_11_set_wep cmd;
771 int ret;
772
773 lbs_deb_enter(LBS_DEB_CFG80211);
774
775 memset(&cmd, 0, sizeof(cmd));
776 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
777 cmd.keyindex = cpu_to_le16(priv->wep_tx_key);
778 cmd.action = cpu_to_le16(CMD_ACT_REMOVE);
779
780 ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd);
781
782 lbs_deb_leave(LBS_DEB_CFG80211);
783 return ret;
784}
785
786/*
787 * Set WEP keys
788 */
789static int lbs_set_wep_keys(struct lbs_private *priv)
790{
791 struct cmd_ds_802_11_set_wep cmd;
792 int i;
793 int ret;
794
795 lbs_deb_enter(LBS_DEB_CFG80211);
796
797 /*
798 * command 13 00
799 * size 50 00
800 * sequence xx xx
801 * result 00 00
802 * action 02 00 ACT_ADD
803 * transmit key 00 00
804 * type for key 1 01 WEP40
805 * type for key 2 00
806 * type for key 3 00
807 * type for key 4 00
808 * key 1 39 39 39 39 39 00 00 00
809 * 00 00 00 00 00 00 00 00
810 * key 2 00 00 00 00 00 00 00 00
811 * 00 00 00 00 00 00 00 00
812 * key 3 00 00 00 00 00 00 00 00
813 * 00 00 00 00 00 00 00 00
814 * key 4 00 00 00 00 00 00 00 00
815 */
816 if (priv->wep_key_len[0] || priv->wep_key_len[1] ||
817 priv->wep_key_len[2] || priv->wep_key_len[3]) {
818 /* Only set wep keys if we have at least one of them */
819 memset(&cmd, 0, sizeof(cmd));
820 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
821 cmd.keyindex = cpu_to_le16(priv->wep_tx_key);
822 cmd.action = cpu_to_le16(CMD_ACT_ADD);
823
824 for (i = 0; i < 4; i++) {
825 switch (priv->wep_key_len[i]) {
826 case WLAN_KEY_LEN_WEP40:
827 cmd.keytype[i] = CMD_TYPE_WEP_40_BIT;
828 break;
829 case WLAN_KEY_LEN_WEP104:
830 cmd.keytype[i] = CMD_TYPE_WEP_104_BIT;
831 break;
832 default:
833 cmd.keytype[i] = 0;
834 break;
835 }
836 memcpy(cmd.keymaterial[i], priv->wep_key[i],
837 priv->wep_key_len[i]);
838 }
839
840 ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd);
841 } else {
842 /* Otherwise remove all wep keys */
843 ret = lbs_remove_wep_keys(priv);
844 }
845
846 lbs_deb_leave(LBS_DEB_CFG80211);
847 return ret;
848}
849
850
851/*
852 * Enable/Disable RSN status
853 */
854static int lbs_enable_rsn(struct lbs_private *priv, int enable)
855{
856 struct cmd_ds_802_11_enable_rsn cmd;
857 int ret;
858
859 lbs_deb_enter_args(LBS_DEB_CFG80211, "%d", enable);
860
861 /*
862 * cmd 2f 00
863 * size 0c 00
864 * sequence xx xx
865 * result 00 00
866 * action 01 00 ACT_SET
867 * enable 01 00
868 */
869 memset(&cmd, 0, sizeof(cmd));
870 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
871 cmd.action = cpu_to_le16(CMD_ACT_SET);
872 cmd.enable = cpu_to_le16(enable);
873
874 ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd);
875
876 lbs_deb_leave(LBS_DEB_CFG80211);
877 return ret;
878}
879
880
881/*
882 * Set WPA/WPA key material
883 */
884
885/* like "struct cmd_ds_802_11_key_material", but with cmd_header. Once we
886 * get rid of WEXT, this should go into host.h */
887
888struct cmd_key_material {
889 struct cmd_header hdr;
890
891 __le16 action;
892 struct MrvlIEtype_keyParamSet param;
893} __attribute__ ((packed));
894
895static int lbs_set_key_material(struct lbs_private *priv,
896 int key_type,
897 int key_info,
898 u8 *key, u16 key_len)
899{
900 struct cmd_key_material cmd;
901 int ret;
902
903 lbs_deb_enter(LBS_DEB_CFG80211);
904
905 /*
906 * Example for WPA (TKIP):
907 *
908 * cmd 5e 00
909 * size 34 00
910 * sequence xx xx
911 * result 00 00
912 * action 01 00
913 * TLV type 00 01 key param
914 * length 00 26
915 * key type 01 00 TKIP
916 * key info 06 00 UNICAST | ENABLED
917 * key len 20 00
918 * key 32 bytes
919 */
920 memset(&cmd, 0, sizeof(cmd));
921 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
922 cmd.action = cpu_to_le16(CMD_ACT_SET);
923 cmd.param.type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
924 cmd.param.length = cpu_to_le16(sizeof(cmd.param) - 4);
925 cmd.param.keytypeid = cpu_to_le16(key_type);
926 cmd.param.keyinfo = cpu_to_le16(key_info);
927 cmd.param.keylen = cpu_to_le16(key_len);
928 if (key && key_len)
929 memcpy(cmd.param.key, key, key_len);
930
931 ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd);
932
933 lbs_deb_leave(LBS_DEB_CFG80211);
934 return ret;
935}
936
937
938/*
939 * Sets the auth type (open, shared, etc) in the firmware. That
940 * we use CMD_802_11_AUTHENTICATE is misleading, this firmware
941 * command doesn't send an authentication frame at all, it just
942 * stores the auth_type.
943 */
944static int lbs_set_authtype(struct lbs_private *priv,
945 struct cfg80211_connect_params *sme)
946{
947 struct cmd_ds_802_11_authenticate cmd;
948 int ret;
949
950 lbs_deb_enter_args(LBS_DEB_CFG80211, "%d", sme->auth_type);
951
952 /*
953 * cmd 11 00
954 * size 19 00
955 * sequence xx xx
956 * result 00 00
957 * BSS id 00 13 19 80 da 30
958 * auth type 00
959 * reserved 00 00 00 00 00 00 00 00 00 00
960 */
961 memset(&cmd, 0, sizeof(cmd));
962 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
963 if (sme->bssid)
964 memcpy(cmd.bssid, sme->bssid, ETH_ALEN);
965 /* convert auth_type */
966 ret = lbs_auth_to_authtype(sme->auth_type);
967 if (ret < 0)
968 goto done;
969
970 cmd.authtype = ret;
971 ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd);
972
973 done:
974 lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
975 return ret;
976}
977
978
979/*
980 * Create association request
981 */
982#define LBS_ASSOC_MAX_CMD_SIZE \
983 (sizeof(struct cmd_ds_802_11_associate) \
984 - 512 /* cmd_ds_802_11_associate.iebuf */ \
985 + LBS_MAX_SSID_TLV_SIZE \
986 + LBS_MAX_CHANNEL_TLV_SIZE \
987 + LBS_MAX_CF_PARAM_TLV_SIZE \
988 + LBS_MAX_AUTH_TYPE_TLV_SIZE \
989 + LBS_MAX_WPA_TLV_SIZE)
990
991static int lbs_associate(struct lbs_private *priv,
992 struct cfg80211_bss *bss,
993 struct cfg80211_connect_params *sme)
994{
995 struct cmd_ds_802_11_associate_response *resp;
996 struct cmd_ds_802_11_associate *cmd = kzalloc(LBS_ASSOC_MAX_CMD_SIZE,
997 GFP_KERNEL);
998 const u8 *ssid_eid;
999 size_t len, resp_ie_len;
1000 int status;
1001 int ret;
1002 u8 *pos = &(cmd->iebuf[0]);
1003
1004 lbs_deb_enter(LBS_DEB_CFG80211);
1005
1006 if (!cmd) {
1007 ret = -ENOMEM;
1008 goto done;
1009 }
1010
1011 /*
1012 * cmd 50 00
1013 * length 34 00
1014 * sequence xx xx
1015 * result 00 00
1016 * BSS id 00 13 19 80 da 30
1017 * capabilities 11 00
1018 * listen interval 0a 00
1019 * beacon interval 00 00
1020 * DTIM period 00
1021 * TLVs xx (up to 512 bytes)
1022 */
1023 cmd->hdr.command = cpu_to_le16(CMD_802_11_ASSOCIATE);
1024
1025 /* Fill in static fields */
1026 memcpy(cmd->bssid, bss->bssid, ETH_ALEN);
1027 cmd->listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL);
1028 cmd->capability = cpu_to_le16(bss->capability);
1029
1030 /* add SSID TLV */
1031 ssid_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SSID);
1032 if (ssid_eid)
1033 pos += lbs_add_ssid_tlv(pos, ssid_eid + 2, ssid_eid[1]);
1034 else
1035 lbs_deb_assoc("no SSID\n");
1036
1037 /* add DS param TLV */
1038 if (bss->channel)
1039 pos += lbs_add_channel_tlv(pos, bss->channel->hw_value);
1040 else
1041 lbs_deb_assoc("no channel\n");
1042
1043 /* add (empty) CF param TLV */
1044 pos += lbs_add_cf_param_tlv(pos);
1045
1046 /* add rates TLV */
1047 pos += lbs_add_common_rates_tlv(pos, bss);
1048
1049 /* add auth type TLV */
1050 if (priv->fwrelease >= 0x09000000)
1051 pos += lbs_add_auth_type_tlv(pos, sme->auth_type);
1052
1053 /* add WPA/WPA2 TLV */
1054 if (sme->ie && sme->ie_len)
1055 pos += lbs_add_wpa_tlv(pos, sme->ie, sme->ie_len);
1056
1057 len = (sizeof(*cmd) - sizeof(cmd->iebuf)) +
1058 (u16)(pos - (u8 *) &cmd->iebuf);
1059 cmd->hdr.size = cpu_to_le16(len);
1060
1061 /* store for later use */
1062 memcpy(priv->assoc_bss, bss->bssid, ETH_ALEN);
1063
1064 ret = lbs_cmd_with_response(priv, CMD_802_11_ASSOCIATE, cmd);
1065 if (ret)
1066 goto done;
1067
1068
1069 /* generate connect message to cfg80211 */
1070
1071 resp = (void *) cmd; /* recast for easier field access */
1072 status = le16_to_cpu(resp->statuscode);
1073
1074 /* Convert statis code of old firmware */
1075 if (priv->fwrelease < 0x09000000)
1076 switch (status) {
1077 case 0:
1078 break;
1079 case 1:
1080 lbs_deb_assoc("invalid association parameters\n");
1081 status = WLAN_STATUS_CAPS_UNSUPPORTED;
1082 break;
1083 case 2:
1084 lbs_deb_assoc("timer expired while waiting for AP\n");
1085 status = WLAN_STATUS_AUTH_TIMEOUT;
1086 break;
1087 case 3:
1088 lbs_deb_assoc("association refused by AP\n");
1089 status = WLAN_STATUS_ASSOC_DENIED_UNSPEC;
1090 break;
1091 case 4:
1092 lbs_deb_assoc("authentication refused by AP\n");
1093 status = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
1094 break;
1095 default:
1096 lbs_deb_assoc("association failure %d\n", status);
1097 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
1098 }
1099
1100 lbs_deb_assoc("status %d, capability 0x%04x\n", status,
1101 le16_to_cpu(resp->capability));
1102
1103 resp_ie_len = le16_to_cpu(resp->hdr.size)
1104 - sizeof(resp->hdr)
1105 - 6;
1106 cfg80211_connect_result(priv->dev,
1107 priv->assoc_bss,
1108 sme->ie, sme->ie_len,
1109 resp->iebuf, resp_ie_len,
1110 status,
1111 GFP_KERNEL);
1112
1113 if (status == 0) {
1114 /* TODO: get rid of priv->connect_status */
1115 priv->connect_status = LBS_CONNECTED;
1116 netif_carrier_on(priv->dev);
1117 if (!priv->tx_pending_len)
1118 netif_tx_wake_all_queues(priv->dev);
1119 }
1120
1121
1122done:
1123 lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
1124 return ret;
1125}
1126
1127
1128
1129static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
1130 struct cfg80211_connect_params *sme)
1131{
1132 struct lbs_private *priv = wiphy_priv(wiphy);
1133 struct cfg80211_bss *bss = NULL;
1134 int ret = 0;
1135 u8 preamble = RADIO_PREAMBLE_SHORT;
1136
1137 lbs_deb_enter(LBS_DEB_CFG80211);
1138
1139 if (sme->bssid) {
1140 bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
1141 sme->ssid, sme->ssid_len,
1142 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
1143 } else {
1144 /*
1145 * Here we have an impedance mismatch. The firmware command
1146 * CMD_802_11_ASSOCIATE always needs a BSSID, it cannot
1147 * connect otherwise. However, for the connect-API of
1148 * cfg80211 the bssid is purely optional. We don't get one,
1149 * except the user specifies one on the "iw" command line.
1150 *
1151 * If we don't got one, we could initiate a scan and look
1152 * for the best matching cfg80211_bss entry.
1153 *
1154 * Or, better yet, net/wireless/sme.c get's rewritten into
1155 * something more generally useful.
1156 */
1157 lbs_pr_err("TODO: no BSS specified\n");
1158 ret = -ENOTSUPP;
1159 goto done;
1160 }
1161
1162
1163 if (!bss) {
1164 lbs_pr_err("assicate: bss %pM not in scan results\n",
1165 sme->bssid);
1166 ret = -ENOENT;
1167 goto done;
1168 }
1169 lbs_deb_assoc("trying %pM", sme->bssid);
1170 lbs_deb_assoc("cipher 0x%x, key index %d, key len %d\n",
1171 sme->crypto.cipher_group,
1172 sme->key_idx, sme->key_len);
1173
1174 /* As this is a new connection, clear locally stored WEP keys */
1175 priv->wep_tx_key = 0;
1176 memset(priv->wep_key, 0, sizeof(priv->wep_key));
1177 memset(priv->wep_key_len, 0, sizeof(priv->wep_key_len));
1178
1179 /* set/remove WEP keys */
1180 switch (sme->crypto.cipher_group) {
1181 case WLAN_CIPHER_SUITE_WEP40:
1182 case WLAN_CIPHER_SUITE_WEP104:
1183 /* Store provided WEP keys in priv-> */
1184 priv->wep_tx_key = sme->key_idx;
1185 priv->wep_key_len[sme->key_idx] = sme->key_len;
1186 memcpy(priv->wep_key[sme->key_idx], sme->key, sme->key_len);
1187 /* Set WEP keys and WEP mode */
1188 lbs_set_wep_keys(priv);
1189 priv->mac_control |= CMD_ACT_MAC_WEP_ENABLE;
1190 lbs_set_mac_control(priv);
1191 /* No RSN mode for WEP */
1192 lbs_enable_rsn(priv, 0);
1193 break;
1194 case 0: /* there's no WLAN_CIPHER_SUITE_NONE definition */
1195 /*
1196 * If we don't have no WEP, no WPA and no WPA2,
1197 * we remove all keys like in the WPA/WPA2 setup,
1198 * we just don't set RSN.
1199 *
1200 * Therefore: fall-throught
1201 */
1202 case WLAN_CIPHER_SUITE_TKIP:
1203 case WLAN_CIPHER_SUITE_CCMP:
1204 /* Remove WEP keys and WEP mode */
1205 lbs_remove_wep_keys(priv);
1206 priv->mac_control &= ~CMD_ACT_MAC_WEP_ENABLE;
1207 lbs_set_mac_control(priv);
1208
1209 /* clear the WPA/WPA2 keys */
1210 lbs_set_key_material(priv,
1211 KEY_TYPE_ID_WEP, /* doesn't matter */
1212 KEY_INFO_WPA_UNICAST,
1213 NULL, 0);
1214 lbs_set_key_material(priv,
1215 KEY_TYPE_ID_WEP, /* doesn't matter */
1216 KEY_INFO_WPA_MCAST,
1217 NULL, 0);
1218 /* RSN mode for WPA/WPA2 */
1219 lbs_enable_rsn(priv, sme->crypto.cipher_group != 0);
1220 break;
1221 default:
1222 lbs_pr_err("unsupported cipher group 0x%x\n",
1223 sme->crypto.cipher_group);
1224 ret = -ENOTSUPP;
1225 goto done;
1226 }
1227
1228 lbs_set_authtype(priv, sme);
1229 lbs_set_radio(priv, preamble, 1);
1230
1231 /* Do the actual association */
1232 lbs_associate(priv, bss, sme);
1233
1234 done:
1235 if (bss)
1236 cfg80211_put_bss(bss);
1237 lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
1238 return ret;
1239}
1240
1241
1242
1243
1244/* callback from lbs_cfg_disconnect() */
1245static int lbs_cfg_ret_disconnect(struct lbs_private *priv, unsigned long dummy,
1246 struct cmd_header *resp)
1247{
1248 lbs_deb_enter(LBS_DEB_CFG80211);
1249
1250 cfg80211_disconnected(priv->dev,
1251 priv->disassoc_reason,
1252 NULL, 0, /* TODO? */
1253 GFP_KERNEL);
1254
1255 /* TODO: get rid of priv->connect_status */
1256 priv->connect_status = LBS_CONNECTED;
1257
1258 lbs_deb_leave(LBS_DEB_CFG80211);
1259 return 0;
1260}
1261
1262
1263static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev,
1264 u16 reason_code)
1265{
1266 struct lbs_private *priv = wiphy_priv(wiphy);
1267 struct cmd_ds_802_11_deauthenticate cmd;
1268
1269 lbs_deb_enter_args(LBS_DEB_CFG80211, "reason_code %d", reason_code);
1270
1271 /* store for lbs_cfg_ret_disconnect() */
1272 priv->disassoc_reason = reason_code;
1273
1274 memset(&cmd, 0, sizeof(cmd));
1275 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
1276 /* Mildly ugly to use a locally store my own BSSID ... */
1277 memcpy(cmd.macaddr, &priv->assoc_bss, ETH_ALEN);
1278 cmd.reasoncode = cpu_to_le16(reason_code);
1279
1280 __lbs_cmd_async(priv, CMD_802_11_DEAUTHENTICATE,
1281 &cmd.hdr, sizeof(cmd),
1282 lbs_cfg_ret_disconnect, 0);
1283
1284 return 0;
1285}
1286
1287
1288static int lbs_cfg_set_default_key(struct wiphy *wiphy,
1289 struct net_device *netdev,
1290 u8 key_index)
1291{
1292 struct lbs_private *priv = wiphy_priv(wiphy);
1293
1294 lbs_deb_enter(LBS_DEB_CFG80211);
1295
1296 if (key_index != priv->wep_tx_key) {
1297 lbs_deb_assoc("set_default_key: to %d\n", key_index);
1298 priv->wep_tx_key = key_index;
1299 lbs_set_wep_keys(priv);
1300 }
1301
1302 return 0;
1303}
1304
1305
1306static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev,
1307 u8 idx, const u8 *mac_addr,
1308 struct key_params *params)
1309{
1310 struct lbs_private *priv = wiphy_priv(wiphy);
1311 u16 key_info;
1312 u16 key_type;
1313 int ret = 0;
1314
1315 lbs_deb_enter(LBS_DEB_CFG80211);
1316
1317 lbs_deb_assoc("add_key: cipher 0x%x, mac_addr %pM\n",
1318 params->cipher, mac_addr);
1319 lbs_deb_assoc("add_key: key index %d, key len %d\n",
1320 idx, params->key_len);
1321 if (params->key_len)
1322 lbs_deb_hex(LBS_DEB_CFG80211, "KEY",
1323 params->key, params->key_len);
1324
1325 lbs_deb_assoc("add_key: seq len %d\n", params->seq_len);
1326 if (params->seq_len)
1327 lbs_deb_hex(LBS_DEB_CFG80211, "SEQ",
1328 params->seq, params->seq_len);
1329
1330 switch (params->cipher) {
1331 case WLAN_CIPHER_SUITE_WEP40:
1332 case WLAN_CIPHER_SUITE_WEP104:
1333 /* actually compare if something has changed ... */
1334 if ((priv->wep_key_len[idx] != params->key_len) ||
1335 memcmp(priv->wep_key[idx],
1336 params->key, params->key_len) != 0) {
1337 priv->wep_key_len[idx] = params->key_len;
1338 memcpy(priv->wep_key[idx],
1339 params->key, params->key_len);
1340 lbs_set_wep_keys(priv);
1341 }
1342 break;
1343 case WLAN_CIPHER_SUITE_TKIP:
1344 case WLAN_CIPHER_SUITE_CCMP:
1345 key_info = KEY_INFO_WPA_ENABLED | ((idx == 0)
1346 ? KEY_INFO_WPA_UNICAST
1347 : KEY_INFO_WPA_MCAST);
1348 key_type = (params->cipher == WLAN_CIPHER_SUITE_TKIP)
1349 ? KEY_TYPE_ID_TKIP
1350 : KEY_TYPE_ID_AES;
1351 lbs_set_key_material(priv,
1352 key_type,
1353 key_info,
1354 params->key, params->key_len);
1355 break;
1356 default:
1357 lbs_pr_err("unhandled cipher 0x%x\n", params->cipher);
1358 ret = -ENOTSUPP;
1359 break;
1360 }
1361
1362 return ret;
1363}
1364
1365
1366static int lbs_cfg_del_key(struct wiphy *wiphy, struct net_device *netdev,
1367 u8 key_index, const u8 *mac_addr)
1368{
1369
1370 lbs_deb_enter(LBS_DEB_CFG80211);
1371
1372 lbs_deb_assoc("del_key: key_idx %d, mac_addr %pM\n",
1373 key_index, mac_addr);
1374
1375#ifdef TODO
1376 struct lbs_private *priv = wiphy_priv(wiphy);
1377 /*
1378 * I think can keep this a NO-OP, because:
1379
1380 * - we clear all keys whenever we do lbs_cfg_connect() anyway
1381 * - neither "iw" nor "wpa_supplicant" won't call this during
1382 * an ongoing connection
1383 * - TODO: but I have to check if this is still true when
1384 * I set the AP to periodic re-keying
1385 * - we've not kzallec() something when we've added a key at
1386 * lbs_cfg_connect() or lbs_cfg_add_key().
1387 *
1388 * This causes lbs_cfg_del_key() only called at disconnect time,
1389 * where we'd just waste time deleting a key that is not going
1390 * to be used anyway.
1391 */
1392 if (key_index < 3 && priv->wep_key_len[key_index]) {
1393 priv->wep_key_len[key_index] = 0;
1394 lbs_set_wep_keys(priv);
1395 }
1396#endif
1397
1398 return 0;
1399}
1400
1401
1402
1403/***************************************************************************
1404 * Monitor mode
1405 */
1406
1407/* like "struct cmd_ds_802_11_monitor_mode", but with cmd_header. Once we
1408 * get rid of WEXT, this should go into host.h */
1409struct cmd_monitor_mode {
1410 struct cmd_header hdr;
1411
1412 __le16 action;
1413 __le16 mode;
1414} __attribute__ ((packed));
1415
1416static int lbs_enable_monitor_mode(struct lbs_private *priv, int mode)
1417{
1418 struct cmd_monitor_mode cmd;
1419 int ret;
1420
1421 lbs_deb_enter(LBS_DEB_CFG80211);
1422
1423 /*
1424 * cmd 98 00
1425 * size 0c 00
1426 * sequence xx xx
1427 * result 00 00
1428 * action 01 00 ACT_SET
1429 * enable 01 00
1430 */
1431 memset(&cmd, 0, sizeof(cmd));
1432 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
1433 cmd.action = cpu_to_le16(CMD_ACT_SET);
1434 cmd.mode = cpu_to_le16(mode);
1435
1436 ret = lbs_cmd_with_response(priv, CMD_802_11_MONITOR_MODE, &cmd);
1437
1438 if (ret == 0)
1439 priv->dev->type = ARPHRD_IEEE80211_RADIOTAP;
1440 else
1441 priv->dev->type = ARPHRD_ETHER;
1442
1443 lbs_deb_leave(LBS_DEB_CFG80211);
1444 return ret;
1445}
1446
1447
1448
1449
1450
1451
1452/***************************************************************************
1453 * Get station
1454 */
1455
1456/*
1457 * Returns the signal or 0 in case of an error.
1458 */
1459
1460/* like "struct cmd_ds_802_11_rssi", but with cmd_header. Once we get rid
1461 * of WEXT, this should go into host.h */
1462struct cmd_rssi {
1463 struct cmd_header hdr;
1464
1465 __le16 n_or_snr;
1466 __le16 nf;
1467 __le16 avg_snr;
1468 __le16 avg_nf;
1469} __attribute__ ((packed));
1470
1471static int lbs_get_signal(struct lbs_private *priv, s8 *signal, s8 *noise)
1472{
1473 struct cmd_rssi cmd;
1474 int ret;
1475
1476 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
1477 cmd.n_or_snr = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR);
1478 ret = lbs_cmd_with_response(priv, CMD_802_11_RSSI, &cmd);
1479
1480 if (ret == 0) {
1481 *signal = CAL_RSSI(le16_to_cpu(cmd.n_or_snr),
1482 le16_to_cpu(cmd.nf));
1483 *noise = CAL_NF(le16_to_cpu(cmd.nf));
1484 }
1485 return ret;
1486}
1487
1488
1489static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev,
1490 u8 *mac, struct station_info *sinfo)
1491{
1492 struct lbs_private *priv = wiphy_priv(wiphy);
1493 s8 signal, noise;
1494 int ret;
1495 size_t i;
1496
1497 lbs_deb_enter(LBS_DEB_CFG80211);
1498
1499 sinfo->filled |= STATION_INFO_TX_BYTES |
1500 STATION_INFO_TX_PACKETS |
1501 STATION_INFO_RX_BYTES |
1502 STATION_INFO_RX_PACKETS;
1503 sinfo->tx_bytes = priv->dev->stats.tx_bytes;
1504 sinfo->tx_packets = priv->dev->stats.tx_packets;
1505 sinfo->rx_bytes = priv->dev->stats.rx_bytes;
1506 sinfo->rx_packets = priv->dev->stats.rx_packets;
1507
1508 /* Get current RSSI */
1509 ret = lbs_get_signal(priv, &signal, &noise);
1510 if (ret == 0) {
1511 sinfo->signal = signal;
1512 sinfo->filled |= STATION_INFO_SIGNAL;
1513 }
1514
1515 /* Convert priv->cur_rate from hw_value to NL80211 value */
1516 for (i = 0; i < ARRAY_SIZE(lbs_rates); i++) {
1517 if (priv->cur_rate == lbs_rates[i].hw_value) {
1518 sinfo->txrate.legacy = lbs_rates[i].bitrate;
1519 sinfo->filled |= STATION_INFO_TX_BITRATE;
1520 break;
1521 }
1522 }
1523
1524 return 0;
1525}
1526
1527
1528
1529
1530/***************************************************************************
1531 * "Site survey", here just current channel and noise level
1532 */
1533
1534static int lbs_get_survey(struct wiphy *wiphy, struct net_device *dev,
1535 int idx, struct survey_info *survey)
1536{
1537 struct lbs_private *priv = wiphy_priv(wiphy);
1538 s8 signal, noise;
1539 int ret;
1540
1541 if (idx != 0)
1542 ret = -ENOENT;
1543
1544 lbs_deb_enter(LBS_DEB_CFG80211);
1545
1546 survey->channel = ieee80211_get_channel(wiphy,
1547 ieee80211_channel_to_frequency(priv->channel));
1548
1549 ret = lbs_get_signal(priv, &signal, &noise);
1550 if (ret == 0) {
1551 survey->filled = SURVEY_INFO_NOISE_DBM;
1552 survey->noise = noise;
1553 }
1554
1555 lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
1556 return ret;
1557}
1558
1559
1560
1561
1562/***************************************************************************
1563 * Change interface
1564 */
1565
1566static int lbs_change_intf(struct wiphy *wiphy, struct net_device *dev,
1567 enum nl80211_iftype type, u32 *flags,
1568 struct vif_params *params)
1569{
1570 struct lbs_private *priv = wiphy_priv(wiphy);
1571 int ret = 0;
1572
1573 lbs_deb_enter(LBS_DEB_CFG80211);
1574
1575 switch (type) {
1576 case NL80211_IFTYPE_MONITOR:
1577 ret = lbs_enable_monitor_mode(priv, 1);
1578 break;
1579 case NL80211_IFTYPE_STATION:
1580 if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)
1581 ret = lbs_enable_monitor_mode(priv, 0);
1582 if (!ret)
1583 ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 1);
1584 break;
1585 case NL80211_IFTYPE_ADHOC:
1586 if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)
1587 ret = lbs_enable_monitor_mode(priv, 0);
1588 if (!ret)
1589 ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 2);
1590 break;
1591 default:
1592 ret = -ENOTSUPP;
1593 }
1594
1595 if (!ret)
1596 priv->wdev->iftype = type;
1597
1598 lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
1599 return ret;
1600}
1601
1602
1603
1604/***************************************************************************
1605 * IBSS (Ad-Hoc)
1606 */
1607
1608/* The firmware needs the following bits masked out of the beacon-derived
1609 * capability field when associating/joining to a BSS:
1610 * 9 (QoS), 11 (APSD), 12 (unused), 14 (unused), 15 (unused)
1611 */
1612#define CAPINFO_MASK (~(0xda00))
1613
1614
1615static void lbs_join_post(struct lbs_private *priv,
1616 struct cfg80211_ibss_params *params,
1617 u8 *bssid, u16 capability)
1618{
1619 u8 fake_ie[2 + IEEE80211_MAX_SSID_LEN + /* ssid */
1620 2 + 4 + /* basic rates */
1621 2 + 1 + /* DS parameter */
1622 2 + 2 + /* atim */
1623 2 + 8]; /* extended rates */
1624 u8 *fake = fake_ie;
1625
1626 lbs_deb_enter(LBS_DEB_CFG80211);
1627
1628 /*
1629 * For cfg80211_inform_bss, we'll need a fake IE, as we can't get
1630 * the real IE from the firmware. So we fabricate a fake IE based on
1631 * what the firmware actually sends (sniffed with wireshark).
1632 */
1633 /* Fake SSID IE */
1634 *fake++ = WLAN_EID_SSID;
1635 *fake++ = params->ssid_len;
1636 memcpy(fake, params->ssid, params->ssid_len);
1637 fake += params->ssid_len;
1638 /* Fake supported basic rates IE */
1639 *fake++ = WLAN_EID_SUPP_RATES;
1640 *fake++ = 4;
1641 *fake++ = 0x82;
1642 *fake++ = 0x84;
1643 *fake++ = 0x8b;
1644 *fake++ = 0x96;
1645 /* Fake DS channel IE */
1646 *fake++ = WLAN_EID_DS_PARAMS;
1647 *fake++ = 1;
1648 *fake++ = params->channel->hw_value;
1649 /* Fake IBSS params IE */
1650 *fake++ = WLAN_EID_IBSS_PARAMS;
1651 *fake++ = 2;
1652 *fake++ = 0; /* ATIM=0 */
1653 *fake++ = 0;
1654 /* Fake extended rates IE, TODO: don't add this for 802.11b only,
1655 * but I don't know how this could be checked */
1656 *fake++ = WLAN_EID_EXT_SUPP_RATES;
1657 *fake++ = 8;
1658 *fake++ = 0x0c;
1659 *fake++ = 0x12;
1660 *fake++ = 0x18;
1661 *fake++ = 0x24;
1662 *fake++ = 0x30;
1663 *fake++ = 0x48;
1664 *fake++ = 0x60;
1665 *fake++ = 0x6c;
1666 lbs_deb_hex(LBS_DEB_CFG80211, "IE", fake_ie, fake - fake_ie);
1667
1668 cfg80211_inform_bss(priv->wdev->wiphy,
1669 params->channel,
1670 bssid,
1671 0,
1672 capability,
1673 params->beacon_interval,
1674 fake_ie, fake - fake_ie,
1675 0, GFP_KERNEL);
1676 cfg80211_ibss_joined(priv->dev, bssid, GFP_KERNEL);
1677
1678 /* TODO: consider doing this at MACREG_INT_CODE_LINK_SENSED time */
1679 priv->connect_status = LBS_CONNECTED;
1680 netif_carrier_on(priv->dev);
1681 if (!priv->tx_pending_len)
1682 netif_wake_queue(priv->dev);
1683
1684 lbs_deb_leave(LBS_DEB_CFG80211);
1685}
1686
1687static int lbs_ibss_join_existing(struct lbs_private *priv,
1688 struct cfg80211_ibss_params *params,
1689 struct cfg80211_bss *bss)
1690{
1691 const u8 *rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
1692 struct cmd_ds_802_11_ad_hoc_join cmd;
1693 u8 preamble = RADIO_PREAMBLE_SHORT;
1694 int ret = 0;
1695
1696 lbs_deb_enter(LBS_DEB_CFG80211);
1697
1698 /* TODO: set preamble based on scan result */
1699 ret = lbs_set_radio(priv, preamble, 1);
1700 if (ret)
1701 goto out;
1702
1703 /*
1704 * Example CMD_802_11_AD_HOC_JOIN command:
1705 *
1706 * command 2c 00 CMD_802_11_AD_HOC_JOIN
1707 * size 65 00
1708 * sequence xx xx
1709 * result 00 00
1710 * bssid 02 27 27 97 2f 96
1711 * ssid 49 42 53 53 00 00 00 00
1712 * 00 00 00 00 00 00 00 00
1713 * 00 00 00 00 00 00 00 00
1714 * 00 00 00 00 00 00 00 00
1715 * type 02 CMD_BSS_TYPE_IBSS
1716 * beacon period 64 00
1717 * dtim period 00
1718 * timestamp 00 00 00 00 00 00 00 00
1719 * localtime 00 00 00 00 00 00 00 00
1720 * IE DS 03
1721 * IE DS len 01
1722 * IE DS channel 01
1723 * reserveed 00 00 00 00
1724 * IE IBSS 06
1725 * IE IBSS len 02
1726 * IE IBSS atim 00 00
1727 * reserved 00 00 00 00
1728 * capability 02 00
1729 * rates 82 84 8b 96 0c 12 18 24 30 48 60 6c 00
1730 * fail timeout ff 00
1731 * probe delay 00 00
1732 */
1733 memset(&cmd, 0, sizeof(cmd));
1734 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
1735
1736 memcpy(cmd.bss.bssid, bss->bssid, ETH_ALEN);
1737 memcpy(cmd.bss.ssid, params->ssid, params->ssid_len);
1738 cmd.bss.type = CMD_BSS_TYPE_IBSS;
1739 cmd.bss.beaconperiod = cpu_to_le16(params->beacon_interval);
1740 cmd.bss.ds.header.id = WLAN_EID_DS_PARAMS;
1741 cmd.bss.ds.header.len = 1;
1742 cmd.bss.ds.channel = params->channel->hw_value;
1743 cmd.bss.ibss.header.id = WLAN_EID_IBSS_PARAMS;
1744 cmd.bss.ibss.header.len = 2;
1745 cmd.bss.ibss.atimwindow = 0;
1746 cmd.bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK);
1747
1748 /* set rates to the intersection of our rates and the rates in the
1749 bss */
1750 if (!rates_eid) {
1751 lbs_add_rates(cmd.bss.rates);
1752 } else {
1753 int hw, i;
1754 u8 rates_max = rates_eid[1];
1755 u8 *rates = cmd.bss.rates;
1756 for (hw = 0; hw < ARRAY_SIZE(lbs_rates); hw++) {
1757 u8 hw_rate = lbs_rates[hw].bitrate / 5;
1758 for (i = 0; i < rates_max; i++) {
1759 if (hw_rate == (rates_eid[i+2] & 0x7f)) {
1760 u8 rate = rates_eid[i+2];
1761 if (rate == 0x02 || rate == 0x04 ||
1762 rate == 0x0b || rate == 0x16)
1763 rate |= 0x80;
1764 *rates++ = rate;
1765 }
1766 }
1767 }
1768 }
1769
1770 /* Only v8 and below support setting this */
1771 if (MRVL_FW_MAJOR_REV(priv->fwrelease) <= 8) {
1772 cmd.failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
1773 cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
1774 }
1775 ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd);
1776 if (ret)
1777 goto out;
1778
1779 /*
1780 * This is a sample response to CMD_802_11_AD_HOC_JOIN:
1781 *
1782 * response 2c 80
1783 * size 09 00
1784 * sequence xx xx
1785 * result 00 00
1786 * reserved 00
1787 */
1788 lbs_join_post(priv, params, bss->bssid, bss->capability);
1789
1790 out:
1791 lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
1792 return ret;
1793}
1794
1795
1796
1797static int lbs_ibss_start_new(struct lbs_private *priv,
1798 struct cfg80211_ibss_params *params)
1799{
1800 struct cmd_ds_802_11_ad_hoc_start cmd;
1801 struct cmd_ds_802_11_ad_hoc_result *resp =
1802 (struct cmd_ds_802_11_ad_hoc_result *) &cmd;
1803 u8 preamble = RADIO_PREAMBLE_SHORT;
1804 int ret = 0;
1805 u16 capability;
1806
1807 lbs_deb_enter(LBS_DEB_CFG80211);
1808
1809 ret = lbs_set_radio(priv, preamble, 1);
1810 if (ret)
1811 goto out;
1812
1813 /*
1814 * Example CMD_802_11_AD_HOC_START command:
1815 *
1816 * command 2b 00 CMD_802_11_AD_HOC_START
1817 * size b1 00
1818 * sequence xx xx
1819 * result 00 00
1820 * ssid 54 45 53 54 00 00 00 00
1821 * 00 00 00 00 00 00 00 00
1822 * 00 00 00 00 00 00 00 00
1823 * 00 00 00 00 00 00 00 00
1824 * bss type 02
1825 * beacon period 64 00
1826 * dtim period 00
1827 * IE IBSS 06
1828 * IE IBSS len 02
1829 * IE IBSS atim 00 00
1830 * reserved 00 00 00 00
1831 * IE DS 03
1832 * IE DS len 01
1833 * IE DS channel 01
1834 * reserved 00 00 00 00
1835 * probe delay 00 00
1836 * capability 02 00
1837 * rates 82 84 8b 96 (basic rates with have bit 7 set)
1838 * 0c 12 18 24 30 48 60 6c
1839 * padding 100 bytes
1840 */
1841 memset(&cmd, 0, sizeof(cmd));
1842 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
1843 memcpy(cmd.ssid, params->ssid, params->ssid_len);
1844 cmd.bsstype = CMD_BSS_TYPE_IBSS;
1845 cmd.beaconperiod = cpu_to_le16(params->beacon_interval);
1846 cmd.ibss.header.id = WLAN_EID_IBSS_PARAMS;
1847 cmd.ibss.header.len = 2;
1848 cmd.ibss.atimwindow = 0;
1849 cmd.ds.header.id = WLAN_EID_DS_PARAMS;
1850 cmd.ds.header.len = 1;
1851 cmd.ds.channel = params->channel->hw_value;
1852 /* Only v8 and below support setting probe delay */
1853 if (MRVL_FW_MAJOR_REV(priv->fwrelease) <= 8)
1854 cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
1855 /* TODO: mix in WLAN_CAPABILITY_PRIVACY */
1856 capability = WLAN_CAPABILITY_IBSS;
1857 cmd.capability = cpu_to_le16(capability);
1858 lbs_add_rates(cmd.rates);
1859
1860
1861 ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_START, &cmd);
1862 if (ret)
1863 goto out;
1864
1865 /*
1866 * This is a sample response to CMD_802_11_AD_HOC_JOIN:
1867 *
1868 * response 2b 80
1869 * size 14 00
1870 * sequence xx xx
1871 * result 00 00
1872 * reserved 00
1873 * bssid 02 2b 7b 0f 86 0e
1874 */
1875 lbs_join_post(priv, params, resp->bssid, capability);
95 1876
96 out: 1877 out:
97 lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); 1878 lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
@@ -99,10 +1880,83 @@ static int lbs_cfg_set_channel(struct wiphy *wiphy,
99} 1880}
100 1881
101 1882
1883static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev,
1884 struct cfg80211_ibss_params *params)
1885{
1886 struct lbs_private *priv = wiphy_priv(wiphy);
1887 int ret = 0;
1888 struct cfg80211_bss *bss;
1889 DECLARE_SSID_BUF(ssid_buf);
1890
1891 lbs_deb_enter(LBS_DEB_CFG80211);
1892
1893 if (!params->channel) {
1894 ret = -ENOTSUPP;
1895 goto out;
1896 }
1897
1898 ret = lbs_set_channel(priv, params->channel->hw_value);
1899 if (ret)
1900 goto out;
1901
1902 /* Search if someone is beaconing. This assumes that the
1903 * bss list is populated already */
1904 bss = cfg80211_get_bss(wiphy, params->channel, params->bssid,
1905 params->ssid, params->ssid_len,
1906 WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS);
102 1907
1908 if (bss) {
1909 ret = lbs_ibss_join_existing(priv, params, bss);
1910 cfg80211_put_bss(bss);
1911 } else
1912 ret = lbs_ibss_start_new(priv, params);
1913
1914
1915 out:
1916 lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
1917 return ret;
1918}
1919
1920
1921static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
1922{
1923 struct lbs_private *priv = wiphy_priv(wiphy);
1924 struct cmd_ds_802_11_ad_hoc_stop cmd;
1925 int ret = 0;
1926
1927 lbs_deb_enter(LBS_DEB_CFG80211);
1928
1929 memset(&cmd, 0, sizeof(cmd));
1930 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
1931 ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_STOP, &cmd);
1932
1933 /* TODO: consider doing this at MACREG_INT_CODE_ADHOC_BCN_LOST time */
1934 lbs_mac_event_disconnected(priv);
1935
1936 lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
1937 return ret;
1938}
1939
1940
1941
1942
1943/***************************************************************************
1944 * Initialization
1945 */
103 1946
104static struct cfg80211_ops lbs_cfg80211_ops = { 1947static struct cfg80211_ops lbs_cfg80211_ops = {
105 .set_channel = lbs_cfg_set_channel, 1948 .set_channel = lbs_cfg_set_channel,
1949 .scan = lbs_cfg_scan,
1950 .connect = lbs_cfg_connect,
1951 .disconnect = lbs_cfg_disconnect,
1952 .add_key = lbs_cfg_add_key,
1953 .del_key = lbs_cfg_del_key,
1954 .set_default_key = lbs_cfg_set_default_key,
1955 .get_station = lbs_cfg_get_station,
1956 .dump_survey = lbs_get_survey,
1957 .change_virtual_intf = lbs_change_intf,
1958 .join_ibss = lbs_join_ibss,
1959 .leave_ibss = lbs_leave_ibss,
106}; 1960};
107 1961
108 1962
@@ -142,6 +1996,36 @@ struct wireless_dev *lbs_cfg_alloc(struct device *dev)
142} 1996}
143 1997
144 1998
1999static void lbs_cfg_set_regulatory_hint(struct lbs_private *priv)
2000{
2001 struct region_code_mapping {
2002 const char *cn;
2003 int code;
2004 };
2005
2006 /* Section 5.17.2 */
2007 static struct region_code_mapping regmap[] = {
2008 {"US ", 0x10}, /* US FCC */
2009 {"CA ", 0x20}, /* Canada */
2010 {"EU ", 0x30}, /* ETSI */
2011 {"ES ", 0x31}, /* Spain */
2012 {"FR ", 0x32}, /* France */
2013 {"JP ", 0x40}, /* Japan */
2014 };
2015 size_t i;
2016
2017 lbs_deb_enter(LBS_DEB_CFG80211);
2018
2019 for (i = 0; i < ARRAY_SIZE(regmap); i++)
2020 if (regmap[i].code == priv->regioncode) {
2021 regulatory_hint(priv->wdev->wiphy, regmap[i].cn);
2022 break;
2023 }
2024
2025 lbs_deb_leave(LBS_DEB_CFG80211);
2026}
2027
2028
145/* 2029/*
146 * This function get's called after lbs_setup_firmware() determined the 2030 * This function get's called after lbs_setup_firmware() determined the
147 * firmware capabities. So we can setup the wiphy according to our 2031 * firmware capabities. So we can setup the wiphy according to our
@@ -157,10 +2041,12 @@ int lbs_cfg_register(struct lbs_private *priv)
157 wdev->wiphy->max_scan_ssids = 1; 2041 wdev->wiphy->max_scan_ssids = 1;
158 wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; 2042 wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
159 2043
160 /* TODO: BIT(NL80211_IFTYPE_ADHOC); */ 2044 wdev->wiphy->interface_modes =
161 wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); 2045 BIT(NL80211_IFTYPE_STATION) |
2046 BIT(NL80211_IFTYPE_ADHOC);
2047 if (lbs_rtap_supported(priv))
2048 wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
162 2049
163 /* TODO: honor priv->regioncode */
164 wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &lbs_band_2ghz; 2050 wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &lbs_band_2ghz;
165 2051
166 /* 2052 /*
@@ -180,11 +2066,22 @@ int lbs_cfg_register(struct lbs_private *priv)
180 if (ret) 2066 if (ret)
181 lbs_pr_err("cannot register network device\n"); 2067 lbs_pr_err("cannot register network device\n");
182 2068
2069 INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker);
2070
2071 lbs_cfg_set_regulatory_hint(priv);
2072
183 lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); 2073 lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
184 return ret; 2074 return ret;
185} 2075}
186 2076
187 2077
2078void lbs_scan_deinit(struct lbs_private *priv)
2079{
2080 lbs_deb_enter(LBS_DEB_CFG80211);
2081 cancel_delayed_work_sync(&priv->scan_work);
2082}
2083
2084
188void lbs_cfg_free(struct lbs_private *priv) 2085void lbs_cfg_free(struct lbs_private *priv)
189{ 2086{
190 struct wireless_dev *wdev = priv->wdev; 2087 struct wireless_dev *wdev = priv->wdev;
diff --git a/drivers/net/wireless/libertas/cfg.h b/drivers/net/wireless/libertas/cfg.h
index e09a193a34d6..eae3fd911abb 100644
--- a/drivers/net/wireless/libertas/cfg.h
+++ b/drivers/net/wireless/libertas/cfg.h
@@ -1,16 +1,22 @@
1#ifndef __LBS_CFG80211_H__ 1#ifndef __LBS_CFG80211_H__
2#define __LBS_CFG80211_H__ 2#define __LBS_CFG80211_H__
3 3
4#include "dev.h" 4struct device;
5struct lbs_private;
5 6
6struct wireless_dev *lbs_cfg_alloc(struct device *dev); 7struct wireless_dev *lbs_cfg_alloc(struct device *dev);
7int lbs_cfg_register(struct lbs_private *priv); 8int lbs_cfg_register(struct lbs_private *priv);
8void lbs_cfg_free(struct lbs_private *priv); 9void lbs_cfg_free(struct lbs_private *priv);
9 10
10int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid, 11/* All of those are TODOs: */
11 u8 ssid_len); 12#define lbs_cmd_802_11_rssi(priv, cmdptr) (0)
12int lbs_scan_networks(struct lbs_private *priv, int full_scan); 13#define lbs_ret_802_11_rssi(priv, resp) (0)
13void lbs_cfg_scan_worker(struct work_struct *work); 14#define lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action) (0)
15#define lbs_ret_802_11_bcn_ctrl(priv, resp) (0)
14 16
17void lbs_send_disconnect_notification(struct lbs_private *priv);
18void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event);
19
20void lbs_scan_deinit(struct lbs_private *priv);
15 21
16#endif 22#endif
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index 0fa6b0e59ea5..d8838461e596 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -7,13 +7,8 @@
7#include <linux/sched.h> 7#include <linux/sched.h>
8#include <linux/slab.h> 8#include <linux/slab.h>
9 9
10#include "host.h"
11#include "decl.h" 10#include "decl.h"
12#include "defs.h" 11#include "cfg.h"
13#include "dev.h"
14#include "assoc.h"
15#include "wext.h"
16#include "scan.h"
17#include "cmd.h" 12#include "cmd.h"
18 13
19 14
@@ -177,11 +172,6 @@ int lbs_update_hw_spec(struct lbs_private *priv)
177 if (priv->mesh_dev) 172 if (priv->mesh_dev)
178 memcpy(priv->mesh_dev->dev_addr, priv->current_addr, ETH_ALEN); 173 memcpy(priv->mesh_dev->dev_addr, priv->current_addr, ETH_ALEN);
179 174
180 if (lbs_set_regiontable(priv, priv->regioncode, 0)) {
181 ret = -1;
182 goto out;
183 }
184
185out: 175out:
186 lbs_deb_leave(LBS_DEB_CMD); 176 lbs_deb_leave(LBS_DEB_CMD);
187 return ret; 177 return ret;
@@ -1325,6 +1315,15 @@ int lbs_execute_next_command(struct lbs_private *priv)
1325 * check if in power save mode, if yes, put the device back 1315 * check if in power save mode, if yes, put the device back
1326 * to PS mode 1316 * to PS mode
1327 */ 1317 */
1318#ifdef TODO
1319 /*
1320 * This was the old code for libertas+wext. Someone that
1321 * understands this beast should re-code it in a sane way.
1322 *
1323 * I actually don't understand why this is related to WPA
1324 * and to connection status, shouldn't powering should be
1325 * independ of such things?
1326 */
1328 if ((priv->psmode != LBS802_11POWERMODECAM) && 1327 if ((priv->psmode != LBS802_11POWERMODECAM) &&
1329 (priv->psstate == PS_STATE_FULL_POWER) && 1328 (priv->psstate == PS_STATE_FULL_POWER) &&
1330 ((priv->connect_status == LBS_CONNECTED) || 1329 ((priv->connect_status == LBS_CONNECTED) ||
@@ -1346,6 +1345,7 @@ int lbs_execute_next_command(struct lbs_private *priv)
1346 lbs_ps_sleep(priv, 0); 1345 lbs_ps_sleep(priv, 0);
1347 } 1346 }
1348 } 1347 }
1348#endif
1349 } 1349 }
1350 1350
1351 ret = 0; 1351 ret = 0;
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index d6c306353640..9c18227ecc75 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -5,18 +5,10 @@
5#include <linux/slab.h> 5#include <linux/slab.h>
6#include <linux/delay.h> 6#include <linux/delay.h>
7#include <linux/sched.h> 7#include <linux/sched.h>
8#include <linux/if_arp.h>
9#include <linux/netdevice.h>
10#include <asm/unaligned.h> 8#include <asm/unaligned.h>
11#include <net/iw_handler.h> 9#include <net/cfg80211.h>
12 10
13#include "host.h" 11#include "cfg.h"
14#include "decl.h"
15#include "cmd.h"
16#include "defs.h"
17#include "dev.h"
18#include "assoc.h"
19#include "wext.h"
20#include "cmd.h" 12#include "cmd.h"
21 13
22/** 14/**
@@ -50,23 +42,8 @@ void lbs_mac_event_disconnected(struct lbs_private *priv)
50 priv->currenttxskb = NULL; 42 priv->currenttxskb = NULL;
51 priv->tx_pending_len = 0; 43 priv->tx_pending_len = 0;
52 44
53 /* reset SNR/NF/RSSI values */
54 memset(priv->SNR, 0x00, sizeof(priv->SNR));
55 memset(priv->NF, 0x00, sizeof(priv->NF));
56 memset(priv->RSSI, 0x00, sizeof(priv->RSSI));
57 memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR));
58 memset(priv->rawNF, 0x00, sizeof(priv->rawNF));
59 priv->nextSNRNF = 0;
60 priv->numSNRNF = 0;
61 priv->connect_status = LBS_DISCONNECTED; 45 priv->connect_status = LBS_DISCONNECTED;
62 46
63 /* Clear out associated SSID and BSSID since connection is
64 * no longer valid.
65 */
66 memset(&priv->curbssparams.bssid, 0, ETH_ALEN);
67 memset(&priv->curbssparams.ssid, 0, IEEE80211_MAX_SSID_LEN);
68 priv->curbssparams.ssid_len = 0;
69
70 if (priv->psstate != PS_STATE_FULL_POWER) { 47 if (priv->psstate != PS_STATE_FULL_POWER) {
71 /* make firmware to exit PS mode */ 48 /* make firmware to exit PS mode */
72 lbs_deb_cmd("disconnected, so exit PS mode\n"); 49 lbs_deb_cmd("disconnected, so exit PS mode\n");
@@ -262,7 +239,7 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
262 * ad-hoc mode. It takes place in 239 * ad-hoc mode. It takes place in
263 * lbs_execute_next_command(). 240 * lbs_execute_next_command().
264 */ 241 */
265 if (priv->mode == IW_MODE_ADHOC && 242 if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR &&
266 action == CMD_SUBCMD_ENTER_PS) 243 action == CMD_SUBCMD_ENTER_PS)
267 priv->psmode = LBS802_11POWERMODECAM; 244 priv->psmode = LBS802_11POWERMODECAM;
268 } else if (action == CMD_SUBCMD_ENTER_PS) { 245 } else if (action == CMD_SUBCMD_ENTER_PS) {
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
index de2caac11dd6..17367463c855 100644
--- a/drivers/net/wireless/libertas/debugfs.c
+++ b/drivers/net/wireless/libertas/debugfs.c
@@ -1,18 +1,13 @@
1#include <linux/module.h>
2#include <linux/dcache.h> 1#include <linux/dcache.h>
3#include <linux/debugfs.h> 2#include <linux/debugfs.h>
4#include <linux/delay.h> 3#include <linux/delay.h>
5#include <linux/mm.h> 4#include <linux/mm.h>
6#include <linux/string.h> 5#include <linux/string.h>
7#include <linux/slab.h> 6#include <linux/slab.h>
8#include <net/iw_handler.h>
9#include <net/lib80211.h>
10 7
11#include "dev.h"
12#include "decl.h" 8#include "decl.h"
13#include "host.h"
14#include "debugfs.h"
15#include "cmd.h" 9#include "cmd.h"
10#include "debugfs.h"
16 11
17static struct dentry *lbs_dir; 12static struct dentry *lbs_dir;
18static char *szStates[] = { 13static char *szStates[] = {
@@ -60,51 +55,6 @@ static ssize_t lbs_dev_info(struct file *file, char __user *userbuf,
60 return res; 55 return res;
61} 56}
62 57
63
64static ssize_t lbs_getscantable(struct file *file, char __user *userbuf,
65 size_t count, loff_t *ppos)
66{
67 struct lbs_private *priv = file->private_data;
68 size_t pos = 0;
69 int numscansdone = 0, res;
70 unsigned long addr = get_zeroed_page(GFP_KERNEL);
71 char *buf = (char *)addr;
72 DECLARE_SSID_BUF(ssid);
73 struct bss_descriptor * iter_bss;
74 if (!buf)
75 return -ENOMEM;
76
77 pos += snprintf(buf+pos, len-pos,
78 "# | ch | rssi | bssid | cap | Qual | SSID\n");
79
80 mutex_lock(&priv->lock);
81 list_for_each_entry (iter_bss, &priv->network_list, list) {
82 u16 ibss = (iter_bss->capability & WLAN_CAPABILITY_IBSS);
83 u16 privacy = (iter_bss->capability & WLAN_CAPABILITY_PRIVACY);
84 u16 spectrum_mgmt = (iter_bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT);
85
86 pos += snprintf(buf+pos, len-pos, "%02u| %03d | %04d | %pM |",
87 numscansdone, iter_bss->channel, iter_bss->rssi,
88 iter_bss->bssid);
89 pos += snprintf(buf+pos, len-pos, " %04x-", iter_bss->capability);
90 pos += snprintf(buf+pos, len-pos, "%c%c%c |",
91 ibss ? 'A' : 'I', privacy ? 'P' : ' ',
92 spectrum_mgmt ? 'S' : ' ');
93 pos += snprintf(buf+pos, len-pos, " %04d |", SCAN_RSSI(iter_bss->rssi));
94 pos += snprintf(buf+pos, len-pos, " %s\n",
95 print_ssid(ssid, iter_bss->ssid,
96 iter_bss->ssid_len));
97
98 numscansdone++;
99 }
100 mutex_unlock(&priv->lock);
101
102 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
103
104 free_page(addr);
105 return res;
106}
107
108static ssize_t lbs_sleepparams_write(struct file *file, 58static ssize_t lbs_sleepparams_write(struct file *file,
109 const char __user *user_buf, size_t count, 59 const char __user *user_buf, size_t count,
110 loff_t *ppos) 60 loff_t *ppos)
@@ -723,8 +673,6 @@ struct lbs_debugfs_files {
723 673
724static const struct lbs_debugfs_files debugfs_files[] = { 674static const struct lbs_debugfs_files debugfs_files[] = {
725 { "info", 0444, FOPS(lbs_dev_info, write_file_dummy), }, 675 { "info", 0444, FOPS(lbs_dev_info, write_file_dummy), },
726 { "getscantable", 0444, FOPS(lbs_getscantable,
727 write_file_dummy), },
728 { "sleepparams", 0644, FOPS(lbs_sleepparams_read, 676 { "sleepparams", 0644, FOPS(lbs_sleepparams_read,
729 lbs_sleepparams_write), }, 677 lbs_sleepparams_write), },
730}; 678};
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index 61db8bc62b3c..85c97d3ed88d 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -1,3 +1,4 @@
1
1/** 2/**
2 * This file contains declaration referring to 3 * This file contains declaration referring to
3 * functions defined in other source files 4 * functions defined in other source files
@@ -34,6 +35,8 @@ int lbs_start_card(struct lbs_private *priv);
34void lbs_stop_card(struct lbs_private *priv); 35void lbs_stop_card(struct lbs_private *priv);
35void lbs_host_to_card_done(struct lbs_private *priv); 36void lbs_host_to_card_done(struct lbs_private *priv);
36 37
38int lbs_rtap_supported(struct lbs_private *priv);
39
37int lbs_set_mac_address(struct net_device *dev, void *addr); 40int lbs_set_mac_address(struct net_device *dev, void *addr);
38void lbs_set_multicast_list(struct net_device *dev); 41void lbs_set_multicast_list(struct net_device *dev);
39 42
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index 71c5ad46ebf6..be263acf19c4 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -7,8 +7,8 @@
7#define _LBS_DEV_H_ 7#define _LBS_DEV_H_
8 8
9#include "mesh.h" 9#include "mesh.h"
10#include "scan.h" 10#include "defs.h"
11#include "assoc.h" 11#include "host.h"
12 12
13#include <linux/kfifo.h> 13#include <linux/kfifo.h>
14 14
@@ -29,7 +29,6 @@ struct lbs_private {
29 /* Basic networking */ 29 /* Basic networking */
30 struct net_device *dev; 30 struct net_device *dev;
31 u32 connect_status; 31 u32 connect_status;
32 int infra_open;
33 struct work_struct mcast_work; 32 struct work_struct mcast_work;
34 u32 nr_of_multicastmacaddr; 33 u32 nr_of_multicastmacaddr;
35 u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN]; 34 u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
@@ -37,6 +36,9 @@ struct lbs_private {
37 /* CFG80211 */ 36 /* CFG80211 */
38 struct wireless_dev *wdev; 37 struct wireless_dev *wdev;
39 bool wiphy_registered; 38 bool wiphy_registered;
39 struct cfg80211_scan_request *scan_req;
40 u8 assoc_bss[ETH_ALEN];
41 u8 disassoc_reason;
40 42
41 /* Mesh */ 43 /* Mesh */
42 struct net_device *mesh_dev; /* Virtual device */ 44 struct net_device *mesh_dev; /* Virtual device */
@@ -49,10 +51,6 @@ struct lbs_private {
49 u8 mesh_ssid_len; 51 u8 mesh_ssid_len;
50#endif 52#endif
51 53
52 /* Monitor mode */
53 struct net_device *rtap_net_dev;
54 u32 monitormode;
55
56 /* Debugfs */ 54 /* Debugfs */
57 struct dentry *debugfs_dir; 55 struct dentry *debugfs_dir;
58 struct dentry *debugfs_debug; 56 struct dentry *debugfs_debug;
@@ -133,14 +131,10 @@ struct lbs_private {
133 struct workqueue_struct *work_thread; 131 struct workqueue_struct *work_thread;
134 132
135 /** Encryption stuff */ 133 /** Encryption stuff */
136 struct lbs_802_11_security secinfo;
137 struct enc_key wpa_mcast_key;
138 struct enc_key wpa_unicast_key;
139 u8 wpa_ie[MAX_WPA_IE_LEN];
140 u8 wpa_ie_len;
141 u16 wep_tx_keyidx;
142 struct enc_key wep_keys[4];
143 u8 authtype_auto; 134 u8 authtype_auto;
135 u8 wep_tx_key;
136 u8 wep_key[4][WLAN_KEY_LEN_WEP104];
137 u8 wep_key_len[4];
144 138
145 /* Wake On LAN */ 139 /* Wake On LAN */
146 uint32_t wol_criteria; 140 uint32_t wol_criteria;
@@ -161,6 +155,7 @@ struct lbs_private {
161 /* NIC/link operation characteristics */ 155 /* NIC/link operation characteristics */
162 u16 mac_control; 156 u16 mac_control;
163 u8 radio_on; 157 u8 radio_on;
158 u8 cur_rate;
164 u8 channel; 159 u8 channel;
165 s16 txpower_cur; 160 s16 txpower_cur;
166 s16 txpower_min; 161 s16 txpower_min;
@@ -169,42 +164,6 @@ struct lbs_private {
169 /** Scanning */ 164 /** Scanning */
170 struct delayed_work scan_work; 165 struct delayed_work scan_work;
171 int scan_channel; 166 int scan_channel;
172 /* remember which channel was scanned last, != 0 if currently scanning */
173 u8 scan_ssid[IEEE80211_MAX_SSID_LEN + 1];
174 u8 scan_ssid_len;
175
176 /* Associating */
177 struct delayed_work assoc_work;
178 struct current_bss_params curbssparams;
179 u8 mode;
180 struct list_head network_list;
181 struct list_head network_free_list;
182 struct bss_descriptor *networks;
183 struct assoc_request * pending_assoc_req;
184 struct assoc_request * in_progress_assoc_req;
185 uint16_t enablehwauto;
186
187 /* ADHOC */
188 u16 beacon_period;
189 u8 beacon_enable;
190 u8 adhoccreate;
191
192 /* WEXT */
193 char name[DEV_NAME_LEN];
194 u8 nodename[16];
195 struct iw_statistics wstats;
196 u8 cur_rate;
197#define MAX_REGION_CHANNEL_NUM 2
198 struct region_channel region_channel[MAX_REGION_CHANNEL_NUM];
199
200 /** Requested Signal Strength*/
201 u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG];
202 u16 NF[MAX_TYPE_B][MAX_TYPE_AVG];
203 u8 RSSI[MAX_TYPE_B][MAX_TYPE_AVG];
204 u8 rawSNR[DEFAULT_DATA_AVG_FACTOR];
205 u8 rawNF[DEFAULT_DATA_AVG_FACTOR];
206 u16 nextSNRNF;
207 u16 numSNRNF;
208}; 167};
209 168
210extern struct cmd_confirm_sleep confirm_sleep; 169extern struct cmd_confirm_sleep confirm_sleep;
diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c
index 0cf31bbf6567..50193aac679e 100644
--- a/drivers/net/wireless/libertas/ethtool.c
+++ b/drivers/net/wireless/libertas/ethtool.c
@@ -2,13 +2,8 @@
2#include <linux/ethtool.h> 2#include <linux/ethtool.h>
3#include <linux/delay.h> 3#include <linux/delay.h>
4 4
5#include "host.h"
6#include "decl.h" 5#include "decl.h"
7#include "defs.h"
8#include "dev.h"
9#include "wext.h"
10#include "cmd.h" 6#include "cmd.h"
11#include "mesh.h"
12 7
13 8
14static void lbs_ethtool_get_drvinfo(struct net_device *dev, 9static void lbs_ethtool_get_drvinfo(struct net_device *dev,
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index abfecc4814b4..51b7e1923ab2 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -11,20 +11,14 @@
11#include <linux/if_arp.h> 11#include <linux/if_arp.h>
12#include <linux/kthread.h> 12#include <linux/kthread.h>
13#include <linux/kfifo.h> 13#include <linux/kfifo.h>
14#include <linux/stddef.h>
15#include <linux/ieee80211.h>
16#include <linux/slab.h> 14#include <linux/slab.h>
17#include <net/iw_handler.h>
18#include <net/cfg80211.h> 15#include <net/cfg80211.h>
19 16
20#include "host.h" 17#include "host.h"
21#include "decl.h" 18#include "decl.h"
22#include "dev.h" 19#include "dev.h"
23#include "wext.h"
24#include "cfg.h" 20#include "cfg.h"
25#include "debugfs.h" 21#include "debugfs.h"
26#include "scan.h"
27#include "assoc.h"
28#include "cmd.h" 22#include "cmd.h"
29 23
30#define DRIVER_RELEASE_VERSION "323.p0" 24#define DRIVER_RELEASE_VERSION "323.p0"
@@ -96,72 +90,6 @@ u8 lbs_data_rate_to_fw_index(u32 rate)
96} 90}
97 91
98 92
99static int lbs_add_rtap(struct lbs_private *priv);
100static void lbs_remove_rtap(struct lbs_private *priv);
101
102
103/**
104 * Get function for sysfs attribute rtap
105 */
106static ssize_t lbs_rtap_get(struct device *dev,
107 struct device_attribute *attr, char * buf)
108{
109 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
110 return snprintf(buf, 5, "0x%X\n", priv->monitormode);
111}
112
113/**
114 * Set function for sysfs attribute rtap
115 */
116static ssize_t lbs_rtap_set(struct device *dev,
117 struct device_attribute *attr, const char * buf, size_t count)
118{
119 int monitor_mode;
120 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
121
122 sscanf(buf, "%x", &monitor_mode);
123 if (monitor_mode) {
124 if (priv->monitormode == monitor_mode)
125 return strlen(buf);
126 if (!priv->monitormode) {
127 if (priv->infra_open || lbs_mesh_open(priv))
128 return -EBUSY;
129 if (priv->mode == IW_MODE_INFRA)
130 lbs_cmd_80211_deauthenticate(priv,
131 priv->curbssparams.bssid,
132 WLAN_REASON_DEAUTH_LEAVING);
133 else if (priv->mode == IW_MODE_ADHOC)
134 lbs_adhoc_stop(priv);
135 lbs_add_rtap(priv);
136 }
137 priv->monitormode = monitor_mode;
138 } else {
139 if (!priv->monitormode)
140 return strlen(buf);
141 priv->monitormode = 0;
142 lbs_remove_rtap(priv);
143
144 if (priv->currenttxskb) {
145 dev_kfree_skb_any(priv->currenttxskb);
146 priv->currenttxskb = NULL;
147 }
148
149 /* Wake queues, command thread, etc. */
150 lbs_host_to_card_done(priv);
151 }
152
153 lbs_prepare_and_send_command(priv,
154 CMD_802_11_MONITOR_MODE, CMD_ACT_SET,
155 CMD_OPTION_WAITFORRSP, 0, &priv->monitormode);
156 return strlen(buf);
157}
158
159/**
160 * lbs_rtap attribute to be exported per ethX interface
161 * through sysfs (/sys/class/net/ethX/lbs_rtap)
162 */
163static DEVICE_ATTR(lbs_rtap, 0644, lbs_rtap_get, lbs_rtap_set );
164
165/** 93/**
166 * @brief This function opens the ethX interface 94 * @brief This function opens the ethX interface
167 * 95 *
@@ -177,13 +105,6 @@ static int lbs_dev_open(struct net_device *dev)
177 105
178 spin_lock_irq(&priv->driver_lock); 106 spin_lock_irq(&priv->driver_lock);
179 107
180 if (priv->monitormode) {
181 ret = -EBUSY;
182 goto out;
183 }
184
185 priv->infra_open = 1;
186
187 if (priv->connect_status == LBS_CONNECTED) 108 if (priv->connect_status == LBS_CONNECTED)
188 netif_carrier_on(dev); 109 netif_carrier_on(dev);
189 else 110 else
@@ -191,7 +112,6 @@ static int lbs_dev_open(struct net_device *dev)
191 112
192 if (!priv->tx_pending_len) 113 if (!priv->tx_pending_len)
193 netif_wake_queue(dev); 114 netif_wake_queue(dev);
194 out:
195 115
196 spin_unlock_irq(&priv->driver_lock); 116 spin_unlock_irq(&priv->driver_lock);
197 lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); 117 lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
@@ -211,7 +131,6 @@ static int lbs_eth_stop(struct net_device *dev)
211 lbs_deb_enter(LBS_DEB_NET); 131 lbs_deb_enter(LBS_DEB_NET);
212 132
213 spin_lock_irq(&priv->driver_lock); 133 spin_lock_irq(&priv->driver_lock);
214 priv->infra_open = 0;
215 netif_stop_queue(dev); 134 netif_stop_queue(dev);
216 spin_unlock_irq(&priv->driver_lock); 135 spin_unlock_irq(&priv->driver_lock);
217 136
@@ -822,37 +741,16 @@ int lbs_exit_auto_deep_sleep(struct lbs_private *priv)
822 741
823static int lbs_init_adapter(struct lbs_private *priv) 742static int lbs_init_adapter(struct lbs_private *priv)
824{ 743{
825 size_t bufsize; 744 int ret;
826 int i, ret = 0;
827 745
828 lbs_deb_enter(LBS_DEB_MAIN); 746 lbs_deb_enter(LBS_DEB_MAIN);
829 747
830 /* Allocate buffer to store the BSSID list */
831 bufsize = MAX_NETWORK_COUNT * sizeof(struct bss_descriptor);
832 priv->networks = kzalloc(bufsize, GFP_KERNEL);
833 if (!priv->networks) {
834 lbs_pr_err("Out of memory allocating beacons\n");
835 ret = -1;
836 goto out;
837 }
838
839 /* Initialize scan result lists */
840 INIT_LIST_HEAD(&priv->network_free_list);
841 INIT_LIST_HEAD(&priv->network_list);
842 for (i = 0; i < MAX_NETWORK_COUNT; i++) {
843 list_add_tail(&priv->networks[i].list,
844 &priv->network_free_list);
845 }
846
847 memset(priv->current_addr, 0xff, ETH_ALEN); 748 memset(priv->current_addr, 0xff, ETH_ALEN);
848 749
849 priv->connect_status = LBS_DISCONNECTED; 750 priv->connect_status = LBS_DISCONNECTED;
850 priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
851 priv->mode = IW_MODE_INFRA;
852 priv->channel = DEFAULT_AD_HOC_CHANNEL; 751 priv->channel = DEFAULT_AD_HOC_CHANNEL;
853 priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; 752 priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
854 priv->radio_on = 1; 753 priv->radio_on = 1;
855 priv->enablehwauto = 1;
856 priv->psmode = LBS802_11POWERMODECAM; 754 priv->psmode = LBS802_11POWERMODECAM;
857 priv->psstate = PS_STATE_FULL_POWER; 755 priv->psstate = PS_STATE_FULL_POWER;
858 priv->is_deep_sleep = 0; 756 priv->is_deep_sleep = 0;
@@ -907,8 +805,6 @@ static void lbs_free_adapter(struct lbs_private *priv)
907 kfifo_free(&priv->event_fifo); 805 kfifo_free(&priv->event_fifo);
908 del_timer(&priv->command_timer); 806 del_timer(&priv->command_timer);
909 del_timer(&priv->auto_deepsleep_timer); 807 del_timer(&priv->auto_deepsleep_timer);
910 kfree(priv->networks);
911 priv->networks = NULL;
912 808
913 lbs_deb_leave(LBS_DEB_MAIN); 809 lbs_deb_leave(LBS_DEB_MAIN);
914} 810}
@@ -945,7 +841,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
945 lbs_pr_err("cfg80211 init failed\n"); 841 lbs_pr_err("cfg80211 init failed\n");
946 goto done; 842 goto done;
947 } 843 }
948 /* TODO? */ 844
949 wdev->iftype = NL80211_IFTYPE_STATION; 845 wdev->iftype = NL80211_IFTYPE_STATION;
950 priv = wdev_priv(wdev); 846 priv = wdev_priv(wdev);
951 priv->wdev = wdev; 847 priv->wdev = wdev;
@@ -955,7 +851,6 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
955 goto err_wdev; 851 goto err_wdev;
956 } 852 }
957 853
958 //TODO? dev = alloc_netdev_mq(0, "wlan%d", ether_setup, IWM_TX_QUEUES);
959 dev = alloc_netdev(0, "wlan%d", ether_setup); 854 dev = alloc_netdev(0, "wlan%d", ether_setup);
960 if (!dev) { 855 if (!dev) {
961 dev_err(dmdev, "no memory for network device instance\n"); 856 dev_err(dmdev, "no memory for network device instance\n");
@@ -971,20 +866,10 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
971 dev->netdev_ops = &lbs_netdev_ops; 866 dev->netdev_ops = &lbs_netdev_ops;
972 dev->watchdog_timeo = 5 * HZ; 867 dev->watchdog_timeo = 5 * HZ;
973 dev->ethtool_ops = &lbs_ethtool_ops; 868 dev->ethtool_ops = &lbs_ethtool_ops;
974#ifdef WIRELESS_EXT
975 dev->wireless_handlers = &lbs_handler_def;
976#endif
977 dev->flags |= IFF_BROADCAST | IFF_MULTICAST; 869 dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
978 870
979
980 // TODO: kzalloc + iwm_init_default_profile(iwm, iwm->umac_profile); ??
981
982
983 priv->card = card; 871 priv->card = card;
984 priv->infra_open = 0;
985
986 872
987 priv->rtap_net_dev = NULL;
988 strcpy(dev->name, "wlan%d"); 873 strcpy(dev->name, "wlan%d");
989 874
990 lbs_deb_thread("Starting main thread...\n"); 875 lbs_deb_thread("Starting main thread...\n");
@@ -996,8 +881,6 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
996 } 881 }
997 882
998 priv->work_thread = create_singlethread_workqueue("lbs_worker"); 883 priv->work_thread = create_singlethread_workqueue("lbs_worker");
999 INIT_DELAYED_WORK(&priv->assoc_work, lbs_association_worker);
1000 INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker);
1001 INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker); 884 INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker);
1002 885
1003 priv->wol_criteria = 0xffffffff; 886 priv->wol_criteria = 0xffffffff;
@@ -1031,12 +914,10 @@ void lbs_remove_card(struct lbs_private *priv)
1031 lbs_deb_enter(LBS_DEB_MAIN); 914 lbs_deb_enter(LBS_DEB_MAIN);
1032 915
1033 lbs_remove_mesh(priv); 916 lbs_remove_mesh(priv);
1034 lbs_remove_rtap(priv); 917 lbs_scan_deinit(priv);
1035 918
1036 dev = priv->dev; 919 dev = priv->dev;
1037 920
1038 cancel_delayed_work_sync(&priv->scan_work);
1039 cancel_delayed_work_sync(&priv->assoc_work);
1040 cancel_work_sync(&priv->mcast_work); 921 cancel_work_sync(&priv->mcast_work);
1041 922
1042 /* worker thread destruction blocks on the in-flight command which 923 /* worker thread destruction blocks on the in-flight command which
@@ -1077,7 +958,7 @@ void lbs_remove_card(struct lbs_private *priv)
1077EXPORT_SYMBOL_GPL(lbs_remove_card); 958EXPORT_SYMBOL_GPL(lbs_remove_card);
1078 959
1079 960
1080static int lbs_rtap_supported(struct lbs_private *priv) 961int lbs_rtap_supported(struct lbs_private *priv)
1081{ 962{
1082 if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) 963 if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5)
1083 return 1; 964 return 1;
@@ -1109,16 +990,6 @@ int lbs_start_card(struct lbs_private *priv)
1109 990
1110 lbs_init_mesh(priv); 991 lbs_init_mesh(priv);
1111 992
1112 /*
1113 * While rtap isn't related to mesh, only mesh-enabled
1114 * firmware implements the rtap functionality via
1115 * CMD_802_11_MONITOR_MODE.
1116 */
1117 if (lbs_rtap_supported(priv)) {
1118 if (device_create_file(&dev->dev, &dev_attr_lbs_rtap))
1119 lbs_pr_err("cannot register lbs_rtap attribute\n");
1120 }
1121
1122 lbs_debugfs_init_one(priv, dev); 993 lbs_debugfs_init_one(priv, dev);
1123 994
1124 lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name); 995 lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name);
@@ -1150,9 +1021,6 @@ void lbs_stop_card(struct lbs_private *priv)
1150 lbs_debugfs_remove_one(priv); 1021 lbs_debugfs_remove_one(priv);
1151 lbs_deinit_mesh(priv); 1022 lbs_deinit_mesh(priv);
1152 1023
1153 if (lbs_rtap_supported(priv))
1154 device_remove_file(&dev->dev, &dev_attr_lbs_rtap);
1155
1156 /* Delete the timeout of the currently processing command */ 1024 /* Delete the timeout of the currently processing command */
1157 del_timer_sync(&priv->command_timer); 1025 del_timer_sync(&priv->command_timer);
1158 del_timer_sync(&priv->auto_deepsleep_timer); 1026 del_timer_sync(&priv->auto_deepsleep_timer);
@@ -1239,87 +1107,6 @@ static void __exit lbs_exit_module(void)
1239 lbs_deb_leave(LBS_DEB_MAIN); 1107 lbs_deb_leave(LBS_DEB_MAIN);
1240} 1108}
1241 1109
1242/*
1243 * rtap interface support fuctions
1244 */
1245
1246static int lbs_rtap_open(struct net_device *dev)
1247{
1248 /* Yes, _stop_ the queue. Because we don't support injection */
1249 lbs_deb_enter(LBS_DEB_MAIN);
1250 netif_carrier_off(dev);
1251 netif_stop_queue(dev);
1252 lbs_deb_leave(LBS_DEB_LEAVE);
1253 return 0;
1254}
1255
1256static int lbs_rtap_stop(struct net_device *dev)
1257{
1258 lbs_deb_enter(LBS_DEB_MAIN);
1259 lbs_deb_leave(LBS_DEB_MAIN);
1260 return 0;
1261}
1262
1263static netdev_tx_t lbs_rtap_hard_start_xmit(struct sk_buff *skb,
1264 struct net_device *dev)
1265{
1266 netif_stop_queue(dev);
1267 return NETDEV_TX_BUSY;
1268}
1269
1270static void lbs_remove_rtap(struct lbs_private *priv)
1271{
1272 lbs_deb_enter(LBS_DEB_MAIN);
1273 if (priv->rtap_net_dev == NULL)
1274 goto out;
1275 unregister_netdev(priv->rtap_net_dev);
1276 free_netdev(priv->rtap_net_dev);
1277 priv->rtap_net_dev = NULL;
1278out:
1279 lbs_deb_leave(LBS_DEB_MAIN);
1280}
1281
1282static const struct net_device_ops rtap_netdev_ops = {
1283 .ndo_open = lbs_rtap_open,
1284 .ndo_stop = lbs_rtap_stop,
1285 .ndo_start_xmit = lbs_rtap_hard_start_xmit,
1286};
1287
1288static int lbs_add_rtap(struct lbs_private *priv)
1289{
1290 int ret = 0;
1291 struct net_device *rtap_dev;
1292
1293 lbs_deb_enter(LBS_DEB_MAIN);
1294 if (priv->rtap_net_dev) {
1295 ret = -EPERM;
1296 goto out;
1297 }
1298
1299 rtap_dev = alloc_netdev(0, "rtap%d", ether_setup);
1300 if (rtap_dev == NULL) {
1301 ret = -ENOMEM;
1302 goto out;
1303 }
1304
1305 memcpy(rtap_dev->dev_addr, priv->current_addr, ETH_ALEN);
1306 rtap_dev->type = ARPHRD_IEEE80211_RADIOTAP;
1307 rtap_dev->netdev_ops = &rtap_netdev_ops;
1308 rtap_dev->ml_priv = priv;
1309 SET_NETDEV_DEV(rtap_dev, priv->dev->dev.parent);
1310
1311 ret = register_netdev(rtap_dev);
1312 if (ret) {
1313 free_netdev(rtap_dev);
1314 goto out;
1315 }
1316 priv->rtap_net_dev = rtap_dev;
1317
1318out:
1319 lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
1320 return ret;
1321}
1322
1323module_init(lbs_init_module); 1110module_init(lbs_init_module);
1324module_exit(lbs_exit_module); 1111module_exit(lbs_exit_module);
1325 1112
diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c
index e385af1f4583..bc5bc1384c35 100644
--- a/drivers/net/wireless/libertas/mesh.c
+++ b/drivers/net/wireless/libertas/mesh.c
@@ -5,6 +5,7 @@
5#include <linux/if_arp.h> 5#include <linux/if_arp.h>
6#include <linux/kthread.h> 6#include <linux/kthread.h>
7#include <linux/kfifo.h> 7#include <linux/kfifo.h>
8#include <net/cfg80211.h>
8 9
9#include "mesh.h" 10#include "mesh.h"
10#include "decl.h" 11#include "decl.h"
@@ -314,7 +315,7 @@ static int lbs_mesh_dev_open(struct net_device *dev)
314 315
315 spin_lock_irq(&priv->driver_lock); 316 spin_lock_irq(&priv->driver_lock);
316 317
317 if (priv->monitormode) { 318 if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
318 ret = -EBUSY; 319 ret = -EBUSY;
319 goto out; 320 goto out;
320 } 321 }
@@ -369,9 +370,6 @@ int lbs_add_mesh(struct lbs_private *priv)
369 370
370 SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent); 371 SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent);
371 372
372#ifdef WIRELESS_EXT
373 mesh_dev->wireless_handlers = &mesh_handler_def;
374#endif
375 mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST; 373 mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
376 /* Register virtual mesh interface */ 374 /* Register virtual mesh interface */
377 ret = register_netdev(mesh_dev); 375 ret = register_netdev(mesh_dev);
diff --git a/drivers/net/wireless/libertas/mesh.h b/drivers/net/wireless/libertas/mesh.h
index e2573303a328..84ea2481ff20 100644
--- a/drivers/net/wireless/libertas/mesh.h
+++ b/drivers/net/wireless/libertas/mesh.h
@@ -70,11 +70,6 @@ void lbs_persist_config_init(struct net_device *net);
70void lbs_persist_config_remove(struct net_device *net); 70void lbs_persist_config_remove(struct net_device *net);
71 71
72 72
73/* WEXT handler */
74
75extern struct iw_handler_def mesh_handler_def;
76
77
78/* Ethtool statistics */ 73/* Ethtool statistics */
79 74
80struct ethtool_stats; 75struct ethtool_stats;
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
index 7a377f5b7662..2163df01caed 100644
--- a/drivers/net/wireless/libertas/rx.c
+++ b/drivers/net/wireless/libertas/rx.c
@@ -4,12 +4,13 @@
4#include <linux/etherdevice.h> 4#include <linux/etherdevice.h>
5#include <linux/slab.h> 5#include <linux/slab.h>
6#include <linux/types.h> 6#include <linux/types.h>
7#include <net/cfg80211.h>
7 8
9#include "defs.h"
8#include "host.h" 10#include "host.h"
9#include "radiotap.h" 11#include "radiotap.h"
10#include "decl.h" 12#include "decl.h"
11#include "dev.h" 13#include "dev.h"
12#include "wext.h"
13 14
14struct eth803hdr { 15struct eth803hdr {
15 u8 dest_addr[6]; 16 u8 dest_addr[6];
@@ -39,98 +40,6 @@ static int process_rxed_802_11_packet(struct lbs_private *priv,
39 struct sk_buff *skb); 40 struct sk_buff *skb);
40 41
41/** 42/**
42 * @brief This function computes the avgSNR .
43 *
44 * @param priv A pointer to struct lbs_private structure
45 * @return avgSNR
46 */
47static u8 lbs_getavgsnr(struct lbs_private *priv)
48{
49 u8 i;
50 u16 temp = 0;
51 if (priv->numSNRNF == 0)
52 return 0;
53 for (i = 0; i < priv->numSNRNF; i++)
54 temp += priv->rawSNR[i];
55 return (u8) (temp / priv->numSNRNF);
56
57}
58
59/**
60 * @brief This function computes the AvgNF
61 *
62 * @param priv A pointer to struct lbs_private structure
63 * @return AvgNF
64 */
65static u8 lbs_getavgnf(struct lbs_private *priv)
66{
67 u8 i;
68 u16 temp = 0;
69 if (priv->numSNRNF == 0)
70 return 0;
71 for (i = 0; i < priv->numSNRNF; i++)
72 temp += priv->rawNF[i];
73 return (u8) (temp / priv->numSNRNF);
74
75}
76
77/**
78 * @brief This function save the raw SNR/NF to our internel buffer
79 *
80 * @param priv A pointer to struct lbs_private structure
81 * @param prxpd A pointer to rxpd structure of received packet
82 * @return n/a
83 */
84static void lbs_save_rawSNRNF(struct lbs_private *priv, struct rxpd *p_rx_pd)
85{
86 if (priv->numSNRNF < DEFAULT_DATA_AVG_FACTOR)
87 priv->numSNRNF++;
88 priv->rawSNR[priv->nextSNRNF] = p_rx_pd->snr;
89 priv->rawNF[priv->nextSNRNF] = p_rx_pd->nf;
90 priv->nextSNRNF++;
91 if (priv->nextSNRNF >= DEFAULT_DATA_AVG_FACTOR)
92 priv->nextSNRNF = 0;
93}
94
95/**
96 * @brief This function computes the RSSI in received packet.
97 *
98 * @param priv A pointer to struct lbs_private structure
99 * @param prxpd A pointer to rxpd structure of received packet
100 * @return n/a
101 */
102static void lbs_compute_rssi(struct lbs_private *priv, struct rxpd *p_rx_pd)
103{
104
105 lbs_deb_enter(LBS_DEB_RX);
106
107 lbs_deb_rx("rxpd: SNR %d, NF %d\n", p_rx_pd->snr, p_rx_pd->nf);
108 lbs_deb_rx("before computing SNR: SNR-avg = %d, NF-avg = %d\n",
109 priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
110 priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
111
112 priv->SNR[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->snr;
113 priv->NF[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->nf;
114 lbs_save_rawSNRNF(priv, p_rx_pd);
115
116 priv->SNR[TYPE_RXPD][TYPE_AVG] = lbs_getavgsnr(priv) * AVG_SCALE;
117 priv->NF[TYPE_RXPD][TYPE_AVG] = lbs_getavgnf(priv) * AVG_SCALE;
118 lbs_deb_rx("after computing SNR: SNR-avg = %d, NF-avg = %d\n",
119 priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
120 priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
121
122 priv->RSSI[TYPE_RXPD][TYPE_NOAVG] =
123 CAL_RSSI(priv->SNR[TYPE_RXPD][TYPE_NOAVG],
124 priv->NF[TYPE_RXPD][TYPE_NOAVG]);
125
126 priv->RSSI[TYPE_RXPD][TYPE_AVG] =
127 CAL_RSSI(priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
128 priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
129
130 lbs_deb_leave(LBS_DEB_RX);
131}
132
133/**
134 * @brief This function processes received packet and forwards it 43 * @brief This function processes received packet and forwards it
135 * to kernel/upper layer 44 * to kernel/upper layer
136 * 45 *
@@ -154,7 +63,7 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
154 63
155 skb->ip_summed = CHECKSUM_NONE; 64 skb->ip_summed = CHECKSUM_NONE;
156 65
157 if (priv->monitormode) 66 if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)
158 return process_rxed_802_11_packet(priv, skb); 67 return process_rxed_802_11_packet(priv, skb);
159 68
160 p_rx_pd = (struct rxpd *) skb->data; 69 p_rx_pd = (struct rxpd *) skb->data;
@@ -225,13 +134,7 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
225 */ 134 */
226 skb_pull(skb, hdrchop); 135 skb_pull(skb, hdrchop);
227 136
228 /* Take the data rate from the rxpd structure 137 priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate);
229 * only if the rate is auto
230 */
231 if (priv->enablehwauto)
232 priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate);
233
234 lbs_compute_rssi(priv, p_rx_pd);
235 138
236 lbs_deb_rx("rx data: size of actual packet %d\n", skb->len); 139 lbs_deb_rx("rx data: size of actual packet %d\n", skb->len);
237 dev->stats.rx_bytes += skb->len; 140 dev->stats.rx_bytes += skb->len;
@@ -352,20 +255,18 @@ static int process_rxed_802_11_packet(struct lbs_private *priv,
352 pradiotap_hdr = (void *)skb_push(skb, sizeof(struct rx_radiotap_hdr)); 255 pradiotap_hdr = (void *)skb_push(skb, sizeof(struct rx_radiotap_hdr));
353 memcpy(pradiotap_hdr, &radiotap_hdr, sizeof(struct rx_radiotap_hdr)); 256 memcpy(pradiotap_hdr, &radiotap_hdr, sizeof(struct rx_radiotap_hdr));
354 257
355 /* Take the data rate from the rxpd structure 258 priv->cur_rate = lbs_fw_index_to_data_rate(prxpd->rx_rate);
356 * only if the rate is auto
357 */
358 if (priv->enablehwauto)
359 priv->cur_rate = lbs_fw_index_to_data_rate(prxpd->rx_rate);
360
361 lbs_compute_rssi(priv, prxpd);
362 259
363 lbs_deb_rx("rx data: size of actual packet %d\n", skb->len); 260 lbs_deb_rx("rx data: size of actual packet %d\n", skb->len);
364 dev->stats.rx_bytes += skb->len; 261 dev->stats.rx_bytes += skb->len;
365 dev->stats.rx_packets++; 262 dev->stats.rx_packets++;
366 263
367 skb->protocol = eth_type_trans(skb, priv->rtap_net_dev); 264 skb->protocol = eth_type_trans(skb, priv->dev);
368 netif_rx(skb); 265
266 if (in_interrupt())
267 netif_rx(skb);
268 else
269 netif_rx_ni(skb);
369 270
370 ret = 0; 271 ret = 0;
371 272
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
deleted file mode 100644
index 7d82f13bdf1d..000000000000
--- a/drivers/net/wireless/libertas/scan.c
+++ /dev/null
@@ -1,1354 +0,0 @@
1/**
2 * Functions implementing wlan scan IOCTL and firmware command APIs
3 *
4 * IOCTL handlers as well as command preperation and response routines
5 * for sending scan commands to the firmware.
6 */
7#include <linux/slab.h>
8#include <linux/types.h>
9#include <linux/kernel.h>
10#include <linux/etherdevice.h>
11#include <linux/if_arp.h>
12#include <asm/unaligned.h>
13#include <net/lib80211.h>
14
15#include "host.h"
16#include "dev.h"
17#include "scan.h"
18#include "assoc.h"
19#include "wext.h"
20#include "cmd.h"
21
22//! Approximate amount of data needed to pass a scan result back to iwlist
23#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \
24 + IEEE80211_MAX_SSID_LEN \
25 + IW_EV_UINT_LEN \
26 + IW_EV_FREQ_LEN \
27 + IW_EV_QUAL_LEN \
28 + IEEE80211_MAX_SSID_LEN \
29 + IW_EV_PARAM_LEN \
30 + 40) /* 40 for WPAIE */
31
32//! Memory needed to store a max sized channel List TLV for a firmware scan
33#define CHAN_TLV_MAX_SIZE (sizeof(struct mrvl_ie_header) \
34 + (MRVDRV_MAX_CHANNELS_PER_SCAN \
35 * sizeof(struct chanscanparamset)))
36
37//! Memory needed to store a max number/size SSID TLV for a firmware scan
38#define SSID_TLV_MAX_SIZE (1 * sizeof(struct mrvl_ie_ssid_param_set))
39
40//! Maximum memory needed for a cmd_ds_802_11_scan with all TLVs at max
41#define MAX_SCAN_CFG_ALLOC (sizeof(struct cmd_ds_802_11_scan) \
42 + CHAN_TLV_MAX_SIZE + SSID_TLV_MAX_SIZE)
43
44//! The maximum number of channels the firmware can scan per command
45#define MRVDRV_MAX_CHANNELS_PER_SCAN 14
46
47/**
48 * @brief Number of channels to scan per firmware scan command issuance.
49 *
50 * Number restricted to prevent hitting the limit on the amount of scan data
51 * returned in a single firmware scan command.
52 */
53#define MRVDRV_CHANNELS_PER_SCAN_CMD 4
54
55//! Scan time specified in the channel TLV for each channel for passive scans
56#define MRVDRV_PASSIVE_SCAN_CHAN_TIME 100
57
58//! Scan time specified in the channel TLV for each channel for active scans
59#define MRVDRV_ACTIVE_SCAN_CHAN_TIME 100
60
61#define DEFAULT_MAX_SCAN_AGE (15 * HZ)
62
63static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy,
64 struct cmd_header *resp);
65
66/*********************************************************************/
67/* */
68/* Misc helper functions */
69/* */
70/*********************************************************************/
71
72/**
73 * @brief Unsets the MSB on basic rates
74 *
75 * Scan through an array and unset the MSB for basic data rates.
76 *
77 * @param rates buffer of data rates
78 * @param len size of buffer
79 */
80static void lbs_unset_basic_rate_flags(u8 *rates, size_t len)
81{
82 int i;
83
84 for (i = 0; i < len; i++)
85 rates[i] &= 0x7f;
86}
87
88
89static inline void clear_bss_descriptor(struct bss_descriptor *bss)
90{
91 /* Don't blow away ->list, just BSS data */
92 memset(bss, 0, offsetof(struct bss_descriptor, list));
93}
94
95/**
96 * @brief Compare two SSIDs
97 *
98 * @param ssid1 A pointer to ssid to compare
99 * @param ssid2 A pointer to ssid to compare
100 *
101 * @return 0: ssid is same, otherwise is different
102 */
103int lbs_ssid_cmp(uint8_t *ssid1, uint8_t ssid1_len, uint8_t *ssid2,
104 uint8_t ssid2_len)
105{
106 if (ssid1_len != ssid2_len)
107 return -1;
108
109 return memcmp(ssid1, ssid2, ssid1_len);
110}
111
112static inline int is_same_network(struct bss_descriptor *src,
113 struct bss_descriptor *dst)
114{
115 /* A network is only a duplicate if the channel, BSSID, and ESSID
116 * all match. We treat all <hidden> with the same BSSID and channel
117 * as one network */
118 return ((src->ssid_len == dst->ssid_len) &&
119 (src->channel == dst->channel) &&
120 !compare_ether_addr(src->bssid, dst->bssid) &&
121 !memcmp(src->ssid, dst->ssid, src->ssid_len));
122}
123
124
125
126/*********************************************************************/
127/* */
128/* Region channel support */
129/* */
130/*********************************************************************/
131
132#define LBS_TX_PWR_DEFAULT 20 /*100mW */
133#define LBS_TX_PWR_US_DEFAULT 20 /*100mW */
134#define LBS_TX_PWR_JP_DEFAULT 16 /*50mW */
135#define LBS_TX_PWR_FR_DEFAULT 20 /*100mW */
136#define LBS_TX_PWR_EMEA_DEFAULT 20 /*100mW */
137
138/* Format { channel, frequency (MHz), maxtxpower } */
139/* band: 'B/G', region: USA FCC/Canada IC */
140static struct chan_freq_power channel_freq_power_US_BG[] = {
141 {1, 2412, LBS_TX_PWR_US_DEFAULT},
142 {2, 2417, LBS_TX_PWR_US_DEFAULT},
143 {3, 2422, LBS_TX_PWR_US_DEFAULT},
144 {4, 2427, LBS_TX_PWR_US_DEFAULT},
145 {5, 2432, LBS_TX_PWR_US_DEFAULT},
146 {6, 2437, LBS_TX_PWR_US_DEFAULT},
147 {7, 2442, LBS_TX_PWR_US_DEFAULT},
148 {8, 2447, LBS_TX_PWR_US_DEFAULT},
149 {9, 2452, LBS_TX_PWR_US_DEFAULT},
150 {10, 2457, LBS_TX_PWR_US_DEFAULT},
151 {11, 2462, LBS_TX_PWR_US_DEFAULT}
152};
153
154/* band: 'B/G', region: Europe ETSI */
155static struct chan_freq_power channel_freq_power_EU_BG[] = {
156 {1, 2412, LBS_TX_PWR_EMEA_DEFAULT},
157 {2, 2417, LBS_TX_PWR_EMEA_DEFAULT},
158 {3, 2422, LBS_TX_PWR_EMEA_DEFAULT},
159 {4, 2427, LBS_TX_PWR_EMEA_DEFAULT},
160 {5, 2432, LBS_TX_PWR_EMEA_DEFAULT},
161 {6, 2437, LBS_TX_PWR_EMEA_DEFAULT},
162 {7, 2442, LBS_TX_PWR_EMEA_DEFAULT},
163 {8, 2447, LBS_TX_PWR_EMEA_DEFAULT},
164 {9, 2452, LBS_TX_PWR_EMEA_DEFAULT},
165 {10, 2457, LBS_TX_PWR_EMEA_DEFAULT},
166 {11, 2462, LBS_TX_PWR_EMEA_DEFAULT},
167 {12, 2467, LBS_TX_PWR_EMEA_DEFAULT},
168 {13, 2472, LBS_TX_PWR_EMEA_DEFAULT}
169};
170
171/* band: 'B/G', region: Spain */
172static struct chan_freq_power channel_freq_power_SPN_BG[] = {
173 {10, 2457, LBS_TX_PWR_DEFAULT},
174 {11, 2462, LBS_TX_PWR_DEFAULT}
175};
176
177/* band: 'B/G', region: France */
178static struct chan_freq_power channel_freq_power_FR_BG[] = {
179 {10, 2457, LBS_TX_PWR_FR_DEFAULT},
180 {11, 2462, LBS_TX_PWR_FR_DEFAULT},
181 {12, 2467, LBS_TX_PWR_FR_DEFAULT},
182 {13, 2472, LBS_TX_PWR_FR_DEFAULT}
183};
184
185/* band: 'B/G', region: Japan */
186static struct chan_freq_power channel_freq_power_JPN_BG[] = {
187 {1, 2412, LBS_TX_PWR_JP_DEFAULT},
188 {2, 2417, LBS_TX_PWR_JP_DEFAULT},
189 {3, 2422, LBS_TX_PWR_JP_DEFAULT},
190 {4, 2427, LBS_TX_PWR_JP_DEFAULT},
191 {5, 2432, LBS_TX_PWR_JP_DEFAULT},
192 {6, 2437, LBS_TX_PWR_JP_DEFAULT},
193 {7, 2442, LBS_TX_PWR_JP_DEFAULT},
194 {8, 2447, LBS_TX_PWR_JP_DEFAULT},
195 {9, 2452, LBS_TX_PWR_JP_DEFAULT},
196 {10, 2457, LBS_TX_PWR_JP_DEFAULT},
197 {11, 2462, LBS_TX_PWR_JP_DEFAULT},
198 {12, 2467, LBS_TX_PWR_JP_DEFAULT},
199 {13, 2472, LBS_TX_PWR_JP_DEFAULT},
200 {14, 2484, LBS_TX_PWR_JP_DEFAULT}
201};
202
203/**
204 * the structure for channel, frequency and power
205 */
206struct region_cfp_table {
207 u8 region;
208 struct chan_freq_power *cfp_BG;
209 int cfp_no_BG;
210};
211
212/**
213 * the structure for the mapping between region and CFP
214 */
215static struct region_cfp_table region_cfp_table[] = {
216 {0x10, /*US FCC */
217 channel_freq_power_US_BG,
218 ARRAY_SIZE(channel_freq_power_US_BG),
219 }
220 ,
221 {0x20, /*CANADA IC */
222 channel_freq_power_US_BG,
223 ARRAY_SIZE(channel_freq_power_US_BG),
224 }
225 ,
226 {0x30, /*EU*/ channel_freq_power_EU_BG,
227 ARRAY_SIZE(channel_freq_power_EU_BG),
228 }
229 ,
230 {0x31, /*SPAIN*/ channel_freq_power_SPN_BG,
231 ARRAY_SIZE(channel_freq_power_SPN_BG),
232 }
233 ,
234 {0x32, /*FRANCE*/ channel_freq_power_FR_BG,
235 ARRAY_SIZE(channel_freq_power_FR_BG),
236 }
237 ,
238 {0x40, /*JAPAN*/ channel_freq_power_JPN_BG,
239 ARRAY_SIZE(channel_freq_power_JPN_BG),
240 }
241 ,
242/*Add new region here */
243};
244
245/**
246 * @brief This function finds the CFP in
247 * region_cfp_table based on region and band parameter.
248 *
249 * @param region The region code
250 * @param band The band
251 * @param cfp_no A pointer to CFP number
252 * @return A pointer to CFP
253 */
254static struct chan_freq_power *lbs_get_region_cfp_table(u8 region, int *cfp_no)
255{
256 int i, end;
257
258 lbs_deb_enter(LBS_DEB_MAIN);
259
260 end = ARRAY_SIZE(region_cfp_table);
261
262 for (i = 0; i < end ; i++) {
263 lbs_deb_main("region_cfp_table[i].region=%d\n",
264 region_cfp_table[i].region);
265 if (region_cfp_table[i].region == region) {
266 *cfp_no = region_cfp_table[i].cfp_no_BG;
267 lbs_deb_leave(LBS_DEB_MAIN);
268 return region_cfp_table[i].cfp_BG;
269 }
270 }
271
272 lbs_deb_leave_args(LBS_DEB_MAIN, "ret NULL");
273 return NULL;
274}
275
276int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band)
277{
278 int ret = 0;
279 int i = 0;
280
281 struct chan_freq_power *cfp;
282 int cfp_no;
283
284 lbs_deb_enter(LBS_DEB_MAIN);
285
286 memset(priv->region_channel, 0, sizeof(priv->region_channel));
287
288 cfp = lbs_get_region_cfp_table(region, &cfp_no);
289 if (cfp != NULL) {
290 priv->region_channel[i].nrcfp = cfp_no;
291 priv->region_channel[i].CFP = cfp;
292 } else {
293 lbs_deb_main("wrong region code %#x in band B/G\n",
294 region);
295 ret = -1;
296 goto out;
297 }
298 priv->region_channel[i].valid = 1;
299 priv->region_channel[i].region = region;
300 priv->region_channel[i].band = band;
301 i++;
302out:
303 lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
304 return ret;
305}
306
307
308
309
310/*********************************************************************/
311/* */
312/* Main scanning support */
313/* */
314/*********************************************************************/
315
316/**
317 * @brief Create a channel list for the driver to scan based on region info
318 *
319 * Only used from lbs_scan_setup_scan_config()
320 *
321 * Use the driver region/band information to construct a comprehensive list
322 * of channels to scan. This routine is used for any scan that is not
323 * provided a specific channel list to scan.
324 *
325 * @param priv A pointer to struct lbs_private structure
326 * @param scanchanlist Output parameter: resulting channel list to scan
327 *
328 * @return void
329 */
330static int lbs_scan_create_channel_list(struct lbs_private *priv,
331 struct chanscanparamset *scanchanlist)
332{
333 struct region_channel *scanregion;
334 struct chan_freq_power *cfp;
335 int rgnidx;
336 int chanidx;
337 int nextchan;
338 uint8_t scantype;
339
340 chanidx = 0;
341
342 /* Set the default scan type to the user specified type, will later
343 * be changed to passive on a per channel basis if restricted by
344 * regulatory requirements (11d or 11h)
345 */
346 scantype = CMD_SCAN_TYPE_ACTIVE;
347
348 for (rgnidx = 0; rgnidx < ARRAY_SIZE(priv->region_channel); rgnidx++) {
349 if (!priv->region_channel[rgnidx].valid)
350 continue;
351 scanregion = &priv->region_channel[rgnidx];
352
353 for (nextchan = 0; nextchan < scanregion->nrcfp; nextchan++, chanidx++) {
354 struct chanscanparamset *chan = &scanchanlist[chanidx];
355
356 cfp = scanregion->CFP + nextchan;
357
358 if (scanregion->band == BAND_B || scanregion->band == BAND_G)
359 chan->radiotype = CMD_SCAN_RADIO_TYPE_BG;
360
361 if (scantype == CMD_SCAN_TYPE_PASSIVE) {
362 chan->maxscantime = cpu_to_le16(MRVDRV_PASSIVE_SCAN_CHAN_TIME);
363 chan->chanscanmode.passivescan = 1;
364 } else {
365 chan->maxscantime = cpu_to_le16(MRVDRV_ACTIVE_SCAN_CHAN_TIME);
366 chan->chanscanmode.passivescan = 0;
367 }
368
369 chan->channumber = cfp->channel;
370 }
371 }
372 return chanidx;
373}
374
375/*
376 * Add SSID TLV of the form:
377 *
378 * TLV-ID SSID 00 00
379 * length 06 00
380 * ssid 4d 4e 54 45 53 54
381 */
382static int lbs_scan_add_ssid_tlv(struct lbs_private *priv, u8 *tlv)
383{
384 struct mrvl_ie_ssid_param_set *ssid_tlv = (void *)tlv;
385
386 ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID);
387 ssid_tlv->header.len = cpu_to_le16(priv->scan_ssid_len);
388 memcpy(ssid_tlv->ssid, priv->scan_ssid, priv->scan_ssid_len);
389 return sizeof(ssid_tlv->header) + priv->scan_ssid_len;
390}
391
392/*
393 * Add CHANLIST TLV of the form
394 *
395 * TLV-ID CHANLIST 01 01
396 * length 5b 00
397 * channel 1 00 01 00 00 00 64 00
398 * radio type 00
399 * channel 01
400 * scan type 00
401 * min scan time 00 00
402 * max scan time 64 00
403 * channel 2 00 02 00 00 00 64 00
404 * channel 3 00 03 00 00 00 64 00
405 * channel 4 00 04 00 00 00 64 00
406 * channel 5 00 05 00 00 00 64 00
407 * channel 6 00 06 00 00 00 64 00
408 * channel 7 00 07 00 00 00 64 00
409 * channel 8 00 08 00 00 00 64 00
410 * channel 9 00 09 00 00 00 64 00
411 * channel 10 00 0a 00 00 00 64 00
412 * channel 11 00 0b 00 00 00 64 00
413 * channel 12 00 0c 00 00 00 64 00
414 * channel 13 00 0d 00 00 00 64 00
415 *
416 */
417static int lbs_scan_add_chanlist_tlv(uint8_t *tlv,
418 struct chanscanparamset *chan_list,
419 int chan_count)
420{
421 size_t size = sizeof(struct chanscanparamset) *chan_count;
422 struct mrvl_ie_chanlist_param_set *chan_tlv = (void *)tlv;
423
424 chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
425 memcpy(chan_tlv->chanscanparam, chan_list, size);
426 chan_tlv->header.len = cpu_to_le16(size);
427 return sizeof(chan_tlv->header) + size;
428}
429
430/*
431 * Add RATES TLV of the form
432 *
433 * TLV-ID RATES 01 00
434 * length 0e 00
435 * rates 82 84 8b 96 0c 12 18 24 30 48 60 6c
436 *
437 * The rates are in lbs_bg_rates[], but for the 802.11b
438 * rates the high bit isn't set.
439 */
440static int lbs_scan_add_rates_tlv(uint8_t *tlv)
441{
442 int i;
443 struct mrvl_ie_rates_param_set *rate_tlv = (void *)tlv;
444
445 rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES);
446 tlv += sizeof(rate_tlv->header);
447 for (i = 0; i < MAX_RATES; i++) {
448 *tlv = lbs_bg_rates[i];
449 if (*tlv == 0)
450 break;
451 /* This code makes sure that the 802.11b rates (1 MBit/s, 2
452 MBit/s, 5.5 MBit/s and 11 MBit/s get's the high bit set.
453 Note that the values are MBit/s * 2, to mark them as
454 basic rates so that the firmware likes it better */
455 if (*tlv == 0x02 || *tlv == 0x04 ||
456 *tlv == 0x0b || *tlv == 0x16)
457 *tlv |= 0x80;
458 tlv++;
459 }
460 rate_tlv->header.len = cpu_to_le16(i);
461 return sizeof(rate_tlv->header) + i;
462}
463
464/*
465 * Generate the CMD_802_11_SCAN command with the proper tlv
466 * for a bunch of channels.
467 */
468static int lbs_do_scan(struct lbs_private *priv, uint8_t bsstype,
469 struct chanscanparamset *chan_list, int chan_count)
470{
471 int ret = -ENOMEM;
472 struct cmd_ds_802_11_scan *scan_cmd;
473 uint8_t *tlv; /* pointer into our current, growing TLV storage area */
474
475 lbs_deb_enter_args(LBS_DEB_SCAN, "bsstype %d, chanlist[].chan %d, chan_count %d",
476 bsstype, chan_list ? chan_list[0].channumber : -1,
477 chan_count);
478
479 /* create the fixed part for scan command */
480 scan_cmd = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL);
481 if (scan_cmd == NULL)
482 goto out;
483
484 tlv = scan_cmd->tlvbuffer;
485 /* TODO: do we need to scan for a specific BSSID?
486 memcpy(scan_cmd->bssid, priv->scan_bssid, ETH_ALEN); */
487 scan_cmd->bsstype = bsstype;
488
489 /* add TLVs */
490 if (priv->scan_ssid_len)
491 tlv += lbs_scan_add_ssid_tlv(priv, tlv);
492 if (chan_list && chan_count)
493 tlv += lbs_scan_add_chanlist_tlv(tlv, chan_list, chan_count);
494 tlv += lbs_scan_add_rates_tlv(tlv);
495
496 /* This is the final data we are about to send */
497 scan_cmd->hdr.size = cpu_to_le16(tlv - (uint8_t *)scan_cmd);
498 lbs_deb_hex(LBS_DEB_SCAN, "SCAN_CMD", (void *)scan_cmd,
499 sizeof(*scan_cmd));
500 lbs_deb_hex(LBS_DEB_SCAN, "SCAN_TLV", scan_cmd->tlvbuffer,
501 tlv - scan_cmd->tlvbuffer);
502
503 ret = __lbs_cmd(priv, CMD_802_11_SCAN, &scan_cmd->hdr,
504 le16_to_cpu(scan_cmd->hdr.size),
505 lbs_ret_80211_scan, 0);
506
507out:
508 kfree(scan_cmd);
509 lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
510 return ret;
511}
512
513/**
514 * @brief Internal function used to start a scan based on an input config
515 *
516 * Use the input user scan configuration information when provided in
517 * order to send the appropriate scan commands to firmware to populate or
518 * update the internal driver scan table
519 *
520 * @param priv A pointer to struct lbs_private structure
521 * @param full_scan Do a full-scan (blocking)
522 *
523 * @return 0 or < 0 if error
524 */
525int lbs_scan_networks(struct lbs_private *priv, int full_scan)
526{
527 int ret = -ENOMEM;
528 struct chanscanparamset *chan_list;
529 struct chanscanparamset *curr_chans;
530 int chan_count;
531 uint8_t bsstype = CMD_BSS_TYPE_ANY;
532 int numchannels = MRVDRV_CHANNELS_PER_SCAN_CMD;
533 union iwreq_data wrqu;
534#ifdef CONFIG_LIBERTAS_DEBUG
535 struct bss_descriptor *iter;
536 int i = 0;
537 DECLARE_SSID_BUF(ssid);
538#endif
539
540 lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d", full_scan);
541
542 /* Cancel any partial outstanding partial scans if this scan
543 * is a full scan.
544 */
545 if (full_scan && delayed_work_pending(&priv->scan_work))
546 cancel_delayed_work(&priv->scan_work);
547
548 /* User-specified bsstype or channel list
549 TODO: this can be implemented if some user-space application
550 need the feature. Formerly, it was accessible from debugfs,
551 but then nowhere used.
552 if (user_cfg) {
553 if (user_cfg->bsstype)
554 bsstype = user_cfg->bsstype;
555 } */
556
557 lbs_deb_scan("numchannels %d, bsstype %d\n", numchannels, bsstype);
558
559 /* Create list of channels to scan */
560 chan_list = kzalloc(sizeof(struct chanscanparamset) *
561 LBS_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL);
562 if (!chan_list) {
563 lbs_pr_alert("SCAN: chan_list empty\n");
564 goto out;
565 }
566
567 /* We want to scan all channels */
568 chan_count = lbs_scan_create_channel_list(priv, chan_list);
569
570 netif_stop_queue(priv->dev);
571 if (priv->mesh_dev)
572 netif_stop_queue(priv->mesh_dev);
573
574 /* Prepare to continue an interrupted scan */
575 lbs_deb_scan("chan_count %d, scan_channel %d\n",
576 chan_count, priv->scan_channel);
577 curr_chans = chan_list;
578 /* advance channel list by already-scanned-channels */
579 if (priv->scan_channel > 0) {
580 curr_chans += priv->scan_channel;
581 chan_count -= priv->scan_channel;
582 }
583
584 /* Send scan command(s)
585 * numchannels contains the number of channels we should maximally scan
586 * chan_count is the total number of channels to scan
587 */
588
589 while (chan_count) {
590 int to_scan = min(numchannels, chan_count);
591 lbs_deb_scan("scanning %d of %d channels\n",
592 to_scan, chan_count);
593 ret = lbs_do_scan(priv, bsstype, curr_chans,
594 to_scan);
595 if (ret) {
596 lbs_pr_err("SCAN_CMD failed\n");
597 goto out2;
598 }
599 curr_chans += to_scan;
600 chan_count -= to_scan;
601
602 /* somehow schedule the next part of the scan */
603 if (chan_count && !full_scan &&
604 !priv->surpriseremoved) {
605 /* -1 marks just that we're currently scanning */
606 if (priv->scan_channel < 0)
607 priv->scan_channel = to_scan;
608 else
609 priv->scan_channel += to_scan;
610 cancel_delayed_work(&priv->scan_work);
611 queue_delayed_work(priv->work_thread, &priv->scan_work,
612 msecs_to_jiffies(300));
613 /* skip over GIWSCAN event */
614 goto out;
615 }
616
617 }
618 memset(&wrqu, 0, sizeof(union iwreq_data));
619 wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
620
621#ifdef CONFIG_LIBERTAS_DEBUG
622 /* Dump the scan table */
623 mutex_lock(&priv->lock);
624 lbs_deb_scan("scan table:\n");
625 list_for_each_entry(iter, &priv->network_list, list)
626 lbs_deb_scan("%02d: BSSID %pM, RSSI %d, SSID '%s'\n",
627 i++, iter->bssid, iter->rssi,
628 print_ssid(ssid, iter->ssid, iter->ssid_len));
629 mutex_unlock(&priv->lock);
630#endif
631
632out2:
633 priv->scan_channel = 0;
634
635out:
636 if (priv->connect_status == LBS_CONNECTED && !priv->tx_pending_len)
637 netif_wake_queue(priv->dev);
638
639 if (priv->mesh_dev && lbs_mesh_connected(priv) &&
640 !priv->tx_pending_len)
641 netif_wake_queue(priv->mesh_dev);
642
643 kfree(chan_list);
644
645 lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
646 return ret;
647}
648
649void lbs_scan_worker(struct work_struct *work)
650{
651 struct lbs_private *priv =
652 container_of(work, struct lbs_private, scan_work.work);
653
654 lbs_deb_enter(LBS_DEB_SCAN);
655 lbs_scan_networks(priv, 0);
656 lbs_deb_leave(LBS_DEB_SCAN);
657}
658
659
660/*********************************************************************/
661/* */
662/* Result interpretation */
663/* */
664/*********************************************************************/
665
666/**
667 * @brief Interpret a BSS scan response returned from the firmware
668 *
669 * Parse the various fixed fields and IEs passed back for a BSS probe
670 * response or beacon from the scan command. Record information as needed
671 * in the scan table struct bss_descriptor for that entry.
672 *
673 * @param bss Output parameter: Pointer to the BSS Entry
674 *
675 * @return 0 or -1
676 */
677static int lbs_process_bss(struct bss_descriptor *bss,
678 uint8_t **pbeaconinfo, int *bytesleft)
679{
680 struct ieee_ie_fh_param_set *fh;
681 struct ieee_ie_ds_param_set *ds;
682 struct ieee_ie_cf_param_set *cf;
683 struct ieee_ie_ibss_param_set *ibss;
684 DECLARE_SSID_BUF(ssid);
685 uint8_t *pos, *end, *p;
686 uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0;
687 uint16_t beaconsize = 0;
688 int ret;
689
690 lbs_deb_enter(LBS_DEB_SCAN);
691
692 if (*bytesleft >= sizeof(beaconsize)) {
693 /* Extract & convert beacon size from the command buffer */
694 beaconsize = get_unaligned_le16(*pbeaconinfo);
695 *bytesleft -= sizeof(beaconsize);
696 *pbeaconinfo += sizeof(beaconsize);
697 }
698
699 if (beaconsize == 0 || beaconsize > *bytesleft) {
700 *pbeaconinfo += *bytesleft;
701 *bytesleft = 0;
702 ret = -1;
703 goto done;
704 }
705
706 /* Initialize the current working beacon pointer for this BSS iteration */
707 pos = *pbeaconinfo;
708 end = pos + beaconsize;
709
710 /* Advance the return beacon pointer past the current beacon */
711 *pbeaconinfo += beaconsize;
712 *bytesleft -= beaconsize;
713
714 memcpy(bss->bssid, pos, ETH_ALEN);
715 lbs_deb_scan("process_bss: BSSID %pM\n", bss->bssid);
716 pos += ETH_ALEN;
717
718 if ((end - pos) < 12) {
719 lbs_deb_scan("process_bss: Not enough bytes left\n");
720 ret = -1;
721 goto done;
722 }
723
724 /*
725 * next 4 fields are RSSI, time stamp, beacon interval,
726 * and capability information
727 */
728
729 /* RSSI is 1 byte long */
730 bss->rssi = *pos;
731 lbs_deb_scan("process_bss: RSSI %d\n", *pos);
732 pos++;
733
734 /* time stamp is 8 bytes long */
735 pos += 8;
736
737 /* beacon interval is 2 bytes long */
738 bss->beaconperiod = get_unaligned_le16(pos);
739 pos += 2;
740
741 /* capability information is 2 bytes long */
742 bss->capability = get_unaligned_le16(pos);
743 lbs_deb_scan("process_bss: capabilities 0x%04x\n", bss->capability);
744 pos += 2;
745
746 if (bss->capability & WLAN_CAPABILITY_PRIVACY)
747 lbs_deb_scan("process_bss: WEP enabled\n");
748 if (bss->capability & WLAN_CAPABILITY_IBSS)
749 bss->mode = IW_MODE_ADHOC;
750 else
751 bss->mode = IW_MODE_INFRA;
752
753 /* rest of the current buffer are IE's */
754 lbs_deb_scan("process_bss: IE len %zd\n", end - pos);
755 lbs_deb_hex(LBS_DEB_SCAN, "process_bss: IE info", pos, end - pos);
756
757 /* process variable IE */
758 while (pos <= end - 2) {
759 if (pos + pos[1] > end) {
760 lbs_deb_scan("process_bss: error in processing IE, "
761 "bytes left < IE length\n");
762 break;
763 }
764
765 switch (pos[0]) {
766 case WLAN_EID_SSID:
767 bss->ssid_len = min_t(int, IEEE80211_MAX_SSID_LEN, pos[1]);
768 memcpy(bss->ssid, pos + 2, bss->ssid_len);
769 lbs_deb_scan("got SSID IE: '%s', len %u\n",
770 print_ssid(ssid, bss->ssid, bss->ssid_len),
771 bss->ssid_len);
772 break;
773
774 case WLAN_EID_SUPP_RATES:
775 n_basic_rates = min_t(uint8_t, MAX_RATES, pos[1]);
776 memcpy(bss->rates, pos + 2, n_basic_rates);
777 got_basic_rates = 1;
778 lbs_deb_scan("got RATES IE\n");
779 break;
780
781 case WLAN_EID_FH_PARAMS:
782 fh = (struct ieee_ie_fh_param_set *) pos;
783 memcpy(&bss->phy.fh, fh, sizeof(*fh));
784 lbs_deb_scan("got FH IE\n");
785 break;
786
787 case WLAN_EID_DS_PARAMS:
788 ds = (struct ieee_ie_ds_param_set *) pos;
789 bss->channel = ds->channel;
790 memcpy(&bss->phy.ds, ds, sizeof(*ds));
791 lbs_deb_scan("got DS IE, channel %d\n", bss->channel);
792 break;
793
794 case WLAN_EID_CF_PARAMS:
795 cf = (struct ieee_ie_cf_param_set *) pos;
796 memcpy(&bss->ss.cf, cf, sizeof(*cf));
797 lbs_deb_scan("got CF IE\n");
798 break;
799
800 case WLAN_EID_IBSS_PARAMS:
801 ibss = (struct ieee_ie_ibss_param_set *) pos;
802 bss->atimwindow = ibss->atimwindow;
803 memcpy(&bss->ss.ibss, ibss, sizeof(*ibss));
804 lbs_deb_scan("got IBSS IE\n");
805 break;
806
807 case WLAN_EID_EXT_SUPP_RATES:
808 /* only process extended supported rate if data rate is
809 * already found. Data rate IE should come before
810 * extended supported rate IE
811 */
812 lbs_deb_scan("got RATESEX IE\n");
813 if (!got_basic_rates) {
814 lbs_deb_scan("... but ignoring it\n");
815 break;
816 }
817
818 n_ex_rates = pos[1];
819 if (n_basic_rates + n_ex_rates > MAX_RATES)
820 n_ex_rates = MAX_RATES - n_basic_rates;
821
822 p = bss->rates + n_basic_rates;
823 memcpy(p, pos + 2, n_ex_rates);
824 break;
825
826 case WLAN_EID_GENERIC:
827 if (pos[1] >= 4 &&
828 pos[2] == 0x00 && pos[3] == 0x50 &&
829 pos[4] == 0xf2 && pos[5] == 0x01) {
830 bss->wpa_ie_len = min(pos[1] + 2, MAX_WPA_IE_LEN);
831 memcpy(bss->wpa_ie, pos, bss->wpa_ie_len);
832 lbs_deb_scan("got WPA IE\n");
833 lbs_deb_hex(LBS_DEB_SCAN, "WPA IE", bss->wpa_ie,
834 bss->wpa_ie_len);
835 } else if (pos[1] >= MARVELL_MESH_IE_LENGTH &&
836 pos[2] == 0x00 && pos[3] == 0x50 &&
837 pos[4] == 0x43 && pos[5] == 0x04) {
838 lbs_deb_scan("got mesh IE\n");
839 bss->mesh = 1;
840 } else {
841 lbs_deb_scan("got generic IE: %02x:%02x:%02x:%02x, len %d\n",
842 pos[2], pos[3],
843 pos[4], pos[5],
844 pos[1]);
845 }
846 break;
847
848 case WLAN_EID_RSN:
849 lbs_deb_scan("got RSN IE\n");
850 bss->rsn_ie_len = min(pos[1] + 2, MAX_WPA_IE_LEN);
851 memcpy(bss->rsn_ie, pos, bss->rsn_ie_len);
852 lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE",
853 bss->rsn_ie, bss->rsn_ie_len);
854 break;
855
856 default:
857 lbs_deb_scan("got IE 0x%04x, len %d\n",
858 pos[0], pos[1]);
859 break;
860 }
861
862 pos += pos[1] + 2;
863 }
864
865 /* Timestamp */
866 bss->last_scanned = jiffies;
867 lbs_unset_basic_rate_flags(bss->rates, sizeof(bss->rates));
868
869 ret = 0;
870
871done:
872 lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
873 return ret;
874}
875
876/**
877 * @brief Send a scan command for all available channels filtered on a spec
878 *
879 * Used in association code and from debugfs
880 *
881 * @param priv A pointer to struct lbs_private structure
882 * @param ssid A pointer to the SSID to scan for
883 * @param ssid_len Length of the SSID
884 *
885 * @return 0-success, otherwise fail
886 */
887int lbs_send_specific_ssid_scan(struct lbs_private *priv, uint8_t *ssid,
888 uint8_t ssid_len)
889{
890 DECLARE_SSID_BUF(ssid_buf);
891 int ret = 0;
892
893 lbs_deb_enter_args(LBS_DEB_SCAN, "SSID '%s'\n",
894 print_ssid(ssid_buf, ssid, ssid_len));
895
896 if (!ssid_len)
897 goto out;
898
899 memcpy(priv->scan_ssid, ssid, ssid_len);
900 priv->scan_ssid_len = ssid_len;
901
902 lbs_scan_networks(priv, 1);
903 if (priv->surpriseremoved) {
904 ret = -1;
905 goto out;
906 }
907
908out:
909 lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
910 return ret;
911}
912
913
914
915
916/*********************************************************************/
917/* */
918/* Support for Wireless Extensions */
919/* */
920/*********************************************************************/
921
922
923#define MAX_CUSTOM_LEN 64
924
925static inline char *lbs_translate_scan(struct lbs_private *priv,
926 struct iw_request_info *info,
927 char *start, char *stop,
928 struct bss_descriptor *bss)
929{
930 struct chan_freq_power *cfp;
931 char *current_val; /* For rates */
932 struct iw_event iwe; /* Temporary buffer */
933 int j;
934#define PERFECT_RSSI ((uint8_t)50)
935#define WORST_RSSI ((uint8_t)0)
936#define RSSI_DIFF ((uint8_t)(PERFECT_RSSI - WORST_RSSI))
937 uint8_t rssi;
938
939 lbs_deb_enter(LBS_DEB_SCAN);
940
941 cfp = lbs_find_cfp_by_band_and_channel(priv, 0, bss->channel);
942 if (!cfp) {
943 lbs_deb_scan("Invalid channel number %d\n", bss->channel);
944 start = NULL;
945 goto out;
946 }
947
948 /* First entry *MUST* be the BSSID */
949 iwe.cmd = SIOCGIWAP;
950 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
951 memcpy(iwe.u.ap_addr.sa_data, &bss->bssid, ETH_ALEN);
952 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN);
953
954 /* SSID */
955 iwe.cmd = SIOCGIWESSID;
956 iwe.u.data.flags = 1;
957 iwe.u.data.length = min((uint32_t) bss->ssid_len, (uint32_t) IEEE80211_MAX_SSID_LEN);
958 start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid);
959
960 /* Mode */
961 iwe.cmd = SIOCGIWMODE;
962 iwe.u.mode = bss->mode;
963 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_UINT_LEN);
964
965 /* Frequency */
966 iwe.cmd = SIOCGIWFREQ;
967 iwe.u.freq.m = (long)cfp->freq * 100000;
968 iwe.u.freq.e = 1;
969 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN);
970
971 /* Add quality statistics */
972 iwe.cmd = IWEVQUAL;
973 iwe.u.qual.updated = IW_QUAL_ALL_UPDATED;
974 iwe.u.qual.level = SCAN_RSSI(bss->rssi);
975
976 rssi = iwe.u.qual.level - MRVDRV_NF_DEFAULT_SCAN_VALUE;
977 iwe.u.qual.qual =
978 (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - rssi) *
979 (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - rssi))) /
980 (RSSI_DIFF * RSSI_DIFF);
981 if (iwe.u.qual.qual > 100)
982 iwe.u.qual.qual = 100;
983
984 if (priv->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
985 iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
986 } else {
987 iwe.u.qual.noise = CAL_NF(priv->NF[TYPE_BEACON][TYPE_NOAVG]);
988 }
989
990 /* Locally created ad-hoc BSSs won't have beacons if this is the
991 * only station in the adhoc network; so get signal strength
992 * from receive statistics.
993 */
994 if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate
995 && !lbs_ssid_cmp(priv->curbssparams.ssid,
996 priv->curbssparams.ssid_len,
997 bss->ssid, bss->ssid_len)) {
998 int snr, nf;
999 snr = priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
1000 nf = priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
1001 iwe.u.qual.level = CAL_RSSI(snr, nf);
1002 }
1003 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN);
1004
1005 /* Add encryption capability */
1006 iwe.cmd = SIOCGIWENCODE;
1007 if (bss->capability & WLAN_CAPABILITY_PRIVACY) {
1008 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
1009 } else {
1010 iwe.u.data.flags = IW_ENCODE_DISABLED;
1011 }
1012 iwe.u.data.length = 0;
1013 start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid);
1014
1015 current_val = start + iwe_stream_lcp_len(info);
1016
1017 iwe.cmd = SIOCGIWRATE;
1018 iwe.u.bitrate.fixed = 0;
1019 iwe.u.bitrate.disabled = 0;
1020 iwe.u.bitrate.value = 0;
1021
1022 for (j = 0; j < ARRAY_SIZE(bss->rates) && bss->rates[j]; j++) {
1023 /* Bit rate given in 500 kb/s units */
1024 iwe.u.bitrate.value = bss->rates[j] * 500000;
1025 current_val = iwe_stream_add_value(info, start, current_val,
1026 stop, &iwe, IW_EV_PARAM_LEN);
1027 }
1028 if ((bss->mode == IW_MODE_ADHOC) && priv->adhoccreate
1029 && !lbs_ssid_cmp(priv->curbssparams.ssid,
1030 priv->curbssparams.ssid_len,
1031 bss->ssid, bss->ssid_len)) {
1032 iwe.u.bitrate.value = 22 * 500000;
1033 current_val = iwe_stream_add_value(info, start, current_val,
1034 stop, &iwe, IW_EV_PARAM_LEN);
1035 }
1036 /* Check if we added any event */
1037 if ((current_val - start) > iwe_stream_lcp_len(info))
1038 start = current_val;
1039
1040 memset(&iwe, 0, sizeof(iwe));
1041 if (bss->wpa_ie_len) {
1042 char buf[MAX_WPA_IE_LEN];
1043 memcpy(buf, bss->wpa_ie, bss->wpa_ie_len);
1044 iwe.cmd = IWEVGENIE;
1045 iwe.u.data.length = bss->wpa_ie_len;
1046 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
1047 }
1048
1049 memset(&iwe, 0, sizeof(iwe));
1050 if (bss->rsn_ie_len) {
1051 char buf[MAX_WPA_IE_LEN];
1052 memcpy(buf, bss->rsn_ie, bss->rsn_ie_len);
1053 iwe.cmd = IWEVGENIE;
1054 iwe.u.data.length = bss->rsn_ie_len;
1055 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
1056 }
1057
1058 if (bss->mesh) {
1059 char custom[MAX_CUSTOM_LEN];
1060 char *p = custom;
1061
1062 iwe.cmd = IWEVCUSTOM;
1063 p += snprintf(p, MAX_CUSTOM_LEN, "mesh-type: olpc");
1064 iwe.u.data.length = p - custom;
1065 if (iwe.u.data.length)
1066 start = iwe_stream_add_point(info, start, stop,
1067 &iwe, custom);
1068 }
1069
1070out:
1071 lbs_deb_leave_args(LBS_DEB_SCAN, "start %p", start);
1072 return start;
1073}
1074
1075
1076/**
1077 * @brief Handle Scan Network ioctl
1078 *
1079 * @param dev A pointer to net_device structure
1080 * @param info A pointer to iw_request_info structure
1081 * @param vwrq A pointer to iw_param structure
1082 * @param extra A pointer to extra data buf
1083 *
1084 * @return 0 --success, otherwise fail
1085 */
1086int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
1087 union iwreq_data *wrqu, char *extra)
1088{
1089 DECLARE_SSID_BUF(ssid);
1090 struct lbs_private *priv = dev->ml_priv;
1091 int ret = 0;
1092
1093 lbs_deb_enter(LBS_DEB_WEXT);
1094
1095 if (!priv->radio_on) {
1096 ret = -EINVAL;
1097 goto out;
1098 }
1099
1100 if (!netif_running(dev)) {
1101 ret = -ENETDOWN;
1102 goto out;
1103 }
1104
1105 /* mac80211 does this:
1106 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1107 if (sdata->type != IEEE80211_IF_TYPE_xxx) {
1108 ret = -EOPNOTSUPP;
1109 goto out;
1110 }
1111 */
1112
1113 if (wrqu->data.length == sizeof(struct iw_scan_req) &&
1114 wrqu->data.flags & IW_SCAN_THIS_ESSID) {
1115 struct iw_scan_req *req = (struct iw_scan_req *)extra;
1116 priv->scan_ssid_len = req->essid_len;
1117 memcpy(priv->scan_ssid, req->essid, priv->scan_ssid_len);
1118 lbs_deb_wext("set_scan, essid '%s'\n",
1119 print_ssid(ssid, priv->scan_ssid, priv->scan_ssid_len));
1120 } else {
1121 priv->scan_ssid_len = 0;
1122 }
1123
1124 if (!delayed_work_pending(&priv->scan_work))
1125 queue_delayed_work(priv->work_thread, &priv->scan_work,
1126 msecs_to_jiffies(50));
1127 /* set marker that currently a scan is taking place */
1128 priv->scan_channel = -1;
1129
1130 if (priv->surpriseremoved)
1131 ret = -EIO;
1132
1133out:
1134 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1135 return ret;
1136}
1137
1138
1139/**
1140 * @brief Handle Retrieve scan table ioctl
1141 *
1142 * @param dev A pointer to net_device structure
1143 * @param info A pointer to iw_request_info structure
1144 * @param dwrq A pointer to iw_point structure
1145 * @param extra A pointer to extra data buf
1146 *
1147 * @return 0 --success, otherwise fail
1148 */
1149int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
1150 struct iw_point *dwrq, char *extra)
1151{
1152#define SCAN_ITEM_SIZE 128
1153 struct lbs_private *priv = dev->ml_priv;
1154 int err = 0;
1155 char *ev = extra;
1156 char *stop = ev + dwrq->length;
1157 struct bss_descriptor *iter_bss;
1158 struct bss_descriptor *safe;
1159
1160 lbs_deb_enter(LBS_DEB_WEXT);
1161
1162 /* iwlist should wait until the current scan is finished */
1163 if (priv->scan_channel)
1164 return -EAGAIN;
1165
1166 /* Update RSSI if current BSS is a locally created ad-hoc BSS */
1167 if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate) {
1168 err = lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
1169 CMD_OPTION_WAITFORRSP, 0, NULL);
1170 if (err)
1171 goto out;
1172 }
1173
1174 mutex_lock(&priv->lock);
1175 list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) {
1176 char *next_ev;
1177 unsigned long stale_time;
1178
1179 if (stop - ev < SCAN_ITEM_SIZE) {
1180 err = -E2BIG;
1181 break;
1182 }
1183
1184 /* For mesh device, list only mesh networks */
1185 if (dev == priv->mesh_dev && !iter_bss->mesh)
1186 continue;
1187
1188 /* Prune old an old scan result */
1189 stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE;
1190 if (time_after(jiffies, stale_time)) {
1191 list_move_tail(&iter_bss->list, &priv->network_free_list);
1192 clear_bss_descriptor(iter_bss);
1193 continue;
1194 }
1195
1196 /* Translate to WE format this entry */
1197 next_ev = lbs_translate_scan(priv, info, ev, stop, iter_bss);
1198 if (next_ev == NULL)
1199 continue;
1200 ev = next_ev;
1201 }
1202 mutex_unlock(&priv->lock);
1203
1204 dwrq->length = (ev - extra);
1205 dwrq->flags = 0;
1206out:
1207 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", err);
1208 return err;
1209}
1210
1211
1212
1213
1214/*********************************************************************/
1215/* */
1216/* Command execution */
1217/* */
1218/*********************************************************************/
1219
1220
1221/**
1222 * @brief This function handles the command response of scan
1223 *
1224 * Called from handle_cmd_response() in cmdrespc.
1225 *
1226 * The response buffer for the scan command has the following
1227 * memory layout:
1228 *
1229 * .-----------------------------------------------------------.
1230 * | header (4 * sizeof(u16)): Standard command response hdr |
1231 * .-----------------------------------------------------------.
1232 * | bufsize (u16) : sizeof the BSS Description data |
1233 * .-----------------------------------------------------------.
1234 * | NumOfSet (u8) : Number of BSS Descs returned |
1235 * .-----------------------------------------------------------.
1236 * | BSSDescription data (variable, size given in bufsize) |
1237 * .-----------------------------------------------------------.
1238 * | TLV data (variable, size calculated using header->size, |
1239 * | bufsize and sizeof the fixed fields above) |
1240 * .-----------------------------------------------------------.
1241 *
1242 * @param priv A pointer to struct lbs_private structure
1243 * @param resp A pointer to cmd_ds_command
1244 *
1245 * @return 0 or -1
1246 */
1247static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy,
1248 struct cmd_header *resp)
1249{
1250 struct cmd_ds_802_11_scan_rsp *scanresp = (void *)resp;
1251 struct bss_descriptor *iter_bss;
1252 struct bss_descriptor *safe;
1253 uint8_t *bssinfo;
1254 uint16_t scanrespsize;
1255 int bytesleft;
1256 int idx;
1257 int tlvbufsize;
1258 int ret;
1259
1260 lbs_deb_enter(LBS_DEB_SCAN);
1261
1262 /* Prune old entries from scan table */
1263 list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) {
1264 unsigned long stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE;
1265 if (time_before(jiffies, stale_time))
1266 continue;
1267 list_move_tail (&iter_bss->list, &priv->network_free_list);
1268 clear_bss_descriptor(iter_bss);
1269 }
1270
1271 if (scanresp->nr_sets > MAX_NETWORK_COUNT) {
1272 lbs_deb_scan("SCAN_RESP: too many scan results (%d, max %d)\n",
1273 scanresp->nr_sets, MAX_NETWORK_COUNT);
1274 ret = -1;
1275 goto done;
1276 }
1277
1278 bytesleft = get_unaligned_le16(&scanresp->bssdescriptsize);
1279 lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft);
1280
1281 scanrespsize = le16_to_cpu(resp->size);
1282 lbs_deb_scan("SCAN_RESP: scan results %d\n", scanresp->nr_sets);
1283
1284 bssinfo = scanresp->bssdesc_and_tlvbuffer;
1285
1286 /* The size of the TLV buffer is equal to the entire command response
1287 * size (scanrespsize) minus the fixed fields (sizeof()'s), the
1288 * BSS Descriptions (bssdescriptsize as bytesLef) and the command
1289 * response header (sizeof(struct cmd_header))
1290 */
1291 tlvbufsize = scanrespsize - (bytesleft + sizeof(scanresp->bssdescriptsize)
1292 + sizeof(scanresp->nr_sets)
1293 + sizeof(struct cmd_header));
1294
1295 /*
1296 * Process each scan response returned (scanresp->nr_sets). Save
1297 * the information in the newbssentry and then insert into the
1298 * driver scan table either as an update to an existing entry
1299 * or as an addition at the end of the table
1300 */
1301 for (idx = 0; idx < scanresp->nr_sets && bytesleft; idx++) {
1302 struct bss_descriptor new;
1303 struct bss_descriptor *found = NULL;
1304 struct bss_descriptor *oldest = NULL;
1305
1306 /* Process the data fields and IEs returned for this BSS */
1307 memset(&new, 0, sizeof (struct bss_descriptor));
1308 if (lbs_process_bss(&new, &bssinfo, &bytesleft) != 0) {
1309 /* error parsing the scan response, skipped */
1310 lbs_deb_scan("SCAN_RESP: process_bss returned ERROR\n");
1311 continue;
1312 }
1313
1314 /* Try to find this bss in the scan table */
1315 list_for_each_entry (iter_bss, &priv->network_list, list) {
1316 if (is_same_network(iter_bss, &new)) {
1317 found = iter_bss;
1318 break;
1319 }
1320
1321 if ((oldest == NULL) ||
1322 (iter_bss->last_scanned < oldest->last_scanned))
1323 oldest = iter_bss;
1324 }
1325
1326 if (found) {
1327 /* found, clear it */
1328 clear_bss_descriptor(found);
1329 } else if (!list_empty(&priv->network_free_list)) {
1330 /* Pull one from the free list */
1331 found = list_entry(priv->network_free_list.next,
1332 struct bss_descriptor, list);
1333 list_move_tail(&found->list, &priv->network_list);
1334 } else if (oldest) {
1335 /* If there are no more slots, expire the oldest */
1336 found = oldest;
1337 clear_bss_descriptor(found);
1338 list_move_tail(&found->list, &priv->network_list);
1339 } else {
1340 continue;
1341 }
1342
1343 lbs_deb_scan("SCAN_RESP: BSSID %pM\n", new.bssid);
1344
1345 /* Copy the locally created newbssentry to the scan table */
1346 memcpy(found, &new, offsetof(struct bss_descriptor, list));
1347 }
1348
1349 ret = 0;
1350
1351done:
1352 lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
1353 return ret;
1354}
diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h
deleted file mode 100644
index 8fb1706d7526..000000000000
--- a/drivers/net/wireless/libertas/scan.h
+++ /dev/null
@@ -1,63 +0,0 @@
1/**
2 * Interface for the wlan network scan routines
3 *
4 * Driver interface functions and type declarations for the scan module
5 * implemented in scan.c.
6 */
7#ifndef _LBS_SCAN_H
8#define _LBS_SCAN_H
9
10#include <net/iw_handler.h>
11
12struct lbs_private;
13
14#define MAX_NETWORK_COUNT 128
15
16/** Chan-freq-TxPower mapping table*/
17struct chan_freq_power {
18 /** channel Number */
19 u16 channel;
20 /** frequency of this channel */
21 u32 freq;
22 /** Max allowed Tx power level */
23 u16 maxtxpower;
24 /** TRUE:channel unsupported; FLASE:supported*/
25 u8 unsupported;
26};
27
28/** region-band mapping table*/
29struct region_channel {
30 /** TRUE if this entry is valid */
31 u8 valid;
32 /** region code for US, Japan ... */
33 u8 region;
34 /** band B/G/A, used for BAND_CONFIG cmd */
35 u8 band;
36 /** Actual No. of elements in the array below */
37 u8 nrcfp;
38 /** chan-freq-txpower mapping table*/
39 struct chan_freq_power *CFP;
40};
41
42/**
43 * @brief Maximum number of channels that can be sent in a setuserscan ioctl
44 */
45#define LBS_IOCTL_USER_SCAN_CHAN_MAX 50
46
47int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len);
48
49int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band);
50
51int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid,
52 u8 ssid_len);
53
54int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
55 struct iw_point *dwrq, char *extra);
56int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
57 union iwreq_data *wrqu, char *extra);
58
59int lbs_scan_networks(struct lbs_private *priv, int full_scan);
60
61void lbs_scan_worker(struct work_struct *work);
62
63#endif
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c
index a9bf658659eb..411a3bbf035e 100644
--- a/drivers/net/wireless/libertas/tx.c
+++ b/drivers/net/wireless/libertas/tx.c
@@ -4,13 +4,13 @@
4#include <linux/netdevice.h> 4#include <linux/netdevice.h>
5#include <linux/etherdevice.h> 5#include <linux/etherdevice.h>
6#include <linux/sched.h> 6#include <linux/sched.h>
7#include <net/cfg80211.h>
7 8
8#include "host.h" 9#include "host.h"
9#include "radiotap.h" 10#include "radiotap.h"
10#include "decl.h" 11#include "decl.h"
11#include "defs.h" 12#include "defs.h"
12#include "dev.h" 13#include "dev.h"
13#include "wext.h"
14 14
15/** 15/**
16 * @brief This function converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE 16 * @brief This function converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE
@@ -111,7 +111,7 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
111 p802x_hdr = skb->data; 111 p802x_hdr = skb->data;
112 pkt_len = skb->len; 112 pkt_len = skb->len;
113 113
114 if (dev == priv->rtap_net_dev) { 114 if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
115 struct tx_radiotap_hdr *rtap_hdr = (void *)skb->data; 115 struct tx_radiotap_hdr *rtap_hdr = (void *)skb->data;
116 116
117 /* set txpd fields from the radiotap header */ 117 /* set txpd fields from the radiotap header */
@@ -147,7 +147,7 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
147 dev->stats.tx_packets++; 147 dev->stats.tx_packets++;
148 dev->stats.tx_bytes += skb->len; 148 dev->stats.tx_bytes += skb->len;
149 149
150 if (priv->monitormode) { 150 if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
151 /* Keep the skb to echo it back once Tx feedback is 151 /* Keep the skb to echo it back once Tx feedback is
152 received from FW */ 152 received from FW */
153 skb_orphan(skb); 153 skb_orphan(skb);
@@ -158,6 +158,7 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
158 free: 158 free:
159 dev_kfree_skb_any(skb); 159 dev_kfree_skb_any(skb);
160 } 160 }
161
161 unlock: 162 unlock:
162 spin_unlock_irqrestore(&priv->driver_lock, flags); 163 spin_unlock_irqrestore(&priv->driver_lock, flags);
163 wake_up(&priv->waitq); 164 wake_up(&priv->waitq);
@@ -179,7 +180,8 @@ void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count)
179{ 180{
180 struct tx_radiotap_hdr *radiotap_hdr; 181 struct tx_radiotap_hdr *radiotap_hdr;
181 182
182 if (!priv->monitormode || priv->currenttxskb == NULL) 183 if (!priv->wdev->iftype == NL80211_IFTYPE_MONITOR ||
184 priv->currenttxskb == NULL)
183 return; 185 return;
184 186
185 radiotap_hdr = (struct tx_radiotap_hdr *)priv->currenttxskb->data; 187 radiotap_hdr = (struct tx_radiotap_hdr *)priv->currenttxskb->data;
@@ -188,7 +190,7 @@ void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count)
188 (1 + priv->txretrycount - try_count) : 0; 190 (1 + priv->txretrycount - try_count) : 0;
189 191
190 priv->currenttxskb->protocol = eth_type_trans(priv->currenttxskb, 192 priv->currenttxskb->protocol = eth_type_trans(priv->currenttxskb,
191 priv->rtap_net_dev); 193 priv->dev);
192 netif_rx(priv->currenttxskb); 194 netif_rx(priv->currenttxskb);
193 195
194 priv->currenttxskb = NULL; 196 priv->currenttxskb = NULL;
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
deleted file mode 100644
index f96a96031a50..000000000000
--- a/drivers/net/wireless/libertas/wext.c
+++ /dev/null
@@ -1,2353 +0,0 @@
1/**
2 * This file contains ioctl functions
3 */
4#include <linux/ctype.h>
5#include <linux/slab.h>
6#include <linux/delay.h>
7#include <linux/if.h>
8#include <linux/if_arp.h>
9#include <linux/wireless.h>
10#include <linux/bitops.h>
11
12#include <net/lib80211.h>
13#include <net/iw_handler.h>
14
15#include "host.h"
16#include "radiotap.h"
17#include "decl.h"
18#include "defs.h"
19#include "dev.h"
20#include "wext.h"
21#include "scan.h"
22#include "assoc.h"
23#include "cmd.h"
24
25
26static inline void lbs_postpone_association_work(struct lbs_private *priv)
27{
28 if (priv->surpriseremoved)
29 return;
30 cancel_delayed_work(&priv->assoc_work);
31 queue_delayed_work(priv->work_thread, &priv->assoc_work, HZ / 2);
32}
33
34static inline void lbs_do_association_work(struct lbs_private *priv)
35{
36 if (priv->surpriseremoved)
37 return;
38 cancel_delayed_work(&priv->assoc_work);
39 queue_delayed_work(priv->work_thread, &priv->assoc_work, 0);
40}
41
42static inline void lbs_cancel_association_work(struct lbs_private *priv)
43{
44 cancel_delayed_work(&priv->assoc_work);
45 kfree(priv->pending_assoc_req);
46 priv->pending_assoc_req = NULL;
47}
48
49void lbs_send_disconnect_notification(struct lbs_private *priv)
50{
51 union iwreq_data wrqu;
52
53 memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
54 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
55 wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
56}
57
58static void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str)
59{
60 union iwreq_data iwrq;
61 u8 buf[50];
62
63 lbs_deb_enter(LBS_DEB_WEXT);
64
65 memset(&iwrq, 0, sizeof(union iwreq_data));
66 memset(buf, 0, sizeof(buf));
67
68 snprintf(buf, sizeof(buf) - 1, "%s", str);
69
70 iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN;
71
72 /* Send Event to upper layer */
73 lbs_deb_wext("event indication string %s\n", (char *)buf);
74 lbs_deb_wext("event indication length %d\n", iwrq.data.length);
75 lbs_deb_wext("sending wireless event IWEVCUSTOM for %s\n", str);
76
77 wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf);
78
79 lbs_deb_leave(LBS_DEB_WEXT);
80}
81
82/**
83 * @brief This function handles MIC failure event.
84 *
85 * @param priv A pointer to struct lbs_private structure
86 * @para event the event id
87 * @return n/a
88 */
89void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event)
90{
91 char buf[50];
92
93 lbs_deb_enter(LBS_DEB_CMD);
94 memset(buf, 0, sizeof(buf));
95
96 sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication ");
97
98 if (event == MACREG_INT_CODE_MIC_ERR_UNICAST)
99 strcat(buf, "unicast ");
100 else
101 strcat(buf, "multicast ");
102
103 lbs_send_iwevcustom_event(priv, buf);
104 lbs_deb_leave(LBS_DEB_CMD);
105}
106
107/**
108 * @brief Find the channel frequency power info with specific channel
109 *
110 * @param priv A pointer to struct lbs_private structure
111 * @param band it can be BAND_A, BAND_G or BAND_B
112 * @param channel the channel for looking
113 * @return A pointer to struct chan_freq_power structure or NULL if not find.
114 */
115struct chan_freq_power *lbs_find_cfp_by_band_and_channel(
116 struct lbs_private *priv,
117 u8 band,
118 u16 channel)
119{
120 struct chan_freq_power *cfp = NULL;
121 struct region_channel *rc;
122 int i, j;
123
124 for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) {
125 rc = &priv->region_channel[j];
126
127 if (!rc->valid || !rc->CFP)
128 continue;
129 if (rc->band != band)
130 continue;
131 for (i = 0; i < rc->nrcfp; i++) {
132 if (rc->CFP[i].channel == channel) {
133 cfp = &rc->CFP[i];
134 break;
135 }
136 }
137 }
138
139 if (!cfp && channel)
140 lbs_deb_wext("lbs_find_cfp_by_band_and_channel: can't find "
141 "cfp by band %d / channel %d\n", band, channel);
142
143 return cfp;
144}
145
146/**
147 * @brief Find the channel frequency power info with specific frequency
148 *
149 * @param priv A pointer to struct lbs_private structure
150 * @param band it can be BAND_A, BAND_G or BAND_B
151 * @param freq the frequency for looking
152 * @return A pointer to struct chan_freq_power structure or NULL if not find.
153 */
154static struct chan_freq_power *find_cfp_by_band_and_freq(
155 struct lbs_private *priv,
156 u8 band,
157 u32 freq)
158{
159 struct chan_freq_power *cfp = NULL;
160 struct region_channel *rc;
161 int i, j;
162
163 for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) {
164 rc = &priv->region_channel[j];
165
166 if (!rc->valid || !rc->CFP)
167 continue;
168 if (rc->band != band)
169 continue;
170 for (i = 0; i < rc->nrcfp; i++) {
171 if (rc->CFP[i].freq == freq) {
172 cfp = &rc->CFP[i];
173 break;
174 }
175 }
176 }
177
178 if (!cfp && freq)
179 lbs_deb_wext("find_cfp_by_band_and_freql: can't find cfp by "
180 "band %d / freq %d\n", band, freq);
181
182 return cfp;
183}
184
185/**
186 * @brief Copy active data rates based on adapter mode and status
187 *
188 * @param priv A pointer to struct lbs_private structure
189 * @param rate The buf to return the active rates
190 */
191static void copy_active_data_rates(struct lbs_private *priv, u8 *rates)
192{
193 lbs_deb_enter(LBS_DEB_WEXT);
194
195 if ((priv->connect_status != LBS_CONNECTED) &&
196 !lbs_mesh_connected(priv))
197 memcpy(rates, lbs_bg_rates, MAX_RATES);
198 else
199 memcpy(rates, priv->curbssparams.rates, MAX_RATES);
200
201 lbs_deb_leave(LBS_DEB_WEXT);
202}
203
204static int lbs_get_name(struct net_device *dev, struct iw_request_info *info,
205 char *cwrq, char *extra)
206{
207
208 lbs_deb_enter(LBS_DEB_WEXT);
209
210 /* We could add support for 802.11n here as needed. Jean II */
211 snprintf(cwrq, IFNAMSIZ, "IEEE 802.11b/g");
212
213 lbs_deb_leave(LBS_DEB_WEXT);
214 return 0;
215}
216
217static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info,
218 struct iw_freq *fwrq, char *extra)
219{
220 struct lbs_private *priv = dev->ml_priv;
221 struct chan_freq_power *cfp;
222
223 lbs_deb_enter(LBS_DEB_WEXT);
224
225 cfp = lbs_find_cfp_by_band_and_channel(priv, 0,
226 priv->channel);
227
228 if (!cfp) {
229 if (priv->channel)
230 lbs_deb_wext("invalid channel %d\n",
231 priv->channel);
232 return -EINVAL;
233 }
234
235 fwrq->m = (long)cfp->freq * 100000;
236 fwrq->e = 1;
237
238 lbs_deb_wext("freq %u\n", fwrq->m);
239 lbs_deb_leave(LBS_DEB_WEXT);
240 return 0;
241}
242
243static int lbs_get_wap(struct net_device *dev, struct iw_request_info *info,
244 struct sockaddr *awrq, char *extra)
245{
246 struct lbs_private *priv = dev->ml_priv;
247
248 lbs_deb_enter(LBS_DEB_WEXT);
249
250 if (priv->connect_status == LBS_CONNECTED) {
251 memcpy(awrq->sa_data, priv->curbssparams.bssid, ETH_ALEN);
252 } else {
253 memset(awrq->sa_data, 0, ETH_ALEN);
254 }
255 awrq->sa_family = ARPHRD_ETHER;
256
257 lbs_deb_leave(LBS_DEB_WEXT);
258 return 0;
259}
260
261static int lbs_set_nick(struct net_device *dev, struct iw_request_info *info,
262 struct iw_point *dwrq, char *extra)
263{
264 struct lbs_private *priv = dev->ml_priv;
265
266 lbs_deb_enter(LBS_DEB_WEXT);
267
268 /*
269 * Check the size of the string
270 */
271
272 if (dwrq->length > 16) {
273 return -E2BIG;
274 }
275
276 mutex_lock(&priv->lock);
277 memset(priv->nodename, 0, sizeof(priv->nodename));
278 memcpy(priv->nodename, extra, dwrq->length);
279 mutex_unlock(&priv->lock);
280
281 lbs_deb_leave(LBS_DEB_WEXT);
282 return 0;
283}
284
285static int lbs_get_nick(struct net_device *dev, struct iw_request_info *info,
286 struct iw_point *dwrq, char *extra)
287{
288 struct lbs_private *priv = dev->ml_priv;
289
290 lbs_deb_enter(LBS_DEB_WEXT);
291
292 dwrq->length = strlen(priv->nodename);
293 memcpy(extra, priv->nodename, dwrq->length);
294 extra[dwrq->length] = '\0';
295
296 dwrq->flags = 1; /* active */
297
298 lbs_deb_leave(LBS_DEB_WEXT);
299 return 0;
300}
301
302#ifdef CONFIG_LIBERTAS_MESH
303static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info,
304 struct iw_point *dwrq, char *extra)
305{
306 struct lbs_private *priv = dev->ml_priv;
307
308 lbs_deb_enter(LBS_DEB_WEXT);
309
310 /* Use nickname to indicate that mesh is on */
311
312 if (lbs_mesh_connected(priv)) {
313 strncpy(extra, "Mesh", 12);
314 extra[12] = '\0';
315 dwrq->length = strlen(extra);
316 }
317
318 else {
319 extra[0] = '\0';
320 dwrq->length = 0;
321 }
322
323 lbs_deb_leave(LBS_DEB_WEXT);
324 return 0;
325}
326#endif
327
328static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info,
329 struct iw_param *vwrq, char *extra)
330{
331 int ret = 0;
332 struct lbs_private *priv = dev->ml_priv;
333 u32 val = vwrq->value;
334
335 lbs_deb_enter(LBS_DEB_WEXT);
336
337 if (vwrq->disabled)
338 val = MRVDRV_RTS_MAX_VALUE;
339
340 if (val > MRVDRV_RTS_MAX_VALUE) /* min rts value is 0 */
341 return -EINVAL;
342
343 ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, (u16) val);
344
345 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
346 return ret;
347}
348
349static int lbs_get_rts(struct net_device *dev, struct iw_request_info *info,
350 struct iw_param *vwrq, char *extra)
351{
352 struct lbs_private *priv = dev->ml_priv;
353 int ret = 0;
354 u16 val = 0;
355
356 lbs_deb_enter(LBS_DEB_WEXT);
357
358 ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, &val);
359 if (ret)
360 goto out;
361
362 vwrq->value = val;
363 vwrq->disabled = val > MRVDRV_RTS_MAX_VALUE; /* min rts value is 0 */
364 vwrq->fixed = 1;
365
366out:
367 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
368 return ret;
369}
370
371static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info,
372 struct iw_param *vwrq, char *extra)
373{
374 struct lbs_private *priv = dev->ml_priv;
375 int ret = 0;
376 u32 val = vwrq->value;
377
378 lbs_deb_enter(LBS_DEB_WEXT);
379
380 if (vwrq->disabled)
381 val = MRVDRV_FRAG_MAX_VALUE;
382
383 if (val < MRVDRV_FRAG_MIN_VALUE || val > MRVDRV_FRAG_MAX_VALUE)
384 return -EINVAL;
385
386 ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, (u16) val);
387
388 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
389 return ret;
390}
391
392static int lbs_get_frag(struct net_device *dev, struct iw_request_info *info,
393 struct iw_param *vwrq, char *extra)
394{
395 struct lbs_private *priv = dev->ml_priv;
396 int ret = 0;
397 u16 val = 0;
398
399 lbs_deb_enter(LBS_DEB_WEXT);
400
401 ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, &val);
402 if (ret)
403 goto out;
404
405 vwrq->value = val;
406 vwrq->disabled = ((val < MRVDRV_FRAG_MIN_VALUE)
407 || (val > MRVDRV_FRAG_MAX_VALUE));
408 vwrq->fixed = 1;
409
410out:
411 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
412 return ret;
413}
414
415static int lbs_get_mode(struct net_device *dev,
416 struct iw_request_info *info, u32 * uwrq, char *extra)
417{
418 struct lbs_private *priv = dev->ml_priv;
419
420 lbs_deb_enter(LBS_DEB_WEXT);
421
422 *uwrq = priv->mode;
423
424 lbs_deb_leave(LBS_DEB_WEXT);
425 return 0;
426}
427
428#ifdef CONFIG_LIBERTAS_MESH
429static int mesh_wlan_get_mode(struct net_device *dev,
430 struct iw_request_info *info, u32 * uwrq,
431 char *extra)
432{
433 lbs_deb_enter(LBS_DEB_WEXT);
434
435 *uwrq = IW_MODE_REPEAT;
436
437 lbs_deb_leave(LBS_DEB_WEXT);
438 return 0;
439}
440#endif
441
442static int lbs_get_txpow(struct net_device *dev,
443 struct iw_request_info *info,
444 struct iw_param *vwrq, char *extra)
445{
446 struct lbs_private *priv = dev->ml_priv;
447 s16 curlevel = 0;
448 int ret = 0;
449
450 lbs_deb_enter(LBS_DEB_WEXT);
451
452 if (!priv->radio_on) {
453 lbs_deb_wext("tx power off\n");
454 vwrq->value = 0;
455 vwrq->disabled = 1;
456 goto out;
457 }
458
459 ret = lbs_get_tx_power(priv, &curlevel, NULL, NULL);
460 if (ret)
461 goto out;
462
463 lbs_deb_wext("tx power level %d dbm\n", curlevel);
464 priv->txpower_cur = curlevel;
465
466 vwrq->value = curlevel;
467 vwrq->fixed = 1;
468 vwrq->disabled = 0;
469 vwrq->flags = IW_TXPOW_DBM;
470
471out:
472 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
473 return ret;
474}
475
476static int lbs_set_retry(struct net_device *dev, struct iw_request_info *info,
477 struct iw_param *vwrq, char *extra)
478{
479 struct lbs_private *priv = dev->ml_priv;
480 int ret = 0;
481 u16 slimit = 0, llimit = 0;
482
483 lbs_deb_enter(LBS_DEB_WEXT);
484
485 if ((vwrq->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT)
486 return -EOPNOTSUPP;
487
488 /* The MAC has a 4-bit Total_Tx_Count register
489 Total_Tx_Count = 1 + Tx_Retry_Count */
490#define TX_RETRY_MIN 0
491#define TX_RETRY_MAX 14
492 if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX)
493 return -EINVAL;
494
495 /* Add 1 to convert retry count to try count */
496 if (vwrq->flags & IW_RETRY_SHORT)
497 slimit = (u16) (vwrq->value + 1);
498 else if (vwrq->flags & IW_RETRY_LONG)
499 llimit = (u16) (vwrq->value + 1);
500 else
501 slimit = llimit = (u16) (vwrq->value + 1); /* set both */
502
503 if (llimit) {
504 ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_LONG_RETRY_LIMIT,
505 llimit);
506 if (ret)
507 goto out;
508 }
509
510 if (slimit) {
511 /* txretrycount follows the short retry limit */
512 priv->txretrycount = slimit;
513 ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_SHORT_RETRY_LIMIT,
514 slimit);
515 if (ret)
516 goto out;
517 }
518
519out:
520 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
521 return ret;
522}
523
524static int lbs_get_retry(struct net_device *dev, struct iw_request_info *info,
525 struct iw_param *vwrq, char *extra)
526{
527 struct lbs_private *priv = dev->ml_priv;
528 int ret = 0;
529 u16 val = 0;
530
531 lbs_deb_enter(LBS_DEB_WEXT);
532
533 vwrq->disabled = 0;
534
535 if (vwrq->flags & IW_RETRY_LONG) {
536 ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_LONG_RETRY_LIMIT, &val);
537 if (ret)
538 goto out;
539
540 /* Subtract 1 to convert try count to retry count */
541 vwrq->value = val - 1;
542 vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
543 } else {
544 ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_SHORT_RETRY_LIMIT, &val);
545 if (ret)
546 goto out;
547
548 /* txretry count follows the short retry limit */
549 priv->txretrycount = val;
550 /* Subtract 1 to convert try count to retry count */
551 vwrq->value = val - 1;
552 vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_SHORT;
553 }
554
555out:
556 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
557 return ret;
558}
559
560static inline void sort_channels(struct iw_freq *freq, int num)
561{
562 int i, j;
563 struct iw_freq temp;
564
565 for (i = 0; i < num; i++)
566 for (j = i + 1; j < num; j++)
567 if (freq[i].i > freq[j].i) {
568 temp.i = freq[i].i;
569 temp.m = freq[i].m;
570
571 freq[i].i = freq[j].i;
572 freq[i].m = freq[j].m;
573
574 freq[j].i = temp.i;
575 freq[j].m = temp.m;
576 }
577}
578
579/* data rate listing
580 MULTI_BANDS:
581 abg a b b/g
582 Infra G(12) A(8) B(4) G(12)
583 Adhoc A+B(12) A(8) B(4) B(4)
584
585 non-MULTI_BANDS:
586 b b/g
587 Infra B(4) G(12)
588 Adhoc B(4) B(4)
589 */
590/**
591 * @brief Get Range Info
592 *
593 * @param dev A pointer to net_device structure
594 * @param info A pointer to iw_request_info structure
595 * @param vwrq A pointer to iw_param structure
596 * @param extra A pointer to extra data buf
597 * @return 0 --success, otherwise fail
598 */
599static int lbs_get_range(struct net_device *dev, struct iw_request_info *info,
600 struct iw_point *dwrq, char *extra)
601{
602 int i, j;
603 struct lbs_private *priv = dev->ml_priv;
604 struct iw_range *range = (struct iw_range *)extra;
605 struct chan_freq_power *cfp;
606 u8 rates[MAX_RATES + 1];
607
608 lbs_deb_enter(LBS_DEB_WEXT);
609
610 dwrq->length = sizeof(struct iw_range);
611 memset(range, 0, sizeof(struct iw_range));
612
613 range->min_nwid = 0;
614 range->max_nwid = 0;
615
616 memset(rates, 0, sizeof(rates));
617 copy_active_data_rates(priv, rates);
618 range->num_bitrates = strnlen(rates, IW_MAX_BITRATES);
619 for (i = 0; i < range->num_bitrates; i++)
620 range->bitrate[i] = rates[i] * 500000;
621 range->num_bitrates = i;
622 lbs_deb_wext("IW_MAX_BITRATES %d, num_bitrates %d\n", IW_MAX_BITRATES,
623 range->num_bitrates);
624
625 range->num_frequency = 0;
626
627 range->scan_capa = IW_SCAN_CAPA_ESSID;
628
629 for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
630 && (j < ARRAY_SIZE(priv->region_channel)); j++) {
631 cfp = priv->region_channel[j].CFP;
632 for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
633 && priv->region_channel[j].valid
634 && cfp
635 && (i < priv->region_channel[j].nrcfp); i++) {
636 range->freq[range->num_frequency].i =
637 (long)cfp->channel;
638 range->freq[range->num_frequency].m =
639 (long)cfp->freq * 100000;
640 range->freq[range->num_frequency].e = 1;
641 cfp++;
642 range->num_frequency++;
643 }
644 }
645
646 lbs_deb_wext("IW_MAX_FREQUENCIES %d, num_frequency %d\n",
647 IW_MAX_FREQUENCIES, range->num_frequency);
648
649 range->num_channels = range->num_frequency;
650
651 sort_channels(&range->freq[0], range->num_frequency);
652
653 /*
654 * Set an indication of the max TCP throughput in bit/s that we can
655 * expect using this interface
656 */
657 if (i > 2)
658 range->throughput = 5000 * 1000;
659 else
660 range->throughput = 1500 * 1000;
661
662 range->min_rts = MRVDRV_RTS_MIN_VALUE;
663 range->max_rts = MRVDRV_RTS_MAX_VALUE;
664 range->min_frag = MRVDRV_FRAG_MIN_VALUE;
665 range->max_frag = MRVDRV_FRAG_MAX_VALUE;
666
667 range->encoding_size[0] = 5;
668 range->encoding_size[1] = 13;
669 range->num_encoding_sizes = 2;
670 range->max_encoding_tokens = 4;
671
672 /*
673 * Right now we support only "iwconfig ethX power on|off"
674 */
675 range->pm_capa = IW_POWER_ON;
676
677 /*
678 * Minimum version we recommend
679 */
680 range->we_version_source = 15;
681
682 /*
683 * Version we are compiled with
684 */
685 range->we_version_compiled = WIRELESS_EXT;
686
687 range->retry_capa = IW_RETRY_LIMIT;
688 range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
689
690 range->min_retry = TX_RETRY_MIN;
691 range->max_retry = TX_RETRY_MAX;
692
693 /*
694 * Set the qual, level and noise range values
695 */
696 range->max_qual.qual = 100;
697 range->max_qual.level = 0;
698 range->max_qual.noise = 0;
699 range->max_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
700
701 range->avg_qual.qual = 70;
702 /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
703 range->avg_qual.level = 0;
704 range->avg_qual.noise = 0;
705 range->avg_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
706
707 range->sensitivity = 0;
708
709 /* Setup the supported power level ranges */
710 memset(range->txpower, 0, sizeof(range->txpower));
711 range->txpower_capa = IW_TXPOW_DBM | IW_TXPOW_RANGE;
712 range->txpower[0] = priv->txpower_min;
713 range->txpower[1] = priv->txpower_max;
714 range->num_txpower = 2;
715
716 range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
717 IW_EVENT_CAPA_MASK(SIOCGIWAP) |
718 IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
719 range->event_capa[1] = IW_EVENT_CAPA_K_1;
720
721 if (priv->fwcapinfo & FW_CAPINFO_WPA) {
722 range->enc_capa = IW_ENC_CAPA_WPA
723 | IW_ENC_CAPA_WPA2
724 | IW_ENC_CAPA_CIPHER_TKIP
725 | IW_ENC_CAPA_CIPHER_CCMP;
726 }
727
728 lbs_deb_leave(LBS_DEB_WEXT);
729 return 0;
730}
731
732static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
733 struct iw_param *vwrq, char *extra)
734{
735 struct lbs_private *priv = dev->ml_priv;
736 int ret = 0;
737
738 lbs_deb_enter(LBS_DEB_WEXT);
739
740 if (!(priv->fwcapinfo & FW_CAPINFO_PS)) {
741 if (vwrq->disabled)
742 return 0;
743 else
744 return -EINVAL;
745 }
746
747 /* PS is currently supported only in Infrastructure mode
748 * Remove this check if it is to be supported in IBSS mode also
749 */
750
751 if (vwrq->disabled) {
752 priv->psmode = LBS802_11POWERMODECAM;
753 if (priv->psstate != PS_STATE_FULL_POWER) {
754 lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
755 }
756
757 return 0;
758 }
759
760 if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
761 lbs_deb_wext(
762 "setting power timeout is not supported\n");
763 return -EINVAL;
764 } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
765 vwrq->value = vwrq->value / 1000;
766 if (!priv->enter_deep_sleep) {
767 lbs_pr_err("deep sleep feature is not implemented "
768 "for this interface driver\n");
769 return -EINVAL;
770 }
771
772 if (priv->connect_status == LBS_CONNECTED) {
773 if ((priv->is_auto_deep_sleep_enabled) &&
774 (vwrq->value == -1000)) {
775 lbs_exit_auto_deep_sleep(priv);
776 return 0;
777 } else {
778 lbs_pr_err("can't use deep sleep cmd in "
779 "connected state\n");
780 return -EINVAL;
781 }
782 }
783
784 if ((vwrq->value < 0) && (vwrq->value != -1000)) {
785 lbs_pr_err("unknown option\n");
786 return -EINVAL;
787 }
788
789 if (vwrq->value > 0) {
790 if (!priv->is_auto_deep_sleep_enabled) {
791 priv->is_activity_detected = 0;
792 priv->auto_deep_sleep_timeout = vwrq->value;
793 lbs_enter_auto_deep_sleep(priv);
794 } else {
795 priv->auto_deep_sleep_timeout = vwrq->value;
796 lbs_deb_debugfs("auto deep sleep: "
797 "already enabled\n");
798 }
799 return 0;
800 } else {
801 if (priv->is_auto_deep_sleep_enabled) {
802 lbs_exit_auto_deep_sleep(priv);
803 /* Try to exit deep sleep if auto */
804 /*deep sleep disabled */
805 ret = lbs_set_deep_sleep(priv, 0);
806 }
807 if (vwrq->value == 0)
808 ret = lbs_set_deep_sleep(priv, 1);
809 else if (vwrq->value == -1000)
810 ret = lbs_set_deep_sleep(priv, 0);
811 return ret;
812 }
813 }
814
815 if (priv->psmode != LBS802_11POWERMODECAM) {
816 return 0;
817 }
818
819 priv->psmode = LBS802_11POWERMODEMAX_PSP;
820
821 if (priv->connect_status == LBS_CONNECTED) {
822 lbs_ps_sleep(priv, CMD_OPTION_WAITFORRSP);
823 }
824
825 lbs_deb_leave(LBS_DEB_WEXT);
826
827 return 0;
828}
829
830static int lbs_get_power(struct net_device *dev, struct iw_request_info *info,
831 struct iw_param *vwrq, char *extra)
832{
833 struct lbs_private *priv = dev->ml_priv;
834
835 lbs_deb_enter(LBS_DEB_WEXT);
836
837 vwrq->value = 0;
838 vwrq->flags = 0;
839 vwrq->disabled = priv->psmode == LBS802_11POWERMODECAM
840 || priv->connect_status == LBS_DISCONNECTED;
841
842 lbs_deb_leave(LBS_DEB_WEXT);
843 return 0;
844}
845
846static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
847{
848 enum {
849 POOR = 30,
850 FAIR = 60,
851 GOOD = 80,
852 VERY_GOOD = 90,
853 EXCELLENT = 95,
854 PERFECT = 100
855 };
856 struct lbs_private *priv = dev->ml_priv;
857 u32 rssi_qual;
858 u32 tx_qual;
859 u32 quality = 0;
860 int ret, stats_valid = 0;
861 u8 rssi;
862 u32 tx_retries;
863 struct cmd_ds_802_11_get_log log;
864
865 lbs_deb_enter(LBS_DEB_WEXT);
866
867 priv->wstats.status = priv->mode;
868
869 /* If we're not associated, all quality values are meaningless */
870 if ((priv->connect_status != LBS_CONNECTED) &&
871 !lbs_mesh_connected(priv))
872 goto out;
873
874 /* Quality by RSSI */
875 priv->wstats.qual.level =
876 CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],
877 priv->NF[TYPE_BEACON][TYPE_NOAVG]);
878
879 if (priv->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
880 priv->wstats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
881 } else {
882 priv->wstats.qual.noise =
883 CAL_NF(priv->NF[TYPE_BEACON][TYPE_NOAVG]);
884 }
885
886 lbs_deb_wext("signal level %#x\n", priv->wstats.qual.level);
887 lbs_deb_wext("noise %#x\n", priv->wstats.qual.noise);
888
889 rssi = priv->wstats.qual.level - priv->wstats.qual.noise;
890 if (rssi < 15)
891 rssi_qual = rssi * POOR / 10;
892 else if (rssi < 20)
893 rssi_qual = (rssi - 15) * (FAIR - POOR) / 5 + POOR;
894 else if (rssi < 30)
895 rssi_qual = (rssi - 20) * (GOOD - FAIR) / 5 + FAIR;
896 else if (rssi < 40)
897 rssi_qual = (rssi - 30) * (VERY_GOOD - GOOD) /
898 10 + GOOD;
899 else
900 rssi_qual = (rssi - 40) * (PERFECT - VERY_GOOD) /
901 10 + VERY_GOOD;
902 quality = rssi_qual;
903
904 /* Quality by TX errors */
905 priv->wstats.discard.retries = dev->stats.tx_errors;
906
907 memset(&log, 0, sizeof(log));
908 log.hdr.size = cpu_to_le16(sizeof(log));
909 ret = lbs_cmd_with_response(priv, CMD_802_11_GET_LOG, &log);
910 if (ret)
911 goto out;
912
913 tx_retries = le32_to_cpu(log.retry);
914
915 if (tx_retries > 75)
916 tx_qual = (90 - tx_retries) * POOR / 15;
917 else if (tx_retries > 70)
918 tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR;
919 else if (tx_retries > 65)
920 tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;
921 else if (tx_retries > 50)
922 tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) /
923 15 + GOOD;
924 else
925 tx_qual = (50 - tx_retries) *
926 (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
927 quality = min(quality, tx_qual);
928
929 priv->wstats.discard.code = le32_to_cpu(log.wepundecryptable);
930 priv->wstats.discard.retries = tx_retries;
931 priv->wstats.discard.misc = le32_to_cpu(log.ackfailure);
932
933 /* Calculate quality */
934 priv->wstats.qual.qual = min_t(u8, quality, 100);
935 priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
936 stats_valid = 1;
937
938 /* update stats asynchronously for future calls */
939 ret = lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
940 0, 0, NULL);
941 if (ret)
942 lbs_pr_err("RSSI command failed\n");
943out:
944 if (!stats_valid) {
945 priv->wstats.miss.beacon = 0;
946 priv->wstats.discard.retries = 0;
947 priv->wstats.qual.qual = 0;
948 priv->wstats.qual.level = 0;
949 priv->wstats.qual.noise = 0;
950 priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED;
951 priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID |
952 IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
953 }
954
955 lbs_deb_leave(LBS_DEB_WEXT);
956 return &priv->wstats;
957
958
959}
960
961static int lbs_set_freq(struct net_device *dev, struct iw_request_info *info,
962 struct iw_freq *fwrq, char *extra)
963{
964 int ret = -EINVAL;
965 struct lbs_private *priv = dev->ml_priv;
966 struct chan_freq_power *cfp;
967 struct assoc_request * assoc_req;
968
969 lbs_deb_enter(LBS_DEB_WEXT);
970
971 mutex_lock(&priv->lock);
972 assoc_req = lbs_get_association_request(priv);
973 if (!assoc_req) {
974 ret = -ENOMEM;
975 goto out;
976 }
977
978 /* If setting by frequency, convert to a channel */
979 if (fwrq->e == 1) {
980 long f = fwrq->m / 100000;
981
982 cfp = find_cfp_by_band_and_freq(priv, 0, f);
983 if (!cfp) {
984 lbs_deb_wext("invalid freq %ld\n", f);
985 goto out;
986 }
987
988 fwrq->e = 0;
989 fwrq->m = (int) cfp->channel;
990 }
991
992 /* Setting by channel number */
993 if (fwrq->m > 1000 || fwrq->e > 0) {
994 goto out;
995 }
996
997 cfp = lbs_find_cfp_by_band_and_channel(priv, 0, fwrq->m);
998 if (!cfp) {
999 goto out;
1000 }
1001
1002 assoc_req->channel = fwrq->m;
1003 ret = 0;
1004
1005out:
1006 if (ret == 0) {
1007 set_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags);
1008 lbs_postpone_association_work(priv);
1009 } else {
1010 lbs_cancel_association_work(priv);
1011 }
1012 mutex_unlock(&priv->lock);
1013
1014 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1015 return ret;
1016}
1017
1018#ifdef CONFIG_LIBERTAS_MESH
1019static int lbs_mesh_set_freq(struct net_device *dev,
1020 struct iw_request_info *info,
1021 struct iw_freq *fwrq, char *extra)
1022{
1023 struct lbs_private *priv = dev->ml_priv;
1024 struct chan_freq_power *cfp;
1025 int ret = -EINVAL;
1026
1027 lbs_deb_enter(LBS_DEB_WEXT);
1028
1029 /* If setting by frequency, convert to a channel */
1030 if (fwrq->e == 1) {
1031 long f = fwrq->m / 100000;
1032
1033 cfp = find_cfp_by_band_and_freq(priv, 0, f);
1034 if (!cfp) {
1035 lbs_deb_wext("invalid freq %ld\n", f);
1036 goto out;
1037 }
1038
1039 fwrq->e = 0;
1040 fwrq->m = (int) cfp->channel;
1041 }
1042
1043 /* Setting by channel number */
1044 if (fwrq->m > 1000 || fwrq->e > 0) {
1045 goto out;
1046 }
1047
1048 cfp = lbs_find_cfp_by_band_and_channel(priv, 0, fwrq->m);
1049 if (!cfp) {
1050 goto out;
1051 }
1052
1053 if (fwrq->m != priv->channel) {
1054 lbs_deb_wext("mesh channel change forces eth disconnect\n");
1055 if (priv->mode == IW_MODE_INFRA)
1056 lbs_cmd_80211_deauthenticate(priv,
1057 priv->curbssparams.bssid,
1058 WLAN_REASON_DEAUTH_LEAVING);
1059 else if (priv->mode == IW_MODE_ADHOC)
1060 lbs_adhoc_stop(priv);
1061 }
1062 lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, fwrq->m);
1063 lbs_update_channel(priv);
1064 ret = 0;
1065
1066out:
1067 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1068 return ret;
1069}
1070#endif
1071
1072static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info,
1073 struct iw_param *vwrq, char *extra)
1074{
1075 struct lbs_private *priv = dev->ml_priv;
1076 u8 new_rate = 0;
1077 int ret = -EINVAL;
1078 u8 rates[MAX_RATES + 1];
1079
1080 lbs_deb_enter(LBS_DEB_WEXT);
1081
1082 lbs_deb_wext("vwrq->value %d\n", vwrq->value);
1083 lbs_deb_wext("vwrq->fixed %d\n", vwrq->fixed);
1084
1085 if (vwrq->fixed && vwrq->value == -1)
1086 goto out;
1087
1088 /* Auto rate? */
1089 priv->enablehwauto = !vwrq->fixed;
1090
1091 if (vwrq->value == -1)
1092 priv->cur_rate = 0;
1093 else {
1094 if (vwrq->value % 100000)
1095 goto out;
1096
1097 new_rate = vwrq->value / 500000;
1098 priv->cur_rate = new_rate;
1099 /* the rest is only needed for lbs_set_data_rate() */
1100 memset(rates, 0, sizeof(rates));
1101 copy_active_data_rates(priv, rates);
1102 if (!memchr(rates, new_rate, sizeof(rates))) {
1103 lbs_pr_alert("fixed data rate 0x%X out of range\n",
1104 new_rate);
1105 goto out;
1106 }
1107 if (priv->fwrelease < 0x09000000) {
1108 ret = lbs_set_power_adapt_cfg(priv, 0,
1109 POW_ADAPT_DEFAULT_P0,
1110 POW_ADAPT_DEFAULT_P1,
1111 POW_ADAPT_DEFAULT_P2);
1112 if (ret)
1113 goto out;
1114 }
1115 ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1,
1116 TPC_DEFAULT_P2, 1);
1117 if (ret)
1118 goto out;
1119 }
1120
1121 /* Try the newer command first (Firmware Spec 5.1 and above) */
1122 ret = lbs_cmd_802_11_rate_adapt_rateset(priv, CMD_ACT_SET);
1123
1124 /* Fallback to older version */
1125 if (ret)
1126 ret = lbs_set_data_rate(priv, new_rate);
1127
1128out:
1129 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1130 return ret;
1131}
1132
1133static int lbs_get_rate(struct net_device *dev, struct iw_request_info *info,
1134 struct iw_param *vwrq, char *extra)
1135{
1136 struct lbs_private *priv = dev->ml_priv;
1137
1138 lbs_deb_enter(LBS_DEB_WEXT);
1139
1140 if (priv->connect_status == LBS_CONNECTED) {
1141 vwrq->value = priv->cur_rate * 500000;
1142
1143 if (priv->enablehwauto)
1144 vwrq->fixed = 0;
1145 else
1146 vwrq->fixed = 1;
1147
1148 } else {
1149 vwrq->fixed = 0;
1150 vwrq->value = 0;
1151 }
1152
1153 lbs_deb_leave(LBS_DEB_WEXT);
1154 return 0;
1155}
1156
1157static int lbs_set_mode(struct net_device *dev,
1158 struct iw_request_info *info, u32 * uwrq, char *extra)
1159{
1160 int ret = 0;
1161 struct lbs_private *priv = dev->ml_priv;
1162 struct assoc_request * assoc_req;
1163
1164 lbs_deb_enter(LBS_DEB_WEXT);
1165
1166 if ( (*uwrq != IW_MODE_ADHOC)
1167 && (*uwrq != IW_MODE_INFRA)
1168 && (*uwrq != IW_MODE_AUTO)) {
1169 lbs_deb_wext("Invalid mode: 0x%x\n", *uwrq);
1170 ret = -EINVAL;
1171 goto out;
1172 }
1173
1174 mutex_lock(&priv->lock);
1175 assoc_req = lbs_get_association_request(priv);
1176 if (!assoc_req) {
1177 ret = -ENOMEM;
1178 lbs_cancel_association_work(priv);
1179 } else {
1180 assoc_req->mode = *uwrq;
1181 set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
1182 lbs_postpone_association_work(priv);
1183 lbs_deb_wext("Switching to mode: 0x%x\n", *uwrq);
1184 }
1185 mutex_unlock(&priv->lock);
1186
1187out:
1188 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1189 return ret;
1190}
1191
1192
1193/**
1194 * @brief Get Encryption key
1195 *
1196 * @param dev A pointer to net_device structure
1197 * @param info A pointer to iw_request_info structure
1198 * @param vwrq A pointer to iw_param structure
1199 * @param extra A pointer to extra data buf
1200 * @return 0 --success, otherwise fail
1201 */
1202static int lbs_get_encode(struct net_device *dev,
1203 struct iw_request_info *info,
1204 struct iw_point *dwrq, u8 * extra)
1205{
1206 struct lbs_private *priv = dev->ml_priv;
1207 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
1208
1209 lbs_deb_enter(LBS_DEB_WEXT);
1210
1211 lbs_deb_wext("flags 0x%x, index %d, length %d, wep_tx_keyidx %d\n",
1212 dwrq->flags, index, dwrq->length, priv->wep_tx_keyidx);
1213
1214 dwrq->flags = 0;
1215
1216 /* Authentication method */
1217 switch (priv->secinfo.auth_mode) {
1218 case IW_AUTH_ALG_OPEN_SYSTEM:
1219 dwrq->flags = IW_ENCODE_OPEN;
1220 break;
1221
1222 case IW_AUTH_ALG_SHARED_KEY:
1223 case IW_AUTH_ALG_LEAP:
1224 dwrq->flags = IW_ENCODE_RESTRICTED;
1225 break;
1226 default:
1227 dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
1228 break;
1229 }
1230
1231 memset(extra, 0, 16);
1232
1233 mutex_lock(&priv->lock);
1234
1235 /* Default to returning current transmit key */
1236 if (index < 0)
1237 index = priv->wep_tx_keyidx;
1238
1239 if ((priv->wep_keys[index].len) && priv->secinfo.wep_enabled) {
1240 memcpy(extra, priv->wep_keys[index].key,
1241 priv->wep_keys[index].len);
1242 dwrq->length = priv->wep_keys[index].len;
1243
1244 dwrq->flags |= (index + 1);
1245 /* Return WEP enabled */
1246 dwrq->flags &= ~IW_ENCODE_DISABLED;
1247 } else if ((priv->secinfo.WPAenabled)
1248 || (priv->secinfo.WPA2enabled)) {
1249 /* return WPA enabled */
1250 dwrq->flags &= ~IW_ENCODE_DISABLED;
1251 dwrq->flags |= IW_ENCODE_NOKEY;
1252 } else {
1253 dwrq->flags |= IW_ENCODE_DISABLED;
1254 }
1255
1256 mutex_unlock(&priv->lock);
1257
1258 lbs_deb_wext("key: %02x:%02x:%02x:%02x:%02x:%02x, keylen %d\n",
1259 extra[0], extra[1], extra[2],
1260 extra[3], extra[4], extra[5], dwrq->length);
1261
1262 lbs_deb_wext("return flags 0x%x\n", dwrq->flags);
1263
1264 lbs_deb_leave(LBS_DEB_WEXT);
1265 return 0;
1266}
1267
1268/**
1269 * @brief Set Encryption key (internal)
1270 *
1271 * @param priv A pointer to private card structure
1272 * @param key_material A pointer to key material
1273 * @param key_length length of key material
1274 * @param index key index to set
1275 * @param set_tx_key Force set TX key (1 = yes, 0 = no)
1276 * @return 0 --success, otherwise fail
1277 */
1278static int lbs_set_wep_key(struct assoc_request *assoc_req,
1279 const char *key_material,
1280 u16 key_length,
1281 u16 index,
1282 int set_tx_key)
1283{
1284 int ret = 0;
1285 struct enc_key *pkey;
1286
1287 lbs_deb_enter(LBS_DEB_WEXT);
1288
1289 /* Paranoid validation of key index */
1290 if (index > 3) {
1291 ret = -EINVAL;
1292 goto out;
1293 }
1294
1295 /* validate max key length */
1296 if (key_length > KEY_LEN_WEP_104) {
1297 ret = -EINVAL;
1298 goto out;
1299 }
1300
1301 pkey = &assoc_req->wep_keys[index];
1302
1303 if (key_length > 0) {
1304 memset(pkey, 0, sizeof(struct enc_key));
1305 pkey->type = KEY_TYPE_ID_WEP;
1306
1307 /* Standardize the key length */
1308 pkey->len = (key_length > KEY_LEN_WEP_40) ?
1309 KEY_LEN_WEP_104 : KEY_LEN_WEP_40;
1310 memcpy(pkey->key, key_material, key_length);
1311 }
1312
1313 if (set_tx_key) {
1314 /* Ensure the chosen key is valid */
1315 if (!pkey->len) {
1316 lbs_deb_wext("key not set, so cannot enable it\n");
1317 ret = -EINVAL;
1318 goto out;
1319 }
1320 assoc_req->wep_tx_keyidx = index;
1321 }
1322
1323 assoc_req->secinfo.wep_enabled = 1;
1324
1325out:
1326 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1327 return ret;
1328}
1329
1330static int validate_key_index(u16 def_index, u16 raw_index,
1331 u16 *out_index, u16 *is_default)
1332{
1333 if (!out_index || !is_default)
1334 return -EINVAL;
1335
1336 /* Verify index if present, otherwise use default TX key index */
1337 if (raw_index > 0) {
1338 if (raw_index > 4)
1339 return -EINVAL;
1340 *out_index = raw_index - 1;
1341 } else {
1342 *out_index = def_index;
1343 *is_default = 1;
1344 }
1345 return 0;
1346}
1347
1348static void disable_wep(struct assoc_request *assoc_req)
1349{
1350 int i;
1351
1352 lbs_deb_enter(LBS_DEB_WEXT);
1353
1354 /* Set Open System auth mode */
1355 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
1356
1357 /* Clear WEP keys and mark WEP as disabled */
1358 assoc_req->secinfo.wep_enabled = 0;
1359 for (i = 0; i < 4; i++)
1360 assoc_req->wep_keys[i].len = 0;
1361
1362 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1363 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1364
1365 lbs_deb_leave(LBS_DEB_WEXT);
1366}
1367
1368static void disable_wpa(struct assoc_request *assoc_req)
1369{
1370 lbs_deb_enter(LBS_DEB_WEXT);
1371
1372 memset(&assoc_req->wpa_mcast_key, 0, sizeof (struct enc_key));
1373 assoc_req->wpa_mcast_key.flags = KEY_INFO_WPA_MCAST;
1374 set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
1375
1376 memset(&assoc_req->wpa_unicast_key, 0, sizeof (struct enc_key));
1377 assoc_req->wpa_unicast_key.flags = KEY_INFO_WPA_UNICAST;
1378 set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
1379
1380 assoc_req->secinfo.WPAenabled = 0;
1381 assoc_req->secinfo.WPA2enabled = 0;
1382 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1383
1384 lbs_deb_leave(LBS_DEB_WEXT);
1385}
1386
1387/**
1388 * @brief Set Encryption key
1389 *
1390 * @param dev A pointer to net_device structure
1391 * @param info A pointer to iw_request_info structure
1392 * @param vwrq A pointer to iw_param structure
1393 * @param extra A pointer to extra data buf
1394 * @return 0 --success, otherwise fail
1395 */
1396static int lbs_set_encode(struct net_device *dev,
1397 struct iw_request_info *info,
1398 struct iw_point *dwrq, char *extra)
1399{
1400 int ret = 0;
1401 struct lbs_private *priv = dev->ml_priv;
1402 struct assoc_request * assoc_req;
1403 u16 is_default = 0, index = 0, set_tx_key = 0;
1404
1405 lbs_deb_enter(LBS_DEB_WEXT);
1406
1407 mutex_lock(&priv->lock);
1408 assoc_req = lbs_get_association_request(priv);
1409 if (!assoc_req) {
1410 ret = -ENOMEM;
1411 goto out;
1412 }
1413
1414 if (dwrq->flags & IW_ENCODE_DISABLED) {
1415 disable_wep (assoc_req);
1416 disable_wpa (assoc_req);
1417 goto out;
1418 }
1419
1420 ret = validate_key_index(assoc_req->wep_tx_keyidx,
1421 (dwrq->flags & IW_ENCODE_INDEX),
1422 &index, &is_default);
1423 if (ret) {
1424 ret = -EINVAL;
1425 goto out;
1426 }
1427
1428 /* If WEP isn't enabled, or if there is no key data but a valid
1429 * index, set the TX key.
1430 */
1431 if (!assoc_req->secinfo.wep_enabled || (dwrq->length == 0 && !is_default))
1432 set_tx_key = 1;
1433
1434 ret = lbs_set_wep_key(assoc_req, extra, dwrq->length, index, set_tx_key);
1435 if (ret)
1436 goto out;
1437
1438 if (dwrq->length)
1439 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1440 if (set_tx_key)
1441 set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
1442
1443 if (dwrq->flags & IW_ENCODE_RESTRICTED) {
1444 priv->authtype_auto = 0;
1445 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
1446 } else if (dwrq->flags & IW_ENCODE_OPEN) {
1447 priv->authtype_auto = 0;
1448 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
1449 }
1450
1451out:
1452 if (ret == 0) {
1453 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1454 lbs_postpone_association_work(priv);
1455 } else {
1456 lbs_cancel_association_work(priv);
1457 }
1458 mutex_unlock(&priv->lock);
1459
1460 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1461 return ret;
1462}
1463
1464/**
1465 * @brief Get Extended Encryption key (WPA/802.1x and WEP)
1466 *
1467 * @param dev A pointer to net_device structure
1468 * @param info A pointer to iw_request_info structure
1469 * @param vwrq A pointer to iw_param structure
1470 * @param extra A pointer to extra data buf
1471 * @return 0 on success, otherwise failure
1472 */
1473static int lbs_get_encodeext(struct net_device *dev,
1474 struct iw_request_info *info,
1475 struct iw_point *dwrq,
1476 char *extra)
1477{
1478 int ret = -EINVAL;
1479 struct lbs_private *priv = dev->ml_priv;
1480 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1481 int index, max_key_len;
1482
1483 lbs_deb_enter(LBS_DEB_WEXT);
1484
1485 max_key_len = dwrq->length - sizeof(*ext);
1486 if (max_key_len < 0)
1487 goto out;
1488
1489 index = dwrq->flags & IW_ENCODE_INDEX;
1490 if (index) {
1491 if (index < 1 || index > 4)
1492 goto out;
1493 index--;
1494 } else {
1495 index = priv->wep_tx_keyidx;
1496 }
1497
1498 if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
1499 ext->alg != IW_ENCODE_ALG_WEP) {
1500 if (index != 0 || priv->mode != IW_MODE_INFRA)
1501 goto out;
1502 }
1503
1504 dwrq->flags = index + 1;
1505 memset(ext, 0, sizeof(*ext));
1506
1507 if ( !priv->secinfo.wep_enabled
1508 && !priv->secinfo.WPAenabled
1509 && !priv->secinfo.WPA2enabled) {
1510 ext->alg = IW_ENCODE_ALG_NONE;
1511 ext->key_len = 0;
1512 dwrq->flags |= IW_ENCODE_DISABLED;
1513 } else {
1514 u8 *key = NULL;
1515
1516 if ( priv->secinfo.wep_enabled
1517 && !priv->secinfo.WPAenabled
1518 && !priv->secinfo.WPA2enabled) {
1519 /* WEP */
1520 ext->alg = IW_ENCODE_ALG_WEP;
1521 ext->key_len = priv->wep_keys[index].len;
1522 key = &priv->wep_keys[index].key[0];
1523 } else if ( !priv->secinfo.wep_enabled
1524 && (priv->secinfo.WPAenabled ||
1525 priv->secinfo.WPA2enabled)) {
1526 /* WPA */
1527 struct enc_key * pkey = NULL;
1528
1529 if ( priv->wpa_mcast_key.len
1530 && (priv->wpa_mcast_key.flags & KEY_INFO_WPA_ENABLED))
1531 pkey = &priv->wpa_mcast_key;
1532 else if ( priv->wpa_unicast_key.len
1533 && (priv->wpa_unicast_key.flags & KEY_INFO_WPA_ENABLED))
1534 pkey = &priv->wpa_unicast_key;
1535
1536 if (pkey) {
1537 if (pkey->type == KEY_TYPE_ID_AES) {
1538 ext->alg = IW_ENCODE_ALG_CCMP;
1539 } else {
1540 ext->alg = IW_ENCODE_ALG_TKIP;
1541 }
1542 ext->key_len = pkey->len;
1543 key = &pkey->key[0];
1544 } else {
1545 ext->alg = IW_ENCODE_ALG_TKIP;
1546 ext->key_len = 0;
1547 }
1548 } else {
1549 goto out;
1550 }
1551
1552 if (ext->key_len > max_key_len) {
1553 ret = -E2BIG;
1554 goto out;
1555 }
1556
1557 if (ext->key_len)
1558 memcpy(ext->key, key, ext->key_len);
1559 else
1560 dwrq->flags |= IW_ENCODE_NOKEY;
1561 dwrq->flags |= IW_ENCODE_ENABLED;
1562 }
1563 ret = 0;
1564
1565out:
1566 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1567 return ret;
1568}
1569
1570/**
1571 * @brief Set Encryption key Extended (WPA/802.1x and WEP)
1572 *
1573 * @param dev A pointer to net_device structure
1574 * @param info A pointer to iw_request_info structure
1575 * @param vwrq A pointer to iw_param structure
1576 * @param extra A pointer to extra data buf
1577 * @return 0 --success, otherwise fail
1578 */
1579static int lbs_set_encodeext(struct net_device *dev,
1580 struct iw_request_info *info,
1581 struct iw_point *dwrq,
1582 char *extra)
1583{
1584 int ret = 0;
1585 struct lbs_private *priv = dev->ml_priv;
1586 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1587 int alg = ext->alg;
1588 struct assoc_request * assoc_req;
1589
1590 lbs_deb_enter(LBS_DEB_WEXT);
1591
1592 mutex_lock(&priv->lock);
1593 assoc_req = lbs_get_association_request(priv);
1594 if (!assoc_req) {
1595 ret = -ENOMEM;
1596 goto out;
1597 }
1598
1599 if ((alg == IW_ENCODE_ALG_NONE) || (dwrq->flags & IW_ENCODE_DISABLED)) {
1600 disable_wep (assoc_req);
1601 disable_wpa (assoc_req);
1602 } else if (alg == IW_ENCODE_ALG_WEP) {
1603 u16 is_default = 0, index, set_tx_key = 0;
1604
1605 ret = validate_key_index(assoc_req->wep_tx_keyidx,
1606 (dwrq->flags & IW_ENCODE_INDEX),
1607 &index, &is_default);
1608 if (ret)
1609 goto out;
1610
1611 /* If WEP isn't enabled, or if there is no key data but a valid
1612 * index, or if the set-TX-key flag was passed, set the TX key.
1613 */
1614 if ( !assoc_req->secinfo.wep_enabled
1615 || (dwrq->length == 0 && !is_default)
1616 || (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY))
1617 set_tx_key = 1;
1618
1619 /* Copy key to driver */
1620 ret = lbs_set_wep_key(assoc_req, ext->key, ext->key_len, index,
1621 set_tx_key);
1622 if (ret)
1623 goto out;
1624
1625 if (dwrq->flags & IW_ENCODE_RESTRICTED) {
1626 priv->authtype_auto = 0;
1627 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
1628 } else if (dwrq->flags & IW_ENCODE_OPEN) {
1629 priv->authtype_auto = 0;
1630 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
1631 }
1632
1633 /* Mark the various WEP bits as modified */
1634 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1635 if (dwrq->length)
1636 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1637 if (set_tx_key)
1638 set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
1639 } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) {
1640 struct enc_key * pkey;
1641
1642 /* validate key length */
1643 if (((alg == IW_ENCODE_ALG_TKIP)
1644 && (ext->key_len != KEY_LEN_WPA_TKIP))
1645 || ((alg == IW_ENCODE_ALG_CCMP)
1646 && (ext->key_len != KEY_LEN_WPA_AES))) {
1647 lbs_deb_wext("invalid size %d for key of alg "
1648 "type %d\n",
1649 ext->key_len,
1650 alg);
1651 ret = -EINVAL;
1652 goto out;
1653 }
1654
1655 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
1656 pkey = &assoc_req->wpa_mcast_key;
1657 set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
1658 } else {
1659 pkey = &assoc_req->wpa_unicast_key;
1660 set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
1661 }
1662
1663 memset(pkey, 0, sizeof (struct enc_key));
1664 memcpy(pkey->key, ext->key, ext->key_len);
1665 pkey->len = ext->key_len;
1666 if (pkey->len)
1667 pkey->flags |= KEY_INFO_WPA_ENABLED;
1668
1669 /* Do this after zeroing key structure */
1670 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
1671 pkey->flags |= KEY_INFO_WPA_MCAST;
1672 } else {
1673 pkey->flags |= KEY_INFO_WPA_UNICAST;
1674 }
1675
1676 if (alg == IW_ENCODE_ALG_TKIP) {
1677 pkey->type = KEY_TYPE_ID_TKIP;
1678 } else if (alg == IW_ENCODE_ALG_CCMP) {
1679 pkey->type = KEY_TYPE_ID_AES;
1680 }
1681
1682 /* If WPA isn't enabled yet, do that now */
1683 if ( assoc_req->secinfo.WPAenabled == 0
1684 && assoc_req->secinfo.WPA2enabled == 0) {
1685 assoc_req->secinfo.WPAenabled = 1;
1686 assoc_req->secinfo.WPA2enabled = 1;
1687 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1688 }
1689
1690 /* Only disable wep if necessary: can't waste time here. */
1691 if (priv->mac_control & CMD_ACT_MAC_WEP_ENABLE)
1692 disable_wep(assoc_req);
1693 }
1694
1695out:
1696 if (ret == 0) {
1697 /* 802.1x and WPA rekeying must happen as quickly as possible,
1698 * especially during the 4-way handshake; thus if in
1699 * infrastructure mode, and either (a) 802.1x is enabled or
1700 * (b) WPA is being used, set the key right away.
1701 */
1702 if (assoc_req->mode == IW_MODE_INFRA &&
1703 ((assoc_req->secinfo.key_mgmt & IW_AUTH_KEY_MGMT_802_1X) ||
1704 (assoc_req->secinfo.key_mgmt & IW_AUTH_KEY_MGMT_PSK) ||
1705 assoc_req->secinfo.WPAenabled ||
1706 assoc_req->secinfo.WPA2enabled)) {
1707 lbs_do_association_work(priv);
1708 } else
1709 lbs_postpone_association_work(priv);
1710 } else {
1711 lbs_cancel_association_work(priv);
1712 }
1713 mutex_unlock(&priv->lock);
1714
1715 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1716 return ret;
1717}
1718
1719
1720static int lbs_set_genie(struct net_device *dev,
1721 struct iw_request_info *info,
1722 struct iw_point *dwrq,
1723 char *extra)
1724{
1725 struct lbs_private *priv = dev->ml_priv;
1726 int ret = 0;
1727 struct assoc_request * assoc_req;
1728
1729 lbs_deb_enter(LBS_DEB_WEXT);
1730
1731 mutex_lock(&priv->lock);
1732 assoc_req = lbs_get_association_request(priv);
1733 if (!assoc_req) {
1734 ret = -ENOMEM;
1735 goto out;
1736 }
1737
1738 if (dwrq->length > MAX_WPA_IE_LEN ||
1739 (dwrq->length && extra == NULL)) {
1740 ret = -EINVAL;
1741 goto out;
1742 }
1743
1744 if (dwrq->length) {
1745 memcpy(&assoc_req->wpa_ie[0], extra, dwrq->length);
1746 assoc_req->wpa_ie_len = dwrq->length;
1747 } else {
1748 memset(&assoc_req->wpa_ie[0], 0, sizeof(priv->wpa_ie));
1749 assoc_req->wpa_ie_len = 0;
1750 }
1751
1752out:
1753 if (ret == 0) {
1754 set_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags);
1755 lbs_postpone_association_work(priv);
1756 } else {
1757 lbs_cancel_association_work(priv);
1758 }
1759 mutex_unlock(&priv->lock);
1760
1761 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1762 return ret;
1763}
1764
1765static int lbs_get_genie(struct net_device *dev,
1766 struct iw_request_info *info,
1767 struct iw_point *dwrq,
1768 char *extra)
1769{
1770 int ret = 0;
1771 struct lbs_private *priv = dev->ml_priv;
1772
1773 lbs_deb_enter(LBS_DEB_WEXT);
1774
1775 if (priv->wpa_ie_len == 0) {
1776 dwrq->length = 0;
1777 goto out;
1778 }
1779
1780 if (dwrq->length < priv->wpa_ie_len) {
1781 ret = -E2BIG;
1782 goto out;
1783 }
1784
1785 dwrq->length = priv->wpa_ie_len;
1786 memcpy(extra, &priv->wpa_ie[0], priv->wpa_ie_len);
1787
1788out:
1789 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1790 return ret;
1791}
1792
1793
1794static int lbs_set_auth(struct net_device *dev,
1795 struct iw_request_info *info,
1796 struct iw_param *dwrq,
1797 char *extra)
1798{
1799 struct lbs_private *priv = dev->ml_priv;
1800 struct assoc_request * assoc_req;
1801 int ret = 0;
1802 int updated = 0;
1803
1804 lbs_deb_enter(LBS_DEB_WEXT);
1805
1806 mutex_lock(&priv->lock);
1807 assoc_req = lbs_get_association_request(priv);
1808 if (!assoc_req) {
1809 ret = -ENOMEM;
1810 goto out;
1811 }
1812
1813 switch (dwrq->flags & IW_AUTH_INDEX) {
1814 case IW_AUTH_PRIVACY_INVOKED:
1815 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
1816 case IW_AUTH_TKIP_COUNTERMEASURES:
1817 case IW_AUTH_CIPHER_PAIRWISE:
1818 case IW_AUTH_CIPHER_GROUP:
1819 case IW_AUTH_DROP_UNENCRYPTED:
1820 /*
1821 * libertas does not use these parameters
1822 */
1823 break;
1824
1825 case IW_AUTH_KEY_MGMT:
1826 assoc_req->secinfo.key_mgmt = dwrq->value;
1827 updated = 1;
1828 break;
1829
1830 case IW_AUTH_WPA_VERSION:
1831 if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) {
1832 assoc_req->secinfo.WPAenabled = 0;
1833 assoc_req->secinfo.WPA2enabled = 0;
1834 disable_wpa (assoc_req);
1835 }
1836 if (dwrq->value & IW_AUTH_WPA_VERSION_WPA) {
1837 assoc_req->secinfo.WPAenabled = 1;
1838 assoc_req->secinfo.wep_enabled = 0;
1839 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
1840 }
1841 if (dwrq->value & IW_AUTH_WPA_VERSION_WPA2) {
1842 assoc_req->secinfo.WPA2enabled = 1;
1843 assoc_req->secinfo.wep_enabled = 0;
1844 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
1845 }
1846 updated = 1;
1847 break;
1848
1849 case IW_AUTH_80211_AUTH_ALG:
1850 if (dwrq->value & IW_AUTH_ALG_SHARED_KEY) {
1851 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
1852 } else if (dwrq->value & IW_AUTH_ALG_OPEN_SYSTEM) {
1853 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
1854 } else if (dwrq->value & IW_AUTH_ALG_LEAP) {
1855 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_LEAP;
1856 } else {
1857 ret = -EINVAL;
1858 }
1859 updated = 1;
1860 break;
1861
1862 case IW_AUTH_WPA_ENABLED:
1863 if (dwrq->value) {
1864 if (!assoc_req->secinfo.WPAenabled &&
1865 !assoc_req->secinfo.WPA2enabled) {
1866 assoc_req->secinfo.WPAenabled = 1;
1867 assoc_req->secinfo.WPA2enabled = 1;
1868 assoc_req->secinfo.wep_enabled = 0;
1869 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
1870 }
1871 } else {
1872 assoc_req->secinfo.WPAenabled = 0;
1873 assoc_req->secinfo.WPA2enabled = 0;
1874 disable_wpa (assoc_req);
1875 }
1876 updated = 1;
1877 break;
1878
1879 default:
1880 ret = -EOPNOTSUPP;
1881 break;
1882 }
1883
1884out:
1885 if (ret == 0) {
1886 if (updated)
1887 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1888 lbs_postpone_association_work(priv);
1889 } else if (ret != -EOPNOTSUPP) {
1890 lbs_cancel_association_work(priv);
1891 }
1892 mutex_unlock(&priv->lock);
1893
1894 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1895 return ret;
1896}
1897
1898static int lbs_get_auth(struct net_device *dev,
1899 struct iw_request_info *info,
1900 struct iw_param *dwrq,
1901 char *extra)
1902{
1903 int ret = 0;
1904 struct lbs_private *priv = dev->ml_priv;
1905
1906 lbs_deb_enter(LBS_DEB_WEXT);
1907
1908 switch (dwrq->flags & IW_AUTH_INDEX) {
1909 case IW_AUTH_KEY_MGMT:
1910 dwrq->value = priv->secinfo.key_mgmt;
1911 break;
1912
1913 case IW_AUTH_WPA_VERSION:
1914 dwrq->value = 0;
1915 if (priv->secinfo.WPAenabled)
1916 dwrq->value |= IW_AUTH_WPA_VERSION_WPA;
1917 if (priv->secinfo.WPA2enabled)
1918 dwrq->value |= IW_AUTH_WPA_VERSION_WPA2;
1919 if (!dwrq->value)
1920 dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED;
1921 break;
1922
1923 case IW_AUTH_80211_AUTH_ALG:
1924 dwrq->value = priv->secinfo.auth_mode;
1925 break;
1926
1927 case IW_AUTH_WPA_ENABLED:
1928 if (priv->secinfo.WPAenabled && priv->secinfo.WPA2enabled)
1929 dwrq->value = 1;
1930 break;
1931
1932 default:
1933 ret = -EOPNOTSUPP;
1934 }
1935
1936 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1937 return ret;
1938}
1939
1940
1941static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info,
1942 struct iw_param *vwrq, char *extra)
1943{
1944 int ret = 0;
1945 struct lbs_private *priv = dev->ml_priv;
1946 s16 dbm = (s16) vwrq->value;
1947
1948 lbs_deb_enter(LBS_DEB_WEXT);
1949
1950 if (vwrq->disabled) {
1951 lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 0);
1952 goto out;
1953 }
1954
1955 if (vwrq->fixed == 0) {
1956 /* User requests automatic tx power control, however there are
1957 * many auto tx settings. For now use firmware defaults until
1958 * we come up with a good way to expose these to the user. */
1959 if (priv->fwrelease < 0x09000000) {
1960 ret = lbs_set_power_adapt_cfg(priv, 1,
1961 POW_ADAPT_DEFAULT_P0,
1962 POW_ADAPT_DEFAULT_P1,
1963 POW_ADAPT_DEFAULT_P2);
1964 if (ret)
1965 goto out;
1966 }
1967 ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1,
1968 TPC_DEFAULT_P2, 1);
1969 if (ret)
1970 goto out;
1971 dbm = priv->txpower_max;
1972 } else {
1973 /* Userspace check in iwrange if it should use dBm or mW,
1974 * therefore this should never happen... Jean II */
1975 if ((vwrq->flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) {
1976 ret = -EOPNOTSUPP;
1977 goto out;
1978 }
1979
1980 /* Validate requested power level against firmware allowed
1981 * levels */
1982 if (priv->txpower_min && (dbm < priv->txpower_min)) {
1983 ret = -EINVAL;
1984 goto out;
1985 }
1986
1987 if (priv->txpower_max && (dbm > priv->txpower_max)) {
1988 ret = -EINVAL;
1989 goto out;
1990 }
1991 if (priv->fwrelease < 0x09000000) {
1992 ret = lbs_set_power_adapt_cfg(priv, 0,
1993 POW_ADAPT_DEFAULT_P0,
1994 POW_ADAPT_DEFAULT_P1,
1995 POW_ADAPT_DEFAULT_P2);
1996 if (ret)
1997 goto out;
1998 }
1999 ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1,
2000 TPC_DEFAULT_P2, 1);
2001 if (ret)
2002 goto out;
2003 }
2004
2005 /* If the radio was off, turn it on */
2006 if (!priv->radio_on) {
2007 ret = lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 1);
2008 if (ret)
2009 goto out;
2010 }
2011
2012 lbs_deb_wext("txpower set %d dBm\n", dbm);
2013
2014 ret = lbs_set_tx_power(priv, dbm);
2015
2016out:
2017 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
2018 return ret;
2019}
2020
2021static int lbs_get_essid(struct net_device *dev, struct iw_request_info *info,
2022 struct iw_point *dwrq, char *extra)
2023{
2024 struct lbs_private *priv = dev->ml_priv;
2025
2026 lbs_deb_enter(LBS_DEB_WEXT);
2027
2028 /*
2029 * Note : if dwrq->flags != 0, we should get the relevant SSID from
2030 * the SSID list...
2031 */
2032
2033 /*
2034 * Get the current SSID
2035 */
2036 if (priv->connect_status == LBS_CONNECTED) {
2037 memcpy(extra, priv->curbssparams.ssid,
2038 priv->curbssparams.ssid_len);
2039 } else {
2040 memset(extra, 0, 32);
2041 }
2042 /*
2043 * If none, we may want to get the one that was set
2044 */
2045
2046 dwrq->length = priv->curbssparams.ssid_len;
2047
2048 dwrq->flags = 1; /* active */
2049
2050 lbs_deb_leave(LBS_DEB_WEXT);
2051 return 0;
2052}
2053
2054static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info,
2055 struct iw_point *dwrq, char *extra)
2056{
2057 struct lbs_private *priv = dev->ml_priv;
2058 int ret = 0;
2059 u8 ssid[IEEE80211_MAX_SSID_LEN];
2060 u8 ssid_len = 0;
2061 struct assoc_request * assoc_req;
2062 int in_ssid_len = dwrq->length;
2063 DECLARE_SSID_BUF(ssid_buf);
2064
2065 lbs_deb_enter(LBS_DEB_WEXT);
2066
2067 if (!priv->radio_on) {
2068 ret = -EINVAL;
2069 goto out;
2070 }
2071
2072 /* Check the size of the string */
2073 if (in_ssid_len > IEEE80211_MAX_SSID_LEN) {
2074 ret = -E2BIG;
2075 goto out;
2076 }
2077
2078 memset(&ssid, 0, sizeof(ssid));
2079
2080 if (!dwrq->flags || !in_ssid_len) {
2081 /* "any" SSID requested; leave SSID blank */
2082 } else {
2083 /* Specific SSID requested */
2084 memcpy(&ssid, extra, in_ssid_len);
2085 ssid_len = in_ssid_len;
2086 }
2087
2088 if (!ssid_len) {
2089 lbs_deb_wext("requested any SSID\n");
2090 } else {
2091 lbs_deb_wext("requested SSID '%s'\n",
2092 print_ssid(ssid_buf, ssid, ssid_len));
2093 }
2094
2095out:
2096 mutex_lock(&priv->lock);
2097 if (ret == 0) {
2098 /* Get or create the current association request */
2099 assoc_req = lbs_get_association_request(priv);
2100 if (!assoc_req) {
2101 ret = -ENOMEM;
2102 } else {
2103 /* Copy the SSID to the association request */
2104 memcpy(&assoc_req->ssid, &ssid, IEEE80211_MAX_SSID_LEN);
2105 assoc_req->ssid_len = ssid_len;
2106 set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
2107 lbs_postpone_association_work(priv);
2108 }
2109 }
2110
2111 /* Cancel the association request if there was an error */
2112 if (ret != 0) {
2113 lbs_cancel_association_work(priv);
2114 }
2115
2116 mutex_unlock(&priv->lock);
2117
2118 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
2119 return ret;
2120}
2121
2122#ifdef CONFIG_LIBERTAS_MESH
2123static int lbs_mesh_get_essid(struct net_device *dev,
2124 struct iw_request_info *info,
2125 struct iw_point *dwrq, char *extra)
2126{
2127 struct lbs_private *priv = dev->ml_priv;
2128
2129 lbs_deb_enter(LBS_DEB_WEXT);
2130
2131 memcpy(extra, priv->mesh_ssid, priv->mesh_ssid_len);
2132
2133 dwrq->length = priv->mesh_ssid_len;
2134
2135 dwrq->flags = 1; /* active */
2136
2137 lbs_deb_leave(LBS_DEB_WEXT);
2138 return 0;
2139}
2140
2141static int lbs_mesh_set_essid(struct net_device *dev,
2142 struct iw_request_info *info,
2143 struct iw_point *dwrq, char *extra)
2144{
2145 struct lbs_private *priv = dev->ml_priv;
2146 int ret = 0;
2147
2148 lbs_deb_enter(LBS_DEB_WEXT);
2149
2150 if (!priv->radio_on) {
2151 ret = -EINVAL;
2152 goto out;
2153 }
2154
2155 /* Check the size of the string */
2156 if (dwrq->length > IEEE80211_MAX_SSID_LEN) {
2157 ret = -E2BIG;
2158 goto out;
2159 }
2160
2161 if (!dwrq->flags || !dwrq->length) {
2162 ret = -EINVAL;
2163 goto out;
2164 } else {
2165 /* Specific SSID requested */
2166 memcpy(priv->mesh_ssid, extra, dwrq->length);
2167 priv->mesh_ssid_len = dwrq->length;
2168 }
2169
2170 lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
2171 priv->channel);
2172 out:
2173 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
2174 return ret;
2175}
2176#endif
2177
2178/**
2179 * @brief Connect to the AP or Ad-hoc Network with specific bssid
2180 *
2181 * @param dev A pointer to net_device structure
2182 * @param info A pointer to iw_request_info structure
2183 * @param awrq A pointer to iw_param structure
2184 * @param extra A pointer to extra data buf
2185 * @return 0 --success, otherwise fail
2186 */
2187static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info,
2188 struct sockaddr *awrq, char *extra)
2189{
2190 struct lbs_private *priv = dev->ml_priv;
2191 struct assoc_request * assoc_req;
2192 int ret = 0;
2193
2194 lbs_deb_enter(LBS_DEB_WEXT);
2195
2196 if (!priv->radio_on)
2197 return -EINVAL;
2198
2199 if (awrq->sa_family != ARPHRD_ETHER)
2200 return -EINVAL;
2201
2202 lbs_deb_wext("ASSOC: WAP: sa_data %pM\n", awrq->sa_data);
2203
2204 mutex_lock(&priv->lock);
2205
2206 /* Get or create the current association request */
2207 assoc_req = lbs_get_association_request(priv);
2208 if (!assoc_req) {
2209 lbs_cancel_association_work(priv);
2210 ret = -ENOMEM;
2211 } else {
2212 /* Copy the BSSID to the association request */
2213 memcpy(&assoc_req->bssid, awrq->sa_data, ETH_ALEN);
2214 set_bit(ASSOC_FLAG_BSSID, &assoc_req->flags);
2215 lbs_postpone_association_work(priv);
2216 }
2217
2218 mutex_unlock(&priv->lock);
2219
2220 return ret;
2221}
2222
2223/*
2224 * iwconfig settable callbacks
2225 */
2226static const iw_handler lbs_handler[] = {
2227 (iw_handler) NULL, /* SIOCSIWCOMMIT */
2228 (iw_handler) lbs_get_name, /* SIOCGIWNAME */
2229 (iw_handler) NULL, /* SIOCSIWNWID */
2230 (iw_handler) NULL, /* SIOCGIWNWID */
2231 (iw_handler) lbs_set_freq, /* SIOCSIWFREQ */
2232 (iw_handler) lbs_get_freq, /* SIOCGIWFREQ */
2233 (iw_handler) lbs_set_mode, /* SIOCSIWMODE */
2234 (iw_handler) lbs_get_mode, /* SIOCGIWMODE */
2235 (iw_handler) NULL, /* SIOCSIWSENS */
2236 (iw_handler) NULL, /* SIOCGIWSENS */
2237 (iw_handler) NULL, /* SIOCSIWRANGE */
2238 (iw_handler) lbs_get_range, /* SIOCGIWRANGE */
2239 (iw_handler) NULL, /* SIOCSIWPRIV */
2240 (iw_handler) NULL, /* SIOCGIWPRIV */
2241 (iw_handler) NULL, /* SIOCSIWSTATS */
2242 (iw_handler) NULL, /* SIOCGIWSTATS */
2243 iw_handler_set_spy, /* SIOCSIWSPY */
2244 iw_handler_get_spy, /* SIOCGIWSPY */
2245 iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
2246 iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
2247 (iw_handler) lbs_set_wap, /* SIOCSIWAP */
2248 (iw_handler) lbs_get_wap, /* SIOCGIWAP */
2249 (iw_handler) NULL, /* SIOCSIWMLME */
2250 (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */
2251 (iw_handler) lbs_set_scan, /* SIOCSIWSCAN */
2252 (iw_handler) lbs_get_scan, /* SIOCGIWSCAN */
2253 (iw_handler) lbs_set_essid, /* SIOCSIWESSID */
2254 (iw_handler) lbs_get_essid, /* SIOCGIWESSID */
2255 (iw_handler) lbs_set_nick, /* SIOCSIWNICKN */
2256 (iw_handler) lbs_get_nick, /* SIOCGIWNICKN */
2257 (iw_handler) NULL, /* -- hole -- */
2258 (iw_handler) NULL, /* -- hole -- */
2259 (iw_handler) lbs_set_rate, /* SIOCSIWRATE */
2260 (iw_handler) lbs_get_rate, /* SIOCGIWRATE */
2261 (iw_handler) lbs_set_rts, /* SIOCSIWRTS */
2262 (iw_handler) lbs_get_rts, /* SIOCGIWRTS */
2263 (iw_handler) lbs_set_frag, /* SIOCSIWFRAG */
2264 (iw_handler) lbs_get_frag, /* SIOCGIWFRAG */
2265 (iw_handler) lbs_set_txpow, /* SIOCSIWTXPOW */
2266 (iw_handler) lbs_get_txpow, /* SIOCGIWTXPOW */
2267 (iw_handler) lbs_set_retry, /* SIOCSIWRETRY */
2268 (iw_handler) lbs_get_retry, /* SIOCGIWRETRY */
2269 (iw_handler) lbs_set_encode, /* SIOCSIWENCODE */
2270 (iw_handler) lbs_get_encode, /* SIOCGIWENCODE */
2271 (iw_handler) lbs_set_power, /* SIOCSIWPOWER */
2272 (iw_handler) lbs_get_power, /* SIOCGIWPOWER */
2273 (iw_handler) NULL, /* -- hole -- */
2274 (iw_handler) NULL, /* -- hole -- */
2275 (iw_handler) lbs_set_genie, /* SIOCSIWGENIE */
2276 (iw_handler) lbs_get_genie, /* SIOCGIWGENIE */
2277 (iw_handler) lbs_set_auth, /* SIOCSIWAUTH */
2278 (iw_handler) lbs_get_auth, /* SIOCGIWAUTH */
2279 (iw_handler) lbs_set_encodeext,/* SIOCSIWENCODEEXT */
2280 (iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */
2281 (iw_handler) NULL, /* SIOCSIWPMKSA */
2282};
2283struct iw_handler_def lbs_handler_def = {
2284 .num_standard = ARRAY_SIZE(lbs_handler),
2285 .standard = (iw_handler *) lbs_handler,
2286 .get_wireless_stats = lbs_get_wireless_stats,
2287};
2288
2289#ifdef CONFIG_LIBERTAS_MESH
2290static const iw_handler mesh_wlan_handler[] = {
2291 (iw_handler) NULL, /* SIOCSIWCOMMIT */
2292 (iw_handler) lbs_get_name, /* SIOCGIWNAME */
2293 (iw_handler) NULL, /* SIOCSIWNWID */
2294 (iw_handler) NULL, /* SIOCGIWNWID */
2295 (iw_handler) lbs_mesh_set_freq, /* SIOCSIWFREQ */
2296 (iw_handler) lbs_get_freq, /* SIOCGIWFREQ */
2297 (iw_handler) NULL, /* SIOCSIWMODE */
2298 (iw_handler) mesh_wlan_get_mode, /* SIOCGIWMODE */
2299 (iw_handler) NULL, /* SIOCSIWSENS */
2300 (iw_handler) NULL, /* SIOCGIWSENS */
2301 (iw_handler) NULL, /* SIOCSIWRANGE */
2302 (iw_handler) lbs_get_range, /* SIOCGIWRANGE */
2303 (iw_handler) NULL, /* SIOCSIWPRIV */
2304 (iw_handler) NULL, /* SIOCGIWPRIV */
2305 (iw_handler) NULL, /* SIOCSIWSTATS */
2306 (iw_handler) NULL, /* SIOCGIWSTATS */
2307 iw_handler_set_spy, /* SIOCSIWSPY */
2308 iw_handler_get_spy, /* SIOCGIWSPY */
2309 iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
2310 iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
2311 (iw_handler) NULL, /* SIOCSIWAP */
2312 (iw_handler) NULL, /* SIOCGIWAP */
2313 (iw_handler) NULL, /* SIOCSIWMLME */
2314 (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */
2315 (iw_handler) lbs_set_scan, /* SIOCSIWSCAN */
2316 (iw_handler) lbs_get_scan, /* SIOCGIWSCAN */
2317 (iw_handler) lbs_mesh_set_essid,/* SIOCSIWESSID */
2318 (iw_handler) lbs_mesh_get_essid,/* SIOCGIWESSID */
2319 (iw_handler) NULL, /* SIOCSIWNICKN */
2320 (iw_handler) mesh_get_nick, /* SIOCGIWNICKN */
2321 (iw_handler) NULL, /* -- hole -- */
2322 (iw_handler) NULL, /* -- hole -- */
2323 (iw_handler) lbs_set_rate, /* SIOCSIWRATE */
2324 (iw_handler) lbs_get_rate, /* SIOCGIWRATE */
2325 (iw_handler) lbs_set_rts, /* SIOCSIWRTS */
2326 (iw_handler) lbs_get_rts, /* SIOCGIWRTS */
2327 (iw_handler) lbs_set_frag, /* SIOCSIWFRAG */
2328 (iw_handler) lbs_get_frag, /* SIOCGIWFRAG */
2329 (iw_handler) lbs_set_txpow, /* SIOCSIWTXPOW */
2330 (iw_handler) lbs_get_txpow, /* SIOCGIWTXPOW */
2331 (iw_handler) lbs_set_retry, /* SIOCSIWRETRY */
2332 (iw_handler) lbs_get_retry, /* SIOCGIWRETRY */
2333 (iw_handler) lbs_set_encode, /* SIOCSIWENCODE */
2334 (iw_handler) lbs_get_encode, /* SIOCGIWENCODE */
2335 (iw_handler) lbs_set_power, /* SIOCSIWPOWER */
2336 (iw_handler) lbs_get_power, /* SIOCGIWPOWER */
2337 (iw_handler) NULL, /* -- hole -- */
2338 (iw_handler) NULL, /* -- hole -- */
2339 (iw_handler) lbs_set_genie, /* SIOCSIWGENIE */
2340 (iw_handler) lbs_get_genie, /* SIOCGIWGENIE */
2341 (iw_handler) lbs_set_auth, /* SIOCSIWAUTH */
2342 (iw_handler) lbs_get_auth, /* SIOCGIWAUTH */
2343 (iw_handler) lbs_set_encodeext,/* SIOCSIWENCODEEXT */
2344 (iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */
2345 (iw_handler) NULL, /* SIOCSIWPMKSA */
2346};
2347
2348struct iw_handler_def mesh_handler_def = {
2349 .num_standard = ARRAY_SIZE(mesh_wlan_handler),
2350 .standard = (iw_handler *) mesh_wlan_handler,
2351 .get_wireless_stats = lbs_get_wireless_stats,
2352};
2353#endif
diff --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h
deleted file mode 100644
index f3f19fe8c6c6..000000000000
--- a/drivers/net/wireless/libertas/wext.h
+++ /dev/null
@@ -1,17 +0,0 @@
1/**
2 * This file contains definition for IOCTL call.
3 */
4#ifndef _LBS_WEXT_H_
5#define _LBS_WEXT_H_
6
7void lbs_send_disconnect_notification(struct lbs_private *priv);
8void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event);
9
10struct chan_freq_power *lbs_find_cfp_by_band_and_channel(
11 struct lbs_private *priv,
12 u8 band,
13 u16 channel);
14
15extern struct iw_handler_def lbs_handler_def;
16
17#endif