join.c 24.2 KB
Newer Older
1 2 3 4 5 6 7 8 9
/**
  *  Functions implementing wlan infrastructure and adhoc join routines,
  *  IOCTL handlers as well as command preperation and response routines
  *  for sending adhoc start, adhoc join, and association commands
  *  to the firmware.
  */
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/wireless.h>
10
#include <linux/etherdevice.h>
11 12 13 14 15 16 17

#include <net/iw_handler.h>

#include "host.h"
#include "decl.h"
#include "join.h"
#include "dev.h"
18
#include "assoc.h"
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

/**
 *  @brief This function finds out the common rates between rate1 and rate2.
 *
 * It will fill common rates in rate1 as output if found.
 *
 * NOTE: Setting the MSB of the basic rates need to be taken
 *   care, either before or after calling this function
 *
 *  @param adapter     A pointer to wlan_adapter structure
 *  @param rate1       the buffer which keeps input and output
 *  @param rate1_size  the size of rate1 buffer
 *  @param rate2       the buffer which keeps rate2
 *  @param rate2_size  the size of rate2 buffer.
 *
 *  @return            0 or -1
 */
static int get_common_rates(wlan_adapter * adapter, u8 * rate1,
			    int rate1_size, u8 * rate2, int rate2_size)
{
	u8 *ptr = rate1;
	int ret = 0;
	u8 tmp[30];
	int i;

	memset(&tmp, 0, sizeof(tmp));
	memcpy(&tmp, rate1, min_t(size_t, rate1_size, sizeof(tmp)));
	memset(rate1, 0, rate1_size);

	/* Mask the top bit of the original values */
	for (i = 0; tmp[i] && i < sizeof(tmp); i++)
		tmp[i] &= 0x7F;

	for (i = 0; rate2[i] && i < rate2_size; i++) {
		/* Check for Card Rate in tmp, excluding the top bit */
		if (strchr(tmp, rate2[i] & 0x7F)) {
			/* values match, so copy the Card Rate to rate1 */
			*rate1++ = rate2[i];
		}
	}

	lbs_dbg_hex("rate1 (AP) rates:", tmp, sizeof(tmp));
	lbs_dbg_hex("rate2 (Card) rates:", rate2, rate2_size);
	lbs_dbg_hex("Common rates:", ptr, rate1_size);
63
	lbs_deb_join("Tx datarate is set to 0x%X\n", adapter->datarate);
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89

	if (!adapter->is_datarate_auto) {
		while (*ptr) {
			if ((*ptr & 0x7f) == adapter->datarate) {
				ret = 0;
				goto done;
			}
			ptr++;
		}
		lbs_pr_alert( "Previously set fixed data rate %#x isn't "
		       "compatible with the network.\n", adapter->datarate);

		ret = -1;
		goto done;
	}

	ret = 0;
done:
	return ret;
}

int libertas_send_deauth(wlan_private * priv)
{
	wlan_adapter *adapter = priv->adapter;
	int ret = 0;

90
	if (adapter->mode == IW_MODE_INFRA &&
91
	    adapter->connect_status == LIBERTAS_CONNECTED)
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
		ret = libertas_send_deauthentication(priv);
	else
		ret = -ENOTSUPP;

	return ret;
}

/**
 *  @brief Associate to a specific BSS discovered in a scan
 *
 *  @param priv      A pointer to wlan_private structure
 *  @param pbssdesc  Pointer to the BSS descriptor to associate with.
 *
 *  @return          0-success, otherwise fail
 */
107
int wlan_associate(wlan_private * priv, struct assoc_request * assoc_req)
108 109 110 111
{
	wlan_adapter *adapter = priv->adapter;
	int ret;

112
	lbs_deb_enter(LBS_DEB_JOIN);
113

114 115
	ret = libertas_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE,
				    0, CMD_OPTION_WAITFORRSP,
116
				    0, assoc_req->bss.bssid);
117

118 119
	if (ret)
		goto done;
120 121

	/* set preamble to firmware */
122 123
	if (   (adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
	    && (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE))
124
		adapter->preamble = CMD_TYPE_SHORT_PREAMBLE;
125
	else
126
		adapter->preamble = CMD_TYPE_LONG_PREAMBLE;
127 128 129

	libertas_set_radio_control(priv);

130 131
	ret = libertas_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE,
				    0, CMD_OPTION_WAITFORRSP, 0, assoc_req);
