aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/libertas/assoc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/libertas/assoc.c')
-rw-r--r--drivers/net/wireless/libertas/assoc.c758
1 files changed, 393 insertions, 365 deletions
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
index a0e440cd8967..b9b374119033 100644
--- a/drivers/net/wireless/libertas/assoc.c
+++ b/drivers/net/wireless/libertas/assoc.c
@@ -12,15 +12,14 @@
12#include "scan.h" 12#include "scan.h"
13#include "cmd.h" 13#include "cmd.h"
14 14
15static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp);
16
17static const u8 bssid_any[ETH_ALEN] __attribute__ ((aligned (2))) = 15static const u8 bssid_any[ETH_ALEN] __attribute__ ((aligned (2))) =
18 { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; 16 { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
19static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) = 17static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) =
20 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 18 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
21 19
22/* The firmware needs certain bits masked out of the beacon-derviced capability 20/* The firmware needs the following bits masked out of the beacon-derived
23 * field when associating/joining to BSSs. 21 * capability field when associating/joining to a BSS:
22 * 9 (QoS), 11 (APSD), 12 (unused), 14 (unused), 15 (unused)
24 */ 23 */
25#define CAPINFO_MASK (~(0xda00)) 24#define CAPINFO_MASK (~(0xda00))
26 25
@@ -102,6 +101,295 @@ static void lbs_set_basic_rate_flags(u8 *rates, size_t len)
102} 101}
103 102
104 103
104static u8 iw_auth_to_ieee_auth(u8 auth)
105{
106 if (auth == IW_AUTH_ALG_OPEN_SYSTEM)
107 return 0x00;
108 else if (auth == IW_AUTH_ALG_SHARED_KEY)
109 return 0x01;
110 else if (auth == IW_AUTH_ALG_LEAP)
111 return 0x80;
112
113 lbs_deb_join("%s: invalid auth alg 0x%X\n", __func__, auth);
114 return 0;
115}
116
117/**
118 * @brief This function prepares the authenticate command. AUTHENTICATE only
119 * sets the authentication suite for future associations, as the firmware
120 * handles authentication internally during the ASSOCIATE command.
121 *
122 * @param priv A pointer to struct lbs_private structure
123 * @param bssid The peer BSSID with which to authenticate
124 * @param auth The authentication mode to use (from wireless.h)
125 *
126 * @return 0 or -1
127 */
128static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth)
129{
130 struct cmd_ds_802_11_authenticate cmd;
131 int ret = -1;
132 DECLARE_MAC_BUF(mac);
133
134 lbs_deb_enter(LBS_DEB_JOIN);
135
136 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
137 memcpy(cmd.bssid, bssid, ETH_ALEN);
138
139 cmd.authtype = iw_auth_to_ieee_auth(auth);
140
141 lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n",
142 print_mac(mac, bssid), cmd.authtype);
143
144 ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd);
145
146 lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
147 return ret;
148}
149
150
151static int lbs_assoc_post(struct lbs_private *priv,
152 struct cmd_ds_802_11_associate_response *resp)
153{
154 int ret = 0;
155 union iwreq_data wrqu;
156 struct bss_descriptor *bss;
157 u16 status_code;
158
159 lbs_deb_enter(LBS_DEB_ASSOC);
160
161 if (!priv->in_progress_assoc_req) {
162 lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n");
163 ret = -1;
164 goto done;
165 }
166 bss = &priv->in_progress_assoc_req->bss;
167
168 /*
169 * Older FW versions map the IEEE 802.11 Status Code in the association
170 * response to the following values returned in resp->statuscode:
171 *
172 * IEEE Status Code Marvell Status Code
173 * 0 -> 0x0000 ASSOC_RESULT_SUCCESS
174 * 13 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
175 * 14 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
176 * 15 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
177 * 16 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
178 * others -> 0x0003 ASSOC_RESULT_REFUSED
179 *
180 * Other response codes:
181 * 0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused)
182 * 0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for
183 * association response from the AP)
184 */
185
186 status_code = le16_to_cpu(resp->statuscode);
187 if (priv->fwrelease < 0x09000000) {
188 switch (status_code) {
189 case 0x00:
190 break;
191 case 0x01:
192 lbs_deb_assoc("ASSOC_RESP: invalid parameters\n");
193 break;
194 case 0x02:
195 lbs_deb_assoc("ASSOC_RESP: internal timer "
196 "expired while waiting for the AP\n");
197 break;
198 case 0x03:
199 lbs_deb_assoc("ASSOC_RESP: association "
200 "refused by AP\n");
201 break;
202 case 0x04:
203 lbs_deb_assoc("ASSOC_RESP: authentication "
204 "refused by AP\n");
205 break;
206 default:
207 lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x "
208 " unknown\n", status_code);
209 break;
210 }
211 } else {
212 /* v9+ returns the AP's association response */
213 lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x\n", status_code);
214 }
215
216 if (status_code) {
217 lbs_mac_event_disconnected(priv);
218 ret = -1;
219 goto done;
220 }
221
222 lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_RESP",
223 (void *) (resp + sizeof (resp->hdr)),
224 le16_to_cpu(resp->hdr.size) - sizeof (resp->hdr));
225
226 /* Send a Media Connected event, according to the Spec */
227 priv->connect_status = LBS_CONNECTED;
228
229 /* Update current SSID and BSSID */
230 memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
231 priv->curbssparams.ssid_len = bss->ssid_len;
232 memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
233
234 priv->SNR[TYPE_RXPD][TYPE_AVG] = 0;
235 priv->NF[TYPE_RXPD][TYPE_AVG] = 0;
236
237 memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR));
238 memset(priv->rawNF, 0x00, sizeof(priv->rawNF));
239 priv->nextSNRNF = 0;
240 priv->numSNRNF = 0;
241
242 netif_carrier_on(priv->dev);
243 if (!priv->tx_pending_len)
244 netif_wake_queue(priv->dev);
245
246 memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
247 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
248 wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
249
250done:
251 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
252 return ret;
253}
254
255/**
256 * @brief This function prepares an association-class command.
257 *
258 * @param priv A pointer to struct lbs_private structure
259 * @param assoc_req The association request describing the BSS to associate
260 * or reassociate with
261 * @param command The actual command, either CMD_802_11_ASSOCIATE or
262 * CMD_802_11_REASSOCIATE
263 *
264 * @return 0 or -1
265 */
266static int lbs_associate(struct lbs_private *priv,
267 struct assoc_request *assoc_req,
268 u16 command)
269{
270 struct cmd_ds_802_11_associate cmd;
271 int ret = 0;
272 struct bss_descriptor *bss = &assoc_req->bss;
273 u8 *pos = &(cmd.iebuf[0]);
274 u16 tmpcap, tmplen, tmpauth;
275 struct mrvl_ie_ssid_param_set *ssid;
276 struct mrvl_ie_ds_param_set *ds;
277 struct mrvl_ie_cf_param_set *cf;
278 struct mrvl_ie_rates_param_set *rates;
279 struct mrvl_ie_rsn_param_set *rsn;
280 struct mrvl_ie_auth_type *auth;
281
282 lbs_deb_enter(LBS_DEB_ASSOC);
283
284 BUG_ON((command != CMD_802_11_ASSOCIATE) &&
285 (command != CMD_802_11_REASSOCIATE));
286
287 memset(&cmd, 0, sizeof(cmd));
288 cmd.hdr.command = cpu_to_le16(command);
289
290 /* Fill in static fields */
291 memcpy(cmd.bssid, bss->bssid, ETH_ALEN);
292 cmd.listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL);
293
294 /* Capability info */
295 tmpcap = (bss->capability & CAPINFO_MASK);
296 if (bss->mode == IW_MODE_INFRA)
297 tmpcap |= WLAN_CAPABILITY_ESS;
298 cmd.capability = cpu_to_le16(tmpcap);
299 lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap);
300
301 /* SSID */
302 ssid = (struct mrvl_ie_ssid_param_set *) pos;
303 ssid->header.type = cpu_to_le16(TLV_TYPE_SSID);
304 tmplen = bss->ssid_len;
305 ssid->header.len = cpu_to_le16(tmplen);
306 memcpy(ssid->ssid, bss->ssid, tmplen);
307 pos += sizeof(ssid->header) + tmplen;
308
309 ds = (struct mrvl_ie_ds_param_set *) pos;
310 ds->header.type = cpu_to_le16(TLV_TYPE_PHY_DS);
311 ds->header.len = cpu_to_le16(1);
312 ds->channel = bss->phy.ds.channel;
313 pos += sizeof(ds->header) + 1;
314
315 cf = (struct mrvl_ie_cf_param_set *) pos;
316 cf->header.type = cpu_to_le16(TLV_TYPE_CF);
317 tmplen = sizeof(*cf) - sizeof (cf->header);
318 cf->header.len = cpu_to_le16(tmplen);
319 /* IE payload should be zeroed, firmware fills it in for us */
320 pos += sizeof(*cf);
321
322 rates = (struct mrvl_ie_rates_param_set *) pos;
323 rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
324 memcpy(&rates->rates, &bss->rates, MAX_RATES);
325 tmplen = MAX_RATES;
326 if (get_common_rates(priv, rates->rates, &tmplen)) {
327 ret = -1;
328 goto done;
329 }
330 pos += sizeof(rates->header) + tmplen;
331 rates->header.len = cpu_to_le16(tmplen);
332 lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen);
333
334 /* Copy the infra. association rates into Current BSS state structure */
335 memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
336 memcpy(&priv->curbssparams.rates, &rates->rates, tmplen);
337
338 /* Set MSB on basic rates as the firmware requires, but _after_
339 * copying to current bss rates.
340 */
341 lbs_set_basic_rate_flags(rates->rates, tmplen);
342
343 /* Firmware v9+ indicate authentication suites as a TLV */
344 if (priv->fwrelease >= 0x09000000) {
345 DECLARE_MAC_BUF(mac);
346
347 auth = (struct mrvl_ie_auth_type *) pos;
348 auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
349 auth->header.len = cpu_to_le16(2);
350 tmpauth = iw_auth_to_ieee_auth(priv->secinfo.auth_mode);
351 auth->auth = cpu_to_le16(tmpauth);
352 pos += sizeof(auth->header) + 2;
353
354 lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n",
355 print_mac(mac, bss->bssid), priv->secinfo.auth_mode);
356 }
357
358 /* WPA/WPA2 IEs */
359 if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
360 rsn = (struct mrvl_ie_rsn_param_set *) pos;
361 /* WPA_IE or WPA2_IE */
362 rsn->header.type = cpu_to_le16((u16) assoc_req->wpa_ie[0]);
363 tmplen = (u16) assoc_req->wpa_ie[1];
364 rsn->header.len = cpu_to_le16(tmplen);
365 memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen);
366 lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: WPA/RSN IE", (u8 *) rsn,
367 sizeof(rsn->header) + tmplen);
368 pos += sizeof(rsn->header) + tmplen;
369 }
370
371 cmd.hdr.size = cpu_to_le16((sizeof(cmd) - sizeof(cmd.iebuf)) +
372 (u16)(pos - (u8 *) &cmd.iebuf));
373
374 /* update curbssparams */
375 priv->curbssparams.channel = bss->phy.ds.channel;
376
377 if (lbs_parse_dnld_countryinfo_11d(priv, bss)) {
378 ret = -1;
379 goto done;
380 }
381
382 ret = lbs_cmd_with_response(priv, command, &cmd);
383 if (ret == 0) {
384 ret = lbs_assoc_post(priv,
385 (struct cmd_ds_802_11_associate_response *) &cmd);
386 }
387
388done:
389 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
390 return ret;
391}
392
105/** 393/**
106 * @brief Associate to a specific BSS discovered in a scan 394 * @brief Associate to a specific BSS discovered in a scan
107 * 395 *
@@ -110,7 +398,7 @@ static void lbs_set_basic_rate_flags(u8 *rates, size_t len)
110 * 398 *
111 * @return 0-success, otherwise fail 399 * @return 0-success, otherwise fail
112 */ 400 */
113static int lbs_associate(struct lbs_private *priv, 401static int lbs_try_associate(struct lbs_private *priv,
114 struct assoc_request *assoc_req) 402 struct assoc_request *assoc_req)
115{ 403{
116 int ret; 404 int ret;
@@ -118,11 +406,15 @@ static int lbs_associate(struct lbs_private *priv,
118 406
119 lbs_deb_enter(LBS_DEB_ASSOC); 407 lbs_deb_enter(LBS_DEB_ASSOC);
120 408
121 ret = lbs_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE, 409 /* FW v9 and higher indicate authentication suites as a TLV in the
122 0, CMD_OPTION_WAITFORRSP, 410 * association command, not as a separate authentication command.
123 0, assoc_req->bss.bssid); 411 */
124 if (ret) 412 if (priv->fwrelease < 0x09000000) {
125 goto out; 413 ret = lbs_set_authentication(priv, assoc_req->bss.bssid,
414 priv->secinfo.auth_mode);
415 if (ret)
416 goto out;
417 }
126 418
127 /* Use short preamble only when both the BSS and firmware support it */ 419 /* Use short preamble only when both the BSS and firmware support it */
128 if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && 420 if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
@@ -133,14 +425,78 @@ static int lbs_associate(struct lbs_private *priv,
133 if (ret) 425 if (ret)
134 goto out; 426 goto out;
135 427
136 ret = lbs_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE, 428 ret = lbs_associate(priv, assoc_req, CMD_802_11_ASSOCIATE);
137 0, CMD_OPTION_WAITFORRSP, 0, assoc_req);
138 429
139out: 430out:
140 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); 431 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
141 return ret; 432 return ret;
142} 433}
143 434
435static int lbs_adhoc_post(struct lbs_private *priv,
436 struct cmd_ds_802_11_ad_hoc_result *resp)
437{
438 int ret = 0;
439 u16 command = le16_to_cpu(resp->hdr.command);
440 u16 result = le16_to_cpu(resp->hdr.result);
441 union iwreq_data wrqu;
442 struct bss_descriptor *bss;
443 DECLARE_SSID_BUF(ssid);
444
445 lbs_deb_enter(LBS_DEB_JOIN);
446
447 if (!priv->in_progress_assoc_req) {
448 lbs_deb_join("ADHOC_RESP: no in-progress association "
449 "request\n");
450 ret = -1;
451 goto done;
452 }
453 bss = &priv->in_progress_assoc_req->bss;
454
455 /*
456 * Join result code 0 --> SUCCESS
457 */
458 if (result) {
459 lbs_deb_join("ADHOC_RESP: failed (result 0x%X)\n", result);
460 if (priv->connect_status == LBS_CONNECTED)
461 lbs_mac_event_disconnected(priv);
462 ret = -1;
463 goto done;
464 }
465
466 /* Send a Media Connected event, according to the Spec */
467 priv->connect_status = LBS_CONNECTED;
468
469 if (command == CMD_RET(CMD_802_11_AD_HOC_START)) {
470 /* Update the created network descriptor with the new BSSID */
471 memcpy(bss->bssid, resp->bssid, ETH_ALEN);
472 }
473
474 /* Set the BSSID from the joined/started descriptor */
475 memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
476
477 /* Set the new SSID to current SSID */
478 memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
479 priv->curbssparams.ssid_len = bss->ssid_len;
480
481 netif_carrier_on(priv->dev);
482 if (!priv->tx_pending_len)
483 netif_wake_queue(priv->dev);
484
485 memset(&wrqu, 0, sizeof(wrqu));
486 memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
487 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
488 wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
489
490 lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n",
491 print_ssid(ssid, bss->ssid, bss->ssid_len),
492 priv->curbssparams.bssid,
493 priv->curbssparams.channel);
494
495done:
496 lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
497 return ret;
498}
499
144/** 500/**
145 * @brief Join an adhoc network found in a previous scan 501 * @brief Join an adhoc network found in a previous scan
146 * 502 *
@@ -219,11 +575,10 @@ static int lbs_adhoc_join(struct lbs_private *priv,
219 memcpy(&cmd.bss.bssid, &bss->bssid, ETH_ALEN); 575 memcpy(&cmd.bss.bssid, &bss->bssid, ETH_ALEN);
220 memcpy(&cmd.bss.ssid, &bss->ssid, bss->ssid_len); 576 memcpy(&cmd.bss.ssid, &bss->ssid, bss->ssid_len);
221 577
222 memcpy(&cmd.bss.phyparamset, &bss->phyparamset, 578 memcpy(&cmd.bss.ds, &bss->phy.ds, sizeof(struct ieee_ie_ds_param_set));
223 sizeof(union ieeetypes_phyparamset));
224 579
225 memcpy(&cmd.bss.ssparamset, &bss->ssparamset, 580 memcpy(&cmd.bss.ibss, &bss->ss.ibss,
226 sizeof(union IEEEtypes_ssparamset)); 581 sizeof(struct ieee_ie_ibss_param_set));
227 582
228 cmd.bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK); 583 cmd.bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK);
229 lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n", 584 lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
@@ -260,7 +615,7 @@ static int lbs_adhoc_join(struct lbs_private *priv,
260 */ 615 */
261 lbs_set_basic_rate_flags(cmd.bss.rates, ratesize); 616 lbs_set_basic_rate_flags(cmd.bss.rates, ratesize);
262 617
263 cmd.bss.ssparamset.ibssparamset.atimwindow = cpu_to_le16(bss->atimwindow); 618 cmd.bss.ibss.atimwindow = bss->atimwindow;
264 619
265 if (assoc_req->secinfo.wep_enabled) { 620 if (assoc_req->secinfo.wep_enabled) {
266 u16 tmp = le16_to_cpu(cmd.bss.capability); 621 u16 tmp = le16_to_cpu(cmd.bss.capability);
@@ -287,8 +642,10 @@ static int lbs_adhoc_join(struct lbs_private *priv,
287 } 642 }
288 643
289 ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd); 644 ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd);
290 if (ret == 0) 645 if (ret == 0) {
291 ret = lbs_adhoc_post(priv, (struct cmd_header *) &cmd); 646 ret = lbs_adhoc_post(priv,
647 (struct cmd_ds_802_11_ad_hoc_result *)&cmd);
648 }
292 649
293out: 650out:
294 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); 651 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
@@ -343,22 +700,24 @@ static int lbs_adhoc_start(struct lbs_private *priv,
343 WARN_ON(!assoc_req->channel); 700 WARN_ON(!assoc_req->channel);
344 701
345 /* set Physical parameter set */ 702 /* set Physical parameter set */
346 cmd.phyparamset.dsparamset.elementid = WLAN_EID_DS_PARAMS; 703 cmd.ds.header.id = WLAN_EID_DS_PARAMS;
347 cmd.phyparamset.dsparamset.len = 1; 704 cmd.ds.header.len = 1;
348 cmd.phyparamset.dsparamset.currentchan = assoc_req->channel; 705 cmd.ds.channel = assoc_req->channel;
349 706
350 /* set IBSS parameter set */ 707 /* set IBSS parameter set */
351 cmd.ssparamset.ibssparamset.elementid = WLAN_EID_IBSS_PARAMS; 708 cmd.ibss.header.id = WLAN_EID_IBSS_PARAMS;
352 cmd.ssparamset.ibssparamset.len = 2; 709 cmd.ibss.header.len = 2;
353 cmd.ssparamset.ibssparamset.atimwindow = 0; 710 cmd.ibss.atimwindow = cpu_to_le16(0);
354 711
355 /* set capability info */ 712 /* set capability info */
356 tmpcap = WLAN_CAPABILITY_IBSS; 713 tmpcap = WLAN_CAPABILITY_IBSS;
357 if (assoc_req->secinfo.wep_enabled) { 714 if (assoc_req->secinfo.wep_enabled ||
358 lbs_deb_join("ADHOC_START: WEP enabled, setting privacy on\n"); 715 assoc_req->secinfo.WPAenabled ||
716 assoc_req->secinfo.WPA2enabled) {
717 lbs_deb_join("ADHOC_START: WEP/WPA enabled, privacy on\n");
359 tmpcap |= WLAN_CAPABILITY_PRIVACY; 718 tmpcap |= WLAN_CAPABILITY_PRIVACY;
360 } else 719 } else
361 lbs_deb_join("ADHOC_START: WEP disabled, setting privacy off\n"); 720 lbs_deb_join("ADHOC_START: WEP disabled, privacy off\n");
362 721
363 cmd.capability = cpu_to_le16(tmpcap); 722 cmd.capability = cpu_to_le16(tmpcap);
364 723
@@ -395,7 +754,8 @@ static int lbs_adhoc_start(struct lbs_private *priv,
395 754
396 ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_START, &cmd); 755 ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_START, &cmd);
397 if (ret == 0) 756 if (ret == 0)
398 ret = lbs_adhoc_post(priv, (struct cmd_header *) &cmd); 757 ret = lbs_adhoc_post(priv,
758 (struct cmd_ds_802_11_ad_hoc_result *)&cmd);
399 759
400out: 760out:
401 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); 761 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
@@ -720,7 +1080,7 @@ static int assoc_helper_essid(struct lbs_private *priv,
720 assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel); 1080 assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel);
721 if (bss != NULL) { 1081 if (bss != NULL) {
722 memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor)); 1082 memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
723 ret = lbs_associate(priv, assoc_req); 1083 ret = lbs_try_associate(priv, assoc_req);
724 } else { 1084 } else {
725 lbs_deb_assoc("SSID not found; cannot associate\n"); 1085 lbs_deb_assoc("SSID not found; cannot associate\n");
726 } 1086 }
@@ -772,8 +1132,9 @@ static int assoc_helper_bssid(struct lbs_private *priv,
772 1132
773 memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor)); 1133 memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
774 if (assoc_req->mode == IW_MODE_INFRA) { 1134 if (assoc_req->mode == IW_MODE_INFRA) {
775 ret = lbs_associate(priv, assoc_req); 1135 ret = lbs_try_associate(priv, assoc_req);
776 lbs_deb_assoc("ASSOC: lbs_associate(bssid) returned %d\n", ret); 1136 lbs_deb_assoc("ASSOC: lbs_try_associate(bssid) returned %d\n",
1137 ret);
777 } else if (assoc_req->mode == IW_MODE_ADHOC) { 1138 } else if (assoc_req->mode == IW_MODE_ADHOC) {
778 lbs_adhoc_join(priv, assoc_req); 1139 lbs_adhoc_join(priv, assoc_req);
779 } 1140 }
@@ -1467,57 +1828,6 @@ struct assoc_request *lbs_get_association_request(struct lbs_private *priv)
1467 1828
1468 1829
1469/** 1830/**
1470 * @brief This function prepares command of authenticate.
1471 *
1472 * @param priv A pointer to struct lbs_private structure
1473 * @param cmd A pointer to cmd_ds_command structure
1474 * @param pdata_buf Void cast of pointer to a BSSID to authenticate with
1475 *
1476 * @return 0 or -1
1477 */
1478int lbs_cmd_80211_authenticate(struct lbs_private *priv,
1479 struct cmd_ds_command *cmd,
1480 void *pdata_buf)
1481{
1482 struct cmd_ds_802_11_authenticate *pauthenticate = &cmd->params.auth;
1483 int ret = -1;
1484 u8 *bssid = pdata_buf;
1485
1486 lbs_deb_enter(LBS_DEB_JOIN);
1487
1488 cmd->command = cpu_to_le16(CMD_802_11_AUTHENTICATE);
1489 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate)
1490 + S_DS_GEN);
1491
1492 /* translate auth mode to 802.11 defined wire value */
1493 switch (priv->secinfo.auth_mode) {
1494 case IW_AUTH_ALG_OPEN_SYSTEM:
1495 pauthenticate->authtype = 0x00;
1496 break;
1497 case IW_AUTH_ALG_SHARED_KEY:
1498 pauthenticate->authtype = 0x01;
1499 break;
1500 case IW_AUTH_ALG_LEAP:
1501 pauthenticate->authtype = 0x80;
1502 break;
1503 default:
1504 lbs_deb_join("AUTH_CMD: invalid auth alg 0x%X\n",
1505 priv->secinfo.auth_mode);
1506 goto out;
1507 }
1508
1509 memcpy(pauthenticate->macaddr, bssid, ETH_ALEN);
1510
1511 lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n",
1512 bssid, pauthenticate->authtype);
1513 ret = 0;
1514
1515out:
1516 lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
1517 return ret;
1518}
1519
1520/**
1521 * @brief Deauthenticate from a specific BSS 1831 * @brief Deauthenticate from a specific BSS
1522 * 1832 *
1523 * @param priv A pointer to struct lbs_private structure 1833 * @param priv A pointer to struct lbs_private structure
@@ -1550,285 +1860,3 @@ int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, u8 bssid[ETH_ALEN],
1550 return ret; 1860 return ret;
1551} 1861}
1552 1862
1553int lbs_cmd_80211_associate(struct lbs_private *priv,
1554 struct cmd_ds_command *cmd, void *pdata_buf)
1555{
1556 struct cmd_ds_802_11_associate *passo = &cmd->params.associate;
1557 int ret = 0;
1558 struct assoc_request *assoc_req = pdata_buf;
1559 struct bss_descriptor *bss = &assoc_req->bss;
1560 u8 *pos;
1561 u16 tmpcap, tmplen;
1562 struct mrvlietypes_ssidparamset *ssid;
1563 struct mrvlietypes_phyparamset *phy;
1564 struct mrvlietypes_ssparamset *ss;
1565 struct mrvlietypes_ratesparamset *rates;
1566 struct mrvlietypes_rsnparamset *rsn;
1567
1568 lbs_deb_enter(LBS_DEB_ASSOC);
1569
1570 pos = (u8 *) passo;
1571
1572 if (!priv) {
1573 ret = -1;
1574 goto done;
1575 }
1576
1577 cmd->command = cpu_to_le16(CMD_802_11_ASSOCIATE);
1578
1579 memcpy(passo->peerstaaddr, bss->bssid, sizeof(passo->peerstaaddr));
1580 pos += sizeof(passo->peerstaaddr);
1581
1582 /* set the listen interval */
1583 passo->listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL);
1584
1585 pos += sizeof(passo->capability);
1586 pos += sizeof(passo->listeninterval);
1587 pos += sizeof(passo->bcnperiod);
1588 pos += sizeof(passo->dtimperiod);
1589
1590 ssid = (struct mrvlietypes_ssidparamset *) pos;
1591 ssid->header.type = cpu_to_le16(TLV_TYPE_SSID);
1592 tmplen = bss->ssid_len;
1593 ssid->header.len = cpu_to_le16(tmplen);
1594 memcpy(ssid->ssid, bss->ssid, tmplen);
1595 pos += sizeof(ssid->header) + tmplen;
1596
1597 phy = (struct mrvlietypes_phyparamset *) pos;
1598 phy->header.type = cpu_to_le16(TLV_TYPE_PHY_DS);
1599 tmplen = sizeof(phy->fh_ds.dsparamset);
1600 phy->header.len = cpu_to_le16(tmplen);
1601 memcpy(&phy->fh_ds.dsparamset,
1602 &bss->phyparamset.dsparamset.currentchan,
1603 tmplen);
1604 pos += sizeof(phy->header) + tmplen;
1605
1606 ss = (struct mrvlietypes_ssparamset *) pos;
1607 ss->header.type = cpu_to_le16(TLV_TYPE_CF);
1608 tmplen = sizeof(ss->cf_ibss.cfparamset);
1609 ss->header.len = cpu_to_le16(tmplen);
1610 pos += sizeof(ss->header) + tmplen;
1611
1612 rates = (struct mrvlietypes_ratesparamset *) pos;
1613 rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
1614 memcpy(&rates->rates, &bss->rates, MAX_RATES);
1615 tmplen = MAX_RATES;
1616 if (get_common_rates(priv, rates->rates, &tmplen)) {
1617 ret = -1;
1618 goto done;
1619 }
1620 pos += sizeof(rates->header) + tmplen;
1621 rates->header.len = cpu_to_le16(tmplen);
1622 lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen);
1623
1624 /* Copy the infra. association rates into Current BSS state structure */
1625 memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
1626 memcpy(&priv->curbssparams.rates, &rates->rates, tmplen);
1627
1628 /* Set MSB on basic rates as the firmware requires, but _after_
1629 * copying to current bss rates.
1630 */
1631 lbs_set_basic_rate_flags(rates->rates, tmplen);
1632
1633 if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
1634 rsn = (struct mrvlietypes_rsnparamset *) pos;
1635 /* WPA_IE or WPA2_IE */
1636 rsn->header.type = cpu_to_le16((u16) assoc_req->wpa_ie[0]);
1637 tmplen = (u16) assoc_req->wpa_ie[1];
1638 rsn->header.len = cpu_to_le16(tmplen);
1639 memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen);
1640 lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: RSN IE", (u8 *) rsn,
1641 sizeof(rsn->header) + tmplen);
1642 pos += sizeof(rsn->header) + tmplen;
1643 }
1644
1645 /* update curbssparams */
1646 priv->curbssparams.channel = bss->phyparamset.dsparamset.currentchan;
1647
1648 if (lbs_parse_dnld_countryinfo_11d(priv, bss)) {
1649 ret = -1;
1650 goto done;
1651 }
1652
1653 cmd->size = cpu_to_le16((u16) (pos - (u8 *) passo) + S_DS_GEN);
1654
1655 /* set the capability info */
1656 tmpcap = (bss->capability & CAPINFO_MASK);
1657 if (bss->mode == IW_MODE_INFRA)
1658 tmpcap |= WLAN_CAPABILITY_ESS;
1659 passo->capability = cpu_to_le16(tmpcap);
1660 lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap);
1661
1662done:
1663 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
1664 return ret;
1665}
1666
1667int lbs_ret_80211_associate(struct lbs_private *priv,
1668 struct cmd_ds_command *resp)
1669{
1670 int ret = 0;
1671 union iwreq_data wrqu;
1672 struct ieeetypes_assocrsp *passocrsp;
1673 struct bss_descriptor *bss;
1674 u16 status_code;
1675
1676 lbs_deb_enter(LBS_DEB_ASSOC);
1677
1678 if (!priv->in_progress_assoc_req) {
1679 lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n");
1680 ret = -1;
1681 goto done;
1682 }
1683 bss = &priv->in_progress_assoc_req->bss;
1684
1685 passocrsp = (struct ieeetypes_assocrsp *) &resp->params;
1686
1687 /*
1688 * Older FW versions map the IEEE 802.11 Status Code in the association
1689 * response to the following values returned in passocrsp->statuscode:
1690 *
1691 * IEEE Status Code Marvell Status Code
1692 * 0 -> 0x0000 ASSOC_RESULT_SUCCESS
1693 * 13 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
1694 * 14 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
1695 * 15 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
1696 * 16 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
1697 * others -> 0x0003 ASSOC_RESULT_REFUSED
1698 *
1699 * Other response codes:
1700 * 0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused)
1701 * 0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for
1702 * association response from the AP)
1703 */
1704
1705 status_code = le16_to_cpu(passocrsp->statuscode);
1706 switch (status_code) {
1707 case 0x00:
1708 break;
1709 case 0x01:
1710 lbs_deb_assoc("ASSOC_RESP: invalid parameters\n");
1711 break;
1712 case 0x02:
1713 lbs_deb_assoc("ASSOC_RESP: internal timer "
1714 "expired while waiting for the AP\n");
1715 break;
1716 case 0x03:
1717 lbs_deb_assoc("ASSOC_RESP: association "
1718 "refused by AP\n");
1719 break;
1720 case 0x04:
1721 lbs_deb_assoc("ASSOC_RESP: authentication "
1722 "refused by AP\n");
1723 break;
1724 default:
1725 lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x "
1726 " unknown\n", status_code);
1727 break;
1728 }
1729
1730 if (status_code) {
1731 lbs_mac_event_disconnected(priv);
1732 ret = -1;
1733 goto done;
1734 }
1735
1736 lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_RESP", (void *)&resp->params,
1737 le16_to_cpu(resp->size) - S_DS_GEN);
1738
1739 /* Send a Media Connected event, according to the Spec */
1740 priv->connect_status = LBS_CONNECTED;
1741
1742 /* Update current SSID and BSSID */
1743 memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
1744 priv->curbssparams.ssid_len = bss->ssid_len;
1745 memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
1746
1747 priv->SNR[TYPE_RXPD][TYPE_AVG] = 0;
1748 priv->NF[TYPE_RXPD][TYPE_AVG] = 0;
1749
1750 memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR));
1751 memset(priv->rawNF, 0x00, sizeof(priv->rawNF));
1752 priv->nextSNRNF = 0;
1753 priv->numSNRNF = 0;
1754
1755 netif_carrier_on(priv->dev);
1756 if (!priv->tx_pending_len)
1757 netif_wake_queue(priv->dev);
1758
1759 memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
1760 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
1761 wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
1762
1763done:
1764 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
1765 return ret;
1766}
1767
1768static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp)
1769{
1770 int ret = 0;
1771 u16 command = le16_to_cpu(resp->command);
1772 u16 result = le16_to_cpu(resp->result);
1773 struct cmd_ds_802_11_ad_hoc_result *adhoc_resp;
1774 union iwreq_data wrqu;
1775 struct bss_descriptor *bss;
1776 DECLARE_SSID_BUF(ssid);
1777
1778 lbs_deb_enter(LBS_DEB_JOIN);
1779
1780 adhoc_resp = (struct cmd_ds_802_11_ad_hoc_result *) resp;
1781
1782 if (!priv->in_progress_assoc_req) {
1783 lbs_deb_join("ADHOC_RESP: no in-progress association "
1784 "request\n");
1785 ret = -1;
1786 goto done;
1787 }
1788 bss = &priv->in_progress_assoc_req->bss;
1789
1790 /*
1791 * Join result code 0 --> SUCCESS
1792 */
1793 if (result) {
1794 lbs_deb_join("ADHOC_RESP: failed (result 0x%X)\n", result);
1795 if (priv->connect_status == LBS_CONNECTED)
1796 lbs_mac_event_disconnected(priv);
1797 ret = -1;
1798 goto done;
1799 }
1800
1801 /* Send a Media Connected event, according to the Spec */
1802 priv->connect_status = LBS_CONNECTED;
1803
1804 if (command == CMD_RET(CMD_802_11_AD_HOC_START)) {
1805 /* Update the created network descriptor with the new BSSID */
1806 memcpy(bss->bssid, adhoc_resp->bssid, ETH_ALEN);
1807 }
1808
1809 /* Set the BSSID from the joined/started descriptor */
1810 memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
1811
1812 /* Set the new SSID to current SSID */
1813 memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
1814 priv->curbssparams.ssid_len = bss->ssid_len;
1815
1816 netif_carrier_on(priv->dev);
1817 if (!priv->tx_pending_len)
1818 netif_wake_queue(priv->dev);
1819
1820 memset(&wrqu, 0, sizeof(wrqu));
1821 memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
1822 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
1823 wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
1824
1825 lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n",
1826 print_ssid(ssid, bss->ssid, bss->ssid_len),
1827 priv->curbssparams.bssid,
1828 priv->curbssparams.channel);
1829
1830done:
1831 lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
1832 return ret;
1833}
1834