cmdresp.c 26.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/**
  * This file contains the handling of command
  * responses as well as events generated by firmware.
  */
#include <linux/delay.h>
#include <linux/if_arp.h>
#include <linux/netdevice.h>

#include <net/iw_handler.h>

#include "host.h"
#include "decl.h"
#include "defs.h"
#include "dev.h"
#include "join.h"
#include "wext.h"

/**
 *  @brief This function handles disconnect event. it
 *  reports disconnect to upper layer, clean tx/rx packets,
 *  reset link state etc.
 *
23
 *  @param priv    A pointer to struct lbs_private structure
24 25
 *  @return 	   n/a
 */
26
void lbs_mac_event_disconnected(struct lbs_private *priv)
27 28 29
{
	union iwreq_data wrqu;

30
	if (priv->connect_status != LBS_CONNECTED)
31 32
		return;

33
	lbs_deb_enter(LBS_DEB_ASSOC);
34 35 36 37 38 39 40 41 42 43

	memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
	wrqu.ap_addr.sa_family = ARPHRD_ETHER;

	/*
	 * Cisco AP sends EAP failure and de-auth in less than 0.5 ms.
	 * It causes problem in the Supplicant
	 */

	msleep_interruptible(1000);
44
	wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
45 46

	/* Free Tx and Rx packets */
47 48
	kfree_skb(priv->currenttxskb);
	priv->currenttxskb = NULL;
49 50

	/* report disconnect to upper layer */
51 52
	netif_stop_queue(priv->dev);
	netif_carrier_off(priv->dev);
53 54

	/* reset SNR/NF/RSSI values */
55 56 57 58 59 60 61 62
	memset(priv->SNR, 0x00, sizeof(priv->SNR));
	memset(priv->NF, 0x00, sizeof(priv->NF));
	memset(priv->RSSI, 0x00, sizeof(priv->RSSI));
	memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR));
	memset(priv->rawNF, 0x00, sizeof(priv->rawNF));
	priv->nextSNRNF = 0;
	priv->numSNRNF = 0;
	priv->connect_status = LBS_DISCONNECTED;
63

64 65 66
	/* Clear out associated SSID and BSSID since connection is
	 * no longer valid.
	 */
67 68 69
	memset(&priv->curbssparams.bssid, 0, ETH_ALEN);
	memset(&priv->curbssparams.ssid, 0, IW_ESSID_MAX_SIZE);
	priv->curbssparams.ssid_len = 0;
70

71
	if (priv->psstate != PS_STATE_FULL_POWER) {
72
		/* make firmware to exit PS mode */
73
		lbs_deb_cmd("disconnected, so exit PS mode\n");
74
		lbs_ps_wakeup(priv, 0);
75
	}
76
	lbs_deb_leave(LBS_DEB_CMD);
77 78 79 80 81
}

/**
 *  @brief This function handles MIC failure event.
 *
82
 *  @param priv    A pointer to struct lbs_private structure
83 84 85
 *  @para  event   the event id
 *  @return 	   n/a
 */
86
static void handle_mic_failureevent(struct lbs_private *priv, u32 event)
87 88 89
{
	char buf[50];

90
	lbs_deb_enter(LBS_DEB_CMD);
91 92 93 94 95 96 97 98 99 100
	memset(buf, 0, sizeof(buf));

	sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication ");

	if (event == MACREG_INT_CODE_MIC_ERR_UNICAST) {
		strcat(buf, "unicast ");
	} else {
		strcat(buf, "multicast ");
	}

101
	lbs_send_iwevcustom_event(priv, buf);
102
	lbs_deb_leave(LBS_DEB_CMD);
103 104
}

105
static int lbs_ret_reg_access(struct lbs_private *priv,
106 107
			       u16 type, struct cmd_ds_command *resp)
{
108
	int ret = 0;
109

110
	lbs_deb_enter(LBS_DEB_CMD);
111 112

	switch (type) {
113
	case CMD_RET(CMD_MAC_REG_ACCESS):
114
		{
115
			struct cmd_ds_mac_reg_access *reg = &resp->params.macreg;
116

117 118
			priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
			priv->offsetvalue.value = le32_to_cpu(reg->value);
119 120 121
			break;
		}

122
	case CMD_RET(CMD_BBP_REG_ACCESS):
123
		{
124
			struct cmd_ds_bbp_reg_access *reg = &resp->params.bbpreg;
125

126 127
			priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
			priv->offsetvalue.value = reg->value;
128 129 130
			break;
		}

131
	case CMD_RET(CMD_RF_REG_ACCESS):
132
		{
133
			struct cmd_ds_rf_reg_access *reg = &resp->params.rfreg;
134

135 136
			priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
			priv->offsetvalue.value = reg->value;
137 138 139 140
			break;
		}

	default:
141
		ret = -1;
142 143
	}

144
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
145
	return ret;
146 147
}

