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