cmdresp.c 28.5 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
	struct lbs_adapter *adapter = priv->adapter;
29 30
	union iwreq_data wrqu;

31
	if (adapter->connect_status != LBS_CONNECTED)
32 33
		return;

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

	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);
45
	wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
46 47 48 49 50 51

	/* Free Tx and Rx packets */
	kfree_skb(priv->adapter->currenttxskb);
	priv->adapter->currenttxskb = NULL;

	/* report disconnect to upper layer */
52 53
	netif_stop_queue(priv->dev);
	netif_carrier_off(priv->dev);
54 55 56 57 58 59 60 61 62

	/* reset SNR/NF/RSSI values */
	memset(adapter->SNR, 0x00, sizeof(adapter->SNR));
	memset(adapter->NF, 0x00, sizeof(adapter->NF));
	memset(adapter->RSSI, 0x00, sizeof(adapter->RSSI));
	memset(adapter->rawSNR, 0x00, sizeof(adapter->rawSNR));
	memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF));
	adapter->nextSNRNF = 0;
	adapter->numSNRNF = 0;
63
	adapter->connect_status = LBS_DISCONNECTED;
64

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

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

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

91
	lbs_deb_enter(LBS_DEB_CMD);
92 93 94 95 96 97 98 99 100 101
	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 ");
	}

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

106
static int lbs_ret_reg_access(struct lbs_private *priv,
107 108
			       u16 type, struct cmd_ds_command *resp)
{
109
	int ret = 0;
110
	struct lbs_adapter *adapter = priv->adapter;
111

112
	lbs_deb_enter(LBS_DEB_CMD);
113 114

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

119 120
			adapter->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
			adapter->offsetvalue.value = le32_to_cpu(reg->value);
121 122 123
			break;
		}

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

128
			adapter->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
129 130 131 132
			adapter->offsetvalue.value = reg->value;
			break;
		}

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

137
			adapter->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
138 139 140 141 142
			adapter->offsetvalue.value = reg->value;
			break;
		}

	default:
143
		ret = -1;
144 145
	}

146
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
147
	return ret;
148 149
}

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

159
	lbs_deb_enter(LBS_DEB_CMD);
160 161 162

	adapter->fwcapinfo = le32_to_cpu(hwspec->fwcapinfo);

163
	memcpy(adapter->fwreleasenumber, hwspec->fwreleasenumber, 4);
164

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

173 174 175 176 177
	/* 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.
	 */
	adapter->regioncode = le16_to_cpu(hwspec->regioncode) & 0xFF;
178 179 180

	for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
		/* use the region code to search for the index */
181
		if (adapter->regioncode == lbs_region_code_to_index[i]) {
182 183 184 185 186 187 188
			break;
		}
	}

	/* if it's unidentified region code, use the default (USA) */
	if (i >= MRVDRV_MAX_REGION_CODE) {
		adapter->regioncode = 0x10;
189
		lbs_pr_info("unidentified region code; using the default (USA)\n");
190 191
	}

192 193
	if (adapter->current_addr[0] == 0xff)
		memmove(adapter->current_addr, hwspec->permanentaddr, ETH_ALEN);
194

195
	memcpy(priv->dev->dev_addr, adapter->current_addr, ETH_ALEN);
196
	if (priv->mesh_dev)
197
		memcpy(priv->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN);
198

199
	if (lbs_set_regiontable(priv, adapter->regioncode, 0)) {
200 201 202 203
		ret = -1;
		goto done;
	}

204
	if (lbs_set_universaltable(priv, 0)) {
205 206 207 208
		ret = -1;
		goto done;
	}

209 210
done:
	lbs_deb_enter_args(LBS_DEB_CMD, "ret %d", ret);
211 212 213
	return ret;
}

214
static int lbs_ret_802_11_sleep_params(struct lbs_private *priv,
215 216 217
					struct cmd_ds_command *resp)
{
	struct cmd_ds_802_11_sleep_params *sp = &resp->params.sleep_params;
218
	struct lbs_adapter *adapter = priv->adapter;
219

220
	lbs_deb_enter(LBS_DEB_CMD);
221

222 223
	lbs_deb_cmd("error 0x%x, offset 0x%x, stabletime 0x%x, calcontrol 0x%x "
		    "extsleepclk 0x%x\n", le16_to_cpu(sp->error),
224 225 226
		    le16_to_cpu(sp->offset), le16_to_cpu(sp->stabletime),
		    sp->calcontrol, sp->externalsleepclk);

227 228 229
	adapter->sp.sp_error = le16_to_cpu(sp->error);
	adapter->sp.sp_offset = le16_to_cpu(sp->offset);
	adapter->sp.sp_stabletime = le16_to_cpu(sp->stabletime);
230 231
	adapter->sp.sp_calcontrol = sp->calcontrol;
	adapter->sp.sp_extsleepclk = sp->externalsleepclk;
232 233
	adapter->sp.sp_reserved = le16_to_cpu(sp->reserved);

234
	lbs_deb_enter(LBS_DEB_CMD);
235 236 237
	return 0;
}

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

	struct cmd_ds_802_11_get_stat *p11Stat = &resp->params.gstat;