132

133 134
done:
	lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
135 136 137 138 139 140 141 142 143 144
	return ret;
}

/**
 *  @brief Start an Adhoc Network
 *
 *  @param priv         A pointer to wlan_private structure
 *  @param adhocssid    The ssid of the Adhoc Network
 *  @return             0--success, -1--fail
 */
145
int libertas_start_adhoc_network(wlan_private * priv, struct assoc_request * assoc_req)
146 147 148 149 150 151
{
	wlan_adapter *adapter = priv->adapter;
	int ret = 0;

	adapter->adhoccreate = 1;

152
	if (adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) {
153
		lbs_deb_join("AdhocStart: Short preamble\n");
154
		adapter->preamble = CMD_TYPE_SHORT_PREAMBLE;
155 156
	} else {
		lbs_deb_join("AdhocStart: Long preamble\n");
157
		adapter->preamble = CMD_TYPE_LONG_PREAMBLE;
158 159 160 161
	}

	libertas_set_radio_control(priv);

162 163
	lbs_deb_join("AdhocStart: channel = %d\n", assoc_req->channel);
	lbs_deb_join("AdhocStart: band = %d\n", assoc_req->band);
164

165 166
	ret = libertas_prepare_and_send_command(priv, CMD_802_11_AD_HOC_START,
				    0, CMD_OPTION_WAITFORRSP, 0, assoc_req);
167 168 169 170 171 172 173 174 175 176 177 178 179

	return ret;
}

/**
 *  @brief Join an adhoc network found in a previous scan
 *
 *  @param priv         A pointer to wlan_private structure
 *  @param pbssdesc     Pointer to a BSS descriptor found in a previous scan
 *                      to attempt to join
 *
 *  @return             0--success, -1--fail
 */
180
int libertas_join_adhoc_network(wlan_private * priv, struct assoc_request * assoc_req)
181 182
{
	wlan_adapter *adapter = priv->adapter;
183
	struct bss_descriptor * bss = &assoc_req->bss;
184 185
	int ret = 0;

186 187 188 189 190 191 192 193
	lbs_deb_join("%s: Current SSID '%s', ssid length %u\n",
	             __func__,
	             escape_essid(adapter->curbssparams.ssid,
	                          adapter->curbssparams.ssid_len),
	             adapter->curbssparams.ssid_len);
	lbs_deb_join("%s: requested ssid '%s', ssid length %u\n",
	             __func__, escape_essid(bss->ssid, bss->ssid_len),
	             bss->ssid_len);
194 195

	/* check if the requested SSID is already joined */
196
	if (adapter->curbssparams.ssid_len
197
	    && !libertas_ssid_cmp(adapter->curbssparams.ssid,
198 199
	                          adapter->curbssparams.ssid_len,
	                          bss->ssid, bss->ssid_len)
200
	    && (adapter->mode == IW_MODE_ADHOC)) {
201
		lbs_deb_join(
202 203 204 205 206
		       "ADHOC_J_CMD: New ad-hoc SSID is the same as current, "
		       "not attempting to re-join");
		return -1;
	}

207
	/* Use shortpreamble only when both creator and card supports
208
	   short preamble */
209 210
	if (   !(bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
	    || !(adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) {
211
		lbs_deb_join("AdhocJoin: Long preamble\n");
212
		adapter->preamble = CMD_TYPE_LONG_PREAMBLE;
213
	} else {
214
		lbs_deb_join("AdhocJoin: Short preamble\n");
215
		adapter->preamble = CMD_TYPE_SHORT_PREAMBLE;
216 217 218 219
	}

	libertas_set_radio_control(priv);

220 221
	lbs_deb_join("AdhocJoin: channel = %d\n", assoc_req->channel);
	lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band);
222 223 224

	adapter->adhoccreate = 0;

225 226
	ret = libertas_prepare_and_send_command(priv, CMD_802_11_AD_HOC_JOIN,
				    0, CMD_OPTION_WAITFORRSP,
227
				    OID_802_11_SSID, assoc_req);
228 229 230 231 232 233

	return ret;
}

int libertas_stop_adhoc_network(wlan_private * priv)
{
234 235
	return libertas_prepare_and_send_command(priv, CMD_802_11_AD_HOC_STOP,
				     0, CMD_OPTION_WAITFORRSP, 0, NULL);
236 237 238 239 240 241 242 243 244 245
}

/**
 *  @brief Send Deauthentication Request
 *
 *  @param priv      A pointer to wlan_private structure
 *  @return          0--success, -1--fail
 */
int libertas_send_deauthentication(wlan_private * priv)
{
246 247
	return libertas_prepare_and_send_command(priv, CMD_802_11_DEAUTHENTICATE,
				     0, CMD_OPTION_WAITFORRSP, 0, NULL);
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
}

/**
 *  @brief This function prepares command of authenticate.
 *
 *  @param priv      A pointer to wlan_private structure
 *  @param cmd       A pointer to cmd_ds_command structure
 *  @param pdata_buf Void cast of pointer to a BSSID to authenticate with
 *
 *  @return         0 or -1
 */
int libertas_cmd_80211_authenticate(wlan_private * priv,
				 struct cmd_ds_command *cmd,
				 void *pdata_buf)
{
	wlan_adapter *adapter = priv->adapter;
264 265
	struct cmd_ds_802_11_authenticate *pauthenticate = &cmd->params.auth;
	int ret = -1;
266 267
	u8 *bssid = pdata_buf;

268 269
	lbs_deb_enter(LBS_DEB_JOIN);

270
	cmd->command = cpu_to_le16(CMD_802_11_AUTHENTICATE);
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate)
	                        + S_DS_GEN);

	/* translate auth mode to 802.11 defined wire value */
	switch (adapter->secinfo.auth_mode) {
	case IW_AUTH_ALG_OPEN_SYSTEM:
		pauthenticate->authtype = 0x00;
		break;
	case IW_AUTH_ALG_SHARED_KEY:
		pauthenticate->authtype = 0x01;
		break;
	case IW_AUTH_ALG_LEAP:
		pauthenticate->authtype = 0x80;
		break;
	default:
286
		lbs_deb_join("AUTH_CMD: invalid auth alg 0x%X\n",
287 288 289
		             adapter->secinfo.auth_mode);
		goto out;
	}
