cmdresp.c 24.9 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_802_11_sleep_params(struct lbs_private *priv,
149 150 151 152
					struct cmd_ds_command *resp)
{
	struct cmd_ds_802_11_sleep_params *sp = &resp->params.sleep_params;

153
	lbs_deb_enter(LBS_DEB_CMD);
154

155 156
	lbs_deb_cmd("error 0x%x, offset 0x%x, stabletime 0x%x, calcontrol 0x%x "
		    "extsleepclk 0x%x\n", le16_to_cpu(sp->error),
157 158 159
		    le16_to_cpu(sp->offset), le16_to_cpu(sp->stabletime),
		    sp->calcontrol, sp->externalsleepclk);

160 161 162 163 164 165
	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);
166

167
	lbs_deb_enter(LBS_DEB_CMD);
168 169 170
	return 0;
}

171
static int lbs_ret_802_11_stat(struct lbs_private *priv,
172 173
				struct cmd_ds_command *resp)
{
174
	lbs_deb_enter(LBS_DEB_CMD);
175
/*	currently priv->wlan802_11Stat is unused
176 177 178 179

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

	// TODO Convert it to Big endian befor copy
180
	memcpy(&priv->wlan802_11Stat,
181 182
	       p11Stat, sizeof(struct cmd_ds_802_11_get_stat));
*/
183
	lbs_deb_leave(LBS_DEB_CMD);
184 185 186
	return 0;
}

187
static int lbs_ret_802_11_snmp_mib(struct lbs_private *priv,
188 189 190 191 192 193
				    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);

194
	lbs_deb_enter(LBS_DEB_CMD);
195

196
	lbs_deb_cmd("SNMP_RESP: oid 0x%x, querytype 0x%x\n", oid,
197
	       querytype);
198
	lbs_deb_cmd("SNMP_RESP: Buf size %d\n", le16_to_cpu(smib->bufsize));
199

200
	if (querytype == CMD_ACT_GET) {
201
		switch (oid) {
202
		case FRAGTHRESH_I:
203
			priv->fragthsd =
204
				le16_to_cpu(*((__le16 *)(smib->value)));
205
			lbs_deb_cmd("SNMP_RESP: frag threshold %u\n",
206
				    priv->fragthsd);
207
			break;
208
		case RTSTHRESH_I:
209
			priv->rtsthsd =
210
				le16_to_cpu(*((__le16 *)(smib->value)));
211
			lbs_deb_cmd("SNMP_RESP: rts threshold %u\n",
212
				    priv->rtsthsd);
213
			break;
214
		case SHORT_RETRYLIM_I:
215
			priv->txretrycount =
216
				le16_to_cpu(*((__le16 *)(smib->value)));
217
			lbs_deb_cmd("SNMP_RESP: tx retry count %u\n",
218
				    priv->rtsthsd);
219 220 221 222 223 224
			break;
		default:
			break;
		}
	}

225
	lbs_deb_enter(LBS_DEB_CMD);
226 227 228
	return 0;
}

229
static int lbs_ret_802_11_key_material(struct lbs_private *priv,
230 231 232 233 234 235
					struct cmd_ds_command *resp)
{
	struct cmd_ds_802_11_key_material *pkeymaterial =
	    &resp->params.keymaterial;
	u16 action = le16_to_cpu(pkeymaterial->action);

236
	lbs_deb_enter(LBS_DEB_CMD);
237 238

