assoc.c 19.6 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 178 179 180 181
		if (adapter->psstate != PS_STATE_FULL_POWER)
			libertas_ps_wakeup(priv, cmd_option_waitforrsp);
		adapter->psmode = wlan802_11powermodecam;
	}

182
	adapter->mode = assoc_req->mode;
183 184 185 186
	ret = libertas_prepare_and_send_command(priv,
				    cmd_802_11_snmp_mib,
				    0, cmd_option_waitforrsp,
				    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 198 199 200 201 202
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);
}

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


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 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296

	/* 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 */
297
	if (assoc_req->secinfo.wep_enabled)
298 299 300 301 302 303 304 305 306 307 308 309
		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],
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 345 346 347
	ret = libertas_prepare_and_send_command(priv,
				    cmd_802_11_enable_rsn,
				    cmd_act_set,
				    cmd_option_waitforrsp,
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
				    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,
				    cmd_802_11_enable_rsn,
				    cmd_act_set,
				    cmd_option_waitforrsp,
				    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 381 382 383 384 385

	ret = libertas_prepare_and_send_command(priv,
				    cmd_802_11_key_material,
				    cmd_act_set,
				    cmd_option_waitforrsp,
				    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 415 416 417 418
	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)) {
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 456 457 458
			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;

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
lbs_deb_assoc("ASSOC(:%d) mode: ret = %d\n", __LINE__, ret);
560 561 562 563
			goto out;
		}
	}

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

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

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

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

		if (adapter->connect_status != libertas_connected) {
622
			lbs_deb_assoc("ASSOC: assoication attempt unsuccessful, "
623 624 625 626 627
				"not connected.\n");
			success = 0;
		}

		if (success) {
628
			lbs_deb_assoc("ASSOC: association attempt successful. "
629
				"Associated to '%s' (" MAC_FMT ")\n",
630 631
				escape_essid(adapter->curbssparams.ssid,
				             adapter->curbssparams.ssid_len),
632
				MAC_ARG(adapter->curbssparams.bssid));
633 634 635 636 637 638 639 640 641 642 643 644 645 646
			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) {
647
		lbs_deb_assoc("ASSOC: reconfiguration attempt unsuccessful: %d\n",
648 649
			ret);
	}
650 651 652 653

	mutex_lock(&adapter->lock);
	adapter->in_progress_assoc_req = NULL;
	mutex_unlock(&adapter->lock);
654
	kfree(assoc_req);
655 656 657

done:
	lbs_deb_leave(LBS_DEB_ASSOC);
658 659 660 661 662 663 664 665 666 667
}


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

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

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

691 692 693
	if (!test_bit(ASSOC_FLAG_BAND, &assoc_req->flags))
		assoc_req->band = adapter->curbssparams.band;

694
	if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags))
695
		assoc_req->mode = adapter->mode;
696 697 698 699 700 701 702 703 704 705

	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],
706
				sizeof(struct enc_key));
707 708 709 710 711 712 713 714
		}
	}

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

	if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
		memcpy(&assoc_req->wpa_unicast_key, &adapter->wpa_unicast_key,
720
			sizeof(struct enc_key));
721 722 723 724 725 726 727 728 729 730 731 732 733
	}

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

734 735
	print_assoc_req(__func__, assoc_req);

736 737
	return assoc_req;
}