Home | History | Annotate | Download | only in sys
      1 /*
      2  * Broadcom Dongle Host Driver (DHD), common DHD core.
      3  *
      4  * Copyright (C) 1999-2010, Broadcom Corporation
      5  *
      6  *      Unless you and Broadcom execute a separate written software license
      7  * agreement governing use of this software, this software is licensed to you
      8  * under the terms of the GNU General Public License version 2 (the "GPL"),
      9  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
     10  * following added to such license:
     11  *
     12  *      As a special exception, the copyright holders of this software give you
     13  * permission to link this software with independent modules, and to copy and
     14  * distribute the resulting executable under terms of your choice, provided that
     15  * you also meet, for each linked independent module, the terms and conditions of
     16  * the license of that module.  An independent module is a module which is not
     17  * derived from this software.  The special exception does not apply to any
     18  * modifications of the software.
     19  *
     20  *      Notwithstanding the above, under no circumstances may you combine this
     21  * software in any way with any other Broadcom software provided under a license
     22  * other than the GPL, without Broadcom's express prior written consent.
     23  *
     24  * $Id: dhd_common.c,v 1.5.6.8.2.6.6.41 2010/02/24 01:52:41 Exp $
     25  */
     26 #include <typedefs.h>
     27 #include <osl.h>
     28 
     29 #include <epivers.h>
     30 #include <bcmutils.h>
     31 
     32 #include <bcmendian.h>
     33 #include <dngl_stats.h>
     34 #include <dhd.h>
     35 #include <dhd_bus.h>
     36 #include <dhd_proto.h>
     37 #include <dhd_dbg.h>
     38 #include <msgtrace.h>
     39 
     40 
     41 int dhd_msg_level;
     42 
     43 char fw_path[MOD_PARAM_PATHLEN];
     44 char nv_path[MOD_PARAM_PATHLEN];
     45 
     46 /* Last connection success/failure status */
     47 uint32 dhd_conn_event;
     48 uint32 dhd_conn_status;
     49 uint32 dhd_conn_reason;
     50 
     51 #ifdef DHD_DEBUG
     52 const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR "\nCompiled on "
     53 	__DATE__ " at " __TIME__;
     54 #else
     55 const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR;
     56 #endif
     57 
     58 void dhd_set_timer(void *bus, uint wdtick);
     59 
     60 
     61 /* IOVar table */
     62 enum {
     63 	IOV_VERSION = 1,
     64 	IOV_MSGLEVEL,
     65 	IOV_BCMERRORSTR,
     66 	IOV_BCMERROR,
     67 	IOV_WDTICK,
     68 	IOV_DUMP,
     69 	IOV_CLEARCOUNTS,
     70 	IOV_LOGDUMP,
     71 	IOV_LOGCAL,
     72 	IOV_LOGSTAMP,
     73 	IOV_GPIOOB,
     74 	IOV_IOCTLTIMEOUT,
     75 	IOV_LAST
     76 };
     77 
     78 const bcm_iovar_t dhd_iovars[] = {
     79 	{"version", 	IOV_VERSION,	0,	IOVT_BUFFER,	sizeof(dhd_version) },
     80 #ifdef DHD_DEBUG
     81 	{"msglevel",	IOV_MSGLEVEL,	0,	IOVT_UINT32,	0 },
     82 #endif /* DHD_DEBUG */
     83 	{"bcmerrorstr", IOV_BCMERRORSTR, 0, IOVT_BUFFER,	BCME_STRLEN },
     84 	{"bcmerror",	IOV_BCMERROR,	0,	IOVT_INT8,	0 },
     85 	{"wdtick",	IOV_WDTICK, 0,	IOVT_UINT32,	0 },
     86 	{"dump",	IOV_DUMP,	0,	IOVT_BUFFER,	DHD_IOCTL_MAXLEN },
     87 	{"clearcounts", IOV_CLEARCOUNTS, 0, IOVT_VOID,	0 },
     88 	{"gpioob",	IOV_GPIOOB,	0,	IOVT_UINT32,	0 },
     89 	{"ioctl_timeout",	IOV_IOCTLTIMEOUT,	0,	IOVT_UINT32,	0 },
     90 	{NULL, 0, 0, 0, 0 }
     91 };
     92 
     93 void
     94 dhd_common_init(void)
     95 {
     96 	/* Init global variables at run-time, not as part of the declaration.
     97 	 * This is required to support init/de-init of the driver. Initialization
     98 	 * of globals as part of the declaration results in non-deterministic
     99 	 * behaviour since the value of the globals may be different on the
    100 	 * first time that the driver is initialized vs subsequent initializations.
    101 	 */
    102 	dhd_msg_level = DHD_ERROR_VAL;
    103 #ifdef CONFIG_BCM4329_FW_PATH
    104 	strncpy(fw_path, CONFIG_BCM4329_FW_PATH, MOD_PARAM_PATHLEN-1);
    105 #else
    106 	fw_path[0] = '\0';
    107 #endif
    108 #ifdef CONFIG_BCM4329_NVRAM_PATH
    109 	strncpy(nv_path, CONFIG_BCM4329_NVRAM_PATH, MOD_PARAM_PATHLEN-1);
    110 #else
    111 	nv_path[0] = '\0';
    112 #endif
    113 }
    114 
    115 static int
    116 dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen)
    117 {
    118 	char eabuf[ETHER_ADDR_STR_LEN];
    119 
    120 	struct bcmstrbuf b;
    121 	struct bcmstrbuf *strbuf = &b;
    122 
    123 	bcm_binit(strbuf, buf, buflen);
    124 
    125 	/* Base DHD info */
    126 	bcm_bprintf(strbuf, "%s\n", dhd_version);
    127 	bcm_bprintf(strbuf, "\n");
    128 	bcm_bprintf(strbuf, "pub.up %d pub.txoff %d pub.busstate %d\n",
    129 	            dhdp->up, dhdp->txoff, dhdp->busstate);
    130 	bcm_bprintf(strbuf, "pub.hdrlen %d pub.maxctl %d pub.rxsz %d\n",
    131 	            dhdp->hdrlen, dhdp->maxctl, dhdp->rxsz);
    132 	bcm_bprintf(strbuf, "pub.iswl %d pub.drv_version %ld pub.mac %s\n",
    133 	            dhdp->iswl, dhdp->drv_version, bcm_ether_ntoa(&dhdp->mac, eabuf));
    134 	bcm_bprintf(strbuf, "pub.bcmerror %d tickcnt %d\n", dhdp->bcmerror, dhdp->tickcnt);
    135 
    136 	bcm_bprintf(strbuf, "dongle stats:\n");
    137 	bcm_bprintf(strbuf, "tx_packets %ld tx_bytes %ld tx_errors %ld tx_dropped %ld\n",
    138 	            dhdp->dstats.tx_packets, dhdp->dstats.tx_bytes,
    139 	            dhdp->dstats.tx_errors, dhdp->dstats.tx_dropped);
    140 	bcm_bprintf(strbuf, "rx_packets %ld rx_bytes %ld rx_errors %ld rx_dropped %ld\n",
    141 	            dhdp->dstats.rx_packets, dhdp->dstats.rx_bytes,
    142 	            dhdp->dstats.rx_errors, dhdp->dstats.rx_dropped);
    143 	bcm_bprintf(strbuf, "multicast %ld\n", dhdp->dstats.multicast);
    144 
    145 	bcm_bprintf(strbuf, "bus stats:\n");
    146 	bcm_bprintf(strbuf, "tx_packets %ld tx_multicast %ld tx_errors %ld\n",
    147 	            dhdp->tx_packets, dhdp->tx_multicast, dhdp->tx_errors);
    148 	bcm_bprintf(strbuf, "tx_ctlpkts %ld tx_ctlerrs %ld\n",
    149 	            dhdp->tx_ctlpkts, dhdp->tx_ctlerrs);
    150 	bcm_bprintf(strbuf, "rx_packets %ld rx_multicast %ld rx_errors %ld \n",
    151 	            dhdp->rx_packets, dhdp->rx_multicast, dhdp->rx_errors);
    152 	bcm_bprintf(strbuf, "rx_ctlpkts %ld rx_ctlerrs %ld rx_dropped %ld rx_flushed %ld\n",
    153 	            dhdp->rx_ctlpkts, dhdp->rx_ctlerrs, dhdp->rx_dropped, dhdp->rx_flushed);
    154 	bcm_bprintf(strbuf, "rx_readahead_cnt %ld tx_realloc %ld fc_packets %ld\n",
    155 	            dhdp->rx_readahead_cnt, dhdp->tx_realloc, dhdp->fc_packets);
    156 	bcm_bprintf(strbuf, "wd_dpc_sched %ld\n", dhdp->wd_dpc_sched);
    157 	bcm_bprintf(strbuf, "\n");
    158 
    159 	/* Add any prot info */
    160 	dhd_prot_dump(dhdp, strbuf);
    161 	bcm_bprintf(strbuf, "\n");
    162 
    163 	/* Add any bus info */
    164 	dhd_bus_dump(dhdp, strbuf);
    165 
    166 	return (!strbuf->size ? BCME_BUFTOOSHORT : 0);
    167 }
    168 
    169 static int
    170 dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const char *name,
    171             void *params, int plen, void *arg, int len, int val_size)
    172 {
    173 	int bcmerror = 0;
    174 	int32 int_val = 0;
    175 
    176 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
    177 
    178 	if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0)
    179 		goto exit;
    180 
    181 	if (plen >= (int)sizeof(int_val))
    182 		bcopy(params, &int_val, sizeof(int_val));
    183 
    184 	switch (actionid) {
    185 	case IOV_GVAL(IOV_VERSION):
    186 		/* Need to have checked buffer length */
    187 		strncpy((char*)arg, dhd_version, len);
    188 		break;
    189 
    190 	case IOV_GVAL(IOV_MSGLEVEL):
    191 		int_val = (int32)dhd_msg_level;
    192 		bcopy(&int_val, arg, val_size);
    193 		break;
    194 
    195 	case IOV_SVAL(IOV_MSGLEVEL):
    196 		dhd_msg_level = int_val;
    197 		break;
    198 
    199 	case IOV_GVAL(IOV_BCMERRORSTR):
    200 		strncpy((char *)arg, bcmerrorstr(dhd_pub->bcmerror), BCME_STRLEN);
    201 		((char *)arg)[BCME_STRLEN - 1] = 0x00;
    202 		break;
    203 
    204 	case IOV_GVAL(IOV_BCMERROR):
    205 		int_val = (int32)dhd_pub->bcmerror;
    206 		bcopy(&int_val, arg, val_size);
    207 		break;
    208 
    209 	case IOV_GVAL(IOV_WDTICK):
    210 		int_val = (int32)dhd_watchdog_ms;
    211 		bcopy(&int_val, arg, val_size);
    212 		break;
    213 
    214 	case IOV_SVAL(IOV_WDTICK):
    215 		if (!dhd_pub->up) {
    216 			bcmerror = BCME_NOTUP;
    217 			break;
    218 		}
    219 		dhd_os_wd_timer(dhd_pub, (uint)int_val);
    220 		break;
    221 
    222 	case IOV_GVAL(IOV_DUMP):
    223 		bcmerror = dhd_dump(dhd_pub, arg, len);
    224 		break;
    225 
    226 
    227 	case IOV_SVAL(IOV_CLEARCOUNTS):
    228 		dhd_pub->tx_packets = dhd_pub->rx_packets = 0;
    229 		dhd_pub->tx_errors = dhd_pub->rx_errors = 0;
    230 		dhd_pub->tx_ctlpkts = dhd_pub->rx_ctlpkts = 0;
    231 		dhd_pub->tx_ctlerrs = dhd_pub->rx_ctlerrs = 0;
    232 		dhd_pub->rx_dropped = 0;
    233 		dhd_pub->rx_readahead_cnt = 0;
    234 		dhd_pub->tx_realloc = 0;
    235 		dhd_pub->wd_dpc_sched = 0;
    236 		memset(&dhd_pub->dstats, 0, sizeof(dhd_pub->dstats));
    237 		dhd_bus_clearcounts(dhd_pub);
    238 		break;
    239 
    240 
    241 	case IOV_GVAL(IOV_IOCTLTIMEOUT): {
    242 		int_val = (int32)dhd_os_get_ioctl_resp_timeout();
    243 		bcopy(&int_val, arg, sizeof(int_val));
    244 		break;
    245 	}
    246 
    247 	case IOV_SVAL(IOV_IOCTLTIMEOUT): {
    248 		if (int_val <= 0)
    249 			bcmerror = BCME_BADARG;
    250 		else
    251 			dhd_os_set_ioctl_resp_timeout((unsigned int)int_val);
    252 		break;
    253 	}
    254 
    255 
    256 	default:
    257 		bcmerror = BCME_UNSUPPORTED;
    258 		break;
    259 	}
    260 
    261 exit:
    262 	return bcmerror;
    263 }
    264 
    265 /* Store the status of a connection attempt for later retrieval by an iovar */
    266 void
    267 dhd_store_conn_status(uint32 event, uint32 status, uint32 reason)
    268 {
    269 	/* Do not overwrite a WLC_E_PRUNE with a WLC_E_SET_SSID
    270 	 * because an encryption/rsn mismatch results in both events, and
    271 	 * the important information is in the WLC_E_PRUNE.
    272 	 */
    273 	if (!(event == WLC_E_SET_SSID && status == WLC_E_STATUS_FAIL &&
    274 	      dhd_conn_event == WLC_E_PRUNE)) {
    275 		dhd_conn_event = event;
    276 		dhd_conn_status = status;
    277 		dhd_conn_reason = reason;
    278 	}
    279 }
    280 
    281 bool
    282 dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec)
    283 {
    284 	void *p;
    285 	int eprec = -1;		/* precedence to evict from */
    286 	bool discard_oldest;
    287 
    288 	/* Fast case, precedence queue is not full and we are also not
    289 	 * exceeding total queue length
    290 	 */
    291 	if (!pktq_pfull(q, prec) && !pktq_full(q)) {
    292 		pktq_penq(q, prec, pkt);
    293 		return TRUE;
    294 	}
    295 
    296 	/* Determine precedence from which to evict packet, if any */
    297 	if (pktq_pfull(q, prec))
    298 		eprec = prec;
    299 	else if (pktq_full(q)) {
    300 		p = pktq_peek_tail(q, &eprec);
    301 		ASSERT(p);
    302 		if (eprec > prec)
    303 			return FALSE;
    304 	}
    305 
    306 	/* Evict if needed */
    307 	if (eprec >= 0) {
    308 		/* Detect queueing to unconfigured precedence */
    309 		ASSERT(!pktq_pempty(q, eprec));
    310 		discard_oldest = AC_BITMAP_TST(dhdp->wme_dp, eprec);
    311 		if (eprec == prec && !discard_oldest)
    312 			return FALSE;		/* refuse newer (incoming) packet */
    313 		/* Evict packet according to discard policy */
    314 		p = discard_oldest ? pktq_pdeq(q, eprec) : pktq_pdeq_tail(q, eprec);
    315 		if (p == NULL) {
    316 			DHD_ERROR(("%s: pktq_penq() failed, oldest %d.",
    317 				__FUNCTION__, discard_oldest));
    318 			ASSERT(p);
    319 		}
    320 
    321 		PKTFREE(dhdp->osh, p, TRUE);
    322 	}
    323 
    324 	/* Enqueue */
    325 	p = pktq_penq(q, prec, pkt);
    326 	if (p == NULL) {
    327 		DHD_ERROR(("%s: pktq_penq() failed.", __FUNCTION__));
    328 		ASSERT(p);
    329 	}
    330 
    331 	return TRUE;
    332 }
    333 
    334 static int
    335 dhd_iovar_op(dhd_pub_t *dhd_pub, const char *name,
    336              void *params, int plen, void *arg, int len, bool set)
    337 {
    338 	int bcmerror = 0;
    339 	int val_size;
    340 	const bcm_iovar_t *vi = NULL;
    341 	uint32 actionid;
    342 
    343 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
    344 
    345 	ASSERT(name);
    346 	ASSERT(len >= 0);
    347 
    348 	/* Get MUST have return space */
    349 	ASSERT(set || (arg && len));
    350 
    351 	/* Set does NOT take qualifiers */
    352 	ASSERT(!set || (!params && !plen));
    353 
    354 	if ((vi = bcm_iovar_lookup(dhd_iovars, name)) == NULL) {
    355 		bcmerror = BCME_UNSUPPORTED;
    356 		goto exit;
    357 	}
    358 
    359 	DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__,
    360 	         name, (set ? "set" : "get"), len, plen));
    361 
    362 	/* set up 'params' pointer in case this is a set command so that
    363 	 * the convenience int and bool code can be common to set and get
    364 	 */
    365 	if (params == NULL) {
    366 		params = arg;
    367 		plen = len;
    368 	}
    369 
    370 	if (vi->type == IOVT_VOID)
    371 		val_size = 0;
    372 	else if (vi->type == IOVT_BUFFER)
    373 		val_size = len;
    374 	else
    375 		/* all other types are integer sized */
    376 		val_size = sizeof(int);
    377 
    378 	actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
    379 	bcmerror = dhd_doiovar(dhd_pub, vi, actionid, name, params, plen, arg, len, val_size);
    380 
    381 exit:
    382 	return bcmerror;
    383 }
    384 
    385 int
    386 dhd_ioctl(dhd_pub_t *dhd_pub, dhd_ioctl_t *ioc, void *buf, uint buflen)
    387 {
    388 	int bcmerror = 0;
    389 
    390 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
    391 
    392 	if (!buf) return BCME_BADARG;
    393 
    394 	switch (ioc->cmd) {
    395 	case DHD_GET_MAGIC:
    396 		if (buflen < sizeof(int))
    397 			bcmerror = BCME_BUFTOOSHORT;
    398 		else
    399 			*(int*)buf = DHD_IOCTL_MAGIC;
    400 		break;
    401 
    402 	case DHD_GET_VERSION:
    403 		if (buflen < sizeof(int))
    404 			bcmerror = -BCME_BUFTOOSHORT;
    405 		else
    406 			*(int*)buf = DHD_IOCTL_VERSION;
    407 		break;
    408 
    409 	case DHD_GET_VAR:
    410 	case DHD_SET_VAR: {
    411 		char *arg;
    412 		uint arglen;
    413 
    414 		/* scan past the name to any arguments */
    415 		for (arg = buf, arglen = buflen; *arg && arglen; arg++, arglen--);
    416 
    417 		if (*arg) {
    418 			bcmerror = BCME_BUFTOOSHORT;
    419 			break;
    420 		}
    421 
    422 		/* account for the NUL terminator */
    423 		arg++, arglen--;
    424 
    425 		/* call with the appropriate arguments */
    426 		if (ioc->cmd == DHD_GET_VAR)
    427 			bcmerror = dhd_iovar_op(dhd_pub, buf, arg, arglen,
    428 			buf, buflen, IOV_GET);
    429 		else
    430 			bcmerror = dhd_iovar_op(dhd_pub, buf, NULL, 0, arg, arglen, IOV_SET);
    431 		if (bcmerror != BCME_UNSUPPORTED)
    432 			break;
    433 
    434 		/* not in generic table, try protocol module */
    435 		if (ioc->cmd == DHD_GET_VAR)
    436 			bcmerror = dhd_prot_iovar_op(dhd_pub, buf, arg,
    437 			                             arglen, buf, buflen, IOV_GET);
    438 		else
    439 			bcmerror = dhd_prot_iovar_op(dhd_pub, buf,
    440 			                             NULL, 0, arg, arglen, IOV_SET);
    441 		if (bcmerror != BCME_UNSUPPORTED)
    442 			break;
    443 
    444 		/* if still not found, try bus module */
    445 		if (ioc->cmd == DHD_GET_VAR)
    446 			bcmerror = dhd_bus_iovar_op(dhd_pub, buf,
    447 			                            arg, arglen, buf, buflen, IOV_GET);
    448 		else
    449 			bcmerror = dhd_bus_iovar_op(dhd_pub, buf,
    450 			                            NULL, 0, arg, arglen, IOV_SET);
    451 
    452 		break;
    453 	}
    454 
    455 	default:
    456 		bcmerror = BCME_UNSUPPORTED;
    457 	}
    458 
    459 	return bcmerror;
    460 }
    461 
    462 #ifdef APSTA_PINGTEST
    463 struct ether_addr guest_eas[MAX_GUEST];
    464 #endif
    465 
    466 #ifdef SHOW_EVENTS
    467 static void
    468 wl_show_host_event(wl_event_msg_t *event, void *event_data)
    469 {
    470 	uint i, status, reason;
    471 	bool group = FALSE, flush_txq = FALSE, link = FALSE;
    472 	char *auth_str, *event_name;
    473 	uchar *buf;
    474 	char err_msg[256], eabuf[ETHER_ADDR_STR_LEN];
    475 	static struct {uint event; char *event_name;} event_names[] = {
    476 		{WLC_E_SET_SSID, "SET_SSID"},
    477 		{WLC_E_JOIN, "JOIN"},
    478 		{WLC_E_START, "START"},
    479 		{WLC_E_AUTH, "AUTH"},
    480 		{WLC_E_AUTH_IND, "AUTH_IND"},
    481 		{WLC_E_DEAUTH, "DEAUTH"},
    482 		{WLC_E_DEAUTH_IND, "DEAUTH_IND"},
    483 		{WLC_E_ASSOC, "ASSOC"},
    484 		{WLC_E_ASSOC_IND, "ASSOC_IND"},
    485 		{WLC_E_REASSOC, "REASSOC"},
    486 		{WLC_E_REASSOC_IND, "REASSOC_IND"},
    487 		{WLC_E_DISASSOC, "DISASSOC"},
    488 		{WLC_E_DISASSOC_IND, "DISASSOC_IND"},
    489 		{WLC_E_QUIET_START, "START_QUIET"},
    490 		{WLC_E_QUIET_END, "END_QUIET"},
    491 		{WLC_E_BEACON_RX, "BEACON_RX"},
    492 		{WLC_E_LINK, "LINK"},
    493 		{WLC_E_MIC_ERROR, "MIC_ERROR"},
    494 		{WLC_E_NDIS_LINK, "NDIS_LINK"},
    495 		{WLC_E_ROAM, "ROAM"},
    496 		{WLC_E_TXFAIL, "TXFAIL"},
    497 		{WLC_E_PMKID_CACHE, "PMKID_CACHE"},
    498 		{WLC_E_RETROGRADE_TSF, "RETROGRADE_TSF"},
    499 		{WLC_E_PRUNE, "PRUNE"},
    500 		{WLC_E_AUTOAUTH, "AUTOAUTH"},
    501 		{WLC_E_EAPOL_MSG, "EAPOL_MSG"},
    502 		{WLC_E_SCAN_COMPLETE, "SCAN_COMPLETE"},
    503 		{WLC_E_ADDTS_IND, "ADDTS_IND"},
    504 		{WLC_E_DELTS_IND, "DELTS_IND"},
    505 		{WLC_E_BCNSENT_IND, "BCNSENT_IND"},
    506 		{WLC_E_BCNRX_MSG, "BCNRX_MSG"},
    507 		{WLC_E_BCNLOST_MSG, "BCNLOST_MSG"},
    508 		{WLC_E_ROAM_PREP, "ROAM_PREP"},
    509 		{WLC_E_PFN_NET_FOUND, "PNO_NET_FOUND"},
    510 		{WLC_E_PFN_NET_LOST, "PNO_NET_LOST"},
    511 		{WLC_E_RESET_COMPLETE, "RESET_COMPLETE"},
    512 		{WLC_E_JOIN_START, "JOIN_START"},
    513 		{WLC_E_ROAM_START, "ROAM_START"},
    514 		{WLC_E_ASSOC_START, "ASSOC_START"},
    515 		{WLC_E_IBSS_ASSOC, "IBSS_ASSOC"},
    516 		{WLC_E_RADIO, "RADIO"},
    517 		{WLC_E_PSM_WATCHDOG, "PSM_WATCHDOG"},
    518 		{WLC_E_PROBREQ_MSG, "PROBREQ_MSG"},
    519 		{WLC_E_SCAN_CONFIRM_IND, "SCAN_CONFIRM_IND"},
    520 		{WLC_E_PSK_SUP, "PSK_SUP"},
    521 		{WLC_E_COUNTRY_CODE_CHANGED, "COUNTRY_CODE_CHANGED"},
    522 		{WLC_E_EXCEEDED_MEDIUM_TIME, "EXCEEDED_MEDIUM_TIME"},
    523 		{WLC_E_ICV_ERROR, "ICV_ERROR"},
    524 		{WLC_E_UNICAST_DECODE_ERROR, "UNICAST_DECODE_ERROR"},
    525 		{WLC_E_MULTICAST_DECODE_ERROR, "MULTICAST_DECODE_ERROR"},
    526 		{WLC_E_TRACE, "TRACE"},
    527 		{WLC_E_ACTION_FRAME, "ACTION FRAME"},
    528 		{WLC_E_ACTION_FRAME_COMPLETE, "ACTION FRAME TX COMPLETE"},
    529 		{WLC_E_IF, "IF"},
    530 		{WLC_E_RSSI, "RSSI"},
    531 		{WLC_E_PFN_SCAN_COMPLETE, "SCAN_COMPLETE"}
    532 	};
    533 	uint event_type, flags, auth_type, datalen;
    534 	event_type = ntoh32(event->event_type);
    535 	flags = ntoh16(event->flags);
    536 	status = ntoh32(event->status);
    537 	reason = ntoh32(event->reason);
    538 	auth_type = ntoh32(event->auth_type);
    539 	datalen = ntoh32(event->datalen);
    540 	/* debug dump of event messages */
    541 	sprintf(eabuf, "%02x:%02x:%02x:%02x:%02x:%02x",
    542 	        (uchar)event->addr.octet[0]&0xff,
    543 	        (uchar)event->addr.octet[1]&0xff,
    544 	        (uchar)event->addr.octet[2]&0xff,
    545 	        (uchar)event->addr.octet[3]&0xff,
    546 	        (uchar)event->addr.octet[4]&0xff,
    547 	        (uchar)event->addr.octet[5]&0xff);
    548 
    549 	event_name = "UNKNOWN";
    550 	for (i = 0; i < ARRAYSIZE(event_names); i++) {
    551 		if (event_names[i].event == event_type)
    552 			event_name = event_names[i].event_name;
    553 	}
    554 
    555 	DHD_EVENT(("EVENT: %s, event ID = %d\n", event_name, event_type));
    556 
    557 	if (flags & WLC_EVENT_MSG_LINK)
    558 		link = TRUE;
    559 	if (flags & WLC_EVENT_MSG_GROUP)
    560 		group = TRUE;
    561 	if (flags & WLC_EVENT_MSG_FLUSHTXQ)
    562 		flush_txq = TRUE;
    563 
    564 	switch (event_type) {
    565 	case WLC_E_START:
    566 	case WLC_E_DEAUTH:
    567 	case WLC_E_DISASSOC:
    568 		DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
    569 		break;
    570 
    571 	case WLC_E_ASSOC_IND:
    572 	case WLC_E_REASSOC_IND:
    573 #ifdef APSTA_PINGTEST
    574 		{
    575 			int i;
    576 			for (i = 0; i < MAX_GUEST; ++i)
    577 				if (ETHER_ISNULLADDR(&guest_eas[i]))
    578 					break;
    579 			if (i < MAX_GUEST)
    580 				bcopy(event->addr.octet, guest_eas[i].octet, ETHER_ADDR_LEN);
    581 		}
    582 #endif /* APSTA_PINGTEST */
    583 		DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
    584 		break;
    585 
    586 	case WLC_E_ASSOC:
    587 	case WLC_E_REASSOC:
    588 		if (status == WLC_E_STATUS_SUCCESS) {
    589 			DHD_EVENT(("MACEVENT: %s, MAC %s, SUCCESS\n", event_name, eabuf));
    590 		} else if (status == WLC_E_STATUS_TIMEOUT) {
    591 			DHD_EVENT(("MACEVENT: %s, MAC %s, TIMEOUT\n", event_name, eabuf));
    592 		} else if (status == WLC_E_STATUS_FAIL) {
    593 			DHD_EVENT(("MACEVENT: %s, MAC %s, FAILURE, reason %d\n",
    594 			       event_name, eabuf, (int)reason));
    595 		} else {
    596 			DHD_EVENT(("MACEVENT: %s, MAC %s, unexpected status %d\n",
    597 			       event_name, eabuf, (int)status));
    598 		}
    599 		break;
    600 
    601 	case WLC_E_DEAUTH_IND:
    602 	case WLC_E_DISASSOC_IND:
    603 #ifdef APSTA_PINGTEST
    604 		{
    605 			int i;
    606 			for (i = 0; i < MAX_GUEST; ++i) {
    607 				if (bcmp(guest_eas[i].octet, event->addr.octet,
    608 				         ETHER_ADDR_LEN) == 0) {
    609 					bzero(guest_eas[i].octet, ETHER_ADDR_LEN);
    610 					break;
    611 				}
    612 			}
    613 		}
    614 #endif /* APSTA_PINGTEST */
    615 		DHD_EVENT(("MACEVENT: %s, MAC %s, reason %d\n", event_name, eabuf, (int)reason));
    616 		break;
    617 
    618 	case WLC_E_AUTH:
    619 	case WLC_E_AUTH_IND:
    620 		if (auth_type == DOT11_OPEN_SYSTEM)
    621 			auth_str = "Open System";
    622 		else if (auth_type == DOT11_SHARED_KEY)
    623 			auth_str = "Shared Key";
    624 		else {
    625 			sprintf(err_msg, "AUTH unknown: %d", (int)auth_type);
    626 			auth_str = err_msg;
    627 		}
    628 		if (event_type == WLC_E_AUTH_IND) {
    629 			DHD_EVENT(("MACEVENT: %s, MAC %s, %s\n", event_name, eabuf, auth_str));
    630 		} else if (status == WLC_E_STATUS_SUCCESS) {
    631 			DHD_EVENT(("MACEVENT: %s, MAC %s, %s, SUCCESS\n",
    632 				event_name, eabuf, auth_str));
    633 		} else if (status == WLC_E_STATUS_TIMEOUT) {
    634 			DHD_EVENT(("MACEVENT: %s, MAC %s, %s, TIMEOUT\n",
    635 				event_name, eabuf, auth_str));
    636 		} else if (status == WLC_E_STATUS_FAIL) {
    637 			DHD_EVENT(("MACEVENT: %s, MAC %s, %s, FAILURE, reason %d\n",
    638 			       event_name, eabuf, auth_str, (int)reason));
    639 		}
    640 
    641 		break;
    642 
    643 	case WLC_E_JOIN:
    644 	case WLC_E_ROAM:
    645 	case WLC_E_SET_SSID:
    646 		if (status == WLC_E_STATUS_SUCCESS) {
    647 			DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
    648 		} else if (status == WLC_E_STATUS_FAIL) {
    649 			DHD_EVENT(("MACEVENT: %s, failed\n", event_name));
    650 		} else if (status == WLC_E_STATUS_NO_NETWORKS) {
    651 			DHD_EVENT(("MACEVENT: %s, no networks found\n", event_name));
    652 		} else {
    653 			DHD_EVENT(("MACEVENT: %s, unexpected status %d\n",
    654 				event_name, (int)status));
    655 		}
    656 		break;
    657 
    658 	case WLC_E_BEACON_RX:
    659 		if (status == WLC_E_STATUS_SUCCESS) {
    660 			DHD_EVENT(("MACEVENT: %s, SUCCESS\n", event_name));
    661 		} else if (status == WLC_E_STATUS_FAIL) {
    662 			DHD_EVENT(("MACEVENT: %s, FAIL\n", event_name));
    663 		} else {
    664 			DHD_EVENT(("MACEVENT: %s, status %d\n", event_name, status));
    665 		}
    666 		break;
    667 
    668 	case WLC_E_LINK:
    669 		DHD_EVENT(("MACEVENT: %s %s\n", event_name, link?"UP":"DOWN"));
    670 		break;
    671 
    672 	case WLC_E_MIC_ERROR:
    673 		DHD_EVENT(("MACEVENT: %s, MAC %s, Group %d, Flush %d\n",
    674 		       event_name, eabuf, group, flush_txq));
    675 		break;
    676 
    677 	case WLC_E_ICV_ERROR:
    678 	case WLC_E_UNICAST_DECODE_ERROR:
    679 	case WLC_E_MULTICAST_DECODE_ERROR:
    680 		DHD_EVENT(("MACEVENT: %s, MAC %s\n",
    681 		       event_name, eabuf));
    682 		break;
    683 
    684 	case WLC_E_TXFAIL:
    685 		DHD_EVENT(("MACEVENT: %s, RA %s\n", event_name, eabuf));
    686 		break;
    687 
    688 	case WLC_E_SCAN_COMPLETE:
    689 	case WLC_E_PMKID_CACHE:
    690 		DHD_EVENT(("MACEVENT: %s\n", event_name));
    691 		break;
    692 
    693 	case WLC_E_PFN_NET_FOUND:
    694 	case WLC_E_PFN_NET_LOST:
    695 	case WLC_E_PFN_SCAN_COMPLETE:
    696 		DHD_EVENT(("PNOEVENT: %s\n", event_name));
    697 		break;
    698 
    699 	case WLC_E_PSK_SUP:
    700 	case WLC_E_PRUNE:
    701 		DHD_EVENT(("MACEVENT: %s, status %d, reason %d\n",
    702 		           event_name, (int)status, (int)reason));
    703 		break;
    704 
    705 	case WLC_E_TRACE:
    706 		{
    707 			static uint32 seqnum_prev = 0;
    708 			msgtrace_hdr_t hdr;
    709 			uint32 nblost;
    710 			char *s, *p;
    711 
    712 			buf = (uchar *) event_data;
    713 			memcpy(&hdr, buf, MSGTRACE_HDRLEN);
    714 
    715 			if (hdr.version != MSGTRACE_VERSION) {
    716 				printf("\nMACEVENT: %s [unsupported version --> "
    717 				       "dhd version:%d dongle version:%d]\n",
    718 				       event_name, MSGTRACE_VERSION, hdr.version);
    719 				/* Reset datalen to avoid display below */
    720 				datalen = 0;
    721 				break;
    722 			}
    723 
    724 			/* There are 2 bytes available at the end of data */
    725 			buf[MSGTRACE_HDRLEN + ntoh16(hdr.len)] = '\0';
    726 
    727 			if (ntoh32(hdr.discarded_bytes) || ntoh32(hdr.discarded_printf)) {
    728 				printf("\nWLC_E_TRACE: [Discarded traces in dongle -->"
    729 				       "discarded_bytes %d discarded_printf %d]\n",
    730 				       ntoh32(hdr.discarded_bytes), ntoh32(hdr.discarded_printf));
    731 			}
    732 
    733 			nblost = ntoh32(hdr.seqnum) - seqnum_prev - 1;
    734 			if (nblost > 0) {
    735 				printf("\nWLC_E_TRACE: [Event lost --> seqnum %d nblost %d\n",
    736 				        ntoh32(hdr.seqnum), nblost);
    737 			}
    738 			seqnum_prev = ntoh32(hdr.seqnum);
    739 
    740 			/* Display the trace buffer. Advance from \n to \n to avoid display big
    741 			 * printf (issue with Linux printk )
    742 			 */
    743 			p = (char *)&buf[MSGTRACE_HDRLEN];
    744 			while ((s = strstr(p, "\n")) != NULL) {
    745 				*s = '\0';
    746 				printf("%s\n", p);
    747 				p = s + 1;
    748 			}
    749 			printf("%s\n", p);
    750 
    751 			/* Reset datalen to avoid display below */
    752 			datalen = 0;
    753 		}
    754 		break;
    755 
    756 
    757 	case WLC_E_RSSI:
    758 		DHD_EVENT(("MACEVENT: %s %d\n", event_name, ntoh32(*((int *)event_data))));
    759 		break;
    760 
    761 	default:
    762 		DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, auth %d\n",
    763 		       event_name, event_type, eabuf, (int)status, (int)reason,
    764 		       (int)auth_type));
    765 		break;
    766 	}
    767 
    768 	/* show any appended data */
    769 	if (datalen) {
    770 		buf = (uchar *) event_data;
    771 		DHD_EVENT((" data (%d) : ", datalen));
    772 		for (i = 0; i < datalen; i++)
    773 			DHD_EVENT((" 0x%02x ", *buf++));
    774 		DHD_EVENT(("\n"));
    775 	}
    776 }
    777 #endif /* SHOW_EVENTS */
    778 
    779 int
    780 wl_host_event(struct dhd_info *dhd, int *ifidx, void *pktdata,
    781               wl_event_msg_t *event, void **data_ptr)
    782 {
    783 	/* check whether packet is a BRCM event pkt */
    784 	bcm_event_t *pvt_data = (bcm_event_t *)pktdata;
    785 	char *event_data;
    786 	uint32 type, status;
    787 	uint16 flags;
    788 	int evlen;
    789 
    790 	if (bcmp(BRCM_OUI, &pvt_data->bcm_hdr.oui[0], DOT11_OUI_LEN)) {
    791 		DHD_ERROR(("%s: mismatched OUI, bailing\n", __FUNCTION__));
    792 		return (BCME_ERROR);
    793 	}
    794 
    795 	/* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */
    796 	if (ntoh16_ua((void *)&pvt_data->bcm_hdr.usr_subtype) != BCMILCP_BCM_SUBTYPE_EVENT) {
    797 		DHD_ERROR(("%s: mismatched subtype, bailing\n", __FUNCTION__));
    798 		return (BCME_ERROR);
    799 	}
    800 
    801 	*data_ptr = &pvt_data[1];
    802 	event_data = *data_ptr;
    803 
    804 	/* memcpy since BRCM event pkt may be unaligned. */
    805 	memcpy(event, &pvt_data->event, sizeof(wl_event_msg_t));
    806 
    807 	type = ntoh32_ua((void *)&event->event_type);
    808 	flags = ntoh16_ua((void *)&event->flags);
    809 	status = ntoh32_ua((void *)&event->status);
    810 	evlen = ntoh32_ua((void *)&event->datalen) + sizeof(bcm_event_t);
    811 
    812 	switch (type) {
    813 		case WLC_E_IF:
    814 			{
    815 				dhd_if_event_t *ifevent = (dhd_if_event_t *)event_data;
    816 				DHD_TRACE(("%s: if event\n", __FUNCTION__));
    817 
    818 				if (ifevent->ifidx > 0 && ifevent->ifidx < DHD_MAX_IFS)
    819 				{
    820 					if (ifevent->action == WLC_E_IF_ADD)
    821 						dhd_add_if(dhd, ifevent->ifidx,
    822 							NULL, event->ifname,
    823 							pvt_data->eth.ether_dhost,
    824 							ifevent->flags, ifevent->bssidx);
    825 					else
    826 						dhd_del_if(dhd, ifevent->ifidx);
    827 				} else {
    828 					DHD_ERROR(("%s: Invalid ifidx %d for %s\n",
    829 						__FUNCTION__, ifevent->ifidx, event->ifname));
    830 				}
    831 			}
    832 			/* send up the if event: btamp user needs it */
    833 			*ifidx = dhd_ifname2idx(dhd, event->ifname);
    834 			/* push up to external supp/auth */
    835 			dhd_event(dhd, (char *)pvt_data, evlen, *ifidx);
    836 			break;
    837 
    838 
    839 #ifdef P2P
    840 		case WLC_E_NDIS_LINK:
    841 			break;
    842 #endif
    843 		/* fall through */
    844 		/* These are what external supplicant/authenticator wants */
    845 		case WLC_E_LINK:
    846 		case WLC_E_ASSOC_IND:
    847 		case WLC_E_REASSOC_IND:
    848 		case WLC_E_DISASSOC_IND:
    849 		case WLC_E_MIC_ERROR:
    850 		default:
    851 		/* Fall through: this should get _everything_  */
    852 
    853 			*ifidx = dhd_ifname2idx(dhd, event->ifname);
    854 			/* push up to external supp/auth */
    855 			dhd_event(dhd, (char *)pvt_data, evlen, *ifidx);
    856 			DHD_TRACE(("%s: MAC event %d, flags %x, status %x\n",
    857 			           __FUNCTION__, type, flags, status));
    858 
    859 			/* put it back to WLC_E_NDIS_LINK */
    860 			if (type == WLC_E_NDIS_LINK) {
    861 				uint32 temp;
    862 
    863 				temp = ntoh32_ua((void *)&event->event_type);
    864 				DHD_TRACE(("Converted to WLC_E_LINK type %d\n", temp));
    865 
    866 				temp = ntoh32(WLC_E_NDIS_LINK);
    867 				memcpy((void *)(&pvt_data->event.event_type), &temp,
    868 					sizeof(pvt_data->event.event_type));
    869 			}
    870 			break;
    871 	}
    872 
    873 #ifdef SHOW_EVENTS
    874 	wl_show_host_event(event, event_data);
    875 #endif /* SHOW_EVENTS */
    876 
    877 	return (BCME_OK);
    878 }
    879 
    880 
    881 void
    882 wl_event_to_host_order(wl_event_msg_t *evt)
    883 {
    884 	/* Event struct members passed from dongle to host are stored in network
    885 	 * byte order. Convert all members to host-order.
    886 	 */
    887 	evt->event_type = ntoh32(evt->event_type);
    888 	evt->flags = ntoh16(evt->flags);
    889 	evt->status = ntoh32(evt->status);
    890 	evt->reason = ntoh32(evt->reason);
    891 	evt->auth_type = ntoh32(evt->auth_type);
    892 	evt->datalen = ntoh32(evt->datalen);
    893 	evt->version = ntoh16(evt->version);
    894 }
    895