cmdresp.c 13.3 KB
Newer Older
1 2 3 4 5
/**
  * This file contains the handling of command
  * responses as well as events generated by firmware.
  */
#include <linux/delay.h>
A
Alan Cox 已提交
6
#include <linux/sched.h>
7 8
#include <linux/if_arp.h>
#include <linux/netdevice.h>
9
#include <asm/unaligned.h>
10 11 12 13
#include <net/iw_handler.h>

#include "host.h"
#include "decl.h"
H
Holger Schurig 已提交
14
#include "cmd.h"
15 16
#include "defs.h"
#include "dev.h"
17
#include "assoc.h"
18 19 20 21 22 23 24
#include "wext.h"

/**
 *  @brief This function handles disconnect event. it
 *  reports disconnect to upper layer, clean tx/rx packets,
 *  reset link state etc.
 *
25
 *  @param priv    A pointer to struct lbs_private structure
26 27
 *  @return 	   n/a
 */
28
void lbs_mac_event_disconnected(struct lbs_private *priv)
29
{
30
	if (priv->connect_status != LBS_CONNECTED)
31 32
		return;

33
	lbs_deb_enter(LBS_DEB_ASSOC);
34 35 36 37 38 39

	/*
	 * Cisco AP sends EAP failure and de-auth in less than 0.5 ms.
	 * It causes problem in the Supplicant
	 */
	msleep_interruptible(1000);
40
	lbs_send_disconnect_notification(priv);
41 42

	/* report disconnect to upper layer */
43 44
	netif_stop_queue(priv->dev);
	netif_carrier_off(priv->dev);
45

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

51
	/* reset SNR/NF/RSSI values */
52 53 54 55 56 57 58 59
	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;
60

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

68
	if (priv->psstate != PS_STATE_FULL_POWER) {
69
		/* make firmware to exit PS mode */
70
		lbs_deb_cmd("disconnected, so exit PS mode\n");
71
		lbs_ps_wakeup(priv, 0);
72
	}
73
	lbs_deb_leave(LBS_DEB_ASSOC);
74 75
}

76
static int lbs_ret_reg_access(struct lbs_private *priv,
77 78
			       u16 type, struct cmd_ds_command *resp)
{
79
	int ret = 0;
80

81
	lbs_deb_enter(LBS_DEB_CMD);
82 83

	switch (type) {
84
	case CMD_RET(CMD_MAC_REG_ACCESS):
85
		{
86
			struct cmd_ds_mac_reg_access *reg = &resp->params.macreg;
87

88 89
			priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
			priv->offsetvalue.value = le32_to_cpu(reg->value);
90 91 92
			break;
		}

93
	case CMD_RET(CMD_BBP_REG_ACCESS):
94
		{
95
			struct cmd_ds_bbp_reg_access *reg = &resp->params.bbpreg;
96

97 98
			priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
			priv->offsetvalue.value = reg->value;
99 100 101
			break;
		}

102
	case CMD_RET(CMD_RF_REG_ACCESS):
103
		{
104
			struct cmd_ds_rf_reg_access *reg = &resp->params.rfreg;
105

106 107
			priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
			priv->offsetvalue.value = reg->value;
108 109 110 111
			break;
		}

	default:
112
		ret = -1;
113 114
	}

115
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
116
	return ret;
117 118
}

119
static inline int handle_cmd_response(struct lbs_private *priv,
120
				      struct cmd_header *cmd_response)