148
static int lbs_ret_get_hw_spec(struct lbs_private *priv,
149 150 151 152 153
				struct cmd_ds_command *resp)
{
	u32 i;
	struct cmd_ds_get_hw_spec *hwspec = &resp->params.hwspec;
	int ret = 0;
154
	DECLARE_MAC_BUF(mac);
155

156
	lbs_deb_enter(LBS_DEB_CMD);
157

158
	priv->fwcapinfo = le32_to_cpu(hwspec->fwcapinfo);
159

160
	memcpy(priv->fwreleasenumber, hwspec->fwreleasenumber, 4);
161

162
	lbs_deb_cmd("GET_HW_SPEC: firmware release %u.%u.%up%u\n",
163 164
		    priv->fwreleasenumber[2], priv->fwreleasenumber[1],
		    priv->fwreleasenumber[0], priv->fwreleasenumber[3]);
165 166
	lbs_deb_cmd("GET_HW_SPEC: MAC addr %s\n",
		    print_mac(mac, hwspec->permanentaddr));
167
	lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",
168 169
	       hwspec->hwifversion, hwspec->version);

170 171 172 173
	/* Clamp region code to 8-bit since FW spec indicates that it should
	 * only ever be 8-bit, even though the field size is 16-bit.  Some firmware
	 * returns non-zero high 8 bits here.
	 */
174
	priv->regioncode = le16_to_cpu(hwspec->regioncode) & 0xFF;
175 176 177

	for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
		/* use the region code to search for the index */
178
		if (priv->regioncode == lbs_region_code_to_index[i]) {
179 180 181 182 183 184
			break;
		}
	}

	/* if it's unidentified region code, use the default (USA) */
	if (i >= MRVDRV_MAX_REGION_CODE) {
185
		priv->regioncode = 0x10;
186
		lbs_pr_info("unidentified region code; using the default (USA)\n");
187 188
	}

189 190
	if (priv->current_addr[0] == 0xff)
		memmove(priv->current_addr, hwspec->permanentaddr, ETH_ALEN);
191

192
	memcpy(priv->dev->dev_addr, priv->current_addr, ETH_ALEN);
193
	if (priv->mesh_dev)
194
		memcpy(priv->mesh_dev->dev_addr, priv->current_addr, ETH_ALEN);
195

196
	if (lbs_set_regiontable(priv, priv->regioncode, 0)) {
197 198 199 200
		ret = -1;
		goto done;
	}

201
	if (lbs_set_universaltable(priv, 0)) {
202 203 204 205
		ret = -1;
		goto done;
	}

206 207
done:
	lbs_deb_enter_args(LBS_DEB_CMD, "ret %d", ret);
208 209 210
	return ret;
}

211
static int lbs_ret_802_11_sleep_params(struct lbs_private *priv,
212 213 214 215
					struct cmd_ds_command *resp)
{
	struct cmd_ds_802_11_sleep_params *sp = &resp->params.sleep_params;

216
	lbs_deb_enter(LBS_DEB_CMD);
217

218 219
	lbs_deb_cmd("error 0x%x, offset 0x%x, stabletime 0x%x, calcontrol 0x%x "
		    "extsleepclk 0x%x\n", le16_to_cpu(sp->error),
220 221 222
		    le16_to_cpu(sp->offset), le16_to_cpu(sp->stabletime),
		    sp->calcontrol, sp->externalsleepclk);

223 224 225 226 227 228
	priv->sp.sp_error = le16_to_cpu(sp->error);
	priv->sp.sp_offset = le16_to_cpu(sp->offset);
	priv->sp.sp_stabletime = le16_to_cpu(sp->stabletime);
	priv->sp.sp_calcontrol = sp->calcontrol;
	priv->sp.sp_extsleepclk = sp->externalsleepclk;
	priv->sp.sp_reserved = le16_to_cpu(sp->reserved);
229

230
	lbs_deb_enter(LBS_DEB_CMD);
231 232 233
	return 0;
}

234
static int lbs_ret_802_11_stat(struct lbs_private *priv,
235 236
				struct cmd_ds_command *resp)
{
237
	lbs_deb_enter(LBS_DEB_CMD);
238
/*	currently priv->wlan802_11Stat is unused
239 240 241 242

	struct cmd_ds_802_11_get_stat *p11Stat = &resp->params.gstat;

	// TODO Convert it to Big endian befor copy
243
	memcpy(&priv->wlan802_11Stat,
244 245
	       p11Stat, sizeof(struct cmd_ds_802_11_get_stat));
*/
246
	lbs_deb_leave(LBS_DEB_CMD);
247 248 249
	return 0;
}

250
static int lbs_ret_802_11_snmp_mib(struct lbs_private *priv,
251 252 253 254 255 256
				    struct cmd_ds_command *resp)
{
	struct cmd_ds_802_11_snmp_mib *smib = &resp->params.smib;
	u16 oid = le16_to_cpu(smib->oid);
	u16 querytype = le16_to_cpu(smib->querytype);

257
	lbs_deb_enter(LBS_DEB_CMD);
258

259
	lbs_deb_cmd("SNMP_RESP: oid 0x%x, querytype 0x%x\n", oid,
260
	       querytype);
261
	lbs_deb_cmd("SNMP_RESP: Buf size %d\n", le16_to_cpu(smib->bufsize));
262

263
	if (querytype == CMD_ACT_GET) {
264
		switch (oid) {
265
		case FRAGTHRESH_I:
266
			priv->fragthsd =
267
				le16_to_cpu(*((__le16 *)(smib->value)));
268
			lbs_deb_cmd("SNMP_RESP: frag threshold %u\n",
269
				    priv->fragthsd);
270
			break;
271
		case RTSTHRESH_I:
272
			priv->rtsthsd =
273
				le16_to_cpu(*((__le16 *)(smib->value)));
274
			lbs_deb_cmd("SNMP_RESP: rts threshold %u\n",
275
				    priv->rtsthsd);
276
			break;
277
		case SHORT_RETRYLIM_I:
278
			priv->txretrycount =
279
				le16_to_cpu(*((__le16 *)(smib->value)));
280
			lbs_deb_cmd("SNMP_RESP: tx retry count %u\n",
281
				    priv->rtsthsd);
282 283 284 285 286 287
			break;
		default:
			break;
		}
	}

288
	lbs_deb_enter(LBS_DEB_CMD);
289 290 291
	return 0;
}

