summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWill McVicker <willmcvicker@google.com>2024-04-15 11:09:17 -0700
committerWill McVicker <willmcvicker@google.com>2024-04-15 11:09:17 -0700
commit740730a9052f59a38df1ecb52e94d510cb89ff00 (patch)
tree61f41f467d0d268f26f44d5fb676c6fca126b485
parent2b2bbb935c2dda6ef4605e06a28b8df81d806cda (diff)
parentc6b6411e0e6f013f060103689205ba7c713f3cd8 (diff)
downloadbcm4389-android14-gs-pixel-6.1.tar.gz
Merge aosp/android-gs-raviole-5.10-android14-qpr2 into aosp/android14-gs-pixel-6.1android14-gs-pixel-6.1
* aosp/android-gs-raviole-5.10-android14-qpr2: (119 commits) bcmdhd: Fixed to apply the DHD_SKIP_COREDUMP_ON_HC properly bcmdhd: Fixed clm restricted channels to be filtered out for p2p gc case bcmdhd: Fixed blacklist connection failure bcmdhd: Fixed KP in stop pno path bcmdhd: Check for send_mb_data function return value before calling wait for d3ack timeout function bcmdhd: Avoid scan fail count based coredump trigger while CSA is in progress bcmdhd: Skip Android-U attribute (NAN_ATTRIBUTE_INST_ID) processing bcmdhd: Fixed to skip unknown attributes in discovery commands bcmdhd: Fixed to ignore validations for not supported channels during cellaoid bcmdhd: Fixed not to collect coredump for host wake assrt too long HC traps bcmdhd: Added to check overlap channel's channel info for avoiding restrict condition to overlap channel. bcmdhd: Deinitialize dbg_ring before ndev cleanup for primary interface bcmdhd: Added the debug log code for checking BY_IFACE_OP_FAILURE issue. bcmdhd: Updating new NAN HAL capabilities bcmdhd: Ignore the Coredump generation for the continuous packet drop with SKIP_COREDUMP_PKTDROP_RXHC bcmdhd: Avoid p2p scan abort on reception of partial scan results bcmdhd: Avoid connecting when the SoftAP interface is created in progress. bcmdhd: Fixed it to ignore a scan request while authorization is in progress bcmdhd: Adding bw and chanspec as part of the rtt result bcmdhd: Update the right band information for 6G channels in regulatory info bcmdhd: Add logs to dump PNO EVENT bcmdhd: Disable LOGSET_BEYOND memdump for customer platform Revert "bcmdhd: disable MACADDR_PROVISION_ENFORCED" bcmdhd: Reduce the P2P GC assoc scan time bcmdhd: Fixed the ACS 2G SCC case bcmdhd: Filter logs out-of-range bcmdhd: Fixed Memory Overwrite in function add_roam_cache_list bcmdhd: Fixed Memory Overwrite in function dhd_prot_ioctcmplt_process bcmdhd: Fixed Memory OOB Read/Write in function wl_update_hidden_ap_ie bcmdhd: Fixed Memory overwrite when handling RTT event bcmdhd: Fixed Memory Overwrite in function add_roam_cache_list bcmdhd: Fixed Memory Overwrite in function dhd_prot_ioctcmplt_process bcmdhd: Fixed Memory OOB Read/Write in function wl_update_hidden_ap_ie bcmdhd: Fixed Memory overwrite when handling RTT event bcmdhd: disable MACADDR_PROVISION_ENFORCED bcmdhd: Use default priority(PRIO_8021D_BE) when it is unknown for a DSCP bcmdhd: Added a debug log to check the case that cfg80211_inform_bss_frame function returns NULL. bcmdhd: Add error log when workqueue allocation fails bcmdhd: Disable compiler flag of DHD_ALLOC_COHERENT_MEM_FROM_ATOMIC_POOL dhd: Fixed not to free wdev twice in case of ENOMEM when system booting up bcmdhd: Added protection logic to avoid unwanted KP at roam scan completion context bcmdhd: Modify IRQ trigger type Revert "bcmdhd: disable IOC check retry meshanism" bcmdhd: Change sarmode casting to uint8 bcmdhd: Add wlan_ptracker supported bcmdhd: Fixed the ACS to avoid a restricted channel for SCC case bcmdhd: Increase the beacon wait timeout from 2sec to 4sec for virtual interface bcmdhd: caches the memdump_type before accessing it in other contexts bcmdhd: disable IOC check retry meshanism bcmdhd: Optimized the connect scan time to reduce the connection time 5.15 dependent changes for 89. bcmdhd: Optimized the connect scan time to reduce the connection time 5.15 dependent changes for 89. Fix for nan instant mode not working in 2G by fixing the input param as channel. Fix for nan instant mode not working in 2G by fixing the input param as channel. bcmdhd: Redirect RuntimePM logs to dbgring bcmdhd: Redirect RuntimePM logs to dbgring bcmdhd: Changed wakepkt_dump control flag to DHD_RPM_VAL bcmdhd: Changed wakepkt_dump control flag to DHD_RPM_VAL bcmdhd: Added a debug log for tracking deauth reason bcmdhd: Added a debug log for tracking deauth reason bcmdhd: Added wakelock to keep host awake when monitor mode is enabled bcmdhd: Added wakelock to keep host awake when monitor mode is enabled bcmdhd: Fix control path tasklet latency too long issue. bcmdhd: Fix control path tasklet latency too long issue. twt get response cmd support bcmdhd: Fixed DHD wrongly updating flowring write pointer to the dongle bcmdhd: Fixing missing files issue in the bugreport bcmdhd: Fixing missing files issue in the bugreport bcmdhd: Fixed DHD wrongly updating flowring write pointer to the dongle bcmdhd: Fixed user-after-free issue in PKT_MON bcmdhd: Optimized by packing multiple log entries into an event bcmdhd: Fixed user-after-free issue in PKT_MON bcmdhd: Optimized by packing multiple log entries into an event dhd: Fixed DSCP setting command path according to the changed structure bcmdhd: Handling dual STA scenario for QOS_MGMT dhd: Fixed DSCP setting command path according to the changed structure bcmdhd: Handling dual STA scenario for QOS_MGMT bcmdhd: Added cleanup keepalive routine in ndo_stop context bcmdhd: Added cleanup keepalive routine in ndo_stop context bcmdhd: HOST_SFH_LLC - unclone the skb in xmit handler if it is in cloned state bcmdhd: HOST_SFH_LLC - unclone the skb in xmit handler if it is in cloned state bcmdhd: Check for max buffer length before calling copy_to_user() bcmdhd: Fixed to filter out SOFTAP flag from 5G channels when STA is connected DFS bcmdhd: Apply discovery P2P probe request IEs on P2P GC interface from connect context bcmdhd: Fixed to add P2P GC scan IE configuration bcmdhd: Added protection code and debug log for RTT Check for 'dhd->pub.up' state in dump_start sysfs callback funtion bcmdhd: Fixed to check the interface for rssi and keepalive from framework return if it is not primary bcmdhd: Fixed use-after-free error bcmdhd: avoid invoking CTO recovery routine when mem_dump is in progress DHD: Fixed not to push data to ringbuffer in ring_send_evt workq context bcmdhd: disabling DHD_SDTC_ETB_DUMP Revert "bcmdhd: Handling dual STA scenario for QOS_MGMT" bcmdhd: Fix for handling replay broadcast deauth packet bcmdhd: Handling dual STA scenario for QOS_MGMT bcmdhd: Replace SMP read/write memory barriers with general memory barrier MB() bcmdhd: Fixed condition so that 5GHz non-DFS frequencies are cleared by CLM restrict bcmdhd: Fixed not to suspend by host during handshake Enable Mac Provision and Disabled memdump for PM wake ... Change-Id: Ia714716ef8f9f760c66b51aca0e298f72ae729d5 Signed-off-by: Will McVicker <willmcvicker@google.com>
-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_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_linux.c9
-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
38 files changed, 1778 insertions, 360 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_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_linux.c b/dhd_pcie_linux.c
index 43105b6..39b5c6d 100644
--- a/dhd_pcie_linux.c
+++ b/dhd_pcie_linux.c
@@ -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++;
}