assoc.c 18.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 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 203 204 205 206 207 208 209 210 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
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;
}


258 259 260 261 262 263 264
static int assoc_helper_wep_keys(wlan_private *priv,
                                 struct assoc_request * assoc_req)
{
	wlan_adapter *adapter = priv->adapter;
	int i;
	int ret = 0;

265
	lbs_deb_enter(LBS_DEB_ASSOC);
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288

	/* 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 */
289
	if (assoc_req->secinfo.wep_enabled)
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
		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:
309
	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
310 311 312 313 314 315 316 317 318
	return ret;
}

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

319
	lbs_deb_enter(LBS_DEB_ASSOC);
320 321 322 323 324

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

	ret = libertas_set_mac_packet_filter(priv);
325 326
	if (ret)
		goto out;
327

328 329 330 331 332 333 334 335
	/* 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:
336
	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
337 338 339 340 341 342 343 344 345
	return ret;
}


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

346
	lbs_deb_enter(LBS_DEB_ASSOC);
347 348 349 350 351 352 353

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

354
	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
355 356 357 358 359 360 361 362 363 364
	return ret;
}


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

365
	lbs_deb_enter(LBS_DEB_ASSOC);
366 367 368 369 370 371 372 373 374

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

375
	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
376 377 378 379 380 381 382 383 384 385 386
	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)) {
387
		lbs_deb_assoc("Deauthenticating due to new SSID in "
388 389 390 391 392
			" configuration request.\n");
		return 1;
	}

	if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
393
		if (adapter->secinfo.auth_mode != assoc_req->secinfo.auth_mode) {
394
			lbs_deb_assoc("Deauthenticating due to updated security "
395 396 397 398 399 400
				"info in configuration request.\n");
			return 1;
		}
	}

	if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
401
		lbs_deb_assoc("Deauthenticating due to new BSSID in "
402 403 404 405 406 407
			" configuration request.\n");
		return 1;
	}

	/* FIXME: deal with 'auto' mode somehow */
	if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
408
		if (assoc_req->mode != IW_MODE_INFRA)
409 410 411 412 413 414 415 416 417 418 419 420 421
			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;

422
	if (libertas_ssid_cmp(adapter->curbssparams.ssid,
423 424
	                      adapter->curbssparams.ssid_len,
	                      assoc_req->ssid, assoc_req->ssid_len) != 0)
425 426 427 428
		return 1;

	/* FIXME: deal with 'auto' mode somehow */
	if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
429
		if (assoc_req->mode != IW_MODE_ADHOC)
430 431 432
			return 1;
	}

433 434 435 436 437
	if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
		if (assoc_req->channel != adapter->curbssparams.channel)
			return 1;
	}

438 439 440 441
	return 0;
}


442
void libertas_association_worker(struct work_struct *work)
443 444 445 446 447 448 449
{
	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;

450
	lbs_deb_enter(LBS_DEB_ASSOC);
451 452

	mutex_lock(&adapter->lock);
453 454 455
	assoc_req = adapter->pending_assoc_req;
	adapter->pending_assoc_req = NULL;
	adapter->in_progress_assoc_req = assoc_req;
456 457
	mutex_unlock(&adapter->lock);

458 459
	if (!assoc_req)
		goto done;
460

461
	print_assoc_req(__func__, assoc_req);
462 463 464

	/* If 'any' SSID was specified, find an SSID to associate with */
	if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)
465
	    && !assoc_req->ssid_len)
