cmdresp.c 16.0 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 14 15
#include <net/iw_handler.h>

#include "host.h"
#include "decl.h"
#include "defs.h"
#include "dev.h"
16
#include "assoc.h"
17 18 19 20 21 22 23
#include "wext.h"

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

31
	if (priv->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

	/* report disconnect to upper layer */
48 49
	netif_stop_queue(priv->dev);
	netif_carrier_off(priv->dev);
50

51 52 53 54 55
	/* Free Tx and Rx packets */
	kfree_skb(priv->currenttxskb);
	priv->currenttxskb = NULL;
	priv->tx_pending_len = 0;

56
	/* reset SNR/NF/RSSI values */
57 58 59 60 61 62 63 64
	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;
65

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

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

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

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

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

107
static int lbs_ret_reg_access(struct lbs_private *priv,
108 109
			       u16 type, struct cmd_ds_command *resp)
{
110
	int ret = 0;
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
			priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
			priv->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 129
			priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
			priv->offsetvalue.value = reg->value;
130 131 132
			break;
		}

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

137 138
			priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
			priv->offsetvalue.value = reg->value;
139 140 141 142
			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_802_11_rssi(struct lbs_private *priv,
151 152 153 154
				struct cmd_ds_command *resp)
{
	struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp;

155 156
	lbs_deb_enter(LBS_DEB_CMD);

157
	/* store the non average value */
158 159
	priv->SNR[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->SNR);
	priv->NF[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->noisefloor);
160

161 162
	priv->SNR[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgSNR);
	priv->NF[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgnoisefloor);
163

164 165 166
	priv->RSSI[TYPE_BEACON][TYPE_NOAVG] =
	    CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],
		     priv->NF[TYPE_BEACON][TYPE_NOAVG]);
167

168 169 170
	priv->RSSI[TYPE_BEACON][TYPE_AVG] =
	    CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
		     priv->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
171

172
	lbs_deb_cmd("RSSI: beacon %d, avg %d\n",
173 174
	       priv->RSSI[TYPE_BEACON][TYPE_NOAVG],
	       priv->RSSI[TYPE_BEACON][TYPE_AVG]);
175

176
	lbs_deb_leave(LBS_DEB_CMD);
177 178 179
	return 0;
}

180 181 182 183 184 185 186 187 188
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) {
189 190
		priv->beacon_enable = (u8) le16_to_cpu(bcn_ctrl->beacon_enable);
		priv->beacon_period = le16_to_cpu(bcn_ctrl->beacon_period);
191 192 193 194 195 196
	}

	lbs_deb_enter(LBS_DEB_CMD);
	return 0;
}

197
static inline int handle_cmd_response(struct lbs_private *priv,
198
				      struct cmd_header *cmd_response)
