summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Kbuild20
-rw-r--r--Makefile4
-rw-r--r--bcmutils.c8
-rw-r--r--dhd.h5
-rwxr-xr-xdhd_common.c68
-rw-r--r--dhd_custom_google.c439
-rw-r--r--dhd_dbg_ring.c4
-rw-r--r--dhd_dbg_ring.h9
-rw-r--r--dhd_debug.c88
-rw-r--r--dhd_debug.h3
-rw-r--r--dhd_debug_linux.c89
-rw-r--r--dhd_linux.c87
-rw-r--r--dhd_linux_exportfs.c17
-rw-r--r--dhd_linux_platdev.c4
-rw-r--r--dhd_linux_rx.c7
-rw-r--r--dhd_linux_tx.c44
-rw-r--r--dhd_log_dump.c18
-rw-r--r--dhd_log_dump.h1
-rw-r--r--dhd_msgbuf.c16
-rw-r--r--dhd_pcie.c30
-rw-r--r--dhd_pcie.h4
-rw-r--r--dhd_pcie_linux.c17
-rw-r--r--dhd_plat.h14
-rw-r--r--dhd_pno.c1
-rw-r--r--dhd_rtt.c181
-rw-r--r--dhd_rtt.h17
-rw-r--r--wl_android.c74
-rw-r--r--wl_android.h4
-rw-r--r--wl_cfg80211.c198
-rw-r--r--wl_cfg80211.h40
-rwxr-xr-xwl_cfg_cellavoid.c46
-rw-r--r--wl_cfgnan.c12
-rw-r--r--wl_cfgnan.h10
-rw-r--r--wl_cfgscan.c145
-rw-r--r--wl_cfgscan.h2
-rwxr-xr-xwl_cfgvendor.c359
-rw-r--r--wl_cfgvendor.h7
-rw-r--r--wl_cfgvif.c43
-rw-r--r--wl_cfgvif.h2
-rw-r--r--wl_roam.c17
40 files changed, 1786 insertions, 368 deletions
diff --git a/Kbuild b/Kbuild
index 8dfc607..6f28c33 100644
--- a/Kbuild
+++ b/Kbuild
@@ -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
diff --git a/Makefile b/Makefile
index 066608d..e7ab51b 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/bcmutils.c b/bcmutils.c
index 1825f42..09cfc2a 100644
--- a/bcmutils.c
+++ b/bcmutils.c
@@ -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;
diff --git a/dhd.h b/dhd.h
index a434b8d..b45502e 100644
--- a/dhd.h
+++ b/dhd.h
@@ -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() */
diff --git a/dhd_pcie.c b/dhd_pcie.c
index ea6e385..28bec01 100644
--- a/dhd_pcie.c
+++ b/dhd_pcie.c
@@ -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) {
diff --git a/dhd_pcie.h b/dhd_pcie.h
index df38944..7fd52d4 100644
--- a/dhd_pcie.h
+++ b/dhd_pcie.h
@@ -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 */
diff --git a/dhd_plat.h b/dhd_plat.h
index df87778..bbd42ab 100644
--- a/dhd_plat.h
+++ b/dhd_plat.h
@@ -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__ */
diff --git a/dhd_pno.c b/dhd_pno.c
index 3089328..a06e5fc 100644
--- a/dhd_pno.c
+++ b/dhd_pno.c
@@ -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__));
diff --git a/dhd_rtt.c b/dhd_rtt.c
index 0558240..cb5b3e6 100644
--- a/dhd_rtt.c
+++ b/dhd_rtt.c
@@ -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));
diff --git a/dhd_rtt.h b/dhd_rtt.h
index 6fb3500..86535c1 100644
--- a/dhd_rtt.h
+++ b/dhd_rtt.h
@@ -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);
diff --git a/wl_roam.c b/wl_roam.c
index a53697d..05043d7 100644
--- a/wl_roam.c
+++ b/wl_roam.c
@@ -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++;
}