121
{
122
	struct cmd_ds_command *resp = (struct cmd_ds_command *) cmd_response;
123 124
	int ret = 0;
	unsigned long flags;
125
	uint16_t respcmd = le16_to_cpu(resp->command);
126

127 128
	lbs_deb_enter(LBS_DEB_HOST);

129
	switch (respcmd) {
130 131 132
	case CMD_RET(CMD_MAC_REG_ACCESS):
	case CMD_RET(CMD_BBP_REG_ACCESS):
	case CMD_RET(CMD_RF_REG_ACCESS):
133
		ret = lbs_ret_reg_access(priv, respcmd, resp);
134 135
		break;

136 137
	case CMD_RET(CMD_802_11_SET_AFC):
	case CMD_RET(CMD_802_11_GET_AFC):
138
		spin_lock_irqsave(&priv->driver_lock, flags);
139
		memmove((void *)priv->cur_cmd->callback_arg, &resp->params.afc,
140
			sizeof(struct cmd_ds_802_11_afc));
141
		spin_unlock_irqrestore(&priv->driver_lock, flags);
142 143 144

		break;

145
	case CMD_RET(CMD_802_11_BEACON_STOP):
146 147
		break;

148
	case CMD_RET(CMD_802_11_RSSI):
149
		ret = lbs_ret_802_11_rssi(priv, resp);
150 151
		break;

152
	case CMD_RET(CMD_802_11_TPC_CFG):
153
		spin_lock_irqsave(&priv->driver_lock, flags);
154
		memmove((void *)priv->cur_cmd->callback_arg, &resp->params.tpccfg,
155
			sizeof(struct cmd_ds_802_11_tpc_cfg));
156
		spin_unlock_irqrestore(&priv->driver_lock, flags);
157
		break;
158

159
	case CMD_RET(CMD_BT_ACCESS):
160
		spin_lock_irqsave(&priv->driver_lock, flags);
161 162
		if (priv->cur_cmd->callback_arg)
			memcpy((void *)priv->cur_cmd->callback_arg,
163
			       &resp->params.bt.addr1, 2 * ETH_ALEN);
164
		spin_unlock_irqrestore(&priv->driver_lock, flags);
165
		break;
166
	case CMD_RET(CMD_FWT_ACCESS):
167
		spin_lock_irqsave(&priv->driver_lock, flags);
168 169
		if (priv->cur_cmd->callback_arg)
			memcpy((void *)priv->cur_cmd->callback_arg, &resp->params.fwt,
170
			       sizeof(resp->params.fwt));
171
		spin_unlock_irqrestore(&priv->driver_lock, flags);
172
		break;
173 174 175 176
	case CMD_RET(CMD_802_11_BEACON_CTRL):
		ret = lbs_ret_802_11_bcn_ctrl(priv, resp);
		break;

177
	default:
178 179
		lbs_pr_err("CMD_RESP: unknown cmd response 0x%04x\n",
			   le16_to_cpu(resp->command));
180 181
		break;
	}
182
	lbs_deb_leave(LBS_DEB_HOST);
183 184 185
	return ret;
}

186
int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
187
{
188
	uint16_t respcmd, curcmd;
189
	struct cmd_header *resp;
190
	int ret = 0;
191 192
	unsigned long flags;
	uint16_t result;
193

194
	lbs_deb_enter(LBS_DEB_HOST);
195

196 197
	mutex_lock(&priv->lock);
	spin_lock_irqsave(&priv->driver_lock, flags);
198

199
	if (!priv->cur_cmd) {
200
		lbs_deb_host("CMD_RESP: cur_cmd is NULL\n");
201
		ret = -1;
202
		spin_unlock_irqrestore(&priv->driver_lock, flags);
203 204
		goto done;
	}
205

206
	resp = (void *)data;
207
	curcmd = le16_to_cpu(priv->cur_cmd->cmdbuf->command);
208 209 210
	respcmd = le16_to_cpu(resp->command);
	result = le16_to_cpu(resp->result);

H
Holger Schurig 已提交
211
	lbs_deb_cmd("CMD_RESP: response 0x%04x, seq %d, size %d\n",
212 213
		     respcmd, le16_to_cpu(resp->seqnum), len);
	lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", (void *) resp, len);
214

215
	if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) {
216
		lbs_pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n",
217
			    le16_to_cpu(resp->seqnum), le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum));
218
		spin_unlock_irqrestore(&priv->driver_lock, flags);
219 220 221
		ret = -1;
		goto done;
	}