245
	struct lbs_adapter *adapter = priv->adapter;
246 247 248 249 250

	// TODO Convert it to Big endian befor copy
	memcpy(&adapter->wlan802_11Stat,
	       p11Stat, sizeof(struct cmd_ds_802_11_get_stat));
*/
251
	lbs_deb_leave(LBS_DEB_CMD);
252 253 254
	return 0;
}

255
static int lbs_ret_802_11_snmp_mib(struct lbs_private *priv,
256 257 258 259 260 261
				    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);

262
	lbs_deb_enter(LBS_DEB_CMD);
263

264
	lbs_deb_cmd("SNMP_RESP: oid 0x%x, querytype 0x%x\n", oid,
265
	       querytype);
266
	lbs_deb_cmd("SNMP_RESP: Buf size %d\n", le16_to_cpu(smib->bufsize));
267

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

293
	lbs_deb_enter(LBS_DEB_CMD);
294 295 296
	return 0;
}

297
static int lbs_ret_802_11_key_material(struct lbs_private *priv,
298 299 300 301
					struct cmd_ds_command *resp)
{
	struct cmd_ds_802_11_key_material *pkeymaterial =
	    &resp->params.keymaterial;
302
	struct lbs_adapter *adapter = priv->adapter;
303 304
	u16 action = le16_to_cpu(pkeymaterial->action);

305
	lbs_deb_enter(LBS_DEB_CMD);
306 307

	/* Copy the returned key to driver private data */
308
	if (action == CMD_ACT_GET) {
309 310 311 312 313 314
		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;
315
			struct enc_key * pkey;
316 317
			u16 param_set_len = le16_to_cpu(pkeyparamset->length);
			u16 key_len = le16_to_cpu(pkeyparamset->keylen);
318 319 320
			u16 key_flags = le16_to_cpu(pkeyparamset->keyinfo);
			u16 key_type = le16_to_cpu(pkeyparamset->keytypeid);
			u8 * end;
321 322 323 324 325 326 327 328

			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;

329
			if (key_flags & KEY_INFO_WPA_UNICAST)
330
				pkey = &adapter->wpa_unicast_key;
331
			else if (key_flags & KEY_INFO_WPA_MCAST)
332 333 334 335 336
				pkey = &adapter->wpa_mcast_key;
			else
				break;

			/* Copy returned key into driver */
337
			memset(pkey, 0, sizeof(struct enc_key));
338 339
			if (key_len > sizeof(pkey->key))
				break;
340 341 342
			pkey->type = key_type;
			pkey->flags = key_flags;
			pkey->len = key_len;
343 344 345 346 347 348
			memcpy(pkey->key, pkeyparamset->key, pkey->len);

			buf_ptr = end + 1;
		}
	}

349
	lbs_deb_enter(LBS_DEB_CMD);
350 351 352
	return 0;
}

353
static int lbs_ret_802_11_mac_address(struct lbs_private *priv,
354 355 356
				       struct cmd_ds_command *resp)
{
	struct cmd_ds_802_11_mac_address *macadd = &resp->params.macadd;
357
	struct lbs_adapter *adapter = priv->adapter;
358

359
	lbs_deb_enter(LBS_DEB_CMD);
360 361 362

	memcpy(adapter->current_addr, macadd->macadd, ETH_ALEN);

363
	lbs_deb_enter(LBS_DEB_CMD);
364 365 366
	return 0;
}

367
static int lbs_ret_802_11_rf_tx_power(struct lbs_private *priv,
368 369 370
				       struct cmd_ds_command *resp)
{
	struct cmd_ds_802_11_rf_tx_power *rtp = &resp->params.txp;
371
	struct lbs_adapter *adapter = priv->adapter;
372

373
	lbs_deb_enter(LBS_DEB_CMD);
374 375 376

	adapter->txpowerlevel = le16_to_cpu(rtp->currentlevel);

377
	lbs_deb_cmd("TX power currently %d\n", adapter->txpowerlevel);
378

379
	lbs_deb_leave(LBS_DEB_CMD);
380 381 382
	return 0;
}