	/* Copy the returned key to driver private data */
239
	if (action == CMD_ACT_GET) {
240 241 242 243 244 245
		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;
246
			struct enc_key * pkey;
247 248
			u16 param_set_len = le16_to_cpu(pkeyparamset->length);
			u16 key_len = le16_to_cpu(pkeyparamset->keylen);
249 250 251
			u16 key_flags = le16_to_cpu(pkeyparamset->keyinfo);
			u16 key_type = le16_to_cpu(pkeyparamset->keytypeid);
			u8 * end;
252 253 254 255 256 257 258 259

			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;

260
			if (key_flags & KEY_INFO_WPA_UNICAST)
261
				pkey = &priv->wpa_unicast_key;
262
			else if (key_flags & KEY_INFO_WPA_MCAST)
263
				pkey = &priv->wpa_mcast_key;
264 265 266 267
			else
				break;

			/* Copy returned key into driver */
268
			memset(pkey, 0, sizeof(struct enc_key));
269 270
			if (key_len > sizeof(pkey->key))
				break;
271 272 273
			pkey->type = key_type;
			pkey->flags = key_flags;
			pkey->len = key_len;
274 275 276 277 278 279
			memcpy(pkey->key, pkeyparamset->key, pkey->len);

			buf_ptr = end + 1;
		}
	}

280
	lbs_deb_enter(LBS_DEB_CMD);
281 282 283
	return 0;
}

284
static int lbs_ret_802_11_mac_address(struct lbs_private *priv,
285 286 287 288
				       struct cmd_ds_command *resp)
{
	struct cmd_ds_802_11_mac_address *macadd = &resp->params.macadd;

289
	lbs_deb_enter(LBS_DEB_CMD);
290

291
	memcpy(priv->current_addr, macadd->macadd, ETH_ALEN);
292

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

297
static int lbs_ret_802_11_rf_tx_power(struct lbs_private *priv,
298 299 300 301
				       struct cmd_ds_command *resp)
{
	struct cmd_ds_802_11_rf_tx_power *rtp = &resp->params.txp;

302
	lbs_deb_enter(LBS_DEB_CMD);
303

304
	priv->txpowerlevel = le16_to_cpu(rtp->currentlevel);
305

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

308
	lbs_deb_leave(LBS_DEB_CMD);
309 310 311
	return 0;
}

312
static int lbs_ret_802_11_rate_adapt_rateset(struct lbs_private *priv,
313 314
					      struct cmd_ds_command *resp)
{
315
	struct cmd_ds_802_11_rate_adapt_rateset *rates = &resp->params.rateset;
316

317
	lbs_deb_enter(LBS_DEB_CMD);
318

319
	if (rates->action == CMD_ACT_GET) {
320 321
		priv->enablehwauto = le16_to_cpu(rates->enablehwauto);
		priv->ratebitmap = le16_to_cpu(rates->bitmap);
322 323
	}

324
	lbs_deb_leave(LBS_DEB_CMD);
325 326 327
	return 0;
}

328
static int lbs_ret_802_11_data_rate(struct lbs_private *priv,
329 330 331 332
				     struct cmd_ds_command *resp)
{
	struct cmd_ds_802_11_data_rate *pdatarate = &resp->params.drate;

333
	lbs_deb_enter(LBS_DEB_CMD);
334

335
	lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) pdatarate,
336
		sizeof(struct cmd_ds_802_11_data_rate));
337

338 339 340
	/* FIXME: get actual rates FW can do if this command actually returns
	 * all data rates supported.
	 */
341 342
	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);
343

344
	lbs_deb_leave(LBS_DEB_CMD);
345 346 347
	return 0;
}

348
static int lbs_ret_802_11_rf_channel(struct lbs_private *priv,
349 350
				      struct cmd_ds_command *resp)
{
351
	struct cmd_ds_802_11_rf_channel *rfchannel = &resp->params.rfchannel;
352 353 354
	u16 action = le16_to_cpu(rfchannel->action);
	u16 newchannel = le16_to_cpu(rfchannel->currentchannel);

355
	lbs_deb_enter(LBS_DEB_CMD);
356

357
	if (action == CMD_OPT_802_11_RF_CHANNEL_GET
358
	    && priv->curbssparams.channel != newchannel) {
359
		lbs_deb_cmd("channel switch from %d to %d\n",
360
		       priv->curbssparams.channel, newchannel);
361 362

		/* Update the channel again */
363
		priv->curbssparams.channel = newchannel;
364 365
	}

366
	lbs_deb_enter(LBS_DEB_CMD);
367 368 369
	return 0;
}