222
	if (respcmd != CMD_RET(curcmd) &&
223
	    respcmd != CMD_RET_802_11_ASSOCIATE && curcmd != CMD_802_11_ASSOCIATE) {
224 225 226 227 228 229
		lbs_pr_info("Invalid CMD_RESP %x to command %x!\n", respcmd, curcmd);
		spin_unlock_irqrestore(&priv->driver_lock, flags);
		ret = -1;
		goto done;
	}

230 231 232 233 234 235 236 237 238 239
	if (resp->result == cpu_to_le16(0x0004)) {
		/* 0x0004 means -EAGAIN. Drop the response, let it time out
		   and be resubmitted */
		lbs_pr_info("Firmware returns DEFER to command %x. Will let it time out...\n",
			    le16_to_cpu(resp->command));
		spin_unlock_irqrestore(&priv->driver_lock, flags);
		ret = -1;
		goto done;
	}

240 241
	/* Now we got response from FW, cancel the command timer */
	del_timer(&priv->command_timer);
242 243 244 245 246 247
	priv->cmd_timed_out = 0;
	if (priv->nr_retries) {
		lbs_pr_info("Received result %x to command %x after %d retries\n",
			    result, curcmd, priv->nr_retries);
		priv->nr_retries = 0;
	}
248 249

	/* Store the response code to cur_cmd_retcode. */
250
	priv->cur_cmd_retcode = result;
251

252
	if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) {
253
		struct cmd_ds_802_11_ps_mode *psmode = (void *) &resp[1];
254
		u16 action = le16_to_cpu(psmode->action);
255

256 257
		lbs_deb_host(
		       "CMD_RESP: PS_MODE cmd reply result 0x%x, action 0x%x\n",
258
		       result, action);
259 260

		if (result) {
261
			lbs_deb_host("CMD_RESP: PS command failed with 0x%x\n",
262 263 264 265
				    result);
			/*
			 * We should not re-try enter-ps command in
			 * ad-hoc mode. It takes place in
266
			 * lbs_execute_next_command().
267
			 */
268
			if (priv->mode == IW_MODE_ADHOC &&
269
			    action == CMD_SUBCMD_ENTER_PS)
270
				priv->psmode = LBS802_11POWERMODECAM;
271
		} else if (action == CMD_SUBCMD_ENTER_PS) {
272 273
			priv->needtowakeup = 0;
			priv->psstate = PS_STATE_AWAKE;
274

275
			lbs_deb_host("CMD_RESP: ENTER_PS command response\n");
276
			if (priv->connect_status != LBS_CONNECTED) {
277 278 279 280
				/*
				 * When Deauth Event received before Enter_PS command
				 * response, We need to wake up the firmware.
				 */
281
				lbs_deb_host(
282
				       "disconnected, invoking lbs_ps_wakeup\n");
283

284 285
				spin_unlock_irqrestore(&priv->driver_lock, flags);
				mutex_unlock(&priv->lock);
286
				lbs_ps_wakeup(priv, 0);
287 288
				mutex_lock(&priv->lock);
				spin_lock_irqsave(&priv->driver_lock, flags);
289
			}
290
		} else if (action == CMD_SUBCMD_EXIT_PS) {
291 292
			priv->needtowakeup = 0;
			priv->psstate = PS_STATE_FULL_POWER;
293
			lbs_deb_host("CMD_RESP: EXIT_PS command response\n");
294
		} else {
295
			lbs_deb_host("CMD_RESP: PS action 0x%X\n", action);
296 297
		}

298
		lbs_complete_command(priv, priv->cur_cmd, result);
299
		spin_unlock_irqrestore(&priv->driver_lock, flags);
300 301 302 303 304 305 306

		ret = 0;
		goto done;
	}

	/* If the command is not successful, cleanup and return failure */
	if ((result != 0 || !(respcmd & 0x8000))) {
307 308
		lbs_deb_host("CMD_RESP: error 0x%04x in command reply 0x%04x\n",
		       result, respcmd);
309 310 311 312
		/*
		 * Handling errors here
		 */
		switch (respcmd) {
313 314
		case CMD_RET(CMD_GET_HW_SPEC):
		case CMD_RET(CMD_802_11_RESET):
315
			lbs_deb_host("CMD_RESP: reset failed\n");
316 317 318
			break;

		}
319
		lbs_complete_command(priv, priv->cur_cmd, result);
320
		spin_unlock_irqrestore(&priv->driver_lock, flags);
321 322 323 324 325

		ret = -1;
		goto done;
	}

