assoc.c 19.2 KB
Newer Older
1 2 3 4
/* Copyright (C) 2006, Red Hat, Inc. */

#include <linux/bitops.h>
#include <net/ieee80211.h>
5
#include <linux/etherdevice.h>
6 7 8 9 10 11 12 13 14 15 16

#include "assoc.h"
#include "join.h"
#include "decl.h"
#include "hostcmd.h"
#include "host.h"


static const u8 bssid_any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
static const u8 bssid_off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
/* From ieee80211_module.c */
static const char *libertas_escape_essid(const char *essid, u8 essid_len)
{
	static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
	const char *s = essid;
	char *d = escaped;

	if (ieee80211_is_empty_essid(essid, essid_len))
		return "";

	essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE);
	while (essid_len--) {
		if (*s == '\0') {
			*d++ = '\\';
			*d++ = '0';
			s++;
		} else {
			*d++ = *s++;
		}
	}
	*d = '\0';
	return escaped;
}

static void print_assoc_req(const char * extra, struct assoc_request * assoc_req)
{
	lbs_deb_assoc(
	       "#### Association Request: %s\n"
	       "       flags:      0x%08lX\n"
	       "       SSID:       '%s'\n"
	       "       channel:    %d\n"
	       "       band:       %d\n"
	       "       mode:       %d\n"
	       "       BSSID:      " MAC_FMT "\n"
	       "       WPA:        %d\n"
	       "       WPA2:       %d\n"
	       "       WEP status: %d\n"
	       "       auth:       %d\n"
	       "       auth_alg:   %d\n"
	       "       encmode:    %d\n",
	       extra, assoc_req->flags,
	       libertas_escape_essid(assoc_req->ssid.ssid, assoc_req->ssid.ssidlength),
	       assoc_req->channel, assoc_req->band, assoc_req->mode,
	       MAC_ARG(assoc_req->bssid), assoc_req->secinfo.WPAenabled,
	       assoc_req->secinfo.WPA2enabled, assoc_req->secinfo.WEPstatus,
	       assoc_req->secinfo.authmode, assoc_req->secinfo.auth1xalg,
	       assoc_req->secinfo.Encryptionmode);
}


67 68 69 70 71
static int assoc_helper_essid(wlan_private *priv,
                              struct assoc_request * assoc_req)
{
	wlan_adapter *adapter = priv->adapter;
	int ret = 0;
72
	struct bss_descriptor * bss;
73
	int channel = -1;
74

75
	lbs_deb_enter(LBS_DEB_ASSOC);
76

77 78 79 80
	/* FIXME: take channel into account when picking SSIDs if a channel
	 * is set.
	 */

81 82 83
	if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
		channel = assoc_req->channel;

84
	lbs_deb_assoc("New SSID requested: %s\n", assoc_req->ssid.ssid);
85
	if (assoc_req->mode == IW_MODE_INFRA) {
86
		if (adapter->prescan) {
87
			libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 0);
88 89
		}

90
		bss = libertas_find_SSID_in_list(adapter, &assoc_req->ssid,
91
				NULL, IW_MODE_INFRA, channel);
92 93
		if (bss != NULL) {
			lbs_deb_assoc("SSID found in scan list, associating\n");
94 95
			memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
			ret = wlan_associate(priv, assoc_req);
96
		} else {
97
			lbs_deb_assoc("SSID '%s' not found; cannot associate\n",
98 99
				assoc_req->ssid.ssid);
		}
100
	} else if (assoc_req->mode == IW_MODE_ADHOC) {
101 102 103
		/* Scan for the network, do not save previous results.  Stale
		 *   scan data will cause us to join a non-existant adhoc network
		 */
104
		libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 1);
105 106

		/* Search for the requested SSID in the scan table */
107
		bss = libertas_find_SSID_in_list(adapter, &assoc_req->ssid, NULL,
108
				IW_MODE_ADHOC, channel);
