Merge tag 'LA.VENDOR.1.0.r1-26900-WAIPIO.QSSI15.0' of https://git.codelinaro.org/clo/la/platform/hardware/qcom/wlan into android-15-caf

"LA.VENDOR.1.0.r1-26900-WAIPIO.QSSI15.0"

Change-Id: I0c2e57b3776647c1629b8cba6aa85a0b89f17d4e
diff --git a/.gitupstream b/.gitupstream
new file mode 100644
index 0000000..fe4ecc8
--- /dev/null
+++ b/.gitupstream
@@ -0,0 +1 @@
+https://git.codelinaro.org/clo/la/platform/hardware/qcom/wlan
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..9515b25
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,2 @@
+soong_namespace {
+}
diff --git a/Android.mk b/Android.mk
index 6695cef..3c542ca 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,6 +1,10 @@
+ifeq ($(call my-dir),$(call project-path-for,qcom-wlan))
+
 # TODO:  Find a better way to separate build configs for ADP vs non-ADP devices
 QCOM_WLAN_ROOT := $(call my-dir)
 
 ifneq ($(BOARD_IS_AUTOMOTIVE),true)
 include $(call all-subdir-makefiles)
 endif
+
+endif
diff --git a/cld80211-lib/Android.bp b/cld80211-lib/Android.bp
new file mode 100644
index 0000000..8879830
--- /dev/null
+++ b/cld80211-lib/Android.bp
@@ -0,0 +1,19 @@
+cc_library_headers {
+    name: "libcld80211_headers",
+    vendor: true,
+    export_include_dirs: ["."],
+}
+
+cc_library_shared {
+    name: "libcld80211",
+    vendor: true,
+
+    header_libs: ["libcld80211_headers"],
+    shared_libs: ["libcutils", "libnl", "liblog"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-parameter",
+    ],
+    srcs: ["cld80211_lib.c"],
+}
diff --git a/cld80211-lib/Android.mk b/cld80211-lib/Android.mk
deleted file mode 100644
index 404c116..0000000
--- a/cld80211-lib/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-# =================================
-# copy header
-# =================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libcld80211_headers
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
-LOCAL_VENDOR_MODULE := true
-include $(BUILD_HEADER_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libcld80211
-LOCAL_CLANG := true
-LOCAL_MODULE_TAGS := optional
-LOCAL_C_INCLUDES += $(LOCAL_PATH) \
-	external/libnl/include
-LOCAL_SHARED_LIBRARIES := libcutils libnl liblog
-LOCAL_SRC_FILES := cld80211_lib.c
-LOCAL_CFLAGS += -Wall -Werror -Wno-unused-parameter
-LOCAL_HEADER_LIBRARIES := libcld80211_headers
-LOCAL_VENDOR_MODULE := true
-include $(BUILD_SHARED_LIBRARY)
-
diff --git a/qcwcn/wifi_hal/Android.mk b/qcwcn/wifi_hal/Android.mk
index bd9eb2b..21e5016 100644
--- a/qcwcn/wifi_hal/Android.mk
+++ b/qcwcn/wifi_hal/Android.mk
@@ -38,7 +38,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_CFLAGS := -Wno-unused-parameter
-ifeq ($(TARGET_BUILD_VARIANT),userdebug)
+ifeq ($(TARGET_BUILD_VARIANT),eng)
 LOCAL_CFLAGS += "-DLOG_NDEBUG=0"
 endif
 
@@ -46,6 +46,10 @@
 LOCAL_CFLAGS += -DWCNSS_QTI_AOSP
 endif
 
+ifeq ($(strip $(CONFIG_MAC_PRIVACY_LOGGING)),true)
+LOCAL_CFLAGS += -DCONFIG_MAC_PRIVACY_LOGGING
+endif
+
 # gscan.cpp: address of array 'cached_results[i].results' will always evaluate to 'true'
 LOCAL_CLANG_CFLAGS := -Wno-pointer-bool-conversion
 
@@ -62,6 +66,7 @@
 	$(LOCAL_PATH) \
 	external/libnl/include \
 	$(call include-path-for, libhardware_legacy)/hardware_legacy \
+	hardware/interfaces/wifi/legacy_headers/include/hardware_legacy \
 	external/wpa_supplicant_8/src/drivers \
 	$(TARGET_OUT_HEADERS)/cld80211-lib
 
@@ -113,6 +118,10 @@
 LOCAL_HEADER_LIBRARIES := libcutils_headers libutils_headers libwifi-hal-ctrl_headers libcld80211_headers
 LOCAL_SANITIZE := cfi signed-integer-overflow unsigned-integer-overflow
 
+ifeq ($(TARGET_SUPPORTS_WEARABLES), true)
+LOCAL_CFLAGS += -DTARGET_SUPPORTS_WEARABLES
+endif
+
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
@@ -125,6 +134,10 @@
 LOCAL_CFLAGS += "-DLOG_NDEBUG=0"
 endif
 
+ifeq ($(strip $(CONFIG_MAC_PRIVACY_LOGGING)),true)
+LOCAL_CFLAGS += -DCONFIG_MAC_PRIVACY_LOGGING
+endif
+
 # gscan.cpp: address of array 'cached_results[i].results' will always evaluate to 'true'
 LOCAL_CLANG_CFLAGS := -Wno-pointer-bool-conversion
 
@@ -139,6 +152,7 @@
 	$(LOCAL_PATH) \
 	external/libnl/include \
 	$(call include-path-for, libhardware_legacy)/hardware_legacy \
+	hardware/interfaces/wifi/legacy_headers/include/hardware_legacy \
 	external/wpa_supplicant_8/src/drivers \
 	$(TARGET_OUT_HEADERS)/cld80211-lib
 
@@ -192,4 +206,9 @@
 
 LOCAL_HEADER_LIBRARIES := libcutils_headers libutils_headers libwifi-hal-ctrl_headers libcld80211_headers
 LOCAL_SANITIZE := cfi integer_overflow
+
+ifeq ($(TARGET_SUPPORTS_WEARABLES), true)
+LOCAL_CFLAGS += -DTARGET_SUPPORTS_WEARABLES
+endif
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/qcwcn/wifi_hal/common.cpp b/qcwcn/wifi_hal/common.cpp
index 263043b..3bd78a6 100644
--- a/qcwcn/wifi_hal/common.cpp
+++ b/qcwcn/wifi_hal/common.cpp
@@ -18,8 +18,6 @@
 #include <linux/pkt_sched.h>
 #include <linux-private/linux/fib_rules.h>
 #include <netlink/object-api.h>
-#include <netlink-private/object-api.h>
-#include <netlink-private/types.h>
 #include <dlfcn.h>
 #include <pthread.h>
 #include "wifi_hal.h"
@@ -239,6 +237,7 @@
 lowi_cb_table_t *LowiWifiHalApi = NULL;
 /* LowiSupportedCapabilities read */
 u32 lowiSupportedCapabilities = 0;
+bool lowiUnsupported = false;
 
 int compareLowiVersion(u16 major, u16 minor, u16 micro)
 {
@@ -269,21 +268,27 @@
     *lowi_wifihal_api = NULL;
     *lowi_get_capa_supported = false;
 
+    if (lowiUnsupported) {
+        return WIFI_ERROR_NOT_SUPPORTED;
+    }
+
 #if __WORDSIZE == 64
     void* lowi_handle = dlopen("/vendor/lib64/liblowi_wifihal.so", RTLD_NOW);
 #else
     void* lowi_handle = dlopen("/vendor/lib/liblowi_wifihal.so", RTLD_NOW);
 #endif
     if (!lowi_handle) {
-        ALOGE("%s: NULL lowi_handle, err: %s", __FUNCTION__, dlerror());
-        return WIFI_ERROR_UNKNOWN;
+        ALOGV("%s: NULL lowi_handle, err: %s", __FUNCTION__, dlerror());
+        retVal = WIFI_ERROR_NOT_SUPPORTED;
+        goto cleanup;
     }
 
     lowiCbTable = (getCbTable_t*)dlsym(lowi_handle,
                                        "lowi_wifihal_get_cb_table");
     if (!lowiCbTable) {
         ALOGE("%s: NULL lowi callback table", __FUNCTION__);
-        return WIFI_ERROR_UNKNOWN;
+        retVal = WIFI_ERROR_NOT_SUPPORTED;
+        goto cleanup;
     }
 
     *lowi_wifihal_api = lowiCbTable();
@@ -344,6 +349,7 @@
 cleanup:
     if (retVal) {
         *lowi_wifihal_api = NULL;
+        lowiUnsupported = true;
     }
     return retVal;
 }
@@ -353,6 +359,10 @@
     int ret = WIFI_SUCCESS;
     bool lowi_get_capabilities_support = false;
 
+    if (lowiUnsupported) {
+        return NULL;
+    }
+
     if (LowiWifiHalApi == NULL) {
         ALOGV("%s: LowiWifiHalApi Null, Initialize Lowi",
               __FUNCTION__);
@@ -366,7 +376,7 @@
         /* Initialize LOWI if it isn't up already. */
         ret = LowiWifiHalApi->init();
         if (ret) {
-            ALOGE("%s: failed lowi initialization. "
+            ALOGW("%s: failed lowi initialization. "
                 "Returned error:%d. Exit.", __FUNCTION__, ret);
             goto cleanup;
         }
@@ -398,10 +408,12 @@
 
 cleanup:
     if (LowiWifiHalApi && LowiWifiHalApi->destroy) {
+        ALOGI("%s: Cleaning up Lowi due to failure. Return NULL", __FUNCTION__);
         ret = LowiWifiHalApi->destroy();
     }
     LowiWifiHalApi = NULL;
     lowiSupportedCapabilities = 0;
+    lowiUnsupported = true;
     return LowiWifiHalApi;
 }
 
diff --git a/qcwcn/wifi_hal/common.h b/qcwcn/wifi_hal/common.h
index 78ae269..9b1c347 100644
--- a/qcwcn/wifi_hal/common.h
+++ b/qcwcn/wifi_hal/common.h
@@ -91,6 +91,14 @@
 
 #define WIFI_HAL_CTRL_IFACE     "/dev/socket/wifihal/wifihal_ctrlsock"
 
+#ifdef CONFIG_MAC_PRIVACY_LOGGING
+#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[5]
+#define MACSTR "%02x:%02x:%02x:**:**:%02x"
+#else
+#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
+#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
+#endif
+
 #define MAC_ADDR_ARRAY(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
 #define MAC_ADDR_STR "%02x:%02x:%02x:%02x:%02x:%02x"
 #ifndef BIT
@@ -213,6 +221,10 @@
     bool apf_enabled;
     bool support_nan_ext_cmd;
     pkt_log_version  pkt_log_ver;
+#ifndef TARGET_SUPPORTS_WEARABLES
+    /* Interface combination matrix */
+    wifi_iface_concurrency_matrix iface_comb_matrix;
+#endif /* TARGET_SUPPORTS_WEARABLES */
     qca_wlan_vendor_sar_version sar_version;
 } hal_info;
 
@@ -267,6 +279,10 @@
 wifi_error wifi_get_radar_history(wifi_interface_handle handle,
         radar_history_result *resultBuf, int resultBufSize, int *numResults);
 wifi_error wifi_disable_next_cac(wifi_interface_handle handle);
+
+wifi_error wifi_get_supported_radio_combinations_matrix(
+        wifi_handle handle, u32 max_size, u32 *size,
+        wifi_radio_combination_matrix *radio_combination_matrix);
 // some common macros
 
 #define min(x, y)       ((x) < (y) ? (x) : (y))
diff --git a/qcwcn/wifi_hal/gscan.cpp b/qcwcn/wifi_hal/gscan.cpp
index d1afee6..9350a34 100644
--- a/qcwcn/wifi_hal/gscan.cpp
+++ b/qcwcn/wifi_hal/gscan.cpp
@@ -1645,13 +1645,8 @@
                         cached_results[i].results[j].ts);
                     ALOGD("%s: SSID  %s ", __FUNCTION__,
                         cached_results[i].results[j].ssid);