292
static int lbs_ret_802_11_key_material(struct lbs_private *priv,
293 294 295 296 297 298
					struct cmd_ds_command *resp)
{
	struct cmd_ds_802_11_key_material *pkeymaterial =
	    &resp->params.keymaterial;
	u16 action = le16_to_cpu(pkeymaterial->action);

299
	lbs_deb_enter(LBS_DEB_CMD);
300 301

	/* Copy the returned key to driver private data */
302
	if (action == CMD_ACT_GET) {
303 304 305 306 307 308
		u8 * buf_ptr = (u8 *) &pkeymaterial->keyParamSet;
		u8 * resp_end = (u8 *) (resp + le16_to_cpu(resp->size));

		while (buf_ptr < resp_end) {
			struct MrvlIEtype_keyParamSet * pkeyparamset =
			    (struct MrvlIEtype_keyParamSet *) buf_ptr;
309
			struct enc_key * pkey;
310 311
			u16 param_set_len = le16_to_cpu(pkeyparamset->length);
			u16 key_len = le16_to_cpu(pkeyparamset->keylen);
312 313 314
			u16 key_flags = le16_to_cpu(pkeyparamset->keyinfo);
			u16 key_type = le16_to_cpu(pkeyparamset->keytypeid);
			u8 * end;
315 316 317 318 319 320 321 322

			end = (u8 *) pkeyparamset + sizeof (pkeyparamset->type)
			                          + sizeof (pkeyparamset->length)
			                          + param_set_len;
			/* Make sure we don't access past the end of the IEs */
			if (end > resp_end)
				break;

323
			if (key_flags & KEY_INFO_WPA_UNICAST)
324
				pkey = &priv->wpa_unicast_key;
325
			else if (key_flags & KEY_INFO_WPA_MCAST)
326
				pkey = &priv->wpa_mcast_key;
327 328 329 330
			else
				break;

			/* Copy returned key into driver */
331
			memset(pkey, 0, sizeof(struct enc_key));
332 333
			if (key_len > sizeof(pkey->key))
				break;
334 335 336
			pkey->type = key_type;
			pkey->flags = key_flags;
			pkey->len = key_len;
337 338 339 340 341 342
			memcpy(pkey->key, pkeyparamset->key, pkey->len);

			buf_ptr = end + 1;
		}
	}

343
	lbs_deb_enter(LBS_DEB_CMD);
344 345 346
	return 0;
}

347
static int lbs_ret_802_11_mac_address(struct lbs_private *priv,
348 349 350 351
				       struct cmd_ds_command *resp)
{
	struct cmd_ds_802_11_mac_address *macadd = &resp->params.macadd;

352
	lbs_deb_enter(LBS_DEB_CMD);
353

354
	memcpy(priv->current_addr, macadd->macadd, ETH_ALEN);
355

356
	lbs_deb_enter(LBS_DEB_CMD);
357 358 359
	return 0;
}

360
static int lbs_ret_802_11_rf_tx_power(struct lbs_private *priv,
361 362 363 364
				       struct cmd_ds_command *resp)
{
	struct cmd_ds_802_11_rf_tx_power *rtp = &resp->params.txp;

365
	lbs_deb_enter(LBS_DEB_CMD);
366

367
	priv->txpowerlevel = le16_to_cpu(rtp->currentlevel);
368

369
	lbs_deb_cmd("TX power currently %d\n", priv->txpowerlevel);
370

371
	lbs_deb_leave(LBS_DEB_CMD);
372 373 374
	return 0;
}

375
static int lbs_ret_802_11_rate_adapt_rateset(struct lbs_private *priv,
376 377
					      struct cmd_ds_command *resp)
{
378
	struct cmd_ds_802_11_rate_adapt_rateset *rates = &resp->params.rateset;
379

380
	lbs_deb_enter(LBS_DEB_CMD);
381

382
	if (rates->action == CMD_ACT_GET) {
383 384
		priv->enablehwauto = le16_to_cpu(rates->enablehwauto);
		priv->ratebitmap = le16_to_cpu(rates->bitmap);
385 386
	}

387
	lbs_deb_leave(LBS_DEB_CMD);
388 389 390
	return 0;
}

391
static int lbs_ret_802_11_data_rate(struct lbs_private *priv,
392 393 394 395
				     struct cmd_ds_command *resp)
{
	struct cmd_ds_802_11_data_rate *pdatarate = &resp->params.drate;

396
	lbs_deb_enter(LBS_DEB_CMD);
397

398
	lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) pdatarate,
399
		sizeof(struct cmd_ds_802_11_data_rate));
400

401 402 403
	/* FIXME: get actual rates FW can do if this command actually returns
	 * all data rates supported.
	 */
