assoc.c 19.7 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
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"
27 28
	       "       Encryption:%s%s%s\n"
	       "       auth:       %d\n",
29
	       extra, assoc_req->flags,
30
	       escape_essid(assoc_req->ssid, assoc_req->ssid_len),
31
	       assoc_req->channel, assoc_req->band, assoc_req->mode,
32 33 34 35 36
	       MAC_ARG(assoc_req->bssid),
	       assoc_req->secinfo.WPAenabled ? " WPA" : "",
	       assoc_req->secinfo.WPA2enabled ? " WPA2" : "",
	       assoc_req->secinfo.wep_enabled ? " WEP" : "",
	       assoc_req->secinfo.auth_mode);
37 38 39
}


40 41 42 43 44
static int assoc_helper_essid(wlan_private *priv,
                              struct assoc_request * assoc_req)
{
	wlan_adapter *adapter = priv->adapter;
	int ret = 0;
45
	struct bss_descriptor * bss;
46
	int channel = -1;
47

48
	lbs_deb_enter(LBS_DEB_ASSOC);
49

50 51 52 53
	/* FIXME: take channel into account when picking SSIDs if a channel
	 * is set.
	 */

54 55 56
	if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
		channel = assoc_req->channel;

57 58
	lbs_deb_assoc("New SSID requested: '%s'\n",
	              escape_essid(assoc_req->ssid, assoc_req->ssid_len));
59
	if (assoc_req->mode == IW_MODE_INFRA) {
60
		if (adapter->prescan) {
61
			libertas_send_specific_ssid_scan(priv, assoc_req->ssid,
62
				assoc_req->ssid_len, 0);
63 64
		}

65
		bss = libertas_find_ssid_in_list(adapter, assoc_req->ssid,
66
				assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel);
67 68
		if (bss != NULL) {
			lbs_deb_assoc("SSID found in scan list, associating\n");
69 70
			memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
			ret = wlan_associate(priv, assoc_req);
71
		} else {
72
			lbs_deb_assoc("SSID not found; cannot associate\n");
73
		}
74
	} else if (assoc_req->mode == IW_MODE_ADHOC) {
75 76 77
		/* Scan for the network, do not save previous results.  Stale
		 *   scan data will cause us to join a non-existant adhoc network
		 */
78
		libertas_send_specific_ssid_scan(priv, assoc_req->ssid,
79
			assoc_req->ssid_len, 1);
80 81

		/* Search for the requested SSID in the scan table */
82
		bss = libertas_find_ssid_in_list(adapter, assoc_req->ssid,
83
				assoc_req->ssid_len, NULL, IW_MODE_ADHOC, channel);
84
		if (bss != NULL) {
85
			lbs_deb_assoc("SSID found, will join\n");
86 87
			memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
			libertas_join_adhoc_network(priv, assoc_req);
88 89
		} else {
			/* else send START command */
90
			lbs_deb_assoc("SSID not found, creating adhoc network\n");
91
			memcpy(&assoc_req->bss.ssid, &assoc_req->ssid,
92 93
				IW_ESSID_MAX_SIZE);
			assoc_req->bss.ssid_len = assoc_req->ssid_len;
94
			libertas_start_adhoc_network(priv, assoc_req);
95 96 97
		}
	}

98
	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
99 100 101 102 103 104 105 106
	return ret;
}


static int assoc_helper_bssid(wlan_private *priv,
                              struct assoc_request * assoc_req)
{
	wlan_adapter *adapter = priv->adapter;
107 108
	int ret = 0;
	struct bss_descriptor * bss;
109

110
	lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID " MAC_FMT,
111 112 113
		MAC_ARG(assoc_req->bssid));

	/* Search for index position in list for requested MAC */
114
	bss = libertas_find_bssid_in_list(adapter, assoc_req->bssid,
115
			    assoc_req->mode);
116
	if (bss == NULL) {
117
		lbs_deb_assoc("ASSOC: WAP: BSSID " MAC_FMT " not found, "
118 119 120 121
			"cannot associate.\n", MAC_ARG(assoc_req->bssid));
		goto out;
	}

122
	memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
123
	if (assoc_req->mode == IW_MODE_INFRA) {
124
		ret = wlan_associate(priv, assoc_req);
125
		lbs_deb_assoc("ASSOC: wlan_associate(bssid) returned %d\n", ret);
126
	} else if (assoc_req->mode == IW_MODE_ADHOC) {
127
		libertas_join_adhoc_network(priv, assoc_req);
128 129 130
	}

out:
131
	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