383
static int lbs_ret_802_11_rate_adapt_rateset(struct lbs_private *priv,
384 385
					      struct cmd_ds_command *resp)
{
386
	struct cmd_ds_802_11_rate_adapt_rateset *rates = &resp->params.rateset;
387
	struct lbs_adapter *adapter = priv->adapter;
388

389
	lbs_deb_enter(LBS_DEB_CMD);
390

391
	if (rates->action == CMD_ACT_GET) {
392 393
		adapter->enablehwauto = le16_to_cpu(rates->enablehwauto);
		adapter->ratebitmap = le16_to_cpu(rates->bitmap);
394 395
	}

396
	lbs_deb_leave(LBS_DEB_CMD);
397 398 399
	return 0;
}

400
static int lbs_ret_802_11_data_rate(struct lbs_private *priv,
401 402 403
				     struct cmd_ds_command *resp)
{
	struct cmd_ds_802_11_data_rate *pdatarate = &resp->params.drate;
404
	struct lbs_adapter *adapter = priv->adapter;
405

406
	lbs_deb_enter(LBS_DEB_CMD);
407

408
	lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) pdatarate,
409
		sizeof(struct cmd_ds_802_11_data_rate));
410

411 412 413
	/* FIXME: get actual rates FW can do if this command actually returns
	 * all data rates supported.
	 */
414
	adapter->cur_rate = lbs_fw_index_to_data_rate(pdatarate->rates[0]);
415
	lbs_deb_cmd("DATA_RATE: current rate 0x%02x\n", adapter->cur_rate);
416

417
	lbs_deb_leave(LBS_DEB_CMD);
418 419 420
	return 0;
}

421
static int lbs_ret_802_11_rf_channel(struct lbs_private *priv,
422 423
				      struct cmd_ds_command *resp)
{
424
	struct cmd_ds_802_11_rf_channel *rfchannel = &resp->params.rfchannel;
425
	struct lbs_adapter *adapter = priv->adapter;
426 427 428
	u16 action = le16_to_cpu(rfchannel->action);
	u16 newchannel = le16_to_cpu(rfchannel->currentchannel);

429
	lbs_deb_enter(LBS_DEB_CMD);
430

431
	if (action == CMD_OPT_802_11_RF_CHANNEL_GET
432
	    && adapter->curbssparams.channel != newchannel) {
433
		lbs_deb_cmd("channel switch from %d to %d\n",
434 435 436 437 438 439
		       adapter->curbssparams.channel, newchannel);

		/* Update the channel again */
		adapter->curbssparams.channel = newchannel;
	}

440
	lbs_deb_enter(LBS_DEB_CMD);
441 442 443
	return 0;
}

444
static int lbs_ret_802_11_rssi(struct lbs_private *priv,
445 446 447
				struct cmd_ds_command *resp)
{
	struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp;
448
	struct lbs_adapter *adapter = priv->adapter;
449

450 451
	lbs_deb_enter(LBS_DEB_CMD);

452 453
	/* store the non average value */
	adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR);
454
	adapter->NF[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->noisefloor);
455 456

	adapter->SNR[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgSNR);
457
	adapter->NF[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgnoisefloor);
458 459 460 461 462 463 464 465 466

	adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] =
	    CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
		     adapter->NF[TYPE_BEACON][TYPE_NOAVG]);

	adapter->RSSI[TYPE_BEACON][TYPE_AVG] =
	    CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
		     adapter->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);

467 468
	lbs_deb_cmd("RSSI: beacon %d, avg %d\n",
	       adapter->RSSI[TYPE_BEACON][TYPE_NOAVG],
469 470
	       adapter->RSSI[TYPE_BEACON][TYPE_AVG]);

471
	lbs_deb_leave(LBS_DEB_CMD);
472 473 474
	return 0;
}

475
static int lbs_ret_802_11_eeprom_access(struct lbs_private *priv,
476 477
				  struct cmd_ds_command *resp)
{
478
	struct lbs_adapter *adapter = priv->adapter;
479 480
	struct lbs_ioctl_regrdwr *pbuf;
	pbuf = (struct lbs_ioctl_regrdwr *) adapter->prdeeprom;
481

482
	lbs_deb_enter_args(LBS_DEB_CMD, "len %d",
483 484 485
	       le16_to_cpu(resp->params.rdeeprom.bytecount));
	if (pbuf->NOB < le16_to_cpu(resp->params.rdeeprom.bytecount)) {
		pbuf->NOB = 0;
486
		lbs_deb_cmd("EEPROM read length too big\n");
487 488 489 490 491 492 493
		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));