404 405
	priv->cur_rate = lbs_fw_index_to_data_rate(pdatarate->rates[0]);
	lbs_deb_cmd("DATA_RATE: current rate 0x%02x\n", priv->cur_rate);
406

407
	lbs_deb_leave(LBS_DEB_CMD);
408 409 410
	return 0;
}

411
static int lbs_ret_802_11_rf_channel(struct lbs_private *priv,
412 413
				      struct cmd_ds_command *resp)
{
414
	struct cmd_ds_802_11_rf_channel *rfchannel = &resp->params.rfchannel;
415 416 417
	u16 action = le16_to_cpu(rfchannel->action);
	u16 newchannel = le16_to_cpu(rfchannel->currentchannel);

418
	lbs_deb_enter(LBS_DEB_CMD);
419

420
	if (action == CMD_OPT_802_11_RF_CHANNEL_GET
421
	    && priv->curbssparams.channel != newchannel) {
422
		lbs_deb_cmd("channel switch from %d to %d\n",
423
		       priv->curbssparams.channel, newchannel);
424 425

		/* Update the channel again */
426
		priv->curbssparams.channel = newchannel;
427 428
	}

429
	lbs_deb_enter(LBS_DEB_CMD);
430 431 432
	return 0;
}

433
static int lbs_ret_802_11_rssi(struct lbs_private *priv,
434 435 436 437
				struct cmd_ds_command *resp)
{
	struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp;

438 439
	lbs_deb_enter(LBS_DEB_CMD);

440
	/* store the non average value */
441 442
	priv->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR);
	priv->NF[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->noisefloor);
443

444 445
	priv->SNR[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgSNR);
	priv->NF[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgnoisefloor);
446

447 448 449
	priv->RSSI[TYPE_BEACON][TYPE_NOAVG] =
	    CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],
		     priv->NF[TYPE_BEACON][TYPE_NOAVG]);
450

451 452 453
	priv->RSSI[TYPE_BEACON][TYPE_AVG] =
	    CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
		     priv->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
454

455
	lbs_deb_cmd("RSSI: beacon %d, avg %d\n",
456 457
	       priv->RSSI[TYPE_BEACON][TYPE_NOAVG],
	       priv->RSSI[TYPE_BEACON][TYPE_AVG]);
458

459
	lbs_deb_leave(LBS_DEB_CMD);
460 461 462
	return 0;
}

463
static int lbs_ret_802_11_eeprom_access(struct lbs_private *priv,
464 465
				  struct cmd_ds_command *resp)
{
466
	struct lbs_ioctl_regrdwr *pbuf;
467
	pbuf = (struct lbs_ioctl_regrdwr *) priv->prdeeprom;
468

469
	lbs_deb_enter_args(LBS_DEB_CMD, "len %d",
470 471 472
	       le16_to_cpu(resp->params.rdeeprom.bytecount));
	if (pbuf->NOB < le16_to_cpu(resp->params.rdeeprom.bytecount)) {
		pbuf->NOB = 0;
473
		lbs_deb_cmd("EEPROM read length too big\n");
474 475 476 477 478 479 480
		return -1;
	}
	pbuf->NOB = le16_to_cpu(resp->params.rdeeprom.bytecount);
	if (pbuf->NOB > 0) {

		memcpy(&pbuf->value, (u8 *) & resp->params.rdeeprom.value,
		       le16_to_cpu(resp->params.rdeeprom.bytecount));
481
		lbs_deb_hex(LBS_DEB_CMD, "EEPROM", (char *)&pbuf->value,
482 483
			le16_to_cpu(resp->params.rdeeprom.bytecount));
	}
484
	lbs_deb_leave(LBS_DEB_CMD);
485 486 487
	return 0;
}

488
static int lbs_ret_get_log(struct lbs_private *priv,
489 490
			    struct cmd_ds_command *resp)
{
491
	struct cmd_ds_802_11_get_log *logmessage = &resp->params.glog;
492

493
	lbs_deb_enter(LBS_DEB_CMD);
494

495
	/* Stored little-endian */
496
	memcpy(&priv->logmsg, logmessage, sizeof(struct cmd_ds_802_11_get_log));
497

498
	lbs_deb_leave(LBS_DEB_CMD);
499 500 501
	return 0;
}

502
static int lbs_ret_802_11_enable_rsn(struct lbs_private *priv,
503 504 505
                                          struct cmd_ds_command *resp)
{
	struct cmd_ds_802_11_enable_rsn *enable_rsn = &resp->params.enbrsn;
506
	u32 * pdata_buf = priv->cur_cmd->pdata_buf;
507 508 509

	lbs_deb_enter(LBS_DEB_CMD);

510
	if (enable_rsn->action == cpu_to_le16(CMD_ACT_GET)) {
511 512 513 514
		if (pdata_buf)
			*pdata_buf = (u32) le16_to_cpu(enable_rsn->enable);
	}

515
	lbs_deb_leave(LBS_DEB_CMD);
516 517 518
	return 0;
}

519 520 521 522 523 524 525 526 527
static int lbs_ret_802_11_bcn_ctrl(struct lbs_private * priv,
					struct cmd_ds_command *resp)
{
	struct cmd_ds_802_11_beacon_control *bcn_ctrl =
	    &resp->params.bcn_ctrl;

	lbs_deb_enter(LBS_DEB_CMD);