109 110
		if (bss != NULL) {
			lbs_deb_assoc("SSID found joining\n");
111 112
			memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
			libertas_join_adhoc_network(priv, assoc_req);
113 114
		} else {
			/* else send START command */
115
			lbs_deb_assoc("SSID not found in list, so creating adhoc"
116
				" with SSID '%s'\n", assoc_req->ssid.ssid);
117 118 119
			memcpy(&assoc_req->bss.ssid, &assoc_req->ssid,
				sizeof(struct WLAN_802_11_SSID));
			libertas_start_adhoc_network(priv, assoc_req);
120 121 122
		}
	}

123
	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
124 125 126 127 128 129 130 131
	return ret;
}


static int assoc_helper_bssid(wlan_private *priv,
                              struct assoc_request * assoc_req)
{
	wlan_adapter *adapter = priv->adapter;
132 133
	int ret = 0;
	struct bss_descriptor * bss;
134

135
	lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID " MAC_FMT "\n",
136 137 138
		MAC_ARG(assoc_req->bssid));

	/* Search for index position in list for requested MAC */
139
	bss = libertas_find_BSSID_in_list(adapter, assoc_req->bssid,
140
			    assoc_req->mode);
141
	if (bss == NULL) {
142
		lbs_deb_assoc("ASSOC: WAP: BSSID " MAC_FMT " not found, "
143 144 145 146
			"cannot associate.\n", MAC_ARG(assoc_req->bssid));
		goto out;
	}

147
	memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
148
	if (assoc_req->mode == IW_MODE_INFRA) {
149
		ret = wlan_associate(priv, assoc_req);
150
		lbs_deb_assoc("ASSOC: wlan_associate(bssid) returned %d\n", ret);
151
	} else if (assoc_req->mode == IW_MODE_ADHOC) {
152
		libertas_join_adhoc_network(priv, assoc_req);
153 154 155
	}

out:
156
	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
157 158 159 160 161 162 163 164 165 166 167 168
	return ret;
}


static int assoc_helper_associate(wlan_private *priv,
                                  struct assoc_request * assoc_req)
{
	int ret = 0, done = 0;

	/* If we're given and 'any' BSSID, try associating based on SSID */

	if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
169 170
		if (compare_ether_addr(bssid_any, assoc_req->bssid)
		    && compare_ether_addr(bssid_off, assoc_req->bssid)) {
171 172 173
			ret = assoc_helper_bssid(priv, assoc_req);
			done = 1;
			if (ret) {
174
				lbs_deb_assoc("ASSOC: bssid: ret = %d\n", ret);
175 176 177 178 179 180 181
			}
		}
	}

	if (!done && test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
		ret = assoc_helper_essid(priv, assoc_req);
		if (ret) {
182
			lbs_deb_assoc("ASSOC: bssid: ret = %d\n", ret);
183 184 185 186 187 188 189 190 191 192 193 194 195
		}
	}

	return ret;
}


static int assoc_helper_mode(wlan_private *priv,
                             struct assoc_request * assoc_req)
{
	wlan_adapter *adapter = priv->adapter;
	int ret = 0;

196
	lbs_deb_enter(LBS_DEB_ASSOC);
197

198 199
	if (assoc_req->mode == adapter->mode)
		goto done;
200

201
	if (assoc_req->mode == IW_MODE_INFRA) {
202 203 204 205 206
		if (adapter->psstate != PS_STATE_FULL_POWER)
			libertas_ps_wakeup(priv, cmd_option_waitforrsp);
		adapter->psmode = wlan802_11powermodecam;
	}

207
	adapter->mode = assoc_req->mode;
208 209 210 211
	ret = libertas_prepare_and_send_command(priv,
				    cmd_802_11_snmp_mib,
				    0, cmd_option_waitforrsp,
				    OID_802_11_INFRASTRUCTURE_MODE,
212
		/* Shoot me now */  (void *) (size_t) assoc_req->mode);
213

214 215
done:
	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
216 217 218 219
	return ret;
}


220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
static int update_channel(wlan_private * priv)
{
	/* the channel in f/w could be out of sync, get the current channel */
	return libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
				    cmd_opt_802_11_rf_channel_get,
				    cmd_option_waitforrsp, 0, NULL);
}