494
		lbs_deb_hex(LBS_DEB_CMD, "EEPROM", (char *)&pbuf->value,
495 496
			le16_to_cpu(resp->params.rdeeprom.bytecount));
	}
497
	lbs_deb_leave(LBS_DEB_CMD);
498 499 500
	return 0;
}

501
static int lbs_ret_get_log(struct lbs_private *priv,
502 503
			    struct cmd_ds_command *resp)
{
504
	struct cmd_ds_802_11_get_log *logmessage = &resp->params.glog;
505
	struct lbs_adapter *adapter = priv->adapter;
506

507
	lbs_deb_enter(LBS_DEB_CMD);
508

509 510
	/* Stored little-endian */
	memcpy(&adapter->logmsg, logmessage, sizeof(struct cmd_ds_802_11_get_log));
511

512
	lbs_deb_leave(LBS_DEB_CMD);
513 514 515
	return 0;
}

516
static int lbs_ret_802_11_enable_rsn(struct lbs_private *priv,
517 518 519
                                          struct cmd_ds_command *resp)
{
	struct cmd_ds_802_11_enable_rsn *enable_rsn = &resp->params.enbrsn;
520
	struct lbs_adapter *adapter = priv->adapter;
521 522 523 524
	u32 * pdata_buf = adapter->cur_cmd->pdata_buf;

	lbs_deb_enter(LBS_DEB_CMD);

525
	if (enable_rsn->action == cpu_to_le16(CMD_ACT_GET)) {
526 527 528 529
		if (pdata_buf)
			*pdata_buf = (u32) le16_to_cpu(enable_rsn->enable);
	}

530
	lbs_deb_leave(LBS_DEB_CMD);
531 532 533
	return 0;
}

534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551
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;
	struct lbs_adapter *adapter = priv->adapter;

	lbs_deb_enter(LBS_DEB_CMD);

	if (bcn_ctrl->action == CMD_ACT_GET) {
		adapter->beacon_enable = (u8) le16_to_cpu(bcn_ctrl->beacon_enable);
		adapter->beacon_period = le16_to_cpu(bcn_ctrl->beacon_period);
	}

	lbs_deb_enter(LBS_DEB_CMD);
	return 0;
}

552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571
static int lbs_ret_802_11_subscribe_event(struct lbs_private *priv,
	struct cmd_ds_command *resp)
{
	struct lbs_adapter *adapter = priv->adapter;
	struct cmd_ds_802_11_subscribe_event *cmd_event =
		&resp->params.subscribe_event;
	struct cmd_ds_802_11_subscribe_event *dst_event =
		adapter->cur_cmd->pdata_buf;

	lbs_deb_enter(LBS_DEB_CMD);

	if (dst_event->action == cpu_to_le16(CMD_ACT_GET)) {
		dst_event->events = le16_to_cpu(cmd_event->events);
		memcpy(dst_event->tlv, cmd_event->tlv, sizeof(dst_event->tlv));
	}

	lbs_deb_leave(LBS_DEB_CMD);
	return 0;
}

572 573
static inline int handle_cmd_response(u16 respcmd,
				      struct cmd_ds_command *resp,
574
				      struct lbs_private *priv)