	if (bcn_ctrl->action == CMD_ACT_GET) {
528 529
		priv->beacon_enable = (u8) le16_to_cpu(bcn_ctrl->beacon_enable);
		priv->beacon_period = le16_to_cpu(bcn_ctrl->beacon_period);
530 531 532 533 534 535
	}

	lbs_deb_enter(LBS_DEB_CMD);
	return 0;
}

536 537 538 539 540 541
static int lbs_ret_802_11_subscribe_event(struct lbs_private *priv,
	struct cmd_ds_command *resp)
{
	struct cmd_ds_802_11_subscribe_event *cmd_event =
		&resp->params.subscribe_event;
	struct cmd_ds_802_11_subscribe_event *dst_event =
542
		priv->cur_cmd->pdata_buf;
543 544 545 546

	lbs_deb_enter(LBS_DEB_CMD);

	if (dst_event->action == cpu_to_le16(CMD_ACT_GET)) {
H
Holger Schurig 已提交
547
		dst_event->events = cmd_event->events;
548 549 550 551 552 553 554
		memcpy(dst_event->tlv, cmd_event->tlv, sizeof(dst_event->tlv));
	}

	lbs_deb_leave(LBS_DEB_CMD);
	return 0;
}

555 556
static inline int handle_cmd_response(u16 respcmd,
				      struct cmd_ds_command *resp,
557
				      struct lbs_private *priv)
