/drivers/net/wireless/bcmdhd_34/dhd_common.c
C | 2342 lines | 1807 code | 359 blank | 176 comment | 360 complexity | 5eb735704fcc817faf900dc1aab7816e MD5 | raw file
Possible License(s): LGPL-2.0, AGPL-1.0, GPL-2.0
Large files files are truncated, but you can click here to view the full file
1/* 2 * Broadcom Dongle Host Driver (DHD), common DHD core. 3 * 4 * Copyright (C) 1999-2012, 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 332273 2012-05-09 20:18:24Z $ 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 <wlioctl.h> 35#include <dhd.h> 36 37#include <proto/bcmevent.h> 38 39#include <dhd_bus.h> 40#include <dhd_proto.h> 41#include <dhd_dbg.h> 42#include <msgtrace.h> 43 44#ifdef WL_CFG80211 45#include <wl_cfg80211.h> 46#endif 47#ifdef WLBTAMP 48#include <proto/bt_amp_hci.h> 49#include <dhd_bta.h> 50#endif 51#ifdef SET_RANDOM_MAC_SOFTAP 52#include <linux/random.h> 53#include <linux/jiffies.h> 54#endif 55 56#define htod32(i) i 57#define htod16(i) i 58#define dtoh32(i) i 59#define dtoh16(i) i 60#define htodchanspec(i) i 61#define dtohchanspec(i) i 62 63#ifdef PROP_TXSTATUS 64#include <wlfc_proto.h> 65#include <dhd_wlfc.h> 66#endif 67 68 69#ifdef WLMEDIA_HTSF 70extern void htsf_update(struct dhd_info *dhd, void *data); 71#endif 72int dhd_msg_level = DHD_ERROR_VAL; 73 74 75#include <wl_iw.h> 76 77char fw_path[MOD_PARAM_PATHLEN]; 78char nv_path[MOD_PARAM_PATHLEN]; 79 80#ifdef SOFTAP 81char fw_path2[MOD_PARAM_PATHLEN]; 82extern bool softap_enabled; 83#endif 84 85/* Last connection success/failure status */ 86uint32 dhd_conn_event; 87uint32 dhd_conn_status; 88uint32 dhd_conn_reason; 89 90extern int dhd_iscan_request(void * dhdp, uint16 action); 91extern void dhd_ind_scan_confirm(void *h, bool status); 92extern int dhd_iscan_in_progress(void *h); 93void dhd_iscan_lock(void); 94void dhd_iscan_unlock(void); 95extern int dhd_change_mtu(dhd_pub_t *dhd, int new_mtu, int ifidx); 96bool ap_cfg_running = FALSE; 97bool ap_fw_loaded = FALSE; 98 99 100#ifdef DHD_DEBUG 101const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR "\nCompiled on " 102 __DATE__ " at " __TIME__; 103#else 104const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR; 105#endif 106 107void dhd_set_timer(void *bus, uint wdtick); 108 109/* IOVar table */ 110enum { 111 IOV_VERSION = 1, 112 IOV_MSGLEVEL, 113 IOV_BCMERRORSTR, 114 IOV_BCMERROR, 115 IOV_WDTICK, 116 IOV_DUMP, 117 IOV_CLEARCOUNTS, 118 IOV_LOGDUMP, 119 IOV_LOGCAL, 120 IOV_LOGSTAMP, 121 IOV_GPIOOB, 122 IOV_IOCTLTIMEOUT, 123#ifdef WLBTAMP 124 IOV_HCI_CMD, /* HCI command */ 125 IOV_HCI_ACL_DATA, /* HCI data packet */ 126#endif 127#if defined(DHD_DEBUG) 128 IOV_CONS, 129 IOV_DCONSOLE_POLL, 130#endif /* defined(DHD_DEBUG) */ 131#ifdef PROP_TXSTATUS 132 IOV_PROPTXSTATUS_ENABLE, 133 IOV_PROPTXSTATUS_MODE, 134#endif 135 IOV_BUS_TYPE, 136#ifdef WLMEDIA_HTSF 137 IOV_WLPKTDLYSTAT_SZ, 138#endif 139 IOV_CHANGEMTU, 140 IOV_HOSTREORDER_FLOWS, 141 IOV_LAST 142}; 143 144const bcm_iovar_t dhd_iovars[] = { 145 {"version", IOV_VERSION, 0, IOVT_BUFFER, sizeof(dhd_version) }, 146#ifdef DHD_DEBUG 147 {"msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 }, 148#endif /* DHD_DEBUG */ 149 {"bcmerrorstr", IOV_BCMERRORSTR, 0, IOVT_BUFFER, BCME_STRLEN }, 150 {"bcmerror", IOV_BCMERROR, 0, IOVT_INT8, 0 }, 151 {"wdtick", IOV_WDTICK, 0, IOVT_UINT32, 0 }, 152 {"dump", IOV_DUMP, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN }, 153#ifdef DHD_DEBUG 154 {"cons", IOV_CONS, 0, IOVT_BUFFER, 0 }, 155 {"dconpoll", IOV_DCONSOLE_POLL, 0, IOVT_UINT32, 0 }, 156#endif 157 {"clearcounts", IOV_CLEARCOUNTS, 0, IOVT_VOID, 0 }, 158 {"gpioob", IOV_GPIOOB, 0, IOVT_UINT32, 0 }, 159 {"ioctl_timeout", IOV_IOCTLTIMEOUT, 0, IOVT_UINT32, 0 }, 160#ifdef WLBTAMP 161 {"HCI_cmd", IOV_HCI_CMD, 0, IOVT_BUFFER, 0}, 162 {"HCI_ACL_data", IOV_HCI_ACL_DATA, 0, IOVT_BUFFER, 0}, 163#endif 164#ifdef PROP_TXSTATUS 165 {"proptx", IOV_PROPTXSTATUS_ENABLE, 0, IOVT_UINT32, 0 }, 166 /* 167 set the proptxtstatus operation mode: 168 0 - Do not do any proptxtstatus flow control 169 1 - Use implied credit from a packet status 170 2 - Use explicit credit 171 */ 172 {"ptxmode", IOV_PROPTXSTATUS_MODE, 0, IOVT_UINT32, 0 }, 173#endif 174 {"bustype", IOV_BUS_TYPE, 0, IOVT_UINT32, 0}, 175#ifdef WLMEDIA_HTSF 176 {"pktdlystatsz", IOV_WLPKTDLYSTAT_SZ, 0, IOVT_UINT8, 0 }, 177#endif 178 {"changemtu", IOV_CHANGEMTU, 0, IOVT_UINT32, 0 }, 179 {"host_reorder_flows", IOV_HOSTREORDER_FLOWS, 0, IOVT_BUFFER, 180 (WLHOST_REORDERDATA_MAXFLOWS + 1) }, 181 {NULL, 0, 0, 0, 0 } 182}; 183 184void 185dhd_common_init(uint16 devid, osl_t *osh) 186{ 187#ifdef CONFIG_BCMDHD_FW_PATH 188 bcm_strncpy_s(fw_path, sizeof(fw_path), CONFIG_BCMDHD_FW_PATH, MOD_PARAM_PATHLEN-1); 189#elif defined(CONFIG_BCMDHD_FW_DIR) /* CONFIG_BCMDHD_FW_PATH */ 190 sprintf(fw_path, "%s/bcm%x/fw_bcmdhd.bin", CONFIG_BCMDHD_FW_DIR, devid); 191#else /* CONFIG_BCMDHD_FW_PATH */ 192 fw_path[0] = '\0'; 193#endif /* CONFIG_BCMDHD_FW_PATH */ 194#ifdef CONFIG_BCMDHD_NVRAM_PATH 195 bcm_strncpy_s(nv_path, sizeof(nv_path), CONFIG_BCMDHD_NVRAM_PATH, MOD_PARAM_PATHLEN-1); 196#else /* CONFIG_BCMDHD_NVRAM_PATH */ 197 nv_path[0] = '\0'; 198#endif /* CONFIG_BCMDHD_NVRAM_PATH */ 199#ifdef SOFTAP 200 fw_path2[0] = '\0'; 201#endif 202 DHD_ERROR(("bcmdhd: fw_path: %s nvram_path: %s\n", fw_path, nv_path)); 203} 204 205static int 206dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen) 207{ 208 char eabuf[ETHER_ADDR_STR_LEN]; 209 210 struct bcmstrbuf b; 211 struct bcmstrbuf *strbuf = &b; 212 213 bcm_binit(strbuf, buf, buflen); 214 215 /* Base DHD info */ 216 bcm_bprintf(strbuf, "%s\n", dhd_version); 217 bcm_bprintf(strbuf, "\n"); 218 bcm_bprintf(strbuf, "pub.up %d pub.txoff %d pub.busstate %d\n", 219 dhdp->up, dhdp->txoff, dhdp->busstate); 220 bcm_bprintf(strbuf, "pub.hdrlen %d pub.maxctl %d pub.rxsz %d\n", 221 dhdp->hdrlen, dhdp->maxctl, dhdp->rxsz); 222 bcm_bprintf(strbuf, "pub.iswl %d pub.drv_version %ld pub.mac %s\n", 223 dhdp->iswl, dhdp->drv_version, bcm_ether_ntoa(&dhdp->mac, eabuf)); 224 bcm_bprintf(strbuf, "pub.bcmerror %d tickcnt %d\n", dhdp->bcmerror, dhdp->tickcnt); 225 226 bcm_bprintf(strbuf, "dongle stats:\n"); 227 bcm_bprintf(strbuf, "tx_packets %ld tx_bytes %ld tx_errors %ld tx_dropped %ld\n", 228 dhdp->dstats.tx_packets, dhdp->dstats.tx_bytes, 229 dhdp->dstats.tx_errors, dhdp->dstats.tx_dropped); 230 bcm_bprintf(strbuf, "rx_packets %ld rx_bytes %ld rx_errors %ld rx_dropped %ld\n", 231 dhdp->dstats.rx_packets, dhdp->dstats.rx_bytes, 232 dhdp->dstats.rx_errors, dhdp->dstats.rx_dropped); 233 bcm_bprintf(strbuf, "multicast %ld\n", dhdp->dstats.multicast); 234 235 bcm_bprintf(strbuf, "bus stats:\n"); 236 bcm_bprintf(strbuf, "tx_packets %ld tx_multicast %ld tx_errors %ld\n", 237 dhdp->tx_packets, dhdp->tx_multicast, dhdp->tx_errors); 238 bcm_bprintf(strbuf, "tx_ctlpkts %ld tx_ctlerrs %ld\n", 239 dhdp->tx_ctlpkts, dhdp->tx_ctlerrs); 240 bcm_bprintf(strbuf, "rx_packets %ld rx_multicast %ld rx_errors %ld \n", 241 dhdp->rx_packets, dhdp->rx_multicast, dhdp->rx_errors); 242 bcm_bprintf(strbuf, "rx_ctlpkts %ld rx_ctlerrs %ld rx_dropped %ld\n", 243 dhdp->rx_ctlpkts, dhdp->rx_ctlerrs, dhdp->rx_dropped); 244 bcm_bprintf(strbuf, "rx_readahead_cnt %ld tx_realloc %ld\n", 245 dhdp->rx_readahead_cnt, dhdp->tx_realloc); 246 bcm_bprintf(strbuf, "\n"); 247 248 /* Add any prot info */ 249 dhd_prot_dump(dhdp, strbuf); 250 bcm_bprintf(strbuf, "\n"); 251 252 /* Add any bus info */ 253 dhd_bus_dump(dhdp, strbuf); 254 255 return (!strbuf->size ? BCME_BUFTOOSHORT : 0); 256} 257 258int 259dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, int ifindex) 260{ 261 wl_ioctl_t ioc; 262 263 ioc.cmd = cmd; 264 ioc.buf = arg; 265 ioc.len = len; 266 ioc.set = set; 267 268 return dhd_wl_ioctl(dhd_pub, ifindex, &ioc, arg, len); 269} 270 271 272int 273dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int len) 274{ 275 int ret; 276 277 dhd_os_proto_block(dhd_pub); 278 279 ret = dhd_prot_ioctl(dhd_pub, ifindex, ioc, buf, len); 280 if (!ret) 281 dhd_os_check_hang(dhd_pub, ifindex, ret); 282 283 dhd_os_proto_unblock(dhd_pub); 284 return ret; 285} 286 287static int 288dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const char *name, 289 void *params, int plen, void *arg, int len, int val_size) 290{ 291 int bcmerror = 0; 292 int32 int_val = 0; 293 294 DHD_TRACE(("%s: Enter\n", __FUNCTION__)); 295 DHD_TRACE(("%s: actionid = %d; name %s\n", __FUNCTION__, actionid, name)); 296 297 if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0) 298 goto exit; 299 300 if (plen >= (int)sizeof(int_val)) 301 bcopy(params, &int_val, sizeof(int_val)); 302 303 switch (actionid) { 304 case IOV_GVAL(IOV_VERSION): 305 /* Need to have checked buffer length */ 306 bcm_strncpy_s((char*)arg, len, dhd_version, len); 307 break; 308 309 case IOV_GVAL(IOV_MSGLEVEL): 310 int_val = (int32)dhd_msg_level; 311 bcopy(&int_val, arg, val_size); 312 break; 313 314 case IOV_SVAL(IOV_MSGLEVEL): 315 dhd_msg_level = int_val; 316#ifdef WL_CFG80211 317 /* Enable DHD and WL logs in oneshot */ 318 if (dhd_msg_level & DHD_WL_VAL) 319 wl_cfg80211_enable_trace(dhd_msg_level); 320#endif 321 break; 322 case IOV_GVAL(IOV_BCMERRORSTR): 323 bcm_strncpy_s((char *)arg, len, bcmerrorstr(dhd_pub->bcmerror), BCME_STRLEN); 324 ((char *)arg)[BCME_STRLEN - 1] = 0x00; 325 break; 326 327 case IOV_GVAL(IOV_BCMERROR): 328 int_val = (int32)dhd_pub->bcmerror; 329 bcopy(&int_val, arg, val_size); 330 break; 331 332 case IOV_GVAL(IOV_WDTICK): 333 int_val = (int32)dhd_watchdog_ms; 334 bcopy(&int_val, arg, val_size); 335 break; 336 337 case IOV_SVAL(IOV_WDTICK): 338 if (!dhd_pub->up) { 339 bcmerror = BCME_NOTUP; 340 break; 341 } 342 dhd_os_wd_timer(dhd_pub, (uint)int_val); 343 break; 344 345 case IOV_GVAL(IOV_DUMP): 346 bcmerror = dhd_dump(dhd_pub, arg, len); 347 break; 348 349#ifdef DHD_DEBUG 350 case IOV_GVAL(IOV_DCONSOLE_POLL): 351 int_val = (int32)dhd_console_ms; 352 bcopy(&int_val, arg, val_size); 353 break; 354 355 case IOV_SVAL(IOV_DCONSOLE_POLL): 356 dhd_console_ms = (uint)int_val; 357 break; 358 359 case IOV_SVAL(IOV_CONS): 360 if (len > 0) 361 bcmerror = dhd_bus_console_in(dhd_pub, arg, len - 1); 362 break; 363#endif /* DHD_DEBUG */ 364 365 case IOV_SVAL(IOV_CLEARCOUNTS): 366 dhd_pub->tx_packets = dhd_pub->rx_packets = 0; 367 dhd_pub->tx_errors = dhd_pub->rx_errors = 0; 368 dhd_pub->tx_ctlpkts = dhd_pub->rx_ctlpkts = 0; 369 dhd_pub->tx_ctlerrs = dhd_pub->rx_ctlerrs = 0; 370 dhd_pub->rx_dropped = 0; 371 dhd_pub->rx_readahead_cnt = 0; 372 dhd_pub->tx_realloc = 0; 373 dhd_pub->wd_dpc_sched = 0; 374 memset(&dhd_pub->dstats, 0, sizeof(dhd_pub->dstats)); 375 dhd_bus_clearcounts(dhd_pub); 376#ifdef PROP_TXSTATUS 377 /* clear proptxstatus related counters */ 378 if (dhd_pub->wlfc_state) { 379 athost_wl_status_info_t *wlfc = 380 (athost_wl_status_info_t*)dhd_pub->wlfc_state; 381 wlfc_hanger_t* hanger; 382 383 memset(&wlfc->stats, 0, sizeof(athost_wl_stat_counters_t)); 384 385 hanger = (wlfc_hanger_t*)wlfc->hanger; 386 hanger->pushed = 0; 387 hanger->popped = 0; 388 hanger->failed_slotfind = 0; 389 hanger->failed_to_pop = 0; 390 hanger->failed_to_push = 0; 391 } 392#endif /* PROP_TXSTATUS */ 393 break; 394 395 396 case IOV_GVAL(IOV_IOCTLTIMEOUT): { 397 int_val = (int32)dhd_os_get_ioctl_resp_timeout(); 398 bcopy(&int_val, arg, sizeof(int_val)); 399 break; 400 } 401 402 case IOV_SVAL(IOV_IOCTLTIMEOUT): { 403 if (int_val <= 0) 404 bcmerror = BCME_BADARG; 405 else 406 dhd_os_set_ioctl_resp_timeout((unsigned int)int_val); 407 break; 408 } 409 410#ifdef WLBTAMP 411 case IOV_SVAL(IOV_HCI_CMD): { 412 amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)arg; 413 414 /* sanity check: command preamble present */ 415 if (len < HCI_CMD_PREAMBLE_SIZE) 416 return BCME_BUFTOOSHORT; 417 418 /* sanity check: command parameters are present */ 419 if (len < (int)(HCI_CMD_PREAMBLE_SIZE + cmd->plen)) 420 return BCME_BUFTOOSHORT; 421 422 dhd_bta_docmd(dhd_pub, cmd, len); 423 break; 424 } 425 426 case IOV_SVAL(IOV_HCI_ACL_DATA): { 427 amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)arg; 428 429 /* sanity check: HCI header present */ 430 if (len < HCI_ACL_DATA_PREAMBLE_SIZE) 431 return BCME_BUFTOOSHORT; 432 433 /* sanity check: ACL data is present */ 434 if (len < (int)(HCI_ACL_DATA_PREAMBLE_SIZE + ACL_data->dlen)) 435 return BCME_BUFTOOSHORT; 436 437 dhd_bta_tx_hcidata(dhd_pub, ACL_data, len); 438 break; 439 } 440#endif /* WLBTAMP */ 441 442#ifdef PROP_TXSTATUS 443 case IOV_GVAL(IOV_PROPTXSTATUS_ENABLE): 444 int_val = dhd_pub->wlfc_enabled? 1 : 0; 445 bcopy(&int_val, arg, val_size); 446 break; 447 448 case IOV_SVAL(IOV_PROPTXSTATUS_ENABLE): 449 dhd_pub->wlfc_enabled = int_val? 1 : 0; 450 break; 451 452 case IOV_GVAL(IOV_PROPTXSTATUS_MODE): { 453 athost_wl_status_info_t *wlfc = 454 (athost_wl_status_info_t*)dhd_pub->wlfc_state; 455 int_val = dhd_pub->wlfc_state ? (int32)wlfc->proptxstatus_mode : 0; 456 bcopy(&int_val, arg, val_size); 457 break; 458 } 459 460 case IOV_SVAL(IOV_PROPTXSTATUS_MODE): 461 if (dhd_pub->wlfc_state) { 462 athost_wl_status_info_t *wlfc = 463 (athost_wl_status_info_t*)dhd_pub->wlfc_state; 464 wlfc->proptxstatus_mode = int_val & 0xff; 465 } 466 break; 467#endif /* PROP_TXSTATUS */ 468 469 case IOV_GVAL(IOV_BUS_TYPE): 470 /* The dhd application queries the driver to check if its usb or sdio. */ 471#ifdef BCMDHDUSB 472 int_val = BUS_TYPE_USB; 473#endif 474 int_val = BUS_TYPE_SDIO; 475 bcopy(&int_val, arg, val_size); 476 break; 477 478 479#ifdef WLMEDIA_HTSF 480 case IOV_GVAL(IOV_WLPKTDLYSTAT_SZ): 481 int_val = dhd_pub->htsfdlystat_sz; 482 bcopy(&int_val, arg, val_size); 483 break; 484 485 case IOV_SVAL(IOV_WLPKTDLYSTAT_SZ): 486 dhd_pub->htsfdlystat_sz = int_val & 0xff; 487 printf("Setting tsfdlystat_sz:%d\n", dhd_pub->htsfdlystat_sz); 488 break; 489#endif 490 case IOV_SVAL(IOV_CHANGEMTU): 491 int_val &= 0xffff; 492 bcmerror = dhd_change_mtu(dhd_pub, int_val, 0); 493 break; 494 495 case IOV_GVAL(IOV_HOSTREORDER_FLOWS): 496 { 497 uint i = 0; 498 uint8 *ptr = (uint8 *)arg; 499 uint8 count = 0; 500 501 ptr++; 502 for (i = 0; i < WLHOST_REORDERDATA_MAXFLOWS; i++) { 503 if (dhd_pub->reorder_bufs[i] != NULL) { 504 *ptr = dhd_pub->reorder_bufs[i]->flow_id; 505 ptr++; 506 count++; 507 } 508 } 509 ptr = (uint8 *)arg; 510 *ptr = count; 511 break; 512 } 513 514 default: 515 bcmerror = BCME_UNSUPPORTED; 516 break; 517 } 518 519exit: 520 DHD_TRACE(("%s: actionid %d, bcmerror %d\n", __FUNCTION__, actionid, bcmerror)); 521 return bcmerror; 522} 523 524/* Store the status of a connection attempt for later retrieval by an iovar */ 525void 526dhd_store_conn_status(uint32 event, uint32 status, uint32 reason) 527{ 528 /* Do not overwrite a WLC_E_PRUNE with a WLC_E_SET_SSID 529 * because an encryption/rsn mismatch results in both events, and 530 * the important information is in the WLC_E_PRUNE. 531 */ 532 if (!(event == WLC_E_SET_SSID && status == WLC_E_STATUS_FAIL && 533 dhd_conn_event == WLC_E_PRUNE)) { 534 dhd_conn_event = event; 535 dhd_conn_status = status; 536 dhd_conn_reason = reason; 537 } 538} 539 540bool 541dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec) 542{ 543 void *p; 544 int eprec = -1; /* precedence to evict from */ 545 bool discard_oldest; 546 547 /* Fast case, precedence queue is not full and we are also not 548 * exceeding total queue length 549 */ 550 if (!pktq_pfull(q, prec) && !pktq_full(q)) { 551 pktq_penq(q, prec, pkt); 552 return TRUE; 553 } 554 555 /* Determine precedence from which to evict packet, if any */ 556 if (pktq_pfull(q, prec)) 557 eprec = prec; 558 else if (pktq_full(q)) { 559 p = pktq_peek_tail(q, &eprec); 560 ASSERT(p); 561 if (eprec > prec || eprec < 0) 562 return FALSE; 563 } 564 565 /* Evict if needed */ 566 if (eprec >= 0) { 567 /* Detect queueing to unconfigured precedence */ 568 ASSERT(!pktq_pempty(q, eprec)); 569 discard_oldest = AC_BITMAP_TST(dhdp->wme_dp, eprec); 570 if (eprec == prec && !discard_oldest) 571 return FALSE; /* refuse newer (incoming) packet */ 572 /* Evict packet according to discard policy */ 573 p = discard_oldest ? pktq_pdeq(q, eprec) : pktq_pdeq_tail(q, eprec); 574 ASSERT(p); 575 576 PKTFREE(dhdp->osh, p, TRUE); 577 } 578 579 /* Enqueue */ 580 p = pktq_penq(q, prec, pkt); 581 ASSERT(p); 582 583 return TRUE; 584} 585 586static int 587dhd_iovar_op(dhd_pub_t *dhd_pub, const char *name, 588 void *params, int plen, void *arg, int len, bool set) 589{ 590 int bcmerror = 0; 591 int val_size; 592 const bcm_iovar_t *vi = NULL; 593 uint32 actionid; 594 595 DHD_TRACE(("%s: Enter\n", __FUNCTION__)); 596 597 ASSERT(name); 598 ASSERT(len >= 0); 599 600 /* Get MUST have return space */ 601 ASSERT(set || (arg && len)); 602 603 /* Set does NOT take qualifiers */ 604 ASSERT(!set || (!params && !plen)); 605 606 if ((vi = bcm_iovar_lookup(dhd_iovars, name)) == NULL) { 607 bcmerror = BCME_UNSUPPORTED; 608 goto exit; 609 } 610 611 DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__, 612 name, (set ? "set" : "get"), len, plen)); 613 614 /* set up 'params' pointer in case this is a set command so that 615 * the convenience int and bool code can be common to set and get 616 */ 617 if (params == NULL) { 618 params = arg; 619 plen = len; 620 } 621 622 if (vi->type == IOVT_VOID) 623 val_size = 0; 624 else if (vi->type == IOVT_BUFFER) 625 val_size = len; 626 else 627 /* all other types are integer sized */ 628 val_size = sizeof(int); 629 630 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); 631 632 bcmerror = dhd_doiovar(dhd_pub, vi, actionid, name, params, plen, arg, len, val_size); 633 634exit: 635 return bcmerror; 636} 637 638int 639dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen) 640{ 641 int bcmerror = 0; 642 643 DHD_TRACE(("%s: Enter\n", __FUNCTION__)); 644 645 if (!buf) { 646 return BCME_BADARG; 647 } 648 649 switch (ioc->cmd) { 650 case DHD_GET_MAGIC: 651 if (buflen < sizeof(int)) 652 bcmerror = BCME_BUFTOOSHORT; 653 else 654 *(int*)buf = DHD_IOCTL_MAGIC; 655 break; 656 657 case DHD_GET_VERSION: 658 if (buflen < sizeof(int)) 659 bcmerror = -BCME_BUFTOOSHORT; 660 else 661 *(int*)buf = DHD_IOCTL_VERSION; 662 break; 663 664 case DHD_GET_VAR: 665 case DHD_SET_VAR: { 666 char *arg; 667 uint arglen; 668 669 /* scan past the name to any arguments */ 670 for (arg = buf, arglen = buflen; *arg && arglen; arg++, arglen--) 671 ; 672 673 if (*arg) { 674 bcmerror = BCME_BUFTOOSHORT; 675 break; 676 } 677 678 /* account for the NUL terminator */ 679 arg++, arglen--; 680 681 /* call with the appropriate arguments */ 682 if (ioc->cmd == DHD_GET_VAR) 683 bcmerror = dhd_iovar_op(dhd_pub, buf, arg, arglen, 684 buf, buflen, IOV_GET); 685 else 686 bcmerror = dhd_iovar_op(dhd_pub, buf, NULL, 0, arg, arglen, IOV_SET); 687 if (bcmerror != BCME_UNSUPPORTED) 688 break; 689 690 /* not in generic table, try protocol module */ 691 if (ioc->cmd == DHD_GET_VAR) 692 bcmerror = dhd_prot_iovar_op(dhd_pub, buf, arg, 693 arglen, buf, buflen, IOV_GET); 694 else 695 bcmerror = dhd_prot_iovar_op(dhd_pub, buf, 696 NULL, 0, arg, arglen, IOV_SET); 697 if (bcmerror != BCME_UNSUPPORTED) 698 break; 699 700 /* if still not found, try bus module */ 701 if (ioc->cmd == DHD_GET_VAR) { 702 bcmerror = dhd_bus_iovar_op(dhd_pub, buf, 703 arg, arglen, buf, buflen, IOV_GET); 704 } else { 705 bcmerror = dhd_bus_iovar_op(dhd_pub, buf, 706 NULL, 0, arg, arglen, IOV_SET); 707 } 708 709 break; 710 } 711 712 default: 713 bcmerror = BCME_UNSUPPORTED; 714 } 715 716 return bcmerror; 717} 718 719#ifdef SHOW_EVENTS 720static void 721wl_show_host_event(wl_event_msg_t *event, void *event_data) 722{ 723 uint i, status, reason; 724 bool group = FALSE, flush_txq = FALSE, link = FALSE; 725 const char *auth_str; 726 const char *event_name; 727 uchar *buf; 728 char err_msg[256], eabuf[ETHER_ADDR_STR_LEN]; 729 uint event_type, flags, auth_type, datalen; 730 731 event_type = ntoh32(event->event_type); 732 flags = ntoh16(event->flags); 733 status = ntoh32(event->status); 734 reason = ntoh32(event->reason); 735 BCM_REFERENCE(reason); 736 auth_type = ntoh32(event->auth_type); 737 datalen = ntoh32(event->datalen); 738 739 /* debug dump of event messages */ 740 sprintf(eabuf, "%02x:%02x:%02x:%02x:%02x:%02x", 741 (uchar)event->addr.octet[0]&0xff, 742 (uchar)event->addr.octet[1]&0xff, 743 (uchar)event->addr.octet[2]&0xff, 744 (uchar)event->addr.octet[3]&0xff, 745 (uchar)event->addr.octet[4]&0xff, 746 (uchar)event->addr.octet[5]&0xff); 747 748 event_name = "UNKNOWN"; 749 for (i = 0; i < (uint)bcmevent_names_size; i++) 750 if (bcmevent_names[i].event == event_type) 751 event_name = bcmevent_names[i].name; 752 753 if (flags & WLC_EVENT_MSG_LINK) 754 link = TRUE; 755 if (flags & WLC_EVENT_MSG_GROUP) 756 group = TRUE; 757 if (flags & WLC_EVENT_MSG_FLUSHTXQ) 758 flush_txq = TRUE; 759 760 switch (event_type) { 761 case WLC_E_START: 762 case WLC_E_DEAUTH: 763 case WLC_E_DISASSOC: 764 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); 765 break; 766 767 case WLC_E_ASSOC_IND: 768 case WLC_E_REASSOC_IND: 769 770 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); 771 break; 772 773 case WLC_E_ASSOC: 774 case WLC_E_REASSOC: 775 if (status == WLC_E_STATUS_SUCCESS) { 776 DHD_EVENT(("MACEVENT: %s, MAC %s, SUCCESS\n", event_name, eabuf)); 777 } else if (status == WLC_E_STATUS_TIMEOUT) { 778 DHD_EVENT(("MACEVENT: %s, MAC %s, TIMEOUT\n", event_name, eabuf)); 779 } else if (status == WLC_E_STATUS_FAIL) { 780 DHD_EVENT(("MACEVENT: %s, MAC %s, FAILURE, reason %d\n", 781 event_name, eabuf, (int)reason)); 782 } else { 783 DHD_EVENT(("MACEVENT: %s, MAC %s, unexpected status %d\n", 784 event_name, eabuf, (int)status)); 785 } 786 break; 787 788 case WLC_E_DEAUTH_IND: 789 case WLC_E_DISASSOC_IND: 790 DHD_EVENT(("MACEVENT: %s, MAC %s, reason %d\n", event_name, eabuf, (int)reason)); 791 break; 792 793 case WLC_E_AUTH: 794 case WLC_E_AUTH_IND: 795 if (auth_type == DOT11_OPEN_SYSTEM) 796 auth_str = "Open System"; 797 else if (auth_type == DOT11_SHARED_KEY) 798 auth_str = "Shared Key"; 799 else { 800 sprintf(err_msg, "AUTH unknown: %d", (int)auth_type); 801 auth_str = err_msg; 802 } 803 if (event_type == WLC_E_AUTH_IND) { 804 DHD_EVENT(("MACEVENT: %s, MAC %s, %s\n", event_name, eabuf, auth_str)); 805 } else if (status == WLC_E_STATUS_SUCCESS) { 806 DHD_EVENT(("MACEVENT: %s, MAC %s, %s, SUCCESS\n", 807 event_name, eabuf, auth_str)); 808 } else if (status == WLC_E_STATUS_TIMEOUT) { 809 DHD_EVENT(("MACEVENT: %s, MAC %s, %s, TIMEOUT\n", 810 event_name, eabuf, auth_str)); 811 } else if (status == WLC_E_STATUS_FAIL) { 812 DHD_EVENT(("MACEVENT: %s, MAC %s, %s, FAILURE, reason %d\n", 813 event_name, eabuf, auth_str, (int)reason)); 814 } 815 BCM_REFERENCE(auth_str); 816 817 break; 818 819 case WLC_E_JOIN: 820 case WLC_E_ROAM: 821 case WLC_E_SET_SSID: 822 if (status == WLC_E_STATUS_SUCCESS) { 823 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); 824 } else if (status == WLC_E_STATUS_FAIL) { 825 DHD_EVENT(("MACEVENT: %s, failed\n", event_name)); 826 } else if (status == WLC_E_STATUS_NO_NETWORKS) { 827 DHD_EVENT(("MACEVENT: %s, no networks found\n", event_name)); 828 } else { 829 DHD_EVENT(("MACEVENT: %s, unexpected status %d\n", 830 event_name, (int)status)); 831 } 832 break; 833 834 case WLC_E_BEACON_RX: 835 if (status == WLC_E_STATUS_SUCCESS) { 836 DHD_EVENT(("MACEVENT: %s, SUCCESS\n", event_name)); 837 } else if (status == WLC_E_STATUS_FAIL) { 838 DHD_EVENT(("MACEVENT: %s, FAIL\n", event_name)); 839 } else { 840 DHD_EVENT(("MACEVENT: %s, status %d\n", event_name, status)); 841 } 842 break; 843 844 case WLC_E_LINK: 845 DHD_EVENT(("MACEVENT: %s %s\n", event_name, link?"UP":"DOWN")); 846 BCM_REFERENCE(link); 847 break; 848 849 case WLC_E_MIC_ERROR: 850 DHD_EVENT(("MACEVENT: %s, MAC %s, Group %d, Flush %d\n", 851 event_name, eabuf, group, flush_txq)); 852 BCM_REFERENCE(group); 853 BCM_REFERENCE(flush_txq); 854 break; 855 856 case WLC_E_ICV_ERROR: 857 case WLC_E_UNICAST_DECODE_ERROR: 858 case WLC_E_MULTICAST_DECODE_ERROR: 859 DHD_EVENT(("MACEVENT: %s, MAC %s\n", 860 event_name, eabuf)); 861 break; 862 863 case WLC_E_TXFAIL: 864 DHD_EVENT(("MACEVENT: %s, RA %s\n", event_name, eabuf)); 865 break; 866 867 case WLC_E_SCAN_COMPLETE: 868 case WLC_E_ASSOC_REQ_IE: 869 case WLC_E_ASSOC_RESP_IE: 870 case WLC_E_PMKID_CACHE: 871 DHD_EVENT(("MACEVENT: %s\n", event_name)); 872 break; 873 874 case WLC_E_PFN_NET_FOUND: 875 case WLC_E_PFN_NET_LOST: 876 case WLC_E_PFN_SCAN_COMPLETE: 877 case WLC_E_PFN_SCAN_NONE: 878 case WLC_E_PFN_SCAN_ALLGONE: 879 DHD_EVENT(("PNOEVENT: %s\n", event_name)); 880 break; 881 882 case WLC_E_PSK_SUP: 883 case WLC_E_PRUNE: 884 DHD_EVENT(("MACEVENT: %s, status %d, reason %d\n", 885 event_name, (int)status, (int)reason)); 886 break; 887 888#ifdef WIFI_ACT_FRAME 889 case WLC_E_ACTION_FRAME: 890 DHD_TRACE(("MACEVENT: %s Bssid %s\n", event_name, eabuf)); 891 break; 892#endif /* WIFI_ACT_FRAME */ 893 894 case WLC_E_TRACE: { 895 static uint32 seqnum_prev = 0; 896 msgtrace_hdr_t hdr; 897 uint32 nblost; 898 char *s, *p; 899 900 buf = (uchar *) event_data; 901 memcpy(&hdr, buf, MSGTRACE_HDRLEN); 902 903 if (hdr.version != MSGTRACE_VERSION) { 904 printf("\nMACEVENT: %s [unsupported version --> " 905 "dhd version:%d dongle version:%d]\n", 906 event_name, MSGTRACE_VERSION, hdr.version); 907 /* Reset datalen to avoid display below */ 908 datalen = 0; 909 break; 910 } 911 912 /* There are 2 bytes available at the end of data */ 913 buf[MSGTRACE_HDRLEN + ntoh16(hdr.len)] = '\0'; 914 915 if (ntoh32(hdr.discarded_bytes) || ntoh32(hdr.discarded_printf)) { 916 printf("\nWLC_E_TRACE: [Discarded traces in dongle -->" 917 "discarded_bytes %d discarded_printf %d]\n", 918 ntoh32(hdr.discarded_bytes), ntoh32(hdr.discarded_printf)); 919 } 920 921 nblost = ntoh32(hdr.seqnum) - seqnum_prev - 1; 922 if (nblost > 0) { 923 printf("\nWLC_E_TRACE: [Event lost --> seqnum %d nblost %d\n", 924 ntoh32(hdr.seqnum), nblost); 925 } 926 seqnum_prev = ntoh32(hdr.seqnum); 927 928 /* Display the trace buffer. Advance from \n to \n to avoid display big 929 * printf (issue with Linux printk ) 930 */ 931 p = (char *)&buf[MSGTRACE_HDRLEN]; 932 while ((s = strstr(p, "\n")) != NULL) { 933 *s = '\0'; 934 printf("%s\n", p); 935 p = s+1; 936 } 937 printf("%s\n", p); 938 939 /* Reset datalen to avoid display below */ 940 datalen = 0; 941 break; 942 } 943 944 945 case WLC_E_RSSI: 946 DHD_EVENT(("MACEVENT: %s %d\n", event_name, ntoh32(*((int *)event_data)))); 947 break; 948 949 default: 950 DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, auth %d\n", 951 event_name, event_type, eabuf, (int)status, (int)reason, 952 (int)auth_type)); 953 break; 954 } 955 956 /* show any appended data */ 957 if (datalen) { 958 buf = (uchar *) event_data; 959 DHD_EVENT((" data (%d) : ", datalen)); 960 for (i = 0; i < datalen; i++) 961 DHD_EVENT((" 0x%02x ", *buf++)); 962 DHD_EVENT(("\n")); 963 } 964} 965#endif /* SHOW_EVENTS */ 966 967int 968wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, 969 wl_event_msg_t *event, void **data_ptr) 970{ 971 /* check whether packet is a BRCM event pkt */ 972 bcm_event_t *pvt_data = (bcm_event_t *)pktdata; 973 uint8 *event_data; 974 uint32 type, status, datalen; 975 uint16 flags; 976 int evlen; 977 978 if (bcmp(BRCM_OUI, &pvt_data->bcm_hdr.oui[0], DOT11_OUI_LEN)) { 979 DHD_ERROR(("%s: mismatched OUI, bailing\n", __FUNCTION__)); 980 return (BCME_ERROR); 981 } 982 983 /* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */ 984 if (ntoh16_ua((void *)&pvt_data->bcm_hdr.usr_subtype) != BCMILCP_BCM_SUBTYPE_EVENT) { 985 DHD_ERROR(("%s: mismatched subtype, bailing\n", __FUNCTION__)); 986 return (BCME_ERROR); 987 } 988 989 *data_ptr = &pvt_data[1]; 990 event_data = *data_ptr; 991 992 /* memcpy since BRCM event pkt may be unaligned. */ 993 memcpy(event, &pvt_data->event, sizeof(wl_event_msg_t)); 994 995 type = ntoh32_ua((void *)&event->event_type); 996 flags = ntoh16_ua((void *)&event->flags); 997 status = ntoh32_ua((void *)&event->status); 998 datalen = ntoh32_ua((void *)&event->datalen); 999 evlen = datalen + sizeof(bcm_event_t); 1000 1001 switch (type) { 1002#ifdef PROP_TXSTATUS 1003 case WLC_E_FIFO_CREDIT_MAP: 1004 dhd_wlfc_event(dhd_pub->info); 1005 dhd_wlfc_FIFOcreditmap_event(dhd_pub->info, event_data); 1006 WLFC_DBGMESG(("WLC_E_FIFO_CREDIT_MAP:(AC0,AC1,AC2,AC3),(BC_MC),(OTHER): " 1007 "(%d,%d,%d,%d),(%d),(%d)\n", event_data[0], event_data[1], 1008 event_data[2], 1009 event_data[3], event_data[4], event_data[5])); 1010 break; 1011#endif 1012 1013 case WLC_E_IF: 1014 { 1015 dhd_if_event_t *ifevent = (dhd_if_event_t *)event_data; 1016#ifdef PROP_TXSTATUS 1017 { 1018 uint8* ea = pvt_data->eth.ether_dhost; 1019 WLFC_DBGMESG(("WLC_E_IF: idx:%d, action:%s, iftype:%s, " 1020 "[%02x:%02x:%02x:%02x:%02x:%02x]\n", 1021 ifevent->ifidx, 1022 ((ifevent->action == WLC_E_IF_ADD) ? "ADD":"DEL"), 1023 ((ifevent->is_AP == 0) ? "STA":"AP "), 1024 ea[0], ea[1], ea[2], ea[3], ea[4], ea[5])); 1025 (void)ea; 1026 if (ifevent->action == WLC_E_IF_CHANGE) 1027 dhd_wlfc_interface_event(dhd_pub->info, 1028 eWLFC_MAC_ENTRY_ACTION_UPDATE, 1029 ifevent->ifidx, ifevent->is_AP, ea); 1030 else 1031 dhd_wlfc_interface_event(dhd_pub->info, 1032 ((ifevent->action == WLC_E_IF_ADD) ? 1033 eWLFC_MAC_ENTRY_ACTION_ADD : eWLFC_MAC_ENTRY_ACTION_DEL), 1034 ifevent->ifidx, ifevent->is_AP, ea); 1035 1036 1037 /* dhd already has created an interface by default, for 0 */ 1038 if (ifevent->ifidx == 0) 1039 break; 1040 } 1041#endif /* PROP_TXSTATUS */ 1042 1043#ifdef WL_CFG80211 1044 if (wl_cfg80211_is_progress_ifchange()) { 1045 DHD_ERROR(("%s: ifidx %d for %s action %d\n", 1046 __FUNCTION__, ifevent->ifidx, 1047 event->ifname, ifevent->action)); 1048 if (ifevent->action == WLC_E_IF_ADD || 1049 ifevent->action == WLC_E_IF_CHANGE) 1050 wl_cfg80211_notify_ifchange(); 1051 return (BCME_OK); 1052 } 1053#endif /* WL_CFG80211 */ 1054 if (ifevent->ifidx > 0 && ifevent->ifidx < DHD_MAX_IFS) { 1055 if (ifevent->action == WLC_E_IF_ADD) { 1056 if (dhd_add_if(dhd_pub->info, ifevent->ifidx, 1057 NULL, event->ifname, 1058 event->addr.octet, 1059 ifevent->flags, ifevent->bssidx)) { 1060 DHD_ERROR(("%s: dhd_add_if failed!!" 1061 " ifidx: %d for %s\n", 1062 __FUNCTION__, 1063 ifevent->ifidx, 1064 event->ifname)); 1065 return (BCME_ERROR); 1066 } 1067 } 1068 else if (ifevent->action == WLC_E_IF_DEL) 1069 dhd_del_if(dhd_pub->info, ifevent->ifidx); 1070 } else { 1071#ifndef PROP_TXSTATUS 1072 DHD_ERROR(("%s: Invalid ifidx %d for %s\n", 1073 __FUNCTION__, ifevent->ifidx, event->ifname)); 1074#endif /* !PROP_TXSTATUS */ 1075 } 1076 } 1077 /* send up the if event: btamp user needs it */ 1078 *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname); 1079 /* push up to external supp/auth */ 1080 dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx); 1081 break; 1082 1083 1084#ifdef WLMEDIA_HTSF 1085 case WLC_E_HTSFSYNC: 1086 htsf_update(dhd_pub->info, event_data); 1087 break; 1088#endif /* WLMEDIA_HTSF */ 1089#if defined(NDIS630) 1090 case WLC_E_NDIS_LINK: 1091 break; 1092#else /* defined(NDIS630) && defined(BCMDONGLEHOST) */ 1093 case WLC_E_NDIS_LINK: { 1094 uint32 temp = hton32(WLC_E_LINK); 1095 1096 memcpy((void *)(&pvt_data->event.event_type), &temp, 1097 sizeof(pvt_data->event.event_type)); 1098 } 1099#endif 1100 /* These are what external supplicant/authenticator wants */ 1101 /* fall through */ 1102 case WLC_E_LINK: 1103 case WLC_E_DEAUTH: 1104 case WLC_E_DEAUTH_IND: 1105 case WLC_E_DISASSOC: 1106 case WLC_E_DISASSOC_IND: 1107 DHD_EVENT(("%s: Link event %d, flags %x, status %x\n", 1108 __FUNCTION__, type, flags, status)); 1109 /* fall through */ 1110 default: 1111 *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname); 1112 /* push up to external supp/auth */ 1113 dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx); 1114 DHD_TRACE(("%s: MAC event %d, flags %x, status %x\n", 1115 __FUNCTION__, type, flags, status)); 1116 BCM_REFERENCE(flags); 1117 BCM_REFERENCE(status); 1118 1119 /* put it back to WLC_E_NDIS_LINK */ 1120 if (type == WLC_E_NDIS_LINK) { 1121 uint32 temp; 1122 1123 temp = ntoh32_ua((void *)&event->event_type); 1124 DHD_TRACE(("Converted to WLC_E_LINK type %d\n", temp)); 1125 1126 temp = ntoh32(WLC_E_NDIS_LINK); 1127 memcpy((void *)(&pvt_data->event.event_type), &temp, 1128 sizeof(pvt_data->event.event_type)); 1129 } 1130 break; 1131 } 1132 1133#ifdef SHOW_EVENTS 1134 wl_show_host_event(event, (void *)event_data); 1135#endif /* SHOW_EVENTS */ 1136 1137 return (BCME_OK); 1138} 1139 1140void 1141wl_event_to_host_order(wl_event_msg_t * evt) 1142{ 1143 /* Event struct members passed from dongle to host are stored in network 1144 * byte order. Convert all members to host-order. 1145 */ 1146 evt->event_type = ntoh32(evt->event_type); 1147 evt->flags = ntoh16(evt->flags); 1148 evt->status = ntoh32(evt->status); 1149 evt->reason = ntoh32(evt->reason); 1150 evt->auth_type = ntoh32(evt->auth_type); 1151 evt->datalen = ntoh32(evt->datalen); 1152 evt->version = ntoh16(evt->version); 1153} 1154 1155void 1156dhd_print_buf(void *pbuf, int len, int bytes_per_line) 1157{ 1158#ifdef DHD_DEBUG 1159 int i, j = 0; 1160 unsigned char *buf = pbuf; 1161 1162 if (bytes_per_line == 0) { 1163 bytes_per_line = len; 1164 } 1165 1166 for (i = 0; i < len; i++) { 1167 printf("%2.2x", *buf++); 1168 j++; 1169 if (j == bytes_per_line) { 1170 printf("\n"); 1171 j = 0; 1172 } else { 1173 printf(":"); 1174 } 1175 } 1176 printf("\n"); 1177#endif /* DHD_DEBUG */ 1178} 1179 1180#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) 1181 1182/* Convert user's input in hex pattern to byte-size mask */ 1183static int 1184wl_pattern_atoh(char *src, char *dst) 1185{ 1186 int i; 1187 if (strncmp(src, "0x", 2) != 0 && 1188 strncmp(src, "0X", 2) != 0) { 1189 DHD_ERROR(("Mask invalid format. Needs to start with 0x\n")); 1190 return -1; 1191 } 1192 src = src + 2; /* Skip past 0x */ 1193 if (strlen(src) % 2 != 0) { 1194 DHD_ERROR(("Mask invalid format. Needs to be of even length\n")); 1195 return -1; 1196 } 1197 for (i = 0; *src != '\0'; i++) { 1198 char num[3]; 1199 bcm_strncpy_s(num, sizeof(num), src, 2); 1200 num[2] = '\0'; 1201 dst[i] = (uint8)strtoul(num, NULL, 16); 1202 src += 2; 1203 } 1204 return i; 1205} 1206 1207void 1208dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode) 1209{ 1210 char *argv[8]; 1211 int i = 0; 1212 const char *str; 1213 int buf_len; 1214 int str_len; 1215 char *arg_save = 0, *arg_org = 0; 1216 int rc; 1217 char buf[128]; 1218 wl_pkt_filter_enable_t enable_parm; 1219 wl_pkt_filter_enable_t * pkt_filterp; 1220 1221 if (!arg) 1222 return; 1223 1224 if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) { 1225 DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); 1226 goto fail; 1227 } 1228 arg_org = arg_save; 1229 memcpy(arg_save, arg, strlen(arg) + 1); 1230 1231 argv[i] = bcmstrtok(&arg_save, " ", 0); 1232 1233 i = 0; 1234 if (argv[i] == NULL) { 1235 DHD_ERROR(("No args provided\n")); 1236 goto fail; 1237 } 1238 1239 str = "pkt_filter_enable"; 1240 str_len = strlen(str); 1241 bcm_strncpy_s(buf, sizeof(buf), str, str_len); 1242 buf[str_len] = '\0'; 1243 buf_len = str_len + 1; 1244 1245 pkt_filterp = (wl_pkt_filter_enable_t *)(buf + str_len + 1); 1246 1247 /* Parse packet filter id. */ 1248 enable_parm.id = htod32(strtoul(argv[i], NULL, 0)); 1249 1250 /* Parse enable/disable value. */ 1251 enable_parm.enable = htod32(enable); 1252 1253 buf_len += sizeof(enable_parm); 1254 memcpy((char *)pkt_filterp, 1255 &enable_parm, 1256 sizeof(enable_parm)); 1257 1258 /* Enable/disable the specified filter. */ 1259 rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); 1260 rc = rc >= 0 ? 0 : rc; 1261 if (rc) 1262 DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", 1263 __FUNCTION__, arg, rc)); 1264 else 1265 DHD_TRACE(("%s: successfully added pktfilter %s\n", 1266 __FUNCTION__, arg)); 1267 1268 /* Contorl the master mode */ 1269 bcm_mkiovar("pkt_filter_mode", (char *)&master_mode, 4, buf, sizeof(buf)); 1270 rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); 1271 rc = rc >= 0 ? 0 : rc; 1272 if (rc) 1273 DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", 1274 __FUNCTION__, arg, rc)); 1275 1276fail: 1277 if (arg_org) 1278 MFREE(dhd->osh, arg_org, strlen(arg) + 1); 1279} 1280 1281void 1282dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg) 1283{ 1284 const char *str; 1285 wl_pkt_filter_t pkt_filter; 1286 wl_pkt_filter_t *pkt_filterp; 1287 int buf_len; 1288 int str_len; 1289 int rc; 1290 uint32 mask_size; 1291 uint32 pattern_size; 1292 char *argv[8], * buf = 0; 1293 int i = 0; 1294 char *arg_save = 0, *arg_org = 0; 1295#define BUF_SIZE 2048 1296 1297 if (!arg) 1298 return; 1299 1300 if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) { 1301 DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); 1302 goto fail; 1303 } 1304 1305 arg_org = arg_save; 1306 1307 if (!(buf = MALLOC(dhd->osh, BUF_SIZE))) { 1308 DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); 1309 goto fail; 1310 } 1311 1312 memcpy(arg_save, arg, strlen(arg) + 1); 1313 1314 if (strlen(arg) > BUF_SIZE) { 1315 DHD_ERROR(("Not enough buffer %d < %d\n", (int)strlen(arg), (int)sizeof(buf))); 1316 goto fail; 1317 } 1318 1319 argv[i] = bcmstrtok(&arg_save, " ", 0); 1320 while (argv[i++]) 1321 argv[i] = bcmstrtok(&arg_save, " ", 0); 1322 1323 i = 0; 1324 if (argv[i] == NULL) { 1325 DHD_ERROR(("No args provided\n")); 1326 goto fail; 1327 } 1328 1329 str = "pkt_filter_add"; 1330 str_len = strlen(str); 1331 bcm_strncpy_s(buf, BUF_SIZE, str, str_len); 1332 buf[ str_len ] = '\0'; 1333 buf_len = str_len + 1; 1334 1335 pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1); 1336 1337 /* Parse packet filter id. */ 1338 pkt_filter.id = htod32(strtoul(argv[i], NULL, 0)); 1339 1340 if (argv[++i] == NULL) { 1341 DHD_ERROR(("Polarity not provided\n")); 1342 goto fail; 1343 } 1344 1345 /* Parse filter polarity. */ 1346 pkt_filter.negate_match = htod32(strtoul(argv[i], NULL, 0)); 1347 1348 if (argv[++i] == NULL) { 1349 DHD_ERROR(("Filter type not provided\n")); 1350 goto fail; 1351 } 1352 1353 /* Parse filter type. */ 1354 pkt_filter.type = htod32(strtoul(argv[i], NULL, 0)); 1355 1356 if (argv[++i] == NULL) { 1357 DHD_ERROR(("Offset not provided\n")); 1358 goto fail; 1359 } 1360 1361 /* Parse pattern filter offset. */ 1362 pkt_filter.u.pattern.offset = htod32(strtoul(argv[i], NULL, 0)); 1363 1364 if (argv[++i] == NULL) { 1365 DHD_ERROR(("Bitmask not provided\n")); 1366 goto fail; 1367 } 1368 1369 /* Parse pattern filter mask. */ 1370 mask_size = 1371 htod32(wl_pattern_atoh(argv[i], (char *) pkt_filterp->u.pattern.mask_and_pattern)); 1372 1373 if (argv[++i] == NULL) { 1374 DHD_ERROR(("Pattern not provided\n")); 1375 goto fail; 1376 } 1377 1378 /* Parse pattern filter pattern. */ 1379 pattern_size = 1380 htod32(wl_pattern_atoh(argv[i], 1381 (char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size])); 1382 1383 if (mask_size != pattern_size) { 1384 DHD_ERROR(("Mask and pattern not the same size\n")); 1385 goto fail; 1386 } 1387 1388 pkt_filter.u.pattern.size_bytes = mask_size; 1389 buf_len += WL_PKT_FILTER_FIXED_LEN; 1390 buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size); 1391 1392 /* Keep-alive attributes are set in local variable (keep_alive_pkt), and 1393 ** then memcpy'ed into buffer (keep_alive_pktp) since there is no 1394 ** guarantee that the buffer is properly aligned. 1395 */ 1396 memcpy((char *)pkt_filterp, 1397 &pkt_filter, 1398 WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN); 1399 1400 rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); 1401 rc = rc >= 0 ? 0 : rc; 1402 1403 if (rc) 1404 DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", 1405 __FUNCTION__, arg, rc)); 1406 else 1407 DHD_TRACE(("%s: successfully added pktfilter %s\n", 1408 __FUNCTION__, arg)); 1409 1410fail: 1411 if (arg_org) 1412 MFREE(dhd->osh, arg_org, strlen(arg) + 1); 1413 1414 if (buf) 1415 MFREE(dhd->osh, buf, BUF_SIZE); 1416} 1417 1418/* ========================== */ 1419/* ==== ARP OFFLOAD SUPPORT = */ 1420/* ========================== */ 1421#ifdef ARP_OFFLOAD_SUPPORT 1422void 1423dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode) 1424{ 1425 char iovbuf[32]; 1426 int retcode; 1427 1428 bcm_mkiovar("arp_ol", (char *)&arp_mode, 4, iovbuf, sizeof(iovbuf)); 1429 retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); 1430 retcode = retcode >= 0 ? 0 : retcode; 1431 if (retcode) 1432 DHD_TRACE(("%s: failed to set ARP offload mode to 0x%x, retcode = %d\n", 1433 __FUNCTION__, arp_mode, retcode)); 1434 else 1435 DHD_TRACE(("%s: successfully set ARP offload mode to 0x%x\n", 1436 __FUNCTION__, arp_mode)); 1437} 1438 1439void 1440dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable) 1441{ 1442 char iovbuf[32]; 1443 int retcode; 1444 1445 bcm_mkiovar("arpoe", (char *)&arp_enable, 4, iovbuf, sizeof(iovbuf)); 1446 retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); 1447 retcode = retcode >= 0 ? 0 : retcode; 1448 if (retcode) 1449 DHD_TRACE(("%s: failed to enabe ARP offload to %d, retcode = %d\n", 1450 __FUNCTION__, arp_enable, retcode)); 1451 else 1452 DHD_TRACE(("%s: successfully enabed ARP offload to %d\n", 1453 __FUNCTION__, arp_enable)); 1454} 1455 1456void 1457dhd_aoe_arp_clr(dhd_pub_t *dhd) 1458{ 1459 int ret = 0; 1460 int iov_len = 0; 1461 char iovbuf[128]; 1462 1463 if (dhd == NULL) return; 1464 1465 iov_len = bcm_mkiovar("arp_table_clear", 0, 0, iovbuf, sizeof(iovbuf)); 1466 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, 0) < 0)) 1467 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); 1468} 1469 1470void 1471dhd_aoe_hostip_clr(dhd_pub_t *dhd) 1472{ 1473 int ret = 0; 1474 int iov_len = 0; 1475 char iovbuf[128]; 1476 1477 if (dhd == NULL) return; 1478 1479 iov_len = bcm_mkiovar("arp_hostip_clear", 0, 0, iovbuf, sizeof(iovbuf)); 1480 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, 0)) < 0) 1481 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); 1482} 1483 1484void 1485dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr) 1486{ 1487 int iov_len = 0; 1488 char iovbuf[32]; 1489 int retcode; 1490 1491 iov_len = bcm_mkiovar("arp_hostip", (char *)&ipaddr, 4, iovbuf, sizeof(iovbuf)); 1492 retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, 0); 1493 1494 if (retcode) 1495 DHD_TRACE(("%s: ARP ip addr add failed, retcode = %d\n", 1496 __FUNCTION__, retcode)); 1497 else 1498 DHD_TRACE(("%s: sARP H ipaddr entry added \n", 1499 __FUNCTION__)); 1500} 1501 1502int 1503dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen) 1504{ 1505 int retcode, i; 1506 int iov_len; 1507 uint32 *ptr32 = buf; 1508 bool clr_bottom = FALSE; 1509 1510 if (!buf) 1511 return -1; 1512 1513 iov_len = bcm_mkiovar("arp_hostip", 0, 0, buf, buflen); 1514 BCM_REFERENCE(iov_len); 1515 retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, buflen, FALSE, 0); 1516 1517 if (retcode) { 1518 DHD_TRACE(("%s: ioctl WLC_GET_VAR error %d\n", 1519 __FUNCTION__, retcode)); 1520 1521 return -1; 1522 } 1523 1524 /* clean up the buf, ascii reminder */ 1525 for (i = 0; i < MAX_IPV4_ENTRIES; i++) { 1526 if (!clr_bottom) { 1527 if (*ptr32 == 0) 1528 clr_bottom = TRUE; 1529 } else { 1530 *ptr32 = 0; 1531 } 1532 ptr32++; 1533 } 1534 1535 return 0; 1536} 1537#endif /* ARP_OFFLOAD_SUPPORT */ 1538 1539/* send up locally generated event */ 1540void 1541dhd_sendup_event_common(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data) 1542{ 1543 switch (ntoh32(event->event_type)) { 1544#ifdef WLBTAMP 1545 case WLC_E_BTA_HCI_EVENT: 1546 break; 1547#endif /* WLBTAMP */ 1548 default: 1549 break; 1550 } 1551 1552 /* Call per-port handler. */ 1553 dhd_sendup_event(dhdp, event, data); 1554} 1555 1556#ifdef SIMPLE_ISCAN 1557 1558uint iscan_thread_id = 0; 1559iscan_buf_t * iscan_chain = 0; 1560 1561iscan_buf_t * 1562dhd_iscan_allocate_buf(dhd_pub_t *dhd, iscan_buf_t **iscanbuf) 1563{ 1564 iscan_buf_t *iscanbuf_alloc = 0; 1565 iscan_buf_t *iscanbuf_head; 1566 1567 DHD_ISCAN(("%s: Entered\n", __FUNCTION__)); 1568 dhd_iscan_lock(); 1569 1570 iscanbuf_alloc = (iscan_buf_t*)MALLOC(dhd->osh, sizeof(iscan_buf_t)); 1571 if (iscanbuf_alloc == NULL) 1572 goto fail; 1573 1574 iscanbuf_alloc->next = NULL; 1575 iscanbuf_head = *iscanbuf; 1576 1577 DHD_ISCAN(("%s: addr of allocated node = 0x%X" 1578 "addr of iscanbuf_head = 0x%X dhd = 0x%X\n", 1579 __FUNCTION__, iscanbuf_alloc, iscanbuf_head, dhd)); 1580 1581 if (iscanbuf_head == NULL) { 1582 *iscanbuf = iscanbuf_alloc; 1583 DHD_ISCAN(("%s: Head is allocated\n", __FUNCTION__)); 1584 goto fail; 1585 } 1586 1587 while (iscanbuf_head->next) 1588 iscanbuf_head = iscanbuf_head->next; 1589 1590 iscanbuf_head->next = iscanbuf_alloc; 1591 1592fail: 1593 dhd_iscan_unlock(); 1594 return iscanbuf_alloc; 1595} 1596 1597void 1598dhd_iscan_free_buf(void *dhdp, iscan_buf_t *iscan_delete) 1599{ 1600 iscan_buf_t *iscanbuf_free = 0; 1601 iscan_buf_t *iscanbuf_prv = 0; 1602 iscan_buf_t *iscanbuf_cur; 1603 dhd_pub_t *dhd = dhd_bus_pub(dhdp); 1604 DHD_ISCAN(("%s: Entered\n", __FUNCTION__)); 1605 1606 dhd_iscan_lock(); 1607 1608 iscanbuf_cur = iscan_chain; 1609 1610 /* If iscan_delete is null then delete the entire 1611 * chain or else delete specific one provided 1612 */ 1613 if (!iscan_delete) { 1614 while (iscanbuf_cur) { 1615 iscanbuf_free = iscanbuf_cur; 1616 iscanbuf_cur = iscanbuf_cur->next; 1617 iscanbuf_free->next = 0; 1618 MFREE(dhd->osh, iscanbuf_free, sizeof(iscan_buf_t)); 1619 } 1620 iscan_chain = 0; 1621 } else { 1622 while (iscanbuf_cur) { 1623 if (iscanbuf_cur == iscan_delete) 1624 break; 1625 iscanbuf_prv = iscanbuf_cur; 1626 iscanbuf_cur = iscanbuf_cur->next; 1627 } 1628 if (iscanbuf_prv) 1629 iscanbuf_prv->next = iscan_delete->next; 1630 1631 iscan_delete->next = 0; 1632 MFREE(dhd->osh, iscan_delete, sizeof(iscan_buf_t)); 1633 1634 if (!iscanbuf_prv) 1635 iscan_chain = 0; 1636 } 1637 dhd_iscan_unlock(); 1638} 1639 1640iscan_buf_t * 1641dhd_iscan_result_buf(void) 1642{ 1643 return iscan_chain; 1644} 1645 1646int 1647dhd_iscan_issue_request(void * dhdp, wl_iscan_params_t *pParams, uint32 size) 1648{ 1649 int rc = -1; 1650 dhd_pub_t *dhd = dhd_bus_pub(dhdp); 1651 char *buf; 1652 char iovar[] = "iscan"; 1653 uint32 allocSize = 0; 1654 wl_ioctl_t ioctl; 1655 1656 if (pParams) { 1657 allocSize = (size + strlen(iovar) + 1); 1658 if ((allocSize < size) || (allocSize < strlen(iovar))) 1659 { 1660 DHD_ERROR(("%s: overflow - allocation size too large %d < %d + %d!\n", 1661 __FUNCTION__, allocSize, size, strlen(iovar))); 1662 goto cleanUp; 1663 } 1664 buf = MALLOC(dhd->osh, allocSize); 1665 1666 if (buf == NULL) 1667 { 1668 DHD_ERROR(("%s: malloc of size %d failed!\n", __FUNCTION__, allocSize)); 1669 goto cleanUp; 1670 } 1671 ioctl.cmd = WLC_SET_VAR; 1672 bcm_mkiovar(iovar, (char *)pParams, size, buf, allocSize); 1673 rc = dhd_wl_ioctl(dhd, 0, &ioctl, buf, allocSize); 1674 } 1675 1676cleanUp: 1677 if (buf) { 1678 MFREE(dhd->osh, buf, allocSize); 1679 } 1680 1681 return rc; 1682} 1683 1684static int 1685dhd_iscan_get_partial_result(void *dhdp, uint *scan_count) 1686{ 1687 wl_iscan_results_t *list_buf; 1688 wl_iscan_results_t list; 1689 wl_scan_results_t *results; 1690 iscan_buf_t *iscan_cur; 1691 int status = -1; 1692 dhd_pub_t *dhd = dhd_bus_pub(dhdp); 1693 int rc; 1694 wl_ioctl_t ioctl; 1695 1696 DHD_ISCAN(("%s: Enter\n", __FUNCTION__)); 1697 1698 iscan_cur = dhd_iscan_allocate_buf(dhd, &iscan_chain); 1699 if (!iscan_cur) { 1700 DHD_ERROR(("%s: Failed to allocate node\n", __FUNCTION__)); 1701 dhd_iscan_free_buf(dhdp, 0); 1702 dhd_iscan_request(dhdp, WL_SCAN_ACTION_ABORT); 1703 dhd_ind_scan_confirm(dhdp, FALSE); 1704 goto fail; 1705 } 1706 1707 dhd_iscan_lock(); 1708 1709 memset(iscan_cur->iscan_buf, 0, WLC_IW_ISCAN_MAXLEN); 1710 list_buf = (wl_iscan_results_t*)iscan_cur->iscan_buf; 1711 results = &list_buf->results; 1712 results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE; 1713 results->version = 0; 1714 results->count = 0; 1715 1716 memset(&list, 0, sizeof(list)); 1717 list.results.buflen = htod32(WLC_IW_ISCAN_MAXLEN); 1718 bcm_mkiovar("iscanresults", (char *)&list, WL_ISCAN_RESULTS_FIXED_SIZE, 1719 iscan_cur->iscan_buf, WLC_IW_ISCAN_MAXLEN); 1720 ioctl.cmd = WLC_GET_VAR; 1721 ioctl.set = FALSE; 1722 rc = dhd_wl_ioctl(dhd, 0, &ioctl, iscan_cur->iscan_buf, WLC_IW_ISCAN_MAXLEN); 1723 1724 results->buflen = dtoh32(results->buflen); 1725 results->version = dtoh32(results->version); 1726 *scan_count = results->count = dtoh32(results->count); 1727 status = dtoh32(list_buf->status); 1728 DHD_ISCAN(("%s: Got %d resuls status = (%x)\n", __FUNCTION__, results->count, status)); 1729 1730 dhd_iscan_unlock(); 1731 1732 if (!(*scan_count)) { 1733 /* TODO: race condition when FLUSH already called */ 1734 dhd_iscan_free_buf(dhdp, 0); 1735 } 1736fail: 1737 return status; 1738} 1739 1740#endif /* SIMPLE_ISCAN */ 1741 1742/* 1743 * returns = TRUE if associated, FALSE if not associated 1744 */ 1745bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf) 1746{ 1747 char bssid[6], zbuf[6]; 1748 int ret = -1; 1749 1750 bzero(bssid, 6); 1751 bzero(zbuf, 6); 1752 1753 ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BSSID, (char *)&bssid, ETHER_ADDR_LEN, FALSE, 0); 1754 DHD_TRACE((" %s WLC_GET_BSSID ioctl res = %d\n", __FUNCTION__, ret)); 1755 1756 if (ret == BCME_NOTASSOCIATED) { 1757 DHD_TRACE(("%s: not associated! res:%d\n", __FUNCTION__, ret)); 1758 } 1759 1760 if (ret < 0) 1761 return FALSE; 1762 1763 if ((memcmp(bssid, zbuf, ETHER_ADDR_LEN) != 0)) { 1764 /* STA is assocoated BSSID is non zero */ 1765 1766 if (bss_buf) { 1767 /* return bss if caller provided buf */ 1768 memcpy(bss_buf, bssid, ETHER_ADDR_LEN); 1769 } 1770 return TRUE; 1771 } else { 1772 DHD_TRACE(("%s: WLC_GET_BSSID ioctl returned zero bssid\n", __FUNCTION__)); 1773 return FALSE; 1774 } 1775} 1776 1777 1778/* Function to estimate possible DTIM_SKIP value */ 1779int 1780dhd_get_dtim_skip(dhd_pub_t *dhd) 1781{ 1782 int bcn_li_dtim; 1783 int ret = -1; 1784 int dtim_assoc = 0; 1785 1786 if ((dhd->dtim_skip == 0) || (dhd->dtim_skip == 1)) 1787 bcn_li_dtim = 3; 1788 else 1789 bcn_li_dtim = dhd->dtim_skip; 1790 1791 /* Check if associated */ 1792 if (dhd_is_associated(dhd, NULL) == FALSE) { 1793 DHD_TRACE(("%s NOT assoc ret %d\n", __FUNCTION__, ret)); 1794 goto exit; 1795 } 1796 1797 /* if assoc grab ap's dtim value */ 1798 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_DTIMPRD, 1799 &dtim_assoc, sizeof(dtim_assoc), FALSE, 0)) < 0) { 1800 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); 1801 goto exit; 1802 } 1803 1804 DHD_ERROR(("%s bcn_li_dtim=%d DTIM=%d Listen=%d\n", 1805 __FUNCTION__, bcn_li_dtim, dtim_assoc, LISTEN_INTERVAL)); 1806 1807 /* if not assocated just eixt */ 1808 if (dtim_assoc == 0) { 1809 goto exit; 1810 } 1811 1812 /* check if sta listen interval fits into AP dtim */ 1813 if (dtim_assoc > LISTEN_INTERVAL) { 1814 /* AP DTIM to big for our Listen Interval : no dtim skiping */ 1815 bcn_li_dtim = 1; 1816 DHD_ERROR(("%s DTIM=%d > Listen=%d : too big ...\n", 1817 __FUNCTION__, dtim_assoc, LISTEN_INTERVAL)); 1818 goto exit; 1819 } 1820 1821 if ((bcn_li_dtim * dtim_assoc) > LISTEN_INTERVAL) { 1822 /* Round up dtim_skip to fit into STAs Listen Interval */ 1823 bcn_li_dtim = (int)(LISTEN_INTERVAL / dtim_assoc); 1824 DHD_TRACE(("%s agjust dtim_skip as %d\n", __FUNCTION__, bcn_li_dtim)); 1825 } 1826 1827exit: 1828 return bcn_li_dtim; 1829} 1830 1831/* Check if HostAPD or WFD mode setup */ 1832bool dhd_check_ap_wfd_mode_set(dhd_pub_t *dhd) 1833{ 1834#ifdef WL_CFG80211 1835#ifndef WL_ENABLE_P2P_IF 1836 /* To be back compatble with ICS MR1 release where p2p interface 1837 * disable but wlan0 used for p2p 1838 */ 1839 if (((dhd->op_mode & HOSTAPD_MASK) == HOSTAPD_MASK) || 1840 ((dhd->op_mode & WFD_MASK) == WFD_MASK)) { 1841 return TRUE; 1842 } 1843 else 1844#else 1845 /* concurent mode with p2p interface for wfd and wlan0 for sta */ 1846 if (((dhd->op_mode & P2P_GO_ENABLED) == P2P_GO_ENABLED) || 1847 ((dhd->op_mode & P2P_GC_ENABLED) == P2P_GC_ENABLED)) { 1848 DHD_ERROR(("%s P2P enabled for mode=%d\n", __FUNCTION__, dhd->op_mode)); 1849 return TRUE; 1850 } 1851 else 1852#endif /* WL_ENABLE_P2P_IF */ 1853#endif /* WL_CFG80211 */ 1854 return FALSE; 1855} 1856 1857#if defined(PNO_SUPPORT) 1858int 1859dhd_pno_clean(dhd_pub_t *dhd) 1860{ 1861 char iovbuf[128]; 1862 int pfn_enabled = 0; 1863 int iov_len = 0; 1864 int ret; 1865 1866 /* Disable pfn */ 1867 iov_len = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf)); 1868 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) >= 0) { 1869 /* clear pfn */ 1870 iov_len = bcm_mkiovar("pfnclear", 0, 0, iovbuf, sizeof(iovbuf)); 1871 if (iov_len) { 1872 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, 1873 iov_len, TRUE, 0)) < 0) { 1874 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); 1875 } 1876 } 1877 else { 1878 ret = -1; 1879 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, iov_len)); 1880 } 1881 } 1882 else 1883 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); 1884 1885 return ret; 1886} 1887 1888int 1889dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled) 1890{ 1891 char iovbuf[128]; 1892 int ret = -1; 1893 1894 if ((!dhd) && ((pfn_enabled != 0) || (pfn_enabled != 1))) { 1895 DHD_ERROR(("%s error exit\n", __FUNCTION__)); 1896 return ret; 1897 } 1898 1899 if (dhd_check_ap_wfd_mode_set(dhd) == TRUE) 1900 return (ret); 1901 1902 memset(iovbuf, 0, sizeof(iovbuf)); 1903 1904 if ((pfn_enabled) && (dhd_is_associated(dhd, NULL) == TRUE)) { 1905 DHD_ERROR(("%s pno is NOT enable : called in assoc mode , ignore\n", __FUNCTION__)); 1906 return ret; 1907 } 1908 1909 /* Enable/disable PNO */ 1910 if ((ret = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf))) > 0) { 1911 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, 1912 iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { 1913 DHD_ERROR(("%s failed for error=%d\n", __FUNCTION__, ret)); 1914 return ret; 1915 } 1916 else { 1917 dhd->pno_enable = pfn_enabled; 1918 DHD_TRACE(("%s set pno as %s\n", 1919 __FUNCTION__, dhd->pno_enable ? "Enable" : "Disable")); 1920 } 1921 } 1922 else DHD_ERROR(("%s failed err=%d\n", __FUNCTION__, ret)); 1923 1924 return ret; 1925} 1926 1927/* Function to execute …
Large files files are truncated, but you can click here to view the full file