-                    ALOGD("%s: BSSID: %02x:%02x:%02x:%02x:%02x:%02x \n",
-                        __FUNCTION__, cached_results[i].results[j].bssid[0],
-                        cached_results[i].results[j].bssid[1],
-                        cached_results[i].results[j].bssid[2],
-                        cached_results[i].results[j].bssid[3],
-                        cached_results[i].results[j].bssid[4],
-                        cached_results[i].results[j].bssid[5]);
+                    ALOGD("%s: BSSID: " MACSTR " \n",
+                        __FUNCTION__, MAC2STR(cached_results[i].results[j].bssid));
                     ALOGD("%s: channel %d ", __FUNCTION__,
                         cached_results[i].results[j].channel);
                     ALOGD("%s: rssi  %d ", __FUNCTION__,
diff --git a/qcwcn/wifi_hal/gscan_event_handler.cpp b/qcwcn/wifi_hal/gscan_event_handler.cpp
index 074d64b..6639f8f 100644
--- a/qcwcn/wifi_hal/gscan_event_handler.cpp
+++ b/qcwcn/wifi_hal/gscan_event_handler.cpp
@@ -334,11 +334,9 @@
             tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT_SD]);
 
         ALOGV("gscan_parse_hotlist_ap_results: ts %" PRId64 " SSID  %s "
-              "BSSID: %02x:%02x:%02x:%02x:%02x:%02x channel %d rssi %d "
+              "BSSID: " MACSTR " channel %d rssi %d "
               "rtt %" PRId64" rtt_sd %" PRId64,
-              results[i].ts, results[i].ssid,
-              results[i].bssid[0], results[i].bssid[1], results[i].bssid[2],
-              results[i].bssid[3], results[i].bssid[4], results[i].bssid[5],
+              results[i].ts, results[i].ssid, MAC2STR(results[i].bssid),
               results[i].channel, results[i].rssi, results[i].rtt,
               results[i].rtt_sd);
         /* Increment loop index for next record */
@@ -436,10 +434,8 @@
         QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_RSSI_LIST]
             ), results[i]->num_rssi * sizeof(wifi_rssi));
 
-        ALOGV("significant_change_result:%d, BSSID:"
-            "%02x:%02x:%02x:%02x:%02x:%02x channel:%d  num_rssi:%d ",
-            i, results[i]->bssid[0], results[i]->bssid[1], results[i]->bssid[2],
-            results[i]->bssid[3], results[i]->bssid[4], results[i]->bssid[5],
+        ALOGV("significant_change_result:%d, BSSID:" MACSTR " channel:%d  num_rssi:%d ",
+            i, MAC2STR(results[i]->bssid),
             results[i]->channel, results[i]->num_rssi);
 
         rem_size = sizeof(rssi_buf);
@@ -577,11 +573,10 @@
             tb2[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT_SD]);
 
         ALOGV("gscan_parse_hotlist_ssid_results: ts %" PRId64 " SSID  %s "
-              "BSSID: %02x:%02x:%02x:%02x:%02x:%02x channel %d rssi %d "
+              "BSSID: " MACSTR " channel %d rssi %d "
               "rtt %" PRId64 " rtt_sd %" PRId64,
               results[i].ts, results[i].ssid,
-              results[i].bssid[0], results[i].bssid[1], results[i].bssid[2],
-              results[i].bssid[3], results[i].bssid[4], results[i].bssid[5],
+              MAC2STR(results[i].bssid),
               results[i].channel, results[i].rssi, results[i].rtt,
               results[i].rtt_sd);
         /* Increment loop index for next record */
@@ -731,16 +726,11 @@
           mPasspointNetworkFoundResult->ie_length);
 
       ALOGV("%s: ts: %" PRId64 " SSID: %s "
-            "BSSID: %02x:%02x:%02x:%02x:%02x:%02x  channel: %d  rssi: %d"
+            "BSSID: " MACSTR "  channel: %d  rssi: %d"
             " rtt: % " PRId64 " rtt_sd  %" PRId64 " ie_length  %u ",
             __FUNCTION__, mPasspointNetworkFoundResult->ts,
             mPasspointNetworkFoundResult->ssid,
-            mPasspointNetworkFoundResult->bssid[0],
-            mPasspointNetworkFoundResult->bssid[1],
-            mPasspointNetworkFoundResult->bssid[2],
-            mPasspointNetworkFoundResult->bssid[3],
-            mPasspointNetworkFoundResult->bssid[4],
-            mPasspointNetworkFoundResult->bssid[5],
+            MAC2STR(mPasspointNetworkFoundResult->bssid),
             mPasspointNetworkFoundResult->channel,
             mPasspointNetworkFoundResult->rssi,
             mPasspointNetworkFoundResult->rtt,
@@ -931,11 +921,10 @@
             QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CAPABILITY]);
 
         ALOGV("gscan_parse_pno_network_results: ts %" PRId64 " SSID  %s "
-              "BSSID: %02x:%02x:%02x:%02x:%02x:%02x channel %d rssi %d "
+              "BSSID: " MACSTR " channel %d rssi %d "
               "rtt %" PRId64 " rtt_sd %" PRId64,
               results[i].ts, results[i].ssid,
-              results[i].bssid[0], results[i].bssid[1], results[i].bssid[2],
-              results[i].bssid[3], results[i].bssid[4], results[i].bssid[5],
+              MAC2STR(results[i].bssid),
               results[i].channel, results[i].rssi, results[i].rtt,
               results[i].rtt_sd);
         /* Increment loop index for next record */
@@ -1196,10 +1185,8 @@
 #ifdef QC_HAL_DEBUG
             ALOGD("handleEvent:FULL_SCAN_RESULTS: ts  %" PRId64, result->ts);
             ALOGD("handleEvent:FULL_SCAN_RESULTS: SSID  %s ", result->ssid) ;
-            ALOGD("handleEvent:FULL_SCAN_RESULTS: "
-                "BSSID: %02x:%02x:%02x:%02x:%02x:%02x \n",
-                result->bssid[0], result->bssid[1], result->bssid[2],
-                result->bssid[3], result->bssid[4], result->bssid[5]);
+            ALOGD("handleEvent:FULL_SCAN_RESULTS: BSSID: " MACSTR " \n",
+                MAC2STR(result->bssid));
             ALOGD("handleEvent:FULL_SCAN_RESULTS: channel %d ",
                 result->channel);
             ALOGD("handleEvent:FULL_SCAN_RESULTS: rssi  %d ", result->rssi);
diff --git a/qcwcn/wifi_hal/ifaceeventhandler.cpp b/qcwcn/wifi_hal/ifaceeventhandler.cpp
index 0c44e25..4f6271a 100644
--- a/qcwcn/wifi_hal/ifaceeventhandler.cpp
+++ b/qcwcn/wifi_hal/ifaceeventhandler.cpp
@@ -24,6 +24,40 @@
  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Changes from Qualcomm Innovation Center are provided under the following license:
+ *
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted (subject to the limitations in the
+ * disclaimer below) provided that the following conditions are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *
+ *   * Neither the name of Qualcomm Innovation Center, Inc. nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
+ * GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
+ * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include "sync.h"
@@ -169,6 +203,7 @@
     mRequestId = id;
     mSubcmd = subcmd;
     registerHandler(mSubcmd);
+    memset(tb, 0, sizeof(struct nlattr *) * (NL80211_ATTR_MAX + 1));
     ALOGV("wifiEventHandler %p constructed", this);
 }
 
@@ -208,6 +243,9 @@
     mfilter_packet_length = 0;
     res_size = 0;
     channel_buff = NULL;
+    mRadio_matrix = NULL;
+    mRadio_matrix_max_size = 0;
+    mRadio_matrix_size = NULL;
     memset(&mDriverFeatures, 0, sizeof(mDriverFeatures));
     memset(&mRadarResultParams, 0, sizeof(RadarHistoryResultsParams));
 }
@@ -561,6 +599,11 @@
                 wifiParseRadarHistory();
             }
             break;