static int assoc_helper_channel(wlan_private *priv,
                                struct assoc_request * assoc_req)
{
	wlan_adapter *adapter = priv->adapter;
	int ret = 0;

	lbs_deb_enter(LBS_DEB_ASSOC);

	ret = update_channel(priv);
	if (ret < 0) {
		lbs_deb_assoc("ASSOC: channel: error getting channel.");
	}

	if (assoc_req->channel == adapter->curbssparams.channel)
		goto done;

	lbs_deb_assoc("ASSOC: channel: %d -> %d\n",
	       adapter->curbssparams.channel, assoc_req->channel);

	ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
				cmd_opt_802_11_rf_channel_set,
				cmd_option_waitforrsp, 0, &assoc_req->channel);
	if (ret < 0) {
		lbs_deb_assoc("ASSOC: channel: error setting channel.");
	}

	ret = update_channel(priv);
	if (ret < 0) {
		lbs_deb_assoc("ASSOC: channel: error getting channel.");
	}

	if (assoc_req->channel != adapter->curbssparams.channel) {
		lbs_deb_assoc("ASSOC: channel: failed to update channel to %d",
		              assoc_req->channel);
		goto done;
	}

	if (   assoc_req->secinfo.wep_enabled
	    &&   (assoc_req->wep_keys[0].len
	       || assoc_req->wep_keys[1].len
	       || assoc_req->wep_keys[2].len
	       || assoc_req->wep_keys[3].len)) {
		/* Make sure WEP keys are re-sent to firmware */
		set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
	}

	/* Must restart/rejoin adhoc networks after channel change */
	set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);

done:
	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
	return ret;
}


283 284 285 286 287 288 289
static int assoc_helper_wep_keys(wlan_private *priv,
                                 struct assoc_request * assoc_req)
{
	wlan_adapter *adapter = priv->adapter;
	int i;
	int ret = 0;

290
	lbs_deb_enter(LBS_DEB_ASSOC);
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313

	/* Set or remove WEP keys */
	if (   assoc_req->wep_keys[0].len
	    || assoc_req->wep_keys[1].len
	    || assoc_req->wep_keys[2].len
	    || assoc_req->wep_keys[3].len) {
		ret = libertas_prepare_and_send_command(priv,
					    cmd_802_11_set_wep,
					    cmd_act_add,
					    cmd_option_waitforrsp,
					    0, assoc_req);
	} else {
		ret = libertas_prepare_and_send_command(priv,
					    cmd_802_11_set_wep,
					    cmd_act_remove,
					    cmd_option_waitforrsp,
					    0, NULL);
	}

	if (ret)
		goto out;

	/* enable/disable the MAC's WEP packet filter */
314
	if (assoc_req->secinfo.wep_enabled)
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
		adapter->currentpacketfilter |= cmd_act_mac_wep_enable;
	else
		adapter->currentpacketfilter &= ~cmd_act_mac_wep_enable;
	ret = libertas_set_mac_packet_filter(priv);
	if (ret)
		goto out;

	mutex_lock(&adapter->lock);

	/* Copy WEP keys into adapter wep key fields */
	for (i = 0; i < 4; i++) {
		memcpy(&adapter->wep_keys[i], &assoc_req->wep_keys[i],
			sizeof(struct WLAN_802_11_KEY));
	}
	adapter->wep_tx_keyidx = assoc_req->wep_tx_keyidx;

	mutex_unlock(&adapter->lock);

out:
334
	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
335 336 337 338 339 340 341 342 343
	return ret;
}

static int assoc_helper_secinfo(wlan_private *priv,
                                struct assoc_request * assoc_req)
{
	wlan_adapter *adapter = priv->adapter;
	int ret = 0;

344
	lbs_deb_enter(LBS_DEB_ASSOC);
345 346 347 348 349

	memcpy(&adapter->secinfo, &assoc_req->secinfo,
		sizeof(struct wlan_802_11_security));