575 576 577
{
	int ret = 0;
	unsigned long flags;
578
	struct lbs_adapter *adapter = priv->adapter;
579

580 581
	lbs_deb_enter(LBS_DEB_HOST);

582
	switch (respcmd) {
583 584 585
	case CMD_RET(CMD_MAC_REG_ACCESS):
	case CMD_RET(CMD_BBP_REG_ACCESS):
	case CMD_RET(CMD_RF_REG_ACCESS):
586
		ret = lbs_ret_reg_access(priv, respcmd, resp);
587 588
		break;

589
	case CMD_RET(CMD_GET_HW_SPEC):
590
		ret = lbs_ret_get_hw_spec(priv, resp);
591 592
		break;

593
	case CMD_RET(CMD_802_11_SCAN):
594
		ret = lbs_ret_80211_scan(priv, resp);
595 596
		break;

597
	case CMD_RET(CMD_802_11_GET_LOG):
598
		ret = lbs_ret_get_log(priv, resp);
599 600
		break;

601
	case CMD_RET_802_11_ASSOCIATE:
602 603
	case CMD_RET(CMD_802_11_ASSOCIATE):
	case CMD_RET(CMD_802_11_REASSOCIATE):
604
		ret = lbs_ret_80211_associate(priv, resp);
605 606
		break;

607 608
	case CMD_RET(CMD_802_11_DISASSOCIATE):
	case CMD_RET(CMD_802_11_DEAUTHENTICATE):
609
		ret = lbs_ret_80211_disassociate(priv, resp);
610 611
		break;

612 613
	case CMD_RET(CMD_802_11_AD_HOC_START):
	case CMD_RET(CMD_802_11_AD_HOC_JOIN):
614
		ret = lbs_ret_80211_ad_hoc_start(priv, resp);
615 616
		break;

617
	case CMD_RET(CMD_802_11_GET_STAT):
618
		ret = lbs_ret_802_11_stat(priv, resp);
619 620
		break;

621
	case CMD_RET(CMD_802_11_SNMP_MIB):
622
		ret = lbs_ret_802_11_snmp_mib(priv, resp);
623 624
		break;

625
	case CMD_RET(CMD_802_11_RF_TX_POWER):
626
		ret = lbs_ret_802_11_rf_tx_power(priv, resp);
627 628
		break;

629 630
	case CMD_RET(CMD_802_11_SET_AFC):
	case CMD_RET(CMD_802_11_GET_AFC):
631
		spin_lock_irqsave(&adapter->driver_lock, flags);
632
		memmove(adapter->cur_cmd->pdata_buf, &resp->params.afc,
633 634 635 636 637
			sizeof(struct cmd_ds_802_11_afc));
		spin_unlock_irqrestore(&adapter->driver_lock, flags);

		break;

638 639 640 641 642 643 644
	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):
645 646
		break;

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

651
	case CMD_RET(CMD_802_11_DATA_RATE):
652
		ret = lbs_ret_802_11_data_rate(priv, resp);
653
		break;
654
	case CMD_RET(CMD_802_11_RATE_ADAPT_RATESET):
655
		ret = lbs_ret_802_11_rate_adapt_rateset(priv, resp);
656
		break;
657
	case CMD_RET(CMD_802_11_RF_CHANNEL):
658
		ret = lbs_ret_802_11_rf_channel(priv, resp);
659 660
		break;

661
	case CMD_RET(CMD_802_11_RSSI):
662
		ret = lbs_ret_802_11_rssi(priv, resp);
663 664
		break;

665
	case CMD_RET(CMD_802_11_MAC_ADDRESS):
666
		ret = lbs_ret_802_11_mac_address(priv, resp);
667 668
		break;

669
	case CMD_RET(CMD_802_11_AD_HOC_STOP):
670
		ret = lbs_ret_80211_ad_hoc_stop(priv, resp);
671 672
		break;

673
	case CMD_RET(CMD_802_11_KEY_MATERIAL):
674
		ret = lbs_ret_802_11_key_material(priv, resp);
675 676
		break;

677
	case CMD_RET(CMD_802_11_EEPROM_ACCESS):
678
		ret = lbs_ret_802_11_eeprom_access(priv, resp);
679 680
		break;

681
	case CMD_RET(CMD_802_11D_DOMAIN_INFO):
682
		ret = lbs_ret_802_11d_domain_info(priv, resp);
683 684
		break;

685
	case CMD_RET(CMD_802_11_SLEEP_PARAMS):
686
		ret = lbs_ret_802_11_sleep_params(priv, resp);
687
		break;
688
	case CMD_RET(CMD_802_11_INACTIVITY_TIMEOUT):
689 690 691 692 693 694
		spin_lock_irqsave(&adapter->driver_lock, flags);
		*((u16 *) adapter->cur_cmd->pdata_buf) =
		    le16_to_cpu(resp->params.inactivity_timeout.timeout);
		spin_unlock_irqrestore(&adapter->driver_lock, flags);
		break;

695
	case CMD_RET(CMD_802_11_TPC_CFG):
696
		spin_lock_irqsave(&adapter->driver_lock, flags);
697
		memmove(adapter->cur_cmd->pdata_buf, &resp->params.tpccfg,
698 699 700
			sizeof(struct cmd_ds_802_11_tpc_cfg));
		spin_unlock_irqrestore(&adapter->driver_lock, flags);
		break;
701
	case CMD_RET(CMD_802_11_LED_GPIO_CTRL):
702
		spin_lock_irqsave(&adapter->driver_lock, flags);
703
		memmove(adapter->cur_cmd->pdata_buf, &resp->params.ledgpio,
704 705 706
			sizeof(struct cmd_ds_802_11_led_ctrl));
		spin_unlock_irqrestore(&adapter->driver_lock, flags);
		break;
707 708 709 710
	case CMD_RET(CMD_802_11_SUBSCRIBE_EVENT):
		ret = lbs_ret_802_11_subscribe_event(priv, resp);
		break;

711
	case CMD_RET(CMD_802_11_PWR_CFG):
712
		spin_lock_irqsave(&adapter->driver_lock, flags);
713
		memmove(adapter->cur_cmd->pdata_buf, &resp->params.pwrcfg,
714 715 716 717 718
			sizeof(struct cmd_ds_802_11_pwr_cfg));
		spin_unlock_irqrestore(&adapter->driver_lock, flags);

		break;

719
	case CMD_RET(CMD_GET_TSF):
720 721 722 723 724
		spin_lock_irqsave(&adapter->driver_lock, flags);
		memcpy(priv->adapter->cur_cmd->pdata_buf,
		       &resp->params.gettsf.tsfvalue, sizeof(u64));
		spin_unlock_irqrestore(&adapter->driver_lock, flags);
		break;
725
	case CMD_RET(CMD_BT_ACCESS):
726 727 728 729 730 731
		spin_lock_irqsave(&adapter->driver_lock, flags);
		if (adapter->cur_cmd->pdata_buf)
			memcpy(adapter->cur_cmd->pdata_buf,
			       &resp->params.bt.addr1, 2 * ETH_ALEN);
		spin_unlock_irqrestore(&adapter->driver_lock, flags);
		break;
732
	case CMD_RET(CMD_FWT_ACCESS):
733 734
		spin_lock_irqsave(&adapter->driver_lock, flags);
		if (adapter->cur_cmd->pdata_buf)
735 736
			memcpy(adapter->cur_cmd->pdata_buf, &resp->params.fwt,
			       sizeof(resp->params.fwt));
737 738
		spin_unlock_irqrestore(&adapter->driver_lock, flags);
		break;
739
	case CMD_RET(CMD_MESH_ACCESS):
740
		if (adapter->cur_cmd->pdata_buf)
741
			memcpy(adapter->cur_cmd->pdata_buf, &resp->params.mesh,
742 743
			       sizeof(resp->params.mesh));
		break;
744 745 746 747
	case CMD_RET(CMD_802_11_BEACON_CTRL):
		ret = lbs_ret_802_11_bcn_ctrl(priv, resp);
		break;

748
	default:
749
		lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n",
750
			    resp->command);