+        case QCA_NL80211_VENDOR_SUBCMD_GET_RADIO_COMBINATION_MATRIX:
+            {
+                wifi_parse_radio_combinations_matrix();
+            }
+	    break;
         case QCA_NL80211_VENDOR_SUBCMD_GET_SAR_CAPABILITY:
             {
                 struct nlattr *tb_vendor[
@@ -568,7 +611,7 @@
                 nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_SAR_CAPABILITY_MAX,
                           (struct nlattr *)mVendorData,mDataLen, NULL);
 
-                if (tb_vendor[QCA_WLAN_VENDOR_ATTR_SAR_CAPABILITY_VERSION])
+                if(tb_vendor[QCA_WLAN_VENDOR_ATTR_SAR_CAPABILITY_VERSION])
                 {
                     mInfo->sar_version = (qca_wlan_vendor_sar_version) nla_get_u32(tb_vendor[
                                                QCA_WLAN_VENDOR_ATTR_SAR_CAPABILITY_VERSION]);
@@ -700,6 +743,161 @@
     return WIFI_SUCCESS;
 }
 
+wifi_error WifihalGeneric::wifi_parse_radio_combinations_matrix() {
+    // tbVendor
+    struct nlattr *tbVendor[QCA_WLAN_VENDOR_ATTR_RADIO_MATRIX_MAX + 1];
+    int rem = 0, rem_radio = 0;
+    u32 num_radio_combinations = 0, num_radio_configurations = 0;
+    // nested radio matrix configurations
+    struct nlattr *radio_combination[QCA_WLAN_VENDOR_ATTR_RADIO_COMBINATIONS_MAX + 1];
+    struct nlattr *attr, *attr_cfg;
+    struct nlattr *radio_cfg[QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_MAX + 1];
+    u8 band, antenna;
+    u32 result_size = sizeof(u32); /* num_radio_combinations */
+    bool max_size_exceeded = false;
+    u32 size_needed = 0, radio_cfg_size = 0;
+    bool invalid_radio_cfg = false;
+    wifi_radio_combination *radio_combination_ptr;
+    wifi_radio_configuration *radio_config;
+    u8 *buff_ptr;
+
+    static struct nla_policy
+        radio_combination_policy[QCA_WLAN_VENDOR_ATTR_RADIO_COMBINATIONS_MAX + 1] = {
+            [QCA_WLAN_VENDOR_ATTR_RADIO_COMBINATIONS_CFGS] = { .type = NLA_NESTED },
+        };
+
+    static struct nla_policy
+        radio_cfg_policy[QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_MAX + 1] = {
+            [QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_BAND] = { .type = NLA_U32 },
+            [QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_ANTENNA] = { .type = NLA_U8 },
+        };
+
+    if (nla_parse(tbVendor, QCA_WLAN_VENDOR_ATTR_RADIO_MATRIX_MAX,
+                (struct nlattr *)mVendorData,mDataLen, NULL)) {
+        ALOGE("%s: nla_parse ATTR_RADIO_MATRIX fail", __FUNCTION__);
+        return WIFI_ERROR_INVALID_ARGS;
+    }
+
+    if (!tbVendor[QCA_WLAN_VENDOR_ATTR_RADIO_MATRIX_SUPPORTED_CFGS]) {
+        ALOGE("%s: radio matrix attr entries not present", __FUNCTION__);
+        return WIFI_ERROR_INVALID_ARGS;
+    }
+
+    if (!mRadio_matrix) {
+        ALOGE("%s: radio matrix buffer is null", __FUNCTION__);
+        return WIFI_ERROR_INVALID_ARGS;
+    }
+
+    buff_ptr = (u8 *)mRadio_matrix;
+    buff_ptr += sizeof(u32); /* num_radio_combinations */
+    nla_for_each_nested(attr,
+            tbVendor[QCA_WLAN_VENDOR_ATTR_RADIO_MATRIX_SUPPORTED_CFGS],
+            rem) {
+        if (nla_parse_nested(radio_combination,
+                    QCA_WLAN_VENDOR_ATTR_RADIO_COMBINATIONS_MAX,
+                    attr, radio_combination_policy)) {
+            ALOGI("%s: nla_parse_nested radio combination fail", __FUNCTION__);
+            continue;
+        }
+        radio_combination_ptr = (wifi_radio_combination *)buff_ptr;
+
+        num_radio_configurations = 0;
+        radio_cfg_size = 0;
+        nla_for_each_nested(attr_cfg,
+                radio_combination[QCA_WLAN_VENDOR_ATTR_RADIO_COMBINATIONS_CFGS],
+                rem_radio) {
+            if (nla_parse_nested(radio_cfg,
+                        QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_MAX,
+                        attr_cfg, radio_cfg_policy)) {
+                ALOGI("%s: nla_parse_nested radio cfg attr fail", __FUNCTION__);
+                continue;
+            }
+
+            if (!radio_cfg[QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_BAND] ||
+                !radio_cfg[QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_ANTENNA]) {
+                ALOGI("%s: band/antenna info not present", __FUNCTION__);
+                continue;
+            }
+
+            if (!invalid_radio_cfg) {
+                if (!num_radio_configurations) {
+                    size_needed = sizeof(wifi_radio_configuration) +
+                                  sizeof(u32);
+                    buff_ptr += sizeof(u32); /* num_radio_configurations */
+                } else {
+                    size_needed = sizeof(wifi_radio_configuration);
+                    buff_ptr += sizeof(wifi_radio_configuration);
+                }
+            }
+            if (mRadio_matrix_max_size < result_size + size_needed) {
+                ALOGI("%s: Max size reached, max size %u, needed %u",
+                        __FUNCTION__, mRadio_matrix_max_size,
+                        result_size + size_needed);
+                max_size_exceeded = true;
+                break;
+            }
+            invalid_radio_cfg = false;
+            radio_config = (wifi_radio_configuration *)buff_ptr;
+
+            if (radio_cfg[QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_BAND]) {
+                band = nla_get_u32(
+                        radio_cfg[QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_BAND]);
+                if (band == QCA_SETBAND_5G) {
+                    radio_config->band = WLAN_MAC_5_0_BAND;
+                } else if (band == QCA_SETBAND_6G) {
+                    radio_config->band = WLAN_MAC_6_0_BAND;
+                } else if (band == QCA_SETBAND_2G) {
+                    radio_config->band = WLAN_MAC_2_4_BAND;
+                } else {
+                    ALOGI("%s: Invalid band value %d", __FUNCTION__, band);
+                    invalid_radio_cfg = true;
+                    continue;
+                }
+            }
+            if (radio_cfg[QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_ANTENNA]) {
+                antenna = nla_get_u8(
+                        radio_cfg[QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_ANTENNA]);
+                if (antenna == 1) {
+                    radio_config->antenna_cfg = WIFI_ANTENNA_1X1;
+                } else if (antenna == 2) {
+                    radio_config->antenna_cfg = WIFI_ANTENNA_2X2;
+                } else if (antenna == 3) {
+                    radio_config->antenna_cfg = WIFI_ANTENNA_3X3;
+                } else if (antenna == 4) {
+                    radio_config->antenna_cfg = WIFI_ANTENNA_4X4;
+                } else {
+                    ALOGI("%s: Invalid antenna cfg value %d", __FUNCTION__,
+                          antenna);
+                    invalid_radio_cfg = true;
+                    continue;
+                }
+            }
+            radio_cfg_size += size_needed;
+            num_radio_configurations++;
+            result_size += size_needed;
+        } /* RADIO_COMBINATIONS_CFGS */
+        if (num_radio_configurations) {
+            num_radio_combinations++;
+            radio_combination_ptr->num_radio_configurations =
+                                                    num_radio_configurations;
+            ALOGI("%s: radio_combinations[%d]: num_radio_configurations %d",
+                  __FUNCTION__, num_radio_combinations,
+                  num_radio_configurations);
+        }
+
+        buff_ptr = (u8 *)radio_combination_ptr + radio_cfg_size;
+
+        if (max_size_exceeded)
+            break;
+    } /* RADIO_MATRIX_SUPPORTED_CFGS */
+    mRadio_matrix->num_radio_combinations = num_radio_combinations;
+    *mRadio_matrix_size = result_size;
+    ALOGI("%s: num_radio_combinations %d, radio_matrix_size %d", __FUNCTION__,
+          num_radio_combinations, result_size);
+
+    return WIFI_SUCCESS;
+}
+
 wifi_error WifihalGeneric::wifiParseRadarHistory() {
 {
     // tbVendor
@@ -822,6 +1020,19 @@
     mConcurrencySet = set;
 }
 
+void WifihalGeneric::set_radio_matrix_max_size(u32 max_size) {
+    mRadio_matrix_max_size = max_size;
+}
+
+void WifihalGeneric::set_radio_matrix_size(u32 *size){
+    mRadio_matrix_size = size;
+}
+
+void WifihalGeneric::set_radio_matrix(
+        wifi_radio_combination_matrix *radio_combination_matrix){
+    mRadio_matrix = radio_combination_matrix;
+}
+
 void WifihalGeneric::setSizePtr(int *set_size) {
     mSetSizePtr = set_size;
 }
@@ -929,6 +1140,8 @@
     }
 }
 
+
+
 wifi_error WifihalGeneric::getSarVersion(wifi_interface_handle handle)
 {
     wifi_error ret;
@@ -956,3 +1169,4 @@
     return ret;
 }
 
+
diff --git a/qcwcn/wifi_hal/ifaceeventhandler.h b/qcwcn/wifi_hal/ifaceeventhandler.h
index eef9624..9e02105 100644
--- a/qcwcn/wifi_hal/ifaceeventhandler.h
+++ b/qcwcn/wifi_hal/ifaceeventhandler.h
@@ -24,6 +24,40 @@
  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Changes from Qualcomm Innovation Center are provided under the following license:
+ *
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted (subject to the limitations in the
+ * disclaimer below) provided that the following conditions are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *
+ *   * Neither the name of Qualcomm Innovation Center, Inc. nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
+ * GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
+ * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #ifndef __WIFI_HAL_IFACEEVENTHANDLER_COMMAND_H__
@@ -103,6 +137,10 @@
     RadarHistoryResultsParams mRadarResultParams;
     virtual wifi_error wifiParseCapabilities(struct nlattr **tbVendor);
     virtual wifi_error wifiParseRadarHistory();
+    u32 mRadio_matrix_max_size;
+    u32 *mRadio_matrix_size;
+    wifi_radio_combination_matrix *mRadio_matrix;
+    virtual wifi_error wifi_parse_radio_combinations_matrix();
 
 public:
     WifihalGeneric(wifi_handle handle, int id, u32 vendor_id, u32 subcmd);
@@ -126,6 +164,9 @@
     virtual wifi_error copyCachedRadarHistory(radar_history_result *resultBuf,
             int resultBufSize, int *numResults);
     virtual void freeCachedRadarHistory();