290 291 292

	memcpy(pauthenticate->macaddr, bssid, ETH_ALEN);

293 294
	lbs_deb_join("AUTH_CMD: BSSID is : " MAC_FMT " auth=0x%X\n",
	             MAC_ARG(bssid), pauthenticate->authtype);
295
	ret = 0;
296

297
out:
298
	lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
299
	return ret;
300 301 302 303 304 305 306 307
}

int libertas_cmd_80211_deauthenticate(wlan_private * priv,
				   struct cmd_ds_command *cmd)
{
	wlan_adapter *adapter = priv->adapter;
	struct cmd_ds_802_11_deauthenticate *dauth = &cmd->params.deauth;

308
	lbs_deb_enter(LBS_DEB_JOIN);
309

310
	cmd->command = cpu_to_le16(CMD_802_11_DEAUTHENTICATE);
311
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate) +
312 313 314
			     S_DS_GEN);

	/* set AP MAC address */
315
	memmove(dauth->macaddr, adapter->curbssparams.bssid, ETH_ALEN);
316 317 318 319 320

	/* Reason code 3 = Station is leaving */
#define REASON_CODE_STA_LEAVING 3
	dauth->reasoncode = cpu_to_le16(REASON_CODE_STA_LEAVING);

321
	lbs_deb_leave(LBS_DEB_JOIN);
322 323 324 325 326 327 328 329 330
	return 0;
}

int libertas_cmd_80211_associate(wlan_private * priv,
			      struct cmd_ds_command *cmd, void *pdata_buf)
{
	wlan_adapter *adapter = priv->adapter;
	struct cmd_ds_802_11_associate *passo = &cmd->params.associate;
	int ret = 0;
331 332
	struct assoc_request * assoc_req = pdata_buf;
	struct bss_descriptor * bss = &assoc_req->bss;
333 334 335
	u8 *card_rates;
	u8 *pos;
	int card_rates_size;
336
	u16 tmpcap, tmplen;
337 338 339 340 341 342
	struct mrvlietypes_ssidparamset *ssid;
	struct mrvlietypes_phyparamset *phy;
	struct mrvlietypes_ssparamset *ss;
	struct mrvlietypes_ratesparamset *rates;
	struct mrvlietypes_rsnparamset *rsn;

343
	lbs_deb_enter(LBS_DEB_JOIN);
344 345 346 347 348 349 350 351