558 559 560 561
{
	int ret = 0;
	unsigned long flags;

562 563
	lbs_deb_enter(LBS_DEB_HOST);

564
	switch (respcmd) {
565 566 567
	case CMD_RET(CMD_MAC_REG_ACCESS):
	case CMD_RET(CMD_BBP_REG_ACCESS):
	case CMD_RET(CMD_RF_REG_ACCESS):
568
		ret = lbs_ret_reg_access(priv, respcmd, resp);
569 570
		break;

571
	case CMD_RET(CMD_GET_HW_SPEC):
572
		ret = lbs_ret_get_hw_spec(priv, resp);
573 574
		break;

575
	case CMD_RET(CMD_802_11_SCAN):
576
		ret = lbs_ret_80211_scan(priv, resp);
577 578
		break;

579
	case CMD_RET(CMD_802_11_GET_LOG):
580
		ret = lbs_ret_get_log(priv, resp);
581 582
		break;

583
	case CMD_RET_802_11_ASSOCIATE:
584 585
	case CMD_RET(CMD_802_11_ASSOCIATE):
	case CMD_RET(CMD_802_11_REASSOCIATE):
586
		ret = lbs_ret_80211_associate(priv, resp);
587 588
		break;

589 590
	case CMD_RET(CMD_802_11_DISASSOCIATE):
	case CMD_RET(CMD_802_11_DEAUTHENTICATE):
591
		ret = lbs_ret_80211_disassociate(priv, resp);
592 593
		break;

594 595
	case CMD_RET(CMD_802_11_AD_HOC_START):
	case CMD_RET(CMD_802_11_AD_HOC_JOIN):
596
		ret = lbs_ret_80211_ad_hoc_start(priv, resp);
597 598
		break;

599
	case CMD_RET(CMD_802_11_GET_STAT):
600
		ret = lbs_ret_802_11_stat(priv, resp);
601 602
		break;

603
	case CMD_RET(CMD_802_11_SNMP_MIB):
604
		ret = lbs_ret_802_11_snmp_mib(priv, resp);
605 606
		break;

607
	case CMD_RET(CMD_802_11_RF_TX_POWER):
608
		ret = lbs_ret_802_11_rf_tx_power(priv, resp);
609 610
		break;

611 612
	case CMD_RET(CMD_802_11_SET_AFC):
	case CMD_RET(CMD_802_11_GET_AFC):
613 614
		spin_lock_irqsave(&priv->driver_lock, flags);
		memmove(priv->cur_cmd->pdata_buf, &resp->params.afc,
615
			sizeof(struct cmd_ds_802_11_afc));
616
		spin_unlock_irqrestore(&priv->driver_lock, flags);
617 618 619

		break;

620 621 622 623 624 625 626
	case CMD_RET(CMD_MAC_MULTICAST_ADR):
	case CMD_RET(CMD_MAC_CONTROL):
	case CMD_RET(CMD_802_11_SET_WEP):
	case CMD_RET(CMD_802_11_RESET):
	case CMD_RET(CMD_802_11_AUTHENTICATE):
	case CMD_RET(CMD_802_11_RADIO_CONTROL):
	case CMD_RET(CMD_802_11_BEACON_STOP):
627 628
		break;

629
	case CMD_RET(CMD_802_11_ENABLE_RSN):
630
		ret = lbs_ret_802_11_enable_rsn(priv, resp);
631 632
		break;

633
	case CMD_RET(CMD_802_11_DATA_RATE):
634
		ret = lbs_ret_802_11_data_rate(priv, resp);
635
		break;
636
	case CMD_RET(CMD_802_11_RATE_ADAPT_RATESET):
637
		ret = lbs_ret_802_11_rate_adapt_rateset(priv, resp);
638
		break;
639
	case CMD_RET(CMD_802_11_RF_CHANNEL):
640
		ret = lbs_ret_802_11_rf_channel(priv, resp);
641 642
		break;

643
	case CMD_RET(CMD_802_11_RSSI):
644
		ret = lbs_ret_802_11_rssi(priv, resp);
645 646
		break;

647
	case CMD_RET(CMD_802_11_MAC_ADDRESS):
648
		ret = lbs_ret_802_11_mac_address(priv, resp);
649 650
		break;

651
	case CMD_RET(CMD_802_11_AD_HOC_STOP):
652
		ret = lbs_ret_80211_ad_hoc_stop(priv, resp);
653 654
		break;

655
	case CMD_RET(CMD_802_11_KEY_MATERIAL):
656
		ret = lbs_ret_802_11_key_material(priv, resp);
657 658
		break;

659
	case CMD_RET(CMD_802_11_EEPROM_ACCESS):
660
		ret = lbs_ret_802_11_eeprom_access(priv, resp);
661 662
		break;

663
	case CMD_RET(CMD_802_11D_DOMAIN_INFO):
664
		ret = lbs_ret_802_11d_domain_info(priv, resp);
665 666
		break;

667
	case CMD_RET(CMD_802_11_SLEEP_PARAMS):
668
		ret = lbs_ret_802_11_sleep_params(priv, resp);
669
		break;
670
	case CMD_RET(CMD_802_11_INACTIVITY_TIMEOUT):
671 672
		spin_lock_irqsave(&priv->driver_lock, flags);
		*((u16 *) priv->cur_cmd->pdata_buf) =
673
		    le16_to_cpu(resp->params.inactivity_timeout.timeout);
674
		spin_unlock_irqrestore(&priv->driver_lock, flags);
675 676
		break;

677
	case CMD_RET(CMD_802_11_TPC_CFG):
678 679
		spin_lock_irqsave(&priv->driver_lock, flags);
		memmove(priv->cur_cmd->pdata_buf, &resp->params.tpccfg,
680
			sizeof(struct cmd_ds_802_11_tpc_cfg));
681
		spin_unlock_irqrestore(&priv->driver_lock, flags);
682
		break;
683
	case CMD_RET(CMD_802_11_LED_GPIO_CTRL):
684 685
		spin_lock_irqsave(&priv->driver_lock, flags);
		memmove(priv->cur_cmd->pdata_buf, &resp->params.ledgpio,
686
			sizeof(struct cmd_ds_802_11_led_ctrl));
687
		spin_unlock_irqrestore(&priv->driver_lock, flags);
688
		break;
689 690 691 692
	case CMD_RET(CMD_802_11_SUBSCRIBE_EVENT):
		ret = lbs_ret_802_11_subscribe_event(priv, resp);
		break;

693
	case CMD_RET(CMD_802_11_PWR_CFG):
694 695
		spin_lock_irqsave(&priv->driver_lock, flags);
		memmove(priv->cur_cmd->pdata_buf, &resp->params.pwrcfg,
696
			sizeof(struct cmd_ds_802_11_pwr_cfg));
697
		spin_unlock_irqrestore(&priv->driver_lock, flags);
698 699 700

		break;

701
	case CMD_RET(CMD_GET_TSF):
702 703
		spin_lock_irqsave(&priv->driver_lock, flags);
		memcpy(priv->cur_cmd->pdata_buf,
704
		       &resp->params.gettsf.tsfvalue, sizeof(u64));
705
		spin_unlock_irqrestore(&priv->driver_lock, flags);
706
		break;
707
	case CMD_RET(CMD_BT_ACCESS):
708 709 710
		spin_lock_irqsave(&priv->driver_lock, flags);
		if (priv->cur_cmd->pdata_buf)
			memcpy(priv->cur_cmd->pdata_buf,
711
			       &resp->params.bt.addr1, 2 * ETH_ALEN);
712
		spin_unlock_irqrestore(&priv->driver_lock, flags);
713
		break;
714
	case CMD_RET(CMD_FWT_ACCESS):
715 716 717
		spin_lock_irqsave(&priv->driver_lock, flags);
		if (priv->cur_cmd->pdata_buf)
			memcpy(priv->cur_cmd->pdata_buf, &resp->params.fwt,
718
			       sizeof(resp->params.fwt));
719
		spin_unlock_irqrestore(&priv->driver_lock, flags);
720
		break;
721
	case CMD_RET(CMD_MESH_ACCESS):
722 723
		if (priv->cur_cmd->pdata_buf)
			memcpy(priv->cur_cmd->pdata_buf, &resp->params.mesh,
724 725
			       sizeof(resp->params.mesh));
		break;
726 727 728 729
	case CMD_RET(CMD_802_11_BEACON_CTRL):
		ret = lbs_ret_802_11_bcn_ctrl(priv, resp);
		break;

730
	default:
731
		lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n",
732
			    resp->command);
733 734
		break;
	}
735
	lbs_deb_leave(LBS_DEB_HOST);
736 737 738
	return ret;
}

