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.69.4.3 2010/09/10 21:30:16 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 #include <wlioctl.h> 41 42 #ifdef SET_RANDOM_MAC_SOFTAP 43 #include <linux/random.h> 44 #include <linux/jiffies.h> 45 #endif 46 47 #ifdef GET_CUSTOM_MAC_ENABLE 48 int wifi_get_mac_addr(unsigned char *buf); 49 #endif /* GET_CUSTOM_MAC_ENABLE */ 50 51 int dhd_msg_level; 52 53 #include <wl_iw.h> 54 55 char fw_path[MOD_PARAM_PATHLEN]; 56 char nv_path[MOD_PARAM_PATHLEN]; 57 58 /* Last connection success/failure status */ 59 uint32 dhd_conn_event; 60 uint32 dhd_conn_status; 61 uint32 dhd_conn_reason; 62 63 #define htod32(i) i 64 #define htod16(i) i 65 #define dtoh32(i) i 66 #define dtoh16(i) i 67 68 extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len); 69 extern void dhd_ind_scan_confirm(void *h, bool status); 70 extern int dhd_wl_ioctl(dhd_pub_t *dhd, uint cmd, char *buf, uint buflen); 71 void dhd_iscan_lock(void); 72 void dhd_iscan_unlock(void); 73 74 /* Packet alignment for most efficient SDIO (can change based on platform) */ 75 #ifndef DHD_SDALIGN 76 #define DHD_SDALIGN 32 77 #endif 78 #if !ISPOWEROF2(DHD_SDALIGN) 79 #error DHD_SDALIGN is not a power of 2! 80 #endif 81 82 #ifdef DHD_DEBUG 83 const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR "\nCompiled on " 84 __DATE__ " at " __TIME__; 85 #else 86 const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR; 87 #endif 88 89 void dhd_set_timer(void *bus, uint wdtick); 90 91 /* IOVar table */ 92 enum { 93 IOV_VERSION = 1, 94 IOV_MSGLEVEL, 95 IOV_BCMERRORSTR, 96 IOV_BCMERROR, 97 IOV_WDTICK, 98 IOV_DUMP, 99 #ifdef DHD_DEBUG 100 IOV_CONS, 101 IOV_DCONSOLE_POLL, 102 #endif 103 IOV_CLEARCOUNTS, 104 IOV_LOGDUMP, 105 IOV_LOGCAL, 106 IOV_LOGSTAMP, 107 IOV_GPIOOB, 108 IOV_IOCTLTIMEOUT, 109 IOV_LAST 110 }; 111 112 const bcm_iovar_t dhd_iovars[] = { 113 {"version", IOV_VERSION, 0, IOVT_BUFFER, sizeof(dhd_version) }, 114 #ifdef DHD_DEBUG 115 {"msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 }, 116 #endif /* DHD_DEBUG */ 117 {"bcmerrorstr", IOV_BCMERRORSTR, 0, IOVT_BUFFER, BCME_STRLEN }, 118 {"bcmerror", IOV_BCMERROR, 0, IOVT_INT8, 0 }, 119 {"wdtick", IOV_WDTICK, 0, IOVT_UINT32, 0 }, 120 {"dump", IOV_DUMP, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN }, 121 #ifdef DHD_DEBUG 122 {"dconpoll", IOV_DCONSOLE_POLL, 0, IOVT_UINT32, 0 }, 123 {"cons", IOV_CONS, 0, IOVT_BUFFER, 0 }, 124 #endif 125 {"clearcounts", IOV_CLEARCOUNTS, 0, IOVT_VOID, 0 }, 126 {"gpioob", IOV_GPIOOB, 0, IOVT_UINT32, 0 }, 127 {"ioctl_timeout", IOV_IOCTLTIMEOUT, 0, IOVT_UINT32, 0 }, 128 {NULL, 0, 0, 0, 0 } 129 }; 130 131 void 132 dhd_common_init(void) 133 { 134 /* Init global variables at run-time, not as part of the declaration. 135 * This is required to support init/de-init of the driver. Initialization 136 * of globals as part of the declaration results in non-deterministic 137 * behaviour since the value of the globals may be different on the 138 * first time that the driver is initialized vs subsequent initializations. 139 */ 140 dhd_msg_level = DHD_ERROR_VAL; 141 #ifdef CONFIG_BCM4329_FW_PATH 142 strncpy(fw_path, CONFIG_BCM4329_FW_PATH, MOD_PARAM_PATHLEN-1); 143 #else 144 fw_path[0] = '\0'; 145 #endif 146 #ifdef CONFIG_BCM4329_NVRAM_PATH 147 strncpy(nv_path, CONFIG_BCM4329_NVRAM_PATH, MOD_PARAM_PATHLEN-1); 148 #else 149 nv_path[0] = '\0'; 150 #endif 151 } 152 153 static int 154 dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen) 155 { 156 char eabuf[ETHER_ADDR_STR_LEN]; 157 158 struct bcmstrbuf b; 159 struct bcmstrbuf *strbuf = &b; 160 161 bcm_binit(strbuf, buf, buflen); 162 163 /* Base DHD info */ 164 bcm_bprintf(strbuf, "%s\n", dhd_version); 165 bcm_bprintf(strbuf, "\n"); 166 bcm_bprintf(strbuf, "pub.up %d pub.txoff %d pub.busstate %d\n", 167 dhdp->up, dhdp->txoff, dhdp->busstate); 168 bcm_bprintf(strbuf, "pub.hdrlen %d pub.maxctl %d pub.rxsz %d\n", 169 dhdp->hdrlen, dhdp->maxctl, dhdp->rxsz); 170 bcm_bprintf(strbuf, "pub.iswl %d pub.drv_version %ld pub.mac %s\n", 171 dhdp->iswl, dhdp->drv_version, bcm_ether_ntoa(&dhdp->mac, eabuf)); 172 bcm_bprintf(strbuf, "pub.bcmerror %d tickcnt %d\n", dhdp->bcmerror, dhdp->tickcnt); 173 174 bcm_bprintf(strbuf, "dongle stats:\n"); 175 bcm_bprintf(strbuf, "tx_packets %ld tx_bytes %ld tx_errors %ld tx_dropped %ld\n", 176 dhdp->dstats.tx_packets, dhdp->dstats.tx_bytes, 177 dhdp->dstats.tx_errors, dhdp->dstats.tx_dropped); 178 bcm_bprintf(strbuf, "rx_packets %ld rx_bytes %ld rx_errors %ld rx_dropped %ld\n", 179 dhdp->dstats.rx_packets, dhdp->dstats.rx_bytes, 180 dhdp->dstats.rx_errors, dhdp->dstats.rx_dropped); 181 bcm_bprintf(strbuf, "multicast %ld\n", dhdp->dstats.multicast); 182 183 bcm_bprintf(strbuf, "bus stats:\n"); 184 bcm_bprintf(strbuf, "tx_packets %ld tx_multicast %ld tx_errors %ld\n", 185 dhdp->tx_packets, dhdp->tx_multicast, dhdp->tx_errors); 186 bcm_bprintf(strbuf, "tx_ctlpkts %ld tx_ctlerrs %ld\n", 187 dhdp->tx_ctlpkts, dhdp->tx_ctlerrs); 188 bcm_bprintf(strbuf, "rx_packets %ld rx_multicast %ld rx_errors %ld \n", 189 dhdp->rx_packets, dhdp->rx_multicast, dhdp->rx_errors); 190 bcm_bprintf(strbuf, "rx_ctlpkts %ld rx_ctlerrs %ld rx_dropped %ld rx_flushed %ld\n", 191 dhdp->rx_ctlpkts, dhdp->rx_ctlerrs, dhdp->rx_dropped, dhdp->rx_flushed); 192 bcm_bprintf(strbuf, "rx_readahead_cnt %ld tx_realloc %ld fc_packets %ld\n", 193 dhdp->rx_readahead_cnt, dhdp->tx_realloc, dhdp->fc_packets); 194 bcm_bprintf(strbuf, "wd_dpc_sched %ld\n", dhdp->wd_dpc_sched); 195 bcm_bprintf(strbuf, "\n"); 196 197 /* Add any prot info */ 198 dhd_prot_dump(dhdp, strbuf); 199 bcm_bprintf(strbuf, "\n"); 200 201 /* Add any bus info */ 202 dhd_bus_dump(dhdp, strbuf); 203 204 return (!strbuf->size ? BCME_BUFTOOSHORT : 0); 205 } 206 207 static int 208 dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const char *name, 209 void *params, int plen, void *arg, int len, int val_size) 210 { 211 int bcmerror = 0; 212 int32 int_val = 0; 213 214 DHD_TRACE(("%s: Enter\n", __FUNCTION__)); 215 216 if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0) 217 goto exit; 218 219 if (plen >= (int)sizeof(int_val)) 220 bcopy(params, &int_val, sizeof(int_val)); 221 222 switch (actionid) { 223 case IOV_GVAL(IOV_VERSION): 224 /* Need to have checked buffer length */ 225 strncpy((char*)arg, dhd_version, len); 226 break; 227 228 case IOV_GVAL(IOV_MSGLEVEL): 229 int_val = (int32)dhd_msg_level; 230 bcopy(&int_val, arg, val_size); 231 break; 232 233 case IOV_SVAL(IOV_MSGLEVEL): 234 dhd_msg_level = int_val; 235 break; 236 237 case IOV_GVAL(IOV_BCMERRORSTR): 238 strncpy((char *)arg, bcmerrorstr(dhd_pub->bcmerror), BCME_STRLEN); 239 ((char *)arg)[BCME_STRLEN - 1] = 0x00; 240 break; 241 242 case IOV_GVAL(IOV_BCMERROR): 243 int_val = (int32)dhd_pub->bcmerror; 244 bcopy(&int_val, arg, val_size); 245 break; 246 247 case IOV_GVAL(IOV_WDTICK): 248 int_val = (int32)dhd_watchdog_ms; 249 bcopy(&int_val, arg, val_size); 250 break; 251 252 case IOV_SVAL(IOV_WDTICK): 253 if (!dhd_pub->up) { 254 bcmerror = BCME_NOTUP; 255 break; 256 } 257 dhd_os_wd_timer(dhd_pub, (uint)int_val); 258 break; 259 260 case IOV_GVAL(IOV_DUMP): 261 bcmerror = dhd_dump(dhd_pub, arg, len); 262 break; 263 264 #ifdef DHD_DEBUG 265 case IOV_GVAL(IOV_DCONSOLE_POLL): 266 int_val = (int32)dhd_console_ms; 267 bcopy(&int_val, arg, val_size); 268 break; 269 270 case IOV_SVAL(IOV_DCONSOLE_POLL): 271 dhd_console_ms = (uint)int_val; 272 break; 273 274 case IOV_SVAL(IOV_CONS): 275 if (len > 0) 276 bcmerror = dhd_bus_console_in(dhd_pub, arg, len - 1); 277 break; 278 #endif 279 280 case IOV_SVAL(IOV_CLEARCOUNTS): 281 dhd_pub->tx_packets = dhd_pub->rx_packets = 0; 282 dhd_pub->tx_errors = dhd_pub->rx_errors = 0; 283 dhd_pub->tx_ctlpkts = dhd_pub->rx_ctlpkts = 0; 284 dhd_pub->tx_ctlerrs = dhd_pub->rx_ctlerrs = 0; 285 dhd_pub->rx_dropped = 0; 286 dhd_pub->rx_readahead_cnt = 0; 287 dhd_pub->tx_realloc = 0; 288 dhd_pub->wd_dpc_sched = 0; 289 memset(&dhd_pub->dstats, 0, sizeof(dhd_pub->dstats)); 290 dhd_bus_clearcounts(dhd_pub); 291 break; 292 293 294 case IOV_GVAL(IOV_IOCTLTIMEOUT): { 295 int_val = (int32)dhd_os_get_ioctl_resp_timeout(); 296 bcopy(&int_val, arg, sizeof(int_val)); 297 break; 298 } 299 300 case IOV_SVAL(IOV_IOCTLTIMEOUT): { 301 if (int_val <= 0) 302 bcmerror = BCME_BADARG; 303 else 304 dhd_os_set_ioctl_resp_timeout((unsigned int)int_val); 305 break; 306 } 307 308 309 default: 310 bcmerror = BCME_UNSUPPORTED; 311 break; 312 } 313 314 exit: 315 return bcmerror; 316 } 317 318 /* Store the status of a connection attempt for later retrieval by an iovar */ 319 void 320 dhd_store_conn_status(uint32 event, uint32 status, uint32 reason) 321 { 322 /* Do not overwrite a WLC_E_PRUNE with a WLC_E_SET_SSID 323 * because an encryption/rsn mismatch results in both events, and 324 * the important information is in the WLC_E_PRUNE. 325 */ 326 if (!(event == WLC_E_SET_SSID && status == WLC_E_STATUS_FAIL && 327 dhd_conn_event == WLC_E_PRUNE)) { 328 dhd_conn_event = event; 329 dhd_conn_status = status; 330 dhd_conn_reason = reason; 331 } 332 } 333 334 bool 335 dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec) 336 { 337 void *p; 338 int eprec = -1; /* precedence to evict from */ 339 bool discard_oldest; 340 341 /* Fast case, precedence queue is not full and we are also not 342 * exceeding total queue length 343 */ 344 if (!pktq_pfull(q, prec) && !pktq_full(q)) { 345 pktq_penq(q, prec, pkt); 346 return TRUE; 347 } 348 349 /* Determine precedence from which to evict packet, if any */ 350 if (pktq_pfull(q, prec)) 351 eprec = prec; 352 else if (pktq_full(q)) { 353 p = pktq_peek_tail(q, &eprec); 354 ASSERT(p); 355 if (eprec > prec) 356 return FALSE; 357 } 358 359 /* Evict if needed */ 360 if (eprec >= 0) { 361 /* Detect queueing to unconfigured precedence */ 362 ASSERT(!pktq_pempty(q, eprec)); 363 discard_oldest = AC_BITMAP_TST(dhdp->wme_dp, eprec); 364 if (eprec == prec && !discard_oldest) 365 return FALSE; /* refuse newer (incoming) packet */ 366 /* Evict packet according to discard policy */ 367 p = discard_oldest ? pktq_pdeq(q, eprec) : pktq_pdeq_tail(q, eprec); 368 if (p == NULL) { 369 DHD_ERROR(("%s: pktq_penq() failed, oldest %d.", 370 __FUNCTION__, discard_oldest)); 371 ASSERT(p); 372 } 373 374 PKTFREE(dhdp->osh, p, TRUE); 375 } 376 377 /* Enqueue */ 378 p = pktq_penq(q, prec, pkt); 379 if (p == NULL) { 380 DHD_ERROR(("%s: pktq_penq() failed.", __FUNCTION__)); 381 ASSERT(p); 382 } 383 384 return TRUE; 385 } 386 387 static int 388 dhd_iovar_op(dhd_pub_t *dhd_pub, const char *name, 389 void *params, int plen, void *arg, int len, bool set) 390 { 391 int bcmerror = 0; 392 int val_size; 393 const bcm_iovar_t *vi = NULL; 394 uint32 actionid; 395 396 DHD_TRACE(("%s: Enter\n", __FUNCTION__)); 397 398 ASSERT(name); 399 ASSERT(len >= 0); 400 401 /* Get MUST have return space */ 402 ASSERT(set || (arg && len)); 403 404 /* Set does NOT take qualifiers */ 405 ASSERT(!set || (!params && !plen)); 406 407 if ((vi = bcm_iovar_lookup(dhd_iovars, name)) == NULL) { 408 bcmerror = BCME_UNSUPPORTED; 409 goto exit; 410 } 411 412 DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__, 413 name, (set ? "set" : "get"), len, plen)); 414 415 /* set up 'params' pointer in case this is a set command so that 416 * the convenience int and bool code can be common to set and get 417 */ 418 if (params == NULL) { 419 params = arg; 420 plen = len; 421 } 422 423 if (vi->type == IOVT_VOID) 424 val_size = 0; 425 else if (vi->type == IOVT_BUFFER) 426 val_size = len; 427 else 428 /* all other types are integer sized */ 429 val_size = sizeof(int); 430 431 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); 432 bcmerror = dhd_doiovar(dhd_pub, vi, actionid, name, params, plen, arg, len, val_size); 433 434 exit: 435 return bcmerror; 436 } 437 438 int 439 dhd_ioctl(dhd_pub_t *dhd_pub, dhd_ioctl_t *ioc, void *buf, uint buflen) 440 { 441 int bcmerror = 0; 442 443 DHD_TRACE(("%s: Enter\n", __FUNCTION__)); 444 445 if (!buf) return BCME_BADARG; 446 447 switch (ioc->cmd) { 448 case DHD_GET_MAGIC: 449 if (buflen < sizeof(int)) 450 bcmerror = BCME_BUFTOOSHORT; 451 else 452 *(int*)buf = DHD_IOCTL_MAGIC; 453 break; 454 455 case DHD_GET_VERSION: 456 if (buflen < sizeof(int)) 457 bcmerror = -BCME_BUFTOOSHORT; 458 else 459 *(int*)buf = DHD_IOCTL_VERSION; 460 break; 461 462 case DHD_GET_VAR: 463 case DHD_SET_VAR: { 464 char *arg; 465 uint arglen; 466 467 /* scan past the name to any arguments */ 468 for (arg = buf, arglen = buflen; *arg && arglen; arg++, arglen--); 469 470 if (*arg) { 471 bcmerror = BCME_BUFTOOSHORT; 472 break; 473 } 474 475 /* account for the NUL terminator */ 476 arg++, arglen--; 477 478 /* call with the appropriate arguments */ 479 if (ioc->cmd == DHD_GET_VAR) 480 bcmerror = dhd_iovar_op(dhd_pub, buf, arg, arglen, 481 buf, buflen, IOV_GET); 482 else 483 bcmerror = dhd_iovar_op(dhd_pub, buf, NULL, 0, arg, arglen, IOV_SET); 484 if (bcmerror != BCME_UNSUPPORTED) 485 break; 486 487 /* not in generic table, try protocol module */ 488 if (ioc->cmd == DHD_GET_VAR) 489 bcmerror = dhd_prot_iovar_op(dhd_pub, buf, arg, 490 arglen, buf, buflen, IOV_GET); 491 else 492 bcmerror = dhd_prot_iovar_op(dhd_pub, buf, 493 NULL, 0, arg, arglen, IOV_SET); 494 if (bcmerror != BCME_UNSUPPORTED) 495 break; 496 497 /* if still not found, try bus module */ 498 if (ioc->cmd == DHD_GET_VAR) 499 bcmerror = dhd_bus_iovar_op(dhd_pub, buf, 500 arg, arglen, buf, buflen, IOV_GET); 501 else 502 bcmerror = dhd_bus_iovar_op(dhd_pub, buf, 503 NULL, 0, arg, arglen, IOV_SET); 504 505 break; 506 } 507 508 default: 509 bcmerror = BCME_UNSUPPORTED; 510 } 511 512 return bcmerror; 513 } 514 515 516 #ifdef SHOW_EVENTS 517 static void 518 wl_show_host_event(wl_event_msg_t *event, void *event_data) 519 { 520 uint i, status, reason; 521 bool group = FALSE, flush_txq = FALSE, link = FALSE; 522 char *auth_str, *event_name; 523 uchar *buf; 524 char err_msg[256], eabuf[ETHER_ADDR_STR_LEN]; 525 static struct {uint event; char *event_name;} event_names[] = { 526 {WLC_E_SET_SSID, "SET_SSID"}, 527 {WLC_E_JOIN, "JOIN"}, 528 {WLC_E_START, "START"}, 529 {WLC_E_AUTH, "AUTH"}, 530 {WLC_E_AUTH_IND, "AUTH_IND"}, 531 {WLC_E_DEAUTH, "DEAUTH"}, 532 {WLC_E_DEAUTH_IND, "DEAUTH_IND"}, 533 {WLC_E_ASSOC, "ASSOC"}, 534 {WLC_E_ASSOC_IND, "ASSOC_IND"}, 535 {WLC_E_REASSOC, "REASSOC"}, 536 {WLC_E_REASSOC_IND, "REASSOC_IND"}, 537 {WLC_E_DISASSOC, "DISASSOC"}, 538 {WLC_E_DISASSOC_IND, "DISASSOC_IND"}, 539 {WLC_E_QUIET_START, "START_QUIET"}, 540 {WLC_E_QUIET_END, "END_QUIET"}, 541 {WLC_E_BEACON_RX, "BEACON_RX"}, 542 {WLC_E_LINK, "LINK"}, 543 {WLC_E_MIC_ERROR, "MIC_ERROR"}, 544 {WLC_E_NDIS_LINK, "NDIS_LINK"}, 545 {WLC_E_ROAM, "ROAM"}, 546 {WLC_E_TXFAIL, "TXFAIL"}, 547 {WLC_E_PMKID_CACHE, "PMKID_CACHE"}, 548 {WLC_E_RETROGRADE_TSF, "RETROGRADE_TSF"}, 549 {WLC_E_PRUNE, "PRUNE"}, 550 {WLC_E_AUTOAUTH, "AUTOAUTH"}, 551 {WLC_E_EAPOL_MSG, "EAPOL_MSG"}, 552 {WLC_E_SCAN_COMPLETE, "SCAN_COMPLETE"}, 553 {WLC_E_ADDTS_IND, "ADDTS_IND"}, 554 {WLC_E_DELTS_IND, "DELTS_IND"}, 555 {WLC_E_BCNSENT_IND, "BCNSENT_IND"}, 556 {WLC_E_BCNRX_MSG, "BCNRX_MSG"}, 557 {WLC_E_BCNLOST_MSG, "BCNLOST_MSG"}, 558 {WLC_E_ROAM_PREP, "ROAM_PREP"}, 559 {WLC_E_PFN_NET_FOUND, "PNO_NET_FOUND"}, 560 {WLC_E_PFN_NET_LOST, "PNO_NET_LOST"}, 561 {WLC_E_RESET_COMPLETE, "RESET_COMPLETE"}, 562 {WLC_E_JOIN_START, "JOIN_START"}, 563 {WLC_E_ROAM_START, "ROAM_START"}, 564 {WLC_E_ASSOC_START, "ASSOC_START"}, 565 {WLC_E_IBSS_ASSOC, "IBSS_ASSOC"}, 566 {WLC_E_RADIO, "RADIO"}, 567 {WLC_E_PSM_WATCHDOG, "PSM_WATCHDOG"}, 568 {WLC_E_PROBREQ_MSG, "PROBREQ_MSG"}, 569 {WLC_E_SCAN_CONFIRM_IND, "SCAN_CONFIRM_IND"}, 570 {WLC_E_PSK_SUP, "PSK_SUP"}, 571 {WLC_E_COUNTRY_CODE_CHANGED, "COUNTRY_CODE_CHANGED"}, 572 {WLC_E_EXCEEDED_MEDIUM_TIME, "EXCEEDED_MEDIUM_TIME"}, 573 {WLC_E_ICV_ERROR, "ICV_ERROR"}, 574 {WLC_E_UNICAST_DECODE_ERROR, "UNICAST_DECODE_ERROR"}, 575 {WLC_E_MULTICAST_DECODE_ERROR, "MULTICAST_DECODE_ERROR"}, 576 {WLC_E_TRACE, "TRACE"}, 577 {WLC_E_ACTION_FRAME, "ACTION FRAME"}, 578 {WLC_E_ACTION_FRAME_COMPLETE, "ACTION FRAME TX COMPLETE"}, 579 {WLC_E_IF, "IF"}, 580 {WLC_E_RSSI, "RSSI"}, 581 {WLC_E_PFN_SCAN_COMPLETE, "SCAN_COMPLETE"} 582 }; 583 uint event_type, flags, auth_type, datalen; 584 event_type = ntoh32(event->event_type); 585 flags = ntoh16(event->flags); 586 status = ntoh32(event->status); 587 reason = ntoh32(event->reason); 588 auth_type = ntoh32(event->auth_type); 589 datalen = ntoh32(event->datalen); 590 /* debug dump of event messages */ 591 sprintf(eabuf, "%02x:%02x:%02x:%02x:%02x:%02x", 592 (uchar)event->addr.octet[0]&0xff, 593 (uchar)event->addr.octet[1]&0xff, 594 (uchar)event->addr.octet[2]&0xff, 595 (uchar)event->addr.octet[3]&0xff, 596 (uchar)event->addr.octet[4]&0xff, 597 (uchar)event->addr.octet[5]&0xff); 598 599 event_name = "UNKNOWN"; 600 for (i = 0; i < ARRAYSIZE(event_names); i++) { 601 if (event_names[i].event == event_type) 602 event_name = event_names[i].event_name; 603 } 604 605 DHD_EVENT(("EVENT: %s, event ID = %d\n", event_name, event_type)); 606 607 if (flags & WLC_EVENT_MSG_LINK) 608 link = TRUE; 609 if (flags & WLC_EVENT_MSG_GROUP) 610 group = TRUE; 611 if (flags & WLC_EVENT_MSG_FLUSHTXQ) 612 flush_txq = TRUE; 613 614 switch (event_type) { 615 case WLC_E_START: 616 case WLC_E_DEAUTH: 617 case WLC_E_DISASSOC: 618 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); 619 break; 620 621 case WLC_E_ASSOC_IND: 622 case WLC_E_REASSOC_IND: 623 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); 624 break; 625 626 case WLC_E_ASSOC: 627 case WLC_E_REASSOC: 628 if (status == WLC_E_STATUS_SUCCESS) { 629 DHD_EVENT(("MACEVENT: %s, MAC %s, SUCCESS\n", event_name, eabuf)); 630 } else if (status == WLC_E_STATUS_TIMEOUT) { 631 DHD_EVENT(("MACEVENT: %s, MAC %s, TIMEOUT\n", event_name, eabuf)); 632 } else if (status == WLC_E_STATUS_FAIL) { 633 DHD_EVENT(("MACEVENT: %s, MAC %s, FAILURE, reason %d\n", 634 event_name, eabuf, (int)reason)); 635 } else { 636 DHD_EVENT(("MACEVENT: %s, MAC %s, unexpected status %d\n", 637 event_name, eabuf, (int)status)); 638 } 639 break; 640 641 case WLC_E_DEAUTH_IND: 642 case WLC_E_DISASSOC_IND: 643 DHD_EVENT(("MACEVENT: %s, MAC %s, reason %d\n", event_name, eabuf, (int)reason)); 644 break; 645 646 case WLC_E_AUTH: 647 case WLC_E_AUTH_IND: 648 if (auth_type == DOT11_OPEN_SYSTEM) 649 auth_str = "Open System"; 650 else if (auth_type == DOT11_SHARED_KEY) 651 auth_str = "Shared Key"; 652 else { 653 sprintf(err_msg, "AUTH unknown: %d", (int)auth_type); 654 auth_str = err_msg; 655 } 656 if (event_type == WLC_E_AUTH_IND) { 657 DHD_EVENT(("MACEVENT: %s, MAC %s, %s\n", event_name, eabuf, auth_str)); 658 } else if (status == WLC_E_STATUS_SUCCESS) { 659 DHD_EVENT(("MACEVENT: %s, MAC %s, %s, SUCCESS\n", 660 event_name, eabuf, auth_str)); 661 } else if (status == WLC_E_STATUS_TIMEOUT) { 662 DHD_EVENT(("MACEVENT: %s, MAC %s, %s, TIMEOUT\n", 663 event_name, eabuf, auth_str)); 664 } else if (status == WLC_E_STATUS_FAIL) { 665 DHD_EVENT(("MACEVENT: %s, MAC %s, %s, FAILURE, reason %d\n", 666 event_name, eabuf, auth_str, (int)reason)); 667 } 668 669 break; 670 671 case WLC_E_JOIN: 672 case WLC_E_ROAM: 673 case WLC_E_SET_SSID: 674 if (status == WLC_E_STATUS_SUCCESS) { 675 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); 676 } else if (status == WLC_E_STATUS_FAIL) { 677 DHD_EVENT(("MACEVENT: %s, failed\n", event_name)); 678 } else if (status == WLC_E_STATUS_NO_NETWORKS) { 679 DHD_EVENT(("MACEVENT: %s, no networks found\n", event_name)); 680 } else { 681 DHD_EVENT(("MACEVENT: %s, unexpected status %d\n", 682 event_name, (int)status)); 683 } 684 break; 685 686 case WLC_E_BEACON_RX: 687 if (status == WLC_E_STATUS_SUCCESS) { 688 DHD_EVENT(("MACEVENT: %s, SUCCESS\n", event_name)); 689 } else if (status == WLC_E_STATUS_FAIL) { 690 DHD_EVENT(("MACEVENT: %s, FAIL\n", event_name)); 691 } else { 692 DHD_EVENT(("MACEVENT: %s, status %d\n", event_name, status)); 693 } 694 break; 695 696 case WLC_E_LINK: 697 DHD_EVENT(("MACEVENT: %s %s\n", event_name, link?"UP":"DOWN")); 698 break; 699 700 case WLC_E_MIC_ERROR: 701 DHD_EVENT(("MACEVENT: %s, MAC %s, Group %d, Flush %d\n", 702 event_name, eabuf, group, flush_txq)); 703 break; 704 705 case WLC_E_ICV_ERROR: 706 case WLC_E_UNICAST_DECODE_ERROR: 707 case WLC_E_MULTICAST_DECODE_ERROR: 708 DHD_EVENT(("MACEVENT: %s, MAC %s\n", 709 event_name, eabuf)); 710 break; 711 712 case WLC_E_TXFAIL: 713 DHD_EVENT(("MACEVENT: %s, RA %s\n", event_name, eabuf)); 714 break; 715 716 case WLC_E_SCAN_COMPLETE: 717 case WLC_E_PMKID_CACHE: 718 DHD_EVENT(("MACEVENT: %s\n", event_name)); 719 break; 720 721 case WLC_E_PFN_NET_FOUND: 722 case WLC_E_PFN_NET_LOST: 723 case WLC_E_PFN_SCAN_COMPLETE: 724 DHD_EVENT(("PNOEVENT: %s\n", event_name)); 725 break; 726 727 case WLC_E_PSK_SUP: 728 case WLC_E_PRUNE: 729 DHD_EVENT(("MACEVENT: %s, status %d, reason %d\n", 730 event_name, (int)status, (int)reason)); 731 break; 732 733 case WLC_E_TRACE: 734 { 735 static uint32 seqnum_prev = 0; 736 msgtrace_hdr_t hdr; 737 uint32 nblost; 738 char *s, *p; 739 740 buf = (uchar *) event_data; 741 memcpy(&hdr, buf, MSGTRACE_HDRLEN); 742 743 if (hdr.version != MSGTRACE_VERSION) { 744 printf("\nMACEVENT: %s [unsupported version --> " 745 "dhd version:%d dongle version:%d]\n", 746 event_name, MSGTRACE_VERSION, hdr.version); 747 /* Reset datalen to avoid display below */ 748 datalen = 0; 749 break; 750 } 751 752 /* There are 2 bytes available at the end of data */ 753 buf[MSGTRACE_HDRLEN + ntoh16(hdr.len)] = '\0'; 754 755 if (ntoh32(hdr.discarded_bytes) || ntoh32(hdr.discarded_printf)) { 756 printf("\nWLC_E_TRACE: [Discarded traces in dongle -->" 757 "discarded_bytes %d discarded_printf %d]\n", 758 ntoh32(hdr.discarded_bytes), ntoh32(hdr.discarded_printf)); 759 } 760 761 nblost = ntoh32(hdr.seqnum) - seqnum_prev - 1; 762 if (nblost > 0) { 763 printf("\nWLC_E_TRACE: [Event lost --> seqnum %d nblost %d\n", 764 ntoh32(hdr.seqnum), nblost); 765 } 766 seqnum_prev = ntoh32(hdr.seqnum); 767 768 /* Display the trace buffer. Advance from \n to \n to avoid display big 769 * printf (issue with Linux printk ) 770 */ 771 p = (char *)&buf[MSGTRACE_HDRLEN]; 772 while ((s = strstr(p, "\n")) != NULL) { 773 *s = '\0'; 774 printf("%s\n", p); 775 p = s + 1; 776 } 777 printf("%s\n", p); 778 779 /* Reset datalen to avoid display below */ 780 datalen = 0; 781 } 782 break; 783 784 785 case WLC_E_RSSI: 786 DHD_EVENT(("MACEVENT: %s %d\n", event_name, ntoh32(*((int *)event_data)))); 787 break; 788 789 default: 790 DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, auth %d\n", 791 event_name, event_type, eabuf, (int)status, (int)reason, 792 (int)auth_type)); 793 break; 794 } 795 796 /* show any appended data */ 797 if (datalen) { 798 buf = (uchar *) event_data; 799 DHD_EVENT((" data (%d) : ", datalen)); 800 for (i = 0; i < datalen; i++) 801 DHD_EVENT((" 0x%02x ", *buf++)); 802 DHD_EVENT(("\n")); 803 } 804 } 805 #endif /* SHOW_EVENTS */ 806 807 int 808 wl_host_event(struct dhd_info *dhd, int *ifidx, void *pktdata, 809 wl_event_msg_t *event, void **data_ptr) 810 { 811 /* check whether packet is a BRCM event pkt */ 812 bcm_event_t *pvt_data = (bcm_event_t *)pktdata; 813 char *event_data; 814 uint32 type, status; 815 uint16 flags; 816 int evlen; 817 818 if (bcmp(BRCM_OUI, &pvt_data->bcm_hdr.oui[0], DOT11_OUI_LEN)) { 819 DHD_ERROR(("%s: mismatched OUI, bailing\n", __FUNCTION__)); 820 return (BCME_ERROR); 821 } 822 823 /* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */ 824 if (ntoh16_ua((void *)&pvt_data->bcm_hdr.usr_subtype) != BCMILCP_BCM_SUBTYPE_EVENT) { 825 DHD_ERROR(("%s: mismatched subtype, bailing\n", __FUNCTION__)); 826 return (BCME_ERROR); 827 } 828 829 *data_ptr = &pvt_data[1]; 830 event_data = *data_ptr; 831 832 /* memcpy since BRCM event pkt may be unaligned. */ 833 memcpy(event, &pvt_data->event, sizeof(wl_event_msg_t)); 834 835 type = ntoh32_ua((void *)&event->event_type); 836 flags = ntoh16_ua((void *)&event->flags); 837 status = ntoh32_ua((void *)&event->status); 838 evlen = ntoh32_ua((void *)&event->datalen) + sizeof(bcm_event_t); 839 840 switch (type) { 841 case WLC_E_IF: 842 { 843 dhd_if_event_t *ifevent = (dhd_if_event_t *)event_data; 844 DHD_TRACE(("%s: if event\n", __FUNCTION__)); 845 846 if (ifevent->ifidx > 0 && ifevent->ifidx < DHD_MAX_IFS) 847 { 848 if (ifevent->action == WLC_E_IF_ADD) 849 dhd_add_if(dhd, ifevent->ifidx, 850 NULL, event->ifname, 851 pvt_data->eth.ether_dhost, 852 ifevent->flags, ifevent->bssidx); 853 else 854 dhd_del_if(dhd, ifevent->ifidx); 855 } else { 856 DHD_ERROR(("%s: Invalid ifidx %d for %s\n", 857 __FUNCTION__, ifevent->ifidx, event->ifname)); 858 } 859 } 860 /* send up the if event: btamp user needs it */ 861 *ifidx = dhd_ifname2idx(dhd, event->ifname); 862 /* push up to external supp/auth */ 863 dhd_event(dhd, (char *)pvt_data, evlen, *ifidx); 864 break; 865 866 867 #ifdef P2P 868 case WLC_E_NDIS_LINK: 869 break; 870 #endif 871 /* fall through */ 872 /* These are what external supplicant/authenticator wants */ 873 case WLC_E_LINK: 874 case WLC_E_ASSOC_IND: 875 case WLC_E_REASSOC_IND: 876 case WLC_E_DISASSOC_IND: 877 case WLC_E_MIC_ERROR: 878 default: 879 /* Fall through: this should get _everything_ */ 880 881 *ifidx = dhd_ifname2idx(dhd, event->ifname); 882 /* push up to external supp/auth */ 883 dhd_event(dhd, (char *)pvt_data, evlen, *ifidx); 884 DHD_TRACE(("%s: MAC event %d, flags %x, status %x\n", 885 __FUNCTION__, type, flags, status)); 886 887 /* put it back to WLC_E_NDIS_LINK */ 888 if (type == WLC_E_NDIS_LINK) { 889 uint32 temp; 890 891 temp = ntoh32_ua((void *)&event->event_type); 892 DHD_TRACE(("Converted to WLC_E_LINK type %d\n", temp)); 893 894 temp = ntoh32(WLC_E_NDIS_LINK); 895 memcpy((void *)(&pvt_data->event.event_type), &temp, 896 sizeof(pvt_data->event.event_type)); 897 } 898 break; 899 } 900 901 #ifdef SHOW_EVENTS 902 wl_show_host_event(event, event_data); 903 #endif /* SHOW_EVENTS */ 904 905 return (BCME_OK); 906 } 907 908 909 void 910 wl_event_to_host_order(wl_event_msg_t *evt) 911 { 912 /* Event struct members passed from dongle to host are stored in network 913 * byte order. Convert all members to host-order. 914 */ 915 evt->event_type = ntoh32(evt->event_type); 916 evt->flags = ntoh16(evt->flags); 917 evt->status = ntoh32(evt->status); 918 evt->reason = ntoh32(evt->reason); 919 evt->auth_type = ntoh32(evt->auth_type); 920 evt->datalen = ntoh32(evt->datalen); 921 evt->version = ntoh16(evt->version); 922 } 923 924 void print_buf(void *pbuf, int len, int bytes_per_line) 925 { 926 int i, j = 0; 927 unsigned char *buf = pbuf; 928 929 if (bytes_per_line == 0) { 930 bytes_per_line = len; 931 } 932 933 for (i = 0; i < len; i++) { 934 printf("%2.2x", *buf++); 935 j++; 936 if (j == bytes_per_line) { 937 printf("\n"); 938 j = 0; 939 } else { 940 printf(":"); 941 } 942 } 943 printf("\n"); 944 } 945 946 #define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) 947 948 #ifdef PKT_FILTER_SUPPORT 949 /* Convert user's input in hex pattern to byte-size mask */ 950 static int 951 wl_pattern_atoh(char *src, char *dst) 952 { 953 int i; 954 if (strncmp(src, "0x", 2) != 0 && 955 strncmp(src, "0X", 2) != 0) { 956 DHD_ERROR(("Mask invalid format. Needs to start with 0x\n")); 957 return -1; 958 } 959 src = src + 2; /* Skip past 0x */ 960 if (strlen(src) % 2 != 0) { 961 DHD_ERROR(("Mask invalid format. Needs to be of even length\n")); 962 return -1; 963 } 964 for (i = 0; *src != '\0'; i++) { 965 char num[3]; 966 strncpy(num, src, 2); 967 num[2] = '\0'; 968 dst[i] = (uint8)strtoul(num, NULL, 16); 969 src += 2; 970 } 971 return i; 972 } 973 974 void 975 dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode) 976 { 977 char *argv[8]; 978 int i = 0; 979 const char *str; 980 int buf_len; 981 int str_len; 982 char *arg_save = 0, *arg_org = 0; 983 int rc; 984 char buf[128]; 985 wl_pkt_filter_enable_t enable_parm; 986 wl_pkt_filter_enable_t * pkt_filterp; 987 988 if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) { 989 DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); 990 goto fail; 991 } 992 arg_org = arg_save; 993 memcpy(arg_save, arg, strlen(arg) + 1); 994 995 argv[i] = bcmstrtok(&arg_save, " ", 0); 996 997 i = 0; 998 if (NULL == argv[i]) { 999 DHD_ERROR(("No args provided\n")); 1000 goto fail; 1001 } 1002 1003 str = "pkt_filter_enable"; 1004 str_len = strlen(str); 1005 strncpy(buf, str, str_len); 1006 buf[str_len] = '\0'; 1007 buf_len = str_len + 1; 1008 1009 pkt_filterp = (wl_pkt_filter_enable_t *)(buf + str_len + 1); 1010 1011 /* Parse packet filter id. */ 1012 enable_parm.id = htod32(strtoul(argv[i], NULL, 0)); 1013 1014 /* Parse enable/disable value. */ 1015 enable_parm.enable = htod32(enable); 1016 1017 buf_len += sizeof(enable_parm); 1018 memcpy((char *)pkt_filterp, 1019 &enable_parm, 1020 sizeof(enable_parm)); 1021 1022 /* Enable/disable the specified filter. */ 1023 rc = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, buf_len); 1024 rc = rc >= 0 ? 0 : rc; 1025 if (rc) 1026 DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", 1027 __FUNCTION__, arg, rc)); 1028 else 1029 DHD_TRACE(("%s: successfully added pktfilter %s\n", 1030 __FUNCTION__, arg)); 1031 1032 /* Contorl the master mode */ 1033 bcm_mkiovar("pkt_filter_mode", (char *)&master_mode, 4, buf, sizeof(buf)); 1034 rc = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, sizeof(buf)); 1035 rc = rc >= 0 ? 0 : rc; 1036 if (rc) 1037 DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", 1038 __FUNCTION__, arg, rc)); 1039 1040 fail: 1041 if (arg_org) 1042 MFREE(dhd->osh, arg_org, strlen(arg) + 1); 1043 } 1044 1045 void 1046 dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg) 1047 { 1048 const char *str; 1049 wl_pkt_filter_t pkt_filter; 1050 wl_pkt_filter_t *pkt_filterp; 1051 int buf_len; 1052 int str_len; 1053 int rc; 1054 uint32 mask_size; 1055 uint32 pattern_size; 1056 char *argv[8], * buf = 0; 1057 int i = 0; 1058 char *arg_save = 0, *arg_org = 0; 1059 #define BUF_SIZE 2048 1060 1061 if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) { 1062 DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); 1063 goto fail; 1064 } 1065 1066 arg_org = arg_save; 1067 1068 if (!(buf = MALLOC(dhd->osh, BUF_SIZE))) { 1069 DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); 1070 goto fail; 1071 } 1072 1073 memcpy(arg_save, arg, strlen(arg) + 1); 1074 1075 if (strlen(arg) > BUF_SIZE) { 1076 DHD_ERROR(("Not enough buffer %d < %d\n", (int)strlen(arg), (int)sizeof(buf))); 1077 goto fail; 1078 } 1079 1080 argv[i] = bcmstrtok(&arg_save, " ", 0); 1081 while (argv[i++]) 1082 argv[i] = bcmstrtok(&arg_save, " ", 0); 1083 1084 i = 0; 1085 if (NULL == argv[i]) { 1086 DHD_ERROR(("No args provided\n")); 1087 goto fail; 1088 } 1089 1090 str = "pkt_filter_add"; 1091 str_len = strlen(str); 1092 strncpy(buf, str, str_len); 1093 buf[ str_len ] = '\0'; 1094 buf_len = str_len + 1; 1095 1096 pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1); 1097 1098 /* Parse packet filter id. */ 1099 pkt_filter.id = htod32(strtoul(argv[i], NULL, 0)); 1100 1101 if (NULL == argv[++i]) { 1102 DHD_ERROR(("Polarity not provided\n")); 1103 goto fail; 1104 } 1105 1106 /* Parse filter polarity. */ 1107 pkt_filter.negate_match = htod32(strtoul(argv[i], NULL, 0)); 1108 1109 if (NULL == argv[++i]) { 1110 DHD_ERROR(("Filter type not provided\n")); 1111 goto fail; 1112 } 1113 1114 /* Parse filter type. */ 1115 pkt_filter.type = htod32(strtoul(argv[i], NULL, 0)); 1116 1117 if (NULL == argv[++i]) { 1118 DHD_ERROR(("Offset not provided\n")); 1119 goto fail; 1120 } 1121 1122 /* Parse pattern filter offset. */ 1123 pkt_filter.u.pattern.offset = htod32(strtoul(argv[i], NULL, 0)); 1124 1125 if (NULL == argv[++i]) { 1126 DHD_ERROR(("Bitmask not provided\n")); 1127 goto fail; 1128 } 1129 1130 /* Parse pattern filter mask. */ 1131 mask_size = 1132 htod32(wl_pattern_atoh(argv[i], (char *) pkt_filterp->u.pattern.mask_and_pattern)); 1133 1134 if (NULL == argv[++i]) { 1135 DHD_ERROR(("Pattern not provided\n")); 1136 goto fail; 1137 } 1138 1139 /* Parse pattern filter pattern. */ 1140 pattern_size = 1141 htod32(wl_pattern_atoh(argv[i], 1142 (char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size])); 1143 1144 if (mask_size != pattern_size) { 1145 DHD_ERROR(("Mask and pattern not the same size\n")); 1146 goto fail; 1147 } 1148 1149 pkt_filter.u.pattern.size_bytes = mask_size; 1150 buf_len += WL_PKT_FILTER_FIXED_LEN; 1151 buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size); 1152 1153 /* Keep-alive attributes are set in local variable (keep_alive_pkt), and 1154 ** then memcpy'ed into buffer (keep_alive_pktp) since there is no 1155 ** guarantee that the buffer is properly aligned. 1156 */ 1157 memcpy((char *)pkt_filterp, 1158 &pkt_filter, 1159 WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN); 1160 1161 rc = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, buf_len); 1162 rc = rc >= 0 ? 0 : rc; 1163 1164 if (rc) 1165 DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", 1166 __FUNCTION__, arg, rc)); 1167 else 1168 DHD_TRACE(("%s: successfully added pktfilter %s\n", 1169 __FUNCTION__, arg)); 1170 1171 fail: 1172 if (arg_org) 1173 MFREE(dhd->osh, arg_org, strlen(arg) + 1); 1174 1175 if (buf) 1176 MFREE(dhd->osh, buf, BUF_SIZE); 1177 } 1178 #endif 1179 1180 #ifdef ARP_OFFLOAD_SUPPORT 1181 void 1182 dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode) 1183 { 1184 char iovbuf[32]; 1185 int retcode; 1186 1187 bcm_mkiovar("arp_ol", (char *)&arp_mode, 4, iovbuf, sizeof(iovbuf)); 1188 retcode = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); 1189 retcode = retcode >= 0 ? 0 : retcode; 1190 if (retcode) 1191 DHD_TRACE(("%s: failed to set ARP offload mode to 0x%x, retcode = %d\n", 1192 __FUNCTION__, arp_mode, retcode)); 1193 else 1194 DHD_TRACE(("%s: successfully set ARP offload mode to 0x%x\n", 1195 __FUNCTION__, arp_mode)); 1196 } 1197 1198 void 1199 dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable) 1200 { 1201 char iovbuf[32]; 1202 int retcode; 1203 1204 bcm_mkiovar("arpoe", (char *)&arp_enable, 4, iovbuf, sizeof(iovbuf)); 1205 retcode = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); 1206 retcode = retcode >= 0 ? 0 : retcode; 1207 if (retcode) 1208 DHD_TRACE(("%s: failed to enabe ARP offload to %d, retcode = %d\n", 1209 __FUNCTION__, arp_enable, retcode)); 1210 else 1211 DHD_TRACE(("%s: successfully enabed ARP offload to %d\n", 1212 __FUNCTION__, arp_enable)); 1213 } 1214 #endif 1215 1216 int 1217 dhd_preinit_ioctls(dhd_pub_t *dhd) 1218 { 1219 char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */ 1220 uint up = 0; 1221 char buf[128], *ptr; 1222 uint power_mode = PM_FAST; 1223 uint32 dongle_align = DHD_SDALIGN; 1224 uint32 glom = 0; 1225 uint bcn_timeout = 3; 1226 int scan_assoc_time = 40; 1227 int scan_unassoc_time = 40; 1228 #ifdef GET_CUSTOM_MAC_ENABLE 1229 int ret; 1230 struct ether_addr ea_addr; 1231 #endif /* GET_CUSTOM_MAC_ENABLE */ 1232 1233 dhd_os_proto_block(dhd); 1234 1235 #ifdef GET_CUSTOM_MAC_ENABLE 1236 /* 1237 ** Read MAC address from external customer place 1238 ** NOTE that default mac address has to be present in otp or nvram file 1239 ** to bring up firmware but unique per board mac address maybe provided 1240 ** by customer code 1241 */ 1242 ret = dhd_custom_get_mac_address(ea_addr.octet); 1243 if (!ret) { 1244 bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETHER_ADDR_LEN, buf, sizeof(buf)); 1245 ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, sizeof(buf)); 1246 if (ret < 0) { 1247 DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret)); 1248 } else 1249 memcpy(dhd->mac.octet, (void *)&ea_addr, ETHER_ADDR_LEN); 1250 } 1251 #endif /* GET_CUSTOM_MAC_ENABLE */ 1252 1253 #ifdef SET_RANDOM_MAC_SOFTAP 1254 if (strstr(fw_path, "apsta") != NULL) { 1255 uint rand_mac; 1256 int ret; 1257 1258 srandom32((uint)jiffies); 1259 rand_mac = random32(); 1260 iovbuf[0] = 0x02; /* locally administered bit */ 1261 iovbuf[1] = 0x1A; 1262 iovbuf[2] = 0x11; 1263 iovbuf[3] = (unsigned char)(rand_mac & 0x0F) | 0xF0; 1264 iovbuf[4] = (unsigned char)(rand_mac >> 8); 1265 iovbuf[5] = (unsigned char)(rand_mac >> 16); 1266 1267 printk("Broadcom Dongle Host Driver mac=%02x:%02x:%02x:%02x:%02x:%02x\n", 1268 iovbuf[0], iovbuf[1], iovbuf[2], iovbuf[3], iovbuf[4], iovbuf[5]); 1269 1270 bcm_mkiovar("cur_etheraddr", (void *)iovbuf, ETHER_ADDR_LEN, buf, sizeof(buf)); 1271 ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, sizeof(buf)); 1272 if (ret < 0) { 1273 DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret)); 1274 } else 1275 memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN); 1276 } 1277 #endif /* SET_RANDOM_MAC_SOFTAP */ 1278 1279 /* Set Country code */ 1280 if (dhd->country_code[0] != 0) { 1281 if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_COUNTRY, 1282 dhd->country_code, sizeof(dhd->country_code)) < 0) { 1283 DHD_ERROR(("%s: country code setting failed\n", __FUNCTION__)); 1284 } 1285 } 1286 1287 /* query for 'ver' to get version info from firmware */ 1288 memset(buf, 0, sizeof(buf)); 1289 ptr = buf; 1290 bcm_mkiovar("ver", 0, 0, buf, sizeof(buf)); 1291 dhdcdc_query_ioctl(dhd, 0, WLC_GET_VAR, buf, sizeof(buf)); 1292 bcmstrtok(&ptr, "\n", 0); 1293 /* Print fw version info */ 1294 DHD_ERROR(("Firmware version = %s\n", buf)); 1295 1296 /* Set PowerSave mode */ 1297 dhdcdc_set_ioctl(dhd, 0, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode)); 1298 1299 /* Match Host and Dongle rx alignment */ 1300 bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf)); 1301 dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); 1302 1303 /* disable glom option per default */ 1304 bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf)); 1305 dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); 1306 1307 /* Setup timeout if Beacons are lost and roam is off to report link down */ 1308 bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf)); 1309 dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); 1310 1311 /* Enable/Disable build-in roaming to allowed ext supplicant to take of romaing */ 1312 bcm_mkiovar("roam_off", (char *)&dhd_roam, 4, iovbuf, sizeof(iovbuf)); 1313 dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); 1314 1315 if (dhd_roam == 0) 1316 { 1317 /* set internal roaming roaming parameters */ 1318 int roam_scan_period = 30; /* in sec */ 1319 int roam_fullscan_period = 120; /* in sec */ 1320 int roam_trigger = -85; 1321 int roam_delta = 15; 1322 int band; 1323 int band_temp_set = WLC_BAND_2G; 1324 1325 if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_ROAM_SCAN_PERIOD, \ 1326 (char *)&roam_scan_period, sizeof(roam_scan_period)) < 0) 1327 DHD_ERROR(("%s: roam scan setup failed\n", __FUNCTION__)); 1328 1329 bcm_mkiovar("fullroamperiod", (char *)&roam_fullscan_period, \ 1330 4, iovbuf, sizeof(iovbuf)); 1331 if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, \ 1332 iovbuf, sizeof(iovbuf)) < 0) 1333 DHD_ERROR(("%s: roam fullscan setup failed\n", __FUNCTION__)); 1334 1335 if (dhdcdc_query_ioctl(dhd, 0, WLC_GET_BAND, \ 1336 (char *)&band, sizeof(band)) < 0) 1337 DHD_ERROR(("%s: roam delta setting failed\n", __FUNCTION__)); 1338 else { 1339 if ((band == WLC_BAND_AUTO) || (band == WLC_BAND_ALL)) 1340 { 1341 /* temp set band to insert new roams values */ 1342 if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_BAND, \ 1343 (char *)&band_temp_set, sizeof(band_temp_set)) < 0) 1344 DHD_ERROR(("%s: local band seting failed\n", __FUNCTION__)); 1345 } 1346 if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_ROAM_DELTA, \ 1347 (char *)&roam_delta, sizeof(roam_delta)) < 0) 1348 DHD_ERROR(("%s: roam delta setting failed\n", __FUNCTION__)); 1349 1350 if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_ROAM_TRIGGER, \ 1351 (char *)&roam_trigger, sizeof(roam_trigger)) < 0) 1352 DHD_ERROR(("%s: roam trigger setting failed\n", __FUNCTION__)); 1353 1354 /* Restore original band settinngs */ 1355 if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_BAND, \ 1356 (char *)&band, sizeof(band)) < 0) 1357 DHD_ERROR(("%s: Original band restore failed\n", __FUNCTION__)); 1358 } 1359 } 1360 1361 /* Force STA UP */ 1362 if (dhd_radio_up) 1363 dhdcdc_set_ioctl(dhd, 0, WLC_UP, (char *)&up, sizeof(up)); 1364 1365 /* Setup event_msgs */ 1366 bcm_mkiovar("event_msgs", dhd->eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); 1367 dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); 1368 1369 dhdcdc_set_ioctl(dhd, 0, WLC_SET_SCAN_CHANNEL_TIME, (char *)&scan_assoc_time, 1370 sizeof(scan_assoc_time)); 1371 dhdcdc_set_ioctl(dhd, 0, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time, 1372 sizeof(scan_unassoc_time)); 1373 1374 #ifdef ARP_OFFLOAD_SUPPORT 1375 /* Set and enable ARP offload feature */ 1376 if (dhd_arp_enable) 1377 dhd_arp_offload_set(dhd, dhd_arp_mode); 1378 dhd_arp_offload_enable(dhd, dhd_arp_enable); 1379 #endif /* ARP_OFFLOAD_SUPPORT */ 1380 1381 #ifdef PKT_FILTER_SUPPORT 1382 { 1383 int i; 1384 /* Set up pkt filter */ 1385 if (dhd_pkt_filter_enable) { 1386 for (i = 0; i < dhd->pktfilter_count; i++) { 1387 dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]); 1388 dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i], 1389 dhd_pkt_filter_init, dhd_master_mode); 1390 } 1391 } 1392 } 1393 #endif /* PKT_FILTER_SUPPORT */ 1394 1395 dhd_os_proto_unblock(dhd); 1396 1397 return 0; 1398 } 1399 1400 #ifdef SIMPLE_ISCAN 1401 1402 uint iscan_thread_id; 1403 iscan_buf_t * iscan_chain = 0; 1404 1405 iscan_buf_t * 1406 dhd_iscan_allocate_buf(dhd_pub_t *dhd, iscan_buf_t **iscanbuf) 1407 { 1408 iscan_buf_t *iscanbuf_alloc = 0; 1409 iscan_buf_t *iscanbuf_head; 1410 1411 dhd_iscan_lock(); 1412 1413 iscanbuf_alloc = (iscan_buf_t*)MALLOC(dhd->osh, sizeof(iscan_buf_t)); 1414 if (iscanbuf_alloc == NULL) 1415 goto fail; 1416 1417 iscanbuf_alloc->next = NULL; 1418 iscanbuf_head = *iscanbuf; 1419 1420 DHD_ISCAN(("%s: addr of allocated node = 0x%X" 1421 "addr of iscanbuf_head = 0x%X dhd = 0x%X\n", 1422 __FUNCTION__, iscanbuf_alloc, iscanbuf_head, dhd)); 1423 1424 if (iscanbuf_head == NULL) { 1425 *iscanbuf = iscanbuf_alloc; 1426 DHD_ISCAN(("%s: Head is allocated\n", __FUNCTION__)); 1427 goto fail; 1428 } 1429 1430 while (iscanbuf_head->next) 1431 iscanbuf_head = iscanbuf_head->next; 1432 1433 iscanbuf_head->next = iscanbuf_alloc; 1434 1435 fail: 1436 dhd_iscan_unlock(); 1437 return iscanbuf_alloc; 1438 } 1439 1440 void 1441 dhd_iscan_free_buf(void *dhdp, iscan_buf_t *iscan_delete) 1442 { 1443 iscan_buf_t *iscanbuf_free = 0; 1444 iscan_buf_t *iscanbuf_prv = 0; 1445 iscan_buf_t *iscanbuf_cur = iscan_chain; 1446 dhd_pub_t *dhd = dhd_bus_pub(dhdp); 1447 1448 dhd_iscan_lock(); 1449 /* If iscan_delete is null then delete the entire 1450 * chain or else delete specific one provided 1451 */ 1452 if (!iscan_delete) { 1453 while (iscanbuf_cur) { 1454 iscanbuf_free = iscanbuf_cur; 1455 iscanbuf_cur = iscanbuf_cur->next; 1456 iscanbuf_free->next = 0; 1457 MFREE(dhd->osh, iscanbuf_free, sizeof(iscan_buf_t)); 1458 } 1459 iscan_chain = 0; 1460 } else { 1461 while (iscanbuf_cur) { 1462 if (iscanbuf_cur == iscan_delete) 1463 break; 1464 iscanbuf_prv = iscanbuf_cur; 1465 iscanbuf_cur = iscanbuf_cur->next; 1466 } 1467 if (iscanbuf_prv) 1468 iscanbuf_prv->next = iscan_delete->next; 1469 1470 iscan_delete->next = 0; 1471 MFREE(dhd->osh, iscan_delete, sizeof(iscan_buf_t)); 1472 1473 if (!iscanbuf_prv) 1474 iscan_chain = 0; 1475 } 1476 dhd_iscan_unlock(); 1477 } 1478 1479 iscan_buf_t * 1480 dhd_iscan_result_buf(void) 1481 { 1482 return iscan_chain; 1483 } 1484 1485 1486 1487 /* 1488 * print scan cache 1489 * print partial iscan_skip list differently 1490 */ 1491 int 1492 dhd_iscan_print_cache(iscan_buf_t *iscan_skip) 1493 { 1494 int i = 0, l = 0; 1495 iscan_buf_t *iscan_cur; 1496 wl_iscan_results_t *list; 1497 wl_scan_results_t *results; 1498 wl_bss_info_t UNALIGNED *bi; 1499 1500 dhd_iscan_lock(); 1501 1502 iscan_cur = dhd_iscan_result_buf(); 1503 1504 while (iscan_cur) { 1505 list = (wl_iscan_results_t *)iscan_cur->iscan_buf; 1506 if (!list) 1507 break; 1508 1509 results = (wl_scan_results_t *)&list->results; 1510 if (!results) 1511 break; 1512 1513 if (results->version != WL_BSS_INFO_VERSION) { 1514 DHD_ISCAN(("%s: results->version %d != WL_BSS_INFO_VERSION\n", 1515 __FUNCTION__, results->version)); 1516 goto done; 1517 } 1518 1519 bi = results->bss_info; 1520 for (i = 0; i < results->count; i++) { 1521 if (!bi) 1522 break; 1523 1524 DHD_ISCAN(("%s[%2.2d:%2.2d] %X:%X:%X:%X:%X:%X\n", 1525 iscan_cur != iscan_skip?"BSS":"bss", l, i, 1526 bi->BSSID.octet[0], bi->BSSID.octet[1], bi->BSSID.octet[2], 1527 bi->BSSID.octet[3], bi->BSSID.octet[4], bi->BSSID.octet[5])); 1528 1529 bi = (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)); 1530 } 1531 iscan_cur = iscan_cur->next; 1532 l++; 1533 } 1534 1535 done: 1536 dhd_iscan_unlock(); 1537 return 0; 1538 } 1539 1540 /* 1541 * delete disappeared AP from specific scan cache but skip partial list in iscan_skip 1542 */ 1543 int 1544 dhd_iscan_delete_bss(void *dhdp, void *addr, iscan_buf_t *iscan_skip) 1545 { 1546 int i = 0, j = 0, l = 0; 1547 iscan_buf_t *iscan_cur; 1548 wl_iscan_results_t *list; 1549 wl_scan_results_t *results; 1550 wl_bss_info_t UNALIGNED *bi, *bi_new, *bi_next; 1551 1552 uchar *s_addr = addr; 1553 1554 dhd_iscan_lock(); 1555 DHD_ISCAN(("%s: BSS to remove %X:%X:%X:%X:%X:%X\n", 1556 __FUNCTION__, s_addr[0], s_addr[1], s_addr[2], 1557 s_addr[3], s_addr[4], s_addr[5])); 1558 1559 iscan_cur = dhd_iscan_result_buf(); 1560 1561 while (iscan_cur) { 1562 if (iscan_cur != iscan_skip) { 1563 list = (wl_iscan_results_t *)iscan_cur->iscan_buf; 1564 if (!list) 1565 break; 1566 1567 results = (wl_scan_results_t *)&list->results; 1568 if (!results) 1569 break; 1570 1571 if (results->version != WL_BSS_INFO_VERSION) { 1572 DHD_ERROR(("%s: results->version %d != WL_BSS_INFO_VERSION\n", 1573 __FUNCTION__, results->version)); 1574 goto done; 1575 } 1576 1577 bi = results->bss_info; 1578 for (i = 0; i < results->count; i++) { 1579 if (!bi) 1580 break; 1581 1582 if (!memcmp(bi->BSSID.octet, addr, ETHER_ADDR_LEN)) { 1583 DHD_ISCAN(("%s: Del BSS[%2.2d:%2.2d] %X:%X:%X:%X:%X:%X\n", 1584 __FUNCTION__, l, i, bi->BSSID.octet[0], 1585 bi->BSSID.octet[1], bi->BSSID.octet[2], 1586 bi->BSSID.octet[3], bi->BSSID.octet[4], 1587 bi->BSSID.octet[5])); 1588 1589 bi_new = bi; 1590 bi = (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)); 1591 /* 1592 if(bi && bi_new) { 1593 bcopy(bi, bi_new, results->buflen - 1594 dtoh32(bi_new->length)); 1595 results->buflen -= dtoh32(bi_new->length); 1596 } 1597 */ 1598 results->buflen -= dtoh32(bi_new->length); 1599 results->count--; 1600 1601 for (j = i; j < results->count; j++) { 1602 if (bi && bi_new) { 1603 DHD_ISCAN(("%s: Moved up BSS[%2.2d:%2.2d]" 1604 "%X:%X:%X:%X:%X:%X\n", 1605 __FUNCTION__, l, j, bi->BSSID.octet[0], 1606 bi->BSSID.octet[1], bi->BSSID.octet[2], 1607 bi->BSSID.octet[3], bi->BSSID.octet[4], 1608 bi->BSSID.octet[5])); 1609 1610 bi_next = (wl_bss_info_t *)((uintptr)bi + 1611 dtoh32(bi->length)); 1612 bcopy(bi, bi_new, dtoh32(bi->length)); 1613 bi_new = (wl_bss_info_t *)((uintptr)bi_new + 1614 dtoh32(bi_new->length)); 1615 bi = bi_next; 1616 } 1617 } 1618 1619 if (results->count == 0) { 1620 /* Prune now empty partial scan list */ 1621 dhd_iscan_free_buf(dhdp, iscan_cur); 1622 goto done; 1623 } 1624 break; 1625 } 1626 bi = (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)); 1627 } 1628 } 1629 iscan_cur = iscan_cur->next; 1630 l++; 1631 } 1632 1633 done: 1634 dhd_iscan_unlock(); 1635 return 0; 1636 } 1637 1638 int 1639 dhd_iscan_remove_duplicates(void * dhdp, iscan_buf_t *iscan_cur) 1640 { 1641 int i = 0; 1642 wl_iscan_results_t *list; 1643 wl_scan_results_t *results; 1644 wl_bss_info_t UNALIGNED *bi, *bi_new, *bi_next; 1645 1646 dhd_iscan_lock(); 1647 1648 DHD_ISCAN(("%s: Scan cache before delete\n", 1649 __FUNCTION__)); 1650 dhd_iscan_print_cache(iscan_cur); 1651 1652 if (!iscan_cur) 1653 goto done; 1654 1655 list = (wl_iscan_results_t *)iscan_cur->iscan_buf; 1656 if (!list) 1657 goto done; 1658 1659 results = (wl_scan_results_t *)&list->results; 1660 if (!results) 1661 goto done; 1662 1663 if (results->version != WL_BSS_INFO_VERSION) { 1664 DHD_ERROR(("%s: results->version %d != WL_BSS_INFO_VERSION\n", 1665 __FUNCTION__, results->version)); 1666 goto done; 1667 } 1668 1669 bi = results->bss_info; 1670 for (i = 0; i < results->count; i++) { 1671 if (!bi) 1672 break; 1673 1674 DHD_ISCAN(("%s: Find dups for BSS[%2.2d] %X:%X:%X:%X:%X:%X\n", 1675 __FUNCTION__, i, bi->BSSID.octet[0], bi->BSSID.octet[1], bi->BSSID.octet[2], 1676 bi->BSSID.octet[3], bi->BSSID.octet[4], bi->BSSID.octet[5])); 1677 1678 dhd_iscan_delete_bss(dhdp, bi->BSSID.octet, iscan_cur); 1679 1680 bi = (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)); 1681 } 1682 1683 done: 1684 DHD_ISCAN(("%s: Scan cache after delete\n", __FUNCTION__)); 1685 dhd_iscan_print_cache(iscan_cur); 1686 dhd_iscan_unlock(); 1687 return 0; 1688 } 1689 1690 void 1691 dhd_iscan_ind_scan_confirm(void *dhdp, bool status) 1692 { 1693 1694 dhd_ind_scan_confirm(dhdp, status); 1695 } 1696 1697 int 1698 dhd_iscan_request(void * dhdp, uint16 action) 1699 { 1700 int rc; 1701 wl_iscan_params_t params; 1702 dhd_pub_t *dhd = dhd_bus_pub(dhdp); 1703 char buf[WLC_IOCTL_SMLEN]; 1704 1705 1706 memset(¶ms, 0, sizeof(wl_iscan_params_t)); 1707 memcpy(¶ms.params.bssid, ðer_bcast, ETHER_ADDR_LEN); 1708 1709 params.params.bss_type = DOT11_BSSTYPE_ANY; 1710 params.params.scan_type = DOT11_SCANTYPE_ACTIVE; 1711 1712 params.params.nprobes = htod32(-1); 1713 params.params.active_time = htod32(-1); 1714 params.params.passive_time = htod32(-1); 1715 params.params.home_time = htod32(-1); 1716 params.params.channel_num = htod32(0); 1717 1718 params.version = htod32(ISCAN_REQ_VERSION); 1719 params.action = htod16(action); 1720 params.scan_duration = htod16(0); 1721 1722 bcm_mkiovar("iscan", (char *)¶ms, sizeof(wl_iscan_params_t), buf, WLC_IOCTL_SMLEN); 1723 rc = dhd_wl_ioctl(dhdp, WLC_SET_VAR, buf, WLC_IOCTL_SMLEN); 1724 1725 return rc; 1726 } 1727 1728 static int 1729 dhd_iscan_get_partial_result(void *dhdp, uint *scan_count) 1730 { 1731 wl_iscan_results_t *list_buf; 1732 wl_iscan_results_t list; 1733 wl_scan_results_t *results; 1734 iscan_buf_t *iscan_cur; 1735 int status = -1; 1736 dhd_pub_t *dhd = dhd_bus_pub(dhdp); 1737 int rc; 1738 1739 1740 iscan_cur = dhd_iscan_allocate_buf(dhd, &iscan_chain); 1741 if (!iscan_cur) { 1742 DHD_ERROR(("%s: Failed to allocate node\n", __FUNCTION__)); 1743 dhd_iscan_free_buf(dhdp, 0); 1744 dhd_iscan_request(dhdp, WL_SCAN_ACTION_ABORT); 1745 goto fail; 1746 } 1747 1748 dhd_iscan_lock(); 1749 1750 memset(iscan_cur->iscan_buf, 0, WLC_IW_ISCAN_MAXLEN); 1751 list_buf = (wl_iscan_results_t*)iscan_cur->iscan_buf; 1752 results = &list_buf->results; 1753 results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE; 1754 results->version = 0; 1755 results->count = 0; 1756 1757 memset(&list, 0, sizeof(list)); 1758 list.results.buflen = htod32(WLC_IW_ISCAN_MAXLEN); 1759 bcm_mkiovar("iscanresults", (char *)&list, WL_ISCAN_RESULTS_FIXED_SIZE, 1760 iscan_cur->iscan_buf, WLC_IW_ISCAN_MAXLEN); 1761 rc = dhd_wl_ioctl(dhdp, WLC_GET_VAR, iscan_cur->iscan_buf, WLC_IW_ISCAN_MAXLEN); 1762 1763 results->buflen = dtoh32(results->buflen); 1764 results->version = dtoh32(results->version); 1765 *scan_count = results->count = dtoh32(results->count); 1766 status = dtoh32(list_buf->status); 1767 1768 dhd_iscan_unlock(); 1769 1770 if (!(*scan_count)) 1771 dhd_iscan_free_buf(dhdp, iscan_cur); 1772 else 1773 dhd_iscan_remove_duplicates(dhdp, iscan_cur); 1774 1775 1776 fail: 1777 return status; 1778 } 1779 1780 #endif 1781 1782 #ifdef PNO_SUPPORT 1783 int dhd_pno_clean(dhd_pub_t *dhd) 1784 { 1785 char iovbuf[128]; 1786 int pfn_enabled = 0; 1787 int iov_len = 0; 1788 int ret; 1789 1790 /* Disable pfn */ 1791 iov_len = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf)); 1792 if ((ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf))) >= 0) { 1793 /* clear pfn */ 1794 iov_len = bcm_mkiovar("pfnclear", 0, 0, iovbuf, sizeof(iovbuf)); 1795 if (iov_len) { 1796 if ((ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, iov_len)) < 0) { 1797 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); 1798 } 1799 } 1800 else { 1801 ret = -1; 1802 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, iov_len)); 1803 } 1804 } 1805 else 1806 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); 1807 1808 return ret; 1809 } 1810 1811 int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled) 1812 { 1813 char iovbuf[128]; 1814 int ret = -1; 1815 1816 if ((!dhd) && ((pfn_enabled != 0) || (pfn_enabled != 1))) { 1817 DHD_ERROR(("%s error exit\n", __FUNCTION__)); 1818 return ret; 1819 } 1820 1821 /* Enable/disable PNO */ 1822 if ((ret = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf))) > 0) { 1823 if ((ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf))) < 0) { 1824 DHD_ERROR(("%s failed for error=%d\n", __FUNCTION__, ret)); 1825 return ret; 1826 } 1827 else { 1828 dhd->pno_enable = pfn_enabled; 1829 DHD_TRACE(("%s set pno as %d\n", __FUNCTION__, dhd->pno_enable)); 1830 } 1831 } 1832 else DHD_ERROR(("%s failed err=%d\n", __FUNCTION__, ret)); 1833 1834 return ret; 1835 } 1836 1837 /* Function to execute combined scan */ 1838 int 1839 dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr) 1840 { 1841 int err = -1; 1842 char iovbuf[128]; 1843 int k, i; 1844 wl_pfn_param_t pfn_param; 1845 wl_pfn_t pfn_element; 1846 1847 DHD_TRACE(("%s nssid=%d nchan=%d\n", __FUNCTION__, nssid, scan_fr)); 1848 1849 if ((!dhd) && (!ssids_local)) { 1850 DHD_ERROR(("%s error exit\n", __FUNCTION__)); 1851 err = -1; 1852 } 1853 1854 /* Check for broadcast ssid */ 1855 for (k = 0; k < nssid; k++) { 1856 if (!ssids_local[k].SSID_len) { 1857 DHD_ERROR(("%d: Broadcast SSID is ilegal for PNO setting\n", k)); 1858 return err; 1859 } 1860 } 1861 /* #define PNO_DUMP 1 */ 1862 #ifdef PNO_DUMP 1863 { 1864 int j; 1865 for (j = 0; j < nssid; j++) { 1866 DHD_ERROR(("%d: scan for %s size =%d\n", j, 1867 ssids_local[j].SSID, ssids_local[j].SSID_len)); 1868 } 1869 } 1870 #endif /* PNO_DUMP */ 1871 1872 /* clean up everything */ 1873 if ((err = dhd_pno_clean(dhd)) < 0) { 1874 DHD_ERROR(("%s failed error=%d\n", __FUNCTION__, err)); 1875 return err; 1876 } 1877 memset(&pfn_param, 0, sizeof(pfn_param)); 1878 memset(&pfn_element, 0, sizeof(pfn_element)); 1879 1880 /* set pfn parameters */ 1881 pfn_param.version = htod32(PFN_VERSION); 1882 pfn_param.flags = htod16((PFN_LIST_ORDER << SORT_CRITERIA_BIT)); 1883 1884 /* set up pno scan fr */ 1885 if (scan_fr != 0) 1886 pfn_param.scan_freq = htod32(scan_fr); 1887 1888 bcm_mkiovar("pfn_set", (char *)&pfn_param, sizeof(pfn_param), iovbuf, sizeof(iovbuf)); 1889 dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); 1890 1891 /* set all pfn ssid */ 1892 for (i = 0; i < nssid; i++) { 1893 1894 pfn_element.bss_type = htod32(DOT11_BSSTYPE_INFRASTRUCTURE); 1895 pfn_element.auth = (DOT11_OPEN_SYSTEM); 1896 pfn_element.wpa_auth = htod32(WPA_AUTH_PFN_ANY); 1897 pfn_element.wsec = htod32(0); 1898 pfn_element.infra = htod32(1); 1899 1900 memcpy((char *)pfn_element.ssid.SSID, ssids_local[i].SSID, ssids_local[i].SSID_len); 1901 pfn_element.ssid.SSID_len = ssids_local[i].SSID_len; 1902 1903 if ((err = 1904 bcm_mkiovar("pfn_add", (char *)&pfn_element, 1905 sizeof(pfn_element), iovbuf, sizeof(iovbuf))) > 0) { 1906 if ((err = 1907 dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf))) < 0) { 1908 DHD_ERROR(("%s failed for i=%d error=%d\n", 1909 __FUNCTION__, i, err)); 1910 return err; 1911 } 1912 } 1913 else DHD_ERROR(("%s failed err=%d\n", __FUNCTION__, err)); 1914 } 1915 1916 /* Enable PNO */ 1917 /* dhd_pno_enable(dhd, 1); */ 1918 return err; 1919 } 1920 1921 int dhd_pno_get_status(dhd_pub_t *dhd) 1922 { 1923 int ret = -1; 1924 1925 if (!dhd) 1926 return ret; 1927 else 1928 return (dhd->pno_enable); 1929 } 1930 1931 #endif /* PNO_SUPPORT */ 1932 1933 #if defined(CSCAN) 1934 1935 /* Androd ComboSCAN support */ 1936 /* 1937 * data parsing from ComboScan tlv list 1938 */ 1939 int 1940 wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size, const char token, 1941 int input_size, int *bytes_left) 1942 { 1943 char* str = *list_str; 1944 uint16 short_temp; 1945 uint32 int_temp; 1946 1947 if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) { 1948 DHD_ERROR(("%s error paramters\n", __FUNCTION__)); 1949 return -1; 1950 } 1951 1952 /* Clean all dest bytes */ 1953 memset(dst, 0, dst_size); 1954 while (*bytes_left > 0) { 1955 1956 if (str[0] != token) { 1957 DHD_TRACE(("%s NOT Type=%d get=%d left_parse=%d \n", 1958 __FUNCTION__, token, str[0], *bytes_left)); 1959 return -1; 1960 } 1961 1962 *bytes_left -= 1; 1963 str += 1; 1964 1965 if (input_size == 1) { 1966 memcpy(dst, str, input_size); 1967 } 1968 else if (input_size == 2) { 1969 memcpy(dst, (char *)htod16(memcpy(&short_temp, str, input_size)), 1970 input_size); 1971 } 1972 else if (input_size == 4) { 1973 memcpy(dst, (char *)htod32(memcpy(&int_temp, str, input_size)), 1974 input_size); 1975 } 1976 1977 *bytes_left -= input_size; 1978 str += input_size; 1979 *list_str = str; 1980 return 1; 1981 } 1982 return 1; 1983 } 1984 1985 /* 1986 * channel list parsing from cscan tlv list 1987 */ 1988 int 1989 wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list, 1990 int channel_num, int *bytes_left) 1991 { 1992 char* str = *list_str; 1993 int idx = 0; 1994 1995 if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) { 1996 DHD_ERROR(("%s error paramters\n", __FUNCTION__)); 1997 return -1; 1998 } 1999 2000 while (*bytes_left > 0) { 2001 2002 if (str[0] != CSCAN_TLV_TYPE_CHANNEL_IE) { 2003 *list_str = str; 2004 DHD_TRACE(("End channel=%d left_parse=%d %d\n", idx, *bytes_left, str[0])); 2005 return idx; 2006 } 2007 /* Get proper CSCAN_TLV_TYPE_CHANNEL_IE */ 2008 *bytes_left -= 1; 2009 str += 1; 2010 2011 if (str[0] == 0) { 2012 /* All channels */ 2013 channel_list[idx] = 0x0; 2014 } 2015 else { 2016 channel_list[idx] = (uint16)str[0]; 2017 DHD_TRACE(("%s channel=%d \n", __FUNCTION__, channel_list[idx])); 2018 } 2019 *bytes_left -= 1; 2020 str += 1; 2021 2022 if (idx++ > 255) { 2023 DHD_ERROR(("%s Too many channels \n", __FUNCTION__)); 2024 return -1; 2025 } 2026 } 2027 2028 *list_str = str; 2029 return idx; 2030 } 2031 2032 /* 2033 * SSIDs list parsing from cscan tlv list 2034 */ 2035 int 2036 wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid, int max, int *bytes_left) 2037 { 2038 char* str = *list_str; 2039 int idx = 0; 2040 2041 if ((list_str == NULL) || (*list_str == NULL) || (*bytes_left < 0)) { 2042 DHD_ERROR(("%s error paramters\n", __FUNCTION__)); 2043 return -1; 2044 } 2045 2046 while (*bytes_left > 0) { 2047 2048 if (str[0] != CSCAN_TLV_TYPE_SSID_IE) { 2049 *list_str = str; 2050 DHD_TRACE(("nssid=%d left_parse=%d %d\n", idx, *bytes_left, str[0])); 2051 return idx; 2052 } 2053 2054 /* Get proper CSCAN_TLV_TYPE_SSID_IE */ 2055 *bytes_left -= 1; 2056 str += 1; 2057 2058 if (str[0] == 0) { 2059 /* Broadcast SSID */ 2060 ssid[idx].SSID_len = 0; 2061 memset((char*)ssid[idx].SSID, 0x0, DOT11_MAX_SSID_LEN); 2062 *bytes_left -= 1; 2063 str += 1; 2064 2065 DHD_TRACE(("BROADCAST SCAN left=%d\n", *bytes_left)); 2066 } 2067 else if (str[0] <= DOT11_MAX_SSID_LEN) { 2068 /* Get proper SSID size */ 2069 ssid[idx].SSID_len = str[0]; 2070 *bytes_left -= 1; 2071 str += 1; 2072 2073 /* Get SSID */ 2074 if (ssid[idx].SSID_len > *bytes_left) { 2075 DHD_ERROR(("%s out of memory range len=%d but left=%d\n", 2076 __FUNCTION__, ssid[idx].SSID_len, *bytes_left)); 2077 return -1; 2078 } 2079 2080 memcpy((char*)ssid[idx].SSID, str, ssid[idx].SSID_len); 2081 2082 *bytes_left -= ssid[idx].SSID_len; 2083 str += ssid[idx].SSID_len; 2084 2085 DHD_TRACE(("%s :size=%d left=%d\n", 2086 (char*)ssid[idx].SSID, ssid[idx].SSID_len, *bytes_left)); 2087 } 2088 else { 2089 DHD_ERROR(("### SSID size more that %d\n", str[0])); 2090 return -1; 2091 } 2092 2093 if (idx++ > max) { 2094 DHD_ERROR(("%s number of SSIDs more that %d\n", __FUNCTION__, idx)); 2095 return -1; 2096 } 2097 } 2098 2099 *list_str = str; 2100 return idx; 2101 } 2102 2103 /* Parse a comma-separated list from list_str into ssid array, starting 2104 * at index idx. Max specifies size of the ssid array. Parses ssids 2105 * and returns updated idx; if idx >= max not all fit, the excess have 2106 * not been copied. Returns -1 on empty string, or on ssid too long. 2107 */ 2108 int 2109 wl_iw_parse_ssid_list(char** list_str, wlc_ssid_t* ssid, int idx, int max) 2110 { 2111 char* str, *ptr; 2112 2113 if ((list_str == NULL) || (*list_str == NULL)) 2114 return -1; 2115 2116 for (str = *list_str; str != NULL; str = ptr) { 2117 2118 /* check for next TAG */ 2119 if (!strncmp(str, GET_CHANNEL, strlen(GET_CHANNEL))) { 2120 *list_str = str + strlen(GET_CHANNEL); 2121 return idx; 2122 } 2123 2124 if ((ptr = strchr(str, ',')) != NULL) { 2125 *ptr++ = '\0'; 2126 } 2127 2128 if (strlen(str) > DOT11_MAX_SSID_LEN) { 2129 DHD_ERROR(("ssid <%s> exceeds %d\n", str, DOT11_MAX_SSID_LEN)); 2130 return -1; 2131 } 2132 2133 if (strlen(str) == 0) 2134 ssid[idx].SSID_len = 0; 2135 2136 if (idx < max) { 2137 strcpy((char*)ssid[idx].SSID, str); 2138 ssid[idx].SSID_len = strlen(str); 2139 } 2140 idx++; 2141 } 2142 return idx; 2143 } 2144 2145 /* 2146 * Parse channel list from iwpriv CSCAN 2147 */ 2148 int 2149 wl_iw_parse_channel_list(char** list_str, uint16* channel_list, int channel_num) 2150 { 2151 int num; 2152 int val; 2153 char* str; 2154 char* endptr = NULL; 2155 2156 if ((list_str == NULL)||(*list_str == NULL)) 2157 return -1; 2158 2159 str = *list_str; 2160 num = 0; 2161 while (strncmp(str, GET_NPROBE, strlen(GET_NPROBE))) { 2162 val = (int)strtoul(str, &endptr, 0); 2163 if (endptr == str) { 2164 printf("could not parse channel number starting at" 2165 " substring \"%s\" in list:\n%s\n", 2166 str, *list_str); 2167 return -1; 2168 } 2169 str = endptr + strspn(endptr, " ,"); 2170 2171 if (num == channel_num) { 2172 DHD_ERROR(("too many channels (more than %d) in channel list:\n%s\n", 2173 channel_num, *list_str)); 2174 return -1; 2175 } 2176 2177 channel_list[num++] = (uint16)val; 2178 } 2179 *list_str = str; 2180 return num; 2181 } 2182 2183 #endif 2184