751 752
		break;
	}
753
	lbs_deb_leave(LBS_DEB_HOST);
754 755 756
	return ret;
}

757
int lbs_process_rx_command(struct lbs_private *priv)
758 759 760
{
	u16 respcmd;
	struct cmd_ds_command *resp;
761
	struct lbs_adapter *adapter = priv->adapter;
762 763 764 765
	int ret = 0;
	ulong flags;
	u16 result;

766
	lbs_deb_enter(LBS_DEB_HOST);
767 768 769 770 771 772 773 774

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

	mutex_lock(&adapter->lock);
	spin_lock_irqsave(&adapter->driver_lock, flags);

	if (!adapter->cur_cmd) {
775
		lbs_deb_host("CMD_RESP: cur_cmd is NULL\n");
776 777 778 779 780 781 782 783 784
		ret = -1;
		spin_unlock_irqrestore(&adapter->driver_lock, flags);
		goto done;
	}
	resp = (struct cmd_ds_command *)(adapter->cur_cmd->bufvirtualaddr);

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

785 786 787 788
	lbs_deb_host("CMD_RESP: response 0x%04x, size %d, jiffies %lu\n",
		respcmd, priv->upld_len, jiffies);
	lbs_deb_hex(LBS_DEB_HOST, "CMD_RESP", adapter->cur_cmd->bufvirtualaddr,
		    priv->upld_len);
789 790

	if (!(respcmd & 0x8000)) {
791
		lbs_deb_host("invalid response!\n");
792
		adapter->cur_cmd_retcode = -1;
793
		__lbs_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
794 795 796 797 798 799 800 801
		adapter->nr_cmd_pending--;
		adapter->cur_cmd = NULL;
		spin_unlock_irqrestore(&adapter->driver_lock, flags);
		ret = -1;
		goto done;
	}

	/* Store the response code to cur_cmd_retcode. */
802
	adapter->cur_cmd_retcode = result;;
803

804
	if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) {
805 806
		struct cmd_ds_802_11_ps_mode *psmode = &resp->params.psmode;
		u16 action = le16_to_cpu(psmode->action);
807

808 809
		lbs_deb_host(
		       "CMD_RESP: PS_MODE cmd reply result 0x%x, action 0x%x\n",
810
		       result, action);
811 812

		if (result) {
813
			lbs_deb_host("CMD_RESP: PS command failed with 0x%x\n",
814 815 816 817
				    result);
			/*
			 * We should not re-try enter-ps command in
			 * ad-hoc mode. It takes place in
818
			 * lbs_execute_next_command().
819 820
			 */
			if (adapter->mode == IW_MODE_ADHOC &&
821
			    action == CMD_SUBCMD_ENTER_PS)
822
				adapter->psmode = LBS802_11POWERMODECAM;
823
		} else if (action == CMD_SUBCMD_ENTER_PS) {
824 825 826
			adapter->needtowakeup = 0;
			adapter->psstate = PS_STATE_AWAKE;

827
			lbs_deb_host("CMD_RESP: ENTER_PS command response\n");
828
			if (adapter->connect_status != LBS_CONNECTED) {
829 830 831 832
				/*
				 * When Deauth Event received before Enter_PS command
				 * response, We need to wake up the firmware.
				 */
833
				lbs_deb_host(
834
				       "disconnected, invoking lbs_ps_wakeup\n");
835 836

				spin_unlock_irqrestore(&adapter->driver_lock, flags);
837
				mutex_unlock(&adapter->lock);
838
				lbs_ps_wakeup(priv, 0);
839 840 841
				mutex_lock(&adapter->lock);
				spin_lock_irqsave(&adapter->driver_lock, flags);
			}
842
		} else if (action == CMD_SUBCMD_EXIT_PS) {
843 844
			adapter->needtowakeup = 0;
			adapter->psstate = PS_STATE_FULL_POWER;
845
			lbs_deb_host("CMD_RESP: EXIT_PS command response\n");
846
		} else {
847
			lbs_deb_host("CMD_RESP: PS action 0x%X\n", action);
848 849
		}

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

		ret = 0;
		goto done;
	}

	if (adapter->cur_cmd->cmdflags & CMD_F_HOSTCMD) {
		/* Copy the response back to response buffer */
861 862
		memcpy(adapter->cur_cmd->pdata_buf, resp,
		       le16_to_cpu(resp->size));
863 864 865 866 867
		adapter->cur_cmd->cmdflags &= ~CMD_F_HOSTCMD;
	}

	/* If the command is not successful, cleanup and return failure */
	if ((result != 0 || !(respcmd & 0x8000))) {
868 869
		lbs_deb_host("CMD_RESP: error 0x%04x in command reply 0x%04x\n",
		       result, respcmd);
870 871 872 873
		/*
		 * Handling errors here
		 */
		switch (respcmd) {
874 875
		case CMD_RET(CMD_GET_HW_SPEC):
		case CMD_RET(CMD_802_11_RESET):
876
			lbs_deb_host("CMD_RESP: reset failed\n");
877 878 879 880
			break;

		}

881
		__lbs_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
882 883 884 885 886 887 888 889 890 891 892 893 894 895 896
		adapter->nr_cmd_pending--;
		adapter->cur_cmd = NULL;
		spin_unlock_irqrestore(&adapter->driver_lock, flags);

		ret = -1;
		goto done;
	}

	spin_unlock_irqrestore(&adapter->driver_lock, flags);

	ret = handle_cmd_response(respcmd, resp, priv);

	spin_lock_irqsave(&adapter->driver_lock, flags);
	if (adapter->cur_cmd) {
		/* Clean up and Put current command back to cmdfreeq */
897
		__lbs_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
898 899 900 901 902 903 904 905
		adapter->nr_cmd_pending--;
		WARN_ON(adapter->nr_cmd_pending > 128);
		adapter->cur_cmd = NULL;
	}
	spin_unlock_irqrestore(&adapter->driver_lock, flags);