	ret = libertas_set_mac_packet_filter(priv);
350 351
	if (ret)
		goto out;
352

353 354 355 356 357 358 359 360
	/* enable/disable RSN */
	ret = libertas_prepare_and_send_command(priv,
				    cmd_802_11_enable_rsn,
				    cmd_act_set,
				    cmd_option_waitforrsp,
				    0, assoc_req);

out:
361
	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
362 363 364 365 366 367 368 369 370
	return ret;
}


static int assoc_helper_wpa_keys(wlan_private *priv,
                                 struct assoc_request * assoc_req)
{
	int ret = 0;

371
	lbs_deb_enter(LBS_DEB_ASSOC);
372 373 374 375 376 377 378

	ret = libertas_prepare_and_send_command(priv,
				    cmd_802_11_key_material,
				    cmd_act_set,
				    cmd_option_waitforrsp,
				    0, assoc_req);

379
	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
380 381 382 383 384 385 386 387 388 389
	return ret;
}


static int assoc_helper_wpa_ie(wlan_private *priv,
                               struct assoc_request * assoc_req)
{
	wlan_adapter *adapter = priv->adapter;
	int ret = 0;

390
	lbs_deb_enter(LBS_DEB_ASSOC);
391 392 393 394 395 396 397 398 399

	if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
		memcpy(&adapter->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len);
		adapter->wpa_ie_len = assoc_req->wpa_ie_len;
	} else {
		memset(&adapter->wpa_ie, 0, MAX_WPA_IE_LEN);
		adapter->wpa_ie_len = 0;
	}

400
	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
401 402 403 404 405 406 407 408 409 410 411
	return ret;
}


static int should_deauth_infrastructure(wlan_adapter *adapter,
                                        struct assoc_request * assoc_req)
{
	if (adapter->connect_status != libertas_connected)
		return 0;

	if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
412
		lbs_deb_assoc("Deauthenticating due to new SSID in "
413 414 415 416 417
			" configuration request.\n");
		return 1;
	}

	if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
418
		if (adapter->secinfo.auth_mode != assoc_req->secinfo.auth_mode) {
419
			lbs_deb_assoc("Deauthenticating due to updated security "
420 421 422 423 424 425
				"info in configuration request.\n");
			return 1;
		}
	}

	if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
426
		lbs_deb_assoc("Deauthenticating due to new BSSID in "
427 428 429 430 431 432
			" configuration request.\n");
		return 1;
	}

	/* FIXME: deal with 'auto' mode somehow */
	if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
433
		if (assoc_req->mode != IW_MODE_INFRA)
434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
			return 1;
	}

	return 0;
}


static int should_stop_adhoc(wlan_adapter *adapter,
                             struct assoc_request * assoc_req)
{
	if (adapter->connect_status != libertas_connected)
		return 0;

	if (adapter->curbssparams.ssid.ssidlength != assoc_req->ssid.ssidlength)
		return 1;
	if (memcmp(adapter->curbssparams.ssid.ssid, assoc_req->ssid.ssid,
450
			adapter->curbssparams.ssid.ssidlength))
451 452 453 454
		return 1;

	/* FIXME: deal with 'auto' mode somehow */
	if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
455
		if (assoc_req->mode != IW_MODE_ADHOC)
456 457 458
			return 1;
	}

459 460 461 462 463
	if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
		if (assoc_req->channel != adapter->curbssparams.channel)
			return 1;
	}

464 465 466 467
	return 0;
}


468
void libertas_association_worker(struct work_struct *work)
469 470 471 472 473 474 475
{
	wlan_private *priv = container_of(work, wlan_private, assoc_work.work);
	wlan_adapter *adapter = priv->adapter;
	struct assoc_request * assoc_req = NULL;
	int ret = 0;
	int find_any_ssid = 0;

476
	lbs_deb_enter(LBS_DEB_ASSOC);
477 478

	mutex_lock(&adapter->lock);
479 480 481
	assoc_req = adapter->pending_assoc_req;
	adapter->pending_assoc_req = NULL;
	adapter->in_progress_assoc_req = assoc_req;
482 483
	mutex_unlock(&adapter->lock);

484 485
	if (!assoc_req)
		goto done;
486

487
	print_assoc_req(__func__, assoc_req);
488 489 490 491 492 493 494 495

	/* If 'any' SSID was specified, find an SSID to associate with */
	if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)
	    && !assoc_req->ssid.ssidlength)
		find_any_ssid = 1;

	/* But don't use 'any' SSID if there's a valid locked BSSID to use */
	if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