370
static int lbs_ret_802_11_rssi(struct lbs_private *priv,
371 372 373 374
				struct cmd_ds_command *resp)
{
	struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp;

375 376
	lbs_deb_enter(LBS_DEB_CMD);

377
	/* store the non average value */
378 379
	priv->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR);
	priv->NF[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->noisefloor);
380

381 382
	priv->SNR[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgSNR);
	priv->NF[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgnoisefloor);
383

384 385 386
	priv->RSSI[TYPE_BEACON][TYPE_NOAVG] =
	    CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],
		     priv->NF[TYPE_BEACON][TYPE_NOAVG]);
387

388 389 390
	priv->RSSI[TYPE_BEACON][TYPE_AVG] =
	    CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
		     priv->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
391

392
	lbs_deb_cmd("RSSI: beacon %d, avg %d\n",
393 394
	       priv->RSSI[TYPE_BEACON][TYPE_NOAVG],
	       priv->RSSI[TYPE_BEACON][TYPE_AVG]);
395

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

400
static int lbs_ret_802_11_eeprom_access(struct lbs_private *priv,
401 402
				  struct cmd_ds_command *resp)
{
403
	struct lbs_ioctl_regrdwr *pbuf;
404
	pbuf = (struct lbs_ioctl_regrdwr *) priv->prdeeprom;
405

406
	lbs_deb_enter_args(LBS_DEB_CMD, "len %d",
407 408 409
	       le16_to_cpu(resp->params.rdeeprom.bytecount));
	if (pbuf->NOB < le16_to_cpu(resp->params.rdeeprom.bytecount)) {
		pbuf->NOB = 0;
410
		lbs_deb_cmd("EEPROM read length too big\n");
411 412 413 414 415 416 417
		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));
418
		lbs_deb_hex(LBS_DEB_CMD, "EEPROM", (char *)&pbuf->value,
419 420
			le16_to_cpu(resp->params.rdeeprom.bytecount));
	}
421
	lbs_deb_leave(LBS_DEB_CMD);
422 423 424
	return 0;
}

425
static int lbs_ret_get_log(struct lbs_private *priv,
426 427
			    struct cmd_ds_command *resp)
{
428
	struct cmd_ds_802_11_get_log *logmessage = &resp->params.glog;
429

430
	lbs_deb_enter(LBS_DEB_CMD);
431

432
	/* Stored little-endian */
433
	memcpy(&priv->logmsg, logmessage, sizeof(struct cmd_ds_802_11_get_log));
434

435
	lbs_deb_leave(LBS_DEB_CMD);
436 437 438
	return 0;
}

439
static int lbs_ret_802_11_enable_rsn(struct lbs_private *priv,
440 441 442
                                          struct cmd_ds_command *resp)
{
	struct cmd_ds_802_11_enable_rsn *enable_rsn = &resp->params.enbrsn;
443
	u32 * pdata_buf = priv->cur_cmd->pdata_buf;
444 445 446

	lbs_deb_enter(LBS_DEB_CMD);

447
	if (enable_rsn->action == cpu_to_le16(CMD_ACT_GET)) {
448 449 450 451
		if (pdata_buf)
			*pdata_buf = (u32) le16_to_cpu(enable_rsn->enable);
	}

452
	lbs_deb_leave(LBS_DEB_CMD);
453 454 455
	return 0;
}

456 457 458 459 460 461 462 463 464
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) {
465 466
		priv->beacon_enable = (u8) le16_to_cpu(bcn_ctrl->beacon_enable);
		priv->beacon_period = le16_to_cpu(bcn_ctrl->beacon_period);
467 468 469 470 471 472
	}

	lbs_deb_enter(LBS_DEB_CMD);
	return 0;
}

