2 * Broadcom Dongle Host Driver (DHD), common DHD core.
4 * $Copyright Open Broadcom Corporation$
6 * $Id: dhd_common.c 492215 2014-07-20 16:44:15Z $
14 #include <bcmendian.h>
15 #include <dngl_stats.h>
19 #include <proto/bcmevent.h>
22 #include <event_log.h>
23 #endif /* SHOW_LOGTRACE */
26 #include <dhd_flowring.h>
30 #include <dhd_proto.h>
31 #include <dhd_config.h>
36 #include <wl_cfg80211.h>
39 #include <proto/bt_amp_hci.h>
50 #define htodchanspec(i) (i)
51 #define dtohchanspec(i) (i)
54 #include <wlfc_proto.h>
59 #include <dhd_linux.h>
60 #include <dhd_wmf_linux.h>
65 extern void htsf_update(struct dhd_info *dhd, void *data);
67 int dhd_msg_level = DHD_ERROR_VAL;
73 char fw_path2[MOD_PARAM_PATHLEN];
74 extern bool softap_enabled;
77 /* Last connection success/failure status */
78 uint32 dhd_conn_event;
79 uint32 dhd_conn_status;
80 uint32 dhd_conn_reason;
82 #if defined(SHOW_EVENTS) && defined(SHOW_LOGTRACE)
83 static int check_event_log_sequence_number(uint32 seq_no);
84 #endif /* defined(SHOW_EVENTS) && defined(SHOW_LOGTRACE) */
85 extern int dhd_iscan_request(void * dhdp, uint16 action);
86 extern void dhd_ind_scan_confirm(void *h, bool status);
87 extern int dhd_iscan_in_progress(void *h);
88 void dhd_iscan_lock(void);
89 void dhd_iscan_unlock(void);
90 extern int dhd_change_mtu(dhd_pub_t *dhd, int new_mtu, int ifidx);
91 #if !defined(AP) && defined(WLP2P)
92 extern int dhd_get_concurrent_capabilites(dhd_pub_t *dhd);
94 bool ap_cfg_running = FALSE;
95 bool ap_fw_loaded = FALSE;
97 /* Version string to report */
100 #define SRCBASE "drivers/net/wireless/bcmdhd"
102 #define DHD_COMPILED "\nCompiled in " SRCBASE
103 #endif /* DHD_DEBUG */
105 #if defined(DHD_DEBUG)
106 const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR
107 DHD_COMPILED " on " __DATE__ " at " __TIME__;
109 const char dhd_version[] = "\nDongle Host Driver, version " EPI_VERSION_STR "\nCompiled from ";
112 void dhd_set_timer(void *bus, uint wdtick);
132 IOV_HCI_CMD, /* HCI command */
133 IOV_HCI_ACL_DATA, /* HCI data packet */
135 #if defined(DHD_DEBUG)
138 #endif /* defined(DHD_DEBUG) */
140 IOV_PROPTXSTATUS_ENABLE,
141 IOV_PROPTXSTATUS_MODE,
142 IOV_PROPTXSTATUS_OPT,
145 IOV_QMON_TIME_PERCENT,
146 #endif /* QMONITOR */
147 IOV_PROPTXSTATUS_MODULE_IGNORE,
148 IOV_PROPTXSTATUS_CREDIT_IGNORE,
149 IOV_PROPTXSTATUS_TXSTATUS_IGNORE,
150 IOV_PROPTXSTATUS_RXPKT_CHK,
151 #endif /* PROP_TXSTATUS */
157 IOV_HOSTREORDER_FLOWS,
158 #ifdef DHDTCPACK_SUPPRESS
160 #endif /* DHDTCPACK_SUPPRESS */
164 IOV_WMF_MCAST_DATA_SENDUP,
165 #ifdef WL_IGMP_UCQUERY
166 IOV_WMF_UCAST_IGMP_QUERY,
167 #endif /* WL_IGMP_UCQUERY */
168 #ifdef DHD_UCAST_UPNP
170 #endif /* DHD_UCAST_UPNP */
173 #ifdef DHD_UNICAST_DHCP
175 #endif /* DHD_UNICAST_DHCP */
182 const bcm_iovar_t dhd_iovars[] = {
183 {"version", IOV_VERSION, 0, IOVT_BUFFER, sizeof(dhd_version) },
184 {"wlmsglevel", IOV_WLMSGLEVEL, 0, IOVT_UINT32, 0 },
186 {"msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 },
187 #endif /* DHD_DEBUG */
188 {"bcmerrorstr", IOV_BCMERRORSTR, 0, IOVT_BUFFER, BCME_STRLEN },
189 {"bcmerror", IOV_BCMERROR, 0, IOVT_INT8, 0 },
190 {"wdtick", IOV_WDTICK, 0, IOVT_UINT32, 0 },
191 {"dump", IOV_DUMP, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN },
193 {"cons", IOV_CONS, 0, IOVT_BUFFER, 0 },
194 {"dconpoll", IOV_DCONSOLE_POLL, 0, IOVT_UINT32, 0 },
196 {"clearcounts", IOV_CLEARCOUNTS, 0, IOVT_VOID, 0 },
197 {"gpioob", IOV_GPIOOB, 0, IOVT_UINT32, 0 },
198 {"ioctl_timeout", IOV_IOCTLTIMEOUT, 0, IOVT_UINT32, 0 },
200 {"HCI_cmd", IOV_HCI_CMD, 0, IOVT_BUFFER, 0},
201 {"HCI_ACL_data", IOV_HCI_ACL_DATA, 0, IOVT_BUFFER, 0},
204 {"proptx", IOV_PROPTXSTATUS_ENABLE, 0, IOVT_BOOL, 0 },
206 set the proptxtstatus operation mode:
207 0 - Do not do any proptxtstatus flow control
208 1 - Use implied credit from a packet status
209 2 - Use explicit credit
211 {"ptxmode", IOV_PROPTXSTATUS_MODE, 0, IOVT_UINT32, 0 },
212 {"proptx_opt", IOV_PROPTXSTATUS_OPT, 0, IOVT_UINT32, 0 },
214 {"qtime_thres", IOV_QMON_TIME_THRES, 0, IOVT_UINT32, 0 },
215 {"qtime_percent", IOV_QMON_TIME_PERCENT, 0, IOVT_UINT32, 0 },
216 #endif /* QMONITOR */
217 {"pmodule_ignore", IOV_PROPTXSTATUS_MODULE_IGNORE, 0, IOVT_BOOL, 0 },
218 {"pcredit_ignore", IOV_PROPTXSTATUS_CREDIT_IGNORE, 0, IOVT_BOOL, 0 },
219 {"ptxstatus_ignore", IOV_PROPTXSTATUS_TXSTATUS_IGNORE, 0, IOVT_BOOL, 0 },
220 {"rxpkt_chk", IOV_PROPTXSTATUS_RXPKT_CHK, 0, IOVT_BOOL, 0 },
221 #endif /* PROP_TXSTATUS */
222 {"bustype", IOV_BUS_TYPE, 0, IOVT_UINT32, 0},
224 {"pktdlystatsz", IOV_WLPKTDLYSTAT_SZ, 0, IOVT_UINT8, 0 },
226 {"changemtu", IOV_CHANGEMTU, 0, IOVT_UINT32, 0 },
227 {"host_reorder_flows", IOV_HOSTREORDER_FLOWS, 0, IOVT_BUFFER,
228 (WLHOST_REORDERDATA_MAXFLOWS + 1) },
229 #ifdef DHDTCPACK_SUPPRESS
230 {"tcpack_suppress", IOV_TCPACK_SUPPRESS, 0, IOVT_UINT8, 0 },
231 #endif /* DHDTCPACK_SUPPRESS */
233 {"wmf_bss_enable", IOV_WMF_BSS_ENAB, 0, IOVT_BOOL, 0 },
234 {"wmf_ucast_igmp", IOV_WMF_UCAST_IGMP, 0, IOVT_BOOL, 0 },
235 {"wmf_mcast_data_sendup", IOV_WMF_MCAST_DATA_SENDUP, 0, IOVT_BOOL, 0 },
236 #ifdef WL_IGMP_UCQUERY
237 {"wmf_ucast_igmp_query", IOV_WMF_UCAST_IGMP_QUERY, (0), IOVT_BOOL, 0 },
238 #endif /* WL_IGMP_UCQUERY */
239 #ifdef DHD_UCAST_UPNP
240 {"wmf_ucast_upnp", IOV_WMF_UCAST_UPNP, (0), IOVT_BOOL, 0 },
241 #endif /* DHD_UCAST_UPNP */
243 #ifdef DHD_UNICAST_DHCP
244 {"dhcp_unicast", IOV_DHCP_UNICAST, (0), IOVT_BOOL, 0 },
245 #endif /* DHD_UNICAST_DHCP */
246 {"ap_isolate", IOV_AP_ISOLATE, (0), IOVT_BOOL, 0},
248 {"block_ping", IOV_BLOCK_PING, (0), IOVT_BOOL, 0},
253 #define DHD_IOVAR_BUF_SIZE 128
255 /* to NDIS developer, the structure dhd_common is redundant,
256 * please do NOT merge it back from other branches !!!
260 dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen)
262 char eabuf[ETHER_ADDR_STR_LEN];
265 struct bcmstrbuf *strbuf = &b;
267 bcm_binit(strbuf, buf, buflen);
270 bcm_bprintf(strbuf, "%s\n", dhd_version);
271 bcm_bprintf(strbuf, "\n");
272 bcm_bprintf(strbuf, "pub.up %d pub.txoff %d pub.busstate %d\n",
273 dhdp->up, dhdp->txoff, dhdp->busstate);
274 bcm_bprintf(strbuf, "pub.hdrlen %u pub.maxctl %u pub.rxsz %u\n",
275 dhdp->hdrlen, dhdp->maxctl, dhdp->rxsz);
276 bcm_bprintf(strbuf, "pub.iswl %d pub.drv_version %ld pub.mac %s\n",
277 dhdp->iswl, dhdp->drv_version, bcm_ether_ntoa(&dhdp->mac, eabuf));
278 bcm_bprintf(strbuf, "pub.bcmerror %d tickcnt %u\n", dhdp->bcmerror, dhdp->tickcnt);
280 bcm_bprintf(strbuf, "dongle stats:\n");
281 bcm_bprintf(strbuf, "tx_packets %lu tx_bytes %lu tx_errors %lu tx_dropped %lu\n",
282 dhdp->dstats.tx_packets, dhdp->dstats.tx_bytes,
283 dhdp->dstats.tx_errors, dhdp->dstats.tx_dropped);
284 bcm_bprintf(strbuf, "rx_packets %lu rx_bytes %lu rx_errors %lu rx_dropped %lu\n",
285 dhdp->dstats.rx_packets, dhdp->dstats.rx_bytes,
286 dhdp->dstats.rx_errors, dhdp->dstats.rx_dropped);
287 bcm_bprintf(strbuf, "multicast %lu\n", dhdp->dstats.multicast);
289 bcm_bprintf(strbuf, "bus stats:\n");
290 bcm_bprintf(strbuf, "tx_packets %lu tx_dropped %lu tx_multicast %lu tx_errors %lu\n",
291 dhdp->tx_packets, dhdp->tx_dropped, dhdp->tx_multicast, dhdp->tx_errors);
292 bcm_bprintf(strbuf, "tx_ctlpkts %lu tx_ctlerrs %lu\n",
293 dhdp->tx_ctlpkts, dhdp->tx_ctlerrs);
294 bcm_bprintf(strbuf, "rx_packets %lu rx_multicast %lu rx_errors %lu \n",
295 dhdp->rx_packets, dhdp->rx_multicast, dhdp->rx_errors);
296 bcm_bprintf(strbuf, "rx_ctlpkts %lu rx_ctlerrs %lu rx_dropped %lu\n",
297 dhdp->rx_ctlpkts, dhdp->rx_ctlerrs, dhdp->rx_dropped);
298 bcm_bprintf(strbuf, "rx_readahead_cnt %lu tx_realloc %lu\n",
299 dhdp->rx_readahead_cnt, dhdp->tx_realloc);
300 bcm_bprintf(strbuf, "\n");
302 /* Add any prot info */
303 dhd_prot_dump(dhdp, strbuf);
304 bcm_bprintf(strbuf, "\n");
306 /* Add any bus info */
307 dhd_bus_dump(dhdp, strbuf);
310 return (!strbuf->size ? BCME_BUFTOOSHORT : 0);
314 dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, int ifidx)
323 return dhd_wl_ioctl(dhd_pub, ifidx, &ioc, arg, len);
327 dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifidx, wl_ioctl_t *ioc, void *buf, int len)
329 int ret = BCME_ERROR;
331 if (dhd_os_proto_block(dhd_pub))
333 #if defined(WL_WLC_SHIM)
334 wl_info_t *wl = dhd_pub_wlinfo(dhd_pub);
336 wl_io_pport_t io_pport;
337 io_pport.dhd_pub = dhd_pub;
338 io_pport.ifidx = ifidx;
340 ret = wl_shim_ioctl(wl->shim, ioc, &io_pport);
341 if (ret != BCME_OK) {
342 DHD_ERROR(("%s: wl_shim_ioctl(%d) ERR %d\n", __FUNCTION__, ioc->cmd, ret));
345 ret = dhd_prot_ioctl(dhd_pub, ifidx, ioc, buf, len);
346 #endif /* defined(WL_WLC_SHIM) */
348 if (ret && dhd_pub->up) {
349 /* Send hang event only if dhd_open() was success */
350 dhd_os_check_hang(dhd_pub, ifidx, ret);
353 if (ret == -ETIMEDOUT && !dhd_pub->up) {
354 DHD_ERROR(("%s: 'resumed on timeout' error is "
355 "occurred before the interface does not"
356 " bring up\n", __FUNCTION__));
357 dhd_pub->busstate = DHD_BUS_DOWN;
360 dhd_os_proto_unblock(dhd_pub);
367 uint wl_get_port_num(wl_io_pport_t *io_pport)
372 /* Get bssidx from iovar params
373 * Input: dhd_pub - pointer to dhd_pub_t
374 * params - IOVAR params
375 * Output: idx - BSS index
376 * val - ponter to the IOVAR arguments
379 dhd_iovar_parse_bssidx(dhd_pub_t *dhd_pub, char *params, int *idx, char **val)
381 char *prefix = "bsscfg:";
384 if (!(strncmp(params, prefix, strlen(prefix)))) {
385 /* per bss setting should be prefixed with 'bsscfg:' */
386 char *p = (char *)params + strlen(prefix);
393 bcopy(p, &bssidx, sizeof(uint32));
394 /* Get corresponding dhd index */
395 bssidx = dhd_bssidx2idx(dhd_pub, bssidx);
397 if (bssidx >= DHD_MAX_IFS) {
398 DHD_ERROR(("%s Wrong bssidx provided\n", __FUNCTION__));
407 DHD_ERROR(("%s: bad parameter for per bss iovar\n", __FUNCTION__));
415 dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const char *name,
416 void *params, int plen, void *arg, int len, int val_size)
421 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
422 DHD_TRACE(("%s: actionid = %d; name %s\n", __FUNCTION__, actionid, name));
424 if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0)
427 if (plen >= (int)sizeof(int_val))
428 bcopy(params, &int_val, sizeof(int_val));
431 case IOV_GVAL(IOV_VERSION):
432 /* Need to have checked buffer length */
433 bcm_strncpy_s((char*)arg, len, dhd_version, len);
436 case IOV_GVAL(IOV_WLMSGLEVEL):
437 printf("android_msg_level=0x%x\n", android_msg_level);
438 printf("config_msg_level=0x%x\n", config_msg_level);
439 #if defined(WL_WIRELESS_EXT)
440 int_val = (int32)iw_msg_level;
441 bcopy(&int_val, arg, val_size);
442 printf("iw_msg_level=0x%x\n", iw_msg_level);
445 int_val = (int32)wl_dbg_level;
446 bcopy(&int_val, arg, val_size);
447 printf("cfg_msg_level=0x%x\n", wl_dbg_level);
451 case IOV_SVAL(IOV_WLMSGLEVEL):
452 if (int_val & DHD_ANDROID_VAL) {
453 android_msg_level = (uint)(int_val & 0xFFFF);
454 printf("android_msg_level=0x%x\n", android_msg_level);
456 if (int_val & DHD_CONFIG_VAL) {
457 config_msg_level = (uint)(int_val & 0xFFFF);
458 printf("config_msg_level=0x%x\n", config_msg_level);
460 #if defined(WL_WIRELESS_EXT)
461 if (int_val & DHD_IW_VAL) {
462 iw_msg_level = (uint)(int_val & 0xFFFF);
463 printf("iw_msg_level=0x%x\n", iw_msg_level);
467 if (int_val & DHD_CFG_VAL) {
468 wl_cfg80211_enable_trace((u32)(int_val & 0xFFFF));
473 case IOV_GVAL(IOV_MSGLEVEL):
474 int_val = (int32)dhd_msg_level;
475 bcopy(&int_val, arg, val_size);
478 case IOV_SVAL(IOV_MSGLEVEL):
479 dhd_msg_level = int_val;
482 case IOV_GVAL(IOV_BCMERRORSTR):
483 bcm_strncpy_s((char *)arg, len, bcmerrorstr(dhd_pub->bcmerror), BCME_STRLEN);
484 ((char *)arg)[BCME_STRLEN - 1] = 0x00;
487 case IOV_GVAL(IOV_BCMERROR):
488 int_val = (int32)dhd_pub->bcmerror;
489 bcopy(&int_val, arg, val_size);
492 case IOV_GVAL(IOV_WDTICK):
493 int_val = (int32)dhd_watchdog_ms;
494 bcopy(&int_val, arg, val_size);
497 case IOV_SVAL(IOV_WDTICK):
499 bcmerror = BCME_NOTUP;
502 dhd_os_wd_timer(dhd_pub, (uint)int_val);
505 case IOV_GVAL(IOV_DUMP):
506 bcmerror = dhd_dump(dhd_pub, arg, len);
510 case IOV_GVAL(IOV_DCONSOLE_POLL):
511 int_val = (int32)dhd_console_ms;
512 bcopy(&int_val, arg, val_size);
515 case IOV_SVAL(IOV_DCONSOLE_POLL):
516 dhd_console_ms = (uint)int_val;
519 case IOV_SVAL(IOV_CONS):
521 bcmerror = dhd_bus_console_in(dhd_pub, arg, len - 1);
523 #endif /* DHD_DEBUG */
525 case IOV_SVAL(IOV_CLEARCOUNTS):
526 dhd_pub->tx_packets = dhd_pub->rx_packets = 0;
527 dhd_pub->tx_errors = dhd_pub->rx_errors = 0;
528 dhd_pub->tx_ctlpkts = dhd_pub->rx_ctlpkts = 0;
529 dhd_pub->tx_ctlerrs = dhd_pub->rx_ctlerrs = 0;
530 dhd_pub->tx_dropped = 0;
531 dhd_pub->rx_dropped = 0;
532 dhd_pub->rx_readahead_cnt = 0;
533 dhd_pub->tx_realloc = 0;
534 dhd_pub->wd_dpc_sched = 0;
535 memset(&dhd_pub->dstats, 0, sizeof(dhd_pub->dstats));
536 dhd_bus_clearcounts(dhd_pub);
538 /* clear proptxstatus related counters */
539 dhd_wlfc_clear_counts(dhd_pub);
540 #endif /* PROP_TXSTATUS */
544 case IOV_GVAL(IOV_IOCTLTIMEOUT): {
545 int_val = (int32)dhd_os_get_ioctl_resp_timeout();
546 bcopy(&int_val, arg, sizeof(int_val));
550 case IOV_SVAL(IOV_IOCTLTIMEOUT): {
552 bcmerror = BCME_BADARG;
554 dhd_os_set_ioctl_resp_timeout((unsigned int)int_val);
559 case IOV_SVAL(IOV_HCI_CMD): {
560 amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)arg;
562 /* sanity check: command preamble present */
563 if (len < HCI_CMD_PREAMBLE_SIZE)
564 return BCME_BUFTOOSHORT;
566 /* sanity check: command parameters are present */
567 if (len < (int)(HCI_CMD_PREAMBLE_SIZE + cmd->plen))
568 return BCME_BUFTOOSHORT;
570 dhd_bta_docmd(dhd_pub, cmd, len);
574 case IOV_SVAL(IOV_HCI_ACL_DATA): {
575 amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)arg;
577 /* sanity check: HCI header present */
578 if (len < HCI_ACL_DATA_PREAMBLE_SIZE)
579 return BCME_BUFTOOSHORT;
581 /* sanity check: ACL data is present */
582 if (len < (int)(HCI_ACL_DATA_PREAMBLE_SIZE + ACL_data->dlen))
583 return BCME_BUFTOOSHORT;
585 dhd_bta_tx_hcidata(dhd_pub, ACL_data, len);
591 case IOV_GVAL(IOV_PROPTXSTATUS_ENABLE): {
592 bool wlfc_enab = FALSE;
593 bcmerror = dhd_wlfc_get_enable(dhd_pub, &wlfc_enab);
594 if (bcmerror != BCME_OK)
596 int_val = wlfc_enab ? 1 : 0;
597 bcopy(&int_val, arg, val_size);
600 case IOV_SVAL(IOV_PROPTXSTATUS_ENABLE): {
601 bool wlfc_enab = FALSE;
602 bcmerror = dhd_wlfc_get_enable(dhd_pub, &wlfc_enab);
603 if (bcmerror != BCME_OK)
606 /* wlfc is already set as desired */
607 if (wlfc_enab == (int_val == 0 ? FALSE : TRUE))
611 bcmerror = dhd_wlfc_init(dhd_pub);
613 bcmerror = dhd_wlfc_deinit(dhd_pub);
617 case IOV_GVAL(IOV_PROPTXSTATUS_MODE):
618 bcmerror = dhd_wlfc_get_mode(dhd_pub, &int_val);
619 if (bcmerror != BCME_OK)
621 bcopy(&int_val, arg, val_size);
624 case IOV_SVAL(IOV_PROPTXSTATUS_MODE):
625 dhd_wlfc_set_mode(dhd_pub, int_val);
628 case IOV_GVAL(IOV_QMON_TIME_THRES): {
629 int_val = dhd_qmon_thres(dhd_pub, FALSE, 0);
630 bcopy(&int_val, arg, val_size);
634 case IOV_SVAL(IOV_QMON_TIME_THRES): {
635 dhd_qmon_thres(dhd_pub, TRUE, int_val);
639 case IOV_GVAL(IOV_QMON_TIME_PERCENT): {
640 int_val = dhd_qmon_getpercent(dhd_pub);
641 bcopy(&int_val, arg, val_size);
644 #endif /* QMONITOR */
646 case IOV_GVAL(IOV_PROPTXSTATUS_MODULE_IGNORE):
647 bcmerror = dhd_wlfc_get_module_ignore(dhd_pub, &int_val);
648 if (bcmerror != BCME_OK)
650 bcopy(&int_val, arg, val_size);
653 case IOV_SVAL(IOV_PROPTXSTATUS_MODULE_IGNORE):
654 dhd_wlfc_set_module_ignore(dhd_pub, int_val);
657 case IOV_GVAL(IOV_PROPTXSTATUS_CREDIT_IGNORE):
658 bcmerror = dhd_wlfc_get_credit_ignore(dhd_pub, &int_val);
659 if (bcmerror != BCME_OK)
661 bcopy(&int_val, arg, val_size);
664 case IOV_SVAL(IOV_PROPTXSTATUS_CREDIT_IGNORE):
665 dhd_wlfc_set_credit_ignore(dhd_pub, int_val);
668 case IOV_GVAL(IOV_PROPTXSTATUS_TXSTATUS_IGNORE):
669 bcmerror = dhd_wlfc_get_txstatus_ignore(dhd_pub, &int_val);
670 if (bcmerror != BCME_OK)
672 bcopy(&int_val, arg, val_size);
675 case IOV_SVAL(IOV_PROPTXSTATUS_TXSTATUS_IGNORE):
676 dhd_wlfc_set_txstatus_ignore(dhd_pub, int_val);
679 case IOV_GVAL(IOV_PROPTXSTATUS_RXPKT_CHK):
680 bcmerror = dhd_wlfc_get_rxpkt_chk(dhd_pub, &int_val);
681 if (bcmerror != BCME_OK)
683 bcopy(&int_val, arg, val_size);
686 case IOV_SVAL(IOV_PROPTXSTATUS_RXPKT_CHK):
687 dhd_wlfc_set_rxpkt_chk(dhd_pub, int_val);
690 #endif /* PROP_TXSTATUS */
692 case IOV_GVAL(IOV_BUS_TYPE):
693 /* The dhd application queries the driver to check if its usb or sdio. */
695 int_val = BUS_TYPE_USB;
698 int_val = BUS_TYPE_SDIO;
700 #ifdef PCIE_FULL_DONGLE
701 int_val = BUS_TYPE_PCIE;
703 bcopy(&int_val, arg, val_size);
708 case IOV_GVAL(IOV_WLPKTDLYSTAT_SZ):
709 int_val = dhd_pub->htsfdlystat_sz;
710 bcopy(&int_val, arg, val_size);
713 case IOV_SVAL(IOV_WLPKTDLYSTAT_SZ):
714 dhd_pub->htsfdlystat_sz = int_val & 0xff;
715 printf("Setting tsfdlystat_sz:%d\n", dhd_pub->htsfdlystat_sz);
718 case IOV_SVAL(IOV_CHANGEMTU):
720 bcmerror = dhd_change_mtu(dhd_pub, int_val, 0);
723 case IOV_GVAL(IOV_HOSTREORDER_FLOWS):
726 uint8 *ptr = (uint8 *)arg;
730 for (i = 0; i < WLHOST_REORDERDATA_MAXFLOWS; i++) {
731 if (dhd_pub->reorder_bufs[i] != NULL) {
732 *ptr = dhd_pub->reorder_bufs[i]->flow_id;
741 #ifdef DHDTCPACK_SUPPRESS
742 case IOV_GVAL(IOV_TCPACK_SUPPRESS): {
743 int_val = (uint32)dhd_pub->tcpack_sup_mode;
744 bcopy(&int_val, arg, val_size);
747 case IOV_SVAL(IOV_TCPACK_SUPPRESS): {
748 bcmerror = dhd_tcpack_suppress_set(dhd_pub, (uint8)int_val);
751 #endif /* DHDTCPACK_SUPPRESS */
753 case IOV_GVAL(IOV_WMF_BSS_ENAB): {
758 if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) != BCME_OK) {
759 DHD_ERROR(("%s: wmf_bss_enable: bad parameter\n", __FUNCTION__));
760 bcmerror = BCME_BADARG;
764 wmf = dhd_wmf_conf(dhd_pub, bssidx);
765 int_val = wmf->wmf_enable ? 1 :0;
766 bcopy(&int_val, arg, val_size);
769 case IOV_SVAL(IOV_WMF_BSS_ENAB): {
770 /* Enable/Disable WMF */
775 if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) != BCME_OK) {
776 DHD_ERROR(("%s: wmf_bss_enable: bad parameter\n", __FUNCTION__));
777 bcmerror = BCME_BADARG;
782 bcopy(val, &int_val, sizeof(uint32));
783 wmf = dhd_wmf_conf(dhd_pub, bssidx);
784 if (wmf->wmf_enable == int_val)
788 if (dhd_wmf_instance_add(dhd_pub, bssidx) != BCME_OK) {
789 DHD_ERROR(("%s: Error in creating WMF instance\n",
793 if (dhd_wmf_start(dhd_pub, bssidx) != BCME_OK) {
794 DHD_ERROR(("%s: Failed to start WMF\n", __FUNCTION__));
797 wmf->wmf_enable = TRUE;
800 wmf->wmf_enable = FALSE;
801 dhd_wmf_stop(dhd_pub, bssidx);
802 dhd_wmf_instance_del(dhd_pub, bssidx);
806 case IOV_GVAL(IOV_WMF_UCAST_IGMP):
807 int_val = dhd_pub->wmf_ucast_igmp ? 1 : 0;
808 bcopy(&int_val, arg, val_size);
810 case IOV_SVAL(IOV_WMF_UCAST_IGMP):
811 if (dhd_pub->wmf_ucast_igmp == int_val)
814 if (int_val >= OFF && int_val <= ON)
815 dhd_pub->wmf_ucast_igmp = int_val;
817 bcmerror = BCME_RANGE;
819 case IOV_GVAL(IOV_WMF_MCAST_DATA_SENDUP):
820 int_val = dhd_wmf_mcast_data_sendup(dhd_pub, 0, FALSE, FALSE);
821 bcopy(&int_val, arg, val_size);
823 case IOV_SVAL(IOV_WMF_MCAST_DATA_SENDUP):
824 dhd_wmf_mcast_data_sendup(dhd_pub, 0, TRUE, int_val);
827 #ifdef WL_IGMP_UCQUERY
828 case IOV_GVAL(IOV_WMF_UCAST_IGMP_QUERY):
829 int_val = dhd_pub->wmf_ucast_igmp_query ? 1 : 0;
830 bcopy(&int_val, arg, val_size);
832 case IOV_SVAL(IOV_WMF_UCAST_IGMP_QUERY):
833 if (dhd_pub->wmf_ucast_igmp_query == int_val)
836 if (int_val >= OFF && int_val <= ON)
837 dhd_pub->wmf_ucast_igmp_query = int_val;
839 bcmerror = BCME_RANGE;
841 #endif /* WL_IGMP_UCQUERY */
842 #ifdef DHD_UCAST_UPNP
843 case IOV_GVAL(IOV_WMF_UCAST_UPNP):
844 int_val = dhd_pub->wmf_ucast_upnp ? 1 : 0;
845 bcopy(&int_val, arg, val_size);
847 case IOV_SVAL(IOV_WMF_UCAST_UPNP):
848 if (dhd_pub->wmf_ucast_upnp == int_val)
851 if (int_val >= OFF && int_val <= ON)
852 dhd_pub->wmf_ucast_upnp = int_val;
854 bcmerror = BCME_RANGE;
856 #endif /* DHD_UCAST_UPNP */
860 #ifdef DHD_UNICAST_DHCP
861 case IOV_GVAL(IOV_DHCP_UNICAST):
862 int_val = dhd_pub->dhcp_unicast;
863 bcopy(&int_val, arg, val_size);
865 case IOV_SVAL(IOV_DHCP_UNICAST):
866 if (dhd_pub->dhcp_unicast == int_val)
869 if (int_val >= OFF || int_val <= ON) {
870 dhd_pub->dhcp_unicast = int_val;
872 bcmerror = BCME_RANGE;
875 #endif /* DHD_UNICAST_DHCP */
877 case IOV_GVAL(IOV_BLOCK_PING):
878 int_val = dhd_pub->block_ping;
879 bcopy(&int_val, arg, val_size);
881 case IOV_SVAL(IOV_BLOCK_PING):
882 if (dhd_pub->block_ping == int_val)
884 if (int_val >= OFF || int_val <= ON) {
885 dhd_pub->block_ping = int_val;
887 bcmerror = BCME_RANGE;
892 case IOV_GVAL(IOV_AP_ISOLATE): {
896 if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) != BCME_OK) {
897 DHD_ERROR(("%s: ap isoalate: bad parameter\n", __FUNCTION__));
898 bcmerror = BCME_BADARG;
902 int_val = dhd_get_ap_isolate(dhd_pub, bssidx);
903 bcopy(&int_val, arg, val_size);
906 case IOV_SVAL(IOV_AP_ISOLATE): {
910 if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) != BCME_OK) {
911 DHD_ERROR(("%s: ap isolate: bad parameter\n", __FUNCTION__));
912 bcmerror = BCME_BADARG;
917 bcopy(val, &int_val, sizeof(uint32));
918 dhd_set_ap_isolate(dhd_pub, bssidx, int_val);
923 bcmerror = BCME_UNSUPPORTED;
928 DHD_TRACE(("%s: actionid %d, bcmerror %d\n", __FUNCTION__, actionid, bcmerror));
932 /* Store the status of a connection attempt for later retrieval by an iovar */
934 dhd_store_conn_status(uint32 event, uint32 status, uint32 reason)
936 /* Do not overwrite a WLC_E_PRUNE with a WLC_E_SET_SSID
937 * because an encryption/rsn mismatch results in both events, and
938 * the important information is in the WLC_E_PRUNE.
940 if (!(event == WLC_E_SET_SSID && status == WLC_E_STATUS_FAIL &&
941 dhd_conn_event == WLC_E_PRUNE)) {
942 dhd_conn_event = event;
943 dhd_conn_status = status;
944 dhd_conn_reason = reason;
949 dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec)
952 int eprec = -1; /* precedence to evict from */
955 /* Fast case, precedence queue is not full and we are also not
956 * exceeding total queue length
958 if (!pktq_pfull(q, prec) && !pktq_full(q)) {
959 pktq_penq(q, prec, pkt);
963 /* Determine precedence from which to evict packet, if any */
964 if (pktq_pfull(q, prec))
966 else if (pktq_full(q)) {
967 p = pktq_peek_tail(q, &eprec);
969 if (eprec > prec || eprec < 0)
973 /* Evict if needed */
975 /* Detect queueing to unconfigured precedence */
976 ASSERT(!pktq_pempty(q, eprec));
977 discard_oldest = AC_BITMAP_TST(dhdp->wme_dp, eprec);
978 if (eprec == prec && !discard_oldest)
979 return FALSE; /* refuse newer (incoming) packet */
980 /* Evict packet according to discard policy */
981 p = discard_oldest ? pktq_pdeq(q, eprec) : pktq_pdeq_tail(q, eprec);
983 #ifdef DHDTCPACK_SUPPRESS
984 if (dhd_tcpack_check_xmit(dhdp, p) == BCME_ERROR) {
985 DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using it\n",
986 __FUNCTION__, __LINE__));
987 dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_OFF);
989 #endif /* DHDTCPACK_SUPPRESS */
990 PKTFREE(dhdp->osh, p, TRUE);
994 p = pktq_penq(q, prec, pkt);
1001 * Functions to drop proper pkts from queue:
1002 * If one pkt in queue is non-fragmented, drop first non-fragmented pkt only
1003 * If all pkts in queue are all fragmented, find and drop one whole set fragmented pkts
1004 * If can't find pkts matching upper 2 cases, drop first pkt anyway
1007 dhd_prec_drop_pkts(dhd_pub_t *dhdp, struct pktq *pq, int prec, f_droppkt_t fn)
1009 struct pktq_prec *q = NULL;
1010 void *p, *prev = NULL, *next = NULL, *first = NULL, *last = NULL, *prev_first = NULL;
1011 pkt_frag_t frag_info;
1014 ASSERT(prec >= 0 && prec < pq->num_prec);
1023 frag_info = pkt_frag_info(dhdp->osh, p);
1024 if (frag_info == DHD_PKT_FRAG_NONE) {
1026 } else if (frag_info == DHD_PKT_FRAG_FIRST) {
1028 /* No last frag pkt, use prev as last */
1035 } else if (frag_info == DHD_PKT_FRAG_LAST) {
1046 if ((p == NULL) || ((frag_info != DHD_PKT_FRAG_NONE) && !(first && last))) {
1047 /* Not found matching pkts, use oldest */
1053 if (frag_info == DHD_PKT_FRAG_NONE) {
1064 PKTSETLINK(p, NULL);
1067 fn(dhdp, prec, p, TRUE);
1075 if (prev_first == NULL) {
1076 if ((q->head = next) == NULL)
1079 PKTSETLINK(prev_first, next);
1081 q->tail = prev_first;
1088 dhd_iovar_op(dhd_pub_t *dhd_pub, const char *name,
1089 void *params, int plen, void *arg, int len, bool set)
1093 const bcm_iovar_t *vi = NULL;
1096 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1101 /* Get MUST have return space */
1102 ASSERT(set || (arg && len));
1104 /* Set does NOT take qualifiers */
1105 ASSERT(!set || (!params && !plen));
1107 if ((vi = bcm_iovar_lookup(dhd_iovars, name)) == NULL) {
1108 bcmerror = BCME_UNSUPPORTED;
1112 DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__,
1113 name, (set ? "set" : "get"), len, plen));
1115 /* set up 'params' pointer in case this is a set command so that
1116 * the convenience int and bool code can be common to set and get
1118 if (params == NULL) {
1123 if (vi->type == IOVT_VOID)
1125 else if (vi->type == IOVT_BUFFER)
1128 /* all other types are integer sized */
1129 val_size = sizeof(int);
1131 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
1133 bcmerror = dhd_doiovar(dhd_pub, vi, actionid, name, params, plen, arg, len, val_size);
1140 dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen)
1144 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1152 if (buflen < sizeof(int))
1153 bcmerror = BCME_BUFTOOSHORT;
1155 *(int*)buf = DHD_IOCTL_MAGIC;
1158 case DHD_GET_VERSION:
1159 if (buflen < sizeof(int))
1160 bcmerror = BCME_BUFTOOSHORT;
1162 *(int*)buf = DHD_IOCTL_VERSION;
1170 /* scan past the name to any arguments */
1171 for (arg = buf, arglen = buflen; *arg && arglen; arg++, arglen--)
1175 bcmerror = BCME_BUFTOOSHORT;
1179 /* account for the NUL terminator */
1182 /* call with the appropriate arguments */
1183 if (ioc->cmd == DHD_GET_VAR)
1184 bcmerror = dhd_iovar_op(dhd_pub, buf, arg, arglen,
1185 buf, buflen, IOV_GET);
1187 bcmerror = dhd_iovar_op(dhd_pub, buf, NULL, 0, arg, arglen, IOV_SET);
1188 if (bcmerror != BCME_UNSUPPORTED)
1191 /* not in generic table, try protocol module */
1192 if (ioc->cmd == DHD_GET_VAR)
1193 bcmerror = dhd_prot_iovar_op(dhd_pub, buf, arg,
1194 arglen, buf, buflen, IOV_GET);
1196 bcmerror = dhd_prot_iovar_op(dhd_pub, buf,
1197 NULL, 0, arg, arglen, IOV_SET);
1198 if (bcmerror != BCME_UNSUPPORTED)
1201 /* if still not found, try bus module */
1202 if (ioc->cmd == DHD_GET_VAR) {
1203 bcmerror = dhd_bus_iovar_op(dhd_pub, buf,
1204 arg, arglen, buf, buflen, IOV_GET);
1206 bcmerror = dhd_bus_iovar_op(dhd_pub, buf,
1207 NULL, 0, arg, arglen, IOV_SET);
1214 bcmerror = BCME_UNSUPPORTED;
1221 #ifdef SHOW_LOGTRACE
1223 #define AVOID_BYTE 64
1224 #define MAX_NO_OF_ARG 16
1227 check_event_log_sequence_number(uint32 seq_no)
1231 static uint32 logtrace_seqnum_prev = 0;
1233 diff = ntoh32(seq_no)-logtrace_seqnum_prev;
1237 ret = -1; /* duplicate packet . drop */
1241 ret =0; /* in order */
1245 if ((ntoh32(seq_no) == 0) &&
1246 (logtrace_seqnum_prev == 0xFFFFFFFF) ) { /* in-order - Roll over */
1251 DHD_EVENT(("WLC_E_TRACE:"
1252 "Event lost (log) seqnum %d nblost %d\n",
1253 ntoh32(seq_no), (diff-1)));
1255 DHD_EVENT(("WLC_E_TRACE:"
1256 "Event Packets coming out of order!!\n"));
1262 logtrace_seqnum_prev = ntoh32(seq_no);
1266 #endif /* SHOW_LOGTRACE */
1269 wl_show_host_event(dhd_pub_t *dhd_pub, wl_event_msg_t *event, void *event_data,
1270 void *raw_event_ptr, char *eventmask)
1272 uint i, status, reason;
1273 bool group = FALSE, flush_txq = FALSE, link = FALSE;
1274 const char *auth_str;
1275 const char *event_name;
1277 char err_msg[256], eabuf[ETHER_ADDR_STR_LEN];
1278 uint event_type, flags, auth_type, datalen;
1280 event_type = ntoh32(event->event_type);
1281 flags = ntoh16(event->flags);
1282 status = ntoh32(event->status);
1283 reason = ntoh32(event->reason);
1284 BCM_REFERENCE(reason);
1285 auth_type = ntoh32(event->auth_type);
1286 datalen = ntoh32(event->datalen);
1288 /* debug dump of event messages */
1289 snprintf(eabuf, sizeof(eabuf), "%02x:%02x:%02x:%02x:%02x:%02x",
1290 (uchar)event->addr.octet[0]&0xff,
1291 (uchar)event->addr.octet[1]&0xff,
1292 (uchar)event->addr.octet[2]&0xff,
1293 (uchar)event->addr.octet[3]&0xff,
1294 (uchar)event->addr.octet[4]&0xff,
1295 (uchar)event->addr.octet[5]&0xff);
1297 event_name = bcmevent_get_name(event_type);
1298 BCM_REFERENCE(event_name);
1300 if (flags & WLC_EVENT_MSG_LINK)
1302 if (flags & WLC_EVENT_MSG_GROUP)
1304 if (flags & WLC_EVENT_MSG_FLUSHTXQ)
1307 switch (event_type) {
1310 case WLC_E_DISASSOC:
1311 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
1314 case WLC_E_ASSOC_IND:
1315 case WLC_E_REASSOC_IND:
1317 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
1322 if (status == WLC_E_STATUS_SUCCESS) {
1323 DHD_EVENT(("MACEVENT: %s, MAC %s, SUCCESS\n", event_name, eabuf));
1324 } else if (status == WLC_E_STATUS_TIMEOUT) {
1325 DHD_EVENT(("MACEVENT: %s, MAC %s, TIMEOUT\n", event_name, eabuf));
1326 } else if (status == WLC_E_STATUS_FAIL) {
1327 DHD_EVENT(("MACEVENT: %s, MAC %s, FAILURE, reason %d\n",
1328 event_name, eabuf, (int)reason));
1330 DHD_EVENT(("MACEVENT: %s, MAC %s, unexpected status %d\n",
1331 event_name, eabuf, (int)status));
1335 case WLC_E_DEAUTH_IND:
1336 case WLC_E_DISASSOC_IND:
1337 DHD_EVENT(("MACEVENT: %s, MAC %s, reason %d\n", event_name, eabuf, (int)reason));
1341 case WLC_E_AUTH_IND:
1342 if (auth_type == DOT11_OPEN_SYSTEM)
1343 auth_str = "Open System";
1344 else if (auth_type == DOT11_SHARED_KEY)
1345 auth_str = "Shared Key";
1347 snprintf(err_msg, sizeof(err_msg), "AUTH unknown: %d", (int)auth_type);
1350 if (event_type == WLC_E_AUTH_IND) {
1351 DHD_EVENT(("MACEVENT: %s, MAC %s, %s\n", event_name, eabuf, auth_str));
1352 } else if (status == WLC_E_STATUS_SUCCESS) {
1353 DHD_EVENT(("MACEVENT: %s, MAC %s, %s, SUCCESS\n",
1354 event_name, eabuf, auth_str));
1355 } else if (status == WLC_E_STATUS_TIMEOUT) {
1356 DHD_EVENT(("MACEVENT: %s, MAC %s, %s, TIMEOUT\n",
1357 event_name, eabuf, auth_str));
1358 } else if (status == WLC_E_STATUS_FAIL) {
1359 DHD_EVENT(("MACEVENT: %s, MAC %s, %s, FAILURE, reason %d\n",
1360 event_name, eabuf, auth_str, (int)reason));
1362 BCM_REFERENCE(auth_str);
1368 case WLC_E_SET_SSID:
1369 if (status == WLC_E_STATUS_SUCCESS) {
1370 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
1371 } else if (status == WLC_E_STATUS_FAIL) {
1372 DHD_EVENT(("MACEVENT: %s, failed\n", event_name));
1373 } else if (status == WLC_E_STATUS_NO_NETWORKS) {
1374 DHD_EVENT(("MACEVENT: %s, no networks found\n", event_name));
1376 DHD_EVENT(("MACEVENT: %s, unexpected status %d\n",
1377 event_name, (int)status));
1381 case WLC_E_BEACON_RX:
1382 if (status == WLC_E_STATUS_SUCCESS) {
1383 DHD_EVENT(("MACEVENT: %s, SUCCESS\n", event_name));
1384 } else if (status == WLC_E_STATUS_FAIL) {
1385 DHD_EVENT(("MACEVENT: %s, FAIL\n", event_name));
1387 DHD_EVENT(("MACEVENT: %s, status %d\n", event_name, status));
1392 DHD_EVENT(("MACEVENT: %s %s\n", event_name, link?"UP":"DOWN"));
1393 BCM_REFERENCE(link);
1396 case WLC_E_MIC_ERROR:
1397 DHD_EVENT(("MACEVENT: %s, MAC %s, Group %d, Flush %d\n",
1398 event_name, eabuf, group, flush_txq));
1399 BCM_REFERENCE(group);
1400 BCM_REFERENCE(flush_txq);
1403 case WLC_E_ICV_ERROR:
1404 case WLC_E_UNICAST_DECODE_ERROR:
1405 case WLC_E_MULTICAST_DECODE_ERROR:
1406 DHD_EVENT(("MACEVENT: %s, MAC %s\n",
1407 event_name, eabuf));
1411 DHD_EVENT(("MACEVENT: %s, RA %s\n", event_name, eabuf));
1414 case WLC_E_SCAN_COMPLETE:
1415 case WLC_E_ASSOC_REQ_IE:
1416 case WLC_E_ASSOC_RESP_IE:
1417 case WLC_E_PMKID_CACHE:
1418 DHD_EVENT(("MACEVENT: %s\n", event_name));
1421 case WLC_E_PFN_NET_FOUND:
1422 case WLC_E_PFN_NET_LOST:
1423 case WLC_E_PFN_SCAN_COMPLETE:
1424 case WLC_E_PFN_SCAN_NONE:
1425 case WLC_E_PFN_SCAN_ALLGONE:
1426 DHD_EVENT(("PNOEVENT: %s\n", event_name));
1431 DHD_EVENT(("MACEVENT: %s, status %d, reason %d\n",
1432 event_name, (int)status, (int)reason));
1435 #ifdef WIFI_ACT_FRAME
1436 case WLC_E_ACTION_FRAME:
1437 DHD_TRACE(("MACEVENT: %s Bssid %s\n", event_name, eabuf));
1439 #endif /* WIFI_ACT_FRAME */
1441 #ifdef SHOW_LOGTRACE
1448 static uint32 seqnum_prev = 0;
1449 uint32 *record = NULL;
1450 uint32 *log_ptr = NULL;
1451 uint32 writeindex = 0;
1452 event_log_hdr_t event_hdr;
1455 dhd_event_log_t *raw_event = (dhd_event_log_t *) raw_event_ptr;
1457 buf = (uchar *) event_data;
1458 memcpy(&hdr, buf, MSGTRACE_HDRLEN);
1460 if (hdr.version != MSGTRACE_VERSION) {
1461 DHD_EVENT(("\nMACEVENT: %s [unsupported version --> "
1462 "dhd version:%d dongle version:%d]\n",
1463 event_name, MSGTRACE_VERSION, hdr.version));
1464 /* Reset datalen to avoid display below */
1469 if (hdr.trace_type == MSGTRACE_HDR_TYPE_MSG) {
1470 /* There are 2 bytes available at the end of data */
1471 buf[MSGTRACE_HDRLEN + ntoh16(hdr.len)] = '\0';
1473 if (ntoh32(hdr.discarded_bytes) || ntoh32(hdr.discarded_printf)) {
1474 DHD_EVENT(("WLC_E_TRACE: [Discarded traces in dongle -->"
1475 "discarded_bytes %d discarded_printf %d]\n",
1476 ntoh32(hdr.discarded_bytes),
1477 ntoh32(hdr.discarded_printf)));
1480 nblost = ntoh32(hdr.seqnum) - seqnum_prev - 1;
1482 DHD_EVENT(("WLC_E_TRACE:"
1483 "[Event lost (msg) --> seqnum %d nblost %d\n",
1484 ntoh32(hdr.seqnum), nblost));
1486 seqnum_prev = ntoh32(hdr.seqnum);
1488 /* Display the trace buffer. Advance from
1489 * \n to \n to avoid display big
1490 * printf (issue with Linux printk )
1492 p = (char *)&buf[MSGTRACE_HDRLEN];
1493 while (*p != '\0' && (s = strstr(p, "\n")) != NULL) {
1495 DHD_EVENT(("%s\n", p));
1499 DHD_EVENT(("%s", p));
1501 /* Reset datalen to avoid display below */
1504 } else if (hdr.trace_type == MSGTRACE_HDR_TYPE_LOG) {
1505 /* Let the standard event printing work for now */
1506 uint32 timestamp, w, malloc_len;
1508 if (check_event_log_sequence_number(hdr.seqnum)) {
1510 DHD_EVENT(("%s: WLC_E_TRACE:"
1511 "[Event duplicate (log) %d] dropping!!\n",
1512 __FUNCTION__, hdr.seqnum));
1513 return; /* drop duplicate events */
1516 p = (char *)&buf[MSGTRACE_HDRLEN];
1517 datalen -= MSGTRACE_HDRLEN;
1518 w = ntoh32((uint32)*p);
1521 timestamp = ntoh32((uint32)*p);
1522 BCM_REFERENCE(timestamp);
1525 DHD_EVENT(("timestamp %x%x\n", timestamp, w));
1527 if (raw_event->fmts) {
1528 malloc_len = datalen+ AVOID_BYTE;
1529 record = (uint32 *)MALLOC(dhd_pub->osh, malloc_len);
1530 if (record == NULL) {
1531 DHD_EVENT(("MSGTRACE_HDR_TYPE_LOG:"
1532 "malloc failed\n"));
1535 log_ptr = (uint32 *) (p + datalen);
1536 writeindex = datalen/4;
1539 while (datalen > 4) {
1542 event_hdr.t = *log_ptr;
1544 * Check for partially overriten entries
1546 if (log_ptr - (uint32 *) p < event_hdr.count) {
1550 * Check for end of the Frame.
1552 if (event_hdr.tag == EVENT_LOG_TAG_NULL) {
1556 * Check For Special Time Stamp Packet
1558 if (event_hdr.tag == EVENT_LOG_TAG_TS) {
1560 log_ptr = log_ptr - 3;
1564 log_ptr[0] = event_hdr.t;
1565 if (event_hdr.count > MAX_NO_OF_ARG) {
1568 /* Now place the header at the front
1571 log_ptr -= event_hdr.count;
1573 writeindex = writeindex - event_hdr.count;
1574 record[writeindex++] = event_hdr.t;
1575 for (count = 0; count < (event_hdr.count-1);
1577 record[writeindex++] = log_ptr[count];
1579 writeindex = writeindex - event_hdr.count;
1580 datalen = datalen - (event_hdr.count * 4);
1585 while (no_of_fmts--)
1587 event_log_hdr_t event_hdr;
1588 event_hdr.t = record[writeindex];
1590 if ((event_hdr.fmt_num>>2) < raw_event->num_fmts) {
1591 fmt = raw_event->fmts[event_hdr.fmt_num>>2];
1593 record[writeindex + 1],
1594 record[writeindex + 2],
1595 record[writeindex + 3],
1596 record[writeindex + 4],
1597 record[writeindex + 5],
1598 record[writeindex + 6],
1599 record[writeindex + 7],
1600 record[writeindex + 8],
1601 record[writeindex + 9],
1602 record[writeindex + 10],
1603 record[writeindex + 11],
1604 record[writeindex + 12],
1605 record[writeindex + 13],
1606 record[writeindex + 14],
1607 record[writeindex + 15],
1608 record[writeindex + 16]));
1610 if (fmt[strlen(fmt) - 1] != '\n') {
1611 /* Add newline if missing */
1616 writeindex = writeindex + event_hdr.count;
1620 MFREE(dhd_pub->osh, record, malloc_len);
1624 while (datalen > 4) {
1627 /* Print each word. DO NOT ntoh it. */
1628 DHD_EVENT((" %8.8x", *((uint32 *) p)));
1636 #endif /* SHOW_LOGTRACE */
1639 DHD_EVENT(("MACEVENT: %s %d\n", event_name, ntoh32(*((int *)event_data))));
1642 case WLC_E_SERVICE_FOUND:
1643 case WLC_E_P2PO_ADD_DEVICE:
1644 case WLC_E_P2PO_DEL_DEVICE:
1645 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
1648 #ifdef BT_WIFI_HANDOBER
1649 case WLC_E_BT_WIFI_HANDOVER_REQ:
1650 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
1655 DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, auth %d\n",
1656 event_name, event_type, eabuf, (int)status, (int)reason,
1661 /* show any appended data */
1662 if (DHD_BYTES_ON() && DHD_EVENT_ON() && datalen) {
1663 buf = (uchar *) event_data;
1665 DHD_EVENT((" data (%d) : ", datalen));
1666 for (i = 0; i < datalen; i++)
1667 DHD_EVENT((" 0x%02x ", *buf++));
1671 #endif /* SHOW_EVENTS */
1674 wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata,
1675 wl_event_msg_t *event, void **data_ptr, void *raw_event)
1677 /* check whether packet is a BRCM event pkt */
1678 bcm_event_t *pvt_data = (bcm_event_t *)pktdata;
1680 uint32 type, status, datalen;
1685 if (bcmp(BRCM_OUI, &pvt_data->bcm_hdr.oui[0], DOT11_OUI_LEN)) {
1686 DHD_ERROR(("%s: mismatched OUI, bailing\n", __FUNCTION__));
1687 return (BCME_ERROR);
1690 /* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */
1691 if (ntoh16_ua((void *)&pvt_data->bcm_hdr.usr_subtype) != BCMILCP_BCM_SUBTYPE_EVENT) {
1692 DHD_ERROR(("%s: mismatched subtype, bailing\n", __FUNCTION__));
1693 return (BCME_ERROR);
1696 *data_ptr = &pvt_data[1];
1697 event_data = *data_ptr;
1700 /* memcpy since BRCM event pkt may be unaligned. */
1701 memcpy(event, &pvt_data->event, sizeof(wl_event_msg_t));
1703 type = ntoh32_ua((void *)&event->event_type);
1704 flags = ntoh16_ua((void *)&event->flags);
1705 status = ntoh32_ua((void *)&event->status);
1706 datalen = ntoh32_ua((void *)&event->datalen);
1707 evlen = datalen + sizeof(bcm_event_t);
1709 /* find equivalent host index for event ifidx */
1710 hostidx = dhd_ifidx2hostidx(dhd_pub->info, event->ifidx);
1713 #ifdef PROP_TXSTATUS
1714 case WLC_E_FIFO_CREDIT_MAP:
1715 dhd_wlfc_enable(dhd_pub);
1716 dhd_wlfc_FIFOcreditmap_event(dhd_pub, event_data);
1717 WLFC_DBGMESG(("WLC_E_FIFO_CREDIT_MAP:(AC0,AC1,AC2,AC3),(BC_MC),(OTHER): "
1718 "(%d,%d,%d,%d),(%d),(%d)\n", event_data[0], event_data[1],
1720 event_data[3], event_data[4], event_data[5]));
1723 case WLC_E_BCMC_CREDIT_SUPPORT:
1724 dhd_wlfc_BCMCCredit_support_event(dhd_pub);
1730 struct wl_event_data_if *ifevent = (struct wl_event_data_if *)event_data;
1732 /* Ignore the event if NOIF is set */
1733 if (ifevent->reserved & WLC_E_IF_FLAGS_BSSCFG_NOIF) {
1734 DHD_ERROR(("WLC_E_IF: NO_IF set, event Ignored\r\n"));
1735 return (BCME_UNSUPPORTED);
1737 #ifdef PCIE_FULL_DONGLE
1738 dhd_update_interface_flow_info(dhd_pub, ifevent->ifidx,
1739 ifevent->opcode, ifevent->role);
1741 #ifdef PROP_TXSTATUS
1743 uint8* ea = pvt_data->eth.ether_dhost;
1744 WLFC_DBGMESG(("WLC_E_IF: idx:%d, action:%s, iftype:%s, "
1745 "[%02x:%02x:%02x:%02x:%02x:%02x]\n",
1747 ((ifevent->opcode == WLC_E_IF_ADD) ? "ADD":"DEL"),
1748 ((ifevent->role == 0) ? "STA":"AP "),
1749 ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]));
1752 if (ifevent->opcode == WLC_E_IF_CHANGE)
1753 dhd_wlfc_interface_event(dhd_pub,
1754 eWLFC_MAC_ENTRY_ACTION_UPDATE,
1755 ifevent->ifidx, ifevent->role, ea);
1757 dhd_wlfc_interface_event(dhd_pub,
1758 ((ifevent->opcode == WLC_E_IF_ADD) ?
1759 eWLFC_MAC_ENTRY_ACTION_ADD : eWLFC_MAC_ENTRY_ACTION_DEL),
1760 ifevent->ifidx, ifevent->role, ea);
1762 /* dhd already has created an interface by default, for 0 */
1763 if (ifevent->ifidx == 0)
1766 #endif /* PROP_TXSTATUS */
1768 if (ifevent->ifidx > 0 && ifevent->ifidx < DHD_MAX_IFS) {
1769 if (ifevent->opcode == WLC_E_IF_ADD) {
1770 if (dhd_event_ifadd(dhd_pub->info, ifevent, event->ifname,
1771 event->addr.octet)) {
1773 DHD_ERROR(("%s: dhd_event_ifadd failed ifidx: %d %s\n",
1774 __FUNCTION__, ifevent->ifidx, event->ifname));
1775 return (BCME_ERROR);
1777 } else if (ifevent->opcode == WLC_E_IF_DEL) {
1778 dhd_event_ifdel(dhd_pub->info, ifevent, event->ifname,
1780 } else if (ifevent->opcode == WLC_E_IF_CHANGE) {
1782 wl_cfg80211_notify_ifchange(ifevent->ifidx,
1783 event->ifname, event->addr.octet, ifevent->bssidx);
1784 #endif /* WL_CFG80211 */
1787 #if !defined(PROP_TXSTATUS) || !defined(PCIE_FULL_DONGLE)
1788 DHD_ERROR(("%s: Invalid ifidx %d for %s\n",
1789 __FUNCTION__, ifevent->ifidx, event->ifname));
1790 #endif /* !PROP_TXSTATUS */
1792 /* send up the if event: btamp user needs it */
1794 /* push up to external supp/auth */
1795 dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx);
1800 case WLC_E_HTSFSYNC:
1801 htsf_update(dhd_pub->info, event_data);
1803 #endif /* WLMEDIA_HTSF */
1804 #if defined(NDISVER) && (NDISVER >= 0x0630)
1805 case WLC_E_NDIS_LINK:
1808 case WLC_E_NDIS_LINK: {
1809 uint32 temp = hton32(WLC_E_LINK);
1811 memcpy((void *)(&pvt_data->event.event_type), &temp,
1812 sizeof(pvt_data->event.event_type));
1815 #endif /* NDISVER >= 0x0630 */
1816 case WLC_E_PFN_NET_FOUND:
1817 case WLC_E_PFN_NET_LOST:
1819 #if defined(PNO_SUPPORT)
1820 case WLC_E_PFN_BSSID_NET_FOUND:
1821 case WLC_E_PFN_BSSID_NET_LOST:
1822 case WLC_E_PFN_BEST_BATCHING:
1823 dhd_pno_event_handler(dhd_pub, event, (void *)event_data);
1826 /* These are what external supplicant/authenticator wants */
1827 case WLC_E_ASSOC_IND:
1828 case WLC_E_AUTH_IND:
1829 case WLC_E_REASSOC_IND:
1830 dhd_findadd_sta(dhd_pub, hostidx, &event->addr.octet);
1833 #ifdef PCIE_FULL_DONGLE
1834 if (dhd_update_interface_link_status(dhd_pub, (uint8)hostidx,
1835 (uint8)flags) != BCME_OK)
1838 dhd_flow_rings_delete(dhd_pub, hostidx);
1843 case WLC_E_DEAUTH_IND:
1844 case WLC_E_DISASSOC:
1845 case WLC_E_DISASSOC_IND:
1846 if (type != WLC_E_LINK) {
1847 dhd_del_sta(dhd_pub, hostidx, &event->addr.octet);
1849 DHD_EVENT(("%s: Link event %d, flags %x, status %x\n",
1850 __FUNCTION__, type, flags, status));
1851 #ifdef PCIE_FULL_DONGLE
1852 if (type != WLC_E_LINK) {
1853 uint8 ifindex = (uint8)hostidx;
1854 uint8 role = dhd_flow_rings_ifindex2role(dhd_pub, ifindex);
1855 if (DHD_IF_ROLE_STA(role)) {
1856 dhd_flow_rings_delete(dhd_pub, ifindex);
1858 dhd_flow_rings_delete_for_peer(dhd_pub, ifindex,
1859 &event->addr.octet[0]);
1866 /* push up to external supp/auth */
1867 dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx);
1868 DHD_TRACE(("%s: MAC event %d, flags %x, status %x\n",
1869 __FUNCTION__, type, flags, status));
1870 BCM_REFERENCE(flags);
1871 BCM_REFERENCE(status);
1877 wl_show_host_event(dhd_pub, event,
1878 (void *)event_data, raw_event, dhd_pub->enable_log);
1879 #endif /* SHOW_EVENTS */
1885 wl_event_to_host_order(wl_event_msg_t * evt)
1887 /* Event struct members passed from dongle to host are stored in network
1888 * byte order. Convert all members to host-order.
1890 evt->event_type = ntoh32(evt->event_type);
1891 evt->flags = ntoh16(evt->flags);
1892 evt->status = ntoh32(evt->status);
1893 evt->reason = ntoh32(evt->reason);
1894 evt->auth_type = ntoh32(evt->auth_type);
1895 evt->datalen = ntoh32(evt->datalen);
1896 evt->version = ntoh16(evt->version);
1900 dhd_print_buf(void *pbuf, int len, int bytes_per_line)
1904 unsigned char *buf = pbuf;
1906 if (bytes_per_line == 0) {
1907 bytes_per_line = len;
1910 for (i = 0; i < len; i++) {
1911 printf("%2.2x", *buf++);
1913 if (j == bytes_per_line) {
1921 #endif /* DHD_DEBUG */
1924 #define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
1927 #ifdef PKT_FILTER_SUPPORT
1928 /* Convert user's input in hex pattern to byte-size mask */
1930 wl_pattern_atoh(char *src, char *dst)
1933 if (strncmp(src, "0x", 2) != 0 &&
1934 strncmp(src, "0X", 2) != 0) {
1935 DHD_ERROR(("Mask invalid format. Needs to start with 0x\n"));
1938 src = src + 2; /* Skip past 0x */
1939 if (strlen(src) % 2 != 0) {
1940 DHD_ERROR(("Mask invalid format. Needs to be of even length\n"));
1943 for (i = 0; *src != '\0'; i++) {
1945 bcm_strncpy_s(num, sizeof(num), src, 2);
1947 dst[i] = (uint8)strtoul(num, NULL, 16);
1954 dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode)
1961 char *arg_save = 0, *arg_org = 0;
1964 wl_pkt_filter_enable_t enable_parm;
1965 wl_pkt_filter_enable_t * pkt_filterp;
1970 if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) {
1971 DHD_ERROR(("%s: malloc failed\n", __FUNCTION__));
1975 memcpy(arg_save, arg, strlen(arg) + 1);
1977 argv[i] = bcmstrtok(&arg_save, " ", 0);
1980 if (argv[i] == NULL) {
1981 DHD_ERROR(("No args provided\n"));
1985 str = "pkt_filter_enable";
1986 str_len = strlen(str);
1987 bcm_strncpy_s(buf, sizeof(buf) - 1, str, sizeof(buf) - 1);
1988 buf[ sizeof(buf) - 1 ] = '\0';
1989 buf_len = str_len + 1;
1991 pkt_filterp = (wl_pkt_filter_enable_t *)(buf + str_len + 1);
1993 /* Parse packet filter id. */
1994 enable_parm.id = htod32(strtoul(argv[i], NULL, 0));
1995 if (dhd_conf_del_pkt_filter(dhd, enable_parm.id))
1998 /* Parse enable/disable value. */
1999 enable_parm.enable = htod32(enable);
2001 buf_len += sizeof(enable_parm);
2002 memcpy((char *)pkt_filterp,
2004 sizeof(enable_parm));
2006 /* Enable/disable the specified filter. */
2007 rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0);
2008 rc = rc >= 0 ? 0 : rc;
2010 DHD_ERROR(("%s: failed to %s pktfilter %s, retcode = %d\n",
2011 __FUNCTION__, enable?"enable":"disable", arg, rc));
2013 DHD_TRACE(("%s: successfully %s pktfilter %s\n",
2014 __FUNCTION__, enable?"enable":"disable", arg));
2016 /* Contorl the master mode */
2017 bcm_mkiovar("pkt_filter_mode", (char *)&master_mode, 4, buf, sizeof(buf));
2018 rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
2019 rc = rc >= 0 ? 0 : rc;
2021 DHD_TRACE(("%s: failed to set pkt_filter_mode %d, retcode = %d\n",
2022 __FUNCTION__, master_mode, rc));
2026 MFREE(dhd->osh, arg_org, strlen(arg) + 1);
2030 dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg)
2033 wl_pkt_filter_t pkt_filter;
2034 wl_pkt_filter_t *pkt_filterp;
2039 uint32 pattern_size;
2040 char *argv[8], * buf = 0;
2042 char *arg_save = 0, *arg_org = 0;
2043 #define BUF_SIZE 2048
2048 if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) {
2049 DHD_ERROR(("%s: malloc failed\n", __FUNCTION__));
2055 if (!(buf = MALLOC(dhd->osh, BUF_SIZE))) {
2056 DHD_ERROR(("%s: malloc failed\n", __FUNCTION__));
2060 memcpy(arg_save, arg, strlen(arg) + 1);
2062 if (strlen(arg) > BUF_SIZE) {
2063 DHD_ERROR(("Not enough buffer %d < %d\n", (int)strlen(arg), (int)sizeof(buf)));
2067 argv[i] = bcmstrtok(&arg_save, " ", 0);
2069 argv[i] = bcmstrtok(&arg_save, " ", 0);
2072 if (argv[i] == NULL) {
2073 DHD_ERROR(("No args provided\n"));
2077 str = "pkt_filter_add";
2078 str_len = strlen(str);
2079 bcm_strncpy_s(buf, BUF_SIZE, str, str_len);
2080 buf[ str_len ] = '\0';
2081 buf_len = str_len + 1;
2083 pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1);
2085 /* Parse packet filter id. */
2086 pkt_filter.id = htod32(strtoul(argv[i], NULL, 0));
2087 if (dhd_conf_del_pkt_filter(dhd, pkt_filter.id))
2090 if (argv[++i] == NULL) {
2091 DHD_ERROR(("Polarity not provided\n"));
2095 /* Parse filter polarity. */
2096 pkt_filter.negate_match = htod32(strtoul(argv[i], NULL, 0));
2098 if (argv[++i] == NULL) {
2099 DHD_ERROR(("Filter type not provided\n"));
2103 /* Parse filter type. */
2104 pkt_filter.type = htod32(strtoul(argv[i], NULL, 0));
2106 if (argv[++i] == NULL) {
2107 DHD_ERROR(("Offset not provided\n"));
2111 /* Parse pattern filter offset. */
2112 pkt_filter.u.pattern.offset = htod32(strtoul(argv[i], NULL, 0));
2114 if (argv[++i] == NULL) {
2115 DHD_ERROR(("Bitmask not provided\n"));
2119 /* Parse pattern filter mask. */
2121 htod32(wl_pattern_atoh(argv[i], (char *) pkt_filterp->u.pattern.mask_and_pattern));
2123 if (argv[++i] == NULL) {
2124 DHD_ERROR(("Pattern not provided\n"));
2128 /* Parse pattern filter pattern. */
2130 htod32(wl_pattern_atoh(argv[i],
2131 (char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size]));
2133 if (mask_size != pattern_size) {
2134 DHD_ERROR(("Mask and pattern not the same size\n"));
2138 pkt_filter.u.pattern.size_bytes = mask_size;
2139 buf_len += WL_PKT_FILTER_FIXED_LEN;
2140 buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size);
2142 /* Keep-alive attributes are set in local variable (keep_alive_pkt), and
2143 ** then memcpy'ed into buffer (keep_alive_pktp) since there is no
2144 ** guarantee that the buffer is properly aligned.
2146 memcpy((char *)pkt_filterp,
2148 WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN);
2150 rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0);
2151 rc = rc >= 0 ? 0 : rc;
2154 DHD_ERROR(("%s: failed to add pktfilter %s, retcode = %d\n",
2155 __FUNCTION__, arg, rc));
2157 DHD_TRACE(("%s: successfully added pktfilter %s\n",
2158 __FUNCTION__, arg));
2162 MFREE(dhd->osh, arg_org, strlen(arg) + 1);
2165 MFREE(dhd->osh, buf, BUF_SIZE);
2168 void dhd_pktfilter_offload_delete(dhd_pub_t *dhd, int id)
2173 bcm_mkiovar("pkt_filter_delete", (char *)&id, 4, iovbuf, sizeof(iovbuf));
2174 ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
2176 DHD_ERROR(("%s: Failed to delete filter ID:%d, ret=%d\n",
2177 __FUNCTION__, id, ret));
2180 DHD_TRACE(("%s: successfully deleted pktfilter %d\n",
2183 #endif /* PKT_FILTER_SUPPORT */
2185 /* ========================== */
2186 /* ==== ARP OFFLOAD SUPPORT = */
2187 /* ========================== */
2188 #ifdef ARP_OFFLOAD_SUPPORT
2190 dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode)
2192 char iovbuf[DHD_IOVAR_BUF_SIZE];
2196 iovar_len = bcm_mkiovar("arp_ol", (char *)&arp_mode, 4, iovbuf, sizeof(iovbuf));
2198 DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n",
2199 __FUNCTION__, sizeof(iovbuf)));
2203 retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iovar_len, TRUE, 0);
2204 retcode = retcode >= 0 ? 0 : retcode;
2206 DHD_ERROR(("%s: failed to set ARP offload mode to 0x%x, retcode = %d\n",
2207 __FUNCTION__, arp_mode, retcode));
2209 DHD_ARPOE(("%s: successfully set ARP offload mode to 0x%x\n",
2210 __FUNCTION__, arp_mode));
2214 dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable)
2216 char iovbuf[DHD_IOVAR_BUF_SIZE];
2220 iovar_len = bcm_mkiovar("arpoe", (char *)&arp_enable, 4, iovbuf, sizeof(iovbuf));
2222 DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n",
2223 __FUNCTION__, sizeof(iovbuf)));
2227 retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iovar_len, TRUE, 0);
2228 retcode = retcode >= 0 ? 0 : retcode;
2230 DHD_ERROR(("%s: failed to enabe ARP offload to %d, retcode = %d\n",
2231 __FUNCTION__, arp_enable, retcode));
2233 DHD_ARPOE(("%s: successfully enabed ARP offload to %d\n",
2234 __FUNCTION__, arp_enable));
2237 bcm_mkiovar("arp_version", 0, 0, iovbuf, sizeof(iovbuf));
2238 retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0);
2240 DHD_INFO(("%s: fail to get version (maybe version 1:retcode = %d\n",
2241 __FUNCTION__, retcode));
2242 dhd->arp_version = 1;
2245 memcpy(&version, iovbuf, sizeof(version));
2246 DHD_INFO(("%s: ARP Version= %x\n", __FUNCTION__, version));
2247 dhd->arp_version = version;
2253 dhd_aoe_arp_clr(dhd_pub_t *dhd, int idx)
2257 char iovbuf[DHD_IOVAR_BUF_SIZE];
2259 if (dhd == NULL) return;
2260 if (dhd->arp_version == 1)
2263 iov_len = bcm_mkiovar("arp_table_clear", 0, 0, iovbuf, sizeof(iovbuf));
2265 DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n",
2266 __FUNCTION__, sizeof(iovbuf)));
2269 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx)) < 0)
2270 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
2274 dhd_aoe_hostip_clr(dhd_pub_t *dhd, int idx)
2278 char iovbuf[DHD_IOVAR_BUF_SIZE];
2280 if (dhd == NULL) return;
2281 if (dhd->arp_version == 1)
2284 iov_len = bcm_mkiovar("arp_hostip_clear", 0, 0, iovbuf, sizeof(iovbuf));
2286 DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n",
2287 __FUNCTION__, sizeof(iovbuf)));
2290 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx)) < 0)
2291 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
2295 dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr, int idx)
2298 char iovbuf[DHD_IOVAR_BUF_SIZE];
2302 if (dhd == NULL) return;
2303 if (dhd->arp_version == 1)
2305 iov_len = bcm_mkiovar("arp_hostip", (char *)&ipaddr,
2306 sizeof(ipaddr), iovbuf, sizeof(iovbuf));
2308 DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n",
2309 __FUNCTION__, sizeof(iovbuf)));
2312 retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx);
2315 DHD_ERROR(("%s: ARP ip addr add failed, retcode = %d\n",
2316 __FUNCTION__, retcode));
2318 DHD_ARPOE(("%s: sARP H ipaddr entry added \n",
2323 dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen, int idx)
2327 uint32 *ptr32 = buf;
2328 bool clr_bottom = FALSE;
2332 if (dhd == NULL) return -1;
2333 if (dhd->arp_version == 1)
2336 iov_len = bcm_mkiovar("arp_hostip", 0, 0, buf, buflen);
2337 BCM_REFERENCE(iov_len);
2338 retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, buflen, FALSE, idx);
2341 DHD_ERROR(("%s: ioctl WLC_GET_VAR error %d\n",
2342 __FUNCTION__, retcode));
2347 /* clean up the buf, ascii reminder */
2348 for (i = 0; i < MAX_IPV4_ENTRIES; i++) {
2360 #endif /* ARP_OFFLOAD_SUPPORT */
2363 * Neighbor Discovery Offload: enable NDO feature
2364 * Called by ipv6 event handler when interface comes up/goes down
2367 dhd_ndo_enable(dhd_pub_t * dhd, int ndo_enable)
2369 char iovbuf[DHD_IOVAR_BUF_SIZE];
2376 iov_len = bcm_mkiovar("ndoe", (char *)&ndo_enable, 4, iovbuf, sizeof(iovbuf));
2378 DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n",
2379 __FUNCTION__, sizeof(iovbuf)));
2382 retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, 0);
2384 DHD_ERROR(("%s: failed to enabe ndo to %d, retcode = %d\n",
2385 __FUNCTION__, ndo_enable, retcode));
2387 DHD_TRACE(("%s: successfully enabed ndo offload to %d\n",
2388 __FUNCTION__, ndo_enable));
2394 * Neighbor Discover Offload: enable NDO feature
2395 * Called by ipv6 event handler when interface comes up
2398 dhd_ndo_add_ip(dhd_pub_t *dhd, char* ipv6addr, int idx)
2401 char iovbuf[DHD_IOVAR_BUF_SIZE];
2407 iov_len = bcm_mkiovar("nd_hostip", (char *)ipv6addr,
2408 IPV6_ADDR_LEN, iovbuf, sizeof(iovbuf));
2410 DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n",
2411 __FUNCTION__, sizeof(iovbuf)));
2414 retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx);
2417 DHD_ERROR(("%s: ndo ip addr add failed, retcode = %d\n",
2418 __FUNCTION__, retcode));
2420 DHD_TRACE(("%s: ndo ipaddr entry added \n",
2426 * Neighbor Discover Offload: enable NDO feature
2427 * Called by ipv6 event handler when interface goes down
2430 dhd_ndo_remove_ip(dhd_pub_t *dhd, int idx)
2433 char iovbuf[DHD_IOVAR_BUF_SIZE];
2439 iov_len = bcm_mkiovar("nd_hostip_clear", NULL,
2440 0, iovbuf, sizeof(iovbuf));
2442 DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n",
2443 __FUNCTION__, sizeof(iovbuf)));
2446 retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx);
2449 DHD_ERROR(("%s: ndo ip addr remove failed, retcode = %d\n",
2450 __FUNCTION__, retcode));
2452 DHD_TRACE(("%s: ndo ipaddr entry removed \n",
2458 /* send up locally generated event */
2460 dhd_sendup_event_common(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data)
2462 switch (ntoh32(event->event_type)) {
2464 case WLC_E_BTA_HCI_EVENT:
2466 #endif /* WLBTAMP */
2471 /* Call per-port handler. */
2472 dhd_sendup_event(dhdp, event, data);
2477 * returns = TRUE if associated, FALSE if not associated
2479 bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval)
2481 char bssid[6], zbuf[6];
2487 ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BSSID, (char *)&bssid, ETHER_ADDR_LEN, FALSE, 0);
2488 DHD_TRACE((" %s WLC_GET_BSSID ioctl res = %d\n", __FUNCTION__, ret));
2490 if (ret == BCME_NOTASSOCIATED) {
2491 DHD_TRACE(("%s: not associated! res:%d\n", __FUNCTION__, ret));
2500 if ((memcmp(bssid, zbuf, ETHER_ADDR_LEN) != 0)) {
2501 /* STA is assocoated BSSID is non zero */
2504 /* return bss if caller provided buf */
2505 memcpy(bss_buf, bssid, ETHER_ADDR_LEN);
2509 DHD_TRACE(("%s: WLC_GET_BSSID ioctl returned zero bssid\n", __FUNCTION__));
2514 /* Function to estimate possible DTIM_SKIP value */
2516 dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd)
2518 int bcn_li_dtim = 1; /* deafult no dtim skip setting */
2520 int dtim_period = 0;
2522 int allowed_skip_dtim_cnt = 0;
2523 /* Check if associated */
2524 if (dhd_is_associated(dhd, NULL, NULL) == FALSE) {
2525 DHD_TRACE(("%s NOT assoc ret %d\n", __FUNCTION__, ret));
2529 /* read associated AP beacon interval */
2530 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BCNPRD,
2531 &ap_beacon, sizeof(ap_beacon), FALSE, 0)) < 0) {
2532 DHD_ERROR(("%s get beacon failed code %d\n", __FUNCTION__, ret));
2536 /* read associated ap's dtim setup */
2537 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_DTIMPRD,
2538 &dtim_period, sizeof(dtim_period), FALSE, 0)) < 0) {
2539 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
2543 /* if not assocated just eixt */
2544 if (dtim_period == 0) {
2548 /* attemp to use platform defined dtim skip interval */
2549 bcn_li_dtim = dhd->suspend_bcn_li_dtim;
2551 /* check if sta listen interval fits into AP dtim */
2552 if (dtim_period > CUSTOM_LISTEN_INTERVAL) {
2553 /* AP DTIM to big for our Listen Interval : no dtim skiping */
2554 bcn_li_dtim = NO_DTIM_SKIP;
2555 DHD_ERROR(("%s DTIM=%d > Listen=%d : too big ...\n",
2556 __FUNCTION__, dtim_period, CUSTOM_LISTEN_INTERVAL));
2560 if ((dtim_period * ap_beacon * bcn_li_dtim) > MAX_DTIM_ALLOWED_INTERVAL) {
2561 allowed_skip_dtim_cnt = MAX_DTIM_ALLOWED_INTERVAL / (dtim_period * ap_beacon);
2562 bcn_li_dtim = (allowed_skip_dtim_cnt != 0) ? allowed_skip_dtim_cnt : NO_DTIM_SKIP;
2565 if ((bcn_li_dtim * dtim_period) > CUSTOM_LISTEN_INTERVAL) {
2566 /* Round up dtim_skip to fit into STAs Listen Interval */
2567 bcn_li_dtim = (int)(CUSTOM_LISTEN_INTERVAL / dtim_period);
2568 DHD_TRACE(("%s agjust dtim_skip as %d\n", __FUNCTION__, bcn_li_dtim));
2571 DHD_ERROR(("%s beacon=%d bcn_li_dtim=%d DTIM=%d Listen=%d\n",
2572 __FUNCTION__, ap_beacon, bcn_li_dtim, dtim_period, CUSTOM_LISTEN_INTERVAL));
2578 /* Check if the mode supports STA MODE */
2579 bool dhd_support_sta_mode(dhd_pub_t *dhd)
2583 if (!(dhd->op_mode & DHD_FLAG_STA_MODE))
2586 #endif /* WL_CFG80211 */
2590 #if defined(KEEP_ALIVE)
2591 int dhd_keep_alive_onoff(dhd_pub_t *dhd)
2595 wl_mkeep_alive_pkt_t mkeep_alive_pkt = {0};
2596 wl_mkeep_alive_pkt_t *mkeep_alive_pktp;
2601 if (!dhd_support_sta_mode(dhd))
2604 DHD_TRACE(("%s execution\n", __FUNCTION__));
2606 str = "mkeep_alive";
2607 str_len = strlen(str);
2608 strncpy(buf, str, sizeof(buf) - 1);
2609 buf[ sizeof(buf) - 1 ] = '\0';
2610 mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (buf + str_len + 1);
2611 mkeep_alive_pkt.period_msec = dhd->conf->keep_alive_period;
2612 buf_len = str_len + 1;
2613 mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION);
2614 mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
2615 /* Setup keep alive zero for null packet generation */
2616 mkeep_alive_pkt.keep_alive_id = 0;
2617 mkeep_alive_pkt.len_bytes = 0;
2618 buf_len += WL_MKEEP_ALIVE_FIXED_LEN;
2619 bzero(mkeep_alive_pkt.data, sizeof(mkeep_alive_pkt.data));
2620 /* Keep-alive attributes are set in local variable (mkeep_alive_pkt), and
2621 * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no
2622 * guarantee that the buffer is properly aligned.
2624 memcpy((char *)mkeep_alive_pktp, &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN);
2626 res = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0);
2630 #endif /* defined(KEEP_ALIVE) */
2631 /* Android ComboSCAN support */
2634 * data parsing from ComboScan tlv list
2637 wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size, const char token,
2638 int input_size, int *bytes_left)
2644 if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) {
2645 DHD_ERROR(("%s error paramters\n", __FUNCTION__));
2650 /* Clean all dest bytes */
2651 memset(dst, 0, dst_size);
2652 while (*bytes_left > 0) {
2654 if (str[0] != token) {
2655 DHD_TRACE(("%s NOT Type=%d get=%d left_parse=%d \n",
2656 __FUNCTION__, token, str[0], *bytes_left));
2663 if (input_size == 1) {
2664 memcpy(dst, str, input_size);
2666 else if (input_size == 2) {
2667 memcpy(dst, (char *)htod16(memcpy(&short_temp, str, input_size)),
2670 else if (input_size == 4) {
2671 memcpy(dst, (char *)htod32(memcpy(&int_temp, str, input_size)),
2675 *bytes_left -= input_size;
2684 * channel list parsing from cscan tlv list
2687 wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list,
2688 int channel_num, int *bytes_left)
2693 if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) {
2694 DHD_ERROR(("%s error paramters\n", __FUNCTION__));
2699 while (*bytes_left > 0) {
2701 if (str[0] != CSCAN_TLV_TYPE_CHANNEL_IE) {
2703 DHD_TRACE(("End channel=%d left_parse=%d %d\n", idx, *bytes_left, str[0]));
2706 /* Get proper CSCAN_TLV_TYPE_CHANNEL_IE */
2712 channel_list[idx] = 0x0;
2715 channel_list[idx] = (uint16)str[0];
2716 DHD_TRACE(("%s channel=%d \n", __FUNCTION__, channel_list[idx]));
2722 DHD_ERROR(("%s Too many channels \n", __FUNCTION__));
2732 * SSIDs list parsing from cscan tlv list
2735 wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid, int max, int *bytes_left)
2740 if ((list_str == NULL) || (*list_str == NULL) || (*bytes_left < 0)) {
2741 DHD_ERROR(("%s error paramters\n", __FUNCTION__));
2745 while (*bytes_left > 0) {
2747 if (str[0] != CSCAN_TLV_TYPE_SSID_IE) {
2749 DHD_TRACE(("nssid=%d left_parse=%d %d\n", idx, *bytes_left, str[0]));
2753 /* Get proper CSCAN_TLV_TYPE_SSID_IE */
2758 /* Broadcast SSID */
2759 ssid[idx].SSID_len = 0;
2760 memset((char*)ssid[idx].SSID, 0x0, DOT11_MAX_SSID_LEN);
2764 DHD_TRACE(("BROADCAST SCAN left=%d\n", *bytes_left));
2766 else if (str[0] <= DOT11_MAX_SSID_LEN) {
2767 /* Get proper SSID size */
2768 ssid[idx].SSID_len = str[0];
2773 if (ssid[idx].SSID_len > *bytes_left) {
2774 DHD_ERROR(("%s out of memory range len=%d but left=%d\n",
2775 __FUNCTION__, ssid[idx].SSID_len, *bytes_left));
2779 memcpy((char*)ssid[idx].SSID, str, ssid[idx].SSID_len);
2781 *bytes_left -= ssid[idx].SSID_len;
2782 str += ssid[idx].SSID_len;
2784 DHD_TRACE(("%s :size=%d left=%d\n",
2785 (char*)ssid[idx].SSID, ssid[idx].SSID_len, *bytes_left));
2788 DHD_ERROR(("### SSID size more that %d\n", str[0]));
2793 DHD_ERROR(("%s number of SSIDs more that %d\n", __FUNCTION__, idx));
2802 /* Parse a comma-separated list from list_str into ssid array, starting
2803 * at index idx. Max specifies size of the ssid array. Parses ssids
2804 * and returns updated idx; if idx >= max not all fit, the excess have
2805 * not been copied. Returns -1 on empty string, or on ssid too long.
2808 wl_iw_parse_ssid_list(char** list_str, wlc_ssid_t* ssid, int idx, int max)
2812 if ((list_str == NULL) || (*list_str == NULL))
2815 for (str = *list_str; str != NULL; str = ptr) {
2817 /* check for next TAG */
2818 if (!strncmp(str, GET_CHANNEL, strlen(GET_CHANNEL))) {
2819 *list_str = str + strlen(GET_CHANNEL);
2823 if ((ptr = strchr(str, ',')) != NULL) {
2827 if (strlen(str) > DOT11_MAX_SSID_LEN) {
2828 DHD_ERROR(("ssid <%s> exceeds %d\n", str, DOT11_MAX_SSID_LEN));
2832 if (strlen(str) == 0)
2833 ssid[idx].SSID_len = 0;
2836 bzero(ssid[idx].SSID, sizeof(ssid[idx].SSID));
2837 strncpy((char*)ssid[idx].SSID, str, sizeof(ssid[idx].SSID) - 1);
2838 ssid[idx].SSID_len = strlen(str);
2846 * Parse channel list from iwpriv CSCAN
2849 wl_iw_parse_channel_list(char** list_str, uint16* channel_list, int channel_num)
2854 char* endptr = NULL;
2856 if ((list_str == NULL)||(*list_str == NULL))
2861 while (strncmp(str, GET_NPROBE, strlen(GET_NPROBE))) {
2862 val = (int)strtoul(str, &endptr, 0);
2863 if (endptr == str) {
2864 printf("could not parse channel number starting at"
2865 " substring \"%s\" in list:\n%s\n",
2869 str = endptr + strspn(endptr, " ,");
2871 if (num == channel_num) {
2872 DHD_ERROR(("too many channels (more than %d) in channel list:\n%s\n",
2873 channel_num, *list_str));
2877 channel_list[num++] = (uint16)val;