496 497
		if (compare_ether_addr(assoc_req->bssid, bssid_any)
		    && compare_ether_addr(assoc_req->bssid, bssid_off))
498 499 500 501
			find_any_ssid = 0;
	}

	if (find_any_ssid) {
502
		u8 new_mode;
503 504 505 506

		ret = libertas_find_best_network_SSID(priv, &assoc_req->ssid,
				assoc_req->mode, &new_mode);
		if (ret) {
507
			lbs_deb_assoc("Could not find best network\n");
508 509 510 511 512
			ret = -ENETUNREACH;
			goto out;
		}

		/* Ensure we switch to the mode of the AP */
513
		if (assoc_req->mode == IW_MODE_AUTO) {
514 515 516 517 518 519 520 521 522
			set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
			assoc_req->mode = new_mode;
		}
	}

	/*
	 * Check if the attributes being changing require deauthentication
	 * from the currently associated infrastructure access point.
	 */
523
	if (adapter->mode == IW_MODE_INFRA) {
524 525 526
		if (should_deauth_infrastructure(adapter, assoc_req)) {
			ret = libertas_send_deauthentication(priv);
			if (ret) {
527
				lbs_deb_assoc("Deauthentication due to new "
528 529 530 531
					"configuration request failed: %d\n",
					ret);
			}
		}
532
	} else if (adapter->mode == IW_MODE_ADHOC) {
533 534 535
		if (should_stop_adhoc(adapter, assoc_req)) {
			ret = libertas_stop_adhoc_network(priv);
			if (ret) {
536
				lbs_deb_assoc("Teardown of AdHoc network due to "
537 538 539 540 541 542 543 544 545 546 547
					"new configuration request failed: %d\n",
					ret);
			}

		}
	}

	/* Send the various configuration bits to the firmware */
	if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
		ret = assoc_helper_mode(priv, assoc_req);
		if (ret) {
548
lbs_deb_assoc("ASSOC(:%d) mode: ret = %d\n", __LINE__, ret);
549 550 551 552
			goto out;
		}
	}

553 554 555 556 557 558 559 560 561
	if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
		ret = assoc_helper_channel(priv, assoc_req);
		if (ret) {
			lbs_deb_assoc("ASSOC(:%d) channel: ret = %d\n",
			              __LINE__, ret);
			goto out;
		}
	}

562 563 564 565
	if (   test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)
	    || test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) {
		ret = assoc_helper_wep_keys(priv, assoc_req);
		if (ret) {
566
lbs_deb_assoc("ASSOC(:%d) wep_keys: ret = %d\n", __LINE__, ret);
567 568 569 570 571 572 573
			goto out;
		}
	}

	if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
		ret = assoc_helper_secinfo(priv, assoc_req);
		if (ret) {
574
lbs_deb_assoc("ASSOC(:%d) secinfo: ret = %d\n", __LINE__, ret);
575 576 577 578 579 580 581
			goto out;
		}
	}

	if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
		ret = assoc_helper_wpa_ie(priv, assoc_req);
		if (ret) {
582
lbs_deb_assoc("ASSOC(:%d) wpa_ie: ret = %d\n", __LINE__, ret);
583 584 585 586 587 588 589 590
			goto out;
		}
	}

	if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)
	    || test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
		ret = assoc_helper_wpa_keys(priv, assoc_req);
		if (ret) {
591
lbs_deb_assoc("ASSOC(:%d) wpa_keys: ret = %d\n", __LINE__, ret);
592 593 594 595 596 597 598 599 600 601 602 603 604
			goto out;
		}
	}

	/* SSID/BSSID should be the _last_ config option set, because they
	 * trigger the association attempt.
	 */
	if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)
	    || test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
		int success = 1;

		ret = assoc_helper_associate(priv, assoc_req);
		if (ret) {
605
			lbs_deb_assoc("ASSOC: association attempt unsuccessful: %d\n",
606 607 608 609 610
				ret);
			success = 0;
		}

		if (adapter->connect_status != libertas_connected) {
611
			lbs_deb_assoc("ASSOC: assoication attempt unsuccessful, "
612 613 614 615 616
				"not connected.\n");
			success = 0;
		}

		if (success) {
617
			lbs_deb_assoc("ASSOC: association attempt successful. "
618
				"Associated to '%s' (" MAC_FMT ")\n",
619 620 621
				libertas_escape_essid(adapter->curbssparams.ssid.ssid,
				             adapter->curbssparams.ssid.ssidlength),
				MAC_ARG(adapter->curbssparams.bssid));
622 623 624 625 626 627 628 629 630 631 632 633 634 635
			libertas_prepare_and_send_command(priv,
				cmd_802_11_rssi,
				0, cmd_option_waitforrsp, 0, NULL);

			libertas_prepare_and_send_command(priv,
				cmd_802_11_get_log,
				0, cmd_option_waitforrsp, 0, NULL);
		} else {
			ret = -1;
		}
	}