739
int lbs_process_rx_command(struct lbs_private *priv)
740 741 742 743 744 745 746
{
	u16 respcmd;
	struct cmd_ds_command *resp;
	int ret = 0;
	ulong flags;
	u16 result;

747
	lbs_deb_enter(LBS_DEB_HOST);
748 749

	/* Now we got response from FW, cancel the command timer */
750
	del_timer(&priv->command_timer);
751

752 753
	mutex_lock(&priv->lock);
	spin_lock_irqsave(&priv->driver_lock, flags);
754

755
	if (!priv->cur_cmd) {
756
		lbs_deb_host("CMD_RESP: cur_cmd is NULL\n");
757
		ret = -1;
758
		spin_unlock_irqrestore(&priv->driver_lock, flags);
759 760
		goto done;
	}
761
	resp = (struct cmd_ds_command *)(priv->cur_cmd->bufvirtualaddr);
762 763 764 765

	respcmd = le16_to_cpu(resp->command);
	result = le16_to_cpu(resp->result);

766 767
	lbs_deb_host("CMD_RESP: response 0x%04x, size %d, jiffies %lu\n",
		respcmd, priv->upld_len, jiffies);
768
	lbs_deb_hex(LBS_DEB_HOST, "CMD_RESP", priv->cur_cmd->bufvirtualaddr,
769
		    priv->upld_len);
770 771

	if (!(respcmd & 0x8000)) {
772
		lbs_deb_host("invalid response!\n");
773 774 775 776
		priv->cur_cmd_retcode = -1;
		__lbs_cleanup_and_insert_cmd(priv, priv->cur_cmd);
		priv->cur_cmd = NULL;
		spin_unlock_irqrestore(&priv->driver_lock, flags);
777 778 779 780 781
		ret = -1;
		goto done;
	}

	/* Store the response code to cur_cmd_retcode. */
782
	priv->cur_cmd_retcode = result;
783

784
	if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) {
785 786
		struct cmd_ds_802_11_ps_mode *psmode = &resp->params.psmode;
		u16 action = le16_to_cpu(psmode->action);
787

788 789
		lbs_deb_host(
		       "CMD_RESP: PS_MODE cmd reply result 0x%x, action 0x%x\n",
790
		       result, action);
791 792

		if (result) {
793
			lbs_deb_host("CMD_RESP: PS command failed with 0x%x\n",
794 795 796 797
				    result);
			/*
			 * We should not re-try enter-ps command in
			 * ad-hoc mode. It takes place in
798
			 * lbs_execute_next_command().
799
			 */
800
			if (priv->mode == IW_MODE_ADHOC &&
801
			    action == CMD_SUBCMD_ENTER_PS)
802
				priv->psmode = LBS802_11POWERMODECAM;
803
		} else if (action == CMD_SUBCMD_ENTER_PS) {
804 805
			priv->needtowakeup = 0;
			priv->psstate = PS_STATE_AWAKE;
806

807
			lbs_deb_host("CMD_RESP: ENTER_PS command response\n");
808
			if (priv->connect_status != LBS_CONNECTED) {
809 810 811 812
				/*
				 * When Deauth Event received before Enter_PS command
				 * response, We need to wake up the firmware.
				 */
813
				lbs_deb_host(
814
				       "disconnected, invoking lbs_ps_wakeup\n");
815

816 817
				spin_unlock_irqrestore(&priv->driver_lock, flags);
				mutex_unlock(&priv->lock);
818
				lbs_ps_wakeup(priv, 0);
819 820
				mutex_lock(&priv->lock);
				spin_lock_irqsave(&priv->driver_lock, flags);
821
			}
822
		} else if (action == CMD_SUBCMD_EXIT_PS) {
823 824
			priv->needtowakeup = 0;
			priv->psstate = PS_STATE_FULL_POWER;
825
			lbs_deb_host("CMD_RESP: EXIT_PS command response\n");
826
		} else {
827
			lbs_deb_host("CMD_RESP: PS action 0x%X\n", action);
828 829
		}

830 831 832
		__lbs_cleanup_and_insert_cmd(priv, priv->cur_cmd);
		priv->cur_cmd = NULL;
		spin_unlock_irqrestore(&priv->driver_lock, flags);
833 834 835 836 837 838 839

		ret = 0;
		goto done;
	}

	/* If the command is not successful, cleanup and return failure */
	if ((result != 0 || !(respcmd & 0x8000))) {
840 841
		lbs_deb_host("CMD_RESP: error 0x%04x in command reply 0x%04x\n",
		       result, respcmd);
842 843 844 845
		/*
		 * Handling errors here
		 */
		switch (respcmd) {
846 847
		case CMD_RET(CMD_GET_HW_SPEC):
		case CMD_RET(CMD_802_11_RESET):
848
			lbs_deb_host("CMD_RESP: reset failed\n");
849 850 851 852
			break;

		}

853 854 855
		__lbs_cleanup_and_insert_cmd(priv, priv->cur_cmd);
		priv->cur_cmd = NULL;
		spin_unlock_irqrestore(&priv->driver_lock, flags);
856 857 858 859 860

		ret = -1;
		goto done;
	}

861
	spin_unlock_irqrestore(&priv->driver_lock, flags);
862

863 864
	if (priv->cur_cmd && priv->cur_cmd->callback)
		ret = priv->cur_cmd->callback(respcmd, resp, priv);
865
	else
866
		ret = handle_cmd_response(respcmd, resp, priv);
867

868
	spin_lock_irqsave(&priv->driver_lock, flags);
869

870
	if (priv->cur_cmd) {
871
		/* Clean up and Put current command back to cmdfreeq */
872 873
		__lbs_cleanup_and_insert_cmd(priv, priv->cur_cmd);
		priv->cur_cmd = NULL;
874
	}
875
	spin_unlock_irqrestore(&priv->driver_lock, flags);
876 877

done:
878
	mutex_unlock(&priv->lock);
879
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
880 881 882
	return ret;
}