+    virtual void set_radio_matrix_max_size(u32 max_size);
+    virtual void set_radio_matrix_size(u32 *size);
+    virtual void set_radio_matrix(wifi_radio_combination_matrix *radio_combination_matrix);
     virtual wifi_error getSarVersion(wifi_interface_handle handle);
 };
 
diff --git a/qcwcn/wifi_hal/llstats.cpp b/qcwcn/wifi_hal/llstats.cpp
index 8fc8d77..86c372b 100644
--- a/qcwcn/wifi_hal/llstats.cpp
+++ b/qcwcn/wifi_hal/llstats.cpp
@@ -15,7 +15,7 @@
 
  * Changes from Qualcomm Innovation Center are provided under the following license:
 
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  * SPDX-License-Identifier: BSD-3-Clause-Clear
  */
 
@@ -60,6 +60,7 @@
     mRadioStatsSize = 0;
     mNumRadios = 0;
     mNumRadiosAllocated = 0;
+    mRequestId = 0;
 }
 
 LLStatsCommand::~LLStatsCommand()
@@ -966,7 +967,7 @@
                 {
                     if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS])
                     {
-                        ALOGE("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS"
+                        ALOGD("%s: QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS"
                               " not found", __FUNCTION__);
                         return WIFI_ERROR_INVALID_ARGS;
                     }
@@ -977,7 +978,7 @@
                         QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS
                         ])
                     {
-                        ALOGE("%s:"
+                        ALOGD("%s:"
                             "QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS"
                             " not found", __FUNCTION__);
                         status = WIFI_ERROR_INVALID_ARGS;
@@ -1090,22 +1091,6 @@
                     {
                         goto cleanup;
                     }
-
-                    /* Driver/firmware might send this attribute when there
-                     * are no peers connected.
-                     * So that, the event
-                     * QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_PEERS can be
-                     * avoided.
-                     */
-                    if (tb_vendor[
-                        QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS])
-                    {
-#ifdef QC_HAL_DEBUG
-                        ALOGV("%s: numPeers is %u\n", __FUNCTION__,
-                                nla_get_u32(tb_vendor[
-                                    QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS]));
-#endif
-                    }
                 }
                 break;
 
diff --git a/qcwcn/wifi_hal/nan.cpp b/qcwcn/wifi_hal/nan.cpp
index 1690a86..a73126b 100644
--- a/qcwcn/wifi_hal/nan.cpp
+++ b/qcwcn/wifi_hal/nan.cpp
@@ -977,8 +977,8 @@
     wifi_handle handle = getWifiHandle(iface);
     hal_info *info = getHalInfo(handle);
 
-    if (iface_name == NULL) {
-        ALOGE("%s: Invalid Nan Data Interface Name. \n", __FUNCTION__);
+    if (iface_name == NULL || if_nametoindex(iface_name) == 0) {
+        ALOGE("%s: Invalid/Unknown Nan Data Interface Name. \n", __FUNCTION__);
         return WIFI_ERROR_INVALID_ARGS;
     }
 
@@ -988,11 +988,33 @@
         return WIFI_ERROR_UNKNOWN;
     }
 
+    // NL80211_CMD_DEL_INTERFACE internally takes care of NDP cleanup.
+    if ((check_feature(QCA_WLAN_VENDOR_FEATURE_USE_ADD_DEL_VIRTUAL_INTF_FOR_NDI,
+                       &info->driver_supported_features)) &&
+        if_nametoindex(iface_name)) {
+        wifiConfigCommand = new WiFiConfigCommand(handle,
+                                                  get_requestid(), 0, 0);
+        if (wifiConfigCommand == NULL) {
+            ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
+            return WIFI_ERROR_UNKNOWN;
+        }
+        wifiConfigCommand->create_generic(NL80211_CMD_DEL_INTERFACE);
+        wifiConfigCommand->put_u32(NL80211_ATTR_IFINDEX,
+                                   if_nametoindex(iface_name));
+        /* Send the NL msg. */
+        wifiConfigCommand->waitForRsp(false);
+        if (wifiConfigCommand->requestEvent() != WIFI_SUCCESS) {
+            ALOGE("%s: Delete intf failed", __FUNCTION__);
+        }
+        delete wifiConfigCommand;
+        return WIFI_SUCCESS;
+    }
+
     ret = nan_initialize_vendor_cmd(iface,
                                     &nanCommand);
     if (ret != WIFI_SUCCESS) {
         ALOGE("%s: Initialization failed", __FUNCTION__);
-        goto delete_ndi;
+        return ret;
     }
 
     /* Add the vendor specific attributes for the NL command. */
@@ -1023,28 +1045,6 @@
 
 cleanup:
     delete nanCommand;
-
-delete_ndi:
-    if ((check_feature(QCA_WLAN_VENDOR_FEATURE_USE_ADD_DEL_VIRTUAL_INTF_FOR_NDI,
-                       &info->driver_supported_features)) &&
-        if_nametoindex(iface_name)) {
-        wifiConfigCommand = new WiFiConfigCommand(handle,
-                                                  get_requestid(), 0, 0);
-        if (wifiConfigCommand == NULL) {
-            ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
-            return WIFI_ERROR_UNKNOWN;
-        }
-        wifiConfigCommand->create_generic(NL80211_CMD_DEL_INTERFACE);
-        wifiConfigCommand->put_u32(NL80211_ATTR_IFINDEX,
-                                   if_nametoindex(iface_name));
-        /* Send the NL msg. */
-        wifiConfigCommand->waitForRsp(false);
-        if (wifiConfigCommand->requestEvent() != WIFI_SUCCESS) {
-            ALOGE("%s: Delete intf failed", __FUNCTION__);
-        }
-        delete wifiConfigCommand;
-    }
-
     return ret;
 }
 
diff --git a/qcwcn/wifi_hal/radio_mode.cpp b/qcwcn/wifi_hal/radio_mode.cpp
index 267d3f4..8cbbab2 100644
--- a/qcwcn/wifi_hal/radio_mode.cpp
+++ b/qcwcn/wifi_hal/radio_mode.cpp
@@ -27,8 +27,8 @@
 
  * Changes from Qualcomm Innovation Center are provided under the following license:
 
- *  Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
- *  SPDX-License-Identifier: BSD-3-Clause-Clear
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause-Clear
  */
 
 #include "sync.h"
@@ -95,6 +95,7 @@
         : WifiVendorCommand(handle, id, vendor_id, subcmd)
 {
     memset(&mHandler, 0, sizeof(mHandler));
+    mwifi_iface_mac_info = NULL;
     if (registerVendorHandler(vendor_id, subcmd)) {
         /* Error case should not happen print log */
         ALOGE("%s: Unable to register Vendor Handler Vendor Id=0x%x subcmd=%u",
diff --git a/qcwcn/wifi_hal/roam.cpp b/qcwcn/wifi_hal/roam.cpp
index bd93c3d..ec2b290 100644
--- a/qcwcn/wifi_hal/roam.cpp
+++ b/qcwcn/wifi_hal/roam.cpp
@@ -80,10 +80,7 @@
     }
 
     for (i = 0; i < params.num_bssid; i++) {
-        ALOGV("BSSID: %d : %02x:%02x:%02x:%02x:%02x:%02x", i,
-                params.bssids[i][0], params.bssids[i][1],
-                params.bssids[i][2], params.bssids[i][3],
-                params.bssids[i][4], params.bssids[i][5]);
+        ALOGV("BSSID: %d : " MACSTR, i, MAC2STR(params.bssids[i]));
     }
 
     roamCommand =
diff --git a/qcwcn/wifi_hal/tdls.cpp b/qcwcn/wifi_hal/tdls.cpp
index c54928f..54555e2 100644
--- a/qcwcn/wifi_hal/tdls.cpp
+++ b/qcwcn/wifi_hal/tdls.cpp
@@ -27,7 +27,7 @@
 
  * Changes from Qualcomm Innovation Center are provided under the following license:
 
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  * SPDX-License-Identifier: BSD-3-Clause-Clear
  */
 
@@ -51,6 +51,7 @@
     memset(&mHandler, 0, sizeof(mHandler));
     memset(&mTDLSgetStatusRspParams, 0, sizeof(wifi_tdls_status));
     mRequestId = 0;
+    memset(&mTDLSgetCaps, 0, sizeof(wifiTdlsCapabilities));
 }
 
 TdlsCommand::~TdlsCommand()
diff --git a/qcwcn/wifi_hal/wifi_hal.cpp b/qcwcn/wifi_hal/wifi_hal.cpp
index a6fa064..5de5ac8 100644
--- a/qcwcn/wifi_hal/wifi_hal.cpp
+++ b/qcwcn/wifi_hal/wifi_hal.cpp
@@ -64,8 +64,12 @@
 #include <netlink/object-api.h>
 #include <netlink/netlink.h>
 #include <netlink/socket.h>
+#if __has_include(<netlink-private/types.h>)
 #include <netlink-private/object-api.h>
 #include <netlink-private/types.h>
+#else
+#include <nl-priv-dynamic-core/nl-core.h>
+#endif
 
 #include "nl80211_copy.h"
 
@@ -90,6 +94,7 @@
 #include "wifiloggercmd.h"
 #include "tcp_params_update.h"
 
+
 /*
  BUGBUG: normally, libnl allocates ports for all connections it makes; but
  being a static library, it doesn't really know how many other netlink
@@ -147,6 +152,13 @@
     wifi_init_tcp_param_change_event_handler(wifi_interface_handle iface);
 
 wifi_error wifi_set_voip_mode(wifi_interface_handle iface, wifi_voip_mode mode);
+#ifndef TARGET_SUPPORTS_WEARABLES
+wifi_error wifi_get_supported_iface_combination(wifi_interface_handle iface_handle);
+
+wifi_error wifi_get_supported_iface_concurrency_matrix(
+        wifi_handle handle,
+        wifi_iface_concurrency_matrix *iface_concurrency_matrix);
+#endif /* TARGET_SUPPORTS_WEARABLES */
 
 /* Initialize/Cleanup */
 
@@ -439,6 +451,7 @@
     return ret;
 }
 