132 133 134 135 136 137 138 139 140 141 142 143
	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)) {
144 145
		if (compare_ether_addr(bssid_any, assoc_req->bssid)
		    && compare_ether_addr(bssid_off, assoc_req->bssid)) {
146 147 148
			ret = assoc_helper_bssid(priv, assoc_req);
			done = 1;
			if (ret) {
149
				lbs_deb_assoc("ASSOC: bssid: ret = %d\n", ret);
150 151 152 153 154 155 156
			}
		}
	}

	if (!done && test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
		ret = assoc_helper_essid(priv, assoc_req);
		if (ret) {
157
			lbs_deb_assoc("ASSOC: bssid: ret = %d\n", ret);
158 159 160 161 162 163 164 165 166 167 168 169 170
		}
	}

	return ret;
}


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

171
	lbs_deb_enter(LBS_DEB_ASSOC);
172

173 174
	if (assoc_req->mode == adapter->mode)
		goto done;
175

176
	if (assoc_req->mode == IW_MODE_INFRA) {
177
		if (adapter->psstate != PS_STATE_FULL_POWER)
178 179
			libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
		adapter->psmode = WLAN802_11POWERMODECAM;
180 181
	}

182
	adapter->mode = assoc_req->mode;
183
	ret = libertas_prepare_and_send_command(priv,
184 185
				    CMD_802_11_SNMP_MIB,
				    0, CMD_OPTION_WAITFORRSP,
186
				    OID_802_11_INFRASTRUCTURE_MODE,
187
		/* Shoot me now */  (void *) (size_t) assoc_req->mode);
188

189 190
done:
	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
191 192 193 194
	return ret;
}


195 196 197
static int update_channel(wlan_private * priv)
{
	/* the channel in f/w could be out of sync, get the current channel */
198 199 200
	return libertas_prepare_and_send_command(priv, CMD_802_11_RF_CHANNEL,
				    CMD_OPT_802_11_RF_CHANNEL_GET,
				    CMD_OPTION_WAITFORRSP, 0, NULL);
201 202
}

203 204 205 206 207 208 209 210
void libertas_sync_channel(struct work_struct *work)
{
	wlan_private *priv = container_of(work, wlan_private, sync_channel);

	if (update_channel(priv) != 0)
		lbs_pr_info("Channel synchronization failed.");
}

211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
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);

230 231 232
	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);
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
	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;
}


266 267 268 269 270 271 272
static int assoc_helper_wep_keys(wlan_private *priv,
                                 struct assoc_request * assoc_req)
{
	wlan_adapter *adapter = priv->adapter;
	int i;
	int ret = 0;

273
	lbs_deb_enter(LBS_DEB_ASSOC);
274 275 276 277 278 279 280

	/* 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,
281 282 283
					    CMD_802_11_SET_WEP,
					    CMD_ACT_ADD,
					    CMD_OPTION_WAITFORRSP,
284 285 286
					    0, assoc_req);
	} else {
		ret = libertas_prepare_and_send_command(priv,
287 288 289
					    CMD_802_11_SET_WEP,
					    CMD_ACT_REMOVE,
					    CMD_OPTION_WAITFORRSP,
290 291 292 293 294 295 296
					    0, NULL);
	}

	if (ret)
		goto out;

	/* enable/disable the MAC's WEP packet filter */
297
	if (assoc_req->secinfo.wep_enabled)
298
		adapter->currentpacketfilter |= CMD_ACT_MAC_WEP_ENABLE;
299
	else
300
		adapter->currentpacketfilter &= ~CMD_ACT_MAC_WEP_ENABLE;
301 302 303 304 305 306 307 308 309
	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],
310
			sizeof(struct enc_key));
311 312 313 314 315 316
	}
	adapter->wep_tx_keyidx = assoc_req->wep_tx_keyidx;

	mutex_unlock(&adapter->lock);

out:
317
	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
318 319 320 321 322 323 324 325
	return ret;
}

static int assoc_helper_secinfo(wlan_private *priv,
                                struct assoc_request * assoc_req)
{
	wlan_adapter *adapter = priv->adapter;
	int ret = 0;
326 327
	u32 do_wpa;
	u32 rsn = 0;
328

329
	lbs_deb_enter(LBS_DEB_ASSOC);
330 331 332 333 334

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

	ret = libertas_set_mac_packet_filter(priv);
335 336
	if (ret)
		goto out;
337

338 339 340 341 342 343
	/* If RSN is already enabled, don't try to enable it again, since
	 * ENABLE_RSN resets internal state machines and will clobber the
	 * 4-way WPA handshake.
	 */

	/* Get RSN enabled/disabled */
344
	ret = libertas_prepare_and_send_command(priv,
345 346 347
				    CMD_802_11_ENABLE_RSN,
				    CMD_ACT_GET,
				    CMD_OPTION_WAITFORRSP,
348 349 350 351 352 353 354 355 356 357 358 359 360 361
				    0, &rsn);
	if (ret) {
		lbs_deb_assoc("Failed to get RSN status: %d", ret);
		goto out;
	}

