diff options
-rw-r--r-- | Kbuild | 20 | ||||
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | bcmutils.c | 8 | ||||
-rw-r--r-- | dhd.h | 5 | ||||
-rwxr-xr-x | dhd_common.c | 68 | ||||
-rw-r--r-- | dhd_custom_google.c | 439 | ||||
-rw-r--r-- | dhd_dbg_ring.c | 4 | ||||
-rw-r--r-- | dhd_dbg_ring.h | 9 | ||||
-rw-r--r-- | dhd_debug.c | 88 | ||||
-rw-r--r-- | dhd_debug.h | 3 | ||||
-rw-r--r-- | dhd_debug_linux.c | 89 | ||||
-rw-r--r-- | dhd_linux.c | 87 | ||||
-rw-r--r-- | dhd_linux_exportfs.c | 17 | ||||
-rw-r--r-- | dhd_linux_platdev.c | 4 | ||||
-rw-r--r-- | dhd_linux_rx.c | 7 | ||||
-rw-r--r-- | dhd_linux_tx.c | 44 | ||||
-rw-r--r-- | dhd_log_dump.c | 18 | ||||
-rw-r--r-- | dhd_log_dump.h | 1 | ||||
-rw-r--r-- | dhd_msgbuf.c | 16 | ||||
-rw-r--r-- | dhd_pcie.c | 30 | ||||
-rw-r--r-- | dhd_pcie.h | 4 | ||||
-rw-r--r-- | dhd_pcie_linux.c | 17 | ||||
-rw-r--r-- | dhd_plat.h | 14 | ||||
-rw-r--r-- | dhd_pno.c | 1 | ||||
-rw-r--r-- | dhd_rtt.c | 181 | ||||
-rw-r--r-- | dhd_rtt.h | 17 | ||||
-rw-r--r-- | wl_android.c | 74 | ||||
-rw-r--r-- | wl_android.h | 4 | ||||
-rw-r--r-- | wl_cfg80211.c | 198 | ||||
-rw-r--r-- | wl_cfg80211.h | 40 | ||||
-rwxr-xr-x | wl_cfg_cellavoid.c | 46 | ||||
-rw-r--r-- | wl_cfgnan.c | 12 | ||||
-rw-r--r-- | wl_cfgnan.h | 10 | ||||
-rw-r--r-- | wl_cfgscan.c | 145 | ||||
-rw-r--r-- | wl_cfgscan.h | 2 | ||||
-rwxr-xr-x | wl_cfgvendor.c | 359 | ||||
-rw-r--r-- | wl_cfgvendor.h | 7 | ||||
-rw-r--r-- | wl_cfgvif.c | 43 | ||||
-rw-r--r-- | wl_cfgvif.h | 2 | ||||
-rw-r--r-- | wl_roam.c | 17 |
40 files changed, 1786 insertions, 368 deletions
@@ -284,7 +284,7 @@ ifneq ($(CONFIG_BCMDHD_PCIE),) DHDCFLAGS += -DDHD_TX_CPL_BOUND=64 DHDCFLAGS += -DDHD_TX_POST_BOUND=128 DHDCFLAGS += -DDHD_RX_CPL_POST_BOUND=156 - DHDCFLAGS += -DDHD_CTRL_CPL_POST_BOUND=64 + DHDCFLAGS += -DDHD_CTRL_CPL_POST_BOUND=8 endif ifneq ($(CONFIG_FIB_RULES),) @@ -298,6 +298,8 @@ DHDCFLAGS += -DDHD_HAL_RING_DUMP_MEMDUMP DHDCFLAGS += -DDHD_DUMP_START_COMMAND # Enable pktid logging DHDCFLAGS += -DDHD_MAP_PKTID_LOGGING +# Skip coredump for certain health check traps +DHDCFLAGS += -DDHD_SKIP_COREDUMP_ON_HC else DHDCFLAGS += -DDHD_FILE_DUMP_EVENT # The debug dump file path is blank in DHD, it is defined in HAL. @@ -384,9 +386,9 @@ DHDCFLAGS += -DWL_P2P_RAND #Custom Mapping of DSCP to User Priority DHDCFLAGS += -DWL_CUSTOM_MAPPING_OF_DSCP # Enable below define for production -# ifneq ($(CONFIG_SOC_GOOGLE),) -# DHDCFLAGS += -DMACADDR_PROVISION_ENFORCED -# endif +ifneq ($(CONFIG_SOC_GOOGLE),) +DHDCFLAGS += -DMACADDR_PROVISION_ENFORCED +endif ifneq ($(CONFIG_BCMDHD_PCIE),) DHDCFLAGS += -DDHD_WAKE_STATUS endif @@ -538,7 +540,9 @@ ifneq ($(CONFIG_BCMDHD_PCIE),) DHDCFLAGS += -DDHD_USE_STATIC_CTRLBUF #Use coherent pool DHDCFLAGS += -DDHD_USE_COHERENT_MEM_FOR_RING +ifeq ($(CONFIG_SOC_GS201),) DHDCFLAGS += -DDHD_ALLOC_COHERENT_MEM_FROM_ATOMIC_POOL +endif # Runtime PM feature DHDCFLAGS += -DDHD_PCIE_RUNTIMEPM -DMAX_IDLE_COUNT=5 @@ -706,6 +710,9 @@ DHDCFLAGS += -DWL_RAV_MSCS_NEG_IN_ASSOC # MAX_PFN_LIST_COUNT is defined as 64 in wlioctl_defs.h DHDCFLAGS += -DMAX_PFN_LIST_COUNT=16 +# Ignore the Coredump generation for the continuous packet drop +DHDCFLAGS += -DSKIP_COREDUMP_PKTDROP_RXHC + ########################## # driver type # m: module type driver @@ -907,6 +914,8 @@ ifneq ($(CONFIG_SOC_GOOGLE),) DHDCFLAGS += -DPOWERUP_MAX_RETRY=0 # Explicitly disable Softap 6G DHDCFLAGS += -DWL_DISABLE_SOFTAP_6G + # Increase assoc beacon wait time + DHDCFLAGS += -DDEFAULT_RECREATE_BI_TIMEOUT=40 ifneq ($(filter y, $(CONFIG_BCM4389)),) # Add chip specific suffix to the output on customer release BCM_WLAN_CHIP_SUFFIX = 4389 @@ -943,6 +952,9 @@ else ifneq ($(CONFIG_ARCH_HISI),) # Allow wl event forwarding as network packet DHDCFLAGS += -DWL_EVENT_ENAB + # Enable memdump for logset beyond range only internal builds + DHDCFLAGS += -DDHD_LOGSET_BEYOND_MEMDUMP + ifneq ($(CONFIG_BCMDHD_PCIE),) # LB RXP Flow control to avoid OOM DHDCFLAGS += -DLB_RXP_STOP_THR=200 -DLB_RXP_STRT_THR=199 @@ -29,6 +29,10 @@ ifneq ($(KERNEL_SRC),) EXTRA_CFLAGS+="-Wno-missing-prototypes" endif +ifneq ($(CONFIG_WLAN_TRACKER),) +KBUILD_EXTRA_SYMBOLS=$(OUT_DIR)/../google-modules/wlan/wlan_ptracker/Module.symvers +endif + all: $(MAKE) -C $(KERNEL_SRC) M=$(M) \ $(KBUILD_OPTIONS) EXTRA_CFLAGS="$(EXTRA_CFLAGS)" KBUILD_EXTRA_SYMBOLS="$(EXTRA_SYMBOLS)" modules @@ -1190,9 +1190,11 @@ dscp2up(uint8 *up_table, uint8 dscp) user_priority = up_table[dscp]; } - /* 255 is unused value so return up from dscp */ - if (user_priority == 255) { - user_priority = dscp >> (IPV4_TOS_PREC_SHIFT - IPV4_TOS_DSCP_SHIFT); + if (user_priority == 255) { /* unknown user priority */ + /* If the user_priority from the QoS Map table is unknown(i.e., 255), then + * set the default user priority as PRIO_8021D_BE(0); Reference RFC 8325. + */ + user_priority = PRIO_8021D_BE; /* default priority */ } return user_priority; @@ -1856,6 +1856,7 @@ typedef struct dhd_pub { bool assoc_at_suspend; #endif /* DEVICE_TX_STUCK_DETECT && ASSOC_CHECK_SR */ uint32 p2p_disc_busy_cnt; + bool skip_memdump_map_read; } dhd_pub_t; #if defined(__linux__) @@ -2268,6 +2269,7 @@ extern void dhd_os_oob_irq_wake_unlock(dhd_pub_t *pub); * to prevent the system from entering suspend during TX/RX frame processing. * It can be adjusted depending on the host platform. */ +#define DHD_MONITOR_TIMEOUT_MS 1000 #define DHD_PACKET_TIMEOUT_MS 100 #define DHD_HANDSHAKE_TIMEOUT_MS 1000 #define DHD_EVENT_TIMEOUT_MS 1500 @@ -3895,6 +3897,7 @@ extern int dhd_coredump_mempool_init(dhd_pub_t *dhd); extern void dhd_coredump_mempool_deinit(dhd_pub_t *dhd); #define DHD_COREDUMP_MEMPOOL_INIT(dhdp) dhd_coredump_mempool_init(dhdp) #define DHD_COREDUMP_MEMPOOL_DEINIT(dhdp) dhd_coredump_mempool_deinit(dhdp) +#define DHD_COREDUMP_IGNORE_TRAP_SIG "host_wake_asserted_for_too_long" #else #define DHD_COREDUMP_MEMPOOL_INIT(dhdp) do { /* noop */ } while (0) #define DHD_COREDUMP_MEMPOOL_DEINIT(dhdp) do { /* noop */ } while (0) @@ -4086,7 +4089,7 @@ void dhd_send_trap_to_fw_for_timeout(dhd_pub_t * pub, timeout_reasons_t reason); extern int dhd_bus_set_device_wake(struct dhd_bus *bus, bool val); extern void dhd_bus_dw_deassert(dhd_pub_t *dhd); #endif /* defined(PCIE_OOB) || defined(PCIE_INB_DW) */ -extern void dhd_prhex(const char *msg, volatile uchar *buf, uint nbytes, uint8 dbg_level); +extern void dhd_prhex(const char *msg, volatile uchar *buf, uint nbytes, uint32 dbg_level); int dhd_tput_test(dhd_pub_t *dhd, tput_test_t *tput_data); void dhd_tput_test_rx(dhd_pub_t *dhd, void *pkt); #ifdef DHD_EFI diff --git a/dhd_common.c b/dhd_common.c index d3e13e9..3b943d3 100755 --- a/dhd_common.c +++ b/dhd_common.c @@ -4763,7 +4763,7 @@ wl_show_host_event(dhd_pub_t *dhd_pub, wl_event_msg_t *event, void *event_data, case WLC_E_PFN_PARTIAL_RESULT: #endif /* WL_SCHED_SCAN */ case WLC_E_PFN_SSID_EXT: - DHD_EVENT(("PNOEVENT: %s\n", event_name)); + DHD_EVENT(("PNOEVENT: %s(%d)\n", event_name, event_type)); break; case WLC_E_PFN_SCAN_BACKOFF: @@ -5239,6 +5239,31 @@ dhd_parse_hck_common_sw_event(bcm_xtlv_t *wl_hc) } +#ifdef SKIP_COREDUMP_PKTDROP_RXHC +static bool +dhd_skip_coredump_for_rxhc(bcm_xtlv_t *wl_hc) +{ + wl_rx_hc_info_v2_t *hck_rx_stall_v2; + uint16 id; + bool ignore_coredump = FALSE; + + id = ltoh16(wl_hc->id); + + if (id == WL_HC_DD_RX_STALL_V2) { + /* map the hck_rx_stall_v2 structure to the value of the XTLV */ + hck_rx_stall_v2 = + (wl_rx_hc_info_v2_t*)wl_hc; + if (hck_rx_stall_v2->rx_hc_dropped_all >= + hck_rx_stall_v2->rx_hc_alert_th) { + DHD_ERROR(("Skip the coredump for continous packet drop\n")); + ignore_coredump = TRUE; + } + } + + return ignore_coredump; +} +#endif /* SKIP_COREDUMP_PKTDROP_RXHC */ + #endif /* PARSE_DONGLE_HOST_EVENT */ #ifdef WL_CFGVENDOR_SEND_ALERT_EVENT static void @@ -5399,6 +5424,11 @@ dngl_host_event_process(dhd_pub_t *dhdp, bcm_dngl_event_t *event, #ifdef PARSE_DONGLE_HOST_EVENT dhd_parse_hck_common_sw_event(wl_hc); #endif /* PARSE_DONGLE_HOST_EVENT */ +#ifdef SKIP_COREDUMP_PKTDROP_RXHC + if (dhd_skip_coredump_for_rxhc(wl_hc) == TRUE) { + ignore_hc = TRUE; + } +#endif /* SKIP_COREDUMP_PKTDROP_RXHC */ #ifdef WL_CFGVENDOR_SEND_ALERT_EVENT dhd_send_error_alert_event(dhdp, wl_hc); #endif /* WL_CFGVENDOR_SEND_ALERT_EVENT */ @@ -5855,8 +5885,10 @@ wl_process_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, uint pktlen del_sta = FALSE; } #endif /* WL_CFG80211 */ - DHD_EVENT(("%s: Link event %d, flags %x, status %x, role %d, del_sta %d\n", - __FUNCTION__, type, flags, status, role, del_sta)); + DHD_EVENT(("%s: Link event %d, flags %x, status %x, " + "reason=%d, role %d, del_sta %d\n", + __FUNCTION__, type, flags, status, + reason, role, del_sta)); if (del_sta) { DHD_EVENT(("%s: Deleting STA " MACDBG "\n", @@ -9461,7 +9493,7 @@ int dhd_free_tdls_peer_list(dhd_pub_t *dhd_pub) * based on the debug level specified */ void -dhd_prhex(const char *msg, volatile uchar *buf, uint nbytes, uint8 dbg_level) +dhd_prhex(const char *msg, volatile uchar *buf, uint nbytes, uint32 dbg_level) { char line[128], *p; int len = sizeof(line); @@ -9469,12 +9501,15 @@ dhd_prhex(const char *msg, volatile uchar *buf, uint nbytes, uint8 dbg_level) uint i; if (msg && (msg[0] != '\0')) { - if (dbg_level == DHD_ERROR_VAL) + if (dbg_level == DHD_ERROR_VAL) { DHD_ERROR(("%s:\n", msg)); - else if (dbg_level == DHD_INFO_VAL) + } else if (dbg_level == DHD_INFO_VAL) { DHD_INFO(("%s:\n", msg)); - else if (dbg_level == DHD_TRACE_VAL) + } else if (dbg_level == DHD_TRACE_VAL) { DHD_TRACE(("%s:\n", msg)); + } else if (dbg_level == DHD_RPM_VAL) { + DHD_RPM(("%s:\n", msg)); + } } p = line; @@ -9492,12 +9527,16 @@ dhd_prhex(const char *msg, volatile uchar *buf, uint nbytes, uint8 dbg_level) if (i % 16 == 15) { /* flush line */ - if (dbg_level == DHD_ERROR_VAL) + if (dbg_level == DHD_ERROR_VAL) { DHD_ERROR(("%s:\n", line)); - else if (dbg_level == DHD_INFO_VAL) + } else if (dbg_level == DHD_INFO_VAL) { DHD_INFO(("%s:\n", line)); - else if (dbg_level == DHD_TRACE_VAL) + } else if (dbg_level == DHD_TRACE_VAL) { DHD_TRACE(("%s:\n", line)); + } else if (dbg_level == DHD_RPM_VAL) { + DHD_RPM(("%s:\n", line)); + } + p = line; len = sizeof(line); } @@ -9505,12 +9544,15 @@ dhd_prhex(const char *msg, volatile uchar *buf, uint nbytes, uint8 dbg_level) /* flush last partial line */ if (p != line) { - if (dbg_level == DHD_ERROR_VAL) + if (dbg_level == DHD_ERROR_VAL) { DHD_ERROR(("%s:\n", line)); - else if (dbg_level == DHD_INFO_VAL) + } else if (dbg_level == DHD_INFO_VAL) { DHD_INFO(("%s:\n", line)); - else if (dbg_level == DHD_TRACE_VAL) + } else if (dbg_level == DHD_TRACE_VAL) { DHD_TRACE(("%s:\n", line)); + } else if (dbg_level == DHD_RPM_VAL) { + DHD_RPM(("%s:\n", line)); + } } } diff --git a/dhd_custom_google.c b/dhd_custom_google.c index 5158e3b..5bd91e8 100644 --- a/dhd_custom_google.c +++ b/dhd_custom_google.c @@ -841,7 +841,7 @@ struct resource dhd_wlan_resources = { .start = 0, /* Dummy */ .end = 0, /* Dummy */ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE | - IORESOURCE_IRQ_HIGHEDGE, + IORESOURCE_IRQ_HIGHLEVEL, }; EXPORT_SYMBOL(dhd_wlan_resources); @@ -864,6 +864,432 @@ struct wifi_platform_data dhd_wlan_control = { }; EXPORT_SYMBOL(dhd_wlan_control); + +#ifdef WLAN_TRACKER +#include <wlan_ptracker_client.h> +#include <wldev_common.h> +#include <wl_cfg80211.h> +#include <dhd_linux_priv.h> + +static int +dhd_twt_setup(void *priv, struct dytwt_setup_param *setup) +{ + wl_twt_config_t val; + struct net_device *dev = (struct net_device *)priv; + s32 bw; + u8 mybuf[WLC_IOCTL_SMLEN] = {0}; + u8 resp_buf[WLC_IOCTL_SMLEN] = {0}; + uint8 *rem = mybuf; + uint16 rem_len = sizeof(mybuf); + + bzero(&val, sizeof(val)); + val.version = WL_TWT_SETUP_VER; + val.length = sizeof(val.version) + sizeof(val.length); + + /* Default values, Override Below */ + val.desc.flow_flags = 0; + val.desc.wake_time_h = 0xFFFFFFFF; + val.desc.wake_time_l = 0xFFFFFFFF; + val.desc.wake_int_min = 0xFFFFFFFF; + val.desc.wake_int_max = 0xFFFFFFFF; + val.desc.wake_dur_min = 0xFFFFFFFF; + val.desc.wake_dur_max = 0xFFFFFFFF; + val.desc.avg_pkt_num = 0xFFFFFFFF; + val.desc.avg_pkt_size = 0xFFFFFFFF; + + /* Flow Flag for setup cmd: request, flow type: unannounced */ + val.desc.flow_flags |= WL_TWT_FLOW_FLAG_REQUEST; + val.desc.flow_flags |= WL_TWT_FLOW_FLAG_UNANNOUNCED; + /* Config ID */ + val.desc.configID = setup->config_id; + /* negotiation_type */ + val.desc.negotiation_type = setup->nego_type; + /* Wake Duration */ + val.desc.wake_dur = setup->wake_duration; + /* Wake interval */ + val.desc.wake_int = setup->wake_interval; + + bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_CONFIG, + sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32); + if (bw != BCME_OK) { + goto exit; + } + + bw = wldev_iovar_setbuf(dev, "twt", + mybuf, sizeof(mybuf) - rem_len, resp_buf, WLC_IOCTL_SMLEN, NULL); + if (bw < 0) { + pr_err("twt config set failed. ret:%d\n", bw); + } else { + pr_err("twt config setup succeeded, config ID %d " + "Negotiation type %d flow flags %d\n", val.desc.configID, + val.desc.negotiation_type, val.desc.flow_flags); + } +exit: + return bw; +} + +static int +dhd_twt_teardown(void *priv, struct dytwt_setup_param *setup) +{ + wl_twt_teardown_t val; + struct net_device *dev = (struct net_device *)priv; + s32 bw; + u8 mybuf[WLC_IOCTL_SMLEN] = {0}; + u8 res_buf[WLC_IOCTL_SMLEN] = {0}; + uint8 *rem = mybuf; + uint16 rem_len = sizeof(mybuf); + + bzero(&val, sizeof(val)); + val.version = WL_TWT_TEARDOWN_VER; + val.length = sizeof(val.version) + sizeof(val.length); + + /* Default values, Override Below */ + val.teardesc.flow_id = 0xFF; + val.teardesc.bid = 0xFF; + /* Config ID */ + val.configID = setup->config_id; + /* negotiation_type */ + val.teardesc.negotiation_type = setup->nego_type; + + bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_TEARDOWN, + sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32); + if (bw != BCME_OK) { + goto exit; + } + + bw = wldev_iovar_setbuf(dev, "twt", + mybuf, sizeof(mybuf) - rem_len, res_buf, WLC_IOCTL_SMLEN, NULL); + if (bw < 0) { + pr_err("twt teardown failed. ret:%d\n", bw); + } else { + pr_err("twt teardown succeeded, config ID %d " + "Negotiation type %d alltwt %d\n", val.configID, + val.teardesc.negotiation_type, val.teardesc.alltwt); + } +exit: + return bw; +} + +static void dhd_twt_stats2_dytwt(wl_twt_stats_v2_t *src, struct dytwt_stats *dest) +{ + wl_twt_peer_stats_v2_t *peer_stats = &src->peer_stats_list[0]; + + dest->sp_seq = peer_stats->sp_seq; + dest->tx_ucast_pkts = peer_stats->tx_ucast_pkts; + dest->tx_pkts_min = peer_stats->tx_pkts_min; + dest->tx_pkts_max = peer_stats->tx_pkts_max; + dest->tx_pkts_avg = peer_stats->tx_pkts_avg; + dest->tx_failures = peer_stats->tx_failures; + dest->rx_ucast_pkts = peer_stats->rx_ucast_pkts; + dest->rx_pkts_min = peer_stats->rx_pkts_min; + dest->rx_pkts_max = peer_stats->rx_pkts_max; + dest->rx_pkts_avg = peer_stats->rx_pkts_avg; + dest->rx_pkts_retried = peer_stats->rx_pkts_retried; + dest->tx_pkt_sz_avg = peer_stats->tx_pkt_sz_avg; + dest->rx_pkt_sz_avg = peer_stats->rx_pkt_sz_avg; + dest->eosp_dur_avg = peer_stats->eosp_dur_avg; + dest->eosp_count = peer_stats->eosp_count; +} + +static int +dhd_twt_get_stats(void *priv, struct dytwt_stats *stats) +{ + struct net_device *dev = (struct net_device *)priv; + wl_twt_stats_cmd_v1_t query; + wl_twt_stats_v2_t stats_v2; + int ret = BCME_OK; + char iovbuf[WLC_IOCTL_SMLEN] = {0, }; + uint8 *pxtlv = NULL; + uint8 *iovresp = NULL; + uint16 buflen = 0, bufstart = 0; + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); + + bzero(&query, sizeof(query)); + query.version = WL_TWT_STATS_CMD_VERSION_1; + query.length = sizeof(query) - OFFSETOF(wl_twt_stats_cmd_v1_t, peer); + + /* Default values, Override Below */ + query.num_bid = 0xFF; + query.num_fid = 0xFF; + query.configID = stats->config_id; + + iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN); + if (iovresp == NULL) { + WL_ERR(("%s: iov resp memory alloc exited\n", __FUNCTION__)); + goto exit; + } + //query.flags |= WL_TWT_STATS_CMD_FLAGS_RESET; + buflen = bufstart = WLC_IOCTL_SMLEN; + pxtlv = (uint8 *)iovbuf; + ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_STATS, + sizeof(query), (uint8 *)&query, BCM_XTLV_OPTION_ALIGN32); + if (ret != BCME_OK) { + WL_ERR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret)); + goto exit; + } + + if ((ret = wldev_iovar_getbuf(dev, "twt", iovbuf, bufstart-buflen, + iovresp, WLC_IOCTL_MEDLEN, NULL))) { + WL_ERR(("twt status failed with err=%d \n", ret)); + goto exit; + } + + (void)memcpy_s(&stats_v2, sizeof(stats_v2), iovresp, sizeof(stats_v2)); + if (dtoh16(stats_v2.version) == WL_TWT_STATS_VERSION_2 && + stats_v2.num_stats) { + dhd_twt_stats2_dytwt((wl_twt_stats_v2_t*)iovresp, stats); + } else { + ret = BCME_UNSUPPORTED; + WL_ERR(("Version 1 unsupported. ver %d, \n", dtoh16(stats_v2.version))); + goto exit; + } +exit: + if (iovresp) { + MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN); + } + return ret; +} + +static void dhd_twt_status2_dytwt( + wl_twt_status_v1_t *result, + struct dytwt_status *status) +{ + int i; + wl_twt_sdesc_v0_t *sdesc = NULL; + + for (i = 0 ; i < WL_TWT_MAX_ITWT; i++) { + if (result->itwt_status[i].configID != status->config_id) + continue; + sdesc = &result->itwt_status[i].desc; + status->config_id = result->itwt_status[i].configID; + status->flow_id = sdesc->flow_id; + status->flow_flags = sdesc->flow_flags; + status->setup_cmd = sdesc->setup_cmd; + status->channel = sdesc->channel; + status->nego_type = sdesc->negotiation_type; + status->wake_dur = sdesc->wake_dur; + status->wake_int = sdesc->wake_int; + } +} + +static int +dhd_twt_get_status(void *priv, struct dytwt_status *status) +{ + struct net_device *dev = (struct net_device *)priv; + wl_twt_status_cmd_v1_t query; + wl_twt_status_v1_t result; + int ret = BCME_OK; + char iovbuf[WLC_IOCTL_SMLEN] = {0, }; + uint8 *pxtlv = NULL; + uint8 *iovresp = NULL; + uint16 buflen = 0, bufstart = 0; + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); + + bzero(&query, sizeof(query)); + bzero(&result, sizeof(result)); + query.version = WL_TWT_CMD_STATUS_VERSION_1; + query.length = sizeof(query) - OFFSETOF(wl_twt_status_cmd_v1_t, peer); + + query.configID = status->config_id; + + iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN); + if (iovresp == NULL) { + WL_ERR(("%s: iov resp memory alloc exited\n", __FUNCTION__)); + goto exit; + } + buflen = bufstart = WLC_IOCTL_SMLEN; + pxtlv = (uint8 *)iovbuf; + ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_STATUS, + sizeof(query), (uint8 *)&query, BCM_XTLV_OPTION_ALIGN32); + if (ret != BCME_OK) { + WL_ERR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret)); + goto exit; + } + + if ((ret = wldev_iovar_getbuf(dev, "twt", iovbuf, bufstart-buflen, + iovresp, WLC_IOCTL_MEDLEN, NULL))) { + WL_ERR(("twt status failed with err=%d \n", ret)); + goto exit; + } + + (void)memcpy_s(&result, sizeof(result), iovresp, sizeof(result)); + printk("wlan_ptracker: %s(): version: %d, length: %d\n", + __func__, result.version, result.length); + if (dtoh16(result.version) == WL_TWT_CMD_STATUS_VERSION_1) { + dhd_twt_status2_dytwt(&result, status); + } else { + ret = BCME_UNSUPPORTED; + WL_ERR(("Version 1 unsupported. ver %d, \n", dtoh16(result.version))); + goto exit; + } +exit: + if (iovresp) { + MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN); + } + return ret; +} + +static int +dhd_twt_cap(void *priv, struct dytwt_cap *cap) +{ + int ret = BCME_OK; + struct net_device *dev = (struct net_device *)priv; + char iovbuf[WLC_IOCTL_SMLEN] = {0, }; + uint8 *pxtlv = NULL; + uint8 *iovresp = NULL; + wl_twt_cap_cmd_t cmd_cap; + wl_twt_cap_t result; + scb_val_t scbval; + uint16 buflen = 0, bufstart = 0; + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); + + /* Query link speed */ + ret = wldev_get_link_speed(dev, &cap->link_speed); + if (unlikely(ret)) { + WL_ERR(("get_link speed error (%d)\n", ret)); + goto exit; + } + + /* Query RSSI */ + bzero(&scbval, sizeof(scb_val_t)); + ret = wldev_get_rssi(dev, &scbval); + if (unlikely(ret)) { + WL_ERR(("get_rssi error (%d)\n", ret)); + goto exit; + } + cap->rssi = scbval.val; + bzero(&cmd_cap, sizeof(cmd_cap)); + + cmd_cap.version = WL_TWT_CAP_CMD_VERSION_1; + cmd_cap.length = sizeof(cmd_cap) - OFFSETOF(wl_twt_cap_cmd_t, peer); + + iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN); + if (iovresp == NULL) { + pr_err("%s: iov resp memory alloc exited\n", __FUNCTION__); + goto exit; + } + + buflen = bufstart = WLC_IOCTL_SMLEN; + pxtlv = (uint8 *)iovbuf; + + ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_CAP, + sizeof(cmd_cap), (uint8 *)&cmd_cap, BCM_XTLV_OPTION_ALIGN32); + if (ret != BCME_OK) { + pr_err("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret); + goto exit; + } + + if ((ret = wldev_iovar_getbuf(dev, "twt", iovbuf, bufstart-buflen, + iovresp, WLC_IOCTL_MEDLEN, NULL))) { + pr_err("Getting twt status failed with err=%d \n", ret); + goto exit; + } + + (void)memcpy_s(&result, sizeof(result), iovresp, sizeof(result)); + + if (dtoh16(result.version) == WL_TWT_CAP_CMD_VERSION_1) { + pr_err("capability ver %d, \n", dtoh16(result.version)); + cap->device_cap = dtoh16(result.device_cap); + cap->peer_cap = dtoh16(result.peer_cap); + return ret; + } else { + ret = BCME_UNSUPPORTED; + pr_err("Version 1 unsupported. ver %d, \n", dtoh16(result.version)); + goto exit; + } +exit: + if (iovresp) { + MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN); + } + return ret; +} + +extern ssize_t show_pwrstats_path(struct dhd_info *dev, char *buf); + +static u64 twt_pwrstate_hex_get(char *buf) +{ + char *ptr = buf; + char *token = strsep(&ptr, "\x0a"); + + /* remove prefix space */ + token++; + return simple_strtoull(token, NULL, 16); +} + +#define DHD_PWR_STAT_STR_SIZE 512 +static int dhd_twt_pwstate(void *priv, struct dytwt_pwr_state *state) +{ + char buf[DHD_PWR_STAT_STR_SIZE]; + struct net_device *dev = (struct net_device *)priv; + struct dhd_info *dhd = DHD_DEV_INFO(dev); + char *ptr = &buf[0]; + char *token; + int cnt = 0; + int ret; + + ret = show_pwrstats_path(dhd, buf); + if (!ret) + goto out; + + token = strsep(&ptr, ":"); + while (token) { + if (cnt == 3) + state->awake = twt_pwrstate_hex_get(token); + if (cnt == 6) + state->count = twt_pwrstate_hex_get(token); + if (cnt == 7) + state->asleep = twt_pwrstate_hex_get(token); + token = strsep(&ptr, ":"); + cnt++; + } +out: + return 0; +} + +struct dytwt_client_ops twt_ops = { + .setup = dhd_twt_setup, + .teardown = dhd_twt_teardown, + .get_cap = dhd_twt_cap, + .get_pwrstates = dhd_twt_pwstate, + .get_stats = dhd_twt_get_stats, + .get_status = dhd_twt_get_status, +}; + +struct wlan_ptracker_client client = { + .ifname = "wlan0", + .dytwt_ops = &twt_ops, + .cb = NULL, +}; + +static int dhd_plat_ptracker_register(void) +{ + return wlan_ptracker_register_client(&client); +} + +static void dhd_plat_ptracker_unregister(void) +{ + wlan_ptracker_unregister_client(&client); +} + +static u32 custom_notify_table[] = { + WLAN_PTRACKER_NOTIFY_SUSPEN, //CUSTOM_NOTIFY_BUS_SUSPEND, + WLAN_PTRACKER_NOTIFY_STA_CONNECT, //CUSTOM_NOTIFY_STA_CONNECT, + WLAN_PTRACKER_NOTIFY_STA_DISCONNECT, //CUSTOM_NOTIFY_STA_DISCONNECT, + WLAN_PTRACKER_NOTIFY_DYTWT_DISABLE, //CUSTOM_NOTIFY_TWT_SETUP, + WLAN_PTRACKER_NOTIFY_DYTWT_ENABLE, //CUSTOM_NOTIFY_TWT_TEARDOWN, +}; + +int +dhd_custom_notify(u32 id) +{ + u32 _id = custom_notify_table[id]; + + if (!client.cb) + return 0; + return client.cb(&client, _id); +} +#endif /* WLAN_TRACKER */ + int dhd_wlan_init(void) { @@ -903,6 +1329,10 @@ dhd_wlan_init(void) dhd_wlan_init_hardware_info(); #endif /* SUPPORT_MULTIPLE_NVRAM || SUPPORT_MULTIPLE_CLMBLOB */ +#ifdef WLAN_TRACKER + dhd_plat_ptracker_register(); +#endif /* WLAN_TRACKER */ + fail: DHD_ERROR(("%s: FINISH.......\n", __FUNCTION__)); return ret; @@ -918,6 +1348,10 @@ dhd_wlan_deinit(void) gpio_free(wlan_reg_on); } +#ifdef WLAN_TRACKER + dhd_plat_ptracker_unregister(); +#endif /* WLAN_TRACKER */ + #ifdef DHD_COREDUMP platform_device_unregister(&sscd_dev); #endif /* DHD_COREDUMP */ @@ -928,7 +1362,7 @@ dhd_wlan_deinit(void) void dhd_plat_l1ss_ctrl(bool ctrl) { #if defined(CONFIG_SOC_GOOGLE) - printk(KERN_DEBUG "%s: Control L1ss RC side %d \n", __FUNCTION__, ctrl); + DHD_CONS_ONLY(("%s: Control L1ss RC side %d \n", __FUNCTION__, ctrl)); exynos_pcie_rc_l1ss_ctrl(ctrl, PCIE_L1SS_CTRL_WIFI, 1); #endif /* CONFIG_SOC_GOOGLE */ return; @@ -1005,6 +1439,7 @@ uint16 dhd_plat_align_rxbuf_size(uint16 rxbufpost_sz) #endif } + #ifndef BCMDHD_MODULAR /* Required only for Built-in DHD */ device_initcall(dhd_wlan_init); diff --git a/dhd_dbg_ring.c b/dhd_dbg_ring.c index e741b03..b1c3d85 100644 --- a/dhd_dbg_ring.c +++ b/dhd_dbg_ring.c @@ -490,7 +490,8 @@ exit: } int -dhd_dbg_ring_pull(dhd_dbg_ring_t *ring, void *data, uint32 buf_len, bool strip_hdr) +dhd_dbg_ring_pull(dhd_dbg_ring_t *ring, void *data, uint32 buf_len, + bool strip_hdr, int *num_entries) { int32 r_len, total_r_len = 0; unsigned long flags; @@ -512,6 +513,7 @@ dhd_dbg_ring_pull(dhd_dbg_ring_t *ring, void *data, uint32 buf_len, bool strip_h data = (uint8 *)data + r_len; buf_len -= r_len; total_r_len += r_len; + (*num_entries)++; } return total_r_len; diff --git a/dhd_dbg_ring.h b/dhd_dbg_ring.h index bff2e62..a8a7977 100644 --- a/dhd_dbg_ring.h +++ b/dhd_dbg_ring.h @@ -52,6 +52,11 @@ typedef struct dhd_dbg_ring_entry { uint64 timestamp; /* present if has_timestamp bit is set. */ } PACKED_STRUCT dhd_dbg_ring_entry_t; +typedef struct dhd_dbg_ring_entry_pack { + uint32 magic; + int num_entries; /* the number of log entries */ +} PACKED_STRUCT dhd_dbg_ring_entry_pack_t; + struct ring_statistics { /* number of bytes that was written to the buffer by driver */ uint32 written_bytes; @@ -110,6 +115,8 @@ typedef struct dhd_dbg_ring { status.verbose_level = ring->log_level; \ } while (0) +#define DBG_RING_PACK_MAGIC 0xDBAADBAA +#define DBG_RING_ENTRY_PACK_SIZE (sizeof(dhd_dbg_ring_entry_pack_t)) #define DBG_RING_ENTRY_SIZE (sizeof(dhd_dbg_ring_entry_t)) #define ENTRY_LENGTH(hdr) ((hdr)->len + DBG_RING_ENTRY_SIZE) #define PAYLOAD_MAX_LEN 65535 @@ -140,7 +147,7 @@ int dhd_dbg_ring_update(void *dbg_ring, uint32 w_len); #endif /* DHD_PKT_LOGGING_DBGRING */ int dhd_dbg_ring_push(dhd_dbg_ring_t *ring, dhd_dbg_ring_entry_t *hdr, void *data); int dhd_dbg_ring_pull(dhd_dbg_ring_t *ring, void *data, uint32 buf_len, - bool strip_hdr); + bool strip_hdr, int* num_entries); int dhd_dbg_ring_pull_single(dhd_dbg_ring_t *ring, void *data, uint32 buf_len, bool strip_header); uint32 dhd_dbg_ring_get_pending_len(dhd_dbg_ring_t *ring); diff --git a/dhd_debug.c b/dhd_debug.c index 6efe810..72e9689 100644 --- a/dhd_debug.c +++ b/dhd_debug.c @@ -380,7 +380,8 @@ dhd_dbg_pull_from_pktlog(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_le #endif /* DHD_PKT_LOGGING_DBGRING */ int -dhd_dbg_pull_from_ring(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len) +dhd_dbg_pull_from_ring(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len, + int *num_entries) { dhd_dbg_ring_t *ring; @@ -391,7 +392,7 @@ dhd_dbg_pull_from_ring(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len) return BCME_RANGE; } ring = &dhdp->dbg->dbg_rings[ring_id]; - return dhd_dbg_ring_pull(ring, data, buf_len, FALSE); + return dhd_dbg_ring_pull(ring, data, buf_len, FALSE, num_entries); } static int @@ -1118,16 +1119,17 @@ dhd_dbg_msgtrace_log_parser(dhd_pub_t *dhdp, void *event_data, * event log buffer. Refer to event log buffer structure in * event_log.h */ + logset = (ltoh32(*((uint32 *)(data + 4))) & EVENT_LOG_SETID_MASK); + DHD_MSGTRACE_LOG(("EVENT_LOG_HDR[0x%x]: Set: 0x%08x length = %d\n", - ltoh16(*((uint16 *)(data+2))), ltoh32(*((uint32 *)(data + 4))), - ltoh16(*((uint16 *)(data))))); + ltoh16(*((uint16 *)(data+2))), logset, ltoh16(*((uint16 *)(data))))); - logset = ltoh32(*((uint32 *)(data + 4))); block_hdr_len = ltoh16(*((uint16 *)(data))); if (logset >= event_log_max_sets) { DHD_ERROR(("%s logset: %d max: %d out of range queried: %d\n", __FUNCTION__, logset, event_log_max_sets, event_log_max_sets_queried)); +#ifdef DHD_LOGSET_BEYOND_MEMDUMP #ifdef DHD_FW_COREDUMP if (event_log_max_sets_queried && !dhd_memdump_is_scheduled(dhdp)) { DHD_ERROR(("%s: collect socram for DUMP_TYPE_LOGSET_BEYOND_RANGE\n", @@ -1136,6 +1138,9 @@ dhd_dbg_msgtrace_log_parser(dhd_pub_t *dhdp, void *event_data, dhd_bus_mem_dump(dhdp); } #endif /* DHD_FW_COREDUMP */ +#else + goto exit; +#endif /* DHD_LOGSET_BEYOND_MEMDUMP */ } block = ltoh16(*((uint16 *)(data + 2))); @@ -2269,13 +2274,15 @@ dhd_dbg_monitor_get_tx_pkts(dhd_pub_t *dhdp, void __user *user_buf, uint16 req_count, uint16 *resp_count) { dhd_dbg_tx_report_t *tx_report; - dhd_dbg_tx_info_t *tx_pkt; + dhd_dbg_tx_info_t *tx_pkt, *ori_tx_pkt; wifi_tx_report_t *ptr; compat_wifi_tx_report_t *cptr; dhd_dbg_pkt_mon_state_t tx_pkt_state; dhd_dbg_pkt_mon_state_t tx_status_state; uint16 pkt_count, count; unsigned long flags; + dhd_dbg_tx_info_t *tmp_tx_pkt = NULL; + uint32 alloc_len, i, ret; BCM_REFERENCE(ptr); BCM_REFERENCE(cptr); @@ -2300,8 +2307,31 @@ dhd_dbg_monitor_get_tx_pkts(dhd_pub_t *dhdp, void __user *user_buf, count = 0; tx_report = dhdp->dbg->pkt_mon.tx_report; - tx_pkt = tx_report->tx_pkts; + ori_tx_pkt = tx_report->tx_pkts; pkt_count = MIN(req_count, tx_report->status_pos); + + alloc_len = (sizeof(*tmp_tx_pkt) * pkt_count); + tmp_tx_pkt = (dhd_dbg_tx_info_t *)MALLOCZ(dhdp->osh, alloc_len); + if (unlikely(!tmp_tx_pkt)) { + DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); + DHD_ERROR(("%s: failed to allocate tmp_tx_pkt", __FUNCTION__)); + return -ENOMEM; + } + if ((ret = memcpy_s(tmp_tx_pkt, alloc_len, ori_tx_pkt, alloc_len))) { + DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); + DHD_ERROR(("%s: failed to copy tmp_tx_pkt ret:%d", __FUNCTION__, ret)); + return -EINVAL; + } + for (i = 0; i < pkt_count; i++) { + tmp_tx_pkt[i].info.pkt = skb_copy((struct sk_buff*)ori_tx_pkt[i].info.pkt, + GFP_ATOMIC); + if (!tmp_tx_pkt[i].info.pkt) { + DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); + DHD_ERROR(("%s: failed to copy skb", __FUNCTION__)); + return -ENOMEM; + } + } + tx_pkt = tmp_tx_pkt; DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); #ifdef CONFIG_COMPAT @@ -2364,6 +2394,11 @@ dhd_dbg_monitor_get_tx_pkts(dhd_pub_t *dhdp, void __user *user_buf, "status_pos=%u\n", __FUNCTION__, pkt_count)); } + for (i = 0; i < pkt_count; i++) { + PKTFREE(dhdp->osh, tmp_tx_pkt[i].info.pkt, TRUE); + } + MFREE(dhdp->osh, tmp_tx_pkt, alloc_len); + return BCME_OK; } @@ -2372,12 +2407,14 @@ dhd_dbg_monitor_get_rx_pkts(dhd_pub_t *dhdp, void __user *user_buf, uint16 req_count, uint16 *resp_count) { dhd_dbg_rx_report_t *rx_report; - dhd_dbg_rx_info_t *rx_pkt; + dhd_dbg_rx_info_t *rx_pkt, *ori_rx_pkt; wifi_rx_report_t *ptr; compat_wifi_rx_report_t *cptr; dhd_dbg_pkt_mon_state_t rx_pkt_state; uint16 pkt_count, count; unsigned long flags; + dhd_dbg_rx_info_t *tmp_rx_pkt = NULL; + uint32 alloc_len, i, ret; BCM_REFERENCE(ptr); BCM_REFERENCE(cptr); @@ -2399,8 +2436,31 @@ dhd_dbg_monitor_get_rx_pkts(dhd_pub_t *dhdp, void __user *user_buf, count = 0; rx_report = dhdp->dbg->pkt_mon.rx_report; - rx_pkt = rx_report->rx_pkts; + ori_rx_pkt = rx_report->rx_pkts; pkt_count = MIN(req_count, rx_report->pkt_pos); + + alloc_len = (sizeof(*tmp_rx_pkt) * pkt_count); + tmp_rx_pkt = (dhd_dbg_rx_info_t *)MALLOCZ(dhdp->osh, alloc_len); + if (unlikely(!tmp_rx_pkt)) { + DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); + DHD_ERROR(("%s: failed to allocate tmp_rx_pkt", __FUNCTION__)); + return -ENOMEM; + } + if ((ret = memcpy_s(tmp_rx_pkt, alloc_len, ori_rx_pkt, alloc_len))) { + DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); + DHD_ERROR(("%s: failed to copy tmp_rx_pkt ret:%d", __FUNCTION__, ret)); + return -EINVAL; + } + for (i = 0; i < pkt_count; i++) { + tmp_rx_pkt[i].info.pkt = skb_copy((struct sk_buff*)ori_rx_pkt[i].info.pkt, + GFP_ATOMIC); + if (!tmp_rx_pkt[i].info.pkt) { + DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); + DHD_ERROR(("%s: failed to copy skb", __FUNCTION__)); + return -ENOMEM; + } + } + rx_pkt = tmp_rx_pkt; DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); #ifdef CONFIG_COMPAT @@ -2448,6 +2508,11 @@ dhd_dbg_monitor_get_rx_pkts(dhd_pub_t *dhdp, void __user *user_buf, *resp_count = pkt_count; + for (i = 0; i < pkt_count; i++) { + PKTFREE(dhdp->osh, tmp_rx_pkt[i].info.pkt, TRUE); + } + MFREE(dhdp->osh, tmp_rx_pkt, alloc_len); + return BCME_OK; } @@ -2802,6 +2867,7 @@ void pr_roam_scan_cmpl_v2(prcd_event_log_hdr_t *plog_hdr) int i; roam_log_scan_cmplt_v2_t *log = (roam_log_scan_cmplt_v2_t *)plog_hdr->log_ptr; char chanspec_buf[CHANSPEC_STR_LEN]; + uint8 scan_list_size; DHD_ERROR_ROAM(("ROAM_LOG_SCAN_CMPL: time:%d version:%d" "scan_count:%d score_delta:%d\n", @@ -2812,7 +2878,9 @@ void pr_roam_scan_cmpl_v2(prcd_event_log_hdr_t *plog_hdr) log->cur_info.rssi, log->cur_info.score, wf_chspec_ntoa_ex(log->cur_info.chanspec, chanspec_buf))); - for (i = 0; i < log->scan_list_size; i++) { + + scan_list_size = MIN(log->scan_list_size, ROAM_LOG_RPT_SCAN_LIST_SIZE); + for (i = 0; i < scan_list_size; i++) { DHD_ERROR_ROAM((" ROAM_LOG_CANDIDATE %d: " MACDBG "rssi:%d score:%d cu :%d channel:%s TPUT:%dkbps\n", i, MAC2STRDBG((uint8 *)&log->scan_list[i].addr), diff --git a/dhd_debug.h b/dhd_debug.h index 670e009..5a079b9 100644 --- a/dhd_debug.h +++ b/dhd_debug.h @@ -842,7 +842,8 @@ extern void *dhd_dbg_get_priv(dhd_pub_t *dhdp); extern int dhd_dbg_send_urgent_evt(dhd_pub_t *dhdp, const void *data, const uint32 len); extern void dhd_dbg_verboselog_printf(dhd_pub_t *dhdp, prcd_event_log_hdr_t *plog_hdr, void *raw_event_ptr, uint32 *log_ptr, uint32 logset, uint16 block); -int dhd_dbg_pull_from_ring(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len); +int dhd_dbg_pull_from_ring(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len, + int *num_entries); int dhd_dbg_pull_single_from_ring(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len, bool strip_header); #ifdef DHD_PKT_LOGGING_DBGRING diff --git a/dhd_debug_linux.c b/dhd_debug_linux.c index d0a4ea9..9c45271 100644 --- a/dhd_debug_linux.c +++ b/dhd_debug_linux.c @@ -105,11 +105,21 @@ dbg_ring_poll_worker(struct work_struct *work) dhd_pub_t *dhdp; int ringid; dhd_dbg_ring_status_t ring_status; - void *buf; + void *buf, *buf_entries; + dhd_dbg_ring_entry_pack_t *pack_hdr; dhd_dbg_ring_entry_t *hdr; - uint32 buflen, rlen; + int32 buflen, rlen, remain_buflen; + int32 alloc_len; unsigned long flags; + BCM_REFERENCE(hdr); + + if (!CAN_SLEEP()) { + DHD_CONS_ONLY(("this context should be sleepable\n")); + sched = FALSE; + goto exit; + } + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); ring_info = container_of(d_work, linux_dbgring_info_t, work); GCC_DIAGNOSTIC_POP(); @@ -129,6 +139,7 @@ dbg_ring_poll_worker(struct work_struct *work) buflen = DBG_RING_ENTRY_SIZE; buflen += dhd_os_get_pktlog_dump_size(ndev); DHD_DBGIF(("%s: buflen: %d\n", __FUNCTION__, buflen)); + alloc_len = buflen + DBG_RING_ENTRY_PACK_SIZE; } else #endif /* DHD_PKT_LOGGING_DBGRING */ { @@ -147,35 +158,30 @@ dbg_ring_poll_worker(struct work_struct *work) goto exit; } DHD_DBG_RING_UNLOCK(ring->lock, flags); - } - if (!CAN_SLEEP()) { - DHD_CONS_ONLY(("this context should be sleepable\n")); - sched = FALSE; - goto exit; + alloc_len = NLMSG_DEFAULT_SIZE; } + buf = VMALLOCZ(dhdp->osh, alloc_len); - buf = VMALLOCZ(dhdp->osh, buflen); if (!buf) { DHD_CONS_ONLY(("%s failed to allocate read buf\n", __FUNCTION__)); sched = FALSE; goto exit; } + pack_hdr = (dhd_dbg_ring_entry_pack_t *)buf; + pack_hdr->magic = DBG_RING_PACK_MAGIC; + + buf_entries = (char *)buf + sizeof(dhd_dbg_ring_entry_pack_t); + #ifdef DHD_PKT_LOGGING_DBGRING if (ringid == PACKET_LOG_RING_ID) { - rlen = dhd_dbg_pull_from_pktlog(dhdp, ringid, buf, buflen); + pack_hdr->num_entries = 1u; + rlen = dhd_dbg_pull_from_pktlog(dhdp, ringid, buf_entries, buflen); DHD_DBGIF(("%s: rlen: %d\n", __FUNCTION__, rlen)); - } else -#endif /* DHD_PKT_LOGGING_DBGRING */ - { - rlen = dhd_dbg_pull_from_ring(dhdp, ringid, buf, buflen); - } - hdr = (dhd_dbg_ring_entry_t *)buf; - while (rlen > 0) { - DHD_DBG_RING_LOCK(ring->lock, flags); -#ifdef DHD_PKT_LOGGING_DBGRING - if (ringid == PACKET_LOG_RING_ID) { + hdr = (dhd_dbg_ring_entry_t *)buf_entries; + while (rlen > 0) { + DHD_DBG_RING_LOCK(ring->lock, flags); ring_status.read_bytes += (rlen - DBG_RING_ENTRY_SIZE); ring->stat.read_bytes += (rlen - DBG_RING_ENTRY_SIZE); if (ring->stat.read_bytes > ring->stat.written_bytes) { @@ -186,21 +192,44 @@ dbg_ring_poll_worker(struct work_struct *work) "writen_records %d\n", __FUNCTION__, ring->id, ring->name, ring->stat.read_bytes, ring->stat.written_bytes, ring->stat.written_records)); - } else + DHD_DBG_RING_UNLOCK(ring->lock, flags); + /* offset fw ts to host ts */ + hdr->timestamp += ring_info->tsoffset; + debug_data_send(dhdp, ringid, pack_hdr, + ENTRY_LENGTH(hdr) + DBG_RING_ENTRY_PACK_SIZE, ring_status); + rlen -= ENTRY_LENGTH(hdr); + hdr = (dhd_dbg_ring_entry_t *)((char *)hdr + ENTRY_LENGTH(hdr)); + } + } else #endif /* DHD_PKT_LOGGING_DBGRING */ - { - ring_status.read_bytes += ENTRY_LENGTH(hdr); + { + remain_buflen = buflen; + while (remain_buflen > 0) { + pack_hdr->num_entries = 0; + memset_s(buf_entries, NLMSG_DEFAULT_SIZE - DBG_RING_ENTRY_PACK_SIZE, + 0, NLMSG_DEFAULT_SIZE - DBG_RING_ENTRY_PACK_SIZE); + /* Returns as much as possible with the size of the passed buffer + * rlen means the total length of multiple entries including entry hdr + */ + rlen = dhd_dbg_pull_from_ring(dhdp, ringid, buf_entries, + NLMSG_DEFAULT_SIZE - DBG_RING_ENTRY_PACK_SIZE, + &pack_hdr->num_entries); + if (rlen <= 0) { + break; + } + + DHD_DBG_RING_LOCK(ring->lock, flags); + ring_status.read_bytes += rlen; + DHD_DBG_RING_UNLOCK(ring->lock, flags); + + /* payload length includes pack_hdr size */ + debug_data_send(dhdp, ringid, pack_hdr, + rlen + DBG_RING_ENTRY_PACK_SIZE, ring_status); + remain_buflen -= rlen; } - DHD_DBG_RING_UNLOCK(ring->lock, flags); - /* offset fw ts to host ts */ - hdr->timestamp += ring_info->tsoffset; - debug_data_send(dhdp, ringid, hdr, ENTRY_LENGTH(hdr), - ring_status); - rlen -= ENTRY_LENGTH(hdr); - hdr = (dhd_dbg_ring_entry_t *)((char *)hdr + ENTRY_LENGTH(hdr)); } - VMFREE(dhdp->osh, buf, buflen); + VMFREE(dhdp->osh, buf, alloc_len); DHD_DBG_RING_LOCK(ring->lock, flags); if (!ring->sched_pull) { diff --git a/dhd_linux.c b/dhd_linux.c index 76c6cad..a9ec645 100644 --- a/dhd_linux.c +++ b/dhd_linux.c @@ -14088,6 +14088,16 @@ void dhd_detach(dhd_pub_t *dhdp) } #endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */ + if (dhdp->dbg) { +#ifdef DEBUGABILITY +#ifdef DBG_PKT_MON + dhd_os_dbg_detach_pkt_monitor(dhdp); + osl_spin_lock_deinit(dhd->pub.osh, dhd->pub.dbg->pkt_mon_lock); +#endif /* DBG_PKT_MON */ +#endif /* DEBUGABILITY */ + dhd_os_dbg_detach(dhdp); + } + /* delete all interfaces, start with virtual */ if (dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) { int i = 1; @@ -14146,7 +14156,9 @@ void dhd_detach(dhd_pub_t *dhdp) MFREE(dhd->pub.osh, ifp, sizeof(*ifp)); ifp = NULL; #ifdef WL_CFG80211 - cfg->wdev->netdev = NULL; + if (cfg && cfg->wdev) { + cfg->wdev->netdev = NULL; + } #endif } } @@ -14258,17 +14270,6 @@ void dhd_detach(dhd_pub_t *dhdp) dhdp->dbus = NULL; } #endif /* BCMDBUS */ -#ifdef DEBUGABILITY - if (dhdp->dbg) { -#ifdef DBG_PKT_MON - dhd_os_dbg_detach_pkt_monitor(dhdp); - osl_spin_lock_deinit(dhd->pub.osh, dhd->pub.dbg->pkt_mon_lock); -#endif /* DBG_PKT_MON */ - } -#endif /* DEBUGABILITY */ - if (dhdp->dbg) { - dhd_os_dbg_detach(dhdp); - } #ifdef DHD_MEM_STATS osl_spin_lock_deinit(dhd->pub.osh, dhd->pub.mem_stats_lock); #endif /* DHD_MEM_STATS */ @@ -19087,6 +19088,20 @@ char map_path[PATH_MAX] = VENDOR_PATH CONFIG_BCMDHD_MAP_PATH; extern int dhd_collect_coredump(dhd_pub_t *dhdp, dhd_dump_t *dump); #endif /* DHD_COREDUMP */ +#ifdef DHD_SSSR_COREDUMP +static bool +dhd_is_coredump_reqd(char *trapstr, uint str_len) +{ +#ifdef DHD_SKIP_COREDUMP_ON_HC + if (trapstr && str_len && + strnstr(trapstr, DHD_COREDUMP_IGNORE_TRAP_SIG, str_len)) { + return FALSE; + } +#endif /* DHD_SKIP_COREDUMP_ON_HC */ + return TRUE; +} +#endif /* DHD_SSSR_COREDUMP */ + static void dhd_mem_dump(void *handle, void *event_info, u8 event) { @@ -19108,8 +19123,9 @@ dhd_mem_dump(void *handle, void *event_info, u8 event) char pc_fn[DHD_FUNC_STR_LEN] = "\0"; char lr_fn[DHD_FUNC_STR_LEN] = "\0"; trap_t *tr; - uint32 memdump_type; + bool collect_coredump = FALSE; #endif /* DHD_COREDUMP */ + uint32 memdump_type; DHD_ERROR(("%s: ENTER \n", __FUNCTION__)); @@ -19123,6 +19139,8 @@ dhd_mem_dump(void *handle, void *event_info, u8 event) DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__)); return; } + /* keep it locally to avoid overwriting in other contexts */ + memdump_type = dhdp->memdump_type; DHD_GENERAL_LOCK(dhdp, flags); if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhdp)) { @@ -19202,6 +19220,7 @@ dhd_mem_dump(void *handle, void *event_info, u8 event) } #endif /* BOARD_HIKEY */ } + dhdp->skip_memdump_map_read = FALSE; #elif defined(DHD_DEBUGABILITY_DEBUG_DUMP) dhd_debug_dump_to_ring(dhdp); #endif /* DHD_FILE_DUMP_EVENT */ @@ -19214,14 +19233,11 @@ dhd_mem_dump(void *handle, void *event_info, u8 event) memdump_type = DUMP_TYPE_BY_DSACK_HC_DUE_TO_ISR_DELAY; } else if (dhdp->dsack_hc_due_to_dpc_delay) { memdump_type = DUMP_TYPE_BY_DSACK_HC_DUE_TO_DPC_DELAY; - } else { - memdump_type = dhdp->memdump_type; } - dhd_convert_memdump_type_to_str(memdump_type, dhdp->memdump_str, DHD_MEMDUMP_LONGSTR_LEN, dhdp->debug_dump_subcmd); - if (dhdp->memdump_type == DUMP_TYPE_DONGLE_TRAP && + if (memdump_type == DUMP_TYPE_DONGLE_TRAP && dhdp->dongle_trap_occured == TRUE) { if (!dhdp->dsack_hc_due_to_isr_delay && !dhdp->dsack_hc_due_to_dpc_delay) { @@ -19235,19 +19251,28 @@ dhd_mem_dump(void *handle, void *event_info, u8 event) DHD_ERROR(("%s: dump reason: %s\n", __FUNCTION__, dhdp->memdump_str)); #ifdef DHD_SSSR_COREDUMP - ret = dhd_collect_coredump(dhdp, dump); - if (ret == BCME_ERROR) { - DHD_ERROR(("%s: dhd_collect_coredump() failed.\n", __FUNCTION__)); - goto exit; - } else if (ret == BCME_UNSUPPORTED) { - DHD_LOG_MEM(("%s: Unable to collect SSSR dumps. Skip it.\n", + if (dhd_is_coredump_reqd(dhdp->memdump_str, + strnlen(dhdp->memdump_str, DHD_MEMDUMP_LONGSTR_LEN))) { + ret = dhd_collect_coredump(dhdp, dump); + if (ret == BCME_ERROR) { + DHD_ERROR(("%s: dhd_collect_coredump() failed.\n", + __FUNCTION__)); + goto exit; + } else if (ret == BCME_UNSUPPORTED) { + DHD_LOG_MEM(("%s: Unable to collect SSSR dumps. Skip it.\n", + __FUNCTION__)); + } + collect_coredump = TRUE; + } else { + DHD_PRINT(("%s: coredump not collected, dhd_is_coredump_reqd returns false\n", __FUNCTION__)); } #endif /* DHD_SSSR_COREDUMP */ - if (dhdp->memdump_type == DUMP_TYPE_BY_SYSDUMP) { - DHD_LOG_MEM(("%s: coredump is not supported for BY_SYSDUMP\n", + if (memdump_type == DUMP_TYPE_BY_SYSDUMP) { + DHD_LOG_MEM(("%s: coredump is not supported for BY_SYSDUMP/non trap cases\n", __FUNCTION__)); - } else { + } else if (collect_coredump) { + DHD_ERROR(("%s: writing SoC_RAM dump\n", __FUNCTION__)); if (wifi_platform_set_coredump(dhd->adapter, dump->buf, dump->bufsize, dhdp->memdump_str)) { DHD_ERROR(("%s: writing SoC_RAM dump failed\n", __FUNCTION__)); @@ -19305,7 +19330,7 @@ dhd_mem_dump(void *handle, void *event_info, u8 event) */ #ifdef DHD_LOG_DUMP if (dhd->scheduled_memdump && - dhdp->memdump_type != DUMP_TYPE_BY_SYSDUMP) { + memdump_type != DUMP_TYPE_BY_SYSDUMP) { log_dump_type_t *flush_type = MALLOCZ(dhdp->osh, sizeof(log_dump_type_t)); if (flush_type) { @@ -19341,16 +19366,16 @@ dhd_mem_dump(void *handle, void *event_info, u8 event) if (dhd->pub.memdump_enabled == DUMP_MEMFILE_BUGON && #ifdef DHD_LOG_DUMP - dhd->pub.memdump_type != DUMP_TYPE_BY_SYSDUMP && + memdump_type != DUMP_TYPE_BY_SYSDUMP && #endif /* DHD_LOG_DUMP */ - dhd->pub.memdump_type != DUMP_TYPE_BY_USER && + memdump_type != DUMP_TYPE_BY_USER && #ifdef DHD_DEBUG_UART dhd->pub.memdump_success == TRUE && #endif /* DHD_DEBUG_UART */ #ifdef DNGL_EVENT_SUPPORT - dhd->pub.memdump_type != DUMP_TYPE_DONGLE_HOST_EVENT && + memdump_type != DUMP_TYPE_DONGLE_HOST_EVENT && #endif /* DNGL_EVENT_SUPPORT */ - dhd->pub.memdump_type != DUMP_TYPE_CFG_VENDOR_TRIGGERED) { + memdump_type != DUMP_TYPE_CFG_VENDOR_TRIGGERED) { #ifdef SHOW_LOGTRACE /* Wait till logtrace context is flushed */ dhd_flush_logtrace_process(dhd); diff --git a/dhd_linux_exportfs.c b/dhd_linux_exportfs.c index 62d4fb2..3dc6f7a 100644 --- a/dhd_linux_exportfs.c +++ b/dhd_linux_exportfs.c @@ -580,7 +580,7 @@ static const uint16 pwrstats_req_type[] = { extern uint64 dhdpcie_get_last_suspend_time(dhd_pub_t *dhdp); -static ssize_t +ssize_t show_pwrstats_path(struct dhd_info *dev, char *buf) { int err = 0; @@ -2166,28 +2166,13 @@ static ssize_t trigger_dhd_dump_start_command(struct dhd_info *dhd, char *buf) { ssize_t ret = 0; - dhd_pub_t *dhdp; - unsigned long flags = 0; - dhdp = &dhd->pub; if (dhd->pub.up == 0) { DHD_ERROR(("%s: Not up\n", __FUNCTION__)); return -EINVAL; } DHD_ERROR(("%s: dump_start command delivered.\n", __FUNCTION__)); - DHD_GENERAL_LOCK(dhdp, flags); - DHD_BUS_BUSY_SET_IN_DUMP_DONGLE_MEM(&dhd->pub); - DHD_GENERAL_UNLOCK(dhdp, flags); - - dhd_log_dump_trigger(dhdp, CMD_DEFAULT); - - DHD_GENERAL_LOCK(dhdp, flags); - DHD_BUS_BUSY_CLEAR_IN_DUMP_DONGLE_MEM(&dhd->pub); - dhd_os_busbusy_wake(dhdp); - DHD_GENERAL_UNLOCK(dhdp, flags); - - ret = scnprintf(buf, PAGE_SIZE -1, "%u\n", 0); return ret; } diff --git a/dhd_linux_platdev.c b/dhd_linux_platdev.c index 785433a..a811f48 100644 --- a/dhd_linux_platdev.c +++ b/dhd_linux_platdev.c @@ -117,10 +117,10 @@ extern bool check_bcm4335_rev(void); #if defined(CONFIG_X86) #define PCIE_RC_VENDOR_ID 0x8086 #define PCIE_RC_DEVICE_ID 0x9c1a -#elif defined(CONFIG_ARCH_TEGRA) +#elif defined(CONFIG_PCI_TEGRA) #define PCIE_RC_VENDOR_ID 0x14e4 #define PCIE_RC_DEVICE_ID 0x4347 -#else /* CONFIG_ARCH_TEGRA */ +#else /* CONFIG_PCI_TEGRA */ /* Dummy defn */ #define PCIE_RC_VENDOR_ID 0xffff #define PCIE_RC_DEVICE_ID 0xffff diff --git a/dhd_linux_rx.c b/dhd_linux_rx.c index cc15f2c..5490fc8 100644 --- a/dhd_linux_rx.c +++ b/dhd_linux_rx.c @@ -735,7 +735,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) #if defined(DHD_WAKE_STATUS) && defined(DHD_WAKEPKT_DUMP) if (pkt_wake) { DHD_ERROR(("##### dhdpcie_host_wake caused by packets\n")); - dhd_prhex("[wakepkt_dump]", (char*)dump_data, MIN(len, 64), DHD_ERROR_VAL); + dhd_prhex("[wakepkt_dump]", (char*)dump_data, MIN(len, 64), DHD_RPM_VAL); DHD_ERROR(("config check in_suspend: %d\n", dhdp->in_suspend)); #ifdef ARP_OFFLOAD_SUPPORT DHD_ERROR(("arp hmac_update:%d \n", dhdp->hmac_updated)); @@ -1308,6 +1308,11 @@ dhd_rx_mon_pkt(dhd_pub_t *dhdp, host_rxbuf_cmpl_t* msg, void *pkt, int ifidx) netif_rx(dhd->monitor_skb); dhd->monitor_skb = NULL; + +#if defined(OEM_ANDROID) + DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(dhdp, DHD_MONITOR_TIMEOUT_MS); + DHD_OS_WAKE_LOCK_TIMEOUT(dhdp); +#endif /* OEM_ANDROID */ } #endif /* WL_MONITOR */ diff --git a/dhd_linux_tx.c b/dhd_linux_tx.c index d370c03..e4a6041 100644 --- a/dhd_linux_tx.c +++ b/dhd_linux_tx.c @@ -308,7 +308,15 @@ BCMFASTPATH(__dhd_sendpkt)(dhd_pub_t *dhdp, int ifidx, void *pktbuf) { #if (!defined(BCM_ROUTER_DHD) && (defined(QOS_MAP_SET) || \ defined(WL_CUSTOM_MAPPING_OF_DSCP))) - pktsetprio_qms(pktbuf, wl_get_up_table(dhdp, ifidx), FALSE); + u8 *up_table = wl_get_up_table(dhdp, ifidx); + pktsetprio_qms(pktbuf, up_table, FALSE); + if (PKTPRIO(pktbuf) > MAXPRIO) { + DHD_ERROR_RLMT(("wrong user prio:%d from qosmap ifidx:%d\n", + PKTPRIO(pktbuf), ifidx)); + if (up_table) { + prhex("up_table", up_table, UP_TABLE_MAX); + } + } #else /* For LLR, pkt prio will be changed to 7(NC) here */ pktsetprio(pktbuf, FALSE); @@ -358,13 +366,20 @@ BCMFASTPATH(__dhd_sendpkt)(dhd_pub_t *dhdp, int ifidx, void *pktbuf) /* we only have support for one tx_profile at the moment */ /* tagged packets must be put into TID 6 */ - pkt_flow_prio = PRIO_8021D_VO; - } else + PKTSETPRIO(pktbuf, PRIO_8021D_VO); + } #endif /* defined(DHD_TX_PROFILE) */ - { - pkt_flow_prio = dhdp->flow_prio_map[(PKTPRIO(pktbuf))]; + + if (PKTPRIO(pktbuf) > MAXPRIO) { + DHD_ERROR_RLMT(("Wrong user prio:%d ifidx:%d\n", PKTPRIO(pktbuf), ifidx)); + /* non-assert build, print ratelimit error, free packet and exit */ + ASSERT(0); + PKTCFREE(dhd->pub.osh, pktbuf, TRUE); + return BCME_ERROR; } + pkt_flow_prio = dhdp->flow_prio_map[(PKTPRIO(pktbuf))]; + ret = dhd_flowid_update(dhdp, ifidx, pkt_flow_prio, pktbuf); if (ret != BCME_OK) { PKTCFREE(dhd->pub.osh, pktbuf, TRUE); @@ -698,6 +713,25 @@ BCMFASTPATH(dhd_start_xmit)(struct sk_buff *skb, struct net_device *net) bcm_object_trace_opr(skb, BCM_OBJDBG_ADD_PKT, __FUNCTION__, __LINE__); +#ifdef HOST_SFH_LLC + /* if upper layer has cloned the skb, ex:- packet filter + * unclone the skb, otherwise due to host sfh llc insertion + * the upper layer packet capture will show wrong ethernet DA/SA + */ + if (unlikely(skb_cloned(skb))) { + int res = 0; + gfp_t gfp_flags = CAN_SLEEP() ? GFP_KERNEL : GFP_ATOMIC; + res = skb_unclone(skb, gfp_flags); + if (res) { + DHD_ERROR_RLMT(("%s: sbk_unclone fails ! err = %d\n", + __FUNCTION__, res)); +#ifdef CUSTOMER_HW2_DEBUG + return -ENOMEM; +#endif /* CUSTOMER_HW2_DEBUG */ + } + } +#endif /* HOST_SFH_LLC */ + /* re-align socket buffer if "skb->data" is odd address */ if (((unsigned long)(skb->data)) & 0x1) { unsigned char *data = skb->data; diff --git a/dhd_log_dump.c b/dhd_log_dump.c index e6b6ff7..661c2ca 100644 --- a/dhd_log_dump.c +++ b/dhd_log_dump.c @@ -1882,6 +1882,24 @@ dhd_log_dump_get_timestamp(void) } void +dhd_log_dump_vendor_trigger(dhd_pub_t *dhd_pub) +{ + unsigned long flags = 0; + DHD_GENERAL_LOCK(dhd_pub, flags); + DHD_BUS_BUSY_SET_IN_DUMP_DONGLE_MEM(dhd_pub); + DHD_GENERAL_UNLOCK(dhd_pub, flags); + + dhd_log_dump_trigger(dhd_pub, CMD_DEFAULT); + + DHD_GENERAL_LOCK(dhd_pub, flags); + DHD_BUS_BUSY_CLEAR_IN_DUMP_DONGLE_MEM(dhd_pub); + dhd_os_busbusy_wake(dhd_pub); + DHD_GENERAL_UNLOCK(dhd_pub, flags); + + return; +} + +void dhd_log_dump_trigger(dhd_pub_t *dhdp, int subcmd) { #if defined(DHD_DUMP_FILE_WRITE_FROM_KERNEL) diff --git a/dhd_log_dump.h b/dhd_log_dump.h index 9328b27..074d426 100644 --- a/dhd_log_dump.h +++ b/dhd_log_dump.h @@ -280,6 +280,7 @@ extern void dhd_log_dump_write(int type, char *binary_data, int binary_len, const char *fmt, ...); void dhd_schedule_log_dump(dhd_pub_t *dhdp, void *type); void dhd_log_dump_trigger(dhd_pub_t *dhdp, int subcmd); +void dhd_log_dump_vendor_trigger(dhd_pub_t *dhd_pub); #ifdef DHD_DEBUGABILITY_DEBUG_DUMP int dhd_debug_dump_get_ring_num(int sec_type); diff --git a/dhd_msgbuf.c b/dhd_msgbuf.c index 6768e4f..4bc1d1a 100644 --- a/dhd_msgbuf.c +++ b/dhd_msgbuf.c @@ -7240,10 +7240,6 @@ dhd_prot_update_txflowring(dhd_pub_t *dhd, uint16 flowid, void *msgring) DHD_ERROR(("%s: NULL txflowring. exiting...\n", __FUNCTION__)); return FALSE; } - /* Update read pointer */ - if (dhd->dma_d2h_ring_upd_support) { - ring->rd = dhd_prot_dma_indx_get(dhd, H2D_DMA_INDX_RD_UPD, ring->idx); - } DHD_TRACE(("ringid %d flowid %d write %d read %d \n\n", ring->idx, flowid, ring->wr, ring->rd)); @@ -7754,6 +7750,7 @@ dhd_prot_ioctcmplt_process(dhd_pub_t *dhd, void *msg) #ifdef REPORT_FATAL_TIMEOUTS uint16 dhd_xt_id; #endif + int ret = 0; /* Check for ioctl timeout induce flag, which is set by firing * dhd iovar to induce IOCTL timeout. If flag is set, @@ -7849,11 +7846,18 @@ dhd_prot_ioctcmplt_process(dhd_pub_t *dhd, void *msg) pkt_id, xt_id, prot->ioctl_status, prot->ioctl_resplen)); if (prot->ioctl_resplen > 0) { + uint16 copy_len = MIN(prot->ioctl_resplen, prot->retbuf.len); #ifndef IOCTLRESP_USE_CONSTMEM - bcopy(PKTDATA(dhd->osh, pkt), prot->retbuf.va, prot->ioctl_resplen); + ret = memcpy_s(prot->retbuf.va, prot->retbuf.len, PKTDATA(dhd->osh, pkt), copy_len); #else - bcopy(pkt, prot->retbuf.va, prot->ioctl_resplen); + ret = memcpy_s(prot->retbuf.va, prot->retbuf.len, pkt, copy_len); #endif /* !IOCTLRESP_USE_CONSTMEM */ + if (ret) { + DHD_ERROR(("memcpy failed:%d, destsz:%d, n:%u\n", + ret, prot->retbuf.len, copy_len)); + dhd_wakeup_ioctl_event(dhd, IOCTL_RETURN_ON_ERROR); + goto exit; + } } /* wake up any dhd_os_ioctl_resp_wait() */ @@ -5408,7 +5408,7 @@ static int dhdpcie_mem_dump(dhd_bus_t *bus) { dhd_pub_t *dhdp; - int ret; + int ret = BCME_OK; uint32 dhd_console_ms_prev = 0; #ifdef GDB_PROXY @@ -5534,11 +5534,15 @@ dhdpcie_mem_dump(dhd_bus_t *bus) return BCME_ERROR; #endif /* DHD_PCIE_NATIVE_RUNTIMEPM */ - ret = dhdpcie_get_mem_dump(bus); - if (ret) { - DHD_ERROR(("%s: failed to get mem dump, err=%d\n", - __FUNCTION__, ret)); - goto exit; + if (dhdp->skip_memdump_map_read == FALSE) { + ret = dhdpcie_get_mem_dump(bus); + if (ret) { + DHD_ERROR(("%s: failed to get mem dump, err=%d\n", __FUNCTION__, ret)); + goto exit; + } + } else { + DHD_ERROR(("%s: Skipped to get mem dump, err=%d\n", __FUNCTION__, ret)); + dhdp->skip_memdump_map_read = FALSE; } #ifdef DHD_DEBUG_UART bus->dhd->memdump_success = TRUE; @@ -9310,8 +9314,8 @@ dhdpcie_bus_suspend(struct dhd_bus *bus, bool state, bool byint) dhdpcie_bus_suspend(struct dhd_bus *bus, bool state) #endif /* DHD_PCIE_NATIVE_RUNTIMEPM */ { - int timeleft; - int rc = 0; + int timeleft = 0; + int rc = 0, ret = BCME_OK; unsigned long flags; #ifdef DHD_PCIE_NATIVE_RUNTIMEPM int d3_read_retry = 0; @@ -9465,17 +9469,19 @@ dhdpcie_bus_suspend(struct dhd_bus *bus, bool state) #ifdef PCIE_INB_DW if (INBAND_DW_ENAB(bus)) { DHD_BUS_INB_DW_LOCK(bus->inb_lock, flags); - dhdpcie_send_mb_data(bus, H2D_HOST_D3_INFORM); + ret = dhdpcie_send_mb_data(bus, H2D_HOST_D3_INFORM); DHD_BUS_INB_DW_UNLOCK(bus->inb_lock, flags); } else #endif /* PCIE_INB_DW */ { - dhdpcie_send_mb_data(bus, H2D_HOST_D3_INFORM); + ret = dhdpcie_send_mb_data(bus, H2D_HOST_D3_INFORM); } - /* Wait for D3 ACK for D3_ACK_RESP_TIMEOUT seconds */ + if (!bus->is_linkdown && ret == BCME_OK) { + /* Wait for D3 ACK for D3_ACK_RESP_TIMEOUT seconds */ + timeleft = dhd_os_d3ack_wait(bus->dhd, &bus->wait_for_d3_ack); + } - timeleft = dhd_os_d3ack_wait(bus->dhd, &bus->wait_for_d3_ack); #ifdef DHD_RECOVER_TIMEOUT /* XXX: WAR for missing D3 ACK MB interrupt */ if (bus->wait_for_d3_ack == 0) { @@ -827,10 +827,10 @@ extern void dhd_bus_doorbell_timeout_reset(struct dhd_bus *bus); #define DHD_PCIE_DMA_MASK_FOR_GS101 36 #endif /* DHD_SET_PCIE_DMA_MASK_FOR_GS101 */ -#ifdef CONFIG_ARCH_TEGRA +#ifdef CONFIG_PCI_TEGRA extern int tegra_pcie_pm_suspend(void); extern int tegra_pcie_pm_resume(void); -#endif /* CONFIG_ARCH_TEGRA */ +#endif /* CONFIG_PCI_TEGRA */ extern int dhd_buzzz_dump_dngl(dhd_bus_t *bus); #ifdef IDLE_TX_FLOW_MGMT diff --git a/dhd_pcie_linux.c b/dhd_pcie_linux.c index 43105b6..f94e095 100644 --- a/dhd_pcie_linux.c +++ b/dhd_pcie_linux.c @@ -2556,9 +2556,9 @@ dhdpcie_start_host_dev(dhd_bus_t *bus) bus->dev, NULL, 0); #endif /* SUPPORT_LINKDOWN_RECOVERY */ #endif /* CONFIG_ARCH_MSM */ -#ifdef CONFIG_ARCH_TEGRA +#ifdef CONFIG_PCI_TEGRA ret = tegra_pcie_pm_resume(); -#endif /* CONFIG_ARCH_TEGRA */ +#endif /* CONFIG_PCI_TEGRA */ if (ret) { DHD_ERROR(("%s Failed to bring up PCIe link\n", __FUNCTION__)); @@ -2606,9 +2606,9 @@ dhdpcie_stop_host_dev(dhd_bus_t *bus) bus->dev, NULL, 0); #endif /* SUPPORT_LINKDOWN_RECOVERY */ #endif /* CONFIG_ARCH_MSM */ -#ifdef CONFIG_ARCH_TEGRA +#ifdef CONFIG_PCI_TEGRA ret = tegra_pcie_pm_suspend(); -#endif /* CONFIG_ARCH_TEGRA */ +#endif /* CONFIG_PCI_TEGRA */ if (ret) { DHD_ERROR(("Failed to stop PCIe link\n")); goto done; @@ -3319,7 +3319,7 @@ bool dhd_runtimepm_state(dhd_pub_t *dhd) !DHD_CHECK_CFG_IN_PROGRESS(dhd) && !dhd_os_check_wakelock_all(bus->dhd)) { #ifdef WL_CFG80211 ps_mode_off_dur = dhd_ps_mode_managed_dur(dhd); - DHD_ERROR(("%s: DHD Idle state!! - idletime :%d, wdtick :%d, " + DHD_RPM(("%s: DHD Idle state!! - idletime :%d, wdtick :%d, " "PS mode off dur: %d sec \n", __FUNCTION__, bus->idletime, dhd_runtimepm_ms, ps_mode_off_dur)); #else @@ -3332,6 +3332,9 @@ bool dhd_runtimepm_state(dhd_pub_t *dhd) /* stop all interface network queue. */ dhd_bus_stop_queue(bus); DHD_GENERAL_UNLOCK(dhd, flags); +#ifdef WLAN_TRACKER + dhd_custom_notify(CUSTOM_NOTIFY_BUS_SUSPEND); +#endif /* WLAN_TRACKER */ /* RPM suspend is failed, return FALSE then re-trying */ if (dhdpcie_set_suspend_resume(bus, TRUE)) { DHD_ERROR(("%s: exit with wakelock \n", __FUNCTION__)); @@ -3426,7 +3429,7 @@ bool dhd_runtimepm_state(dhd_pub_t *dhd) smp_wmb(); wake_up(&bus->rpm_queue); - DHD_ERROR(("%s : runtime resume ended \n", __FUNCTION__)); + DHD_RPM(("%s : runtime resume ended \n", __FUNCTION__)); return TRUE; } else { DHD_GENERAL_UNLOCK(dhd, flags); @@ -3473,7 +3476,7 @@ bool dhd_runtime_bus_wake(dhd_bus_t *bus, bool wait, void *func_addr) DHD_GENERAL_UNLOCK(bus->dhd, flags); - DHD_ERROR(("Runtime Resume is called in %ps\n", func_addr)); + DHD_RPM(("Runtime Resume is called in %ps\n", func_addr)); smp_wmb(); wake_up(&bus->rpm_queue); /* No need to wake up the RPM state thread */ @@ -95,5 +95,19 @@ extern uint32 dhd_plat_get_rc_vendor_id(void); extern uint32 dhd_plat_get_rc_device_id(void); extern uint16 dhd_plat_align_rxbuf_size(uint16 rxbufpost_sz); + +#ifdef WLAN_TRACKER +enum { + CUSTOM_NOTIFY_BUS_SUSPEND, + CUSTOM_NOTIFY_STA_CONNECT, + CUSTOM_NOTIFY_STA_DISCONNECT, + CUSTOM_NOTIFY_TWT_SETUP, + CUSTOM_NOTIFY_TWT_TEARDOWN, + CUSTOM_NOTIFY_MAX, +}; + +extern int dhd_custom_notify(u32 id); +#endif /* WLAN_TRACKER */ + #endif /* __linux__ */ #endif /* __DHD_PLAT_H__ */ @@ -1168,6 +1168,7 @@ dhd_pno_stop_for_ssid(dhd_pub_t *dhd) _pno_state = PNO_GET_PNOSTATE(dhd); if (!(_pno_state->pno_mode & DHD_PNO_LEGACY_MODE)) { DHD_ERROR(("%s : LEGACY PNO MODE is not enabled\n", __FUNCTION__)); + err = BCME_UNSUPPORTED; goto exit; } DHD_PNO(("%s enter\n", __FUNCTION__)); @@ -199,6 +199,12 @@ typedef struct ftm_status_map_host_entry { rtt_reason_t rtt_reason; } ftm_status_map_host_entry_t; +typedef struct rtt_event_data_info { + wl_proxd_ftm_session_status_t *session_status; + rtt_result_t *rtt_result; + bcm_xtlv_t *tlv; +} rtt_event_data_info_t; + static uint16 rtt_result_ver(uint16 tlvid, const uint8 *p_data); @@ -844,24 +850,32 @@ rtt_collect_data_event_ver(uint16 len) } } -static void -rtt_collect_event_data_display(uint8 ver, void *ctx, const uint8 *p_data, uint16 len) +static int +rtt_collect_event_data_display(uint8 ver, bcm_xtlv_t *tlv, const uint8 *p_data, uint16 len) { int i; + int ret = BCME_OK; wl_proxd_collect_event_data_v1_t *p_collect_data_v1 = NULL; wl_proxd_collect_event_data_v2_t *p_collect_data_v2 = NULL; wl_proxd_collect_event_data_v3_t *p_collect_data_v3 = NULL; wl_proxd_collect_event_data_v4_t *p_collect_data_v4 = NULL; - if (!ctx || !p_data) { - return; + if (!tlv || !p_data) { + return BCME_ERROR; + } + if (!(len < BCM_XTLV_MAX_DATA_SIZE_EX(BCM_XTLV_OPTION_NONE))) { + return BCME_BUFTOOLONG; } switch (ver) { case WL_PROXD_COLLECT_EVENT_DATA_VERSION_1: DHD_RTT(("\tVERSION_1\n")); - memcpy(ctx, p_data, sizeof(wl_proxd_collect_event_data_v1_t)); - p_collect_data_v1 = (wl_proxd_collect_event_data_v1_t *)ctx; + ret = memcpy_s(tlv->data, tlv->len, p_data, + sizeof(wl_proxd_collect_event_data_v1_t)); + if (ret != BCME_OK) { + break; + } + p_collect_data_v1 = (wl_proxd_collect_event_data_v1_t *)tlv->data; DHD_RTT(("\tH_RX\n")); for (i = 0; i < K_TOF_COLLECT_H_SIZE_20MHZ; i++) { p_collect_data_v1->H_RX[i] = ltoh32_ua(&p_collect_data_v1->H_RX[i]); @@ -882,8 +896,12 @@ rtt_collect_event_data_display(uint8 ver, void *ctx, const uint8 *p_data, uint16 DHD_RTT(("\tphy_err_mask=0x%x\n", p_collect_data_v1->phy_err_mask)); break; case WL_PROXD_COLLECT_EVENT_DATA_VERSION_2: - memcpy(ctx, p_data, sizeof(wl_proxd_collect_event_data_v2_t)); - p_collect_data_v2 = (wl_proxd_collect_event_data_v2_t *)ctx; + ret = memcpy_s(tlv->data, tlv->len, p_data, + sizeof(wl_proxd_collect_event_data_v2_t)); + if (ret != BCME_OK) { + break; + } + p_collect_data_v2 = (wl_proxd_collect_event_data_v2_t *)tlv->data; DHD_RTT(("\tH_RX\n")); for (i = 0; i < K_TOF_COLLECT_H_SIZE_20MHZ; i++) { p_collect_data_v2->H_RX[i] = ltoh32_ua(&p_collect_data_v2->H_RX[i]); @@ -904,8 +922,12 @@ rtt_collect_event_data_display(uint8 ver, void *ctx, const uint8 *p_data, uint16 DHD_RTT(("\tphy_err_mask=0x%x\n", p_collect_data_v2->phy_err_mask)); break; case WL_PROXD_COLLECT_EVENT_DATA_VERSION_3: - memcpy(ctx, p_data, sizeof(wl_proxd_collect_event_data_v3_t)); - p_collect_data_v3 = (wl_proxd_collect_event_data_v3_t *)ctx; + ret = memcpy_s(tlv->data, tlv->len, p_data, + sizeof(wl_proxd_collect_event_data_v3_t)); + if (ret != BCME_OK) { + break; + } + p_collect_data_v3 = (wl_proxd_collect_event_data_v3_t *)tlv->data; switch (p_collect_data_v3->version) { case WL_PROXD_COLLECT_EVENT_DATA_VERSION_3: if (p_collect_data_v3->length != @@ -939,8 +961,12 @@ rtt_collect_event_data_display(uint8 ver, void *ctx, const uint8 *p_data, uint16 } break; case WL_PROXD_COLLECT_EVENT_DATA_VERSION_4: - memcpy(ctx, p_data, sizeof(wl_proxd_collect_event_data_v4_t)); - p_collect_data_v4 = (wl_proxd_collect_event_data_v4_t *)ctx; + ret = memcpy_s(tlv->data, tlv->len, p_data, + sizeof(wl_proxd_collect_event_data_v4_t)); + if (ret != BCME_OK) { + break; + } + p_collect_data_v4 = (wl_proxd_collect_event_data_v4_t *)tlv->data; switch (p_collect_data_v4->version) { case WL_PROXD_COLLECT_EVENT_DATA_VERSION_4: if (p_collect_data_v4->length != @@ -974,6 +1000,7 @@ rtt_collect_event_data_display(uint8 ver, void *ctx, const uint8 *p_data, uint16 } break; } + return ret; } static uint16 @@ -1057,9 +1084,10 @@ rtt_unpack_xtlv_cbfn(void *ctx, const uint8 *p_data, uint16 tlvid, uint16 len) wl_proxd_ftm_session_status_t *p_data_info = NULL; uint32 chan_data_entry = 0; uint16 expected_rtt_result_ver = 0; -#ifdef WL_RTT_LCI - bcm_xtlv_t *tlv = NULL; -#endif /* WL_RTT_LCI */ + + rtt_event_data_info_t *rtt_event_data_info = (rtt_event_data_info_t *)ctx; + rtt_result_t *rtt_result = rtt_event_data_info->rtt_result; + bcm_xtlv_t *tlv = rtt_event_data_info->tlv; BCM_REFERENCE(p_data_info); @@ -1069,17 +1097,21 @@ rtt_unpack_xtlv_cbfn(void *ctx, const uint8 *p_data, uint16 tlvid, uint16 len) case WL_PROXD_TLV_ID_RTT_RESULT_V3: DHD_RTT(("WL_PROXD_TLV_ID_RTT_RESULT\n")); expected_rtt_result_ver = rtt_result_ver(tlvid, p_data); + if (rtt_result == NULL) { + ret = BCME_ERROR; + break; + } switch (expected_rtt_result_ver) { case WL_PROXD_RTT_RESULT_VERSION_1: - ret = dhd_rtt_convert_results_to_host_v1((rtt_result_t *)ctx, + ret = dhd_rtt_convert_results_to_host_v1(rtt_result, p_data, tlvid, len); break; case WL_PROXD_RTT_RESULT_VERSION_2: - ret = dhd_rtt_convert_results_to_host_v2((rtt_result_t *)ctx, + ret = dhd_rtt_convert_results_to_host_v2(rtt_result, p_data, tlvid, len); break; case WL_PROXD_RTT_RESULT_VERSION_3: - ret = dhd_rtt_convert_results_to_host_v3((rtt_result_t *)ctx, + ret = dhd_rtt_convert_results_to_host_v3(rtt_result, p_data, tlvid, len); break; default: @@ -1090,8 +1122,17 @@ rtt_unpack_xtlv_cbfn(void *ctx, const uint8 *p_data, uint16 tlvid, uint16 len) break; case WL_PROXD_TLV_ID_SESSION_STATUS: DHD_RTT(("WL_PROXD_TLV_ID_SESSION_STATUS\n")); - memcpy(ctx, p_data, sizeof(wl_proxd_ftm_session_status_t)); - p_data_info = (wl_proxd_ftm_session_status_t *)ctx; + if (rtt_event_data_info->session_status == NULL) { + ret = BCME_ERROR; + break; + } + ret = memcpy_s(rtt_event_data_info->session_status, + sizeof(wl_proxd_ftm_session_status_t), p_data, len); + if (ret != BCME_OK) { + ret = BCME_BUFTOOSHORT; + break; + } + p_data_info = (wl_proxd_ftm_session_status_t *)rtt_event_data_info->session_status; p_data_info->sid = ltoh16_ua(&p_data_info->sid); p_data_info->state = ltoh16_ua(&p_data_info->state); p_data_info->status = ltoh32_ua(&p_data_info->status); @@ -1109,9 +1150,9 @@ rtt_unpack_xtlv_cbfn(void *ctx, const uint8 *p_data, uint16 tlvid, uint16 len) /* we do not have handle to wl in the context of * xtlv callback without changing the xtlv API. */ - rtt_collect_event_data_display( + ret = rtt_collect_event_data_display( rtt_collect_data_event_ver(len), - ctx, p_data, len); + tlv, p_data, len); break; case WL_PROXD_TLV_ID_COLLECT_CHAN_DATA: GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); @@ -1131,25 +1172,35 @@ rtt_unpack_xtlv_cbfn(void *ctx, const uint8 *p_data, uint16 tlvid, uint16 len) break; #ifdef WL_RTT_LCI case WL_PROXD_TLV_ID_LCI: - tlv = (bcm_xtlv_t *)ctx; DHD_RTT(("WL_PROXD_TLV_ID_LCI, IE data=%lx, len=%d\n", (unsigned long)p_data, len)); rtt_prhex("", p_data, len); if (tlv) { tlv->id = WL_PROXD_TLV_ID_LCI; + ret = memcpy_s(tlv->data, tlv->len, p_data, len); tlv->len = len; - (void)memcpy_s(tlv->data, len, p_data, len); + if (ret != BCME_OK) { + break; + } + } + else { + ret = BCME_ERROR; } break; case WL_PROXD_TLV_ID_CIVIC: - tlv = (bcm_xtlv_t *)ctx; DHD_RTT(("WL_PROXD_TLV_ID_CIVIC, IE data=%lx, len=%d\n", (unsigned long)p_data, len)); rtt_prhex("", p_data, len); if (tlv) { tlv->id = WL_PROXD_TLV_ID_CIVIC; tlv->len = len; - (void)memcpy_s(tlv->data, len, p_data, len); + ret = memcpy_s(tlv->data, tlv->len, p_data, len); + if (ret != BCME_OK) { + break; + } + } + else { + ret = BCME_ERROR; } break; #endif /* WL_RTT_LCI */ @@ -3647,6 +3698,7 @@ dhd_rtt_convert_results_to_host_v2(rtt_result_t *rtt_result, const uint8 *p_data uint8 num_ftm = 0; char *ftm_frame_types[] = FTM_FRAME_TYPES; rtt_report_t *rtt_report = &(rtt_result->report); + chanspec_bw_t chspec_bw = 0; BCM_REFERENCE(ftm_frame_types); BCM_REFERENCE(dist); @@ -3660,6 +3712,7 @@ dhd_rtt_convert_results_to_host_v2(rtt_result_t *rtt_result, const uint8 *p_data BCM_REFERENCE(chanspec); BCM_REFERENCE(session_state); BCM_REFERENCE(ftm_session_state_value_to_logstr); + BCM_REFERENCE(chspec_bw); NULL_CHECK(rtt_report, "rtt_report is NULL", err); NULL_CHECK(p_data, "p_data is NULL", err); @@ -3820,6 +3873,36 @@ dhd_rtt_convert_results_to_host_v2(rtt_result_t *rtt_result, const uint8 *p_data ftm_tmu_value_to_logstr(ltoh16_ua(&p_data_info->u.burst_duration.tmu)))); DHD_RTT(("rtt_report->burst_duration : %d\n", rtt_report->burst_duration)); } + + if (p_data_info->num_meas && p_sample_avg->chanspec) { + chanspec = ltoh32_ua(&p_sample_avg->chanspec); +#ifdef WL_CFG80211 + rtt_result->frequency = wl_channel_to_frequency(wf_chspec_ctlchan(chanspec), + CHSPEC_BAND(chanspec)); +#endif /* WL_CFG80211 */ + chspec_bw = CHSPEC_BW(chanspec); + } + + /* Map as per host enums */ + switch (chspec_bw) { + case WL_CHANSPEC_BW_20: + rtt_result->packet_bw = WIFI_RTT_BW_20; + break; + case WL_CHANSPEC_BW_40: + rtt_result->packet_bw = WIFI_RTT_BW_40; + break; + case WL_CHANSPEC_BW_80: + rtt_result->packet_bw = WIFI_RTT_BW_80; + break; + case WL_CHANSPEC_BW_160: + rtt_result->packet_bw = WIFI_RTT_BW_160; + break; + default: + rtt_result->packet_bw = WIFI_RTT_BW_UNSPECIFIED; + DHD_RTT_ERR(("%s Unspecified bw\n", __FUNCTION__)); + break; + } + /* display detail if available */ num_rtt = ltoh16_ua(&p_data_info->num_rtt); if (num_rtt > 0) { @@ -4076,6 +4159,7 @@ dhd_rtt_convert_results_to_host_v3(rtt_result_t *rtt_result, const uint8 *p_data ftm_tmu_value_to_logstr(ltoh16_ua(&p_data_info->u.burst_duration.tmu)))); DHD_RTT(("rtt_report->burst_duration : %d\n", rtt_report->burst_duration)); } + /* display detail if available */ num_rtt = ltoh16_ua(&p_data_info->num_rtt); if (num_rtt > 0) { @@ -4386,9 +4470,12 @@ dhd_rtt_parse_result_event(wl_proxd_event_t *proxd_ev_data, int tlvs_len, rtt_result_t *rtt_result) { int ret = BCME_OK; + rtt_event_data_info_t rtt_event_data_info; + memset(&rtt_event_data_info, 0, sizeof(rtt_event_data_info_t)); + rtt_event_data_info.rtt_result = rtt_result; /* unpack TLVs and invokes the cbfn to print the event content TLVs */ - ret = bcm_unpack_xtlv_buf((void *) rtt_result, + ret = bcm_unpack_xtlv_buf((void *) &rtt_event_data_info, (uint8 *)&proxd_ev_data->tlvs[0], tlvs_len, BCM_XTLV_OPTION_ALIGN32, rtt_unpack_xtlv_cbfn); if (ret != BCME_OK) { @@ -4639,7 +4726,6 @@ dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) uint16 version; wl_proxd_event_t *p_event; wl_proxd_event_type_t event_type; - wl_proxd_ftm_session_status_t session_status; const ftm_strmap_entry_t *p_loginfo; rtt_result_t *rtt_result; #ifdef WL_CFG80211 @@ -4648,6 +4734,7 @@ dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) bool is_new = TRUE; rtt_target_info_t *target = NULL; #endif /* WL_CFG80211 */ + rtt_event_data_info_t rtt_event_data_info; DHD_RTT(("Enter %s \n", __FUNCTION__)); NULL_CHECK(dhd, "dhd is NULL", ret); @@ -4785,9 +4872,17 @@ dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) #endif /* WL_CFG80211 */ if (tlvs_len > 0) { /* unpack TLVs and invokes the cbfn to print the event content TLVs */ - ret = bcm_unpack_xtlv_buf((void *) &session_status, + rtt_event_data_info.session_status = (wl_proxd_ftm_session_status_t *) + MALLOCZ(dhd->osh, sizeof(wl_proxd_ftm_session_status_t)); + if (!rtt_event_data_info.session_status) { + ret = -ENOMEM; + goto exit; + } + ret = bcm_unpack_xtlv_buf((void *) &rtt_event_data_info, (uint8 *)&p_event->tlvs[0], tlvs_len, BCM_XTLV_OPTION_ALIGN32, rtt_unpack_xtlv_cbfn); + MFREE(dhd->osh, rtt_event_data_info.session_status, + sizeof(wl_proxd_ftm_session_status_t)); if (ret != BCME_OK) { DHD_RTT_ERR(("%s : Failed to unpack xtlv for an event\n", __FUNCTION__)); @@ -4827,19 +4922,19 @@ dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) case WL_PROXD_EVENT_CIVIC_MEAS_REP: DHD_RTT(("WL_PROXD_EVENT_LCI/CIVIC_MEAS_REP\n")); if (tlvs_len > 0) { - void *buffer = NULL; - if (!(buffer = (void *)MALLOCZ(dhd->osh, tlvs_len))) { + if (!(rtt_event_data_info.tlv = (void *)MALLOCZ(dhd->osh, tlvs_len))) { ret = -ENOMEM; goto exit; } + rtt_event_data_info.tlv->len = tlvs_len - BCM_XTLV_HDR_SIZE; /* unpack TLVs and invokes the cbfn to print the event content TLVs */ - ret = bcm_unpack_xtlv_buf(buffer, + ret = bcm_unpack_xtlv_buf(&rtt_event_data_info, (uint8 *)&p_event->tlvs[0], tlvs_len, BCM_XTLV_OPTION_NONE, rtt_unpack_xtlv_cbfn); if (ret != BCME_OK) { DHD_RTT_ERR(("%s : Failed to unpack xtlv for event %d\n", __FUNCTION__, event_type)); - MFREE(dhd->osh, buffer, tlvs_len); + MFREE(dhd->osh, rtt_event_data_info.tlv, tlvs_len); goto exit; } if (event_type == WL_PROXD_EVENT_LCI_MEAS_REP) { @@ -4849,7 +4944,7 @@ dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) target->LCI->len + BCM_XTLV_HDR_SIZE); } DHD_RTT(("WL_PROXD_EVENT_LCI_MEAS_REP: cache the LCI tlv\n")); - target->LCI = (bcm_xtlv_t *)buffer; + target->LCI = rtt_event_data_info.tlv; } else { /* free previous one and update it */ if (target->LCR) { @@ -4857,7 +4952,7 @@ dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) target->LCR->len + BCM_XTLV_HDR_SIZE); } DHD_RTT(("WL_PROXD_EVENT_CIVIC_MEAS_REP: cache the LCR tlv\n")); - target->LCR = (bcm_xtlv_t *)buffer; + target->LCR = rtt_event_data_info.tlv; } } break; @@ -4868,16 +4963,16 @@ dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) case WL_PROXD_EVENT_COLLECT: DHD_RTT(("WL_PROXD_EVENT_COLLECT\n")); if (tlvs_len > 0) { - void *buffer = NULL; - if (!(buffer = (void *)MALLOCZ(dhd->osh, tlvs_len))) { + if (!(rtt_event_data_info.tlv = (void *)MALLOCZ(dhd->osh, tlvs_len))) { ret = -ENOMEM; goto exit; } + rtt_event_data_info.tlv->len = tlvs_len - BCM_XTLV_HDR_SIZE; /* unpack TLVs and invokes the cbfn to print the event content TLVs */ - ret = bcm_unpack_xtlv_buf(buffer, + ret = bcm_unpack_xtlv_buf(&rtt_event_data_info, (uint8 *)&p_event->tlvs[0], tlvs_len, BCM_XTLV_OPTION_NONE, rtt_unpack_xtlv_cbfn); - MFREE(dhd->osh, buffer, tlvs_len); + MFREE(dhd->osh, rtt_event_data_info.tlv, tlvs_len); if (ret != BCME_OK) { DHD_RTT_ERR(("%s : Failed to unpack xtlv for event %d\n", __FUNCTION__, event_type)); @@ -4888,16 +4983,16 @@ dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) case WL_PROXD_EVENT_MF_STATS: DHD_RTT(("WL_PROXD_EVENT_MF_STATS\n")); if (tlvs_len > 0) { - void *buffer = NULL; - if (!(buffer = (void *)MALLOCZ(dhd->osh, tlvs_len))) { + if (!(rtt_event_data_info.tlv = (void *)MALLOCZ(dhd->osh, tlvs_len))) { ret = -ENOMEM; goto exit; } + rtt_event_data_info.tlv->len = tlvs_len - BCM_XTLV_HDR_SIZE; /* unpack TLVs and invokes the cbfn to print the event content TLVs */ - ret = bcm_unpack_xtlv_buf(buffer, + ret = bcm_unpack_xtlv_buf(&rtt_event_data_info, (uint8 *)&p_event->tlvs[0], tlvs_len, BCM_XTLV_OPTION_NONE, rtt_unpack_xtlv_cbfn); - MFREE(dhd->osh, buffer, tlvs_len); + MFREE(dhd->osh, rtt_event_data_info.tlv, tlvs_len); if (ret != BCME_OK) { DHD_RTT_ERR(("%s : Failed to unpack xtlv for event %d\n", __FUNCTION__, event_type)); @@ -159,6 +159,18 @@ enum rtt_rate_bw { RTT_RATE_160M }; +/* RTT Measurement Bandwidth */ +typedef enum wifi_rtt_bw { + WIFI_RTT_BW_UNSPECIFIED = 0x00, + WIFI_RTT_BW_5 = 0x01, + WIFI_RTT_BW_10 = 0x02, + WIFI_RTT_BW_20 = 0x04, + WIFI_RTT_BW_40 = 0x08, + WIFI_RTT_BW_80 = 0x10, + WIFI_RTT_BW_160 = 0x20, + WIFI_RTT_BW_320 = 0x40 +} wifi_rtt_bw_t; + typedef enum ranging_type { RTT_TYPE_INVALID = 0, RTT_TYPE_LEGACY = 1, @@ -392,6 +404,7 @@ typedef struct rtt_results_header { struct list_head list; struct list_head result_list; } rtt_results_header_t; + struct rtt_result_detail { uint8 num_ota_meas; uint32 result_flags; @@ -403,6 +416,10 @@ typedef struct rtt_result { int32 report_len; /* total length of rtt_report */ struct rtt_result_detail rtt_detail; int32 detail_len; + /* primary channel frequency (MHz) used for ranging measurements */ + wifi_channel frequency; + /* RTT packet bandwidth is an average BW of the BWs of RTT frames. */ + uint8 packet_bw; } rtt_result_t; /* RTT Capabilities */ diff --git a/wl_android.c b/wl_android.c index 53e4dc0..7085618 100644 --- a/wl_android.c +++ b/wl_android.c @@ -15092,3 +15092,77 @@ exit: return bytes_written; } #endif /* SUPPORT_AP_INIT_BWCONF */ + +s32 +wl_android_set_blacklist_bssid(struct net_device *dev, maclist_t *blacklist, + uint32 len, uint32 flush) +{ + s32 err; + s32 macmode; + + if (blacklist) { + err = wldev_ioctl_set(dev, WLC_SET_MACLIST, (u8 *)blacklist, len); + if (err != BCME_OK) { + WL_ERR(("WLC_SET_MACLIST failed %d\n", err)); + return err; + } + } + /* By default programming blacklist flushes out old values */ + macmode = (flush && !blacklist) ? WLC_MACMODE_DISABLED : WLC_MACMODE_DENY; + err = wldev_ioctl_set(dev, WLC_SET_MACMODE, (u8 *)&macmode, sizeof(macmode)); + if (err != BCME_OK) { + WL_ERR(("WLC_SET_MACMODE %d failed %d\n", macmode, err)); + } else { + WL_INFORM_MEM(("WLC_SET_MACMODE %d applied\n", macmode)); + } + return err; +} + +s32 +wl_android_set_whitelist_ssid(struct net_device *dev, wl_ssid_whitelist_t *ssid_whitelist, + uint32 len, uint32 flush) +{ + s32 err; + u8 *buf; + u32 buf_len = WLC_IOCTL_MEDLEN; + wl_ssid_whitelist_t whitelist_ssid_flush; + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); + + if (!ssid_whitelist) { + if (flush) { + ssid_whitelist = &whitelist_ssid_flush; + ssid_whitelist->ssid_count = 0; + } else { + WL_ERR(("%s : Nothing to do here\n", __FUNCTION__)); + return BCME_BADARG; + } + } + + buf = (char *)MALLOC(cfg->osh, buf_len); + if (buf == NULL) { + WL_ERR(("failed to allocated memory %d bytes\n", + WLC_IOCTL_MEDLEN)); + return -ENOMEM; + } + + if ((len + strlen("roam_exp_ssid_whitelist")) >= buf_len) { + WL_ERR(("unexpected len for ssid blklist:%d\n", len)); + err = -EINVAL; + goto exit; + } + + ssid_whitelist->version = SSID_WHITELIST_VERSION_1; + ssid_whitelist->flags = flush ? ROAM_EXP_CLEAR_SSID_WHITELIST : 0; + err = wldev_iovar_setbuf(dev, "roam_exp_ssid_whitelist", + (u8 *)ssid_whitelist, len, buf, buf_len, NULL); + if (err != BCME_OK) { + if (err == BCME_UNSUPPORTED) { + WL_ERR(("roam_exp_bssid_pref, UNSUPPORTED \n")); + } else { + WL_ERR(("Failed to execute roam_exp_bssid_pref %d\n", err)); + } + } +exit: + MFREE(cfg->osh, buf, buf_len); + return err; +} diff --git a/wl_android.h b/wl_android.h index 5e330f3..5120c41 100644 --- a/wl_android.h +++ b/wl_android.h @@ -156,6 +156,10 @@ s32 wl_netlink_send_msg(int pid, int type, int seq, const void *data, size_t siz #define APCS_DEFAULT_5G_CH 149 #define APCS_DEFAULT_6G_CH 5 +extern int wl_android_set_whitelist_ssid(struct net_device *dev, + wl_ssid_whitelist_t *ssid_whitelist, uint32 len, uint32 flush); +extern int wl_android_set_blacklist_bssid(struct net_device *dev, maclist_t *blacklist, + uint32 len, uint32 flush); int wl_android_set_ap_mac_list(struct net_device *dev, int macmode, struct maclist *maclist); #ifdef WL_BCNRECV extern int wl_android_bcnrecv_config(struct net_device *ndev, char *data, diff --git a/wl_cfg80211.c b/wl_cfg80211.c index 5a4e780..020bf48 100644 --- a/wl_cfg80211.c +++ b/wl_cfg80211.c @@ -2270,6 +2270,11 @@ wl_cfg80211_p2p_if_add(struct bcm_cfg80211 *cfg, return new_ndev->ieee80211_ptr; } + else { + WL_ERR(("Virtual interface create fail. " + "Checking value timeout [%ld], p2p_status [%x], event_info valid [%x]\n", + timeout, wl_get_p2p_status(cfg, IF_ADDING), cfg->if_event_info.valid)); + } fail: return NULL; @@ -2423,12 +2428,19 @@ wl_cfg80211_iface_state_ops(struct wireless_dev *wdev, wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL); wl_release_vif_macaddr(cfg, wdev->netdev->dev_addr, wl_iftype); #ifdef WL_NAN - if ((wl_iftype == WL_IF_TYPE_NAN) && + if ((cfg->nancfg->nan_init_state && cfg->nancfg->nan_enable && + wl_iftype == WL_IF_TYPE_NAN) && (wl_cfgnan_del_ndi_data(cfg, wdev->netdev->name)) < 0) { WL_ERR(("Failed to find matching data for ndi:%s\n", wdev->netdev->name)); } #endif /* WL_NAN */ +#if defined(KEEP_ALIVE) && defined(DHD_CLEANUP_KEEP_ALIVE) + if ((ndev == cfg->inet_ndev) && cfg->mkeep_alive_avail) { + wl_cleanup_keep_alive(ndev, cfg); + } +#endif /* defined(KEEP_ALIVE) && defined(DHD_CLEANUP_KEEP_ALIVE) */ + break; case WL_IF_CREATE_DONE: if (wl_mode == WL_MODE_BSS) { @@ -2780,7 +2792,6 @@ _wl_cfg80211_add_if(struct bcm_cfg80211 *cfg, } } #endif /* WL_NAN */ - wiphy = bcmcfg_to_wiphy(cfg); #if defined(BCMDONGLEHOST) dhd = (dhd_pub_t *)(cfg->pub); @@ -3089,10 +3100,10 @@ _wl_cfg80211_del_if(struct bcm_cfg80211 *cfg, struct net_device *primary_ndev, #endif /* PCIE_FULL_DONGLE */ #ifdef WL_CELLULAR_CHAN_AVOID - if (wl_iftype == WL_IF_TYPE_AP) { - wl_cellavoid_clear_requested_freq_bands(wdev->netdev, - cfg->cellavoid_info); - } + if (wl_iftype == WL_IF_TYPE_AP) { + wl_cellavoid_clear_requested_freq_bands(wdev->netdev, + cfg->cellavoid_info); + } #endif /* WL_CELLULAR_CHAN_AVOID */ switch (wl_iftype) { @@ -6121,17 +6132,6 @@ wl_do_preassoc_ops(struct bcm_cfg80211 *cfg, wl_restore_ap_bw(cfg); } #endif /* SUPPORT_AP_BWCTRL */ -#if defined(ROAMEXP_SUPPORT) - /* Clear Blacklist bssid and Whitelist ssid list before join issue - * This is temporary fix since currently firmware roaming is not - * disabled by android framework before SSID join from framework - */ - /* Flush blacklist bssid content */ - dhd_dev_set_blacklist_bssid(dev, NULL, 0, true); - /* Flush whitelist ssid content */ - dhd_dev_set_whitelist_ssid(dev, NULL, 0, true); -#endif /* ROAMEXP_SUPPORT */ - WL_DBG(("SME IE : len=%zu\n", sme->ie_len)); if (sme->ie != NULL && sme->ie_len > 0 && (wl_dbg_level & WL_DBG_DBG)) { prhex(NULL, sme->ie, sme->ie_len); @@ -6578,11 +6578,15 @@ wl_handle_assoc_hints(struct bcm_cfg80211 *cfg, struct net_device *dev, WL_DBG(("fw_ap_select:%d skip_hints:%d\n", fw_ap_select, skip_hints)); #endif /* WL_SKIP_CONNECT_HINTS */ + if (IS_P2P_GC(dev->ieee80211_ptr)) { + skip_hints = false; + } + /* Use bssid_hint if hints are allowed and if its unicast addr */ if (!skip_hints && sme->bssid_hint && !ETHER_ISBCAST(sme->bssid_hint)) { WL_INFORM_MEM(("bssid_hint "MACDBG" \n", MAC2STRDBG(sme->bssid_hint))); info->targeted_join = true; - if (cfg->join_iovar_ver) { + if (cfg->join_iovar_ver && IS_STA_IFACE(ndev_to_wdev(dev))) { /* Firmware supports bssid_hint feature */ info->bssid_hint = true; } @@ -6920,6 +6924,11 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, err = -EINVAL; goto fail; } + if (wl_get_drv_status_all(cfg, AP_CREATING)) { + WL_ERR(("AP creates in progress, so skip this connection for creating AP.\n")); + err = -EBUSY; + goto fail; + } #endif /* WL_DUAL_STA */ bzero(&assoc_info, sizeof(wlcfg_assoc_info_t)); if ((assoc_info.bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) { @@ -11939,11 +11948,14 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev static void wl_free_wdev(struct bcm_cfg80211 *cfg) { struct wireless_dev *wdev = cfg->wdev; + struct net_device *ndev; struct wiphy *wiphy = NULL; if (!wdev) { WL_ERR(("wdev is invalid\n")); return; } + + ndev = wdev->netdev; if (wdev->wiphy) { wiphy = wdev->wiphy; @@ -11965,8 +11977,10 @@ static void wl_free_wdev(struct bcm_cfg80211 *cfg) } wl_delete_all_netinfo(cfg); + if (ndev) { + ndev->ieee80211_ptr = NULL; + } if (wiphy) { - MFREE(cfg->osh, wdev, sizeof(*wdev)); wiphy_free(wiphy); } @@ -12815,6 +12829,13 @@ wl_post_linkdown_ops(struct bcm_cfg80211 *cfg, } #endif /* SUPPORT_SET_TID */ +#if defined(ROAMEXP_SUPPORT) + /* Flush blacklist bssid content */ + wl_android_set_blacklist_bssid(ndev, NULL, 0, TRUE); + /* Flush whitelist ssid content */ + wl_android_set_whitelist_ssid(ndev, NULL, 0, TRUE); +#endif /* ROAMEXP_SUPPORT */ + return ret; } @@ -14130,22 +14151,87 @@ wl_check_pmstatus(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, #endif /* CUSTOM_EVENT_PM_WAKE */ #if defined(QOS_MAP_SET) || defined(WL_CUSTOM_MAPPING_OF_DSCP) +void +wl_store_up_table_netinfo(struct bcm_cfg80211 *cfg, + struct net_device *ndev, u8 *uptable) +{ + unsigned long flags; + struct net_info *netinfo; + + WL_CFG_NET_LIST_SYNC_LOCK(&cfg->net_list_sync, flags); + netinfo = _wl_get_netinfo_by_wdev(cfg, ndev->ieee80211_ptr); + if (netinfo) { + netinfo->qos_up_table = uptable; + } else { + WL_ERR(("netinfo not found for %s\n", ndev->name)); + } + WL_CFG_NET_LIST_SYNC_UNLOCK(&cfg->net_list_sync, flags); +} + +u8 * +wl_get_up_table_netinfo(struct bcm_cfg80211 *cfg, struct net_device *ndev) +{ + u8 *uptable = NULL; + unsigned long flags; + struct net_info *netinfo; + + WL_CFG_NET_LIST_SYNC_LOCK(&cfg->net_list_sync, flags); + netinfo = _wl_get_netinfo_by_wdev(cfg, ndev->ieee80211_ptr); + if (netinfo) { + uptable = netinfo->qos_up_table; + } + WL_CFG_NET_LIST_SYNC_UNLOCK(&cfg->net_list_sync, flags); + + return uptable; +} + /* get user priority table */ -uint8 * +u8 * wl_get_up_table(dhd_pub_t * dhdp, int idx) { - struct net_device *ndev; struct bcm_cfg80211 *cfg; + struct net_device *ndev; ndev = dhd_idx2net(dhdp, idx); if (ndev) { cfg = wl_get_cfg(ndev); if (cfg) - return (uint8 *)(cfg->up_table); + return wl_get_up_table_netinfo(cfg, ndev); } return NULL; } + +static s32 +wl_config_up_table(struct bcm_cfg80211 *cfg, + struct net_device *ndev, bcm_tlv_t *qos_map_ie) +{ + u8 *up_table = wl_get_up_table_netinfo(cfg, ndev); + + /* Add/update table */ + if (qos_map_ie) { + WL_INFORM_MEM(("[%s] qos map add\n", ndev->name)); + if (!up_table) { + up_table = (uint8 *)MALLOCZ(cfg->osh, UP_TABLE_MAX); + if (up_table == NULL) { + WL_ERR(("** malloc failure for up_table\n")); + return -ENOMEM; + } + } + wl_set_up_table(up_table, qos_map_ie); + wl_store_up_table_netinfo(cfg, ndev, up_table); + if (wl_dbg_level & WL_DBG_DBG) { + prhex("*** UP Table", up_table, UP_TABLE_MAX); + } + } else if (up_table) { + /* No qos_map_ie. Delete old entry if present */ + wl_store_up_table_netinfo(cfg, ndev, NULL); + MFREE(cfg->osh, up_table, UP_TABLE_MAX); + WL_INFORM_MEM(("[%s] qos map del\n", ndev->name)); + } + + return BCME_OK; +} #endif /* defined(QOS_MAP_SET) || defined(WL_CUSTOM_MAPPING_OF_DSCP) */ #if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON) @@ -14237,6 +14323,7 @@ static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev) struct wl_security *sec; #ifdef QOS_MAP_SET bcm_tlv_t * qos_map_ie = NULL; + bcm_tlv_t * ext_cap_ie = NULL; #endif /* QOS_MAP_SET */ WL_DBG(("Enter \n")); @@ -14327,16 +14414,17 @@ static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev) #endif /* defined(DHD_DSCP_POLICY) */ #ifdef QOS_MAP_SET + if (wl_dbg_level & WL_DBG_DBG) { + /* find extended cap IE */ + ext_cap_ie = bcm_parse_tlvs(conn_info->req_ie, conn_info->req_ie_len, + DOT11_MNG_EXT_CAP_ID); + prhex("ext_cap_ie", (u8 *)ext_cap_ie->data, ext_cap_ie->len); + } /* find qos map set ie */ - if ((qos_map_ie = bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len, - DOT11_MNG_QOS_MAP_ID)) != NULL) { - WL_DBG((" QoS map set IE found in assoc response\n")); - if (!cfg->up_table) { - cfg->up_table = (uint8 *)MALLOC(cfg->osh, UP_TABLE_MAX); - } - wl_set_up_table(cfg->up_table, qos_map_ie); - } else { - MFREE(cfg->osh, cfg->up_table, UP_TABLE_MAX); + qos_map_ie = bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len, + DOT11_MNG_QOS_MAP_ID); + if (wl_config_up_table(cfg, ndev, qos_map_ie) != BCME_OK) { + WL_ERR(("qos map config failed\n")); } #endif /* QOS_MAP_SET */ } else { @@ -15375,26 +15463,10 @@ wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, &mgmt_frame[offset], mgmt_frame_len - offset); } - if ((qos_map_ie = bcm_parse_tlvs( - &mgmt_frame[offset], mgmt_frame_len - offset, - DOT11_MNG_QOS_MAP_ID)) != NULL) { - WL_INFORM((" QoS map set IE found in QoS action frame\n")); - if (!cfg->up_table) { - cfg->up_table = (uint8 *)MALLOCZ(cfg->osh, UP_TABLE_MAX); - if (cfg->up_table == NULL) { - WL_ERR(("** malloc failure for up_table\n")); - goto exit; - } - } - - wl_set_up_table(cfg->up_table, qos_map_ie); - - if (wl_dbg_level & WL_DBG_DBG) { - prhex("*** UP Table", cfg->up_table, UP_TABLE_MAX); - } - } else { - WL_INFORM((" QoS map set IE not found in QoS action frame\n")); - MFREE(cfg->osh, cfg->up_table, UP_TABLE_MAX); + qos_map_ie = bcm_parse_tlvs(&mgmt_frame[offset], mgmt_frame_len - offset, + DOT11_MNG_QOS_MAP_ID); + if (wl_config_up_table(cfg, ndev, qos_map_ie) != BCME_OK) { + WL_ERR(("qos map config failed\n")); } #endif /* QOS_MAP_SET */ @@ -15794,6 +15866,7 @@ static void wl_init_event_handler(struct bcm_cfg80211 *cfg) cfg->evt_handler[WLC_E_NAN_CRITICAL] = wl_cfgnan_notify_nan_status; cfg->evt_handler[WLC_E_NAN_NON_CRITICAL] = wl_cfgnan_notify_nan_status; #endif /* WL_NAN */ + cfg->evt_handler[WLC_E_CSA_START_IND] = wl_cfgvif_csa_start_ind; cfg->evt_handler[WLC_E_CSA_COMPLETE_IND] = wl_csa_complete_ind; cfg->evt_handler[WLC_E_AP_STARTED] = wl_ap_start_ind; #ifdef CUSTOM_EVENT_PM_WAKE @@ -16032,6 +16105,7 @@ static s32 wl_create_event_handler(struct bcm_cfg80211 *cfg) } if (!cfg->event_workq) { + WL_ERR(("Failed to alloc workqueue\n")); ret = -ENOMEM; } else { INIT_WORK(&cfg->event_work, wl_event_handler); @@ -16580,6 +16654,12 @@ static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_ #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */ #endif /* BCMDONGLEHOST */ } +#ifdef WLAN_TRACKER + /* notifer sta state change */ + if (err == BCME_OK) + dhd_custom_notify( + set ? CUSTOM_NOTIFY_STA_CONNECT : CUSTOM_NOTIFY_STA_DISCONNECT); +#endif /* WLAN_TRACKER */ return err; } @@ -18188,6 +18268,12 @@ static s32 wl_cfg80211_config_rav_mscs_params(struct bcm_cfg80211 *cfg, ioctl_buf, WLC_IOCTL_MEDLEN, NULL); if (unlikely(err)) { WL_ERR(("set qos_mgmt failed ,err(%d)\n", err)); + } else { + if (wl_dbg_level & WL_DBG_DBG) { + prhex("mscs config", (u8 *)iov_buf, iovlen); + WL_DBG(("UP bit map: %0x\n", + ((wl_qos_rav_mscs_config_v1_t *)(&iov_buf->data[0]))->up_bitmap)); + } } fail: if (ioctl_buf) { @@ -18755,6 +18841,7 @@ static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg) wl_clr_drv_status(cfg, AP_CREATING, iter->ndev); wl_clr_drv_status(cfg, NESTED_CONNECT, iter->ndev); wl_clr_drv_status(cfg, CFG80211_CONNECT, iter->ndev); + wl_clr_drv_status(cfg, CSA_ACTIVE, iter->ndev); } #ifdef WL_CFG80211_MONITOR if (ndev->ieee80211_ptr->iftype != NL80211_IFTYPE_MONITOR) @@ -23894,7 +23981,8 @@ wl_cfg80211_stop_mkeep_alive(struct net_device *ndev, struct bcm_cfg80211 *cfg, res = wldev_iovar_getbuf(ndev, "mkeep_alive", &mkeep_alive_id, sizeof(mkeep_alive_id), pbuf, KA_TEMP_BUF_SIZE, &cfg->ioctl_buf_sync); if (res < 0) { - WL_ERR(("%s: Get mkeep_alive failed (error=%d)\n", __FUNCTION__, res)); + WL_ERR(("%s: Get mkeep_alive failed id:%d (error=%d)\n", __FUNCTION__, + mkeep_alive_id, res)); goto exit; } else { /* Check occupied ID */ @@ -24768,7 +24856,8 @@ static void wl_get_sar_config_info(struct bcm_cfg80211 *cfg) int ret = BCME_OK; char *buf = NULL, *ptr = NULL, *cptr = NULL; int filelen = 0, buflen = 0, offset = 0, num, len, i; - int8 scenario, sarmode, airplanemode; + int8 scenario, airplanemode; + uint8 sarmode; if (cfg == NULL) { WL_ERR(("cfg is null\n")); @@ -25157,6 +25246,7 @@ wl_cleanup_keep_alive(struct net_device *ndev, struct bcm_cfg80211 *cfg) { int mkeep_alive_id; + WL_MEM(("mkeep_alive_avail:%x\n", cfg->mkeep_alive_avail)); for (mkeep_alive_id = 1; mkeep_alive_id < KEEP_ALIVE_ID_MAX; mkeep_alive_id++) { if (isset(&cfg->mkeep_alive_avail, mkeep_alive_id)) { if (wl_cfg80211_stop_mkeep_alive(ndev, cfg, mkeep_alive_id) == BCME_OK) { @@ -25623,7 +25713,7 @@ int wl_get_usable_channels(struct bcm_cfg80211 *cfg, usable_channel_info_t *u_in } /* Supplicant does scan passive channel but not for DFS channel */ - if (!(chaninfo & WL_CHAN_RADAR) && !ch_160mhz_5g && + if (!restrict_chan && !ch_160mhz_5g && !CHSPEC_IS6G(chspec) && (!is_unii4)) { mask |= (1 << WIFI_INTERFACE_P2P_CLIENT); } diff --git a/wl_cfg80211.h b/wl_cfg80211.h index fd6720e..ee26e35 100644 --- a/wl_cfg80211.h +++ b/wl_cfg80211.h @@ -158,6 +158,16 @@ typedef sta_info_v4_t wlcfg_sta_info_t; #define MSCS_CFG_DEF_TCLAS_MASK 0x5Fu /* TCLAS mask */ #endif /* MSCS_CFG_DEF_TCLAS_MASK */ +#if defined(CONFIG_6GHZ_BKPORT) || (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)) +/* Native 6GHz band supported available. For Backported + * kernels, kernels/customer makefiles should explicitly + * define CONFIG_6GHZ_BKPORT + */ +#if defined(WL_6G_BAND) +#define CFG80211_6G_SUPPORT +#endif +#endif /* CONFIG_6GHZ_BKPORT || LINUX_VER >= 5.4 */ + #define CH_TO_CHSPC(band, _channel) \ ((_channel | band) | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE) #define CHAN2G(_channel, _freq, _flags) { \ @@ -260,16 +270,6 @@ typedef sta_info_v4_t wlcfg_sta_info_t; #endif /* WAIT_FOR_DISCONNECT_MAX */ #define WAIT_FOR_DISCONNECT_STATE_SYNC 10 -#if defined(CONFIG_6GHZ_BKPORT) || (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)) -/* Native 6GHz band supported available. For Backported - * kernels, kernels/customer makefiles should explicitly - * define CONFIG_6GHZ_BKPORT - */ -#if defined(WL_6G_BAND) -#define CFG80211_6G_SUPPORT -#endif -#endif /* CONFIG_6GHZ_BKPORT || LINUX_VER >= 5.4 */ - #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)) /* Newer kernels use defines from nl80211.h */ #define IEEE80211_BAND_2GHZ NL80211_BAND_2GHZ @@ -718,7 +718,7 @@ do { \ #else #define IFACE_MAX_CNT 5 #endif /* WL_MLO */ -#define WL_SCAN_CONNECT_DWELL_TIME_MS 200 +#define WL_SCAN_CONNECT_DWELL_TIME_MS 100 #define WL_SCAN_JOIN_PROBE_INTERVAL_MS 20 #define WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320 #define WL_BCAST_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 80 @@ -942,7 +942,9 @@ typedef wifi_p2psd_gas_pub_act_frame_t wl_dpp_gas_af_t; #define DEFAULT_FULL_ROAM_PRD 0x78u #define DEFAULT_ASSOC_RETRY 0x3u #define DEFAULT_WNM_CONF 0x505u +#ifndef DEFAULT_RECREATE_BI_TIMEOUT #define DEFAULT_RECREATE_BI_TIMEOUT 20u +#endif struct preinit_iov; typedef int (*wl_iov_fn) (struct bcm_cfg80211 *cfg, struct net_device *dev, struct preinit_iov *v); @@ -994,8 +996,9 @@ enum wl_status { #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ WL_STATUS_NESTED_CONNECT, WL_STATUS_CFG80211_CONNECT, - WL_STATUS_AUTHORIZED - + WL_STATUS_AUTHORIZED, + WL_STATUS_ROAMING, + WL_STATUS_CSA_ACTIVE }; typedef enum wl_iftype { @@ -1290,6 +1293,7 @@ struct net_info { */ u8* passphrase_cfg; u16 passphrase_cfg_len; + u8 *qos_up_table; }; #ifdef WL_BCNRECV @@ -1805,7 +1809,7 @@ typedef enum { #define SAR_CONFIG_SCENARIO_COUNT 100 typedef struct wl_sar_config_info { int8 scenario; - int8 sar_tx_power_val; + uint8 sar_tx_power_val; int8 airplane_mode; } wl_sar_config_info_t; #endif /* WL_SAR_TX_POWER && WL_SAR_TX_POWER_CONFIG */ @@ -2483,6 +2487,10 @@ wl_dealloc_netinfo_by_wdev(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev) _net_info->passphrase_cfg = NULL; } + if (_net_info->qos_up_table) { + MFREE(cfg->osh, _net_info->qos_up_table, UP_TABLE_MAX); + _net_info->qos_up_table = NULL; + } list_del(&_net_info->list); cfg->iface_cnt--; MFREE(cfg->osh, _net_info, sizeof(struct net_info)); @@ -3641,6 +3649,10 @@ int wl_cfg80211_set_roam_params(struct net_device *dev, uint32 *data, uint16 dat extern void wl_cfg80211_wdev_lock(struct wireless_dev *wdev); extern void wl_cfg80211_wdev_unlock(struct wireless_dev *wdev); +extern u8 *wl_get_up_table_netinfo(struct bcm_cfg80211 *cfg, struct net_device *ndev); +extern void wl_store_up_table_netinfo(struct bcm_cfg80211 *cfg, + struct net_device *ndev, u8 *uptable); + /* Added wl_reassoc_params_cvt_v1 due to mis-sync between DHD and FW * Because Dongle use wl_reassoc_params_v1_t for WLC_REASSOC * Legacy FW use wl_reassoc_params_t diff --git a/wl_cfg_cellavoid.c b/wl_cfg_cellavoid.c index a3e5130..9f89d12 100755 --- a/wl_cfg_cellavoid.c +++ b/wl_cfg_cellavoid.c @@ -880,6 +880,8 @@ free_list: return BCME_NOMEM; } +#define MAX_20MHZ_CHANNELS 16u + /* This function is used verifying channel items * created by wl_cellavoid_alloc_avail_chan_list are valid * by comparing the channel item to chan_info_list from FW @@ -895,10 +897,13 @@ wl_cellavoid_verify_avail_chan_list(struct bcm_cfg80211 *cfg, wl_cellavoid_info_ void *dngl_chan_list; bool legacy_chan_info = FALSE; bool found; - int i, err; + int i, j, k, err; chanspec_t chanspec = 0; char chanspec_str[CHANSPEC_STR_LEN]; uint32 restrict_chan, chaninfo; + u32 arr_idx = 0, band; + u8 chan_array[MAX_20MHZ_CHANNELS] = {0}; + wl_chanspec_attr_v1_t overlap[MAX_20MHZ_CHANNELS]; /* Get chan_info_list or chanspec from FW */ #define LOCAL_BUF_LEN 4096 @@ -937,6 +942,10 @@ wl_cellavoid_verify_avail_chan_list(struct bcm_cfg80211 *cfg, wl_cellavoid_info_ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); list_for_each_entry_safe(chan_info, next, &cellavoid_info->avail_chan_info_list, list) { GCC_DIAGNOSTIC_POP(); + wf_get_all_ext(chan_info->chanspec, chan_array); + bzero(overlap, sizeof(overlap)); + band = CHSPEC_BAND(chan_info->chanspec); + arr_idx = 0; found = FALSE; for (i = 0; i < dtoh32(list_count); i++) { if (legacy_chan_info) { @@ -949,9 +958,40 @@ wl_cellavoid_verify_avail_chan_list(struct bcm_cfg80211 *cfg, wl_cellavoid_info_ chaninfo = dtoh32 (((wl_chanspec_list_v1_t *)dngl_chan_list)->chspecs[i].chaninfo); + + /* Store chanspec attribute of subbands channel. */ + if ((CHSPEC_BAND(chanspec) == band) && + (CHSPEC_BW(chanspec) == WL_CHANSPEC_BW_20)) { + for (j = 0; j < MAX_20MHZ_CHANNELS; j++) { + if (!chan_array[j]) { + /* if entry is empty, break */ + break; + } + if (chan_array[j] == CHSPEC_CHANNEL(chanspec)) { + overlap[arr_idx].chanspec = chanspec; + overlap[arr_idx].chaninfo = chaninfo; + WL_DBG(("sel_chspec:%x overlap_chspec:%x\n", + chan_info->chanspec, + overlap[arr_idx].chanspec)); + arr_idx++; + break; + } + } + } + restrict_chan = ((chaninfo & WL_CHAN_RADAR) || (chaninfo & WL_CHAN_PASSIVE) || (chaninfo & WL_CHAN_CLM_RESTRICTED)); + + if (chan_info->chanspec == chanspec) { + for (k = 0; k < arr_idx; k++) { + restrict_chan |= + ((overlap[k].chaninfo & WL_CHAN_RADAR) || + (overlap[k].chaninfo & WL_CHAN_PASSIVE) || + (overlap[k].chaninfo & + WL_CHAN_CLM_RESTRICTED)); + } + } } if ((!restrict_chan) && (chan_info->chanspec == chanspec)) { @@ -1456,7 +1496,7 @@ wl_cellavoid_find_ap_chan_info(struct bcm_cfg80211 *cfg, chanspec_t ap_chspec, * Skip DFS case */ WL_INFORM_MEM(("STA in the another core. band %d\n", csa_target_band)); - if (!is_chanspec_dfs(cfg, sta_chspec)) { + if (!wl_is_chanspec_restricted(cfg, sta_chspec)) { chan_info = wl_cellavoid_find_chinfo_fromchspec(cfg->cellavoid_info, sta_chspec); } @@ -1638,8 +1678,6 @@ wl_cellavoid_validate_param(struct bcm_cfg80211 *cfg, wl_cellavoid_param_t *para WL_ERR(("Not supported band %d, channel %d, pwrcap %d\n", param->chan_param[i].band, param->chan_param[i].center_channel, param->chan_param[i].pwr_cap)); - ret = -EINVAL; - goto exit; } param->chan_param[i].chspec_bw = bw; diff --git a/wl_cfgnan.c b/wl_cfgnan.c index 431e441..53f4e91 100644 --- a/wl_cfgnan.c +++ b/wl_cfgnan.c @@ -2091,7 +2091,7 @@ wl_cfgnan_enable_handler(wl_nan_iov_t *nan_iov_data, bool val) } static int -wl_cfgnan_set_instant_chan(nan_config_cmd_data_t *cmd_data, wl_nan_iov_t *nan_iov_data) +wl_cfgnan_set_instant_chanspec(nan_config_cmd_data_t *cmd_data, wl_nan_iov_t *nan_iov_data) { s32 ret = BCME_OK; bcm_iov_batch_subcmd_t *sub_cmd = NULL; @@ -2111,7 +2111,7 @@ wl_cfgnan_set_instant_chan(nan_config_cmd_data_t *cmd_data, wl_nan_iov_t *nan_io sub_cmd->id = htod16(WL_NAN_CMD_CFG_INSTANT_CHAN); sub_cmd->len = sizeof(sub_cmd->u.options) + sizeof(chspec); sub_cmd->u.options = htol32(BCM_XTLV_OPTION_ALIGN32); - chspec = CH20MHZ_CHSPEC(cmd_data->instant_chan); + chspec = cmd_data->instant_chspec; ret = memcpy_s(sub_cmd->data, sizeof(chanspec_t), (uint8*)&chspec, sizeof(chanspec_t)); @@ -3333,8 +3333,8 @@ wl_cfgnan_start_handler(struct net_device *ndev, struct bcm_cfg80211 *cfg, } nan_buf->count++; - if (cmd_data->instant_chan) { - ret = wl_cfgnan_set_instant_chan(cmd_data, nan_iov_data); + if (cmd_data->instant_chspec) { + ret = wl_cfgnan_set_instant_chanspec(cmd_data, nan_iov_data); if (unlikely(ret)) { WL_ERR(("NAN 3.1 Instant disc channel sub_cmd set failed\n")); goto fail; @@ -3910,8 +3910,8 @@ wl_cfgnan_config_handler(struct net_device *ndev, struct bcm_cfg80211 *cfg, } /* Set NAN 3.1 Instant channel */ - if (cmd_data->instant_chan) { - ret = wl_cfgnan_set_instant_chan(cmd_data, nan_iov_data); + if (cmd_data->instant_chspec) { + ret = wl_cfgnan_set_instant_chanspec(cmd_data, nan_iov_data); if (unlikely(ret)) { WL_ERR(("NAN 3.1 Instant communication channel sub_cmd set failed\n")); goto fail; diff --git a/wl_cfgnan.h b/wl_cfgnan.h index 630afdd..5d80a23 100644 --- a/wl_cfgnan.h +++ b/wl_cfgnan.h @@ -541,7 +541,7 @@ typedef struct nan_config_cmd_data { wl_nan_disc_bcn_interval_t disc_bcn_interval; uint32 dw_early_termination; uint32 instant_mode_en; - uint32 instant_chan; + chanspec_t instant_chspec; uint8 chre_req; } nan_config_cmd_data_t; @@ -655,6 +655,11 @@ typedef struct nan_hal_capabilities { uint32 max_subscribe_address; uint32 ndpe_attr_supported; bool is_instant_mode_supported; + bool is_6g_supported; + bool is_he_supported; + bool is_pairing_supported; + bool is_set_cluster_id_supported; + bool is_suspension_supported; } nan_hal_capabilities_t; typedef struct _nan_hal_resp { @@ -1013,7 +1018,8 @@ typedef enum { NAN_ATTRIBUTE_INSTANT_MODE_ENABLE = 230, NAN_ATTRIBUTE_INSTANT_COMM_CHAN = 231, NAN_ATTRIBUTE_CHRE_REQUEST = 232, - NAN_ATTRIBUTE_MAX = 233 + NAN_ATTRIBUTE_SVC_CFG_SUSPENDABLE = 233, + NAN_ATTRIBUTE_MAX = 234 } NAN_ATTRIBUTE; enum geofence_suspend_reason { diff --git a/wl_cfgscan.c b/wl_cfgscan.c index 6fc80b8..5a79779 100644 --- a/wl_cfgscan.c +++ b/wl_cfgscan.c @@ -216,6 +216,7 @@ static void wl_update_hidden_ap_ie(wl_bss_info_v109_t *bi, const u8 *ie_stream, int32 ssid_len = MIN(bi->SSID_len, DOT11_MAX_SSID_LEN); int32 remaining_ie_buf_len, available_buffer_len, unused_buf_len; /* cfg80211_find_ie defined in kernel returning const u8 */ + int ret = 0; GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ie_stream, *ie_size); @@ -259,10 +260,19 @@ static void wl_update_hidden_ap_ie(wl_bss_info_v109_t *bi, const u8 *ie_stream, */ if ((update_ssid && (ssid_len > ssidie[1])) && (unused_buf_len > ssid_len)) { WL_INFORM_MEM(("Changing the SSID Info.\n")); - memmove(ssidie + ssid_len + 2, - (ssidie + 2) + ssidie[1], - remaining_ie_buf_len); - memcpy(ssidie + 2, bi->SSID, ssid_len); + ret = memmove_s(ssidie + ssid_len + 2, available_buffer_len, + (ssidie + 2) + ssidie[1], remaining_ie_buf_len); + if (ret) { + WL_ERR(("SSID Info memmove failed:%d, destsz:%d, n:%d\n", + ret, available_buffer_len, remaining_ie_buf_len)); + return; + } + ret = memcpy_s(ssidie + 2, DOT11_MAX_SSID_LEN, bi->SSID, ssid_len); + if (ret) { + WL_ERR(("SSID Info memcpy failed:%d, destsz:%d, n:%d\n", + ret, DOT11_MAX_SSID_LEN, ssid_len)); + return; + } *ie_size = *ie_size + ssid_len - ssidie[1]; ssidie[1] = ssid_len; } else if (ssid_len < ssidie[1]) { @@ -271,8 +281,14 @@ static void wl_update_hidden_ap_ie(wl_bss_info_v109_t *bi, const u8 *ie_stream, } return; } - if (*(ssidie + 2) == '\0') - memcpy(ssidie + 2, bi->SSID, ssid_len); + if (*(ssidie + 2) == '\0') { + ret = memcpy_s(ssidie + 2, DOT11_MAX_SSID_LEN, bi->SSID, ssid_len); + if (ret) { + WL_ERR(("memcopy failed:%d, destsz:%d, n:%d\n", + ret, DOT11_MAX_SSID_LEN, ssid_len)); + return; + } + } return; } @@ -280,12 +296,19 @@ static s32 wl_mrg_ie(struct bcm_cfg80211 *cfg, u8 *ie_stream, u16 ie_size) { struct wl_ie *ie = wl_to_ie(cfg); s32 err = 0; + int ret = 0; if (unlikely(ie->offset + ie_size > WL_TLV_INFO_MAX)) { WL_ERR(("ei_stream crosses buffer boundary\n")); return -ENOSPC; } - memcpy(&ie->buf[ie->offset], ie_stream, ie_size); + ret = memcpy_s(&ie->buf[ie->offset], (sizeof(ie->buf) - ie->offset), + ie_stream, ie_size); + if (ret) { + WL_ERR(("memcpy failed:%d, destsz: %lu, n: %d\n", + ret, (sizeof(ie->buf) - ie->offset), ie_size)); + return BCME_ERROR; + } ie->offset += ie_size; return err; @@ -339,6 +362,12 @@ s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, wl_bss_info_v109_t *bi, bool return err; } + if (bi->length < (bi->ie_offset + bi->ie_length)) { + WL_ERR(("IE length is not Valid. IE offse:%d, len:%d\n", + bi->ie_offset, bi->ie_length)); + return -EINVAL; + } + if (bi->SSID_len > IEEE80211_MAX_SSID_LEN) { WL_ERR(("wrong SSID len:%d\n", bi->SSID_len)); return -EINVAL; @@ -435,6 +464,14 @@ s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, wl_bss_info_v109_t *bi, bool if (unlikely(!cbss)) { WL_ERR(("cfg80211_inform_bss_frame error bssid " MACDBG " channel %d \n", MAC2STRDBG((u8*)(&bi->BSSID)), notif_bss_info->channel)); + WL_ERR(("SSID : \"%s\", rssi %d, fc : 0x04%x, " + "capability : 0x04%x, beacon_int : 0x04%x, " + "mgmt_type %d, frame_len %d, freq %d, " + "band %d, center_freq %d, freq_offset %d\n", + tmp_buf, notif_bss_info->rssi, mgmt->frame_control, + mgmt->u.probe_resp.capab_info, mgmt->u.probe_resp.beacon_int, + mgmt_type, notif_bss_info->frame_len, freq, + channel->band, channel->center_freq, channel->freq_offset)); err = -EINVAL; goto out_err; } @@ -647,6 +684,7 @@ wl_bcnrecv_result_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, struct wiphy *wiphy = NULL; wl_bcnrecv_result_t *bcn_recv = NULL; struct timespec64 ts; + int ret = 0; if (!bi) { WL_ERR(("%s: bi is NULL\n", __func__)); err = BCME_NORESOURCE; @@ -669,11 +707,15 @@ wl_bcnrecv_result_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, WL_ERR(("Failed to allocate memory\n")); return -ENOMEM; } - /* Returning void here as copy size does not exceed dest size of SSID */ - (void)memcpy_s((char *)bcn_recv->SSID, DOT11_MAX_SSID_LEN, - (char *)bi->SSID, DOT11_MAX_SSID_LEN); - /* Returning void here as copy size does not exceed dest size of ETH_LEN */ - (void)memcpy_s(&bcn_recv->BSSID, ETHER_ADDR_LEN, &bi->BSSID, ETH_ALEN); + ret = memcpy_s((char *)bcn_recv->SSID, sizeof(bcn_recv->SSID), + (char *)bi->SSID, bi->SSID_len); + if (ret) { + WL_ERR(("memcpy failed:%d, destsz:%lu, n:%d\n", + ret, sizeof(bcn_recv->SSID), bi->SSID_len)); + err = BCME_ERROR; + goto exit; + } + eacopy(&bi->BSSID, &bcn_recv->BSSID); bcn_recv->channel = wf_chspec_ctlchan( wl_chspec_driver_to_host(bi->chanspec)); bcn_recv->beacon_interval = bi->beacon_period; @@ -1086,17 +1128,6 @@ wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, list->version = dtoh32(bi->version); list->buflen += bi_length; list->count++; - - /* - * !Broadcast && number of ssid = 1 && number of channels =1 - * means specific scan to association - */ - if (wl_cfgp2p_is_p2p_specific_scan(cfg->scan_request)) { - WL_ERR(("P2P assoc scan fast aborted.\n")); - wl_cfgscan_scan_abort(cfg); - wl_notify_escan_complete(cfg, cfg->escan_info.ndev, false); - goto exit; - } } } else if (status == WLC_E_STATUS_SUCCESS) { @@ -2263,6 +2294,14 @@ wl_cfgscan_handle_scanbusy(struct bcm_cfg80211 *cfg, struct net_device *ndev, s3 busy_count = 0; } + if ((IS_STA_IFACE(ndev_to_wdev(ndev))) && + wl_get_drv_status(cfg, CONNECTED, ndev) && + !wl_get_drv_status(cfg, AUTHORIZED, ndev)) { + WL_ERR(("Authorization is in progress," + " so ignore this scan busy until it's completed.\n")); + busy_count = 0; + } + if (err == BCME_BUSY || err == BCME_NOTREADY) { WL_ERR(("Scan err = (%d), busy?%d", err, -EBUSY)); scanbusy_err = -EBUSY; @@ -2276,6 +2315,14 @@ wl_cfgscan_handle_scanbusy(struct bcm_cfg80211 *cfg, struct net_device *ndev, s3 scanbusy_err = -EAGAIN; } + if (wl_get_drv_status_all(cfg, CSA_ACTIVE)) { + /* override error to EGAIN to avoid forcing panic as CSA can + * take upto 25secs. Don't limit on number of scans in this case. + */ + scanbusy_err = -EAGAIN; + WL_ERR(("scan busy due to csa in progress\n")); + } + /* if continuous busy state, clear assoc type in FW by disassoc cmd */ if (scanbusy_err == -EBUSY) { /* Flush FW preserve buffer logs for checking failure */ @@ -6479,7 +6526,8 @@ bool wl_check_active_2g_chan(struct bcm_cfg80211 *cfg, drv_acs_params_t *paramet #ifdef WL_CELLULAR_CHAN_AVOID if (wl_cellavoid_mandatory_isset(cfg->cellavoid_info, NL80211_IFTYPE_AP) && !wl_cellavoid_is_safe(cfg->cellavoid_info, sta_chanspec)) { - WL_INFORM_MEM(("Not allow unsafe channel and mandatory chspec:0x%x\n", + WL_INFORM_MEM(( + "Not allow unsafe channel and mandatory chspec:0x%x\n", sta_chanspec)); goto exit; } @@ -6928,26 +6976,32 @@ wl_get_ap_chanspecs(struct bcm_cfg80211 *cfg, wl_ap_oper_data_t *ap_data) } } -inline bool -is_chanspec_dfs(struct bcm_cfg80211 *cfg, chanspec_t chspec) +bool wl_is_chanspec_restricted(struct bcm_cfg80211 *cfg, chanspec_t sta_chanspec) { - u32 ch; - s32 err; - u8 buf[WLC_IOCTL_SMLEN]; - struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); + struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); + s32 ret = BCME_OK; + uint bitmap = 0; + u8 ioctl_buf[WLC_IOCTL_SMLEN]; - ch = (u32)chspec; - err = wldev_iovar_getbuf_bsscfg(ndev, "per_chan_info", (void *)&ch, - sizeof(u32), buf, WLC_IOCTL_SMLEN, 0, NULL); - if (unlikely(err)) { - WL_ERR(("get per chan info failed:%d\n", err)); + bzero(ioctl_buf, WLC_IOCTL_SMLEN); + ret = wldev_iovar_getbuf(dev, "per_chan_info", + (void *)&sta_chanspec, sizeof(sta_chanspec), + ioctl_buf, WLC_IOCTL_SMLEN, NULL); + if (ret != BCME_OK) { + WL_ERR(("Failed to get per_chan_info chspec:0x%x, error:%d\n", + sta_chanspec, ret)); return FALSE; } - /* Check the channel flags returned by fw */ - if (*((u32 *)buf) & WL_CHAN_PASSIVE) { + bitmap = dtoh32(*(uint *)ioctl_buf); + if (bitmap & (WL_CHAN_PASSIVE | WL_CHAN_RADAR | + WL_CHAN_RESTRICTED | WL_CHAN_CLM_RESTRICTED)) { + WL_INFORM_MEM(("chanspec:0x%x is restricted by per_chan_info:0x%x\n", + sta_chanspec, bitmap)); return TRUE; } + + WL_INFORM_MEM(("STA chanspec:0x%x per_chan_info:0x%x\n", sta_chanspec, bitmap)); return FALSE; } @@ -6998,7 +7052,17 @@ wl_acs_check_scc(struct bcm_cfg80211 *cfg, drv_acs_params_t *parameter, * get active channels and check it */ if (scc == FALSE && CHSPEC_IS2G(sta_chanspec)) { - scc = wl_check_active_2g_chan(cfg, parameter, sta_chanspec); +#ifdef WL_CELLULAR_CHAN_AVOID + if (!wl_is_chanspec_restricted(cfg, sta_chanspec)) { + scc = wl_cellavoid_operation_allowed(cfg->cellavoid_info, + sta_chanspec, NL80211_IFTYPE_AP); + if (scc == FALSE) { + WL_INFORM_MEM(( + "Not allow unsafe channel and mandatory chspec:0x%x\n", + sta_chanspec)); + } + } +#endif /* WL_CELLULAR_CHAN_AVOID */ } #endif /* DHD_ACS_CHECK_SCC_2G_ACTIVE_CH */ @@ -7087,10 +7151,9 @@ wl_handle_acs_concurrency_cases(struct bcm_cfg80211 *cfg, drv_acs_params_t *para return -EINVAL; } } else if (sta_band == WLC_BAND_5G) { - if (is_chanspec_dfs(cfg, chspec) || + if (wl_is_chanspec_restricted(cfg, chspec) || #ifdef WL_UNII4_CHAN - (CHSPEC_IS5G(chspec) && - IS_UNII4_CHANNEL(wf_chspec_primary20_chan(chspec))) || + IS_UNII4_CHANNEL(wf_chspec_primary20_chan(chspec)) || #endif /* WL_UNII4_CHAN */ FALSE) { /* diff --git a/wl_cfgscan.h b/wl_cfgscan.h index 579aa17..2e5ad91 100644 --- a/wl_cfgscan.h +++ b/wl_cfgscan.h @@ -220,7 +220,7 @@ extern int wl_handle_acs_concurrency_cases(struct bcm_cfg80211 *cfg, extern void wl_cfgscan_sched_scan_stop_work(struct work_struct *work); #endif /* WL_SCHED_SCAN */ #ifdef WL_SOFTAP_ACS -extern bool is_chanspec_dfs(struct bcm_cfg80211 *cfg, chanspec_t chspec); +extern bool wl_is_chanspec_restricted(struct bcm_cfg80211 *cfg, chanspec_t chspec); #endif /* WL_SOFTAP_ACS */ #ifdef ESCAN_CHANNEL_CACHE diff --git a/wl_cfgvendor.c b/wl_cfgvendor.c index 771c69b..9058f19 100755 --- a/wl_cfgvendor.c +++ b/wl_cfgvendor.c @@ -79,6 +79,7 @@ #include <wl_cfgp2p.h> #include <wl_cfgscan.h> #include <wl_cfgvif.h> +#include <dhd_plat.h> #ifdef WL_NAN #include <wl_cfgnan.h> #endif /* WL_NAN */ @@ -2110,6 +2111,19 @@ wl_cfgvendor_rtt_evt(void *ctx, void *rtt_data) ret)); goto free_mem; } + ret = nla_put_u32(skb, RTT_ATTRIBUTE_RESULT_FREQ, + rtt_result->frequency); + if (ret < 0) { + WL_ERR(("Failed to put RTT_ATTRIBUTE_RESULT_FREQ, ret:%d\n", ret)); + goto free_mem; + } + + ret = nla_put_u32(skb, RTT_ATTRIBUTE_RESULT_BW, + rtt_result->packet_bw); + if (ret < 0) { + WL_ERR(("Failed to put RTT_ATTRIBUTE_RESULT_CNT, ret:%d\n", ret)); + goto free_mem; + } } nla_nest_end(skb, rtt_nl_hdr); cfg80211_vendor_event(skb, kflags); @@ -2830,6 +2844,7 @@ wl_cfgvendor_set_bssid_blacklist(struct wiphy *wiphy, err = -EINVAL; goto exit; } + WL_INFORM_MEM(("blacklist_flush:%d\n", flush)); break; case GSCAN_ATTRIBUTE_BLACKLIST_BSSID: if (num == 0 || !blacklist) { @@ -2848,8 +2863,9 @@ wl_cfgvendor_set_bssid_blacklist(struct wiphy *wiphy, err = -EINVAL; goto exit; } - memcpy(&(blacklist->ea[blacklist->count]), nla_data(iter), - ETHER_ADDR_LEN); + WL_INFORM_MEM(("blacklist mac_addr:" MACDBG "\n", + MAC2STRDBG(nla_data(iter)))); + eacopy(nla_data(iter), &(blacklist->ea[blacklist->count])); blacklist->count++; break; default: @@ -2865,8 +2881,8 @@ wl_cfgvendor_set_bssid_blacklist(struct wiphy *wiphy, goto exit; } - err = dhd_dev_set_blacklist_bssid(bcmcfg_to_prmry_ndev(cfg), - blacklist, mem_needed, flush); + err = wl_android_set_blacklist_bssid(wdev_to_ndev(wdev), blacklist, + mem_needed, flush); exit: MFREE(cfg->osh, blacklist, mem_needed); return err; @@ -4431,6 +4447,9 @@ wl_cfgvendor_nan_parse_datapath_args(struct wiphy *wiphy, return ret; } break; + case NAN_ATTRIBUTE_INST_ID: + /* Skip */ + break; default: WL_ERR(("Unknown type, %d\n", attr_type)); ret = -EINVAL; @@ -5110,6 +5129,8 @@ wl_cfgvendor_nan_parse_discover_args(struct wiphy *wiphy, } cmd_data->service_responder_policy = nla_get_u8(iter); break; + case NAN_ATTRIBUTE_SVC_CFG_SUSPENDABLE: + break; default: WL_ERR(("Unknown type, %d\n", attr_type)); ret = -EINVAL; @@ -5142,6 +5163,10 @@ wl_cfgvendor_nan_parse_args(struct wiphy *wiphy, const void *buf, switch (attr_type) { /* NAN Enable request attributes */ + case NAN_ATTRIBUTE_INST_ID: { + /* Skip */ + break; + } case NAN_ATTRIBUTE_2G_SUPPORT:{ if (nla_len(iter) != sizeof(uint8)) { ret = -EINVAL; @@ -5626,22 +5651,14 @@ wl_cfgvendor_nan_parse_args(struct wiphy *wiphy, const void *buf, ret = -EINVAL; goto exit; } - chan = wf_mhz2channel((uint)nla_get_u32(iter), 0); - if (chan < 0) { - WL_ERR((" Instant mode Channel is not valid %d chan %d \n", - (uint)nla_get_u32(iter), chan)); - ret = -EINVAL; - break; - } - /* 20MHz as BW */ - cmd_data->instant_chan = wf_channel2chspec(chan, WL_CHANSPEC_BW_20); - if (cmd_data->instant_chan <= 0) { + cmd_data->instant_chspec = wl_freq_to_chanspec((int)nla_get_u32(iter)); + if (cmd_data->instant_chspec <= 0) { WL_ERR((" Instant mode Channel is not valid \n")); ret = -EINVAL; break; } - WL_DBG(("valid instant mode chanspec, chanspec = 0x%04x \n", - cmd_data->instant_chan)); + WL_INFORM_MEM(("[NAN Instant mode] Freq %d chanspec %x \n", + nla_get_u32(iter), cmd_data->instant_chspec)); break; case NAN_ATTRIBUTE_ENABLE_MERGE: if (nla_len(iter) != sizeof(uint8)) { @@ -8726,6 +8743,7 @@ static int wl_cfgvendor_dbg_get_ring_data(struct wiphy *wiphy, { int ret = BCME_OK, rem, type; char ring_name[DBGRING_NAME_MAX] = {0}; + int ring_id; const struct nlattr *iter; struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); dhd_pub_t *dhd_pub = cfg->pub; @@ -8742,7 +8760,21 @@ static int wl_cfgvendor_dbg_get_ring_data(struct wiphy *wiphy, } } - WL_MEM(("Received GET_RING_DATA ring:%s\n", ring_name)); + /* Moved the dump_start op */ + ring_id = dhd_dbg_find_ring_id(dhd_pub, ring_name); + /* Using first ring get context to trigger ring dump event. */ + if (ring_id == DEBUG_DUMP_RING1_ID) { + /* + * The ring buffer data context timeout at framework is 100ms and + * hence skipping memdump invocation in this path. + */ + dhd_pub->skip_memdump_map_read = true; + WL_MEM(("Doing dump_start op for ring_id %d ring:%s\n", + ring_id, ring_name)); + dhd_log_dump_vendor_trigger(dhd_pub); + } + + WL_DBG_MEM(("Received GET_RING_DATA ring:%s\n", ring_name)); ret = dhd_os_trigger_get_ring_data(dhd_pub, ring_name); if (ret < 0) { WL_ERR(("trigger_get_data failed ret:%d\n", ret)); @@ -10376,10 +10408,8 @@ const uint8 default_dscp_mapping_table[UP_TABLE_MAX] = UNUSED_PRIO, UNUSED_PRIO, UNUSED_PRIO, UNUSED_PRIO /* 60 ~ 63 */ }; -static uint8 custom_dscp2priomap[UP_TABLE_MAX]; - static int -wl_set_dscp_deafult_priority(uint8* table) +wl_set_dscp_default_priority(uint8* table) { int err = BCME_ERROR; @@ -10395,7 +10425,6 @@ static int wl_cfgvendor_custom_mapping_of_dscp(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len) { - struct bcm_cfg80211 *cfg; int err = BCME_OK, rem, type; const struct nlattr *iter; uint32 dscp_start = 0; @@ -10404,14 +10433,27 @@ wl_cfgvendor_custom_mapping_of_dscp(struct wiphy *wiphy, uint32 priority = 0; uint32 dscp; int32 def_dscp_pri; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct net_device *ndev = wdev_to_ndev(wdev); + u8 *up_table; - cfg = wl_cfg80211_get_bcmcfg(); - if (!cfg || !cfg->wdev) { - err = BCME_NOTUP; - goto exit; + if (ndev == NULL) { + WL_ERR(("Invalid net device, NULL\n")); + err = BCME_ERROR; + goto exit; } - if (!cfg->up_table) { - cfg->up_table = (uint8 *) custom_dscp2priomap; + + up_table = wl_get_up_table_netinfo(cfg, ndev); + if (!up_table) { + up_table = (uint8 *)MALLOCZ(cfg->osh, UP_TABLE_MAX); + if (up_table == NULL) { + WL_ERR(("malloc failure for up_table\n")); + err = BCME_NOMEM; + goto exit; + } + wl_set_dscp_default_priority(up_table); + wl_store_up_table_netinfo(cfg, ndev, up_table); + WL_INFORM(("allocate dscp up_table\n")); } nla_for_each_attr(iter, data, len, rem) { @@ -10477,10 +10519,13 @@ wl_cfgvendor_custom_mapping_of_dscp(struct wiphy *wiphy, } /* Set the custom DSCP of user priority. */ - err = memset_s(cfg->up_table + dscp_start, UP_TABLE_MAX - dscp_start, priority, + err = memset_s(up_table + dscp_start, UP_TABLE_MAX - dscp_start, priority, dscp_end - dscp_start + 1); + if (unlikely(err)) { - WL_ERR(("Fail to set table\n")); + WL_ERR(("Fail to set table. free table\n")); + MFREE(cfg->osh, up_table, UP_TABLE_MAX); + wl_store_up_table_netinfo(cfg, ndev, NULL); } exit: @@ -10492,19 +10537,24 @@ static int wl_cfgvendor_custom_mapping_of_dscp_reset(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len) { - struct bcm_cfg80211 *cfg; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct net_device *ndev = wdev_to_ndev(wdev); + u8 *up_table; - cfg = wl_cfg80211_get_bcmcfg(); - if (!cfg || !cfg->wdev) { - return BCME_NOTUP; + if (ndev == NULL) { + WL_ERR(("Invalid net device, NULL\n")); + return BCME_ERROR; } - if (!cfg->up_table) { - WL_INFORM(("Custom table not set yet.\n")); - return BCME_NOTREADY; + up_table = wl_get_up_table_netinfo(cfg, ndev); + if (!up_table) { + WL_ERR(("up_table is not ready\n")); + return BCME_ERROR; } - return wl_set_dscp_deafult_priority(cfg->up_table); + wl_set_dscp_default_priority(up_table); + + return BCME_OK; } #endif /* WL_CUSTOM_MAPPING_OF_DSCP */ @@ -10583,6 +10633,10 @@ wl_cfgvendor_twt_setup(struct wiphy *wiphy, uint8 *rem = mybuf; uint16 rem_len = sizeof(mybuf); +#ifdef WLAN_TRACKER + dhd_custom_notify(CUSTOM_NOTIFY_TWT_SETUP); +#endif /* WLAN_TRACKER */ + bzero(&val, sizeof(val)); val.version = WL_TWT_SETUP_VER; val.length = sizeof(val.version) + sizeof(val.length); @@ -10735,7 +10789,9 @@ wl_cfgvendor_twt_teardown(struct wiphy *wiphy, "Negotiation type %d alltwt %d\n", val.configID, val.teardesc.negotiation_type, val.teardesc.alltwt)); } - +#ifdef WLAN_TRACKER + dhd_custom_notify(CUSTOM_NOTIFY_TWT_TEARDOWN); +#endif /* WLAN_TRACKER */ exit: return bw; } @@ -10892,6 +10948,109 @@ fail: } static int +wl_cfgvendor_send_twt_status_map_v1(struct wiphy *wiphy, uint8 config_id, + wl_twt_status_v1_t *status) +{ + uint i; + int ret = BCME_OK; + wl_twt_sdesc_v0_t *sdesc = NULL; + struct sk_buff *skb; + int32 mem_needed; + + mem_needed = BRCM_TWT_HAL_VENDOR_EVENT_BUF_LEN; + + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed); + if (unlikely(!skb)) { + WL_ERR(("%s: can't allocate %d bytes\n", __FUNCTION__, mem_needed)); + ret = -ENOMEM; + goto fail; + } + + for (i = 0; i < WL_TWT_MAX_ITWT; i ++) { + if ((status->itwt_status[i].configID != WL_TWT_INV_CONFIG_ID) && + (status->itwt_status[i].configID == config_id)) { + sdesc = &status->itwt_status[i].desc; + if (!sdesc) { + WL_ERR(("Failed to fetch the descriptions for the config id %d\n", + config_id)); + goto fail; + } + WL_DBG_MEM(("response o/p for config_id %u: setup_cmd: %d, flow_flags: %u," + " flow_id: %u, channel: %u, wake_dur: %u," + " wake_int: %u, neg_type: %d", + status->itwt_status[i].configID, + (int)sdesc->setup_cmd, sdesc->flow_flags, (int)sdesc->flow_id, + (int)sdesc->channel, sdesc->wake_dur, sdesc->wake_int, + sdesc->negotiation_type)); + + ret = nla_put_u8(skb, ANDR_TWT_ATTRIBUTE_SETUP_CMD, (int)sdesc->setup_cmd); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTRIBUTE_SETUP_CMD, ret:%d\n", + ret)); + goto fail; + } + ret = nla_put_u8(skb, ANDR_TWT_ATTRIBUTE_FLOW_FLAGS, + (int)sdesc->flow_flags); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTRIBUTE_FLOW_FLAGS, ret:%d\n", + ret)); + goto fail; + } + ret = nla_put_u8(skb, ANDR_TWT_ATTRIBUTE_FLOW_ID, (int)sdesc->flow_id); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTRIBUTE_FLOW_ID, ret:%d\n", + ret)); + goto fail; + } + ret = nla_put_u32(skb, ANDR_TWT_ATTRIBUTE_CHANNEL, (int)sdesc->channel); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTRIBUTE_CHANNEL, ret:%d\n", + ret)); + goto fail; + } + ret = nla_put_u8(skb, ANDR_TWT_ATTR_NEGOTIATION_TYPE, + (int)sdesc->negotiation_type); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTR_NEGOTIATION_TYPE, ret:%d\n", + ret)); + goto fail; + } + + /* Convert to us from ms, as fw expects it in us */ + ret = nla_put_u32(skb, ANDR_TWT_ATTR_WAKE_DURATION, + (1000u*sdesc->wake_dur)); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTR_WAKE_DURATION, ret:%d\n", + ret)); + goto fail; + } + + /* Convert to us from ms, as fw expects it in us */ + ret = nla_put_u32(skb, ANDR_TWT_ATTR_WAKE_INTERVAL, + (1000u*sdesc->wake_int)); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTR_WAKE_INTERVAL, ret:%d\n", + ret)); + goto fail; + } + } + } + + ret = cfg80211_vendor_cmd_reply(skb); + if (unlikely(ret)) { + WL_ERR(("vendor command reply failed, ret=%d\n", ret)); + } + return ret; +fail: + /* Free skb for failure cases */ + if (skb) { + kfree_skb(skb); + } + + return ret; +} + +static int wl_cfgvendor_twt_stats(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len, bool clear_stats) { @@ -10948,7 +11107,17 @@ wl_cfgvendor_twt_stats(struct wiphy *wiphy, goto exit; } - (void)memcpy_s(&stats_v2, sizeof(stats_v2), iovresp, sizeof(stats_v2)); + if (sizeof(stats_v2) > sizeof(iovresp)) { + WL_ERR(("Invalid len : %ld\n", sizeof(stats_v2))); + ret = BCME_BADLEN; + goto exit; + } + + ret = memcpy_s(&stats_v2, sizeof(stats_v2), iovresp, sizeof(stats_v2)); + if (ret) { + WL_ERR(("Failed to copy result: %d\n", ret)); + goto exit; + } if (dtoh16(stats_v2.version) == WL_TWT_STATS_VERSION_2) { if (!clear_stats) { @@ -10970,6 +11139,90 @@ exit: } static int +wl_cfgvendor_twt_get_response(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int ret = BCME_OK; + char iovbuf[WLC_IOCTL_SMLEN] = {0, }; + uint8 *pxtlv = NULL; + uint8 *iovresp = NULL; + wl_twt_status_cmd_v1_t status_cmd; + wl_twt_status_v1_t result; + uint16 buflen = 0, bufstart = 0; + s32 type, rem_attr; + const struct nlattr *iter; + struct bcm_cfg80211 *cfg = wl_get_cfg(wdev_to_ndev(wdev)); + + bzero(&status_cmd, sizeof(status_cmd)); + bzero(&result, sizeof(result)); + + status_cmd.version = WL_TWT_CMD_STATUS_VERSION_1; + status_cmd.length = sizeof(status_cmd) - OFFSETOF(wl_twt_status_cmd_v1_t, peer); + + nla_for_each_attr(iter, data, len, rem_attr) { + type = nla_type(iter); + if (type == ANDR_TWT_ATTR_CONFIG_ID) { + /* Config ID */ + status_cmd.configID = nla_get_u8(iter); + } else { + WL_ERR(("Invalid TWT get status attribute type %d\n", type)); + goto exit; + } + } + + iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN); + if (iovresp == NULL) { + WL_ERR(("%s: iov resp memory alloc exited\n", __FUNCTION__)); + goto exit; + } + + buflen = bufstart = WLC_IOCTL_SMLEN; + pxtlv = (uint8 *)iovbuf; + ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_STATUS, + sizeof(status_cmd), (uint8 *)&status_cmd, BCM_XTLV_OPTION_ALIGN32); + if (ret != BCME_OK) { + WL_ERR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret)); + goto exit; + } + + if ((ret = wldev_iovar_getbuf(wdev_to_ndev(wdev), "twt", iovbuf, bufstart-buflen, + iovresp, WLC_IOCTL_MEDLEN, NULL))) { + WL_ERR(("Getting twt status failed with err=%d \n", ret)); + goto exit; + } + + if (sizeof(result) > sizeof(iovresp)) { + WL_ERR(("Invalid len : %ld\n", sizeof(result))); + ret = BCME_BADLEN; + goto exit; + } + + ret = memcpy_s(&result, sizeof(result), iovresp, sizeof(result)); + if (ret) { + WL_ERR(("Failed to copy result: %d\n", ret)); + goto exit; + } + + if (dtoh16(result.version) == WL_TWT_CMD_STATUS_VERSION_1) { + ret = wl_cfgvendor_send_twt_status_map_v1(wiphy, status_cmd.configID, &result); + if (ret != BCME_OK) { + WL_ERR(("Failed to send twt response for config_id %d\n", + status_cmd.configID)); + goto exit; + } + } else { + ret = BCME_UNSUPPORTED; + WL_ERR(("Version 1 unsupported. ver %d, \n", dtoh16(result.version))); + } + +exit: + if (iovresp) { + MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN); + } + return ret; +} + +static int wl_cfgvendor_twt_get_stats(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len) { @@ -11068,7 +11321,17 @@ wl_cfgvendor_twt_cap(struct wiphy *wiphy, goto exit; } - (void)memcpy_s(&result, sizeof(result), iovresp, sizeof(result)); + if (sizeof(result) > sizeof(iovresp)) { + WL_ERR(("Invalid len : %ld\n", sizeof(result))); + ret = BCME_BADLEN; + goto exit; + } + + ret = memcpy_s(&result, sizeof(result), iovresp, sizeof(result)); + if (ret) { + WL_ERR(("Failed to copy result: %d\n", ret)); + goto exit; + } if (dtoh16(result.version) == WL_TWT_CAP_CMD_VERSION_1) { WL_ERR(("capability ver %d, \n", dtoh16(result.version))); @@ -12053,6 +12316,7 @@ const struct nla_policy nan_attr_policy[NAN_ATTRIBUTE_MAX] = { [NAN_ATTRIBUTE_INSTANT_MODE_ENABLE] = { .type = NLA_U32, .len = sizeof(uint32) }, [NAN_ATTRIBUTE_INSTANT_COMM_CHAN] = { .type = NLA_U32, .len = sizeof(uint32) }, [NAN_ATTRIBUTE_CHRE_REQUEST] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_SVC_CFG_SUSPENDABLE] = { .type = NLA_U8, .len = sizeof(uint8) }, }; #endif /* WL_NAN */ @@ -13380,6 +13644,18 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .maxattr = ANDR_TWT_ATTR_MAX #endif /* LINUX_VERSION >= 5.3 */ }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = ANDR_TWT_SUBCMD_GET_RESPONSE + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_twt_get_response, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_twt_attr_policy, + .maxattr = ANDR_TWT_ATTR_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, #endif /* !WL_TWT && WL_TWT_HAL_IF */ #ifdef SUPPORT_OTA_UPDATE { @@ -13573,9 +13849,6 @@ int wl_cfgvendor_attach(struct wiphy *wiphy, dhd_pub_t *dhd) #ifdef DHD_LOG_DUMP dhd_os_dbg_register_urgent_notifier(dhd, wl_cfgvendor_dbg_send_file_dump_evt); #endif /* DHD_LOG_DUMP */ -#ifdef WL_CUSTOM_MAPPING_OF_DSCP - (void)wl_set_dscp_deafult_priority(custom_dscp2priomap); -#endif #ifdef SUPPORT_OTA_UPDATE (void)wl_set_ota_nvram_ext(dhd); #endif /* SUPPORT_OTA_UPDATE */ diff --git a/wl_cfgvendor.h b/wl_cfgvendor.h index e365ce8..112c766 100644 --- a/wl_cfgvendor.h +++ b/wl_cfgvendor.h @@ -233,6 +233,7 @@ enum andr_vendor_subcmd { ANDR_TWT_SUBCMD_INFO_FRAME, ANDR_TWT_SUBCMD_GET_STATS, ANDR_TWT_SUBCMD_CLR_STATS, + ANDR_TWT_SUBCMD_GET_RESPONSE, RTT_SUBCMD_SET_CONFIG = ANDROID_NL80211_SUBCMD_RTT_RANGE_START, RTT_SUBCMD_CANCEL_CONFIG, RTT_SUBCMD_GETCAPABILITY, @@ -465,6 +466,8 @@ enum rtt_attributes { RTT_ATTRIBUTE_RESULT_CNT = 32, RTT_ATTRIBUTE_RESULT = 33, RTT_ATTRIBUTE_RESULT_DETAIL = 34, + RTT_ATTRIBUTE_RESULT_FREQ = 35, + RTT_ATTRIBUTE_RESULT_BW = 36, /* Add any new RTT_ATTRIBUTE prior to RTT_ATTRIBUTE_MAX */ RTT_ATTRIBUTE_MAX }; @@ -1040,6 +1043,10 @@ typedef enum { ANDR_TWT_ATTR_AVG_PKT_SIZE_TX = 27, ANDR_TWT_ATTR_AVG_PKT_NUM_RX = 28, ANDR_TWT_ATTR_AVG_PKT_SIZE_RX = 29, + ANDR_TWT_ATTRIBUTE_SETUP_CMD = 30, + ANDR_TWT_ATTRIBUTE_FLOW_FLAGS = 31, + ANDR_TWT_ATTRIBUTE_FLOW_ID = 32, + ANDR_TWT_ATTRIBUTE_CHANNEL = 33, ANDR_TWT_ATTR_MAX } andr_twt_attribute; diff --git a/wl_cfgvif.c b/wl_cfgvif.c index 2de92ef..f80e4fa 100644 --- a/wl_cfgvif.c +++ b/wl_cfgvif.c @@ -894,6 +894,7 @@ wl_release_vif_macaddr(struct bcm_cfg80211 *cfg, const u8 *mac_addr, u16 wl_ifty #ifdef WL_NAN if (!((cfg->nancfg->mac_rand) && (wl_iftype == WL_IF_TYPE_NAN))) #endif /* WL_NAN */ +#line 902 { /* Fetch last two bytes of mac address */ org_toggle_bytes = ntoh16(*((u16 *)&ndev->dev_addr[4])); @@ -901,14 +902,14 @@ wl_release_vif_macaddr(struct bcm_cfg80211 *cfg, const u8 *mac_addr, u16 wl_ifty toggled_bit = (org_toggle_bytes ^ cur_toggle_bytes); WL_DBG(("org_toggle_bytes:%04X cur_toggle_bytes:%04X\n", - org_toggle_bytes, cur_toggle_bytes)); + org_toggle_bytes, cur_toggle_bytes)); if (toggled_bit & cfg->vif_macaddr_mask) { /* This toggled_bit is marked in the used mac addr * mask. Clear it. */ cfg->vif_macaddr_mask &= ~toggled_bit; - WL_INFORM(("MAC address - " MACDBG " released. toggled_bit:%04X" - " vif_mask:%04X\n", + WL_INFORM(("MAC address - " + MACDBG " released. toggled_bit:%04X vif_mask:%04X\n", MAC2STRDBG(mac_addr), toggled_bit, cfg->vif_macaddr_mask)); } else { WL_ERR(("MAC address - " MACDBG " not found in the used list." @@ -917,8 +918,8 @@ wl_release_vif_macaddr(struct bcm_cfg80211 *cfg, const u8 *mac_addr, u16 wl_ifty return -EINVAL; } } - WL_INFORM_MEM(("vif deleted. vif_count:%d\n", cfg->vif_count)); + return BCME_OK; } @@ -5569,6 +5570,25 @@ const wl_event_msg_t *e, void *data) } s32 +wl_cfgvif_csa_start_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, +const wl_event_msg_t *e, void *data) +{ + struct net_device *ndev = NULL; + + if (!cfgdev) { + WL_ERR(("invalid arg\n")); + return BCME_ERROR; + } + + ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + WL_INFORM_MEM(("[%s] csa started\n", ndev->name)); + + wl_set_drv_status(cfg, CSA_ACTIVE, ndev); + + return BCME_OK; +} + +s32 wl_csa_complete_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data) { @@ -5576,15 +5596,21 @@ const wl_event_msg_t *e, void *data) u32 chanspec = 0; struct net_device *ndev = NULL; struct ether_addr bssid; + u32 status = dtoh32(e->status); WL_DBG(("Enter\n")); - if (unlikely(e->status)) { - WL_ERR(("status:0x%x \n", e->status)); - return -1; - } if (likely(cfgdev)) { ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); + wl_clr_drv_status(cfg, CSA_ACTIVE, ndev); + + WL_INFORM_MEM(("[%s] CSA ind. ch:0x%x status:%d\n", + ndev->name, chanspec, status)); + if (status != WLC_E_STATUS_SUCCESS) { + WL_ERR(("csa complete error. status:0x%x\n", e->status)); + return BCME_ERROR; + } + /* Get association state if not AP and then query chanspec */ if (!((wl_get_mode_by_netdev(cfg, ndev)) == WL_MODE_AP)) { error = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN); @@ -5601,7 +5627,6 @@ const wl_event_msg_t *e, void *data) return -1; } - WL_INFORM_MEM(("[%s] CSA ind. ch:0x%x\n", ndev->name, chanspec)); if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) { /* For AP/GO role */ wl_ap_channel_ind(cfg, ndev, chanspec); diff --git a/wl_cfgvif.h b/wl_cfgvif.h index 9641ac0..2f7ccc8 100644 --- a/wl_cfgvif.h +++ b/wl_cfgvif.h @@ -198,6 +198,8 @@ extern s32 wl_cfg80211_del_beacon(struct wiphy *wiphy, struct net_device *dev); extern s32 wl_ap_start_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); +extern s32 wl_cfgvif_csa_start_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data); extern s32 wl_csa_complete_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); extern s32 wl_cfg80211_set_ap_role(struct bcm_cfg80211 *cfg, struct net_device *dev); @@ -178,7 +178,7 @@ void reset_roam_cache(struct bcm_cfg80211 *cfg) static void add_roam_cache_list(uint8 *SSID, uint32 SSID_len, chanspec_t chanspec) { - int i; + int i, ret = 0; uint8 channel; char chanbuf[CHANSPEC_STR_LEN]; @@ -186,6 +186,11 @@ add_roam_cache_list(uint8 *SSID, uint32 SSID_len, chanspec_t chanspec) return; } + if (SSID_len > DOT11_MAX_SSID_LEN) { + WL_ERR(("SSID len %u out of bounds [0-32]\n", SSID_len)); + return; + } + for (i = 0; i < n_roam_cache; i++) { if ((roam_cache[i].ssid_len == SSID_len) && (roam_cache[i].chanspec == chanspec) && @@ -197,10 +202,16 @@ add_roam_cache_list(uint8 *SSID, uint32 SSID_len, chanspec_t chanspec) roam_cache[n_roam_cache].ssid_len = SSID_len; channel = wf_chspec_ctlchan(chanspec); - WL_DBG(("CHSPEC = %s, CTL %d SSID %s\n", + WL_DBG(("CHSPEC = %s, CTL %d SSID %.32s\n", wf_chspec_ntoa_ex(chanspec, chanbuf), channel, SSID)); roam_cache[n_roam_cache].chanspec = CHSPEC_BAND(chanspec) | band_bw | channel; - (void)memcpy_s(roam_cache[n_roam_cache].ssid, SSID_len, SSID, SSID_len); + ret = memcpy_s(roam_cache[n_roam_cache].ssid, + sizeof(roam_cache[n_roam_cache].ssid), SSID, SSID_len); + if (ret) { + WL_ERR(("memcpy failed:%d, destsz:%lu, n:%d\n", + ret, sizeof(roam_cache[n_roam_cache].ssid), SSID_len)); + return; + } n_roam_cache++; } |