199
{
200
	struct cmd_ds_command *resp = (struct cmd_ds_command *) cmd_response;
201 202
	int ret = 0;
	unsigned long flags;
203
	uint16_t respcmd = le16_to_cpu(resp->command);
204

205 206
	lbs_deb_enter(LBS_DEB_HOST);

207
	switch (respcmd) {
208 209 210
	case CMD_RET(CMD_MAC_REG_ACCESS):
	case CMD_RET(CMD_BBP_REG_ACCESS):
	case CMD_RET(CMD_RF_REG_ACCESS):
211
		ret = lbs_ret_reg_access(priv, respcmd, resp);
212 213
		break;

214 215
	case CMD_RET(CMD_802_11_SET_AFC):
	case CMD_RET(CMD_802_11_GET_AFC):
216
		spin_lock_irqsave(&priv->driver_lock, flags);
217
		memmove((void *)priv->cur_cmd->callback_arg, &resp->params.afc,
218
			sizeof(struct cmd_ds_802_11_afc));
219
		spin_unlock_irqrestore(&priv->driver_lock, flags);
220 221 222

		break;

223
	case CMD_RET(CMD_802_11_BEACON_STOP):
224 225
		break;

226
	case CMD_RET(CMD_802_11_RSSI):
227
		ret = lbs_ret_802_11_rssi(priv, resp);
228 229
		break;

230
	case CMD_RET(CMD_802_11D_DOMAIN_INFO):
231
		ret = lbs_ret_802_11d_domain_info(resp);
232 233
		break;

234
	case CMD_RET(CMD_802_11_TPC_CFG):
235
		spin_lock_irqsave(&priv->driver_lock, flags);
236
		memmove((void *)priv->cur_cmd->callback_arg, &resp->params.tpccfg,
237
			sizeof(struct cmd_ds_802_11_tpc_cfg));
238
		spin_unlock_irqrestore(&priv->driver_lock, flags);
239
		break;
240
	case CMD_RET(CMD_802_11_LED_GPIO_CTRL):
241
		spin_lock_irqsave(&priv->driver_lock, flags);
242
		memmove((void *)priv->cur_cmd->callback_arg, &resp->params.ledgpio,
243
			sizeof(struct cmd_ds_802_11_led_ctrl));
244
		spin_unlock_irqrestore(&priv->driver_lock, flags);
245
		break;
246

247
	case CMD_RET(CMD_GET_TSF):
248
		spin_lock_irqsave(&priv->driver_lock, flags);
249
		memcpy((void *)priv->cur_cmd->callback_arg,
250
		       &resp->params.gettsf.tsfvalue, sizeof(u64));
251
		spin_unlock_irqrestore(&priv->driver_lock, flags);
252
		break;
253
	case CMD_RET(CMD_BT_ACCESS):
254
		spin_lock_irqsave(&priv->driver_lock, flags);
255 256
		if (priv->cur_cmd->callback_arg)
			memcpy((void *)priv->cur_cmd->callback_arg,
257
			       &resp->params.bt.addr1, 2 * ETH_ALEN);
258
		spin_unlock_irqrestore(&priv->driver_lock, flags);
259
		break;
260
	case CMD_RET(CMD_FWT_ACCESS):
261
		spin_lock_irqsave(&priv->driver_lock, flags);
262 263
		if (priv->cur_cmd->callback_arg)
			memcpy((void *)priv->cur_cmd->callback_arg, &resp->params.fwt,
264
			       sizeof(resp->params.fwt));
265
		spin_unlock_irqrestore(&priv->driver_lock, flags);
266
		break;
267 268 269 270
	case CMD_RET(CMD_802_11_BEACON_CTRL):
		ret = lbs_ret_802_11_bcn_ctrl(priv, resp);
		break;

271
	default:
272 273
		lbs_pr_err("CMD_RESP: unknown cmd response 0x%04x\n",
			   le16_to_cpu(resp->command));
274 275
		break;
	}
276
	lbs_deb_leave(LBS_DEB_HOST);
277 278 279
	return ret;
}

280
int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
281
{
282
	uint16_t respcmd, curcmd;
283
	struct cmd_header *resp;
284
	int ret = 0;
285 286
	unsigned long flags;
	uint16_t result;
287

288
	lbs_deb_enter(LBS_DEB_HOST);
289

290 291
	mutex_lock(&priv->lock);
	spin_lock_irqsave(&priv->driver_lock, flags);
292

293
	if (!priv->cur_cmd) {
294
		lbs_deb_host("CMD_RESP: cur_cmd is NULL\n");
295
		ret = -1;
296
		spin_unlock_irqrestore(&priv->driver_lock, flags);
297 298
		goto done;
	}
299

300
	resp = (void *)data;
301
	curcmd = le16_to_cpu(priv->cur_cmd->cmdbuf->command);
302 303 304
	respcmd = le16_to_cpu(resp->command);
	result = le16_to_cpu(resp->result);

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

309
	if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) {
310
		lbs_pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n",
311
			    le16_to_cpu(resp->seqnum), le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum));
312
		spin_unlock_irqrestore(&priv->driver_lock, flags);
313 314 315
		ret = -1;
		goto done;
	}
316
	if (respcmd != CMD_RET(curcmd) &&
317
	    respcmd != CMD_RET_802_11_ASSOCIATE && curcmd != CMD_802_11_ASSOCIATE) {
318 319 320 321 322 323
		lbs_pr_info("Invalid CMD_RESP %x to command %x!\n", respcmd, curcmd);
		spin_unlock_irqrestore(&priv->driver_lock, flags);
		ret = -1;
		goto done;
	}

324 325 326 327 328 329 330 331 332 333
	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;
	}

334 335
	/* Now we got response from FW, cancel the command timer */
	del_timer(&priv->command_timer);
336 337 338 339 340 341
	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;
	}
342 343

	/* Store the response code to cur_cmd_retcode. */
344
	priv->cur_cmd_retcode = result;
345