326
	spin_unlock_irqrestore(&priv->driver_lock, flags);
327

328 329
	if (priv->cur_cmd && priv->cur_cmd->callback) {
		ret = priv->cur_cmd->callback(priv, priv->cur_cmd->callback_arg,
330
				resp);
331
	} else
332
		ret = handle_cmd_response(priv, resp);
333

334
	spin_lock_irqsave(&priv->driver_lock, flags);
335

336
	if (priv->cur_cmd) {
337
		/* Clean up and Put current command back to cmdfreeq */
338
		lbs_complete_command(priv, priv->cur_cmd, result);
339
	}
340
	spin_unlock_irqrestore(&priv->driver_lock, flags);
341 342

done:
343
	mutex_unlock(&priv->lock);
344
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
345 346 347
	return ret;
}

348 349
static int lbs_send_confirmwake(struct lbs_private *priv)
{
350
	struct cmd_header cmd;
351 352 353 354
	int ret = 0;

	lbs_deb_enter(LBS_DEB_HOST);

355 356 357 358
	cmd.command = cpu_to_le16(CMD_802_11_WAKEUP_CONFIRM);
	cmd.size = cpu_to_le16(sizeof(cmd));
	cmd.seqnum = cpu_to_le16(++priv->seqnum);
	cmd.result = 0;
359

360 361
	lbs_deb_hex(LBS_DEB_HOST, "wake confirm", (u8 *) &cmd,
		sizeof(cmd));
362

363
	ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &cmd, sizeof(cmd));
364 365 366 367 368 369 370
	if (ret)
		lbs_pr_alert("SEND_WAKEC_CMD: Host to Card failed for Confirm Wake\n");

	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
	return ret;
}