466 467 468 469
		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)) {
470 471
		if (compare_ether_addr(assoc_req->bssid, bssid_any)
		    && compare_ether_addr(assoc_req->bssid, bssid_off))
472 473 474 475
			find_any_ssid = 0;
	}

	if (find_any_ssid) {
476
		u8 new_mode;
477

478
		ret = libertas_find_best_network_ssid(priv, assoc_req->ssid,
479
				&assoc_req->ssid_len, assoc_req->mode, &new_mode);
480
		if (ret) {
481
			lbs_deb_assoc("Could not find best network\n");
482 483 484 485 486
			ret = -ENETUNREACH;
			goto out;
		}

		/* Ensure we switch to the mode of the AP */
487
		if (assoc_req->mode == IW_MODE_AUTO) {
488 489 490 491 492 493 494 495 496
			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.
	 */
497
	if (adapter->mode == IW_MODE_INFRA) {
498 499 500
		if (should_deauth_infrastructure(adapter, assoc_req)) {
			ret = libertas_send_deauthentication(priv);
			if (ret) {
501
				lbs_deb_assoc("Deauthentication due to new "
502 503 504 505
					"configuration request failed: %d\n",
					ret);
			}
		}
506
	} else if (adapter->mode == IW_MODE_ADHOC) {
507 508 509
		if (should_stop_adhoc(adapter, assoc_req)) {
			ret = libertas_stop_adhoc_network(priv);
			if (ret) {
510
				lbs_deb_assoc("Teardown of AdHoc network due to "
511 512 513 514 515 516 517 518 519 520 521
					"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) {
522
lbs_deb_assoc("ASSOC(:%d) mode: ret = %d\n", __LINE__, ret);
523 524 525 526
			goto out;
		}
	}

527 528 529 530 531 532 533 534 535
	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;
		}
	}

536 537 538 539
	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) {
540
lbs_deb_assoc("ASSOC(:%d) wep_keys: ret = %d\n", __LINE__, ret);
541 542 543 544 545 546 547
			goto out;
		}
	}

	if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
		ret = assoc_helper_secinfo(priv, assoc_req);
		if (ret) {
548
lbs_deb_assoc("ASSOC(:%d) secinfo: ret = %d\n", __LINE__, ret);
549 550 551 552 553 554 555
			goto out;
		}
	}

	if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
		ret = assoc_helper_wpa_ie(priv, assoc_req);
		if (ret) {
556
lbs_deb_assoc("ASSOC(:%d) wpa_ie: ret = %d\n", __LINE__, ret);
557 558 559 560 561 562 563 564
			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) {
565
lbs_deb_assoc("ASSOC(:%d) wpa_keys: ret = %d\n", __LINE__, ret);
566 567 568 569 570 571 572 573 574 575 576 577 578
			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) {
579
			lbs_deb_assoc("ASSOC: association attempt unsuccessful: %d\n",
580 581 582 583 584
				ret);
			success = 0;
		}

		if (adapter->connect_status != libertas_connected) {
585
			lbs_deb_assoc("ASSOC: assoication attempt unsuccessful, "
586 587 588 589 590
				"not connected.\n");
			success = 0;
		}

		if (success) {
591
			lbs_deb_assoc("ASSOC: association attempt successful. "
592
				"Associated to '%s' (" MAC_FMT ")\n",
593 594
				escape_essid(adapter->curbssparams.ssid,
				             adapter->curbssparams.ssid_len),
595
				MAC_ARG(adapter->curbssparams.bssid));
596 597 598 599 600 601 602 603 604 605 606 607 608 609
			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) {
610
		lbs_deb_assoc("ASSOC: reconfiguration attempt unsuccessful: %d\n",
611 612
			ret);
	}
613 614 615 616

	mutex_lock(&adapter->lock);
	adapter->in_progress_assoc_req = NULL;
	mutex_unlock(&adapter->lock);
617
	kfree(assoc_req);
618 619 620

done:
	lbs_deb_leave(LBS_DEB_ASSOC);
621 622 623 624 625 626 627 628 629 630
}


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

631 632 633 634
	if (!adapter->pending_assoc_req) {
		adapter->pending_assoc_req = kzalloc(sizeof(struct assoc_request),
		                                     GFP_KERNEL);
		if (!adapter->pending_assoc_req) {
635 636 637 638 639 640 641 642 643
			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.
	 */
644
	assoc_req = adapter->pending_assoc_req;
645
	if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
646
		memcpy(&assoc_req->ssid, &adapter->curbssparams.ssid,
647 648
		       IW_ESSID_MAX_SIZE);
		assoc_req->ssid_len = adapter->curbssparams.ssid_len;
649 650 651 652 653
	}

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

654 655 656
	if (!test_bit(ASSOC_FLAG_BAND, &assoc_req->flags))
		assoc_req->band = adapter->curbssparams.band;

657
	if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags))
658
		assoc_req->mode = adapter->mode;
659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696

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

697 698
	print_assoc_req(__func__, assoc_req);

699 700
	return assoc_req;
}