473 474 475 476 477 478
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 =
479
		priv->cur_cmd->pdata_buf;
480 481 482 483

	lbs_deb_enter(LBS_DEB_CMD);

	if (dst_event->action == cpu_to_le16(CMD_ACT_GET)) {
H
Holger Schurig 已提交
484
		dst_event->events = cmd_event->events;
485 486 487 488 489 490 491
		memcpy(dst_event->tlv, cmd_event->tlv, sizeof(dst_event->tlv));
	}

	lbs_deb_leave(LBS_DEB_CMD);
	return 0;
}

492 493 494
static inline int handle_cmd_response(struct lbs_private *priv,
				      unsigned long dummy,
				      struct cmd_ds_command *resp)
495 496 497
{
	int ret = 0;
	unsigned long flags;
498
	uint16_t respcmd = le16_to_cpu(resp->command);
499

500 501
	lbs_deb_enter(LBS_DEB_HOST);

502
	switch (respcmd) {
503 504 505
	case CMD_RET(CMD_MAC_REG_ACCESS):
	case CMD_RET(CMD_BBP_REG_ACCESS):
	case CMD_RET(CMD_RF_REG_ACCESS):
506
		ret = lbs_ret_reg_access(priv, respcmd, resp);
507 508
		break;

509
	case CMD_RET(CMD_802_11_SCAN):
510
		ret = lbs_ret_80211_scan(priv, resp);
511 512
		break;

513
	case CMD_RET(CMD_802_11_GET_LOG):
514
		ret = lbs_ret_get_log(priv, resp);
515 516
		break;

517
	case CMD_RET_802_11_ASSOCIATE:
518 519
	case CMD_RET(CMD_802_11_ASSOCIATE):
	case CMD_RET(CMD_802_11_REASSOCIATE):
520
		ret = lbs_ret_80211_associate(priv, resp);
521 522
		break;

523 524
	case CMD_RET(CMD_802_11_DISASSOCIATE):
	case CMD_RET(CMD_802_11_DEAUTHENTICATE):
525
		ret = lbs_ret_80211_disassociate(priv, resp);
526 527
		break;

528 529
	case CMD_RET(CMD_802_11_AD_HOC_START):
	case CMD_RET(CMD_802_11_AD_HOC_JOIN):
530
		ret = lbs_ret_80211_ad_hoc_start(priv, resp);
531 532
		break;

533
	case CMD_RET(CMD_802_11_GET_STAT):
534
		ret = lbs_ret_802_11_stat(priv, resp);
535 536
		break;

537
	case CMD_RET(CMD_802_11_SNMP_MIB):
538
		ret = lbs_ret_802_11_snmp_mib(priv, resp);
539 540
		break;

541
	case CMD_RET(CMD_802_11_RF_TX_POWER):
542
		ret = lbs_ret_802_11_rf_tx_power(priv, resp);
543 544
		break;

545 546
	case CMD_RET(CMD_802_11_SET_AFC):
	case CMD_RET(CMD_802_11_GET_AFC):
547 548
		spin_lock_irqsave(&priv->driver_lock, flags);
		memmove(priv->cur_cmd->pdata_buf, &resp->params.afc,
549
			sizeof(struct cmd_ds_802_11_afc));
550
		spin_unlock_irqrestore(&priv->driver_lock, flags);
551 552 553

		break;

554 555 556 557 558 559 560
	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):
561 562
		break;

563
	case CMD_RET(CMD_802_11_ENABLE_RSN):
564
		ret = lbs_ret_802_11_enable_rsn(priv, resp);
565 566
		break;

567
	case CMD_RET(CMD_802_11_DATA_RATE):
568
		ret = lbs_ret_802_11_data_rate(priv, resp);
569
		break;
570
	case CMD_RET(CMD_802_11_RATE_ADAPT_RATESET):
571
		ret = lbs_ret_802_11_rate_adapt_rateset(priv, resp);
572
		break;
573
	case CMD_RET(CMD_802_11_RF_CHANNEL):
574
		ret = lbs_ret_802_11_rf_channel(priv, resp);
575 576
		break;

577
	case CMD_RET(CMD_802_11_RSSI):
578
		ret = lbs_ret_802_11_rssi(priv, resp);
579 580
		break;

581
	case CMD_RET(CMD_802_11_MAC_ADDRESS):
582
		ret = lbs_ret_802_11_mac_address(priv, resp);
583 584
		break;

585
	case CMD_RET(CMD_802_11_AD_HOC_STOP):
586
		ret = lbs_ret_80211_ad_hoc_stop(priv, resp);
587 588
		break;

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

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

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

601
	case CMD_RET(CMD_802_11_SLEEP_PARAMS):
602
		ret = lbs_ret_802_11_sleep_params(priv, resp);
603
		break;
604
	case CMD_RET(CMD_802_11_INACTIVITY_TIMEOUT):
605 606
		spin_lock_irqsave(&priv->driver_lock, flags);
		*((u16 *) priv->cur_cmd->pdata_buf) =
607
		    le16_to_cpu(resp->params.inactivity_timeout.timeout);
608
		spin_unlock_irqrestore(&priv->driver_lock, flags);
609 610
		break;

611
	case CMD_RET(CMD_802_11_TPC_CFG):
612 613
		spin_lock_irqsave(&priv->driver_lock, flags);
		memmove(priv->cur_cmd->pdata_buf, &resp->params.tpccfg,
614
			sizeof(struct cmd_ds_802_11_tpc_cfg));
615
		spin_unlock_irqrestore(&priv->driver_lock, flags);
616
		break;
617
	case CMD_RET(CMD_802_11_LED_GPIO_CTRL):
618 619
		spin_lock_irqsave(&priv->driver_lock, flags);
		memmove(priv->cur_cmd->pdata_buf, &resp->params.ledgpio,
620
			sizeof(struct cmd_ds_802_11_led_ctrl));
621
		spin_unlock_irqrestore(&priv->driver_lock, flags);
622
		break;
623 624 625 626
	case CMD_RET(CMD_802_11_SUBSCRIBE_EVENT):
		ret = lbs_ret_802_11_subscribe_event(priv, resp);
		break;

627
	case CMD_RET(CMD_802_11_PWR_CFG):
628 629
		spin_lock_irqsave(&priv->driver_lock, flags);
		memmove(priv->cur_cmd->pdata_buf, &resp->params.pwrcfg,
630
			sizeof(struct cmd_ds_802_11_pwr_cfg));
631
		spin_unlock_irqrestore(&priv->driver_lock, flags);
632 633 634

		break;

635
	case CMD_RET(CMD_GET_TSF):
636 637
		spin_lock_irqsave(&priv->driver_lock, flags);
		memcpy(priv->cur_cmd->pdata_buf,
638
		       &resp->params.gettsf.tsfvalue, sizeof(u64));
639
		spin_unlock_irqrestore(&priv->driver_lock, flags);
640
		break;
641
	case CMD_RET(CMD_BT_ACCESS):
642 643 644
		spin_lock_irqsave(&priv->driver_lock, flags);
		if (priv->cur_cmd->pdata_buf)
			memcpy(priv->cur_cmd->pdata_buf,
645
			       &resp->params.bt.addr1, 2 * ETH_ALEN);
646
		spin_unlock_irqrestore(&priv->driver_lock, flags);
647
		break;
648
	case CMD_RET(CMD_FWT_ACCESS):
649 650 651
		spin_lock_irqsave(&priv->driver_lock, flags);
		if (priv->cur_cmd->pdata_buf)
			memcpy(priv->cur_cmd->pdata_buf, &resp->params.fwt,
652
			       sizeof(resp->params.fwt));
653
		spin_unlock_irqrestore(&priv->driver_lock, flags);
654
		break;
655
	case CMD_RET(CMD_MESH_ACCESS):
656 657
		if (priv->cur_cmd->pdata_buf)
			memcpy(priv->cur_cmd->pdata_buf, &resp->params.mesh,
658 659
			       sizeof(resp->params.mesh));
		break;
660 661 662 663
	case CMD_RET(CMD_802_11_BEACON_CTRL):
		ret = lbs_ret_802_11_bcn_ctrl(priv, resp);
		break;

664
	default:
665
		lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n",
666
			    resp->command);