done:
	mutex_unlock(&adapter->lock);
906
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
907 908 909
	return ret;
}

910
int lbs_process_event(struct lbs_private *priv)
911 912
{
	int ret = 0;
913
	struct lbs_adapter *adapter = priv->adapter;
914 915
	u32 eventcause;

916 917
	lbs_deb_enter(LBS_DEB_CMD);

918 919 920 921
	spin_lock_irq(&adapter->driver_lock);
	eventcause = adapter->eventcause;
	spin_unlock_irq(&adapter->driver_lock);

922
	lbs_deb_cmd("event cause 0x%x\n", eventcause);
923 924 925

	switch (eventcause >> SBI_EVENT_CAUSE_SHIFT) {
	case MACREG_INT_CODE_LINK_SENSED:
926
		lbs_deb_cmd("EVENT: MACREG_INT_CODE_LINK_SENSED\n");
927 928 929
		break;

	case MACREG_INT_CODE_DEAUTHENTICATED:
930
		lbs_deb_cmd("EVENT: deauthenticated\n");
931
		lbs_mac_event_disconnected(priv);
932 933 934
		break;

	case MACREG_INT_CODE_DISASSOCIATED:
935
		lbs_deb_cmd("EVENT: disassociated\n");
936
		lbs_mac_event_disconnected(priv);
937 938 939
		break;

	case MACREG_INT_CODE_LINK_LOSE_NO_SCAN:
940
		lbs_deb_cmd("EVENT: link lost\n");
941
		lbs_mac_event_disconnected(priv);
942 943 944
		break;

	case MACREG_INT_CODE_PS_SLEEP:
945
		lbs_deb_cmd("EVENT: sleep\n");
946 947 948

		/* handle unexpected PS SLEEP event */
		if (adapter->psstate == PS_STATE_FULL_POWER) {
949
			lbs_deb_cmd(
950
			       "EVENT: in FULL POWER mode, ignoreing PS_SLEEP\n");
951 952 953 954
			break;
		}
		adapter->psstate = PS_STATE_PRE_SLEEP;

955
		lbs_ps_confirm_sleep(priv, (u16) adapter->psmode);
956 957 958 959

		break;

	case MACREG_INT_CODE_PS_AWAKE:
960
		lbs_deb_cmd("EVENT: awake\n");
961 962 963

		/* handle unexpected PS AWAKE event */
		if (adapter->psstate == PS_STATE_FULL_POWER) {
964
			lbs_deb_cmd(
965 966 967 968 969 970 971 972 973 974 975
			       "EVENT: In FULL POWER mode - ignore PS AWAKE\n");
			break;
		}

		adapter->psstate = PS_STATE_AWAKE;

		if (adapter->needtowakeup) {
			/*
			 * wait for the command processing to finish
			 * before resuming sending
			 * adapter->needtowakeup will be set to FALSE
976
			 * in lbs_ps_wakeup()
977
			 */
978
			lbs_deb_cmd("waking up ...\n");
979
			lbs_ps_wakeup(priv, 0);
980 981 982 983
		}
		break;

	case MACREG_INT_CODE_MIC_ERR_UNICAST:
984
		lbs_deb_cmd("EVENT: UNICAST MIC ERROR\n");
985 986 987 988
		handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_UNICAST);
		break;

	case MACREG_INT_CODE_MIC_ERR_MULTICAST:
989
		lbs_deb_cmd("EVENT: MULTICAST MIC ERROR\n");
990 991 992 993 994 995 996
		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:
997
		lbs_deb_cmd("EVENT: ADHOC beacon lost\n");
998 999 1000
		break;

	case MACREG_INT_CODE_RSSI_LOW:
1001
		lbs_pr_alert("EVENT: rssi low\n");
1002 1003
		break;
	case MACREG_INT_CODE_SNR_LOW:
1004
		lbs_pr_alert("EVENT: snr low\n");
1005 1006
		break;
	case MACREG_INT_CODE_MAX_FAIL:
1007
		lbs_pr_alert("EVENT: max fail\n");
1008 1009
		break;
	case MACREG_INT_CODE_RSSI_HIGH:
1010
		lbs_pr_alert("EVENT: rssi high\n");
1011 1012
		break;
	case MACREG_INT_CODE_SNR_HIGH:
1013
		lbs_pr_alert("EVENT: snr high\n");
1014 1015
		break;

1016
	case MACREG_INT_CODE_MESH_AUTO_STARTED:
1017 1018 1019 1020 1021
		/* Ignore spurious autostart events if autostart is disabled */
		if (!priv->mesh_autostart_enabled) {
			lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n");
			break;
		}
1022
		lbs_pr_info("EVENT: MESH_AUTO_STARTED\n");
1023
		adapter->mesh_connect_status = LBS_CONNECTED;
1024
		if (priv->mesh_open == 1) {
1025 1026
			netif_wake_queue(priv->mesh_dev);
			netif_carrier_on(priv->mesh_dev);
1027
		}
1028
		adapter->mode = IW_MODE_ADHOC;
1029
		schedule_work(&priv->sync_channel);
1030 1031
		break;

1032
	default:
1033
		lbs_pr_alert("EVENT: unknown event id 0x%04x\n",
1034 1035 1036 1037 1038 1039 1040
		       eventcause >> SBI_EVENT_CAUSE_SHIFT);
		break;
	}

	spin_lock_irq(&adapter->driver_lock);
	adapter->eventcause = 0;
	spin_unlock_irq(&adapter->driver_lock);
1041

1042
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
1043 1044
	return ret;
}