	pos = (u8 *) passo;

	if (!adapter) {
		ret = -1;
		goto done;
	}

352
	cmd->command = cpu_to_le16(CMD_802_11_ASSOCIATE);
353

354
	memcpy(passo->peerstaaddr, bss->bssid, sizeof(passo->peerstaaddr));
355 356 357
	pos += sizeof(passo->peerstaaddr);

	/* set the listen interval */
358
	passo->listeninterval = cpu_to_le16(adapter->listeninterval);
359

360
	pos += sizeof(passo->capability);
361 362 363 364 365 366
	pos += sizeof(passo->listeninterval);
	pos += sizeof(passo->bcnperiod);
	pos += sizeof(passo->dtimperiod);

	ssid = (struct mrvlietypes_ssidparamset *) pos;
	ssid->header.type = cpu_to_le16(TLV_TYPE_SSID);
367
	tmplen = bss->ssid_len;
368
	ssid->header.len = cpu_to_le16(tmplen);
369
	memcpy(ssid->ssid, bss->ssid, tmplen);
370
	pos += sizeof(ssid->header) + tmplen;
371 372 373

	phy = (struct mrvlietypes_phyparamset *) pos;
	phy->header.type = cpu_to_le16(TLV_TYPE_PHY_DS);
374 375
	tmplen = sizeof(phy->fh_ds.dsparamset);
	phy->header.len = cpu_to_le16(tmplen);
376
	memcpy(&phy->fh_ds.dsparamset,
377
	       &bss->phyparamset.dsparamset.currentchan,
378 379
	       tmplen);
	pos += sizeof(phy->header) + tmplen;
380 381 382

	ss = (struct mrvlietypes_ssparamset *) pos;
	ss->header.type = cpu_to_le16(TLV_TYPE_CF);
383 384 385
	tmplen = sizeof(ss->cf_ibss.cfparamset);
	ss->header.len = cpu_to_le16(tmplen);
	pos += sizeof(ss->header) + tmplen;
386 387 388 389

	rates = (struct mrvlietypes_ratesparamset *) pos;
	rates->header.type = cpu_to_le16(TLV_TYPE_RATES);

390
	memcpy(&rates->rates, &bss->libertas_supported_rates, WLAN_SUPPORTED_RATES);
391 392 393 394 395 396 397 398 399 400

	card_rates = libertas_supported_rates;
	card_rates_size = sizeof(libertas_supported_rates);

	if (get_common_rates(adapter, rates->rates, WLAN_SUPPORTED_RATES,
			     card_rates, card_rates_size)) {
		ret = -1;
		goto done;
	}

401 402
	tmplen = min_t(size_t, strlen(rates->rates), WLAN_SUPPORTED_RATES);
	adapter->curbssparams.numofrates = tmplen;
403

404 405
	pos += sizeof(rates->header) + tmplen;
	rates->header.len = cpu_to_le16(tmplen);
406

407
	if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
408
		rsn = (struct mrvlietypes_rsnparamset *) pos;
409 410 411 412 413
		/* WPA_IE or WPA2_IE */
		rsn->header.type = cpu_to_le16((u16) assoc_req->wpa_ie[0]);
		tmplen = (u16) assoc_req->wpa_ie[1];
		rsn->header.len = cpu_to_le16(tmplen);
		memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen);
414
		lbs_dbg_hex("ASSOC_CMD: RSN IE", (u8 *) rsn,
415 416
			sizeof(rsn->header) + tmplen);
		pos += sizeof(rsn->header) + tmplen;
417 418 419
	}

	/* update curbssparams */
420
	adapter->curbssparams.channel = bss->phyparamset.dsparamset.currentchan;
421 422 423

	/* Copy the infra. association rates into Current BSS state structure */
	memcpy(&adapter->curbssparams.datarates, &rates->rates,
424 425
	       min_t(size_t, sizeof(adapter->curbssparams.datarates),
		     cpu_to_le16(rates->header.len)));
426

427 428
	lbs_deb_join("ASSOC_CMD: rates->header.len = %d\n",
		     cpu_to_le16(rates->header.len));
429