371
int lbs_process_event(struct lbs_private *priv, u32 event)
372 373 374
{
	int ret = 0;

375 376
	lbs_deb_enter(LBS_DEB_CMD);

377
	switch (event) {
378
	case MACREG_INT_CODE_LINK_SENSED:
379
		lbs_deb_cmd("EVENT: link sensed\n");
380 381 382
		break;

	case MACREG_INT_CODE_DEAUTHENTICATED:
383
		lbs_deb_cmd("EVENT: deauthenticated\n");
384
		lbs_mac_event_disconnected(priv);
385 386 387
		break;

	case MACREG_INT_CODE_DISASSOCIATED:
388
		lbs_deb_cmd("EVENT: disassociated\n");
389
		lbs_mac_event_disconnected(priv);
390 391
		break;

392
	case MACREG_INT_CODE_LINK_LOST_NO_SCAN:
393
		lbs_deb_cmd("EVENT: link lost\n");
394
		lbs_mac_event_disconnected(priv);
395 396 397
		break;

	case MACREG_INT_CODE_PS_SLEEP:
398
		lbs_deb_cmd("EVENT: ps sleep\n");
399 400

		/* handle unexpected PS SLEEP event */
401
		if (priv->psstate == PS_STATE_FULL_POWER) {
402
			lbs_deb_cmd(
403
			       "EVENT: in FULL POWER mode, ignoreing PS_SLEEP\n");
404 405
			break;
		}
406
		priv->psstate = PS_STATE_PRE_SLEEP;
407

408
		lbs_ps_confirm_sleep(priv);
409 410 411

		break;

412
	case MACREG_INT_CODE_HOST_AWAKE:
413
		lbs_deb_cmd("EVENT: host awake\n");
414 415 416
		if (priv->reset_deep_sleep_wakeup)
			priv->reset_deep_sleep_wakeup(priv);
		priv->is_deep_sleep = 0;
417 418 419
		lbs_send_confirmwake(priv);
		break;

420 421 422 423 424 425 426 427 428
	case MACREG_INT_CODE_DEEP_SLEEP_AWAKE:
		if (priv->reset_deep_sleep_wakeup)
			priv->reset_deep_sleep_wakeup(priv);
		lbs_deb_cmd("EVENT: ds awake\n");
		priv->is_deep_sleep = 0;
		priv->wakeup_dev_required = 0;
		wake_up_interruptible(&priv->ds_awake_q);
		break;

429
	case MACREG_INT_CODE_PS_AWAKE:
430
		lbs_deb_cmd("EVENT: ps awake\n");
431
		/* handle unexpected PS AWAKE event */
432
		if (priv->psstate == PS_STATE_FULL_POWER) {
433
			lbs_deb_cmd(
434 435 436 437
			       "EVENT: In FULL POWER mode - ignore PS AWAKE\n");
			break;
		}

438
		priv->psstate = PS_STATE_AWAKE;
439

440
		if (priv->needtowakeup) {
441 442 443
			/*
			 * wait for the command processing to finish
			 * before resuming sending
444
			 * priv->needtowakeup will be set to FALSE
445
			 * in lbs_ps_wakeup()
446
			 */
447
			lbs_deb_cmd("waking up ...\n");
448
			lbs_ps_wakeup(priv, 0);
449 450 451 452
		}
		break;

	case MACREG_INT_CODE_MIC_ERR_UNICAST:
453
		lbs_deb_cmd("EVENT: UNICAST MIC ERROR\n");
454
		lbs_send_mic_failureevent(priv, event);
455 456 457
		break;

	case MACREG_INT_CODE_MIC_ERR_MULTICAST:
458
		lbs_deb_cmd("EVENT: MULTICAST MIC ERROR\n");
459
		lbs_send_mic_failureevent(priv, event);
460
		break;
461

462
	case MACREG_INT_CODE_MIB_CHANGED:
463 464
		lbs_deb_cmd("EVENT: MIB CHANGED\n");
		break;
465
	case MACREG_INT_CODE_INIT_DONE:
466
		lbs_deb_cmd("EVENT: INIT DONE\n");
467 468
		break;
	case MACREG_INT_CODE_ADHOC_BCN_LOST:
469
		lbs_deb_cmd("EVENT: ADHOC beacon lost\n");
470 471
		break;
	case MACREG_INT_CODE_RSSI_LOW:
472
		lbs_pr_alert("EVENT: rssi low\n");
473 474
		break;
	case MACREG_INT_CODE_SNR_LOW:
475
		lbs_pr_alert("EVENT: snr low\n");
476 477
		break;
	case MACREG_INT_CODE_MAX_FAIL:
478
		lbs_pr_alert("EVENT: max fail\n");
479 480
		break;
	case MACREG_INT_CODE_RSSI_HIGH:
481
		lbs_pr_alert("EVENT: rssi high\n");
482 483
		break;
	case MACREG_INT_CODE_SNR_HIGH:
484
		lbs_pr_alert("EVENT: snr high\n");
485 486
		break;

487
	case MACREG_INT_CODE_MESH_AUTO_STARTED:
488 489 490 491 492
		/* Ignore spurious autostart events if autostart is disabled */
		if (!priv->mesh_autostart_enabled) {
			lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n");
			break;
		}
493
		lbs_pr_info("EVENT: MESH_AUTO_STARTED\n");
494
		priv->mesh_connect_status = LBS_CONNECTED;
495
		if (priv->mesh_open) {
496
			netif_carrier_on(priv->mesh_dev);
497 498
			if (!priv->tx_pending_len)
				netif_wake_queue(priv->mesh_dev);
499
		}
500
		priv->mode = IW_MODE_ADHOC;
501
		schedule_work(&priv->sync_channel);
502 503
		break;

504
	default:
505
		lbs_pr_alert("EVENT: unknown event id %d\n", event);
506 507 508
		break;
	}

509
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
510 511
	return ret;
}