883
int lbs_process_event(struct lbs_private *priv)
884 885 886 887
{
	int ret = 0;
	u32 eventcause;

888 889
	lbs_deb_enter(LBS_DEB_CMD);

890 891 892
	spin_lock_irq(&priv->driver_lock);
	eventcause = priv->eventcause >> SBI_EVENT_CAUSE_SHIFT;
	spin_unlock_irq(&priv->driver_lock);
893

894
	lbs_deb_cmd("event cause %d\n", eventcause);
895

896
	switch (eventcause) {
897
	case MACREG_INT_CODE_LINK_SENSED:
898
		lbs_deb_cmd("EVENT: MACREG_INT_CODE_LINK_SENSED\n");
899 900 901
		break;

	case MACREG_INT_CODE_DEAUTHENTICATED:
902
		lbs_deb_cmd("EVENT: deauthenticated\n");
903
		lbs_mac_event_disconnected(priv);
904 905 906
		break;

	case MACREG_INT_CODE_DISASSOCIATED:
907
		lbs_deb_cmd("EVENT: disassociated\n");
908
		lbs_mac_event_disconnected(priv);
909 910
		break;

911
	case MACREG_INT_CODE_LINK_LOST_NO_SCAN:
912
		lbs_deb_cmd("EVENT: link lost\n");
913
		lbs_mac_event_disconnected(priv);
914 915 916
		break;

	case MACREG_INT_CODE_PS_SLEEP:
917
		lbs_deb_cmd("EVENT: sleep\n");
918 919

		/* handle unexpected PS SLEEP event */
920
		if (priv->psstate == PS_STATE_FULL_POWER) {
921
			lbs_deb_cmd(
922
			       "EVENT: in FULL POWER mode, ignoreing PS_SLEEP\n");
923 924
			break;
		}
925
		priv->psstate = PS_STATE_PRE_SLEEP;
926

927
		lbs_ps_confirm_sleep(priv, (u16) priv->psmode);
928 929 930 931

		break;

	case MACREG_INT_CODE_PS_AWAKE:
932
		lbs_deb_cmd("EVENT: awake\n");
933 934

		/* handle unexpected PS AWAKE event */
935
		if (priv->psstate == PS_STATE_FULL_POWER) {
936
			lbs_deb_cmd(
937 938 939 940
			       "EVENT: In FULL POWER mode - ignore PS AWAKE\n");
			break;
		}

941
		priv->psstate = PS_STATE_AWAKE;
942

943
		if (priv->needtowakeup) {
944 945 946
			/*
			 * wait for the command processing to finish
			 * before resuming sending
947
			 * priv->needtowakeup will be set to FALSE
948
			 * in lbs_ps_wakeup()
949
			 */
950
			lbs_deb_cmd("waking up ...\n");
951
			lbs_ps_wakeup(priv, 0);
952 953 954 955
		}
		break;

	case MACREG_INT_CODE_MIC_ERR_UNICAST:
956
		lbs_deb_cmd("EVENT: UNICAST MIC ERROR\n");
957 958 959 960
		handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_UNICAST);
		break;

	case MACREG_INT_CODE_MIC_ERR_MULTICAST:
961
		lbs_deb_cmd("EVENT: MULTICAST MIC ERROR\n");
962 963 964 965 966 967 968
		handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_MULTICAST);
		break;
	case MACREG_INT_CODE_MIB_CHANGED:
	case MACREG_INT_CODE_INIT_DONE:
		break;

	case MACREG_INT_CODE_ADHOC_BCN_LOST:
969
		lbs_deb_cmd("EVENT: ADHOC beacon lost\n");
970 971 972
		break;

	case MACREG_INT_CODE_RSSI_LOW:
973
		lbs_pr_alert("EVENT: rssi low\n");
974 975
		break;
	case MACREG_INT_CODE_SNR_LOW:
976
		lbs_pr_alert("EVENT: snr low\n");
977 978
		break;
	case MACREG_INT_CODE_MAX_FAIL:
979
		lbs_pr_alert("EVENT: max fail\n");
980 981
		break;
	case MACREG_INT_CODE_RSSI_HIGH:
982
		lbs_pr_alert("EVENT: rssi high\n");
983 984
		break;
	case MACREG_INT_CODE_SNR_HIGH:
985
		lbs_pr_alert("EVENT: snr high\n");
986 987
		break;

988
	case MACREG_INT_CODE_MESH_AUTO_STARTED:
989 990 991 992 993
		/* Ignore spurious autostart events if autostart is disabled */
		if (!priv->mesh_autostart_enabled) {
			lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n");
			break;
		}
994
		lbs_pr_info("EVENT: MESH_AUTO_STARTED\n");
995
		priv->mesh_connect_status = LBS_CONNECTED;
996
		if (priv->mesh_open == 1) {
997 998
			netif_wake_queue(priv->mesh_dev);
			netif_carrier_on(priv->mesh_dev);
999
		}
1000
		priv->mode = IW_MODE_ADHOC;
1001
		schedule_work(&priv->sync_channel);
1002 1003
		break;

1004
	default:
1005
		lbs_pr_alert("EVENT: unknown event id %d\n", eventcause);
1006 1007 1008
		break;
	}

1009 1010 1011
	spin_lock_irq(&priv->driver_lock);
	priv->eventcause = 0;
	spin_unlock_irq(&priv->driver_lock);
1012

1013
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
1014 1015
	return ret;
}