430
	if (libertas_parse_dnld_countryinfo_11d(priv, bss)) {
431 432 433 434 435 436
		ret = -1;
		goto done;
	}

	cmd->size = cpu_to_le16((u16) (pos - (u8 *) passo) + S_DS_GEN);

437 438 439 440 441 442
	/* set the capability info */
	tmpcap = (bss->capability & CAPINFO_MASK);
	if (bss->mode == IW_MODE_INFRA)
		tmpcap |= WLAN_CAPABILITY_ESS;
	passo->capability = cpu_to_le16(tmpcap);
	lbs_deb_join("ASSOC_CMD: capability=%4X CAPINFO_MASK=%4X\n",
443
		     tmpcap, CAPINFO_MASK);
444

445 446
done:
	lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
447 448 449 450
	return ret;
}

int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
451
				 struct cmd_ds_command *cmd, void *pdata_buf)
452 453 454 455 456 457
{
	wlan_adapter *adapter = priv->adapter;
	struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads;
	int ret = 0;
	int cmdappendsize = 0;
	int i;
458
	struct assoc_request * assoc_req = pdata_buf;
459
	u16 tmpcap = 0;
460

461
	lbs_deb_enter(LBS_DEB_JOIN);
462 463 464 465 466 467

	if (!adapter) {
		ret = -1;
		goto done;
	}

468
	cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_START);
469 470 471 472 473 474 475 476 477 478 479 480 481

	/*
	 * Fill in the parameters for 2 data structures:
	 *   1. cmd_ds_802_11_ad_hoc_start command
	 *   2. adapter->scantable[i]
	 *
	 * Driver will fill up SSID, bsstype,IBSS param, Physical Param,
	 *   probe delay, and cap info.
	 *
	 * Firmware will fill up beacon period, DTIM, Basic rates
	 *   and operational rates.
	 */

482 483
	memset(adhs->ssid, 0, IW_ESSID_MAX_SIZE);
	memcpy(adhs->ssid, assoc_req->ssid, assoc_req->ssid_len);
484

485 486 487
	lbs_deb_join("ADHOC_S_CMD: SSID '%s', ssid length %u\n",
	             escape_essid(assoc_req->ssid, assoc_req->ssid_len),
	             assoc_req->ssid_len);
488 489

	/* set the BSS type */
490
	adhs->bsstype = CMD_BSS_TYPE_IBSS;
491
	adapter->mode = IW_MODE_ADHOC;
492
	adhs->beaconperiod = cpu_to_le16(adapter->beaconperiod);
493 494 495 496 497 498 499 500

	/* set Physical param set */
#define DS_PARA_IE_ID   3
#define DS_PARA_IE_LEN  1

	adhs->phyparamset.dsparamset.elementid = DS_PARA_IE_ID;
	adhs->phyparamset.dsparamset.len = DS_PARA_IE_LEN;

501
	WARN_ON(!assoc_req->channel);
502

503
	lbs_deb_join("ADHOC_S_CMD: Creating ADHOC on channel %d\n",
504
		     assoc_req->channel);
505

506
	adhs->phyparamset.dsparamset.currentchan = assoc_req->channel;
507 508 509 510 511 512 513

	/* set IBSS param set */
#define IBSS_PARA_IE_ID   6
#define IBSS_PARA_IE_LEN  2

	adhs->ssparamset.ibssparamset.elementid = IBSS_PARA_IE_ID;
	adhs->ssparamset.ibssparamset.len = IBSS_PARA_IE_LEN;
514
	adhs->ssparamset.ibssparamset.atimwindow = cpu_to_le16(adapter->atimwindow);
515 516

	/* set capability info */
517
	tmpcap = WLAN_CAPABILITY_IBSS;
518
	if (assoc_req->secinfo.wep_enabled) {
519
		lbs_deb_join("ADHOC_S_CMD: WEP enabled, setting privacy on\n");
520
		tmpcap |= WLAN_CAPABILITY_PRIVACY;
521
	} else {
522
		lbs_deb_join("ADHOC_S_CMD: WEP disabled, setting privacy off\n");
523
	}
524 525 526
	adhs->capability = cpu_to_le16(tmpcap);

	/* probedelay */