346
	if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) {
347
		struct cmd_ds_802_11_ps_mode *psmode = (void *) &resp[1];
348
		u16 action = le16_to_cpu(psmode->action);
349

350 351
		lbs_deb_host(
		       "CMD_RESP: PS_MODE cmd reply result 0x%x, action 0x%x\n",
352
		       result, action);
353 354

		if (result) {
355
			lbs_deb_host("CMD_RESP: PS command failed with 0x%x\n",
356 357 358 359
				    result);
			/*
			 * We should not re-try enter-ps command in
			 * ad-hoc mode. It takes place in
360
			 * lbs_execute_next_command().
361
			 */
362
			if (priv->mode == IW_MODE_ADHOC &&
363
			    action == CMD_SUBCMD_ENTER_PS)
364
				priv->psmode = LBS802_11POWERMODECAM;
365
		} else if (action == CMD_SUBCMD_ENTER_PS) {
366 367
			priv->needtowakeup = 0;
			priv->psstate = PS_STATE_AWAKE;
368

369
			lbs_deb_host("CMD_RESP: ENTER_PS command response\n");
370
			if (priv->connect_status != LBS_CONNECTED) {
371 372 373 374
				/*
				 * When Deauth Event received before Enter_PS command
				 * response, We need to wake up the firmware.
				 */
375
				lbs_deb_host(
376
				       "disconnected, invoking lbs_ps_wakeup\n");
377

378 379
				spin_unlock_irqrestore(&priv->driver_lock, flags);
				mutex_unlock(&priv->lock);
380
				lbs_ps_wakeup(priv, 0);
381 382
				mutex_lock(&priv->lock);
				spin_lock_irqsave(&priv->driver_lock, flags);
383
			}
384
		} else if (action == CMD_SUBCMD_EXIT_PS) {
385 386
			priv->needtowakeup = 0;
			priv->psstate = PS_STATE_FULL_POWER;
387
			lbs_deb_host("CMD_RESP: EXIT_PS command response\n");
388
		} else {
389
			lbs_deb_host("CMD_RESP: PS action 0x%X\n", action);
390 391
		}

392
		lbs_complete_command(priv, priv->cur_cmd, result);
393
		spin_unlock_irqrestore(&priv->driver_lock, flags);
394 395 396 397 398 399 400

		ret = 0;
		goto done;
	}

	/* If the command is not successful, cleanup and return failure */
	if ((result != 0 || !(respcmd & 0x8000))) {
401 402
		lbs_deb_host("CMD_RESP: error 0x%04x in command reply 0x%04x\n",
		       result, respcmd);
403 404 405 406
		/*
		 * Handling errors here
		 */
		switch (respcmd) {
407 408
		case CMD_RET(CMD_GET_HW_SPEC):
		case CMD_RET(CMD_802_11_RESET):
409
			lbs_deb_host("CMD_RESP: reset failed\n");
410 411 412
			break;

		}
413
		lbs_complete_command(priv, priv->cur_cmd, result);
414
		spin_unlock_irqrestore(&priv->driver_lock, flags);
415 416 417 418 419

		ret = -1;
		goto done;
	}

420
	spin_unlock_irqrestore(&priv->driver_lock, flags);
421

422 423
	if (priv->cur_cmd && priv->cur_cmd->callback) {
		ret = priv->cur_cmd->callback(priv, priv->cur_cmd->callback_arg,
424
				resp);
425
	} else
426
		ret = handle_cmd_response(priv, resp);
427

428
	spin_lock_irqsave(&priv->driver_lock, flags);
429

430
	if (priv->cur_cmd) {
431
		/* Clean up and Put current command back to cmdfreeq */
432
		lbs_complete_command(priv, priv->cur_cmd, result);
433
	}
434
	spin_unlock_irqrestore(&priv->driver_lock, flags);
435 436

done:
437
	mutex_unlock(&priv->lock);
438
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
439 440 441
	return ret;
}

442 443
static int lbs_send_confirmwake(struct lbs_private *priv)
{
444
	struct cmd_header cmd;
445 446 447 448
	int ret = 0;

	lbs_deb_enter(LBS_DEB_HOST);

449 450 451 452
	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;
453

454 455
	lbs_deb_hex(LBS_DEB_HOST, "wake confirm", (u8 *) &cmd,
		sizeof(cmd));
456

457
	ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &cmd, sizeof(cmd));
458 459 460 461 462 463 464
	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;
}