+
 static wifi_error get_firmware_bus_max_size_supported(
                                                 wifi_interface_handle iface)
 {
@@ -1120,6 +1133,12 @@
     fn->wifi_set_dtim_config = wifi_set_dtim_config;
     fn->wifi_set_voip_mode = wifi_set_voip_mode;
     fn->wifi_get_usable_channels = wifi_get_usable_channels;
+    fn->wifi_get_supported_radio_combinations_matrix =
+                                wifi_get_supported_radio_combinations_matrix;
+#ifndef TARGET_SUPPORTS_WEARABLES
+    fn->wifi_get_supported_iface_concurrency_matrix =
+                                wifi_get_supported_iface_concurrency_matrix;
+#endif /* TARGET_SUPPORTS_WEARABLES */
 
     return WIFI_SUCCESS;
 }
@@ -1451,6 +1470,14 @@
     ALOGV("support_nan_ext_cmd is %d",
           info->support_nan_ext_cmd);
 
+#ifndef TARGET_SUPPORTS_WEARABLES
+    ret = wifi_get_supported_iface_combination(iface_handle);
+    if (ret != WIFI_SUCCESS) {
+        ALOGE("Failed to get driver supported interface combinations");
+        goto unload;
+    }
+#endif /* TARGET_SUPPORTS_WEARABLES */
+
     ret = wifi_get_sar_version(iface_handle);
     if (ret != WIFI_SUCCESS) {
         ALOGE("Failed to  get  SAR Version, Setting it to default.");
@@ -2584,6 +2611,73 @@
     return ret;
 }
 
+wifi_error wifi_get_supported_radio_combinations_matrix(
+                wifi_handle handle, u32 max_size, u32 *size,
+                wifi_radio_combination_matrix *radio_combination_matrix)
+{
+    wifi_error ret = WIFI_ERROR_UNKNOWN;;
+    struct nlattr *nlData;
+    WifihalGeneric *vCommand = NULL;
+    hal_info *info = NULL;
+
+    ALOGI("%s: enter", __FUNCTION__);
+    if (!handle) {
+         ALOGE("%s: Error, wifi_handle NULL", __FUNCTION__);
+         return WIFI_ERROR_UNKNOWN;
+    }
+
+    info = getHalInfo(handle);
+    if (!info || info->num_interfaces < 1) {
+         ALOGE("%s: Error, wifi_handle NULL or base wlan interface not present",
+               __FUNCTION__);
+         return WIFI_ERROR_UNKNOWN;
+    }
+
+    if (size == NULL || radio_combination_matrix == NULL) {
+        ALOGE("%s: NULL set pointer provided. Exit.",
+            __func__);
+        return WIFI_ERROR_INVALID_ARGS;
+    }
+
+    if (max_size < sizeof(u32)) {
+        ALOGE("%s: Invalid max size value %d", __func__, max_size);
+        return WIFI_ERROR_INVALID_ARGS;
+    }
+
+    vCommand = new WifihalGeneric(handle, get_requestid(), OUI_QCA,
+                        QCA_NL80211_VENDOR_SUBCMD_GET_RADIO_COMBINATION_MATRIX);
+    if (vCommand == NULL) {
+        ALOGE("%s: Error vCommand NULL", __FUNCTION__);
+        return WIFI_ERROR_OUT_OF_MEMORY;
+    }
+
+    ret = vCommand->create();
+    if (ret != WIFI_SUCCESS)
+        goto cleanup;
+
+    nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
+    if (!nlData){
+        ret = WIFI_ERROR_UNKNOWN;
+        goto cleanup;
+    }
+
+    vCommand->attr_end(nlData);
+
+    /* Populate the input received from caller/framework. */
+    vCommand->set_radio_matrix_max_size(max_size);
+    vCommand->set_radio_matrix_size(size);
+    vCommand->set_radio_matrix(radio_combination_matrix);
+
+    ret = vCommand->requestResponse();
+    if (ret != WIFI_SUCCESS) {
+        ALOGE("%s: requestResponse() error: %d", __FUNCTION__, ret);
+        goto cleanup;
+    }
+
+cleanup:
+    delete vCommand;
+    return ret;
+}
 
 wifi_error wifi_set_nodfs_flag(wifi_interface_handle handle, u32 nodfs)
 {
@@ -3344,6 +3438,330 @@
     }
 }
 