	/* Don't re-enable RSN if it's already enabled */
	do_wpa = (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled);
	if (do_wpa == rsn)
		goto out;

	/* Set RSN enabled/disabled */
	rsn = do_wpa;
	ret = libertas_prepare_and_send_command(priv,
362 363 364
				    CMD_802_11_ENABLE_RSN,
				    CMD_ACT_SET,
				    CMD_OPTION_WAITFORRSP,
365
				    0, &rsn);
366 367

out:
368
	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
369 370 371 372 373 374 375 376 377
	return ret;
}


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

378
	lbs_deb_enter(LBS_DEB_ASSOC);
379 380

	ret = libertas_prepare_and_send_command(priv,
381 382 383
				    CMD_802_11_KEY_MATERIAL,
				    CMD_ACT_SET,
				    CMD_OPTION_WAITFORRSP,
384 385
				    0, assoc_req);

386
	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
387 388 389 390 391 392 393 394 395 396
	return ret;
}


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

397
	lbs_deb_enter(LBS_DEB_ASSOC);
398 399 400 401 402 403 404 405 406

	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;
	}

407
	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
408 409 410 411 412 413 414
	return ret;
}


static int should_deauth_infrastructure(wlan_adapter *adapter,
                                        struct assoc_request * assoc_req)
{
415
	if (adapter->connect_status != LIBERTAS_CONNECTED)
416 417 418
		return 0;

	if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
419
		lbs_deb_assoc("Deauthenticating due to new SSID in "
420 421 422 423 424
			" configuration request.\n");
		return 1;
	}

	if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
425
		if (adapter->secinfo.auth_mode != assoc_req->secinfo.auth_mode) {
426
			lbs_deb_assoc("Deauthenticating due to updated security "
427 428 429 430 431 432
				"info in configuration request.\n");
			return 1;
		}
	}

	if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
433
		lbs_deb_assoc("Deauthenticating due to new BSSID in "
434 435 436 437
			" configuration request.\n");
		return 1;
	}

438 439 440 441 442
	if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
		lbs_deb_assoc("Deauthenticating due to channel switch.\n");
		return 1;
	}

443 444
	/* FIXME: deal with 'auto' mode somehow */
	if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
445
		if (assoc_req->mode != IW_MODE_INFRA)
446 447 448 449 450 451 452 453 454 455
			return 1;
	}

	return 0;
}


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

459
	if (libertas_ssid_cmp(adapter->curbssparams.ssid,
460 461
	                      adapter->curbssparams.ssid_len,
	                      assoc_req->ssid, assoc_req->ssid_len) != 0)
462 463 464 465
		return 1;

	/* FIXME: deal with 'auto' mode somehow */
	if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
466
		if (assoc_req->mode != IW_MODE_ADHOC)
467 468 469
			return 1;
	}

470 471 472 473 474
	if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
		if (assoc_req->channel != adapter->curbssparams.channel)
			return 1;
	}

475 476 477 478
	return 0;
}


479
void libertas_association_worker(struct work_struct *work)
480 481 482 483 484 485 486
{
	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;

487
	lbs_deb_enter(LBS_DEB_ASSOC);
488 489

	mutex_lock(&adapter->lock);
490 491 492
	assoc_req = adapter->pending_assoc_req;
	adapter->pending_assoc_req = NULL;
	adapter->in_progress_assoc_req = assoc_req;
493 494
	mutex_unlock(&adapter->lock);

495 496
	if (!assoc_req)
		goto done;
497

498
	print_assoc_req(__func__, assoc_req);
499 500 501

	/* If 'any' SSID was specified, find an SSID to associate with */
	if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)
502
	    && !assoc_req->ssid_len)