465
int lbs_process_event(struct lbs_private *priv, u32 event)
466 467 468
{
	int ret = 0;

469 470
	lbs_deb_enter(LBS_DEB_CMD);

471
	switch (event) {
472
	case MACREG_INT_CODE_LINK_SENSED:
473
		lbs_deb_cmd("EVENT: link sensed\n");
474 475 476
		break;

	case MACREG_INT_CODE_DEAUTHENTICATED:
477
		lbs_deb_cmd("EVENT: deauthenticated\n");
478
		lbs_mac_event_disconnected(priv);
479 480 481
		break;

	case MACREG_INT_CODE_DISASSOCIATED:
482
		lbs_deb_cmd("EVENT: disassociated\n");
483
		lbs_mac_event_disconnected(priv);
484 485
		break;

486
	case MACREG_INT_CODE_LINK_LOST_NO_SCAN:
487
		lbs_deb_cmd("EVENT: link lost\n");
488
		lbs_mac_event_disconnected(priv);
489 490 491
		break;

	case MACREG_INT_CODE_PS_SLEEP:
492
		lbs_deb_cmd("EVENT: ps sleep\n");
493 494

		/* handle unexpected PS SLEEP event */
495
		if (priv->psstate == PS_STATE_FULL_POWER) {
496
			lbs_deb_cmd(
497
			       "EVENT: in FULL POWER mode, ignoreing PS_SLEEP\n");
498 499
			break;
		}
500
		priv->psstate = PS_STATE_PRE_SLEEP;
501

502
		lbs_ps_confirm_sleep(priv);
503 504 505

		break;

506
	case MACREG_INT_CODE_HOST_AWAKE:
507
		lbs_deb_cmd("EVENT: host awake\n");
508 509 510
		if (priv->reset_deep_sleep_wakeup)
			priv->reset_deep_sleep_wakeup(priv);
		priv->is_deep_sleep = 0;
511 512 513
		lbs_send_confirmwake(priv);
		break;

514 515 516 517 518 519 520 521 522
	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;

523
	case MACREG_INT_CODE_PS_AWAKE:
524
		lbs_deb_cmd("EVENT: ps awake\n");
525
		/* handle unexpected PS AWAKE event */
526
		if (priv->psstate == PS_STATE_FULL_POWER) {
527
			lbs_deb_cmd(
528 529 530 531
			       "EVENT: In FULL POWER mode - ignore PS AWAKE\n");
			break;
		}

532
		priv->psstate = PS_STATE_AWAKE;
533

534
		if (priv->needtowakeup) {
535 536 537
			/*
			 * wait for the command processing to finish
			 * before resuming sending
538
			 * priv->needtowakeup will be set to FALSE
539
			 * in lbs_ps_wakeup()
540
			 */
541
			lbs_deb_cmd("waking up ...\n");
542
			lbs_ps_wakeup(priv, 0);
543 544 545 546
		}
		break;

	case MACREG_INT_CODE_MIC_ERR_UNICAST:
547
		lbs_deb_cmd("EVENT: UNICAST MIC ERROR\n");
548 549 550 551
		handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_UNICAST);
		break;

	case MACREG_INT_CODE_MIC_ERR_MULTICAST:
552
		lbs_deb_cmd("EVENT: MULTICAST MIC ERROR\n");
553 554
		handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_MULTICAST);
		break;
555

556
	case MACREG_INT_CODE_MIB_CHANGED:
557 558
		lbs_deb_cmd("EVENT: MIB CHANGED\n");
		break;
559
	case MACREG_INT_CODE_INIT_DONE:
560
		lbs_deb_cmd("EVENT: INIT DONE\n");
561 562
		break;
	case MACREG_INT_CODE_ADHOC_BCN_LOST:
563
		lbs_deb_cmd("EVENT: ADHOC beacon lost\n");
564 565
		break;
	case MACREG_INT_CODE_RSSI_LOW:
566
		lbs_pr_alert("EVENT: rssi low\n");
567 568
		break;
	case MACREG_INT_CODE_SNR_LOW:
569
		lbs_pr_alert("EVENT: snr low\n");
570 571
		break;
	case MACREG_INT_CODE_MAX_FAIL:
572
		lbs_pr_alert("EVENT: max fail\n");
573 574
		break;
	case MACREG_INT_CODE_RSSI_HIGH:
575
		lbs_pr_alert("EVENT: rssi high\n");
576 577
		break;
	case MACREG_INT_CODE_SNR_HIGH:
578
		lbs_pr_alert("EVENT: snr high\n");
579 580
		break;

581
	case MACREG_INT_CODE_MESH_AUTO_STARTED:
582 583 584 585 586
		/* Ignore spurious autostart events if autostart is disabled */
		if (!priv->mesh_autostart_enabled) {
			lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n");
			break;
		}
587
		lbs_pr_info("EVENT: MESH_AUTO_STARTED\n");
588
		priv->mesh_connect_status = LBS_CONNECTED;
589
		if (priv->mesh_open) {
590
			netif_carrier_on(priv->mesh_dev);
591 592
			if (!priv->tx_pending_len)
				netif_wake_queue(priv->mesh_dev);
593
		}
594
		priv->mode = IW_MODE_ADHOC;
595
		schedule_work(&priv->sync_channel);
596 597
		break;

598
	default:
599
		lbs_pr_alert("EVENT: unknown event id %d\n", event);
600 601 602
		break;
	}

603
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
604 605
	return ret;
}