+#ifndef TARGET_SUPPORTS_WEARABLES
+char *get_iface_mask_str(u32 mask, char *buf, size_t buflen) {
+    char * pos, *end;
+    int res;
+
+    pos = buf;
+    end = buf + buflen;
+
+    res = snprintf(pos, end - pos, "[ ");
+    if (res < 0 || (res >= end - pos))
+        goto error;
+
+    pos += res;
+    res = snprintf(pos, end - pos, "%s", (mask & BIT(WIFI_INTERFACE_TYPE_STA)) ? "STA " : "");
+    if (res < 0 || (res >= end - pos))
+        goto error;
+
+    pos += res;
+    res = snprintf(pos, end - pos, "%s", (mask & BIT(WIFI_INTERFACE_TYPE_AP)) ? "AP " : "");
+    if (res < 0 || (res >= end - pos))
+        goto error;
+
+    pos += res;
+    res = snprintf(pos, end - pos, "%s", (mask & BIT(WIFI_INTERFACE_TYPE_P2P)) ? "P2P " : "");
+    if (res < 0 || (res >= end - pos))
+        goto error;
+
+    pos += res;
+    res = snprintf(pos, end - pos, "%s", (mask & BIT(WIFI_INTERFACE_TYPE_NAN)) ? "NAN " : "");
+    if (res < 0 || (res >= end - pos))
+        goto error;
+
+    pos += res;
+    res = snprintf(pos, end - pos, "%s", (mask & BIT(WIFI_INTERFACE_TYPE_AP_BRIDGED)) ? "AP_BRIDGED " : "");
+    if (res < 0 || (res >= end - pos))
+        goto error;
+
+    pos += res;
+    res = snprintf(pos, end - pos, "]");
+    if (res < 0 || (res >= end - pos))
+        goto error;
+
+    return buf;
+
+error:
+    ALOGE("snprintf() error res=%d, write length=%d", res, static_cast<int>(end - pos));
+    return NULL;
+}
+
+static void dump_wifi_iface_combination(wifi_iface_concurrency_matrix *matrix) {
+
+    u32 i, j;
+    wifi_iface_combination *comb;
+    wifi_iface_limit *limit;
+    char buf[30];
+
+    if (matrix == NULL) return;
+
+    ALOGV("--- DUMP Interface Combination ---");
+    ALOGV("num_iface_combinations: %u", matrix->num_iface_combinations);
+    for (i = 0; i < matrix->num_iface_combinations; i++) {
+        comb = &matrix->iface_combinations[i];
+        ALOGV("comb%d : max_ifaces: %u iface_limit: %u", i+1, comb->max_ifaces, comb->num_iface_limits);
+        for (j = 0; j < comb->num_iface_limits; j++) {
+            limit = &comb->iface_limits[j];
+            ALOGV("    max=%u, iface:%s", limit->max_limit, get_iface_mask_str(limit->iface_mask, buf, 30) ? buf : "");
+        }
+    }
+}
+
+
+class GetSupportedIfaceCombinationCmd : public WifiCommand
+{
+private:
+    hal_info *halinfo;
+
+public:
+    GetSupportedIfaceCombinationCmd(wifi_handle handle,
+                                    hal_info *info)
+                                    : WifiCommand(handle, 0),
+                                    halinfo(info) {}
+
+    virtual wifi_error create() {
+        int nl80211_id = genl_ctrl_resolve(mInfo->cmd_sock, "nl80211");
+        wifi_error ret = mMsg.create(nl80211_id, NL80211_CMD_GET_WIPHY, NLM_F_DUMP, 0);
+        mMsg.put_flag(NL80211_ATTR_SPLIT_WIPHY_DUMP);
+
+        return ret;
+    }
+
+    virtual wifi_error requestResponse() {
+        return WifiCommand::requestResponse(mMsg);
+    }
+    virtual wifi_error set_iface_id(const char* name) {
+        unsigned ifindex = if_nametoindex(name);
+        return mMsg.set_iface_id(ifindex);
+    }
+
+    /**
+     * Derive the bridge combinations by adding the bridge interface when combination
+     * has support for more than one AP interface
+     */
+    void derive_bridge_ap_support(wifi_iface_concurrency_matrix* matrix)
+    {
+        if (matrix == NULL)
+            return;
+
+        int i, j, k, num_bridge, rem_ap;
+        int num_bridge_combination = 0;
+        wifi_iface_combination *comb;
+        wifi_iface_limit *limit;
+
+        // Add Support for bridge interface
+        for (i = 0; i < matrix->num_iface_combinations; i++) {
+            comb = &matrix->iface_combinations[i];
+
+            /* find out if this combination has support for AP > 1 */
+            bool bridge_ap_supported = false;
+            for (j = 0; j < comb->num_iface_limits; j++) {
+                limit = &comb->iface_limits[j];
+                if ((limit->iface_mask & BIT(WIFI_INTERFACE_TYPE_AP))
+                        && (limit->max_limit > 1)) {
+                    bridge_ap_supported = true;
+                    break;
+                }
+            }
+            if (bridge_ap_supported) {
+                /* Bridge combination is a new combination along with other type of ifaces */
+                num_bridge_combination++;
+                k = matrix->num_iface_combinations + num_bridge_combination;
+                if (k == MAX_IFACE_COMBINATIONS) {
+                    ALOGE("max iface combination %u limit reached. Stop processing further", k);
+                    break;
+                }
+
+                wifi_iface_combination *comb_br = &matrix->iface_combinations[k-1];
+                num_bridge = 0;
+
+                for (j = 0, k = 0; (j < comb->num_iface_limits) && (k < MAX_IFACE_LIMITS); j++, k++) {
+                    limit = &comb->iface_limits[j];
+                    /* count the possible number of bridge interface based on max_limit/2
+                     * Also maintain remaining interfaces as AP */
+                    if ((limit->iface_mask & BIT(WIFI_INTERFACE_TYPE_AP))
+                           && (limit->max_limit > 1)) {
+                        num_bridge = limit->max_limit / 2;
+                        rem_ap = limit->max_limit % 2;
+                        if (rem_ap) {
+                            comb_br->iface_limits[k].max_limit = rem_ap;
+                            comb_br->iface_limits[k].iface_mask = BIT(WIFI_INTERFACE_TYPE_AP);
+                            k++;
+                        }
+                        if (k < MAX_IFACE_LIMITS) {
+                            comb_br->iface_limits[k].iface_mask = BIT(WIFI_INTERFACE_TYPE_AP_BRIDGED);
+                            comb_br->iface_limits[k].max_limit = num_bridge;
+                        } else {
+                            ALOGE("Can't add more than %d iface limits."
+                                  " Skip adding bridged mode", MAX_IFACE_LIMITS);
+                            break;
+                        }
+                    } else {
+                        // Retain other ifaces in this combination as is
+                        comb_br->iface_limits[k].iface_mask = limit->iface_mask;
+                        comb_br->iface_limits[k].max_limit = limit->max_limit;
+                    }
+                }
+                // Reduce max ifaces which are converted to bridge iface.
+                comb_br->max_ifaces = comb->max_ifaces - num_bridge;
+                comb_br->num_iface_limits = k;
+            }
+        }
+        matrix->num_iface_combinations += num_bridge_combination;
+    }
+
+    virtual int handleResponse(WifiEvent& reply) {
+        struct nlattr **tb = reply.attributes();
+
+        if (tb[NL80211_ATTR_INTERFACE_COMBINATIONS]) {
+            if (halinfo == NULL) {
+                ALOGE("hal_info is NULL. Abort parsing");
+                return NL_SKIP;
+            }
+
+            wifi_iface_concurrency_matrix* matrix = &halinfo->iface_comb_matrix;
+            wifi_iface_combination *iface_combination;
+            wifi_iface_limit *iface_limits;
+            struct nlattr *nl_combi;
+            int rem, i = 0;
+
+            matrix->num_iface_combinations = 0;
+
+            nla_for_each_nested(nl_combi, tb[NL80211_ATTR_INTERFACE_COMBINATIONS], rem) {
+                struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB];
+                struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT];
+                struct nlattr *nl_limit, *nl_mode;
+                int err, rem_limit, rem_mode, j = 0;
+                static struct nla_policy
+                iface_combination_policy[NUM_NL80211_IFACE_COMB] = {
+                    [NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED },
+                    [NL80211_IFACE_COMB_MAXNUM] = { .type = NLA_U32 },
+                    [NL80211_IFACE_COMB_STA_AP_BI_MATCH] = { .type = NLA_FLAG },
+                    [NL80211_IFACE_COMB_NUM_CHANNELS] = { .type = NLA_U32 },
+                    [NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS] = { .type = NLA_U32 },
+                },
+                iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = {
+                    [NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED },
+                    [NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 },
+                };
+
+                err = nla_parse_nested(tb_comb, MAX_NL80211_IFACE_COMB,
+                                       nl_combi, iface_combination_policy);
+                if (err || !tb_comb[NL80211_IFACE_COMB_LIMITS] ||
+                    !tb_comb[NL80211_IFACE_COMB_MAXNUM] ||
+                    !tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]) {
+                        ALOGE("Broken iface combination detected. skip it");
+                        continue; /* broken combination */
+                }
+
+                iface_combination = &matrix->iface_combinations[i];
+                iface_combination->max_ifaces = nla_get_u32(tb_comb[NL80211_IFACE_COMB_MAXNUM]);
+                iface_limits = iface_combination->iface_limits;
+                nla_for_each_nested(nl_limit, tb_comb[NL80211_IFACE_COMB_LIMITS],
+                                    rem_limit) {
+                    if (j == MAX_IFACE_LIMITS) {
+                        ALOGE("Can't parse more than %d iface limits", MAX_IFACE_LIMITS);
+                        continue;
+                    }
+
+                    err = nla_parse_nested(tb_limit, MAX_NL80211_IFACE_LIMIT,
+                                           nl_limit, iface_limit_policy);
+                    if (err || !tb_limit[NL80211_IFACE_LIMIT_TYPES]) {
+                        ALOGE("Broken iface limt types detected. skip it");
+                        continue; /* broken combination */
+                    }
+
+                    iface_limits[j].iface_mask = 0;
+                    iface_limits[j].max_limit = nla_get_u32(tb_limit[NL80211_IFACE_LIMIT_MAX]);
+                    bool is_p2p_go = false, is_p2p_client = false;
+                    nla_for_each_nested(nl_mode,
+                                        tb_limit[NL80211_IFACE_LIMIT_TYPES],
+                                        rem_mode) {
+                        int ift = nla_type(nl_mode);
+                        switch (ift) {
+                        case NL80211_IFTYPE_STATION:
+                            iface_limits[j].iface_mask |= BIT(WIFI_INTERFACE_TYPE_STA);
+                            break;
+                        case NL80211_IFTYPE_P2P_GO:
+                            is_p2p_go = true;
+                            iface_limits[j].iface_mask |= BIT(WIFI_INTERFACE_TYPE_P2P);
+                            break;
+                        case NL80211_IFTYPE_P2P_CLIENT:
+                            is_p2p_client = true;
+                            iface_limits[j].iface_mask |= BIT(WIFI_INTERFACE_TYPE_P2P);
+                            break;
+                        case NL80211_IFTYPE_AP:
+                            iface_limits[j].iface_mask |= BIT(WIFI_INTERFACE_TYPE_AP);
+                            break;
+                        case NL80211_IFTYPE_NAN:
+                            iface_limits[j].iface_mask |= BIT(WIFI_INTERFACE_TYPE_NAN);
+                            break;
+                        case NL80211_IFTYPE_P2P_DEVICE:
+                            ALOGI("Ignore p2p_device iface type");
+                            iface_limits[j].max_limit--;
+                            break;
+                        default:
+                            ALOGI("Ignore unsupported iface type: %d", ift);
+                            break;
+                        }
+                    }
+                    // Remove P2P if both client/Go are not set.
+                    if ((iface_limits[j].iface_mask & BIT(WIFI_INTERFACE_TYPE_P2P))
+                            && (!is_p2p_client || !is_p2p_go))
+                        iface_limits[j].iface_mask &= ~BIT(WIFI_INTERFACE_TYPE_P2P);
+
+                    // Ignore Unsupported Ifaces (ex Monitor interface)
+                    if (iface_limits[j].iface_mask)
+                        j++;
+                }
+                iface_combination->num_iface_limits = j;
+                i++;
+                if (i == MAX_IFACE_COMBINATIONS) {
+                    ALOGE("%s max iface combination %u limit reached. Stop processing further", __func__, i);
+                    break;
+                }
+            }
+            matrix->num_iface_combinations = i;
+            derive_bridge_ap_support(matrix);
+        }
+        return NL_SKIP;
+    }
+};
+
+wifi_error wifi_get_supported_iface_combination(wifi_interface_handle iface_handle)
+{
+    wifi_error ret;
+    wifi_handle handle = getWifiHandle(iface_handle);
+    hal_info *info = (hal_info *) handle;
+    interface_info *iface_info = getIfaceInfo(iface_handle);
+
+    GetSupportedIfaceCombinationCmd cmd(handle, info);
+
+    ret = cmd.create();
+    if (ret != WIFI_SUCCESS) {
+        ALOGE("%s: create command failed", __func__);
+        return WIFI_ERROR_UNKNOWN;
+    }
+
+    ret = cmd.set_iface_id(iface_info->name);
+    if (ret != WIFI_SUCCESS) {
+        ALOGE("%s: set iface id failed", __func__);
+        return WIFI_ERROR_UNKNOWN;
+    }
+
+    ret = cmd.requestResponse();
+    if (ret != WIFI_SUCCESS) {
+        ALOGE("Failed to query supported iface combination, ret=%d", ret);
+        return WIFI_ERROR_UNKNOWN;
+    }
+
+    dump_wifi_iface_combination(&info->iface_comb_matrix);
+
+    return ret;
+}
+#endif /* TARGET_SUPPORTS_WEARABLES */
+
 wifi_error wifi_get_radar_history(wifi_interface_handle handle,
        radar_history_result *resultBuf, int resultBufSize, int *numResults)
 {
@@ -3514,3 +3932,40 @@
     delete vCommand;
     return ret;
 }
+
+#ifndef TARGET_SUPPORTS_WEARABLES
+wifi_error wifi_get_supported_iface_concurrency_matrix(
+        wifi_handle handle, wifi_iface_concurrency_matrix *iface_comb_matrix)
+{
+    wifi_error ret = WIFI_ERROR_UNKNOWN;
+    hal_info *info = (hal_info *) handle;
+    wifi_iface_combination *comb;
+    wifi_iface_limit *limit;
+
+    if (info == NULL) {
+        ALOGE("Wifi not initialized yet.");
+        return ret;
+    }
+
+    if (iface_comb_matrix == NULL) {
+        ALOGE("Interface combination matrix not initialized.");
+        return ret;
+    }
+
+    ALOGI("Get supported concurrency capabilities");
+    // Copy over from info to input param.
+    iface_comb_matrix->num_iface_combinations =
+            info->iface_comb_matrix.num_iface_combinations;
+    for (int i = 0; i < iface_comb_matrix->num_iface_combinations; i++) {
+        comb = &iface_comb_matrix->iface_combinations[i];
+        comb->max_ifaces = info->iface_comb_matrix.iface_combinations[i].max_ifaces;
+        comb->num_iface_limits = info->iface_comb_matrix.iface_combinations[i].num_iface_limits;
+        for (int j = 0; j < comb->num_iface_limits; j++) {
+            limit = &comb->iface_limits[j];
+            limit->max_limit = info->iface_comb_matrix.iface_combinations[i].iface_limits[j].max_limit;
+            limit->iface_mask = info->iface_comb_matrix.iface_combinations[i].iface_limits[j].iface_mask;
+        }
+    }
+    return WIFI_SUCCESS;
+}
+#endif /* TARGET_SUPPORTS_WEARABLES */
diff --git a/qcwcn/wifi_hal/wificonfig.cpp b/qcwcn/wifi_hal/wificonfig.cpp
index 288a2cf..f5cbddd 100644
--- a/qcwcn/wifi_hal/wificonfig.cpp
+++ b/qcwcn/wifi_hal/wificonfig.cpp
@@ -24,11 +24,41 @@
  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
+ *
  * Changes from Qualcomm Innovation Center are provided under the following license:
-
+ *
  * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  * SPDX-License-Identifier: BSD-3-Clause-Clear
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted (subject to the limitations in the
+ * disclaimer below) provided that the following conditions are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *
+ *   * Neither the name of Qualcomm Innovation Center, Inc. nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
+ * GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
+ * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include "sync.h"
@@ -48,9 +78,12 @@
 #include "wificonfigcommand.h"
 #include "ifaceeventhandler.h"
 
+
 #define NUM_OF_SAR_LIMITS_SPECS 2
 #define NUM_OF_SPEC_CHAINS 2
 
+
+
 /* Implementation of the API functions exposed in wifi_config.h */
 wifi_error wifi_extended_dtim_config_set(wifi_request_id id,
                                          wifi_interface_handle iface,
@@ -561,6 +594,7 @@
     return ret;
 }
 
+
 wifi_error wifi_select_SARv01_tx_power_scenario(wifi_interface_handle handle,
                                          wifi_power_scenario scenario)
 {
@@ -750,7 +784,7 @@
 
 
     nlSpecList = wifiConfigCommand->attr_start(QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC);
-    if (!nlSpecList)
+    if(!nlSpecList)
     {
         ALOGE("Cannot create spec list");
         ret = WIFI_ERROR_UNKNOWN;
@@ -760,11 +794,11 @@
 
     for (int i = 0; i < NUM_OF_SPEC_CHAINS; i++) {
         nlSpec = wifiConfigCommand->attr_start(0);
-        if (!nlSpec) {
+        if(!nlSpec) {
             ret = WIFI_ERROR_UNKNOWN;
             goto cleanup;
         }
-        if (wifiConfigCommand->put_u32(
+        if(wifiConfigCommand->put_u32(
             QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN,
             i))
         {
@@ -773,7 +807,7 @@
             goto cleanup;
         }
 
-        if (wifiConfigCommand->put_u32(
+        if(wifiConfigCommand->put_u32(
             QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT_INDEX,
             power_lim_idx))
         {
@@ -820,8 +854,8 @@
               info->sar_version == QCA_WLAN_VENDOR_SAR_VERSION_3)
         return wifi_select_SARv02_tx_power_scenario(handle,scenario);
     else {
-        ALOGE("wifi_select_tx_power_scenario %u invalid or not supported", (u32)info->sar_version);
-        return WIFI_ERROR_UNKNOWN;
+      ALOGE("wifi_select_tx_power_scenario %u invalid or not supported", (u32)info->sar_version);
+      return WIFI_ERROR_UNKNOWN;
     }
 }
 
@@ -1702,7 +1736,7 @@
     }
 
     if (wifiConfigCommand->put_u8(QCA_WLAN_VENDOR_ATTR_CONFIG_WFC_STATE,
-        (mode==WIFI_VOIP_MODE_ON) ? 1 : 0)) {
+        (mode==WIFI_VOIP_MODE_VOICE) ? 1 : 0)) {
         ALOGE("%s: failed to put vendor data", __FUNCTION__);
         ret = WIFI_ERROR_UNKNOWN;
         goto cleanup;
diff --git a/qcwcn/wifi_hal/wifihal_vendor.cpp b/qcwcn/wifi_hal/wifihal_vendor.cpp
index 4837e63..e05e407 100644
--- a/qcwcn/wifi_hal/wifihal_vendor.cpp
+++ b/qcwcn/wifi_hal/wifihal_vendor.cpp
@@ -28,7 +28,7 @@
 
  * Changes from Qualcomm Innovation Center are provided under the following license:
 
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  * SPDX-License-Identifier: BSD-3-Clause-Clear
  */
 
@@ -74,6 +74,7 @@
     memset(&mStats, 0,sizeof(nud_stats));
     mpktInfo = NULL;
     mnumStats = 0;
+    memset(&mHandler, 0, sizeof(pkt_stats_result_handler));
 }
 
 NUDStatsCommand::~NUDStatsCommand()
diff --git a/qcwcn/wifi_hal/wifilogger.cpp b/qcwcn/wifi_hal/wifilogger.cpp
index 384633a..a7cb0ab 100644
--- a/qcwcn/wifi_hal/wifilogger.cpp
+++ b/qcwcn/wifi_hal/wifilogger.cpp
@@ -27,7 +27,7 @@
  *
  * Changes from Qualcomm Innovation Center are provided under the following license:
  *
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted (subject to the limitations in the
@@ -840,6 +840,7 @@
     mWaitforRsp = false;
     mMoreData = false;
     mSupportedSet = NULL;
+    mGetWakeStats = NULL;
 }
 
 WifiLoggerCommand::~WifiLoggerCommand()
diff --git a/qcwcn/wifi_hal/wifilogger_diag.cpp b/qcwcn/wifi_hal/wifilogger_diag.cpp
index f026a78..96202c4 100644
--- a/qcwcn/wifi_hal/wifilogger_diag.cpp
+++ b/qcwcn/wifi_hal/wifilogger_diag.cpp
@@ -1317,7 +1317,7 @@
     push_out_all_ring_buffers(info);
 
     if (lfd_event->is_fatal == WLAN_LOG_TYPE_FATAL) {
-        ALOGE("Received fatal event, sending alert");
+        ALOGE("Received log complete event, sending alert");
         send_alert(info, lfd_event->reason_code);
     }
 }
@@ -2240,6 +2240,13 @@
                                    info->pkt_fate_stats->n_tx_stats_collected];
 
     pkt_fate_stats->fate = (wifi_tx_packet_fate)log->status;
+
+    if (pkt_fate_stats->fate > TX_PKT_FATE_DRV_DROP_OTHER) {
+        ALOGE("Invalid Tx pkt fate status %d, set to drv_drop_other",
+              pkt_fate_stats->fate);
+        pkt_fate_stats->fate = TX_PKT_FATE_DRV_DROP_OTHER;
+    }
+
     if (log->type == TX_MGMT_PKT)
         pkt_fate_stats->frame_inf.payload_type = FRAME_TYPE_80211_MGMT;
     else
@@ -2774,7 +2781,7 @@
         if (!info->cldctx) {
             if ((wnl->nlh.nlmsg_len <= sizeof(tAniNlHdr)) ||
                 (wnl->nlh.nlmsg_len < (sizeof(tAniNlHdr) + ntohs(wnl->clh.wmsg.length)))) {
-                ALOGE("Received UMAC message with insufficent length: %d",
+                ALOGV("Received UMAC message with insufficent length: %d",
                       wnl->nlh.nlmsg_len);
                 return WIFI_ERROR_UNKNOWN;
             }
diff --git a/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211.c b/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211.c
index b4f7606..397f0c7 100644
--- a/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211.c
+++ b/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211.c
@@ -164,6 +164,9 @@
 #define AP_AC_VALUE_STR_LEN             strlen(AP_AC_VALUE_STR)
 #define MAC_ADDR_STR_LEN             	strlen(MAC_ADDRESS_STR)
 
+// Module defined MAC ADDR macros to print full mac address.
+// This is in order to remove dependency from MAC2STR definitions
+// in common.h from wpa_supplicant.
 #define MAC_ADDR_STR "%02x:%02x:%02x:%02x:%02x:%02x"
 #define MAC_ADDR_ARRAY(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
 
@@ -1225,7 +1228,6 @@
 	}
 
 	ext_id = *ie++;
-	ie_len--;
 
 	switch (ext_id) {
 	case WLAN_EID_EXT_HE_CAPABILITIES:
@@ -2675,7 +2677,6 @@
 				  TWT_SET_PARAM_STR_LEN) == 0) {
 		return QCA_WLAN_TWT_SET_PARAM;
 	} else {
-		wpa_printf(MSG_DEBUG, "Not a TWT command");
 		return TWT_CMD_NOT_EXIST;
 	}
 }
@@ -3045,7 +3046,6 @@
 					get_u32_from_string(cmd, &ret);
 		if (ret < 0)
 			return ret;
-		cmd = move_to_next_str(cmd);
 	}
 
 	print_setup_cmd_values(twt_setup_params);
@@ -5673,7 +5673,7 @@
 		return NL_SKIP;
 	}
 	ret = os_snprintf(info->reply_buf, info->reply_buf_len,
-			  "tsf_value:%llu host_time:%llu", tsf_value, host_time);
+			  "tsf_value:%lul host_time:%lul", tsf_value, host_time);
 	if (os_snprintf_error(info->reply_buf_len, ret)) {
 		wpa_printf(MSG_ERROR, "%s:Fail to print buffer", __func__);
 		return -ENOMEM;
@@ -6626,7 +6626,7 @@
 		ret = linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, macaddr);
 		if (!ret)
 			ret = os_snprintf(buf, buf_len,
-					  "Macaddr = " MACSTR "\n", MAC2STR(macaddr));
+					  "Macaddr = " MAC_ADDR_STR "\n", MAC_ADDR_ARRAY(macaddr));
 	} else if (os_strncasecmp(cmd, "SET_CONGESTION_REPORT ", 22) == 0) {
 		return wpa_driver_cmd_set_congestion_report(priv, cmd + 22);
 	} else if (os_strncasecmp(cmd, "SET_TXPOWER ", 12) == 0) {
diff --git a/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211_extn.c b/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211_extn.c
index 6b611a1..8799326 100644
--- a/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211_extn.c
+++ b/qcwcn/wpa_supplicant_8_lib/driver_cmd_nl80211_extn.c
@@ -77,9 +77,11 @@
 void wpa_msg_handler(struct wpa_driver_nl80211_data *drv,
 		     char *msg, u32 subcmd)
 {
-	if ((subcmd == QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT) ||
-	    (subcmd == QCA_NL80211_VENDOR_SUBCMD_OEM_DATA) ||
-	    (subcmd == QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET)) {
+	if (subcmd == QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT ||
+	    subcmd == QCA_NL80211_VENDOR_SUBCMD_OEM_DATA ||
+	    subcmd == QCA_NL80211_VENDOR_SUBCMD_SR ||
+	    subcmd == QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET ||
+	    subcmd == QCA_NL80211_VENDOR_SUBCMD_CONNECTED_CHANNEL_STATS) {
 		wpa_msg(drv->ctx, MSG_INFO, "%s", msg);
 	}
 }
diff --git a/wcnss-service/Android.mk b/wcnss-service/Android.mk
index fd33ee1..9eab85b 100644
--- a/wcnss-service/Android.mk
+++ b/wcnss-service/Android.mk
@@ -9,7 +9,15 @@
 LOCAL_SRC_FILES := wcnss_service.c
 LOCAL_SHARED_LIBRARIES := libc libcutils libutils liblog
 ifeq ($(strip $(TARGET_USES_QCOM_WCNSS_QMI)),true)
-LOCAL_CFLAGS += -DWCNSS_QMI
+ifeq ($(TARGET_USES_WCNSS_MAC_ADDR_REV),true)
+LOCAL_CFLAGS += -DWCNSS_QMI_MAC_ADDR_REV
+endif
+ifeq ($(TARGET_PROVIDES_WCNSS_QMI),true)
+LOCAL_CFLAGS += -DWCNSS_QMI_OSS
+LOCAL_SHARED_LIBRARIES += libdl
+else
+LOCAL_CFLAGS += -DWCNSS_QMI -DMDM_DETECT
+LOCAL_HEADER_LIBRARIES += libmdmdetect_headers
 ifeq ($(filter 10% Q% q%,$(TARGET_PLATFORM_VERSION)),)
 #For Android R and above, assuming not compiling on Q and lower
 LOCAL_HEADER_LIBRARIES += libqmi_common_headers
@@ -21,6 +29,7 @@
 LOCAL_HEADER_LIBRARIES += libmdmdetect_headers
 LOCAL_SHARED_LIBRARIES += libmdmdetect
 LOCAL_HEADER_LIBRARIES += libril-qc-qmi-services-headers
+endif #TARGET_PROVIDES_WCNSS_QMI
 endif #TARGET_USES_QCOM_WCNSS_QMI
 LOCAL_MODULE_TAGS := optional
 LOCAL_CFLAGS += -Wall -Werror
diff --git a/wcnss-service/wcnss_service.c b/wcnss-service/wcnss_service.c
index c817be1..70f9970 100644
--- a/wcnss-service/wcnss_service.c
+++ b/wcnss-service/wcnss_service.c
@@ -37,13 +37,19 @@
 #include <utime.h>
 #include <sys/stat.h>
 #include <sys/sendfile.h>
+#include <unistd.h>
 #define LOG_TAG "wcnss_service"
 #include <cutils/log.h>
 #include <cutils/properties.h>
 #ifdef WCNSS_QMI
 #include "wcnss_qmi_client.h"
+#ifdef MDM_DETECT
 #include "mdm_detect.h"
 #endif
+#endif
+#ifdef WCNSS_QMI_OSS
+#include <dlfcn.h>
+#endif
 
 #define SUCCESS 0
 #define FAILED -1
@@ -72,7 +78,6 @@
 #define WLAN_INI_FILE_SOURCE "/vendor/etc/wifi/WCNSS_qcom_cfg.ini"
 #define WCNSS_HAS_CAL_DATA\
 		"/sys/module/wcnsscore/parameters/has_calibrated_data"
-#define WLAN_DRIVER_ATH_DEFAULT_VAL "0"
 
 #define ASCII_A		65
 #define ASCII_a		97
@@ -80,7 +85,7 @@
 #define HEXA_A		10
 #define HEX_BASE		16
 
-#ifdef WCNSS_QMI
+#if defined (WCNSS_QMI) || defined(WCNSS_QMI_OSS)
 #define WLAN_ADDR_SIZE   6
 unsigned char wlan_nv_mac_addr[WLAN_ADDR_SIZE];
 #define MAC_ADDR_ARRAY(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
@@ -389,17 +394,15 @@
 }
 
 
-#ifdef WCNSS_QMI
+#if defined(WCNSS_QMI) || defined(WCNSS_QMI_OSS)
 void setup_wcnss_parameters(int *cal, int nv_mac_addr)
 #else
 void setup_wcnss_parameters(int *cal)
 #endif
 {
 	char msg[WCNSS_MAX_CMD_LEN];
-	char serial[PROPERTY_VALUE_MAX];
 	int fd, rc, pos = 0;
 	struct stat st;
-	unsigned int serial_num = 0;
 
 	fd = open(WCNSS_CTRL, O_WRONLY);
 	if (fd < 0) {
@@ -407,26 +410,7 @@
 		return;
 	}
 
-	rc = property_get("ro.serialno", serial, "");
-	if (rc) {
-		serial_num = convert_string_to_hex(serial);
-		ALOGE("Serial Number is  %x", serial_num);
-
-		msg[pos++] = WCNSS_USR_SERIAL_NUM >> BYTE_1;
-		msg[pos++] = WCNSS_USR_SERIAL_NUM >> BYTE_0;
-		msg[pos++] = serial_num >> BYTE_3;
-		msg[pos++] = serial_num >> BYTE_2;
-		msg[pos++] = serial_num >> BYTE_1;
-		msg[pos++] = serial_num >> BYTE_0;
-
-		if (write(fd, msg, pos) < 0) {
-			ALOGE("Failed to write to %s : %s", WCNSS_CTRL,
-					strerror(errno));
-			goto fail;
-		}
-	}
-
-#ifdef WCNSS_QMI
+#if defined(WCNSS_QMI) || defined (WCNSS_QMI_OSS)
 	if (SUCCESS == nv_mac_addr)
 	{
 		pos = 0;
@@ -493,12 +477,7 @@
 	return;
 }
 
-void setup_wlan_driver_ath_prop()
-{
-	property_set("vendor.wlan.driver.ath", WLAN_DRIVER_ATH_DEFAULT_VAL);
-}
-
-#ifdef WCNSS_QMI
+#ifdef MDM_DETECT
 int check_modem_compatability(struct dev_info *mdm_detect_info)
 {
 	char args[MODEM_BASEBAND_PROPERTY_SIZE] = {0};
@@ -720,20 +699,99 @@
 
 }
 
+#ifdef WCNSS_QMI_OSS
+static void *wcnss_qmi_handle = NULL;
+static int (*wcnss_init_qmi)(void) = NULL;
+static int (*wcnss_qmi_get_wlan_address)(unsigned char *) = NULL;
+static void (*wcnss_qmi_deinit)(void) = NULL;
+
+static int setup_wcnss_qmi(void)
+{
+	const char *error = NULL;
+
+	/* initialize the DMS client and request the wlan mac address */
+	wcnss_qmi_handle = dlopen("libwcnss_qmi.so", RTLD_NOW);
+	if (!wcnss_qmi_handle) {
+		ALOGE("Failed to open libwcnss_qmi.so: %s", dlerror());
+		goto dlopen_err;
+	}
+
+	dlerror();
+
+	wcnss_init_qmi = dlsym(wcnss_qmi_handle, "wcnss_init_qmi");
+	if ((error = dlerror()) != NULL) {
+		ALOGE("Failed to resolve function: %s: %s",
+				"wcnss_init_qmi", error);
+		goto dlsym_err;
+	}
+
+	dlerror();
+
+	wcnss_qmi_get_wlan_address = dlsym(wcnss_qmi_handle,
+			"wcnss_qmi_get_wlan_address");
+	if ((error = dlerror()) != NULL) {
+		ALOGE("Failed to resolve function: %s: %s",
+				"wcnss_qmi_get_wlan_address", error);
+		goto dlsym_err;
+	}
+
+	dlerror();
+
+	wcnss_qmi_deinit = dlsym(wcnss_qmi_handle, "wcnss_qmi_deinit");
+	if ((error = dlerror()) != NULL) {
+		ALOGE("Failed to resolve function: %s: %s",
+				"wcnss_qmi_deinit", error);
+		goto dlsym_err;
+	}
+
+	return SUCCESS;
+
+dlsym_err:
+	dlclose(wcnss_qmi_handle);
+dlopen_err:
+	return FAILED;
+}
+#endif
+
 int main(int argc, char *argv[])
 {
 	UNUSED(argc), UNUSED(argv);
 	int rc;
 	int fd_dev, ret_cal;
-#ifdef WCNSS_QMI
+#if defined(WCNSS_QMI) || defined(WCNSS_QMI_OSS)
 	int nv_mac_addr = FAILED;
+#ifdef MDM_DETECT
 	struct dev_info mdm_detect_info;
 	int nom = 0;
 #endif
+#endif
 
 	setup_wlan_config_file();
 
+#ifdef WCNSS_QMI_OSS
+	/* dlopen WCNSS QMI lib */
+
+	rc = setup_wcnss_qmi();
+	if (rc == SUCCESS) {
+		if (SUCCESS == (*wcnss_init_qmi)()) {
+			rc = (*wcnss_qmi_get_wlan_address)(wlan_nv_mac_addr);
+			if (rc == SUCCESS) {
+				nv_mac_addr = SUCCESS;
+				ALOGE("WLAN MAC Addr:" MAC_ADDRESS_STR,
+						MAC_ADDR_ARRAY(wlan_nv_mac_addr));
+			} else
+				ALOGE("Failed to Get MAC addr from modem");
+
+			(*wcnss_qmi_deinit)();
+		}
+		else
+			ALOGE("Failed to Initialize wcnss QMI Interface");
+	} else {
+		ALOGE("Failed to Initialize wcnss QMI interface library");
+	}
+#endif
 #ifdef WCNSS_QMI
+#ifdef MDM_DETECT
 	/* Call ESOC API to get the number of modems.
 	   If the number of modems is not zero, only then proceed
 	   with the eap_proxy intialization.*/
@@ -755,6 +813,7 @@
 		ALOGE("wcnss_service: Target does not have external modem");
 		goto nomodem;
 	}
+#endif
 
 	/* initialize the DMS client and request the wlan mac address */
 
@@ -779,7 +838,7 @@
 
 	dynamic_nv_replace();
 
-#ifdef WCNSS_QMI
+#if defined(WCNSS_QMI) || defined(WCNSS_QMI_OSS)
 	setup_wcnss_parameters(&ret_cal, nv_mac_addr);
 #else
 	setup_wcnss_parameters(&ret_cal);
@@ -800,8 +859,6 @@
 			ALOGE("Cal data is successfully written to WCNSS");
 	}
 
-	setup_wlan_driver_ath_prop();
-
 	rc = wcnss_read_and_store_cal_data(fd_dev);
 	if (rc != SUCCESS)
 		ALOGE("Failed to read and save cal data %d", rc);
@@ -811,5 +868,9 @@
 
 	close(fd_dev);
 
+#ifdef WCNSS_QMI_OSS
+	dlclose(wcnss_qmi_handle);
+#endif
+
 	return rc;
 }