527
	adhs->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547

	memset(adhs->datarate, 0, sizeof(adhs->datarate));

	if (adapter->adhoc_grate_enabled) {
		memcpy(adhs->datarate, libertas_adhoc_rates_g,
		       min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_g)));
	} else {
		memcpy(adhs->datarate, libertas_adhoc_rates_b,
		       min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_b)));
	}

	/* Find the last non zero */
	for (i = 0; i < sizeof(adhs->datarate) && adhs->datarate[i]; i++) ;

	adapter->curbssparams.numofrates = i;

	/* Copy the ad-hoc creating rates into Current BSS state structure */
	memcpy(&adapter->curbssparams.datarates,
	       &adhs->datarate, adapter->curbssparams.numofrates);

548
	lbs_deb_join("ADHOC_S_CMD: rates=%02x %02x %02x %02x \n",
549 550 551
	       adhs->datarate[0], adhs->datarate[1],
	       adhs->datarate[2], adhs->datarate[3]);

552
	lbs_deb_join("ADHOC_S_CMD: AD HOC Start command is ready\n");
553 554

	if (libertas_create_dnld_countryinfo_11d(priv)) {
555
		lbs_deb_join("ADHOC_S_CMD: dnld_countryinfo_11d failed\n");
556 557 558 559
		ret = -1;
		goto done;
	}

560 561
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_start) +
				S_DS_GEN + cmdappendsize);
562 563 564

	ret = 0;
done:
565
	lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
566 567 568 569 570 571
	return ret;
}

int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv,
				struct cmd_ds_command *cmd)
{
572
	cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_STOP);
573 574 575 576 577 578 579 580 581
	cmd->size = cpu_to_le16(S_DS_GEN);

	return 0;
}

int libertas_cmd_80211_ad_hoc_join(wlan_private * priv,
				struct cmd_ds_command *cmd, void *pdata_buf)
{
	wlan_adapter *adapter = priv->adapter;
582
	struct cmd_ds_802_11_ad_hoc_join *join_cmd = &cmd->params.adj;
583 584
	struct assoc_request * assoc_req = pdata_buf;
	struct bss_descriptor *bss = &assoc_req->bss;
585 586 587 588 589 590
	int cmdappendsize = 0;
	int ret = 0;
	u8 *card_rates;
	int card_rates_size;
	int i;

591
	lbs_deb_enter(LBS_DEB_JOIN);
592

593
	cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_JOIN);
594

595
	join_cmd->bss.type = CMD_BSS_TYPE_IBSS;
596
	join_cmd->bss.beaconperiod = cpu_to_le16(bss->beaconperiod);
597

598 599
	memcpy(&join_cmd->bss.bssid, &bss->bssid, ETH_ALEN);
	memcpy(&join_cmd->bss.ssid, &bss->ssid, bss->ssid_len);
600

601 602
	memcpy(&join_cmd->bss.phyparamset, &bss->phyparamset,
	       sizeof(union ieeetypes_phyparamset));
603

604 605
	memcpy(&join_cmd->bss.ssparamset, &bss->ssparamset,
	       sizeof(union IEEEtypes_ssparamset));
606

607
	join_cmd->bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK);
608
	lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
609
	       bss->capability, CAPINFO_MASK);
610 611

	/* information on BSSID descriptor passed to FW */
612 613
	lbs_deb_join(
	       "ADHOC_J_CMD: BSSID = " MAC_FMT ", SSID = '%s'\n",
614
	       MAC_ARG(join_cmd->bss.bssid), join_cmd->bss.ssid);
615 616

	/* failtimeout */
617
	join_cmd->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
618 619

	/* probedelay */
620
	join_cmd->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
621 622

	/* Copy Data rates from the rates recorded in scan response */
623 624 625
	memset(join_cmd->bss.datarates, 0, sizeof(join_cmd->bss.datarates));
	memcpy(join_cmd->bss.datarates, bss->datarates,
	       min(sizeof(join_cmd->bss.datarates), sizeof(bss->datarates)));
626 627 628 629

	card_rates = libertas_supported_rates;
	card_rates_size = sizeof(libertas_supported_rates);

630
	adapter->curbssparams.channel = bss->channel;
631

632 633
	if (get_common_rates(adapter, join_cmd->bss.datarates,
			     sizeof(join_cmd->bss.datarates),
634
			     card_rates, card_rates_size)) {
635
		lbs_deb_join("ADHOC_J_CMD: get_common_rates returns error.\n");
636 637 638 639 640
		ret = -1;
		goto done;
	}

	/* Find the last non zero */