out:
	if (ret) {
636
		lbs_deb_assoc("ASSOC: reconfiguration attempt unsuccessful: %d\n",
637 638
			ret);
	}
639 640 641 642

	mutex_lock(&adapter->lock);
	adapter->in_progress_assoc_req = NULL;
	mutex_unlock(&adapter->lock);
643
	kfree(assoc_req);
644 645 646

done:
	lbs_deb_leave(LBS_DEB_ASSOC);
647 648 649 650 651 652 653 654 655 656
}


/*
 * Caller MUST hold any necessary locks
 */
struct assoc_request * wlan_get_association_request(wlan_adapter *adapter)
{
	struct assoc_request * assoc_req;

657 658 659 660
	if (!adapter->pending_assoc_req) {
		adapter->pending_assoc_req = kzalloc(sizeof(struct assoc_request),
		                                     GFP_KERNEL);
		if (!adapter->pending_assoc_req) {
661 662 663 664 665 666 667 668 669
			lbs_pr_info("Not enough memory to allocate association"
				" request!\n");
			return NULL;
		}
	}

	/* Copy current configuration attributes to the association request,
	 * but don't overwrite any that are already set.
	 */
670
	assoc_req = adapter->pending_assoc_req;
671
	if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
672 673
		memcpy(&assoc_req->ssid, &adapter->curbssparams.ssid,
		       sizeof(struct WLAN_802_11_SSID));
674 675 676 677 678
	}

	if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
		assoc_req->channel = adapter->curbssparams.channel;

679 680 681
	if (!test_bit(ASSOC_FLAG_BAND, &assoc_req->flags))
		assoc_req->band = adapter->curbssparams.band;

682
	if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags))
683
		assoc_req->mode = adapter->mode;
684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721

	if (!test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
		memcpy(&assoc_req->bssid, adapter->curbssparams.bssid,
			ETH_ALEN);
	}

	if (!test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)) {
		int i;
		for (i = 0; i < 4; i++) {
			memcpy(&assoc_req->wep_keys[i], &adapter->wep_keys[i],
				sizeof(struct WLAN_802_11_KEY));
		}
	}

	if (!test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags))
		assoc_req->wep_tx_keyidx = adapter->wep_tx_keyidx;

	if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
		memcpy(&assoc_req->wpa_mcast_key, &adapter->wpa_mcast_key,
			sizeof(struct WLAN_802_11_KEY));
	}

	if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
		memcpy(&assoc_req->wpa_unicast_key, &adapter->wpa_unicast_key,
			sizeof(struct WLAN_802_11_KEY));
	}

	if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
		memcpy(&assoc_req->secinfo, &adapter->secinfo,
			sizeof(struct wlan_802_11_security));
	}

	if (!test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
		memcpy(&assoc_req->wpa_ie, &adapter->wpa_ie,
			MAX_WPA_IE_LEN);
		assoc_req->wpa_ie_len = adapter->wpa_ie_len;
	}

722 723
	print_assoc_req(__func__, assoc_req);

724 725
	return assoc_req;
}