667 668
		break;
	}
669
	lbs_deb_leave(LBS_DEB_HOST);
670 671 672
	return ret;
}

673
int lbs_process_rx_command(struct lbs_private *priv)
674 675 676 677 678 679 680
{
	u16 respcmd;
	struct cmd_ds_command *resp;
	int ret = 0;
	ulong flags;
	u16 result;

681
	lbs_deb_enter(LBS_DEB_HOST);
682 683

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

686 687
	mutex_lock(&priv->lock);
	spin_lock_irqsave(&priv->driver_lock, flags);
688

689
	if (!priv->cur_cmd) {
690
		lbs_deb_host("CMD_RESP: cur_cmd is NULL\n");
691
		ret = -1;
692
		spin_unlock_irqrestore(&priv->driver_lock, flags);
693 694
		goto done;
	}
695
	resp = (struct cmd_ds_command *)(priv->cur_cmd->bufvirtualaddr);
696 697 698 699

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

700 701
	lbs_deb_host("CMD_RESP: response 0x%04x, size %d, jiffies %lu\n",
		respcmd, priv->upld_len, jiffies);
702
	lbs_deb_hex(LBS_DEB_HOST, "CMD_RESP", priv->cur_cmd->bufvirtualaddr,
703
		    priv->upld_len);
704 705

	if (!(respcmd & 0x8000)) {
706
		lbs_deb_host("invalid response!\n");
707 708 709 710
		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);
711 712 713 714 715
		ret = -1;
		goto done;
	}

	/* Store the response code to cur_cmd_retcode. */