641 642
	for (i = 0; i < sizeof(join_cmd->bss.datarates)
	     && join_cmd->bss.datarates[i]; i++) ;
643 644 645 646 647 648 649

	adapter->curbssparams.numofrates = i;

	/*
	 * Copy the adhoc joining rates to Current BSS State structure
	 */
	memcpy(adapter->curbssparams.datarates,
650
	       join_cmd->bss.datarates,
651 652
	       adapter->curbssparams.numofrates);

653
	join_cmd->bss.ssparamset.ibssparamset.atimwindow =
654
	    cpu_to_le16(bss->atimwindow);
655

656
	if (assoc_req->secinfo.wep_enabled) {
657 658 659
		u16 tmp = le16_to_cpu(join_cmd->bss.capability);
		tmp |= WLAN_CAPABILITY_PRIVACY;
		join_cmd->bss.capability = cpu_to_le16(tmp);
660 661
	}

662
	if (adapter->psmode == WLAN802_11POWERMODEMAX_PSP) {
663
		/* wake up first */
664
		__le32 Localpsmode;
665

666
		Localpsmode = cpu_to_le32(WLAN802_11POWERMODECAM);
667
		ret = libertas_prepare_and_send_command(priv,
668 669
					    CMD_802_11_PS_MODE,
					    CMD_ACT_SET,
670 671 672 673 674 675 676 677
					    0, 0, &Localpsmode);

		if (ret) {
			ret = -1;
			goto done;
		}
	}

678
	if (libertas_parse_dnld_countryinfo_11d(priv, bss)) {
679 680 681 682
		ret = -1;
		goto done;
	}

683 684
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_join) +
				S_DS_GEN + cmdappendsize);
685

686 687
done:
	lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
688 689 690 691 692 693 694 695 696 697
	return ret;
}

int libertas_ret_80211_associate(wlan_private * priv,
			      struct cmd_ds_command *resp)
{
	wlan_adapter *adapter = priv->adapter;
	int ret = 0;
	union iwreq_data wrqu;
	struct ieeetypes_assocrsp *passocrsp;
698
	struct bss_descriptor * bss;
699

700
	lbs_deb_enter(LBS_DEB_JOIN);
701

702 703 704 705 706 707 708
	if (!adapter->in_progress_assoc_req) {
		lbs_deb_join("ASSOC_RESP: no in-progress association request\n");
		ret = -1;
		goto done;
	}
	bss = &adapter->in_progress_assoc_req->bss;

709 710
	passocrsp = (struct ieeetypes_assocrsp *) & resp->params;

711
	if (le16_to_cpu(passocrsp->statuscode)) {
712 713
		libertas_mac_event_disconnected(priv);

714
		lbs_deb_join("ASSOC_RESP: Association failed, status code = %d\n",
715
			     le16_to_cpu(passocrsp->statuscode));
716 717 718 719 720 721 722 723 724

		ret = -1;
		goto done;
	}

	lbs_dbg_hex("ASSOC_RESP:", (void *)&resp->params,
		le16_to_cpu(resp->size) - S_DS_GEN);

	/* Send a Media Connected event, according to the Spec */
725
	adapter->connect_status = LIBERTAS_CONNECTED;
726

727 728
	lbs_deb_join("ASSOC_RESP: assocated to '%s'\n",
	             escape_essid(bss->ssid, bss->ssid_len));
729

730
	/* Update current SSID and BSSID */
731 732
	memcpy(&adapter->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
	adapter->curbssparams.ssid_len = bss->ssid_len;
733
	memcpy(adapter->curbssparams.bssid, bss->bssid, ETH_ALEN);
734

735
	lbs_deb_join("ASSOC_RESP: currentpacketfilter is %x\n",
736 737 738 739 740 741 742 743 744 745
	       adapter->currentpacketfilter);

	adapter->SNR[TYPE_RXPD][TYPE_AVG] = 0;
	adapter->NF[TYPE_RXPD][TYPE_AVG] = 0;

	memset(adapter->rawSNR, 0x00, sizeof(adapter->rawSNR));
	memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF));
	adapter->nextSNRNF = 0;
	adapter->numSNRNF = 0;

746 747
	netif_carrier_on(priv->dev);
	netif_wake_queue(priv->dev);
748