503 504 505 506
		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)) {
507 508
		if (compare_ether_addr(assoc_req->bssid, bssid_any)
		    && compare_ether_addr(assoc_req->bssid, bssid_off))
509 510 511 512
			find_any_ssid = 0;
	}

	if (find_any_ssid) {
513
		u8 new_mode;
514

515
		ret = libertas_find_best_network_ssid(priv, assoc_req->ssid,
516
				&assoc_req->ssid_len, assoc_req->mode, &new_mode);
517
		if (ret) {
518
			lbs_deb_assoc("Could not find best network\n");
519 520 521 522 523
			ret = -ENETUNREACH;
			goto out;
		}

		/* Ensure we switch to the mode of the AP */
524
		if (assoc_req->mode == IW_MODE_AUTO) {
525 526 527 528 529 530 531 532 533
			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.
	 */
534
	if (adapter->mode == IW_MODE_INFRA) {
535 536 537
		if (should_deauth_infrastructure(adapter, assoc_req)) {
			ret = libertas_send_deauthentication(priv);
			if (ret) {
538
				lbs_deb_assoc("Deauthentication due to new "
539 540 541 542
					"configuration request failed: %d\n",
					ret);
			}
		}
543
	} else if (adapter->mode == IW_MODE_ADHOC) {
544 545 546
		if (should_stop_adhoc(adapter, assoc_req)) {
			ret = libertas_stop_adhoc_network(priv);
			if (ret) {
547
				lbs_deb_assoc("Teardown of AdHoc network due to "
548 549 550 551 552 553 554 555 556 557 558
					"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) {
559 560
			lbs_deb_assoc("ASSOC(:%d) mode: ret = %d\n",
			              __LINE__, ret);
561 562 563 564
			goto out;
		}
	}

565 566 567 568 569 570 571 572 573
	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;
		}
	}

574 575 576 577
	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) {
578 579
			lbs_deb_assoc("ASSOC(:%d) wep_keys: ret = %d\n",
			              __LINE__, ret);
580 581 582 583 584 585 586
			goto out;
		}
	}

	if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
		ret = assoc_helper_secinfo(priv, assoc_req);
		if (ret) {
587 588
			lbs_deb_assoc("ASSOC(:%d) secinfo: ret = %d\n",
			              __LINE__, ret);
589 590 591 592 593 594 595
			goto out;
		}
	}

	if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
		ret = assoc_helper_wpa_ie(priv, assoc_req);
		if (ret) {
596 597
			lbs_deb_assoc("ASSOC(:%d) wpa_ie: ret = %d\n",
			              __LINE__, ret);
598 599 600 601 602 603 604 605
			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) {
606 607
			lbs_deb_assoc("ASSOC(:%d) wpa_keys: ret = %d\n",
			              __LINE__, ret);
608 609 610 611 612 613 614 615 616 617 618 619 620
			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) {
621
			lbs_deb_assoc("ASSOC: association attempt unsuccessful: %d\n",
622 623 624 625
				ret);
			success = 0;
		}

626
		if (adapter->connect_status != LIBERTAS_CONNECTED) {
627
			lbs_deb_assoc("ASSOC: assoication attempt unsuccessful, "
628 629 630 631 632
				"not connected.\n");
			success = 0;
		}

		if (success) {
633
			lbs_deb_assoc("ASSOC: association attempt successful. "
634
				"Associated to '%s' (" MAC_FMT ")\n",
635 636
				escape_essid(adapter->curbssparams.ssid,
				             adapter->curbssparams.ssid_len),
637
				MAC_ARG(adapter->curbssparams.bssid));
638
			libertas_prepare_and_send_command(priv,
639 640
				CMD_802_11_RSSI,
				0, CMD_OPTION_WAITFORRSP, 0, NULL);
641 642

			libertas_prepare_and_send_command(priv,
643 644
				CMD_802_11_GET_LOG,
				0, CMD_OPTION_WAITFORRSP, 0, NULL);
645 646 647 648 649 650 651
		} else {
			ret = -1;
		}
	}

out:
	if (ret) {
652
		lbs_deb_assoc("ASSOC: reconfiguration attempt unsuccessful: %d\n",
653 654
			ret);
	}
655 656 657 658

	mutex_lock(&adapter->lock);
	adapter->in_progress_assoc_req = NULL;
	mutex_unlock(&adapter->lock);
659
	kfree(assoc_req);
660 661 662

done:
	lbs_deb_leave(LBS_DEB_ASSOC);
663 664 665 666 667 668 669 670 671 672
}


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

673 674 675 676
	if (!adapter->pending_assoc_req) {
		adapter->pending_assoc_req = kzalloc(sizeof(struct assoc_request),
		                                     GFP_KERNEL);
		if (!adapter->pending_assoc_req) {
677 678 679 680 681 682 683 684 685
			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.
	 */
686
	assoc_req = adapter->pending_assoc_req;
687
	if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
688
		memcpy(&assoc_req->ssid, &adapter->curbssparams.ssid,
689 690
		       IW_ESSID_MAX_SIZE);
		assoc_req->ssid_len = adapter->curbssparams.ssid_len;
691 692 693 694 695
	}

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

696 697 698
	if (!test_bit(ASSOC_FLAG_BAND, &assoc_req->flags))
		assoc_req->band = adapter->curbssparams.band;

699
	if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags))
700
		assoc_req->mode = adapter->mode;
701 702 703 704 705 706 707 708 709 710

	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],
711
				sizeof(struct enc_key));
712 713 714 715 716 717 718 719
		}
	}

	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,
720
			sizeof(struct enc_key));
721 722 723 724
	}

	if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
		memcpy(&assoc_req->wpa_unicast_key, &adapter->wpa_unicast_key,
725
			sizeof(struct enc_key));
726 727 728 729 730 731 732 733 734 735 736 737 738
	}

	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;
	}

739 740
	print_assoc_req(__func__, assoc_req);

741 742
	return assoc_req;
}