2 * Broadcom Dongle Host Driver (DHD), common DHD core.
4 * $Copyright Open Broadcom Corporation$
6 * $Id: dhd_common.c 419132 2013-08-19 21:33:05Z $
14 #include <bcmendian.h>
15 #include <dngl_stats.h>
20 #include <proto/bcmevent.h>
21 #include <proto/bcmip.h>
24 #include <dhd_proto.h>
25 #include <dhd_config.h>
30 #include <wl_cfg80211.h>
33 #include <proto/bt_amp_hci.h>
39 #ifdef SET_RANDOM_MAC_SOFTAP
40 #include <linux/random.h>
41 #include <linux/jiffies.h>
48 #define htodchanspec(i) i
49 #define dtohchanspec(i) i
52 #include <wlfc_proto.h>
57 extern void htsf_update(struct dhd_info
*dhd
, void *data
);
59 int dhd_msg_level
= DHD_ERROR_VAL
;
64 char fw_path
[MOD_PARAM_PATHLEN
];
65 char nv_path
[MOD_PARAM_PATHLEN
];
66 // terence 20130703: customer can add some parameters to configure driver
67 char conf_path
[MOD_PARAM_PATHLEN
];
70 char fw_path2
[MOD_PARAM_PATHLEN
];
71 extern bool softap_enabled
;
74 /* Last connection success/failure status */
75 uint32 dhd_conn_event
;
76 uint32 dhd_conn_status
;
77 uint32 dhd_conn_reason
;
79 extern int dhd_iscan_request(void * dhdp
, uint16 action
);
80 extern void dhd_ind_scan_confirm(void *h
, bool status
);
81 extern int dhd_iscan_in_progress(void *h
);
82 void dhd_iscan_lock(void);
83 void dhd_iscan_unlock(void);
84 extern int dhd_change_mtu(dhd_pub_t
*dhd
, int new_mtu
, int ifidx
);
85 #if !defined(AP) && defined(WLP2P)
86 extern int dhd_get_concurrent_capabilites(dhd_pub_t
*dhd
);
88 bool ap_cfg_running
= FALSE
;
89 bool ap_fw_loaded
= FALSE
;
93 const char dhd_version
[] = "Dongle Host Driver, version " EPI_VERSION_STR
"\nCompiled on "
94 __DATE__
" at " __TIME__
;
96 const char dhd_version
[] = "Dongle Host Driver, version " EPI_VERSION_STR
;
99 void dhd_set_timer(void *bus
, uint wdtick
);
117 IOV_HCI_CMD
, /* HCI command */
118 IOV_HCI_ACL_DATA
, /* HCI data packet */
120 #if defined(DHD_DEBUG)
123 #endif /* defined(DHD_DEBUG) */
125 IOV_PROPTXSTATUS_ENABLE
,
126 IOV_PROPTXSTATUS_MODE
,
127 IOV_PROPTXSTATUS_OPT
,
130 IOV_QMON_TIME_PERCENT
,
131 #endif /* QMONITOR */
132 #endif /* PROP_TXSTATUS */
138 IOV_HOSTREORDER_FLOWS
,
142 const bcm_iovar_t dhd_iovars
[] = {
143 {"version", IOV_VERSION
, 0, IOVT_BUFFER
, sizeof(dhd_version
) },
144 {"wlmsglevel", IOV_WLMSGLEVEL
, 0, IOVT_UINT32
, 0 },
146 {"msglevel", IOV_MSGLEVEL
, 0, IOVT_UINT32
, 0 },
147 #endif /* DHD_DEBUG */
148 {"bcmerrorstr", IOV_BCMERRORSTR
, 0, IOVT_BUFFER
, BCME_STRLEN
},
149 {"bcmerror", IOV_BCMERROR
, 0, IOVT_INT8
, 0 },
150 {"wdtick", IOV_WDTICK
, 0, IOVT_UINT32
, 0 },
151 {"dump", IOV_DUMP
, 0, IOVT_BUFFER
, DHD_IOCTL_MAXLEN
},
153 {"cons", IOV_CONS
, 0, IOVT_BUFFER
, 0 },
154 {"dconpoll", IOV_DCONSOLE_POLL
, 0, IOVT_UINT32
, 0 },
156 {"clearcounts", IOV_CLEARCOUNTS
, 0, IOVT_VOID
, 0 },
157 {"gpioob", IOV_GPIOOB
, 0, IOVT_UINT32
, 0 },
158 {"ioctl_timeout", IOV_IOCTLTIMEOUT
, 0, IOVT_UINT32
, 0 },
160 {"HCI_cmd", IOV_HCI_CMD
, 0, IOVT_BUFFER
, 0},
161 {"HCI_ACL_data", IOV_HCI_ACL_DATA
, 0, IOVT_BUFFER
, 0},
164 {"proptx", IOV_PROPTXSTATUS_ENABLE
, 0, IOVT_UINT32
, 0 },
166 set the proptxtstatus operation mode:
167 0 - Do not do any proptxtstatus flow control
168 1 - Use implied credit from a packet status
169 2 - Use explicit credit
171 {"ptxmode", IOV_PROPTXSTATUS_MODE
, 0, IOVT_UINT32
, 0 },
172 {"proptx_opt", IOV_PROPTXSTATUS_OPT
, 0, IOVT_UINT32
, 0 },
174 {"qtime_thres", IOV_QMON_TIME_THRES
, 0, IOVT_UINT32
, 0 },
175 {"qtime_percent", IOV_QMON_TIME_PERCENT
, 0, IOVT_UINT32
, 0 },
176 #endif /* QMONITOR */
177 #endif /* PROP_TXSTATUS */
178 {"bustype", IOV_BUS_TYPE
, 0, IOVT_UINT32
, 0},
180 {"pktdlystatsz", IOV_WLPKTDLYSTAT_SZ
, 0, IOVT_UINT8
, 0 },
182 {"changemtu", IOV_CHANGEMTU
, 0, IOVT_UINT32
, 0 },
183 {"host_reorder_flows", IOV_HOSTREORDER_FLOWS
, 0, IOVT_BUFFER
,
184 (WLHOST_REORDERDATA_MAXFLOWS
+ 1) },
187 #define DHD_IOVAR_BUF_SIZE 128
190 dhd_common_init(osl_t
*osh
)
192 #ifdef CONFIG_BCMDHD_FW_PATH
193 bcm_strncpy_s(fw_path
, sizeof(fw_path
), CONFIG_BCMDHD_FW_PATH
, MOD_PARAM_PATHLEN
-1);
194 #else /* CONFIG_BCMDHD_FW_PATH */
196 #endif /* CONFIG_BCMDHD_FW_PATH */
197 #ifdef CONFIG_BCMDHD_NVRAM_PATH
198 bcm_strncpy_s(nv_path
, sizeof(nv_path
), CONFIG_BCMDHD_NVRAM_PATH
, MOD_PARAM_PATHLEN
-1);
199 #else /* CONFIG_BCMDHD_NVRAM_PATH */
201 #endif /* CONFIG_BCMDHD_NVRAM_PATH */
202 #ifdef CONFIG_BCMDHD_CONFIG_PATH
203 bcm_strncpy_s(conf_path
, sizeof(conf_path
), CONFIG_BCMDHD_CONFIG_PATH
, MOD_PARAM_PATHLEN
-1);
204 #else /* CONFIG_BCMDHD_CONFIG_PATH */
206 #endif /* CONFIG_BCMDHD_CONFIG_PATH */
213 dhd_common_deinit(dhd_pub_t
*dhd_pub
, dhd_cmn_t
*sa_cmn
)
231 MFREE(osh
, cmn
, sizeof(dhd_cmn_t
));
235 dhd_dump(dhd_pub_t
*dhdp
, char *buf
, int buflen
)
237 char eabuf
[ETHER_ADDR_STR_LEN
];
240 struct bcmstrbuf
*strbuf
= &b
;
242 bcm_binit(strbuf
, buf
, buflen
);
245 bcm_bprintf(strbuf
, "%s\n", dhd_version
);
246 bcm_bprintf(strbuf
, "\n");
247 bcm_bprintf(strbuf
, "pub.up %d pub.txoff %d pub.busstate %d\n",
248 dhdp
->up
, dhdp
->txoff
, dhdp
->busstate
);
249 bcm_bprintf(strbuf
, "pub.hdrlen %u pub.maxctl %u pub.rxsz %u\n",
250 dhdp
->hdrlen
, dhdp
->maxctl
, dhdp
->rxsz
);
251 bcm_bprintf(strbuf
, "pub.iswl %d pub.drv_version %ld pub.mac %s\n",
252 dhdp
->iswl
, dhdp
->drv_version
, bcm_ether_ntoa(&dhdp
->mac
, eabuf
));
253 bcm_bprintf(strbuf
, "pub.bcmerror %d tickcnt %u\n", dhdp
->bcmerror
, dhdp
->tickcnt
);
255 bcm_bprintf(strbuf
, "dongle stats:\n");
256 bcm_bprintf(strbuf
, "tx_packets %lu tx_bytes %lu tx_errors %lu tx_dropped %lu\n",
257 dhdp
->dstats
.tx_packets
, dhdp
->dstats
.tx_bytes
,
258 dhdp
->dstats
.tx_errors
, dhdp
->dstats
.tx_dropped
);
259 bcm_bprintf(strbuf
, "rx_packets %lu rx_bytes %lu rx_errors %lu rx_dropped %lu\n",
260 dhdp
->dstats
.rx_packets
, dhdp
->dstats
.rx_bytes
,
261 dhdp
->dstats
.rx_errors
, dhdp
->dstats
.rx_dropped
);
262 bcm_bprintf(strbuf
, "multicast %lu\n", dhdp
->dstats
.multicast
);
264 bcm_bprintf(strbuf
, "bus stats:\n");
265 bcm_bprintf(strbuf
, "tx_packets %lu tx_multicast %lu tx_errors %lu\n",
266 dhdp
->tx_packets
, dhdp
->tx_multicast
, dhdp
->tx_errors
);
267 bcm_bprintf(strbuf
, "tx_ctlpkts %lu tx_ctlerrs %lu\n",
268 dhdp
->tx_ctlpkts
, dhdp
->tx_ctlerrs
);
269 bcm_bprintf(strbuf
, "rx_packets %lu rx_multicast %lu rx_errors %lu \n",
270 dhdp
->rx_packets
, dhdp
->rx_multicast
, dhdp
->rx_errors
);
271 bcm_bprintf(strbuf
, "rx_ctlpkts %lu rx_ctlerrs %lu rx_dropped %lu\n",
272 dhdp
->rx_ctlpkts
, dhdp
->rx_ctlerrs
, dhdp
->rx_dropped
);
273 bcm_bprintf(strbuf
, "rx_readahead_cnt %lu tx_realloc %lu\n",
274 dhdp
->rx_readahead_cnt
, dhdp
->tx_realloc
);
275 bcm_bprintf(strbuf
, "\n");
277 /* Add any prot info */
278 dhd_prot_dump(dhdp
, strbuf
);
279 bcm_bprintf(strbuf
, "\n");
281 /* Add any bus info */
282 dhd_bus_dump(dhdp
, strbuf
);
284 return (!strbuf
->size
? BCME_BUFTOOSHORT
: 0);
288 dhd_wl_ioctl_cmd(dhd_pub_t
*dhd_pub
, int cmd
, void *arg
, int len
, uint8 set
, int ifindex
)
297 return dhd_wl_ioctl(dhd_pub
, ifindex
, &ioc
, arg
, len
);
302 dhd_wl_ioctl(dhd_pub_t
*dhd_pub
, int ifindex
, wl_ioctl_t
*ioc
, void *buf
, int len
)
306 if (dhd_os_proto_block(dhd_pub
))
308 ret
= dhd_prot_ioctl(dhd_pub
, ifindex
, ioc
, buf
, len
);
309 if ((ret
) && (dhd_pub
->up
))
310 /* Send hang event only if dhd_open() was success */
311 dhd_os_check_hang(dhd_pub
, ifindex
, ret
);
313 if (ret
== -ETIMEDOUT
&& !dhd_pub
->up
) {
314 DHD_ERROR(("%s: 'resumed on timeout' error is "
315 "occurred before the interface does not"
316 " bring up\n", __FUNCTION__
));
317 dhd_pub
->busstate
= DHD_BUS_DOWN
;
320 dhd_os_proto_unblock(dhd_pub
);
327 dhd_doiovar(dhd_pub_t
*dhd_pub
, const bcm_iovar_t
*vi
, uint32 actionid
, const char *name
,
328 void *params
, int plen
, void *arg
, int len
, int val_size
)
333 DHD_TRACE(("%s: Enter\n", __FUNCTION__
));
334 DHD_TRACE(("%s: actionid = %d; name %s\n", __FUNCTION__
, actionid
, name
));
336 if ((bcmerror
= bcm_iovar_lencheck(vi
, arg
, len
, IOV_ISSET(actionid
))) != 0)
339 if (plen
>= (int)sizeof(int_val
))
340 bcopy(params
, &int_val
, sizeof(int_val
));
343 case IOV_GVAL(IOV_VERSION
):
344 /* Need to have checked buffer length */
345 bcm_strncpy_s((char*)arg
, len
, dhd_version
, len
);
348 case IOV_GVAL(IOV_WLMSGLEVEL
):
349 printk("android_msg_level=0x%x\n", android_msg_level
);
350 printk("config_msg_level=0x%x\n", config_msg_level
);
351 #if defined(WL_WIRELESS_EXT)
352 int_val
= (int32
)iw_msg_level
;
353 bcopy(&int_val
, arg
, val_size
);
354 printk("iw_msg_level=0x%x\n", iw_msg_level
);
357 int_val
= (int32
)wl_dbg_level
;
358 bcopy(&int_val
, arg
, val_size
);
359 printk("cfg_msg_level=0x%x\n", wl_dbg_level
);
363 case IOV_SVAL(IOV_WLMSGLEVEL
):
364 if (int_val
& DHD_ANDROID_VAL
) {
365 android_msg_level
= (uint
)(int_val
& 0xFFFF);
366 printk("android_msg_level=0x%x\n", android_msg_level
);
368 if (int_val
& DHD_CONFIG_VAL
) {
369 config_msg_level
= (uint
)(int_val
& 0xFFFF);
370 printk("config_msg_level=0x%x\n", config_msg_level
);
372 #if defined(WL_WIRELESS_EXT)
373 if (int_val
& DHD_IW_VAL
) {
374 iw_msg_level
= (uint
)(int_val
& 0xFFFF);
375 printk("iw_msg_level=0x%x\n", iw_msg_level
);
379 if (int_val
& DHD_CFG_VAL
) {
380 wl_cfg80211_enable_trace((u32
)(int_val
& 0xFFFF));
385 case IOV_GVAL(IOV_MSGLEVEL
):
386 int_val
= (int32
)dhd_msg_level
;
387 bcopy(&int_val
, arg
, val_size
);
390 case IOV_SVAL(IOV_MSGLEVEL
):
391 dhd_msg_level
= int_val
;
394 case IOV_GVAL(IOV_BCMERRORSTR
):
395 bcm_strncpy_s((char *)arg
, len
, bcmerrorstr(dhd_pub
->bcmerror
), BCME_STRLEN
);
396 ((char *)arg
)[BCME_STRLEN
- 1] = 0x00;
399 case IOV_GVAL(IOV_BCMERROR
):
400 int_val
= (int32
)dhd_pub
->bcmerror
;
401 bcopy(&int_val
, arg
, val_size
);
404 case IOV_GVAL(IOV_WDTICK
):
405 int_val
= (int32
)dhd_watchdog_ms
;
406 bcopy(&int_val
, arg
, val_size
);
409 case IOV_SVAL(IOV_WDTICK
):
411 bcmerror
= BCME_NOTUP
;
414 dhd_os_wd_timer(dhd_pub
, (uint
)int_val
);
417 case IOV_GVAL(IOV_DUMP
):
418 bcmerror
= dhd_dump(dhd_pub
, arg
, len
);
422 case IOV_GVAL(IOV_DCONSOLE_POLL
):
423 int_val
= (int32
)dhd_console_ms
;
424 bcopy(&int_val
, arg
, val_size
);
427 case IOV_SVAL(IOV_DCONSOLE_POLL
):
428 dhd_console_ms
= (uint
)int_val
;
431 case IOV_SVAL(IOV_CONS
):
433 bcmerror
= dhd_bus_console_in(dhd_pub
, arg
, len
- 1);
435 #endif /* DHD_DEBUG */
437 case IOV_SVAL(IOV_CLEARCOUNTS
):
438 dhd_pub
->tx_packets
= dhd_pub
->rx_packets
= 0;
439 dhd_pub
->tx_errors
= dhd_pub
->rx_errors
= 0;
440 dhd_pub
->tx_ctlpkts
= dhd_pub
->rx_ctlpkts
= 0;
441 dhd_pub
->tx_ctlerrs
= dhd_pub
->rx_ctlerrs
= 0;
442 dhd_pub
->rx_dropped
= 0;
443 dhd_pub
->rx_readahead_cnt
= 0;
444 dhd_pub
->tx_realloc
= 0;
445 dhd_pub
->wd_dpc_sched
= 0;
446 memset(&dhd_pub
->dstats
, 0, sizeof(dhd_pub
->dstats
));
447 dhd_bus_clearcounts(dhd_pub
);
449 /* clear proptxstatus related counters */
450 if (dhd_pub
->wlfc_state
) {
451 athost_wl_status_info_t
*wlfc
=
452 (athost_wl_status_info_t
*)dhd_pub
->wlfc_state
;
453 wlfc_hanger_t
* hanger
;
455 memset(&wlfc
->stats
, 0, sizeof(athost_wl_stat_counters_t
));
457 hanger
= (wlfc_hanger_t
*)wlfc
->hanger
;
460 hanger
->failed_slotfind
= 0;
461 hanger
->failed_to_pop
= 0;
462 hanger
->failed_to_push
= 0;
464 #endif /* PROP_TXSTATUS */
467 case IOV_GVAL(IOV_IOCTLTIMEOUT
): {
468 int_val
= (int32
)dhd_os_get_ioctl_resp_timeout();
469 bcopy(&int_val
, arg
, sizeof(int_val
));
473 case IOV_SVAL(IOV_IOCTLTIMEOUT
): {
475 bcmerror
= BCME_BADARG
;
477 dhd_os_set_ioctl_resp_timeout((unsigned int)int_val
);
482 case IOV_SVAL(IOV_HCI_CMD
): {
483 amp_hci_cmd_t
*cmd
= (amp_hci_cmd_t
*)arg
;
485 /* sanity check: command preamble present */
486 if (len
< HCI_CMD_PREAMBLE_SIZE
)
487 return BCME_BUFTOOSHORT
;
489 /* sanity check: command parameters are present */
490 if (len
< (int)(HCI_CMD_PREAMBLE_SIZE
+ cmd
->plen
))
491 return BCME_BUFTOOSHORT
;
493 dhd_bta_docmd(dhd_pub
, cmd
, len
);
497 case IOV_SVAL(IOV_HCI_ACL_DATA
): {
498 amp_hci_ACL_data_t
*ACL_data
= (amp_hci_ACL_data_t
*)arg
;
500 /* sanity check: HCI header present */
501 if (len
< HCI_ACL_DATA_PREAMBLE_SIZE
)
502 return BCME_BUFTOOSHORT
;
504 /* sanity check: ACL data is present */
505 if (len
< (int)(HCI_ACL_DATA_PREAMBLE_SIZE
+ ACL_data
->dlen
))
506 return BCME_BUFTOOSHORT
;
508 dhd_bta_tx_hcidata(dhd_pub
, ACL_data
, len
);
514 case IOV_GVAL(IOV_PROPTXSTATUS_ENABLE
):
515 int_val
= dhd_pub
->wlfc_enabled
? 1 : 0;
516 bcopy(&int_val
, arg
, val_size
);
519 case IOV_SVAL(IOV_PROPTXSTATUS_ENABLE
):
520 dhd_pub
->wlfc_enabled
= int_val
? 1 : 0;
523 case IOV_GVAL(IOV_PROPTXSTATUS_MODE
): {
524 athost_wl_status_info_t
*wlfc
=
525 (athost_wl_status_info_t
*)dhd_pub
->wlfc_state
;
526 int_val
= dhd_pub
->wlfc_state
? (int32
)wlfc
->proptxstatus_mode
: 0;
527 bcopy(&int_val
, arg
, val_size
);
531 case IOV_SVAL(IOV_PROPTXSTATUS_MODE
):
532 if (dhd_pub
->wlfc_state
) {
533 athost_wl_status_info_t
*wlfc
=
534 (athost_wl_status_info_t
*)dhd_pub
->wlfc_state
;
535 wlfc
->proptxstatus_mode
= int_val
& 0xff;
539 case IOV_GVAL(IOV_QMON_TIME_THRES
): {
540 int_val
= dhd_qmon_thres(dhd_pub
, FALSE
, 0);
541 bcopy(&int_val
, arg
, val_size
);
545 case IOV_SVAL(IOV_QMON_TIME_THRES
): {
546 dhd_qmon_thres(dhd_pub
, TRUE
, int_val
);
550 case IOV_GVAL(IOV_QMON_TIME_PERCENT
): {
551 int_val
= dhd_qmon_getpercent(dhd_pub
);
552 bcopy(&int_val
, arg
, val_size
);
555 #endif /* QMONITOR */
556 #endif /* PROP_TXSTATUS */
558 case IOV_GVAL(IOV_BUS_TYPE
):
559 /* The dhd application queries the driver to check if its usb or sdio. */
561 int_val
= BUS_TYPE_USB
;
563 int_val
= BUS_TYPE_SDIO
;
564 bcopy(&int_val
, arg
, val_size
);
569 case IOV_GVAL(IOV_WLPKTDLYSTAT_SZ
):
570 int_val
= dhd_pub
->htsfdlystat_sz
;
571 bcopy(&int_val
, arg
, val_size
);
574 case IOV_SVAL(IOV_WLPKTDLYSTAT_SZ
):
575 dhd_pub
->htsfdlystat_sz
= int_val
& 0xff;
576 printf("Setting tsfdlystat_sz:%d\n", dhd_pub
->htsfdlystat_sz
);
579 case IOV_SVAL(IOV_CHANGEMTU
):
581 bcmerror
= dhd_change_mtu(dhd_pub
, int_val
, 0);
584 case IOV_GVAL(IOV_HOSTREORDER_FLOWS
):
587 uint8
*ptr
= (uint8
*)arg
;
591 for (i
= 0; i
< WLHOST_REORDERDATA_MAXFLOWS
; i
++) {
592 if (dhd_pub
->reorder_bufs
[i
] != NULL
) {
593 *ptr
= dhd_pub
->reorder_bufs
[i
]->flow_id
;
604 bcmerror
= BCME_UNSUPPORTED
;
609 DHD_TRACE(("%s: actionid %d, bcmerror %d\n", __FUNCTION__
, actionid
, bcmerror
));
613 /* Store the status of a connection attempt for later retrieval by an iovar */
615 dhd_store_conn_status(uint32 event
, uint32 status
, uint32 reason
)
617 /* Do not overwrite a WLC_E_PRUNE with a WLC_E_SET_SSID
618 * because an encryption/rsn mismatch results in both events, and
619 * the important information is in the WLC_E_PRUNE.
621 if (!(event
== WLC_E_SET_SSID
&& status
== WLC_E_STATUS_FAIL
&&
622 dhd_conn_event
== WLC_E_PRUNE
)) {
623 dhd_conn_event
= event
;
624 dhd_conn_status
= status
;
625 dhd_conn_reason
= reason
;
630 dhd_prec_enq(dhd_pub_t
*dhdp
, struct pktq
*q
, void *pkt
, int prec
)
633 int eprec
= -1; /* precedence to evict from */
636 /* Fast case, precedence queue is not full and we are also not
637 * exceeding total queue length
639 if (!pktq_pfull(q
, prec
) && !pktq_full(q
)) {
640 pktq_penq(q
, prec
, pkt
);
644 /* Determine precedence from which to evict packet, if any */
645 if (pktq_pfull(q
, prec
))
647 else if (pktq_full(q
)) {
648 p
= pktq_peek_tail(q
, &eprec
);
650 if (eprec
> prec
|| eprec
< 0)
654 /* Evict if needed */
656 /* Detect queueing to unconfigured precedence */
657 ASSERT(!pktq_pempty(q
, eprec
));
658 discard_oldest
= AC_BITMAP_TST(dhdp
->wme_dp
, eprec
);
659 if (eprec
== prec
&& !discard_oldest
)
660 return FALSE
; /* refuse newer (incoming) packet */
661 /* Evict packet according to discard policy */
662 p
= discard_oldest
? pktq_pdeq(q
, eprec
) : pktq_pdeq_tail(q
, eprec
);
665 PKTFREE(dhdp
->osh
, p
, TRUE
);
669 p
= pktq_penq(q
, prec
, pkt
);
676 * Functions to drop proper pkts from queue:
677 * If one pkt in queue is non-fragmented, drop first non-fragmented pkt only
678 * If all pkts in queue are all fragmented, find and drop one whole set fragmented pkts
679 * If can't find pkts matching upper 2 cases, drop first pkt anyway
682 dhd_prec_drop_pkts(osl_t
*osh
, struct pktq
*pq
, int prec
)
684 struct pktq_prec
*q
= NULL
;
685 void *p
, *prev
= NULL
, *next
= NULL
, *first
= NULL
, *last
= NULL
, *prev_first
= NULL
;
686 pkt_frag_t frag_info
;
689 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
698 frag_info
= pkt_frag_info(osh
, p
);
699 if (frag_info
== DHD_PKT_FRAG_NONE
) {
701 } else if (frag_info
== DHD_PKT_FRAG_FIRST
) {
703 /* No last frag pkt, use prev as last */
709 } else if (frag_info
== DHD_PKT_FRAG_LAST
) {
720 if ((p
== NULL
) || ((frag_info
!= DHD_PKT_FRAG_NONE
) && !(first
&& last
))) {
721 /* Not found matching pkts, use oldest */
727 if (frag_info
== DHD_PKT_FRAG_NONE
) {
740 PKTFREE(osh
, p
, TRUE
);
748 if (prev_first
== NULL
) {
749 if ((q
->head
= next
) == NULL
)
752 PKTSETLINK(prev_first
, next
);
759 dhd_iovar_op(dhd_pub_t
*dhd_pub
, const char *name
,
760 void *params
, int plen
, void *arg
, int len
, bool set
)
764 const bcm_iovar_t
*vi
= NULL
;
767 DHD_TRACE(("%s: Enter\n", __FUNCTION__
));
772 /* Get MUST have return space */
773 ASSERT(set
|| (arg
&& len
));
775 /* Set does NOT take qualifiers */
776 ASSERT(!set
|| (!params
&& !plen
));
778 if ((vi
= bcm_iovar_lookup(dhd_iovars
, name
)) == NULL
) {
779 bcmerror
= BCME_UNSUPPORTED
;
783 DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__
,
784 name
, (set
? "set" : "get"), len
, plen
));
786 /* set up 'params' pointer in case this is a set command so that
787 * the convenience int and bool code can be common to set and get
789 if (params
== NULL
) {
794 if (vi
->type
== IOVT_VOID
)
796 else if (vi
->type
== IOVT_BUFFER
)
799 /* all other types are integer sized */
800 val_size
= sizeof(int);
802 actionid
= set
? IOV_SVAL(vi
->varid
) : IOV_GVAL(vi
->varid
);
804 bcmerror
= dhd_doiovar(dhd_pub
, vi
, actionid
, name
, params
, plen
, arg
, len
, val_size
);
811 dhd_ioctl(dhd_pub_t
* dhd_pub
, dhd_ioctl_t
*ioc
, void * buf
, uint buflen
)
815 DHD_TRACE(("%s: Enter\n", __FUNCTION__
));
823 if (buflen
< sizeof(int))
824 bcmerror
= BCME_BUFTOOSHORT
;
826 *(int*)buf
= DHD_IOCTL_MAGIC
;
829 case DHD_GET_VERSION
:
830 if (buflen
< sizeof(int))
831 bcmerror
= BCME_BUFTOOSHORT
;
833 *(int*)buf
= DHD_IOCTL_VERSION
;
841 /* scan past the name to any arguments */
842 for (arg
= buf
, arglen
= buflen
; *arg
&& arglen
; arg
++, arglen
--)
846 bcmerror
= BCME_BUFTOOSHORT
;
850 /* account for the NUL terminator */
853 /* call with the appropriate arguments */
854 if (ioc
->cmd
== DHD_GET_VAR
)
855 bcmerror
= dhd_iovar_op(dhd_pub
, buf
, arg
, arglen
,
856 buf
, buflen
, IOV_GET
);
858 bcmerror
= dhd_iovar_op(dhd_pub
, buf
, NULL
, 0, arg
, arglen
, IOV_SET
);
859 if (bcmerror
!= BCME_UNSUPPORTED
)
862 /* not in generic table, try protocol module */
863 if (ioc
->cmd
== DHD_GET_VAR
)
864 bcmerror
= dhd_prot_iovar_op(dhd_pub
, buf
, arg
,
865 arglen
, buf
, buflen
, IOV_GET
);
867 bcmerror
= dhd_prot_iovar_op(dhd_pub
, buf
,
868 NULL
, 0, arg
, arglen
, IOV_SET
);
869 if (bcmerror
!= BCME_UNSUPPORTED
)
872 /* if still not found, try bus module */
873 if (ioc
->cmd
== DHD_GET_VAR
) {
874 bcmerror
= dhd_bus_iovar_op(dhd_pub
, buf
,
875 arg
, arglen
, buf
, buflen
, IOV_GET
);
877 bcmerror
= dhd_bus_iovar_op(dhd_pub
, buf
,
878 NULL
, 0, arg
, arglen
, IOV_SET
);
885 bcmerror
= BCME_UNSUPPORTED
;
893 wl_show_host_event(wl_event_msg_t
*event
, void *event_data
)
895 uint i
, status
, reason
;
896 bool group
= FALSE
, flush_txq
= FALSE
, link
= FALSE
;
897 const char *auth_str
;
898 const char *event_name
;
900 char err_msg
[256], eabuf
[ETHER_ADDR_STR_LEN
];
901 uint event_type
, flags
, auth_type
, datalen
;
903 event_type
= ntoh32(event
->event_type
);
904 flags
= ntoh16(event
->flags
);
905 status
= ntoh32(event
->status
);
906 reason
= ntoh32(event
->reason
);
907 BCM_REFERENCE(reason
);
908 auth_type
= ntoh32(event
->auth_type
);
909 datalen
= ntoh32(event
->datalen
);
911 /* debug dump of event messages */
912 snprintf(eabuf
, sizeof(eabuf
), "%02x:%02x:%02x:%02x:%02x:%02x",
913 (uchar
)event
->addr
.octet
[0]&0xff,
914 (uchar
)event
->addr
.octet
[1]&0xff,
915 (uchar
)event
->addr
.octet
[2]&0xff,
916 (uchar
)event
->addr
.octet
[3]&0xff,
917 (uchar
)event
->addr
.octet
[4]&0xff,
918 (uchar
)event
->addr
.octet
[5]&0xff);
920 event_name
= "UNKNOWN";
921 for (i
= 0; i
< (uint
)bcmevent_names_size
; i
++)
922 if (bcmevent_names
[i
].event
== event_type
)
923 event_name
= bcmevent_names
[i
].name
;
925 if (flags
& WLC_EVENT_MSG_LINK
)
927 if (flags
& WLC_EVENT_MSG_GROUP
)
929 if (flags
& WLC_EVENT_MSG_FLUSHTXQ
)
932 switch (event_type
) {
936 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name
, eabuf
));
939 case WLC_E_ASSOC_IND
:
940 case WLC_E_REASSOC_IND
:
942 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name
, eabuf
));
947 if (status
== WLC_E_STATUS_SUCCESS
) {
948 DHD_EVENT(("MACEVENT: %s, MAC %s, SUCCESS\n", event_name
, eabuf
));
949 } else if (status
== WLC_E_STATUS_TIMEOUT
) {
950 DHD_EVENT(("MACEVENT: %s, MAC %s, TIMEOUT\n", event_name
, eabuf
));
951 } else if (status
== WLC_E_STATUS_FAIL
) {
952 DHD_EVENT(("MACEVENT: %s, MAC %s, FAILURE, reason %d\n",
953 event_name
, eabuf
, (int)reason
));
955 DHD_EVENT(("MACEVENT: %s, MAC %s, unexpected status %d\n",
956 event_name
, eabuf
, (int)status
));
960 case WLC_E_DEAUTH_IND
:
961 case WLC_E_DISASSOC_IND
:
962 DHD_EVENT(("MACEVENT: %s, MAC %s, reason %d\n", event_name
, eabuf
, (int)reason
));
967 if (auth_type
== DOT11_OPEN_SYSTEM
)
968 auth_str
= "Open System";
969 else if (auth_type
== DOT11_SHARED_KEY
)
970 auth_str
= "Shared Key";
972 snprintf(err_msg
, sizeof(err_msg
), "AUTH unknown: %d", (int)auth_type
);
975 if (event_type
== WLC_E_AUTH_IND
) {
976 DHD_EVENT(("MACEVENT: %s, MAC %s, %s\n", event_name
, eabuf
, auth_str
));
977 } else if (status
== WLC_E_STATUS_SUCCESS
) {
978 DHD_EVENT(("MACEVENT: %s, MAC %s, %s, SUCCESS\n",
979 event_name
, eabuf
, auth_str
));
980 } else if (status
== WLC_E_STATUS_TIMEOUT
) {
981 DHD_EVENT(("MACEVENT: %s, MAC %s, %s, TIMEOUT\n",
982 event_name
, eabuf
, auth_str
));
983 } else if (status
== WLC_E_STATUS_FAIL
) {
984 DHD_EVENT(("MACEVENT: %s, MAC %s, %s, FAILURE, reason %d\n",
985 event_name
, eabuf
, auth_str
, (int)reason
));
987 BCM_REFERENCE(auth_str
);
994 if (status
== WLC_E_STATUS_SUCCESS
) {
995 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name
, eabuf
));
996 } else if (status
== WLC_E_STATUS_FAIL
) {
997 DHD_EVENT(("MACEVENT: %s, failed\n", event_name
));
998 } else if (status
== WLC_E_STATUS_NO_NETWORKS
) {
999 DHD_EVENT(("MACEVENT: %s, no networks found\n", event_name
));
1001 DHD_EVENT(("MACEVENT: %s, unexpected status %d\n",
1002 event_name
, (int)status
));
1006 case WLC_E_BEACON_RX
:
1007 if (status
== WLC_E_STATUS_SUCCESS
) {
1008 DHD_EVENT(("MACEVENT: %s, SUCCESS\n", event_name
));
1009 } else if (status
== WLC_E_STATUS_FAIL
) {
1010 DHD_EVENT(("MACEVENT: %s, FAIL\n", event_name
));
1012 DHD_EVENT(("MACEVENT: %s, status %d\n", event_name
, status
));
1017 DHD_EVENT(("MACEVENT: %s %s\n", event_name
, link
?"UP":"DOWN"));
1018 BCM_REFERENCE(link
);
1021 case WLC_E_MIC_ERROR
:
1022 DHD_EVENT(("MACEVENT: %s, MAC %s, Group %d, Flush %d\n",
1023 event_name
, eabuf
, group
, flush_txq
));
1024 BCM_REFERENCE(group
);
1025 BCM_REFERENCE(flush_txq
);
1028 case WLC_E_ICV_ERROR
:
1029 case WLC_E_UNICAST_DECODE_ERROR
:
1030 case WLC_E_MULTICAST_DECODE_ERROR
:
1031 DHD_EVENT(("MACEVENT: %s, MAC %s\n",
1032 event_name
, eabuf
));
1036 DHD_EVENT(("MACEVENT: %s, RA %s\n", event_name
, eabuf
));
1039 case WLC_E_SCAN_COMPLETE
:
1040 case WLC_E_ASSOC_REQ_IE
:
1041 case WLC_E_ASSOC_RESP_IE
:
1042 case WLC_E_PMKID_CACHE
:
1043 DHD_EVENT(("MACEVENT: %s\n", event_name
));
1046 case WLC_E_PFN_NET_FOUND
:
1047 case WLC_E_PFN_NET_LOST
:
1048 case WLC_E_PFN_SCAN_COMPLETE
:
1049 case WLC_E_PFN_SCAN_NONE
:
1050 case WLC_E_PFN_SCAN_ALLGONE
:
1051 DHD_EVENT(("PNOEVENT: %s\n", event_name
));
1056 DHD_EVENT(("MACEVENT: %s, status %d, reason %d\n",
1057 event_name
, (int)status
, (int)reason
));
1060 #ifdef WIFI_ACT_FRAME
1061 case WLC_E_ACTION_FRAME
:
1062 DHD_TRACE(("MACEVENT: %s Bssid %s\n", event_name
, eabuf
));
1064 #endif /* WIFI_ACT_FRAME */
1067 static uint32 seqnum_prev
= 0;
1068 static uint32 logtrace_seqnum_prev
= 0;
1073 buf
= (uchar
*) event_data
;
1074 memcpy(&hdr
, buf
, MSGTRACE_HDRLEN
);
1076 if (hdr
.version
!= MSGTRACE_VERSION
) {
1077 printf("\nMACEVENT: %s [unsupported version --> "
1078 "dhd version:%d dongle version:%d]\n",
1079 event_name
, MSGTRACE_VERSION
, hdr
.version
);
1080 /* Reset datalen to avoid display below */
1085 if (hdr
.trace_type
== MSGTRACE_HDR_TYPE_MSG
) {
1086 /* There are 2 bytes available at the end of data */
1087 buf
[MSGTRACE_HDRLEN
+ ntoh16(hdr
.len
)] = '\0';
1089 if (ntoh32(hdr
.discarded_bytes
) || ntoh32(hdr
.discarded_printf
)) {
1090 printf("\nWLC_E_TRACE: [Discarded traces in dongle -->"
1091 "discarded_bytes %d discarded_printf %d]\n",
1092 ntoh32(hdr
.discarded_bytes
), ntoh32(hdr
.discarded_printf
));
1095 nblost
= ntoh32(hdr
.seqnum
) - seqnum_prev
- 1;
1097 printf("\nWLC_E_TRACE: [Event lost (msg) --> seqnum %d nblost %d\n",
1098 ntoh32(hdr
.seqnum
), nblost
);
1100 seqnum_prev
= ntoh32(hdr
.seqnum
);
1102 /* Display the trace buffer. Advance from \n to \n to avoid display big
1103 * printf (issue with Linux printk )
1105 p
= (char *)&buf
[MSGTRACE_HDRLEN
];
1106 while (*p
!= '\0' && (s
= strstr(p
, "\n")) != NULL
) {
1111 if (*p
) printf("%s", p
);
1113 /* Reset datalen to avoid display below */
1116 } else if (hdr
.trace_type
== MSGTRACE_HDR_TYPE_LOG
) {
1117 /* Let the standard event printing work for now */
1118 uint32 timestamp
, w
;
1119 if (ntoh32(hdr
.seqnum
) == logtrace_seqnum_prev
) {
1120 printf("\nWLC_E_TRACE: [Event duplicate (log) %d",
1121 logtrace_seqnum_prev
);
1123 nblost
= ntoh32(hdr
.seqnum
) - logtrace_seqnum_prev
- 1;
1125 printf("\nWLC_E_TRACE: [Event lost (log)"
1126 " --> seqnum %d nblost %d\n",
1127 ntoh32(hdr
.seqnum
), nblost
);
1129 logtrace_seqnum_prev
= ntoh32(hdr
.seqnum
);
1131 p
= (char *)&buf
[MSGTRACE_HDRLEN
];
1132 datalen
-= MSGTRACE_HDRLEN
;
1133 w
= ntoh32((uint32
) *p
);
1136 timestamp
= ntoh32((uint32
) *p
);
1137 printf("Logtrace %x timestamp %x %x",
1138 logtrace_seqnum_prev
, timestamp
, w
);
1140 while (datalen
> 4) {
1143 /* Print each word. DO NOT ntoh it. */
1144 printf(" %8.8x", *((uint32
*) p
));
1156 DHD_EVENT(("MACEVENT: %s %d\n", event_name
, ntoh32(*((int *)event_data
))));
1159 case WLC_E_SERVICE_FOUND
:
1160 case WLC_E_P2PO_ADD_DEVICE
:
1161 case WLC_E_P2PO_DEL_DEVICE
:
1162 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name
, eabuf
));
1166 DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, auth %d\n",
1167 event_name
, event_type
, eabuf
, (int)status
, (int)reason
,
1172 /* show any appended data */
1173 if (DHD_BYTES_ON() && DHD_EVENT_ON() && datalen
) {
1174 buf
= (uchar
*) event_data
;
1175 DHD_EVENT((" data (%d) : ", datalen
));
1176 for (i
= 0; i
< datalen
; i
++)
1177 DHD_EVENT((" 0x%02x ", *buf
++));
1181 #endif /* SHOW_EVENTS */
1184 wl_host_event(dhd_pub_t
*dhd_pub
, int *ifidx
, void *pktdata
,
1185 wl_event_msg_t
*event
, void **data_ptr
)
1187 /* check whether packet is a BRCM event pkt */
1188 bcm_event_t
*pvt_data
= (bcm_event_t
*)pktdata
;
1190 uint32 type
, status
, datalen
;
1194 if (bcmp(BRCM_OUI
, &pvt_data
->bcm_hdr
.oui
[0], DOT11_OUI_LEN
)) {
1195 DHD_ERROR(("%s: mismatched OUI, bailing\n", __FUNCTION__
));
1196 return (BCME_ERROR
);
1199 /* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */
1200 if (ntoh16_ua((void *)&pvt_data
->bcm_hdr
.usr_subtype
) != BCMILCP_BCM_SUBTYPE_EVENT
) {
1201 DHD_ERROR(("%s: mismatched subtype, bailing\n", __FUNCTION__
));
1202 return (BCME_ERROR
);
1205 *data_ptr
= &pvt_data
[1];
1206 event_data
= *data_ptr
;
1208 /* memcpy since BRCM event pkt may be unaligned. */
1209 memcpy(event
, &pvt_data
->event
, sizeof(wl_event_msg_t
));
1211 type
= ntoh32_ua((void *)&event
->event_type
);
1212 flags
= ntoh16_ua((void *)&event
->flags
);
1213 status
= ntoh32_ua((void *)&event
->status
);
1214 datalen
= ntoh32_ua((void *)&event
->datalen
);
1215 evlen
= datalen
+ sizeof(bcm_event_t
);
1218 #ifdef PROP_TXSTATUS
1219 case WLC_E_FIFO_CREDIT_MAP
:
1220 dhd_os_wlfc_block(dhd_pub
);
1221 dhd_wlfc_event(dhd_pub
->info
);
1222 dhd_wlfc_FIFOcreditmap_event(dhd_pub
->info
, event_data
);
1223 dhd_os_wlfc_unblock(dhd_pub
);
1224 WLFC_DBGMESG(("WLC_E_FIFO_CREDIT_MAP:(AC0,AC1,AC2,AC3),(BC_MC),(OTHER): "
1225 "(%d,%d,%d,%d),(%d),(%d)\n", event_data
[0], event_data
[1],
1227 event_data
[3], event_data
[4], event_data
[5]));
1233 dhd_if_event_t
*ifevent
= (dhd_if_event_t
*)event_data
;
1235 /* Ignore the event if NOIF is set */
1236 if (ifevent
->flags
& WLC_E_IF_FLAGS_BSSCFG_NOIF
) {
1237 WLFC_DBGMESG(("WLC_E_IF: NO_IF set, event Ignored\r\n"));
1241 #ifdef PROP_TXSTATUS
1243 uint8
* ea
= pvt_data
->eth
.ether_dhost
;
1244 WLFC_DBGMESG(("WLC_E_IF: idx:%d, action:%s, iftype:%s, "
1245 "[%02x:%02x:%02x:%02x:%02x:%02x]\n",
1247 ((ifevent
->action
== WLC_E_IF_ADD
) ? "ADD":"DEL"),
1248 ((ifevent
->is_AP
== 0) ? "STA":"AP "),
1249 ea
[0], ea
[1], ea
[2], ea
[3], ea
[4], ea
[5]));
1252 dhd_os_wlfc_block(dhd_pub
);
1253 if (ifevent
->action
== WLC_E_IF_CHANGE
)
1254 dhd_wlfc_interface_event(dhd_pub
->info
,
1255 eWLFC_MAC_ENTRY_ACTION_UPDATE
,
1256 ifevent
->ifidx
, ifevent
->is_AP
, ea
);
1258 dhd_wlfc_interface_event(dhd_pub
->info
,
1259 ((ifevent
->action
== WLC_E_IF_ADD
) ?
1260 eWLFC_MAC_ENTRY_ACTION_ADD
: eWLFC_MAC_ENTRY_ACTION_DEL
),
1261 ifevent
->ifidx
, ifevent
->is_AP
, ea
);
1262 dhd_os_wlfc_unblock(dhd_pub
);
1264 /* dhd already has created an interface by default, for 0 */
1265 if (ifevent
->ifidx
== 0)
1268 #endif /* PROP_TXSTATUS */
1271 if (wl_cfg80211_is_progress_ifchange()) {
1272 DHD_ERROR(("%s: ifidx %d for %s action %d\n",
1273 __FUNCTION__
, ifevent
->ifidx
,
1274 event
->ifname
, ifevent
->action
));
1275 if (ifevent
->action
== WLC_E_IF_ADD
||
1276 ifevent
->action
== WLC_E_IF_CHANGE
)
1277 wl_cfg80211_notify_ifchange();
1280 #endif /* WL_CFG80211 */
1281 if (ifevent
->ifidx
> 0 && ifevent
->ifidx
< DHD_MAX_IFS
) {
1282 if (ifevent
->action
== WLC_E_IF_ADD
) {
1283 if (dhd_add_if(dhd_pub
->info
, ifevent
->ifidx
,
1284 NULL
, event
->ifname
,
1286 ifevent
->flags
, ifevent
->bssidx
)) {
1287 DHD_ERROR(("%s: dhd_add_if failed!!"
1288 " ifidx: %d for %s\n",
1292 return (BCME_ERROR
);
1295 else if (ifevent
->action
== WLC_E_IF_DEL
)
1296 dhd_del_if(dhd_pub
->info
, ifevent
->ifidx
);
1298 #ifndef PROP_TXSTATUS
1299 DHD_ERROR(("%s: Invalid ifidx %d for %s\n",
1300 __FUNCTION__
, ifevent
->ifidx
, event
->ifname
));
1301 #endif /* !PROP_TXSTATUS */
1304 /* send up the if event: btamp user needs it */
1305 *ifidx
= dhd_ifname2idx(dhd_pub
->info
, event
->ifname
);
1306 /* push up to external supp/auth */
1307 dhd_event(dhd_pub
->info
, (char *)pvt_data
, evlen
, *ifidx
);
1312 case WLC_E_HTSFSYNC
:
1313 htsf_update(dhd_pub
->info
, event_data
);
1315 #endif /* WLMEDIA_HTSF */
1316 case WLC_E_NDIS_LINK
: {
1317 uint32 temp
= hton32(WLC_E_LINK
);
1319 memcpy((void *)(&pvt_data
->event
.event_type
), &temp
,
1320 sizeof(pvt_data
->event
.event_type
));
1322 case WLC_E_PFN_NET_FOUND
:
1323 case WLC_E_PFN_NET_LOST
:
1325 case WLC_E_PFN_BSSID_NET_FOUND
:
1326 case WLC_E_PFN_BSSID_NET_LOST
:
1327 case WLC_E_PFN_BEST_BATCHING
:
1329 dhd_pno_event_handler(dhd_pub
, event
, (void *)event_data
);
1332 /* These are what external supplicant/authenticator wants */
1336 case WLC_E_DEAUTH_IND
:
1337 case WLC_E_DISASSOC
:
1338 case WLC_E_DISASSOC_IND
:
1339 DHD_EVENT(("%s: Link event %d, flags %x, status %x\n",
1340 __FUNCTION__
, type
, flags
, status
));
1343 *ifidx
= dhd_ifname2idx(dhd_pub
->info
, event
->ifname
);
1344 /* push up to external supp/auth */
1345 dhd_event(dhd_pub
->info
, (char *)pvt_data
, evlen
, *ifidx
);
1346 DHD_TRACE(("%s: MAC event %d, flags %x, status %x\n",
1347 __FUNCTION__
, type
, flags
, status
));
1348 BCM_REFERENCE(flags
);
1349 BCM_REFERENCE(status
);
1351 /* put it back to WLC_E_NDIS_LINK */
1352 if (type
== WLC_E_NDIS_LINK
) {
1355 temp
= ntoh32_ua((void *)&event
->event_type
);
1356 DHD_TRACE(("Converted to WLC_E_LINK type %d\n", temp
));
1358 temp
= ntoh32(WLC_E_NDIS_LINK
);
1359 memcpy((void *)(&pvt_data
->event
.event_type
), &temp
,
1360 sizeof(pvt_data
->event
.event_type
));
1366 wl_show_host_event(event
, (void *)event_data
);
1367 #endif /* SHOW_EVENTS */
1373 wl_event_to_host_order(wl_event_msg_t
* evt
)
1375 /* Event struct members passed from dongle to host are stored in network
1376 * byte order. Convert all members to host-order.
1378 evt
->event_type
= ntoh32(evt
->event_type
);
1379 evt
->flags
= ntoh16(evt
->flags
);
1380 evt
->status
= ntoh32(evt
->status
);
1381 evt
->reason
= ntoh32(evt
->reason
);
1382 evt
->auth_type
= ntoh32(evt
->auth_type
);
1383 evt
->datalen
= ntoh32(evt
->datalen
);
1384 evt
->version
= ntoh16(evt
->version
);
1388 dhd_print_buf(void *pbuf
, int len
, int bytes_per_line
)
1392 unsigned char *buf
= pbuf
;
1394 if (bytes_per_line
== 0) {
1395 bytes_per_line
= len
;
1398 for (i
= 0; i
< len
; i
++) {
1399 printf("%2.2x", *buf
++);
1401 if (j
== bytes_per_line
) {
1409 #endif /* DHD_DEBUG */
1413 #define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
1416 #ifdef PKT_FILTER_SUPPORT
1417 /* Convert user's input in hex pattern to byte-size mask */
1419 wl_pattern_atoh(char *src
, char *dst
)
1422 if (strncmp(src
, "0x", 2) != 0 &&
1423 strncmp(src
, "0X", 2) != 0) {
1424 DHD_ERROR(("Mask invalid format. Needs to start with 0x\n"));
1427 src
= src
+ 2; /* Skip past 0x */
1428 if (strlen(src
) % 2 != 0) {
1429 DHD_ERROR(("Mask invalid format. Needs to be of even length\n"));
1432 for (i
= 0; *src
!= '\0'; i
++) {
1434 bcm_strncpy_s(num
, sizeof(num
), src
, 2);
1436 dst
[i
] = (uint8
)strtoul(num
, NULL
, 16);
1443 dhd_pktfilter_offload_enable(dhd_pub_t
* dhd
, char *arg
, int enable
, int master_mode
)
1450 char *arg_save
= 0, *arg_org
= 0;
1453 wl_pkt_filter_enable_t enable_parm
;
1454 wl_pkt_filter_enable_t
* pkt_filterp
;
1459 if (!(arg_save
= MALLOC(dhd
->osh
, strlen(arg
) + 1))) {
1460 DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__
));
1464 memcpy(arg_save
, arg
, strlen(arg
) + 1);
1466 argv
[i
] = bcmstrtok(&arg_save
, " ", 0);
1469 if (argv
[i
] == NULL
) {
1470 DHD_ERROR(("No args provided\n"));
1474 str
= "pkt_filter_enable";
1475 str_len
= strlen(str
);
1476 bcm_strncpy_s(buf
, sizeof(buf
), str
, str_len
);
1477 buf
[str_len
] = '\0';
1478 buf_len
= str_len
+ 1;
1480 pkt_filterp
= (wl_pkt_filter_enable_t
*)(buf
+ str_len
+ 1);
1482 /* Parse packet filter id. */
1483 enable_parm
.id
= htod32(strtoul(argv
[i
], NULL
, 0));
1484 if (dhd_conf_del_pkt_filter(dhd
, enable_parm
.id
))
1487 /* Parse enable/disable value. */
1488 enable_parm
.enable
= htod32(enable
);
1490 buf_len
+= sizeof(enable_parm
);
1491 memcpy((char *)pkt_filterp
,
1493 sizeof(enable_parm
));
1495 /* Enable/disable the specified filter. */
1496 rc
= dhd_wl_ioctl_cmd(dhd
, WLC_SET_VAR
, buf
, buf_len
, TRUE
, 0);
1497 rc
= rc
>= 0 ? 0 : rc
;
1499 DHD_TRACE(("%s: failed to %s pktfilter %s, retcode = %d\n",
1500 __FUNCTION__
, enable
?"enable":"disable", arg
, rc
));
1502 DHD_TRACE(("%s: successfully %s pktfilter %s\n",
1503 __FUNCTION__
, enable
?"enable":"disable", arg
));
1505 /* Contorl the master mode */
1506 bcm_mkiovar("pkt_filter_mode", (char *)&master_mode
, 4, buf
, sizeof(buf
));
1507 rc
= dhd_wl_ioctl_cmd(dhd
, WLC_SET_VAR
, buf
, sizeof(buf
), TRUE
, 0);
1508 rc
= rc
>= 0 ? 0 : rc
;
1510 DHD_TRACE(("%s: failed to set pkt_filter_mode %d, retcode = %d\n",
1511 __FUNCTION__
, master_mode
, rc
));
1515 MFREE(dhd
->osh
, arg_org
, strlen(arg
) + 1);
1519 dhd_pktfilter_offload_set(dhd_pub_t
* dhd
, char *arg
)
1522 wl_pkt_filter_t pkt_filter
;
1523 wl_pkt_filter_t
*pkt_filterp
;
1528 uint32 pattern_size
;
1529 char *argv
[8], * buf
= 0;
1531 char *arg_save
= 0, *arg_org
= 0;
1532 #define BUF_SIZE 2048
1537 if (!(arg_save
= MALLOC(dhd
->osh
, strlen(arg
) + 1))) {
1538 DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__
));
1544 if (!(buf
= MALLOC(dhd
->osh
, BUF_SIZE
))) {
1545 DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__
));
1549 memcpy(arg_save
, arg
, strlen(arg
) + 1);
1551 if (strlen(arg
) > BUF_SIZE
) {
1552 DHD_ERROR(("Not enough buffer %d < %d\n", (int)strlen(arg
), (int)sizeof(buf
)));
1556 argv
[i
] = bcmstrtok(&arg_save
, " ", 0);
1558 argv
[i
] = bcmstrtok(&arg_save
, " ", 0);
1561 if (argv
[i
] == NULL
) {
1562 DHD_ERROR(("No args provided\n"));
1566 str
= "pkt_filter_add";
1567 str_len
= strlen(str
);
1568 bcm_strncpy_s(buf
, BUF_SIZE
, str
, str_len
);
1569 buf
[ str_len
] = '\0';
1570 buf_len
= str_len
+ 1;
1572 pkt_filterp
= (wl_pkt_filter_t
*) (buf
+ str_len
+ 1);
1574 /* Parse packet filter id. */
1575 pkt_filter
.id
= htod32(strtoul(argv
[i
], NULL
, 0));
1576 if (dhd_conf_del_pkt_filter(dhd
, pkt_filter
.id
))
1579 if (argv
[++i
] == NULL
) {
1580 DHD_ERROR(("Polarity not provided\n"));
1584 /* Parse filter polarity. */
1585 pkt_filter
.negate_match
= htod32(strtoul(argv
[i
], NULL
, 0));
1587 if (argv
[++i
] == NULL
) {
1588 DHD_ERROR(("Filter type not provided\n"));
1592 /* Parse filter type. */
1593 pkt_filter
.type
= htod32(strtoul(argv
[i
], NULL
, 0));
1595 if (argv
[++i
] == NULL
) {
1596 DHD_ERROR(("Offset not provided\n"));
1600 /* Parse pattern filter offset. */
1601 pkt_filter
.u
.pattern
.offset
= htod32(strtoul(argv
[i
], NULL
, 0));
1603 if (argv
[++i
] == NULL
) {
1604 DHD_ERROR(("Bitmask not provided\n"));
1608 /* Parse pattern filter mask. */
1610 htod32(wl_pattern_atoh(argv
[i
], (char *) pkt_filterp
->u
.pattern
.mask_and_pattern
));
1612 if (argv
[++i
] == NULL
) {
1613 DHD_ERROR(("Pattern not provided\n"));
1617 /* Parse pattern filter pattern. */
1619 htod32(wl_pattern_atoh(argv
[i
],
1620 (char *) &pkt_filterp
->u
.pattern
.mask_and_pattern
[mask_size
]));
1622 if (mask_size
!= pattern_size
) {
1623 DHD_ERROR(("Mask and pattern not the same size\n"));
1627 pkt_filter
.u
.pattern
.size_bytes
= mask_size
;
1628 buf_len
+= WL_PKT_FILTER_FIXED_LEN
;
1629 buf_len
+= (WL_PKT_FILTER_PATTERN_FIXED_LEN
+ 2 * mask_size
);
1631 /* Keep-alive attributes are set in local variable (keep_alive_pkt), and
1632 ** then memcpy'ed into buffer (keep_alive_pktp) since there is no
1633 ** guarantee that the buffer is properly aligned.
1635 memcpy((char *)pkt_filterp
,
1637 WL_PKT_FILTER_FIXED_LEN
+ WL_PKT_FILTER_PATTERN_FIXED_LEN
);
1639 rc
= dhd_wl_ioctl_cmd(dhd
, WLC_SET_VAR
, buf
, buf_len
, TRUE
, 0);
1640 rc
= rc
>= 0 ? 0 : rc
;
1643 DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
1644 __FUNCTION__
, arg
, rc
));
1646 DHD_TRACE(("%s: successfully added pktfilter %s\n",
1647 __FUNCTION__
, arg
));
1651 MFREE(dhd
->osh
, arg_org
, strlen(arg
) + 1);
1654 MFREE(dhd
->osh
, buf
, BUF_SIZE
);
1657 void dhd_pktfilter_offload_delete(dhd_pub_t
*dhd
, int id
)
1662 bcm_mkiovar("pkt_filter_delete", (char *)&id
, 4, iovbuf
, sizeof(iovbuf
));
1663 ret
= dhd_wl_ioctl_cmd(dhd
, WLC_SET_VAR
, iovbuf
, sizeof(iovbuf
), TRUE
, 0);
1665 DHD_ERROR(("%s: Failed to delete filter ID:%d, ret=%d\n",
1666 __FUNCTION__
, id
, ret
));
1669 DHD_TRACE(("%s: successfully deleted pktfilter %d\n",
1672 #endif /* PKT_FILTER_SUPPORT */
1674 /* ========================== */
1675 /* ==== ARP OFFLOAD SUPPORT = */
1676 /* ========================== */
1677 #ifdef ARP_OFFLOAD_SUPPORT
1679 dhd_arp_offload_set(dhd_pub_t
* dhd
, int arp_mode
)
1684 bcm_mkiovar("arp_ol", (char *)&arp_mode
, 4, iovbuf
, sizeof(iovbuf
));
1685 retcode
= dhd_wl_ioctl_cmd(dhd
, WLC_SET_VAR
, iovbuf
, sizeof(iovbuf
), TRUE
, 0);
1686 retcode
= retcode
>= 0 ? 0 : retcode
;
1688 DHD_TRACE(("%s: failed to set ARP offload mode to 0x%x, retcode = %d\n",
1689 __FUNCTION__
, arp_mode
, retcode
));
1691 DHD_TRACE(("%s: successfully set ARP offload mode to 0x%x\n",
1692 __FUNCTION__
, arp_mode
));
1696 dhd_arp_offload_enable(dhd_pub_t
* dhd
, int arp_enable
)
1701 bcm_mkiovar("arpoe", (char *)&arp_enable
, 4, iovbuf
, sizeof(iovbuf
));
1702 retcode
= dhd_wl_ioctl_cmd(dhd
, WLC_SET_VAR
, iovbuf
, sizeof(iovbuf
), TRUE
, 0);
1703 retcode
= retcode
>= 0 ? 0 : retcode
;
1705 DHD_TRACE(("%s: failed to enabe ARP offload to %d, retcode = %d\n",
1706 __FUNCTION__
, arp_enable
, retcode
));
1708 DHD_TRACE(("%s: successfully enabed ARP offload to %d\n",
1709 __FUNCTION__
, arp_enable
));
1712 bcm_mkiovar("arp_version", 0, 0, iovbuf
, sizeof(iovbuf
));
1713 retcode
= dhd_wl_ioctl_cmd(dhd
, WLC_GET_VAR
, iovbuf
, sizeof(iovbuf
), FALSE
, 0);
1715 DHD_INFO(("%s: fail to get version (maybe version 1:retcode = %d\n",
1716 __FUNCTION__
, retcode
));
1717 dhd
->arp_version
= 1;
1720 memcpy(&version
, iovbuf
, sizeof(version
));
1721 DHD_INFO(("%s: ARP Version= %x\n", __FUNCTION__
, version
));
1722 dhd
->arp_version
= version
;
1728 dhd_aoe_arp_clr(dhd_pub_t
*dhd
, int idx
)
1732 char iovbuf
[DHD_IOVAR_BUF_SIZE
];
1734 if (dhd
== NULL
) return;
1735 if (dhd
->arp_version
== 1)
1738 iov_len
= bcm_mkiovar("arp_table_clear", 0, 0, iovbuf
, sizeof(iovbuf
));
1739 if ((ret
= dhd_wl_ioctl_cmd(dhd
, WLC_SET_VAR
, iovbuf
, iov_len
, TRUE
, idx
)) < 0)
1740 DHD_ERROR(("%s failed code %d\n", __FUNCTION__
, ret
));
1744 dhd_aoe_hostip_clr(dhd_pub_t
*dhd
, int idx
)
1748 char iovbuf
[DHD_IOVAR_BUF_SIZE
];
1750 if (dhd
== NULL
) return;
1751 if (dhd
->arp_version
== 1)
1754 iov_len
= bcm_mkiovar("arp_hostip_clear", 0, 0, iovbuf
, sizeof(iovbuf
));
1755 if ((ret
= dhd_wl_ioctl_cmd(dhd
, WLC_SET_VAR
, iovbuf
, iov_len
, TRUE
, idx
)) < 0)
1756 DHD_ERROR(("%s failed code %d\n", __FUNCTION__
, ret
));
1760 dhd_arp_offload_add_ip(dhd_pub_t
*dhd
, uint32 ipaddr
, int idx
)
1763 char iovbuf
[DHD_IOVAR_BUF_SIZE
];
1767 if (dhd
== NULL
) return;
1768 if (dhd
->arp_version
== 1)
1770 iov_len
= bcm_mkiovar("arp_hostip", (char *)&ipaddr
,
1771 sizeof(ipaddr
), iovbuf
, sizeof(iovbuf
));
1772 retcode
= dhd_wl_ioctl_cmd(dhd
, WLC_SET_VAR
, iovbuf
, iov_len
, TRUE
, idx
);
1775 DHD_TRACE(("%s: ARP ip addr add failed, retcode = %d\n",
1776 __FUNCTION__
, retcode
));
1778 DHD_TRACE(("%s: sARP H ipaddr entry added \n",
1783 dhd_arp_get_arp_hostip_table(dhd_pub_t
*dhd
, void *buf
, int buflen
, int idx
)
1787 uint32
*ptr32
= buf
;
1788 bool clr_bottom
= FALSE
;
1792 if (dhd
== NULL
) return -1;
1793 if (dhd
->arp_version
== 1)
1796 iov_len
= bcm_mkiovar("arp_hostip", 0, 0, buf
, buflen
);
1797 BCM_REFERENCE(iov_len
);
1798 retcode
= dhd_wl_ioctl_cmd(dhd
, WLC_GET_VAR
, buf
, buflen
, FALSE
, idx
);
1801 DHD_TRACE(("%s: ioctl WLC_GET_VAR error %d\n",
1802 __FUNCTION__
, retcode
));
1807 /* clean up the buf, ascii reminder */
1808 for (i
= 0; i
< MAX_IPV4_ENTRIES
; i
++) {
1820 #endif /* ARP_OFFLOAD_SUPPORT */
1822 * Neighbor Discovery Offload: enable NDO feature
1823 * Called by ipv6 event handler when interface comes up/goes down
1826 dhd_ndo_enable(dhd_pub_t
* dhd
, int ndo_enable
)
1828 char iovbuf
[DHD_IOVAR_BUF_SIZE
];
1834 bcm_mkiovar("ndoe", (char *)&ndo_enable
, 4, iovbuf
, sizeof(iovbuf
));
1835 retcode
= dhd_wl_ioctl_cmd(dhd
, WLC_SET_VAR
, iovbuf
, sizeof(iovbuf
), TRUE
, 0);
1837 DHD_ERROR(("%s: failed to enabe ndo to %d, retcode = %d\n",
1838 __FUNCTION__
, ndo_enable
, retcode
));
1840 DHD_TRACE(("%s: successfully enabed ndo offload to %d\n",
1841 __FUNCTION__
, ndo_enable
));
1847 * Neighbor Discover Offload: add host ipv6 ip into firmware
1848 * Called by ipv6 event handler when interface comes up
1851 dhd_ndo_add_ip(dhd_pub_t
*dhd
, char* ipv6addr
, int idx
)
1854 char iovbuf
[DHD_IOVAR_BUF_SIZE
];
1857 if (dhd
== NULL
|| ipv6addr
== NULL
)
1860 iov_len
= bcm_mkiovar("nd_hostip", ipv6addr
,
1861 IPV6_ADDR_LEN
, iovbuf
, sizeof(iovbuf
));
1862 retcode
= dhd_wl_ioctl_cmd(dhd
, WLC_SET_VAR
, iovbuf
, iov_len
, TRUE
, idx
);
1865 DHD_ERROR(("%s: ndo ip addr add failed, retcode = %d\n",
1866 __FUNCTION__
, retcode
));
1868 DHD_ERROR(("%s: ndo ipaddr entry added \n",
1873 * Neighbor Discover Offload: disable NDO feature
1874 * Called by ipv6 event handler when interface goes down
1877 dhd_ndo_remove_ip(dhd_pub_t
*dhd
, int idx
)
1880 char iovbuf
[DHD_IOVAR_BUF_SIZE
];
1886 iov_len
= bcm_mkiovar("nd_hostip_clear", (char *)NULL
,
1887 0, iovbuf
, sizeof(iovbuf
));
1888 retcode
= dhd_wl_ioctl_cmd(dhd
, WLC_SET_VAR
, iovbuf
, iov_len
, TRUE
, idx
);
1891 DHD_ERROR(("%s: ndo ip addr remove failed, retcode = %d\n",
1892 __FUNCTION__
, retcode
));
1894 DHD_TRACE(("%s: ndo ipaddr entry removed \n",
1900 /* send up locally generated event */
1902 dhd_sendup_event_common(dhd_pub_t
*dhdp
, wl_event_msg_t
*event
, void *data
)
1904 switch (ntoh32(event
->event_type
)) {
1906 case WLC_E_BTA_HCI_EVENT
:
1908 #endif /* WLBTAMP */
1913 /* Call per-port handler. */
1914 dhd_sendup_event(dhdp
, event
, data
);
1919 * returns = TRUE if associated, FALSE if not associated
1921 bool dhd_is_associated(dhd_pub_t
*dhd
, void *bss_buf
, int *retval
)
1923 char bssid
[6], zbuf
[6];
1929 ret
= dhd_wl_ioctl_cmd(dhd
, WLC_GET_BSSID
, (char *)&bssid
, ETHER_ADDR_LEN
, FALSE
, 0);
1930 DHD_TRACE((" %s WLC_GET_BSSID ioctl res = %d\n", __FUNCTION__
, ret
));
1932 if (ret
== BCME_NOTASSOCIATED
) {
1933 DHD_TRACE(("%s: not associated! res:%d\n", __FUNCTION__
, ret
));
1942 if ((memcmp(bssid
, zbuf
, ETHER_ADDR_LEN
) != 0)) {
1943 /* STA is assocoated BSSID is non zero */
1946 /* return bss if caller provided buf */
1947 memcpy(bss_buf
, bssid
, ETHER_ADDR_LEN
);
1951 DHD_TRACE(("%s: WLC_GET_BSSID ioctl returned zero bssid\n", __FUNCTION__
));
1957 /* Function to estimate possible DTIM_SKIP value */
1959 dhd_get_suspend_bcn_li_dtim(dhd_pub_t
*dhd
)
1961 int bcn_li_dtim
= 1; /* deafult no dtim skip setting */
1966 /* Check if associated */
1967 if (dhd_is_associated(dhd
, NULL
, NULL
) == FALSE
) {
1968 DHD_TRACE(("%s NOT assoc ret %d\n", __FUNCTION__
, ret
));
1972 /* read associated AP beacon interval */
1973 if ((ret
= dhd_wl_ioctl_cmd(dhd
, WLC_GET_BCNPRD
,
1974 &ap_beacon
, sizeof(ap_beacon
), FALSE
, 0)) < 0) {
1975 DHD_ERROR(("%s get beacon failed code %d\n", __FUNCTION__
, ret
));
1979 /* if associated APs Beacon more that 100msec do no dtim skip */
1980 if (ap_beacon
> MAX_DTIM_SKIP_BEACON_ITERVAL
) {
1981 DHD_ERROR(("%s NO dtim skip for AP with beacon %d ms\n", __FUNCTION__
, ap_beacon
));
1985 /* read associated ap's dtim setup */
1986 if ((ret
= dhd_wl_ioctl_cmd(dhd
, WLC_GET_DTIMPRD
,
1987 &dtim_assoc
, sizeof(dtim_assoc
), FALSE
, 0)) < 0) {
1988 DHD_ERROR(("%s failed code %d\n", __FUNCTION__
, ret
));
1992 /* if not assocated just eixt */
1993 if (dtim_assoc
== 0) {
1997 /* attemp to use platform defined dtim skip interval */
1998 bcn_li_dtim
= dhd
->suspend_bcn_li_dtim
;
2000 /* check if sta listen interval fits into AP dtim */
2001 if (dtim_assoc
> CUSTOM_LISTEN_INTERVAL
) {
2002 /* AP DTIM to big for our Listen Interval : no dtim skiping */
2004 DHD_ERROR(("%s DTIM=%d > Listen=%d : too big ...\n",
2005 __FUNCTION__
, dtim_assoc
, CUSTOM_LISTEN_INTERVAL
));
2009 if ((bcn_li_dtim
* dtim_assoc
) > CUSTOM_LISTEN_INTERVAL
) {
2010 /* Round up dtim_skip to fit into STAs Listen Interval */
2011 bcn_li_dtim
= (int)(CUSTOM_LISTEN_INTERVAL
/ dtim_assoc
);
2012 DHD_TRACE(("%s agjust dtim_skip as %d\n", __FUNCTION__
, bcn_li_dtim
));
2015 DHD_ERROR(("%s beacon=%d bcn_li_dtim=%d DTIM=%d Listen=%d\n",
2016 __FUNCTION__
, ap_beacon
, bcn_li_dtim
, dtim_assoc
, CUSTOM_LISTEN_INTERVAL
));
2022 /* Check if the mode supports STA MODE */
2023 bool dhd_support_sta_mode(dhd_pub_t
*dhd
)
2027 if (!(dhd
->op_mode
& DHD_FLAG_STA_MODE
))
2030 #endif /* WL_CFG80211 */
2034 #if defined(KEEP_ALIVE)
2035 int dhd_keep_alive_onoff(dhd_pub_t
*dhd
)
2039 wl_mkeep_alive_pkt_t mkeep_alive_pkt
= {0};
2040 wl_mkeep_alive_pkt_t
*mkeep_alive_pktp
;
2045 if (!dhd_support_sta_mode(dhd
))
2048 DHD_TRACE(("%s execution\n", __FUNCTION__
));
2050 str
= "mkeep_alive";
2051 str_len
= strlen(str
);
2052 strncpy(buf
, str
, str_len
);
2053 buf
[ str_len
] = '\0';
2054 mkeep_alive_pktp
= (wl_mkeep_alive_pkt_t
*) (buf
+ str_len
+ 1);
2055 mkeep_alive_pkt
.period_msec
= dhd
->conf
->keep_alive_period
;
2056 buf_len
= str_len
+ 1;
2057 mkeep_alive_pkt
.version
= htod16(WL_MKEEP_ALIVE_VERSION
);
2058 mkeep_alive_pkt
.length
= htod16(WL_MKEEP_ALIVE_FIXED_LEN
);
2059 /* Setup keep alive zero for null packet generation */
2060 mkeep_alive_pkt
.keep_alive_id
= 0;
2061 mkeep_alive_pkt
.len_bytes
= 0;
2062 buf_len
+= WL_MKEEP_ALIVE_FIXED_LEN
;
2063 bzero(mkeep_alive_pkt
.data
, sizeof(mkeep_alive_pkt
.data
));
2064 /* Keep-alive attributes are set in local variable (mkeep_alive_pkt), and
2065 * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no
2066 * guarantee that the buffer is properly aligned.
2068 memcpy((char *)mkeep_alive_pktp
, &mkeep_alive_pkt
, WL_MKEEP_ALIVE_FIXED_LEN
);
2070 res
= dhd_wl_ioctl_cmd(dhd
, WLC_SET_VAR
, buf
, buf_len
, TRUE
, 0);
2074 #endif /* defined(KEEP_ALIVE) */
2075 /* Android ComboSCAN support */
2078 * data parsing from ComboScan tlv list
2081 wl_iw_parse_data_tlv(char** list_str
, void *dst
, int dst_size
, const char token
,
2082 int input_size
, int *bytes_left
)
2088 if ((list_str
== NULL
) || (*list_str
== NULL
) ||(bytes_left
== NULL
) || (*bytes_left
< 0)) {
2089 DHD_ERROR(("%s error paramters\n", __FUNCTION__
));
2094 /* Clean all dest bytes */
2095 memset(dst
, 0, dst_size
);
2096 while (*bytes_left
> 0) {
2098 if (str
[0] != token
) {
2099 DHD_TRACE(("%s NOT Type=%d get=%d left_parse=%d \n",
2100 __FUNCTION__
, token
, str
[0], *bytes_left
));
2107 if (input_size
== 1) {
2108 memcpy(dst
, str
, input_size
);
2110 else if (input_size
== 2) {
2111 memcpy(dst
, (char *)htod16(memcpy(&short_temp
, str
, input_size
)),
2114 else if (input_size
== 4) {
2115 memcpy(dst
, (char *)htod32(memcpy(&int_temp
, str
, input_size
)),
2119 *bytes_left
-= input_size
;
2128 * channel list parsing from cscan tlv list
2131 wl_iw_parse_channel_list_tlv(char** list_str
, uint16
* channel_list
,
2132 int channel_num
, int *bytes_left
)
2137 if ((list_str
== NULL
) || (*list_str
== NULL
) ||(bytes_left
== NULL
) || (*bytes_left
< 0)) {
2138 DHD_ERROR(("%s error paramters\n", __FUNCTION__
));
2143 while (*bytes_left
> 0) {
2145 if (str
[0] != CSCAN_TLV_TYPE_CHANNEL_IE
) {
2147 DHD_TRACE(("End channel=%d left_parse=%d %d\n", idx
, *bytes_left
, str
[0]));
2150 /* Get proper CSCAN_TLV_TYPE_CHANNEL_IE */
2156 channel_list
[idx
] = 0x0;
2159 channel_list
[idx
] = (uint16
)str
[0];
2160 DHD_TRACE(("%s channel=%d \n", __FUNCTION__
, channel_list
[idx
]));
2166 DHD_ERROR(("%s Too many channels \n", __FUNCTION__
));
2176 * SSIDs list parsing from cscan tlv list
2179 wl_iw_parse_ssid_list_tlv(char** list_str
, wlc_ssid_t
* ssid
, int max
, int *bytes_left
)
2184 if ((list_str
== NULL
) || (*list_str
== NULL
) || (*bytes_left
< 0)) {
2185 DHD_ERROR(("%s error paramters\n", __FUNCTION__
));
2189 while (*bytes_left
> 0) {
2191 if (str
[0] != CSCAN_TLV_TYPE_SSID_IE
) {
2193 DHD_TRACE(("nssid=%d left_parse=%d %d\n", idx
, *bytes_left
, str
[0]));
2197 /* Get proper CSCAN_TLV_TYPE_SSID_IE */
2202 /* Broadcast SSID */
2203 ssid
[idx
].SSID_len
= 0;
2204 memset((char*)ssid
[idx
].SSID
, 0x0, DOT11_MAX_SSID_LEN
);
2208 DHD_TRACE(("BROADCAST SCAN left=%d\n", *bytes_left
));
2210 else if (str
[0] <= DOT11_MAX_SSID_LEN
) {
2211 /* Get proper SSID size */
2212 ssid
[idx
].SSID_len
= str
[0];
2217 if (ssid
[idx
].SSID_len
> *bytes_left
) {
2218 DHD_ERROR(("%s out of memory range len=%d but left=%d\n",
2219 __FUNCTION__
, ssid
[idx
].SSID_len
, *bytes_left
));
2223 memcpy((char*)ssid
[idx
].SSID
, str
, ssid
[idx
].SSID_len
);
2225 *bytes_left
-= ssid
[idx
].SSID_len
;
2226 str
+= ssid
[idx
].SSID_len
;
2228 DHD_TRACE(("%s :size=%d left=%d\n",
2229 (char*)ssid
[idx
].SSID
, ssid
[idx
].SSID_len
, *bytes_left
));
2232 DHD_ERROR(("### SSID size more that %d\n", str
[0]));
2237 DHD_ERROR(("%s number of SSIDs more that %d\n", __FUNCTION__
, idx
));
2246 /* Parse a comma-separated list from list_str into ssid array, starting
2247 * at index idx. Max specifies size of the ssid array. Parses ssids
2248 * and returns updated idx; if idx >= max not all fit, the excess have
2249 * not been copied. Returns -1 on empty string, or on ssid too long.
2252 wl_iw_parse_ssid_list(char** list_str
, wlc_ssid_t
* ssid
, int idx
, int max
)
2256 if ((list_str
== NULL
) || (*list_str
== NULL
))
2259 for (str
= *list_str
; str
!= NULL
; str
= ptr
) {
2261 /* check for next TAG */
2262 if (!strncmp(str
, GET_CHANNEL
, strlen(GET_CHANNEL
))) {
2263 *list_str
= str
+ strlen(GET_CHANNEL
);
2267 if ((ptr
= strchr(str
, ',')) != NULL
) {
2271 if (strlen(str
) > DOT11_MAX_SSID_LEN
) {
2272 DHD_ERROR(("ssid <%s> exceeds %d\n", str
, DOT11_MAX_SSID_LEN
));
2276 if (strlen(str
) == 0)
2277 ssid
[idx
].SSID_len
= 0;
2280 bzero(ssid
[idx
].SSID
, sizeof(ssid
[idx
].SSID
));
2281 strncpy((char*)ssid
[idx
].SSID
, str
, sizeof(ssid
[idx
].SSID
) - 1);
2282 ssid
[idx
].SSID_len
= strlen(str
);
2290 * Parse channel list from iwpriv CSCAN
2293 wl_iw_parse_channel_list(char** list_str
, uint16
* channel_list
, int channel_num
)
2298 char* endptr
= NULL
;
2300 if ((list_str
== NULL
)||(*list_str
== NULL
))
2305 while (strncmp(str
, GET_NPROBE
, strlen(GET_NPROBE
))) {
2306 val
= (int)strtoul(str
, &endptr
, 0);
2307 if (endptr
== str
) {
2308 printf("could not parse channel number starting at"
2309 " substring \"%s\" in list:\n%s\n",
2313 str
= endptr
+ strspn(endptr
, " ,");
2315 if (num
== channel_num
) {
2316 DHD_ERROR(("too many channels (more than %d) in channel list:\n%s\n",
2317 channel_num
, *list_str
));
2321 channel_list
[num
++] = (uint16
)val
;