749 750 751
	netif_carrier_on(priv->mesh_dev);
	netif_wake_queue(priv->mesh_dev);

752
	lbs_deb_join("ASSOC_RESP: Associated \n");
753 754 755

	memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN);
	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
756
	wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
757

758 759
done:
	lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
760 761 762 763 764 765
	return ret;
}

int libertas_ret_80211_disassociate(wlan_private * priv,
				 struct cmd_ds_command *resp)
{
766
	lbs_deb_enter(LBS_DEB_JOIN);
767 768 769

	libertas_mac_event_disconnected(priv);

770
	lbs_deb_leave(LBS_DEB_JOIN);
771 772 773 774 775 776 777 778 779 780 781 782
	return 0;
}

int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
				 struct cmd_ds_command *resp)
{
	wlan_adapter *adapter = priv->adapter;
	int ret = 0;
	u16 command = le16_to_cpu(resp->command);
	u16 result = le16_to_cpu(resp->result);
	struct cmd_ds_802_11_ad_hoc_result *padhocresult;
	union iwreq_data wrqu;
783
	struct bss_descriptor *bss;
784

785
	lbs_deb_enter(LBS_DEB_JOIN);
786 787 788

	padhocresult = &resp->params.result;

789 790 791
	lbs_deb_join("ADHOC_RESP: size = %d\n", le16_to_cpu(resp->size));
	lbs_deb_join("ADHOC_RESP: command = %x\n", command);
	lbs_deb_join("ADHOC_RESP: result = %x\n", result);
792

793 794 795 796 797 798
	if (!adapter->in_progress_assoc_req) {
		lbs_deb_join("ADHOC_RESP: no in-progress association request\n");
		ret = -1;
		goto done;
	}
	bss = &adapter->in_progress_assoc_req->bss;
799 800 801 802 803

	/*
	 * Join result code 0 --> SUCCESS
	 */
	if (result) {
804
		lbs_deb_join("ADHOC_RESP: failed\n");
805
		if (adapter->connect_status == LIBERTAS_CONNECTED) {
806 807
			libertas_mac_event_disconnected(priv);
		}
808 809
		ret = -1;
		goto done;
810 811 812 813 814 815
	}

	/*
	 * Now the join cmd should be successful
	 * If BSSID has changed use SSID to compare instead of BSSID
	 */
816 817
	lbs_deb_join("ADHOC_RESP: associated to '%s'\n",
	             escape_essid(bss->ssid, bss->ssid_len));
818 819

	/* Send a Media Connected event, according to the Spec */
820
	adapter->connect_status = LIBERTAS_CONNECTED;
821

822
	if (command == CMD_RET_802_11_AD_HOC_START) {
823
		/* Update the created network descriptor with the new BSSID */
824
		memcpy(bss->bssid, padhocresult->bssid, ETH_ALEN);
825 826 827
	}

	/* Set the BSSID from the joined/started descriptor */
828
	memcpy(&adapter->curbssparams.bssid, bss->bssid, ETH_ALEN);
829 830

	/* Set the new SSID to current SSID */
831 832
	memcpy(&adapter->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
	adapter->curbssparams.ssid_len = bss->ssid_len;
833

834 835
	netif_carrier_on(priv->dev);
	netif_wake_queue(priv->dev);
836

837 838 839
	netif_carrier_on(priv->mesh_dev);
	netif_wake_queue(priv->mesh_dev);

840 841 842
	memset(&wrqu, 0, sizeof(wrqu));
	memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN);
	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
843
	wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
844

845
	lbs_deb_join("ADHOC_RESP: - Joined/Started Ad Hoc\n");
846
	lbs_deb_join("ADHOC_RESP: channel = %d\n", adapter->curbssparams.channel);
847
	lbs_deb_join("ADHOC_RESP: BSSID = " MAC_FMT "\n",
848
	       MAC_ARG(padhocresult->bssid));
849

850 851
done:
	lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
852 853 854 855 856 857
	return ret;
}

int libertas_ret_80211_ad_hoc_stop(wlan_private * priv,
				struct cmd_ds_command *resp)
{
858
	lbs_deb_enter(LBS_DEB_JOIN);
859 860 861

	libertas_mac_event_disconnected(priv);

862
	lbs_deb_leave(LBS_DEB_JOIN);
863 864
	return 0;
}