716
	priv->cur_cmd_retcode = result;
717

718
	if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) {
719 720
		struct cmd_ds_802_11_ps_mode *psmode = &resp->params.psmode;
		u16 action = le16_to_cpu(psmode->action);
721

722 723
		lbs_deb_host(
		       "CMD_RESP: PS_MODE cmd reply result 0x%x, action 0x%x\n",
724
		       result, action);
725 726

		if (result) {
727
			lbs_deb_host("CMD_RESP: PS command failed with 0x%x\n",
728 729 730 731
				    result);
			/*
			 * We should not re-try enter-ps command in
			 * ad-hoc mode. It takes place in
732
			 * lbs_execute_next_command().
733
			 */
734
			if (priv->mode == IW_MODE_ADHOC &&
735
			    action == CMD_SUBCMD_ENTER_PS)
736
				priv->psmode = LBS802_11POWERMODECAM;
737
		} else if (action == CMD_SUBCMD_ENTER_PS) {
738 739
			priv->needtowakeup = 0;
			priv->psstate = PS_STATE_AWAKE;
740

741
			lbs_deb_host("CMD_RESP: ENTER_PS command response\n");
742
			if (priv->connect_status != LBS_CONNECTED) {
743 744 745 746
				/*
				 * When Deauth Event received before Enter_PS command
				 * response, We need to wake up the firmware.
				 */
747
				lbs_deb_host(
748
				       "disconnected, invoking lbs_ps_wakeup\n");
749

750 751
				spin_unlock_irqrestore(&priv->driver_lock, flags);
				mutex_unlock(&priv->lock);
752
				lbs_ps_wakeup(priv, 0);
753 754
				mutex_lock(&priv->lock);
				spin_lock_irqsave(&priv->driver_lock, flags);
755
			}
756
		} else if (action == CMD_SUBCMD_EXIT_PS) {
757 758
			priv->needtowakeup = 0;
			priv->psstate = PS_STATE_FULL_POWER;
759
			lbs_deb_host("CMD_RESP: EXIT_PS command response\n");
760
		} else {
761
			lbs_deb_host("CMD_RESP: PS action 0x%X\n", action);
762 763
		}

764 765 766
		__lbs_cleanup_and_insert_cmd(priv, priv->cur_cmd);
		priv->cur_cmd = NULL;
		spin_unlock_irqrestore(&priv->driver_lock, flags);
767 768 769 770 771 772 773

		ret = 0;
		goto done;
	}

	/* If the command is not successful, cleanup and return failure */
	if ((result != 0 || !(respcmd & 0x8000))) {
774 775
		lbs_deb_host("CMD_RESP: error 0x%04x in command reply 0x%04x\n",
		       result, respcmd);
776 777 778 779
		/*
		 * Handling errors here
		 */
		switch (respcmd) {
780 781
		case CMD_RET(CMD_GET_HW_SPEC):
		case CMD_RET(CMD_802_11_RESET):
782
			lbs_deb_host("CMD_RESP: reset failed\n");
783 784 785 786
			break;

		}

787 788 789
		__lbs_cleanup_and_insert_cmd(priv, priv->cur_cmd);
		priv->cur_cmd = NULL;
		spin_unlock_irqrestore(&priv->driver_lock, flags);
790 791 792 793 794

		ret = -1;
		goto done;
	}

795
	spin_unlock_irqrestore(&priv->driver_lock, flags);
796

797 798 799 800
	if (priv->cur_cmd && priv->cur_cmd->callback) {
		ret = priv->cur_cmd->callback(priv, priv->cur_cmd->callback_arg,
				(struct cmd_header *) resp);
	} else
801
		ret = handle_cmd_response(priv, 0, resp);
802

803
	spin_lock_irqsave(&priv->driver_lock, flags);
804

805
	if (priv->cur_cmd) {
806
		/* Clean up and Put current command back to cmdfreeq */
807 808
		__lbs_cleanup_and_insert_cmd(priv, priv->cur_cmd);
		priv->cur_cmd = NULL;
809
	}
810
	spin_unlock_irqrestore(&priv->driver_lock, flags);
811 812

done:
813
	mutex_unlock(&priv->lock);
814
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
815 816 817
	return ret;
}

818
int lbs_process_event(struct lbs_private *priv)
819 820 821 822
{
	int ret = 0;
	u32 eventcause;

823 824
	lbs_deb_enter(LBS_DEB_CMD);

825 826 827
	spin_lock_irq(&priv->driver_lock);
	eventcause = priv->eventcause >> SBI_EVENT_CAUSE_SHIFT;
	spin_unlock_irq(&priv->driver_lock);
828

829
	lbs_deb_cmd("event cause %d\n", eventcause);
830

831
	switch (eventcause) {
832
	case MACREG_INT_CODE_LINK_SENSED:
833
		lbs_deb_cmd("EVENT: MACREG_INT_CODE_LINK_SENSED\n");
834 835 836
		break;

	case MACREG_INT_CODE_DEAUTHENTICATED:
837
		lbs_deb_cmd("EVENT: deauthenticated\n");
838
		lbs_mac_event_disconnected(priv);
839 840 841
		break;

	case MACREG_INT_CODE_DISASSOCIATED:
842
		lbs_deb_cmd("EVENT: disassociated\n");
843
		lbs_mac_event_disconnected(priv);
844 845
		break;

846
	case MACREG_INT_CODE_LINK_LOST_NO_SCAN:
847
		lbs_deb_cmd("EVENT: link lost\n");
848
		lbs_mac_event_disconnected(priv);
849 850 851
		break;

	case MACREG_INT_CODE_PS_SLEEP:
852
		lbs_deb_cmd("EVENT: sleep\n");
853 854

		/* handle unexpected PS SLEEP event */
855
		if (priv->psstate == PS_STATE_FULL_POWER) {
856
			lbs_deb_cmd(
857
			       "EVENT: in FULL POWER mode, ignoreing PS_SLEEP\n");
858 859
			break;
		}
860
		priv->psstate = PS_STATE_PRE_SLEEP;
861

862
		lbs_ps_confirm_sleep(priv, (u16) priv->psmode);
863 864 865 866

		break;

	case MACREG_INT_CODE_PS_AWAKE:
867
		lbs_deb_cmd("EVENT: awake\n");
868 869

		/* handle unexpected PS AWAKE event */
870
		if (priv->psstate == PS_STATE_FULL_POWER) {
871
			lbs_deb_cmd(
872 873 874 875
			       "EVENT: In FULL POWER mode - ignore PS AWAKE\n");
			break;
		}

876
		priv->psstate = PS_STATE_AWAKE;
877

878
		if (priv->needtowakeup) {
879 880 881
			/*
			 * wait for the command processing to finish
			 * before resuming sending
882
			 * priv->needtowakeup will be set to FALSE
883
			 * in lbs_ps_wakeup()
884
			 */
885
			lbs_deb_cmd("waking up ...\n");
886
			lbs_ps_wakeup(priv, 0);
887 888 889 890
		}
		break;

	case MACREG_INT_CODE_MIC_ERR_UNICAST:
891
		lbs_deb_cmd("EVENT: UNICAST MIC ERROR\n");
892 893 894 895
		handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_UNICAST);
		break;

	case MACREG_INT_CODE_MIC_ERR_MULTICAST:
896
		lbs_deb_cmd("EVENT: MULTICAST MIC ERROR\n");
897 898 899 900 901 902 903
		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:
904
		lbs_deb_cmd("EVENT: ADHOC beacon lost\n");
905 906 907
		break;

	case MACREG_INT_CODE_RSSI_LOW:
908
		lbs_pr_alert("EVENT: rssi low\n");
909 910
		break;
	case MACREG_INT_CODE_SNR_LOW:
911
		lbs_pr_alert("EVENT: snr low\n");
912 913
		break;
	case MACREG_INT_CODE_MAX_FAIL:
914
		lbs_pr_alert("EVENT: max fail\n");
915 916
		break;
	case MACREG_INT_CODE_RSSI_HIGH:
917
		lbs_pr_alert("EVENT: rssi high\n");
918 919
		break;
	case MACREG_INT_CODE_SNR_HIGH:
920
		lbs_pr_alert("EVENT: snr high\n");
921 922
		break;

923
	case MACREG_INT_CODE_MESH_AUTO_STARTED:
924 925 926 927 928
		/* Ignore spurious autostart events if autostart is disabled */
		if (!priv->mesh_autostart_enabled) {
			lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n");
			break;
		}
929
		lbs_pr_info("EVENT: MESH_AUTO_STARTED\n");
930
		priv->mesh_connect_status = LBS_CONNECTED;
931
		if (priv->mesh_open == 1) {
932 933
			netif_wake_queue(priv->mesh_dev);
			netif_carrier_on(priv->mesh_dev);
934
		}
935
		priv->mode = IW_MODE_ADHOC;
936
		schedule_work(&priv->sync_channel);
937 938
		break;

939
	default:
940
		lbs_pr_alert("EVENT: unknown event id %d\n", eventcause);
941 942 943
		break;
	}

944 945 946
	spin_lock_irq(&priv->driver_lock);
	priv->eventcause = 0;
	spin_unlock_irq(&priv->driver_lock);
947

948
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
949 950
	return ret;
}