Snap for 8564071 from 19cb6f27c73ab4f738d0836fa39f1edebffb9559 to mainline-permission-release

Change-Id: I7ac9f121fd1f49a0a314c272729530d579084813
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..d97975c
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,3 @@
+third_party {
+  license_type: NOTICE
+}
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..d8c95cc
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,3 @@
+arabawy@google.com
+etancohen@google.com
+kumachang@google.com
diff --git a/bcmdhd/dhdutil/Android.mk b/bcmdhd/dhdutil/Android.mk
index 2385abd..c7e7fdc 100644
--- a/bcmdhd/dhdutil/Android.mk
+++ b/bcmdhd/dhdutil/Android.mk
@@ -26,6 +26,9 @@
 	miniopt.c
 
 LOCAL_MODULE := dhdutil
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-BSD SPDX-license-identifier-ISC
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/NOTICE
 LOCAL_CFLAGS := -DSDTEST -DTARGETENV_android -Dlinux -DLINUX
 ifeq ($(TARGET_ARCH),arm)
 LOCAL_CFLAGS += -mabi=aapcs-linux
diff --git a/bcmdhd/dhdutil/bcmutils.c b/bcmdhd/dhdutil/bcmutils.c
index 0fdbe73..655d267 100644
--- a/bcmdhd/dhdutil/bcmutils.c
+++ b/bcmdhd/dhdutil/bcmutils.c
@@ -1776,7 +1776,7 @@
 	"AES_CCM",
 	"AES_OCB_MSDU",
 	"AES_OCB_MPDU",
-	"NALG"
+	"NALG",
 	"UNDEF",
 	"UNDEF",
 	"UNDEF",
diff --git a/bcmdhd/wifi_hal/Android.mk b/bcmdhd/wifi_hal/Android.mk
index 5763789..471c312 100755
--- a/bcmdhd/wifi_hal/Android.mk
+++ b/bcmdhd/wifi_hal/Android.mk
@@ -41,6 +41,14 @@
 
 LOCAL_HEADER_LIBRARIES := libutils_headers liblog_headers
 
+ifneq ($(wildcard vendor/google/libraries/GoogleWifiConfigLib),)
+LOCAL_SHARED_LIBRARIES += \
+	google_wifi_firmware_config_version_c_wrapper
+LOCAL_CFLAGS += -DGOOGLE_WIFI_FW_CONFIG_VERSION_C_WRAPPER
+#only for pixel feature
+LOCAL_CFLAGS += -DRING_DUMP
+endif
+
 LOCAL_SRC_FILES := \
 	wifi_hal.cpp \
 	rtt.cpp \
@@ -50,10 +58,12 @@
 	nan.cpp \
 	link_layer_stats.cpp \
 	wifi_logger.cpp \
-	wifi_offload.cpp
+	wifi_offload.cpp \
+	twt.cpp
 
 LOCAL_MODULE := libwifi-hal-bcm
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
 LOCAL_PROPRIETARY_MODULE := true
 
 include $(BUILD_STATIC_LIBRARY)
-
diff --git a/bcmdhd/wifi_hal/brcm_version.h b/bcmdhd/wifi_hal/brcm_version.h
index 14efbee..184d5d5 100755
--- a/bcmdhd/wifi_hal/brcm_version.h
+++ b/bcmdhd/wifi_hal/brcm_version.h
@@ -1 +1 @@
-#define HAL_VERSION "Android-10-FRC2-SDK_29 59.0 (r854927) 2019-12-06 23:33:52 +0530 (Fri, 06 Dec 2019)"
+#define HAL_VERSION "BCMDHD vendor HAL"
diff --git a/bcmdhd/wifi_hal/common.cpp b/bcmdhd/wifi_hal/common.cpp
index c164ba4..5a9d5ab 100755
--- a/bcmdhd/wifi_hal/common.cpp
+++ b/bcmdhd/wifi_hal/common.cpp
@@ -105,14 +105,34 @@
     wifi_error result = WIFI_ERROR_OUT_OF_MEMORY;
 
     if (info->num_event_cb < info->alloc_event_cb) {
-        info->event_cb[info->num_event_cb].nl_cmd  = NL80211_CMD_VENDOR;
-        info->event_cb[info->num_event_cb].vendor_id  = id;
-        info->event_cb[info->num_event_cb].vendor_subcmd  = subcmd;
-        info->event_cb[info->num_event_cb].cb_func = func;
-        info->event_cb[info->num_event_cb].cb_arg  = arg;
-        ALOGV("Added event handler %p:%p for vendor 0x%0x and subcmd 0x%0x at %d",
-                arg, func, id, subcmd, info->num_event_cb);
-        info->num_event_cb++;
+        /* To avoid an unwanted duplication of the record, find first.
+         * Update it if the same record is already exist.
+         * KEY => [nl_cmd, vendor_id, vendor_subcmd]
+         */
+        int i = 0;
+        bool is_update = false;
+        for (i = 0; i < info->num_event_cb; i++) {
+            if ((info->event_cb[i].nl_cmd == NL80211_CMD_VENDOR) &&
+                    (info->event_cb[i].vendor_id == id) &&
+                    (info->event_cb[i].vendor_subcmd == subcmd)) {
+                is_update = true;
+                break;
+            }
+        }
+
+        if (is_update) {
+            info->event_cb[i].cb_func = func;
+            info->event_cb[i].cb_arg = arg;
+        } else {
+            info->event_cb[info->num_event_cb].nl_cmd  = NL80211_CMD_VENDOR;
+            info->event_cb[info->num_event_cb].vendor_id  = id;
+            info->event_cb[info->num_event_cb].vendor_subcmd  = subcmd;
+            info->event_cb[info->num_event_cb].cb_func = func;
+            info->event_cb[info->num_event_cb].cb_arg  = arg;
+            info->num_event_cb++;
+        }
+        ALOGI("%s ""event handler %p:%p for vendor 0x%0x and subcmd 0x%0x at %d",
+            is_update ? "Updated" : "Added", arg, func, id, subcmd, info->num_event_cb);
         result = WIFI_SUCCESS;
     }
 
@@ -146,18 +166,15 @@
     pthread_mutex_unlock(&info->cb_lock);
 }
 
-void wifi_unregister_vendor_handler(wifi_handle handle, uint32_t id, int subcmd)
+void wifi_unregister_vendor_handler_without_lock(wifi_handle handle, uint32_t id, int subcmd)
 {
     hal_info *info = (hal_info *)handle;
 
-    pthread_mutex_lock(&info->cb_lock);
-
     for (int i = 0; i < info->num_event_cb; i++) {
-
         if (info->event_cb[i].nl_cmd == NL80211_CMD_VENDOR
                 && info->event_cb[i].vendor_id == id
                 && info->event_cb[i].vendor_subcmd == subcmd) {
-            ALOGV("Successfully removed event handler %p:%p for vendor 0x%0x, subcmd 0x%0x from %d",
+            ALOGI("Successfully removed event handler %p:%p for vendor 0x%0x, subcmd 0x%0x from %d",
                     info->event_cb[i].cb_arg, info->event_cb[i].cb_func, id, subcmd, i);
             memmove(&info->event_cb[i], &info->event_cb[i+1],
                 (info->num_event_cb - i - 1) * sizeof(cb_info));
@@ -165,10 +182,16 @@
             break;
         }
     }
-
-    pthread_mutex_unlock(&info->cb_lock);
 }
 
+void wifi_unregister_vendor_handler(wifi_handle handle, uint32_t id, int subcmd)
+{
+    hal_info *info = (hal_info *)handle;
+
+    pthread_mutex_lock(&info->cb_lock);
+    wifi_unregister_vendor_handler_without_lock(handle, id, subcmd);
+    pthread_mutex_unlock(&info->cb_lock);
+}
 
 wifi_error wifi_register_cmd(wifi_handle handle, int id, WifiCommand *cmd)
 {
@@ -263,6 +286,19 @@
     return WIFI_ERROR_INVALID_ARGS;
 }
 
+wifi_error wifi_get_cancel_cmd(wifi_request_id id, wifi_interface_handle iface)
+{
+    wifi_handle handle = getWifiHandle(iface);
+    WifiCommand *cmd = wifi_get_cmd(handle, id);
+    ALOGV("Get Cancel WifiCommand = %p", cmd);
+    if (cmd) {
+        cmd->cancel();
+        cmd->releaseRef();
+        return WIFI_SUCCESS;
+    }
+
+    return WIFI_ERROR_INVALID_ARGS;
+}
 void set_hautil_mode(bool util_mode)
 {
     halutil_mode = util_mode;
diff --git a/bcmdhd/wifi_hal/common.h b/bcmdhd/wifi_hal/common.h
index 98801b2..ecc1abf 100755
--- a/bcmdhd/wifi_hal/common.h
+++ b/bcmdhd/wifi_hal/common.h
@@ -44,6 +44,7 @@
  */
 
 const uint32_t GOOGLE_OUI = 0x001A11;
+const uint32_t BRCM_OUI =  0x001018;
 /* TODO: define vendor OUI here */
 
 
@@ -53,7 +54,11 @@
 #define NMR2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5], (a)[6], (a)[7]
 #define NMRSTR "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
 #define NAN_MASTER_RANK_LEN 8
+#define NAN_SCID_INFO_LEN   16
 
+#define SAR_CONFIG_SCENARIO_COUNT      100
+#define MAX_NUM_RADIOS 3
+#define MAX_CMD_RESP_BUF_LEN 8192
 
 /*
  This enum defines ranges for various commands; commands themselves
@@ -102,8 +107,40 @@
     ANDROID_NL80211_SUBCMD_PKT_FILTER_RANGE_END   = 0x18FF,
 
     /* define all tx power related commands between 0x1900 and 0x1910 */
-    ANDROID_NL80211_SUBCMD_TX_POWER_RANGE_START	= 0x1900,
-    ANDROID_NL80211_SUBCMD_TX_POWER_RANGE_END	= 0x1910,
+    ANDROID_NL80211_SUBCMD_TX_POWER_RANGE_START = 0x1900,
+    ANDROID_NL80211_SUBCMD_TX_POWER_RANGE_END	 = 0x1910,
+
+    /* define all thermal mode related commands between 0x1920 and 0x192F */
+    ANDROID_NL80211_SUBCMD_MITIGATION_RANGE_START = 0x1920,
+    ANDROID_NL80211_SUBCMD_MITIGATION_RANGE_END   = 0x192F,
+
+    /* define all DSCP related commands between 0x2000 and 0x20FF */
+    ANDROID_NL80211_SUBCMD_DSCP_RANGE_START =	0x2000,
+    ANDROID_NL80211_SUBCMD_DSCP_RANGE_END   =	0x20FF,
+
+    /* define all Channel Avoidance related commands between 0x2100 and 0x211F */
+    ANDROID_NL80211_SUBCMD_CHAVOID_RANGE_START =    0x2100,
+    ANDROID_NL80211_SUBCMD_CHAVOID_RANGE_END   =    0x211F,
+
+    /* define all OTA Download related commands between 0x2120 and 0x212F */
+    ANDROID_NL80211_SUBCMD_OTA_DOWNLOAD_START	= 0x2120,
+    ANDROID_NL80211_SUBCMD_OTA_DOWNLOAD_END	= 0x212F,
+
+    /* define all VOIP mode config related commands between 0x2130 and 0x213F */
+    ANDROID_NL80211_SUBCMD_VIOP_MODE_START =	    0x2130,
+    ANDROID_NL80211_SUBCMD_VIOP_MODE_END =	    0x213F,
+
+    /* define all TWT related commands between 0x2140 and 0x214F */
+    ANDROID_NL80211_SUBCMD_TWT_START =              0x2140,
+    ANDROID_NL80211_SUBCMD_TWT_END =                0x214F,
+
+    /* define all Usable Channel related commands between 0x2150 and 0x215F */
+    ANDROID_NL80211_SUBCMD_USABLE_CHANNEL_START =   0x2150,
+    ANDROID_NL80211_SUBCMD_USABLE_CHANNEL_END =     0x215F,
+
+    /* define all init/deinit related commands between 0x2160 and 0x216F */
+    ANDROID_NL80211_SUBCMD_INIT_DEINIT_RANGE_START = 0x2160,
+    ANDROID_NL80211_SUBCMD_INIT_DEINIT_RANGE_END   = 0x216F,
 
     /* This is reserved for future usage */
 
@@ -147,6 +184,9 @@
     WIFI_SUBCMD_FW_ROAM_POLICY,                          /* 0x1019 */
     WIFI_SUBCMD_ROAM_CAPABILITY,                         /* 0x101a */
     WIFI_SUBCMD_SET_LATENCY_MODE,                        /* 0x101b */
+    WIFI_SUBCMD_SET_MULTISTA_PRIMARY_CONNECTION,         /* 0x101c */
+    WIFI_SUBCMD_SET_MULTISTA_USE_CASE,                   /* 0x101d */
+    WIFI_SUBCMD_SET_DTIM_CONFIG,                         /* 0x101e */
 
     GSCAN_SUBCMD_MAX,
 
@@ -172,7 +212,27 @@
     NAN_SUBCMD_ENABLE_MERGE,                            /* 0x1712 */
     APF_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_PKT_FILTER_RANGE_START,
     APF_SUBCMD_SET_FILTER,
+    APF_SUBCMD_READ_FILTER,
     WIFI_SUBCMD_TX_POWER_SCENARIO = ANDROID_NL80211_SUBCMD_TX_POWER_RANGE_START,
+    WIFI_SUBCMD_THERMAL_MITIGATION = ANDROID_NL80211_SUBCMD_MITIGATION_RANGE_START,
+    DSCP_SUBCMD_SET_TABLE = ANDROID_NL80211_SUBCMD_DSCP_RANGE_START,
+    DSCP_SUBCMD_RESET_TABLE,			    	/* 0x2001 */
+    CHAVOID_SUBCMD_SET_CONFIG = ANDROID_NL80211_SUBCMD_CHAVOID_RANGE_START,
+
+    TWT_SUBCMD_GETCAPABILITY	= ANDROID_NL80211_SUBCMD_TWT_START,
+    TWT_SUBCMD_SETUP_REQUEST,
+    TWT_SUBCMD_TEAR_DOWN_REQUEST,
+    TWT_SUBCMD_INFO_FRAME_REQUEST,
+    TWT_SUBCMD_GETSTATS,
+    TWT_SUBCMD_CLR_STATS,
+
+    WIFI_SUBCMD_CONFIG_VOIP_MODE = ANDROID_NL80211_SUBCMD_VIOP_MODE_START,
+
+    WIFI_SUBCMD_GET_OTA_CURRUNT_INFO = ANDROID_NL80211_SUBCMD_OTA_DOWNLOAD_START,
+    WIFI_SUBCMD_OTA_UPDATE,
+    WIFI_SUBCMD_USABLE_CHANNEL = ANDROID_NL80211_SUBCMD_USABLE_CHANNEL_START,
+    WIFI_SUBCMD_TRIGGER_SSR = ANDROID_NL80211_SUBCMD_INIT_DEINIT_RANGE_START,
+    WIFI_SUBCMD_GET_RADIO_COMBO_MATRIX,
 } WIFI_SUB_COMMAND;
 
 typedef enum {
@@ -212,10 +272,14 @@
     NAN_EVENT_SDF				= 28,
     NAN_EVENT_TCA				= 29,
     NAN_EVENT_SUBSCRIBE_UNMATCH			= 30,
-    NAN_EVENT_UNKNOWN,
+    NAN_EVENT_UNKNOWN				= 31,
+    BRCM_VENDOR_EVENT_HANGED			= 33,
     ROAM_EVENT_START,
     GOOGLE_FILE_DUMP_EVENT			= 37,
-    NAN_ASYNC_RESPONSE_DISABLED			= 40
+    NAN_ASYNC_RESPONSE_DISABLED			= 40,
+    BRCM_VENDOR_EVENT_TWT			= 43,
+    BRCM_TPUT_DUMP_EVENT			= 44,
+    NAN_EVENT_MATCH_EXPIRY			= 45
 } WIFI_EVENT;
 
 typedef void (*wifi_internal_event_handler) (wifi_handle handle, int events);
@@ -239,8 +303,15 @@
     wifi_handle handle;                             // handle to wifi data
     char name[IFNAMSIZ+1];                          // interface name + trailing null
     int  id;                                        // id to use when talking to driver
+    bool is_virtual;                                // mark each iface as virtual or static
 } interface_info;
 
+typedef enum {
+	NAN_STATE_DISABLED = 0,
+	NAN_STATE_AP = 1,
+	NAN_STATE_CHRE = 2,
+} nan_enab_state_t;
+
 typedef struct {
 
     struct nl_sock *cmd_sock;                       // command socket object
@@ -265,7 +336,11 @@
 
     interface_info **interfaces;                    // array of interfaces
     int num_interfaces;                             // number of interfaces
+    int max_num_interfaces;                         // max number of interfaces
+    wifi_subsystem_restart_handler restart_handler; // trigger sub system handler
 
+    wifi_chre_handler chre_nan_cb;                  // chre CB for nan status
+    nan_enab_state_t nan_state;                     // Nan enable state
 
     // add other details
 } hal_info;
@@ -302,11 +377,65 @@
     u8  ie_data[1];                  // IE data to follow
 } wifi_gscan_full_result_t;
 
+void twt_deinit_handler();
+
+typedef enum {
+    TWT_EVENT_INVALID          = 0,
+    TWT_SETUP_RESPONSE         = 1,
+    TWT_TEARDOWN_COMPLETION    = 2,
+    TWT_INFORM_FRAME           = 3,
+    TWT_NOTIFY                 = 4,
+    TWT_EVENT_LAST
+} TwtEventType;
+
+typedef enum {
+    TWT_INVALID			= 0,
+    TWT_SETUP_REQUEST		= 1,
+    TWT_INFO_FRAME_REQUEST	= 2,
+    TWT_TEAR_DOWN_REQUEST	= 3,
+    TWT_LAST
+} TwtRequestType;
+
+typedef enum {
+    TWT_ATTRIBUTE_INVALID		= 0,
+    TWT_ATTRIBUTE_CONFIG_ID		= 1,
+    TWT_ATTRIBUTE_NEG_TYPE		= 2,
+    TWT_ATTRIBUTE_TRIGGER_TYPE		= 3,
+    TWT_ATTRIBUTE_WAKE_DUR_US		= 4,
+    TWT_ATTRIBUTE_WAKE_INT_US		= 5,
+    TWT_ATTRIBUTE_WAKE_INT_MIN_US	= 6,
+    TWT_ATTRIBUTE_WAKE_INT_MAX_US	= 7,
+    TWT_ATTRIBUTE_WAKE_DUR_MIN_US	= 8,
+    TWT_ATTRIBUTE_WAKE_DUR_MAX_US	= 9,
+    TWT_ATTRIBUTE_AVG_PKT_SIZE		= 10,
+    TWT_ATTRIBUTE_AVG_PKT_NUM		= 11,
+    TWT_ATTRIBUTE_WAKE_TIME_OFF_US	= 12,
+    TWT_ATTRIBUTE_ALL_TWT		= 13,
+    TWT_ATTRIBUTE_RESUME_TIME_US	= 14,
+    TWT_ATTRIBUTE_AVG_EOSP_DUR		= 15,
+    TWT_ATTRIBUTE_EOSP_COUNT		= 16,
+    TWT_ATTRIBUTE_NUM_SP		= 17,
+    TWT_ATTRIBUTE_DEVICE_CAP		= 18,
+    TWT_ATTRIBUTE_PEER_CAP		= 19,
+    TWT_ATTRIBUTE_STATUS		= 20,
+    TWT_ATTRIBUTE_REASON_CODE		= 21,
+    TWT_ATTRIBUTE_RESUMED		= 22,
+    TWT_ATTRIBUTE_NOTIFICATION		= 23,
+    TWT_ATTRIBUTE_SUB_EVENT		= 24,
+    TWT_ATTRIBUTE_NUM_PEER_STATS	= 25,
+    TWT_ATTRIBUTE_AVG_PKT_NUM_TX	= 26,
+    TWT_ATTRIBUTE_AVG_PKT_SIZE_TX	= 27,
+    TWT_ATTRIBUTE_AVG_PKT_NUM_RX	= 28,
+    TWT_ATTRIBUTE_AVG_PKT_SIZE_RX	= 29,
+    TWT_ATTRIBUTE_MAX
+} TWT_ATTRIBUTE;
+
 wifi_error wifi_register_handler(wifi_handle handle, int cmd, nl_recvmsg_msg_cb_t func, void *arg);
 wifi_error wifi_register_vendor_handler(wifi_handle handle,
             uint32_t id, int subcmd, nl_recvmsg_msg_cb_t func, void *arg);
 
 void wifi_unregister_handler(wifi_handle handle, int cmd);
+void wifi_unregister_vendor_handler_without_lock(wifi_handle handle, uint32_t id, int subcmd);
 void wifi_unregister_vendor_handler(wifi_handle handle, uint32_t id, int subcmd);
 
 wifi_error wifi_register_cmd(wifi_handle handle, int id, WifiCommand *cmd);
@@ -321,18 +450,127 @@
 wifi_handle getWifiHandle(hal_info *info);
 wifi_interface_handle getIfaceHandle(interface_info *info);
 wifi_error wifi_cancel_cmd(wifi_request_id id, wifi_interface_handle iface);
+wifi_error wifi_get_cancel_cmd(wifi_request_id id, wifi_interface_handle iface);
 wifi_error nan_deinit_handler();
 wifi_error wifi_start_hal(wifi_interface_handle iface);
 wifi_error wifi_stop_hal(wifi_interface_handle iface);
 wifi_interface_handle wifi_get_wlan_interface(wifi_handle info,
 	    wifi_interface_handle *ifaceHandles, int numIfaceHandles);
+#ifdef RING_DUMP
+wifi_error wifi_start_ring_dump(wifi_interface_handle iface,
+            wifi_ring_buffer_data_handler ring_handle);
+wifi_error wifi_stop_ring_dump(wifi_interface_handle iface,
+            wifi_ring_buffer_data_handler ring_handle);
+#endif /* RING_DUMP */
+wifi_error wifi_hal_ota_update(wifi_interface_handle iface, uint32_t ota_version);
 wifi_error wifi_hal_preInit(wifi_interface_handle iface);
 /* API to get wake reason statistics */
 wifi_error wifi_get_wake_reason_stats(wifi_interface_handle handle,
         WLAN_DRIVER_WAKE_REASON_CNT *wifi_wake_reason_cnt);
+wifi_error wifi_virtual_interface_create(wifi_handle handle, const char* ifname,
+        wifi_interface_type iface_type);
+wifi_error wifi_virtual_interface_delete(wifi_handle handle, const char* ifname);
+wifi_error wifi_set_coex_unsafe_channels(wifi_handle handle, u32 num_channels,
+                                         wifi_coex_unsafe_channel channels[], u32 restrictions);
+wifi_error wifi_set_voip_mode(wifi_interface_handle handle, wifi_voip_mode mode);
+wifi_error wifi_set_dtim_config(wifi_interface_handle handle, u32 multiplier);
 void set_hautil_mode(bool halutil_mode);
 bool get_halutil_mode();
 
+/* API's to support TWT */
+
+/**@brief twt_get_capability
+ *        Request TWT capability
+ * @param wifi_interface_handle:
+ * @return Synchronous wifi_error and TwtCapabilitySet
+ */
+wifi_error twt_get_capability(wifi_interface_handle iface, TwtCapabilitySet* twt_cap_set);
+
+/**@brief twt_register_handler
+ *        Request to register TWT callback
+ * @param wifi_interface_handle:
+ * @param TwtCallbackHandler:
+ * @return Synchronous wifi_error
+ */
+wifi_error twt_register_handler(wifi_interface_handle iface, TwtCallbackHandler handler);
+
+/**@brief twt_setup_request
+ *        Request to send TWT setup frame
+ * @param wifi_interface_handle:
+ * @param TwtSetupRequest:
+ * @return Synchronous wifi_error
+ * @return Asynchronous EventTwtSetupResponse CB return TwtSetupResponse
+ */
+wifi_error twt_setup_request(wifi_interface_handle iface, TwtSetupRequest* msg);
+
+/**@brief twt_teardown_request
+ *        Request to send TWT teardown frame
+ * @param wifi_interface_handle:
+ * @param TwtTeardownRequest:
+ * @return Synchronous wifi_error
+ * @return Asynchronous EventTwtTeardownCompletion CB return TwtTeardownCompletion
+ * TwtTeardownCompletion may also be received due to other events
+ * like CSA, BTCX, TWT scheduler, MultiConnection, peer-initiated teardown, etc.
+ */
+wifi_error twt_teardown_request(wifi_interface_handle iface, TwtTeardownRequest* msg);
+
+/**@brief twt_info_frame_request
+ *        Request to send TWT info frame
+ * @param wifi_interface_handle:
+ * @param TwtInfoFrameRequest:
+ * @return Synchronous wifi_error
+ * @return Asynchronous EventTwtInfoFrameReceived CB return TwtInfoFrameReceived
+ * Driver may also receive Peer-initiated TwtInfoFrame
+ */
+wifi_error twt_info_frame_request(wifi_interface_handle iface, TwtInfoFrameRequest* msg);
+
+/**@brief twt_get_stats
+ *        Request to get TWT stats
+ * @param wifi_interface_handle:
+ * @param config_id:
+ * @return Synchronous wifi_error and TwtStats
+ */
+wifi_error twt_get_stats(wifi_interface_handle iface, u8 config_id, TwtStats* stats);
+
+/**@brief twt_clear_stats
+ *        Request to clear TWT stats
+ * @param wifi_interface_handle:
+ * @param config_id:
+ * @return Synchronous wifi_error
+ */
+wifi_error twt_clear_stats(wifi_interface_handle iface, u8 config_id);
+
+wifi_error wifi_trigger_subsystem_restart(wifi_handle handle);
+
+/**@brief nan_chre_enable_request
+ *        Request from CHRE to enable NAN
+ * @param transaction id:
+ * @param wifi_interface_handle:
+ * @param NanEnableRequest:
+ * @return Synchronous wifi_error
+ */
+wifi_error nan_chre_enable_request(transaction_id id,
+                        wifi_interface_handle iface,
+                        NanEnableRequest* msg);
+
+/**@brief nan_chre_disable_request
+ *        Request from CHRE to disable NAN
+ * @param transaction id:
+ * @param wifi_interface_handle:
+ * @return Synchronous wifi_error
+ */
+wifi_error nan_chre_disable_request(transaction_id id,
+                        wifi_interface_handle iface);
+
+/**@brief nan_chre_register_handler
+ *        Register chre handler to handle NAN status
+ * @param wifi_interface_handle:
+ * @param wifi_chre_handler:
+ * @return Synchronous wifi_error
+ */
+wifi_error nan_chre_register_handler(wifi_interface_handle iface,
+                        wifi_chre_handler handler);
+
 // some common macros
 
 #define min(x, y)       ((x) < (y) ? (x) : (y))
diff --git a/bcmdhd/wifi_hal/cpp_bindings.cpp b/bcmdhd/wifi_hal/cpp_bindings.cpp
index 5ca6431..7a634bd 100755
--- a/bcmdhd/wifi_hal/cpp_bindings.cpp
+++ b/bcmdhd/wifi_hal/cpp_bindings.cpp
@@ -579,27 +579,56 @@
     }
 }
 
+static int mapErrorCodes(int err)
+{
+    int ret;
+    if (!err) {
+        return WIFI_SUCCESS;
+    }
+    switch (err) {
+        case -EOPNOTSUPP:
+            ret = WIFI_ERROR_NOT_SUPPORTED;
+            break;
+        case -ETIMEDOUT:
+            ret = WIFI_ERROR_TIMED_OUT;
+            break;
+        case -EINVAL:
+            ret = WIFI_ERROR_INVALID_ARGS;
+            break;
+        case -ENOMEM:
+            ret = WIFI_ERROR_OUT_OF_MEMORY;
+            break;
+        case -EBUSY:
+            ret = WIFI_ERROR_BUSY;
+            break;
+        default:
+            ret = WIFI_ERROR_UNKNOWN;
+    }
+    ALOGD("error code %d mapped to %d", err, ret);
+    return ret;
+}
+
 int WifiRequest::create(uint32_t id, int subcmd) {
     int res = create(NL80211_CMD_VENDOR);
     if (res < 0) {
-        return res;
+        return mapErrorCodes(res);
     }
 
     res = put_u32(NL80211_ATTR_VENDOR_ID, id);
     if (res < 0) {
-        return res;
+        return mapErrorCodes(res);
     }
 
     res = put_u32(NL80211_ATTR_VENDOR_SUBCMD, subcmd);
     if (res < 0) {
-        return res;
+        return mapErrorCodes(res);
     }
 
     if (mIface != -1) {
         res = set_iface_id(mIface);
     }
 
-    return res;
+    return mapErrorCodes(res);
 }
 
 
@@ -618,8 +647,7 @@
 }
 
 int WifiCommand::requestResponse(WifiRequest& request) {
-    pthread_mutex_lock(&ResponseMutex);
-    int err = 0, res = 0;
+    int err = 0;
 
     struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
     if (!cb)
@@ -645,8 +673,7 @@
     }
 out:
     nl_cb_put(cb);
-    pthread_mutex_unlock(&ResponseMutex);
-    return err;
+    return mapErrorCodes(err);
 }
 
 int WifiCommand::requestEvent(int cmd) {
@@ -675,7 +702,7 @@
 
 out:
     wifi_unregister_handler(wifiHandle(), cmd);
-    return res;
+    return mapErrorCodes(res);
 }
 
 int WifiCommand::requestVendorEvent(uint32_t id, int subcmd) {
@@ -699,7 +726,7 @@
 
 out:
     wifi_unregister_vendor_handler(wifiHandle(), id, subcmd);
-    return res;
+    return mapErrorCodes(res);
 }
 
 /* Event handlers */
diff --git a/bcmdhd/wifi_hal/cpp_bindings.h b/bcmdhd/wifi_hal/cpp_bindings.h
index 8839a72..8b5600a 100755
--- a/bcmdhd/wifi_hal/cpp_bindings.h
+++ b/bcmdhd/wifi_hal/cpp_bindings.h
@@ -126,7 +126,7 @@
         return pos;
     }
     uint16_t get_type() {
-        return pos->nla_type;
+        return nla_type(pos);
     }
     uint8_t get_u8() {
         return nla_get_u8(pos);
@@ -278,7 +278,7 @@
 
     virtual void addRef() {
         int refs = __sync_add_and_fetch(&mRefs, 1);
-        // ALOGD("addRef: WifiCommand %p has %d references", this, refs);
+        ALOGV("addRef: WifiCommand %p has %d references", this, refs);
     }
 
     virtual void releaseRef() {
@@ -347,6 +347,10 @@
         return wifi_register_vendor_handler(wifiHandle(), id, subcmd, &event_handler, this);
     }
 
+    void unregisterVendorHandlerWithoutLock(uint32_t id, int subcmd) {
+        wifi_unregister_vendor_handler_without_lock(wifiHandle(), id, subcmd);
+    }
+
     void unregisterVendorHandler(uint32_t id, int subcmd) {
         wifi_unregister_vendor_handler(wifiHandle(), id, subcmd);
     }
diff --git a/bcmdhd/wifi_hal/gscan.cpp b/bcmdhd/wifi_hal/gscan.cpp
index f5722f2..995c989 100755
--- a/bcmdhd/wifi_hal/gscan.cpp
+++ b/bcmdhd/wifi_hal/gscan.cpp
@@ -235,7 +235,7 @@
         void *data = reply.get_vendor_data();
         int len = reply.get_vendor_data_len();
 
-        ALOGV("Id = %0x, subcmd = 0x%x, len = %d, expected len = %zd", id, subcmd, len,
+        ALOGV("Id = %0x, subcmd = 0x%x, len = %d, expected len = %d", id, subcmd, len,
             mRequestsize);
 
         memcpy(mCapabilities, data, min(len, mRequestsize));
@@ -252,6 +252,7 @@
     return (wifi_error) command.requestResponse();
 }
 
+/* Function to get chipset supported roaming capabilities */
 wifi_error wifi_get_roaming_capabilities(wifi_interface_handle handle,
         wifi_roaming_capabilities *capabilities)
 {
@@ -345,48 +346,6 @@
 /////////////////////////////////////////////////////////////////////////////
 
 /* helper functions */
-
-static int parseScanResults(wifi_scan_result *results, int num, nlattr *attr)
-{
-    memset(results, 0, sizeof(wifi_scan_result) * num);
-
-    int i = 0;
-    for (nl_iterator it(attr); it.has_next() && i < num; it.next(), i++) {
-
-        int index = it.get_type();
-        ALOGI("retrieved scan result %d", index);
-        nlattr *sc_data = (nlattr *) it.get_data();
-        wifi_scan_result *result = results + i;
-
-        for (nl_iterator it2(sc_data); it2.has_next(); it2.next()) {
-            int type = it2.get_type();
-            if (type == GSCAN_ATTRIBUTE_SSID) {
-                strncpy(result->ssid, (char *) it2.get_data(), it2.get_len());
-                result->ssid[it2.get_len()] = 0;
-            } else if (type == GSCAN_ATTRIBUTE_BSSID) {
-                memcpy(result->bssid, (byte *) it2.get_data(), sizeof(mac_addr));
-            } else if (type == GSCAN_ATTRIBUTE_TIMESTAMP) {
-                result->ts = it2.get_u64();
-            } else if (type == GSCAN_ATTRIBUTE_CHANNEL) {
-                result->ts = it2.get_u16();
-            } else if (type == GSCAN_ATTRIBUTE_RSSI) {
-                result->rssi = it2.get_u8();
-            } else if (type == GSCAN_ATTRIBUTE_RTT) {
-                result->rtt = it2.get_u64();
-            } else if (type == GSCAN_ATTRIBUTE_RTTSD) {
-                result->rtt_sd = it2.get_u64();
-            }
-        }
-
-    }
-
-    if (i >= num) {
-        ALOGE("Got too many results; skipping some");
-    }
-
-    return i;
-}
-
 int createFeatureRequest(WifiRequest& request, int subcmd, int enable) {
 
     int result = request.create(GOOGLE_OUI, subcmd);
@@ -413,7 +372,7 @@
     FullScanResultsCommand(wifi_interface_handle iface, int id, int *params,
                 wifi_scan_result_handler handler)
         : WifiCommand("FullScanResultsCommand", iface, id), mParams(params), mHandler(handler)
-    { }
+    {*mParams = 0;}
 
     int createRequest(WifiRequest& request, int subcmd, int enable) {
         int result = request.create(GOOGLE_OUI, subcmd);
@@ -445,8 +404,8 @@
 
         result = requestResponse(request);
         if (result != WIFI_SUCCESS) {
-            ALOGE("failed to enable full scan results; result = %d", result);
             unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
+            ALOGE("failed to enable full scan results; result = %d", result);
             return result;
         }
 
@@ -607,6 +566,12 @@
         return createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 0);
     }
 
+    void unregisterVendorHandlerAll() {
+        unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN);
+        unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
+        unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
+    }
+
     int start() {
         ALOGV("GSCAN start");
         WifiRequest request(familyId(), ifaceId());
@@ -616,8 +581,13 @@
             return result;
         }
 
+        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
+        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN);
+        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
+
         result = requestResponse(request);
         if (result != WIFI_SUCCESS) {
+            unregisterVendorHandlerAll();
             ALOGE("failed to configure setup; result = %d", result);
             return result;
         }
@@ -626,12 +596,14 @@
 
         result = createScanConfigRequest(request);
         if (result != WIFI_SUCCESS) {
+            unregisterVendorHandlerAll();
             ALOGE("failed to create scan config request; result = %d", result);
             return result;
         }
 
         result = requestResponse(request);
         if (result != WIFI_SUCCESS) {
+            unregisterVendorHandlerAll();
             ALOGE("failed to configure scan; result = %d", result);
             return result;
         }
@@ -640,20 +612,15 @@
 
         result = createStartRequest(request);
         if (result != WIFI_SUCCESS) {
+            unregisterVendorHandlerAll();
             ALOGE("failed to create start request; result = %d", result);
             return result;
         }
 
-        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
-        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN);
-        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
-
         result = requestResponse(request);
         if (result != WIFI_SUCCESS) {
+            unregisterVendorHandlerAll();
             ALOGE("failed to start scan; result = %d", result);
-            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN);
-            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
-            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
             return result;
         }
         return result;
@@ -673,9 +640,7 @@
             }
         }
 
-        unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN);
-        unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
-        unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
+        unregisterVendorHandlerAll();
         return WIFI_SUCCESS;
     }
 
@@ -744,7 +709,6 @@
     if (id == -1) {
         wifi_scan_result_handler handler;
         wifi_scan_cmd_params dummy_params;
-        wifi_handle handle = getWifiHandle(iface);
         memset(&handler, 0, sizeof(handler));
 
         ScanCommand *cmd = new ScanCommand(iface, id, &dummy_params, handler);
@@ -803,7 +767,7 @@
     wifi_gscan_result_t *fixed = &drv_res->fixed;
 
     if ((ie_len + offsetof(wifi_gscan_full_result_t, ie_data)) > len) {
-        ALOGE("BAD event data, len %d ie_len %d fixed length %d!\n", len,
+        ALOGE("BAD event data, len %d ie_len %d fixed length %lu!\n", len,
             ie_len, offsetof(wifi_gscan_full_result_t, ie_data));
         return NL_SKIP;
     }
@@ -818,7 +782,7 @@
     if(handler.on_full_scan_result)
         handler.on_full_scan_result(id, full_scan_result, drv_res->scan_ch_bucket);
 
-    ALOGV("Full scan result: %-32s %02x:%02x:%02x:%02x:%02x:%02x %d %d %lld %lld %lld %x %d\n",
+    ALOGV("Full scan result: %-32s %02x:%02x:%02x:%02x:%02x:%02x %d %d %ld %lx %lx %x %d\n",
         fixed->ssid, fixed->bssid[0], fixed->bssid[1], fixed->bssid[2], fixed->bssid[3],
         fixed->bssid[4], fixed->bssid[5], fixed->rssi, fixed->channel, fixed->ts,
         fixed->rtt, fixed->rtt_sd, drv_res->scan_ch_bucket, drv_res->ie_length);
@@ -830,11 +794,9 @@
 wifi_error wifi_disable_full_scan_results(wifi_request_id id, wifi_interface_handle iface)
 {
     ALOGV("Disabling full scan results");
-    wifi_handle handle = getWifiHandle(iface);
 
     if(id == -1) {
         wifi_scan_result_handler handler;
-        wifi_handle handle = getWifiHandle(iface);
         int params_dummy;
 
         memset(&handler, 0, sizeof(handler));
@@ -1101,6 +1063,11 @@
         return result;
     }
 
+    void unregisterVendorHandlerAll() {
+        unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND);
+        unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST);
+    }
+
     int start() {
         ALOGI("Executing hotlist setup request, num = %d", mParams.num_bssid);
         WifiRequest request(familyId(), ifaceId());
@@ -1109,27 +1076,26 @@
             return result;
         }
 
-        result = requestResponse(request);
-        if (result < 0) {
-            ALOGI("Failed to execute hotlist setup request, result = %d", result);
-            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND);
-            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST);
-            return result;
-        }
-
-        ALOGI("Successfully set %d APs in the hotlist ", mParams.num_bssid);
-        result = createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1);
-        if (result < 0) {
-            return result;
-        }
-
         registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND);
         registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST);
 
         result = requestResponse(request);
         if (result < 0) {
-            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND);
-            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST);
+            unregisterVendorHandlerAll();
+            ALOGI("Failed to execute hotlist setup request, result = %d", result);
+            return result;
+        }
+
+        ALOGI("Successfully set %d APs in the hotlist ", mParams.num_bssid);
+        result = createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1);
+        if (result < 0) {
+            unregisterVendorHandlerAll();
+            return result;
+        }
+
+        result = requestResponse(request);
+        if (result < 0) {
+            unregisterVendorHandlerAll();
             return result;
         }
 
@@ -1139,8 +1105,7 @@
 
     virtual int cancel() {
         /* unregister event handler */
-        unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND);
-        unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST);
+        unregisterVendorHandlerAll();
         /* create set hotlist message with empty hotlist */
         WifiRequest request(familyId(), ifaceId());
         int result = createTeardownRequest(request);
@@ -1329,15 +1294,15 @@
             return result;
         }
 
+        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_EPNO_EVENT);
         result = requestResponse(request);
         if (result < 0) {
-            ALOGI("Failed to execute ePNO setup request, result = %d", result);
             unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_EPNO_EVENT);
+            ALOGI("Failed to execute ePNO setup request, result = %d", result);
             return result;
         }
 
         ALOGI("Successfully set %d SSIDs for ePNO", epno_params.num_networks);
-        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_EPNO_EVENT);
         ALOGI("successfully restarted the scan");
         return result;
     }
@@ -1368,7 +1333,6 @@
 
     virtual int handleEvent(WifiEvent& event) {
         ALOGI("ePNO event");
-        int event_id = event.get_vendor_subcmd();
         // event.log();
 
         nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
@@ -1537,8 +1501,11 @@
             return result;
         }
 
+        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
+
         result = requestResponse(request);
         if (result < 0) {
+            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
             ALOGI("failed to set significant wifi change config %d", result);
             return result;
         }
@@ -1547,11 +1514,10 @@
 
         result = createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1);
         if (result < 0) {
+            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
             return result;
         }
 
-        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
-
         result = requestResponse(request);
         if (result < 0) {
             unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
@@ -1661,7 +1627,6 @@
 {
     if (id == -1) {
         wifi_epno_handler handler;
-        wifi_handle handle = getWifiHandle(iface);
 
         memset(&handler, 0, sizeof(handler));
         ePNOCommand *cmd = new ePNOCommand(iface, id, NULL, handler);
@@ -1677,6 +1642,9 @@
         const wifi_epno_params *params, wifi_epno_handler handler)
 {
     wifi_handle handle = getWifiHandle(iface);
+    if (handler.on_network_found == NULL) {
+        return WIFI_ERROR_INVALID_ARGS;
+    }
 
     ePNOCommand *cmd = new ePNOCommand(iface, id, params, handler);
     NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
@@ -1761,8 +1729,6 @@
 wifi_error wifi_set_bssid_blacklist(wifi_request_id id, wifi_interface_handle iface,
         wifi_bssid_params params)
 {
-    wifi_handle handle = getWifiHandle(iface);
-
     BssidBlacklistCommand *cmd = new BssidBlacklistCommand(iface, id, &params);
     NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
     wifi_error result = (wifi_error)cmd->start();
@@ -1936,8 +1902,8 @@
 
         result = requestResponse(request);
         if (result != WIFI_SUCCESS) {
-            ALOGE("failed to set ANQPO networks; result = %d", result);
             unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_ANQPO_HOTSPOT_MATCH);
+            ALOGE("failed to set ANQPO networks; result = %d", result);
             return result;
         }
 
@@ -2004,11 +1970,11 @@
         ALOGI("%02x:%02x:%02x:%02x:%02x:%02x ", mResult->bssid[0], mResult->bssid[1],
                 mResult->bssid[2], mResult->bssid[3], mResult->bssid[4], mResult->bssid[5]);
 
-        ALOGI("%d\t", mResult->rssi);
-        ALOGI("%d\t", mResult->channel);
-        ALOGI("%lld\t", mResult->ts);
-        ALOGI("%lld\t", mResult->rtt);
-        ALOGI("%lld\n", mResult->rtt_sd);
+        ALOGI("rssi:%d\t", mResult->rssi);
+        ALOGI("channel:%d\t", mResult->channel);
+        ALOGI("ts:0x%jx\t", mResult->ts);
+        ALOGI("rtt:0x%jx\t", mResult->rtt);
+        ALOGI("rtt_sd:0x%jx\n", mResult->rtt_sd);
 
         if(*mHandler.on_passpoint_network_found)
             (*mHandler.on_passpoint_network_found)(id(), networkId, mResult, anqp_len, anqp);
diff --git a/bcmdhd/wifi_hal/link_layer_stats.cpp b/bcmdhd/wifi_hal/link_layer_stats.cpp
index 34226f4..3a922db 100644
--- a/bcmdhd/wifi_hal/link_layer_stats.cpp
+++ b/bcmdhd/wifi_hal/link_layer_stats.cpp
@@ -37,12 +37,19 @@
 
 #define LOG_TAG  "WifiHAL"
 
-#include <log/log.h>
+#include <utils/Log.h>
 
 #include "wifi_hal.h"
 #include "common.h"
 #include "cpp_bindings.h"
 
+typedef enum {
+    ANDR_WIFI_ATTRIBUTE_INVALID        = 0,
+    ANDR_WIFI_ATTRIBUTE_NUM_RADIO      = 1,
+    ANDR_WIFI_ATTRIBUTE_STATS_INFO     = 2,
+    ANDR_WIFI_ATTRIBUTE_STATS_MAX      = 3
+} LINK_STAT_ATTRIBUTE;
+
 /* Internal radio statistics structure in the driver */
 typedef struct {
 	wifi_radio radio;
@@ -85,6 +92,12 @@
 
 protected:
     virtual int handleResponse(WifiEvent& reply) {
+        void *data = NULL;
+        wifi_radio_stat *radio_stat_ptr = NULL;
+        u8 *iface_stat = NULL;
+        u8 *radioStatsBuf = NULL, *output = NULL, *data_ptr = NULL;
+        uint32_t total_size = 0, per_radio_size = 0, data_len = 0, rem_len = 0;
+        int num_radios = 0, id = 0, subcmd = 0, len = 0;
 
         // ALOGI("In GetLinkStatsCommand::handleResponse");
 
@@ -93,31 +106,153 @@
             return NL_SKIP;
         }
 
-        int id = reply.get_vendor_id();
-        int subcmd = reply.get_vendor_subcmd();
+        id = reply.get_vendor_id();
+        subcmd = reply.get_vendor_subcmd();
+        nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+        len = reply.get_vendor_data_len();
 
-        // ALOGI("Id = %0x, subcmd = %d", id, subcmd);
-
-        void *data = reply.get_vendor_data();
-        int len = reply.get_vendor_data_len();
-        wifi_radio_stat *radio_stat =
-            convertToExternalRadioStatStructure((wifi_radio_stat_internal *)data);
-        if (!radio_stat) {
-            ALOGE("Invalid stats pointer received");
+        ALOGV("Id = %0x, subcmd = %d, len = %d\n", id, subcmd, len);
+        if (vendor_data == NULL || len == 0) {
+            ALOGE("no vendor data in GetLinkStatCommand response; ignoring it");
             return NL_SKIP;
         }
-        wifi_iface_stat *iface_stat =
-            (wifi_iface_stat *)((char *)&((wifi_radio_stat_internal *)data)->channels
-                + radio_stat->num_channels * sizeof(wifi_channel_stat));
-        (*mHandler.on_link_stats_results)(id, iface_stat, 1, radio_stat);
-        free(radio_stat);
+
+        for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+            if (it.get_type() == ANDR_WIFI_ATTRIBUTE_NUM_RADIO) {
+                num_radios = it.get_u32();
+            } else if (it.get_type() == ANDR_WIFI_ATTRIBUTE_STATS_INFO) {
+                data = it.get_data();
+                data_len = it.get_len();
+            } else {
+                ALOGW("Ignoring invalid attribute type = %d, size = %d\n",
+                it.get_type(), it.get_len());
+            }
+        }
+
+        if (num_radios) {
+            rem_len = MAX_CMD_RESP_BUF_LEN;
+            radioStatsBuf = (u8 *)malloc(MAX_CMD_RESP_BUF_LEN);
+            if (!radioStatsBuf) {
+                ALOGE("No memory\n");
+                return NL_SKIP;
+            }
+            memset(radioStatsBuf, 0, MAX_CMD_RESP_BUF_LEN);
+            output = radioStatsBuf;
+
+            if (!data || !data_len) {
+                ALOGE("%s: null data\n", __func__);
+                return NL_SKIP;
+            }
+
+            data_ptr = (u8*)data;
+            for (int i = 0; i < num_radios; i++) {
+                rem_len -= per_radio_size;
+                if (rem_len < per_radio_size) {
+                    ALOGE("No data left for radio %d\n", i);
+                    goto exit;
+                }
+                data_ptr = (u8*)data + total_size;
+                if (!data_ptr) {
+                    ALOGE("Invalid data for radio index = %d\n", i);
+                    goto exit;
+                }
+                radio_stat_ptr =
+                    convertToExternalRadioStatStructure((wifi_radio_stat*)data_ptr,
+                        &per_radio_size);
+                if (!radio_stat_ptr || !per_radio_size) {
+                    ALOGE("No data for radio %d\n", i);
+                    continue;
+                }
+                memcpy(output, radio_stat_ptr, per_radio_size);
+                output += per_radio_size;
+                total_size += per_radio_size;
+            }
+
+            iface_stat = ((u8*)data + total_size);
+            if (!iface_stat || data_len < total_size) {
+                ALOGE("No data for iface stats!!, data_len = %d, total_size = %d\n",
+                    data_len, total_size);
+                goto exit;
+            }
+            (*mHandler.on_link_stats_results)(id, (wifi_iface_stat *)iface_stat,
+            num_radios, (wifi_radio_stat *)radioStatsBuf);
+        } else {
+            /* To be deprecated, adding it to keep it backward compatible */
+            ALOGD("GetLinkStatCommand: zero radio case\n");
+            data = reply.get_vendor_data();
+            if (!data) {
+                ALOGE("Invalid vendor data received\n");
+                return NL_SKIP;
+            }
+
+            num_radios = 1;
+            data = reply.get_vendor_data();
+            len = reply.get_vendor_data_len();
+            if (!data || !len) {
+                ALOGE("Invalid vendor data received\n");
+                return NL_SKIP;
+            }
+            radio_stat_ptr =
+                convertToExternalRadioStatStructureLegacy((wifi_radio_stat_internal *)data);
+            if (!radio_stat_ptr) {
+                ALOGE("Invalid stats pointer received\n");
+                return NL_SKIP;
+            }
+            wifi_iface_stat *iface_stat =
+                (wifi_iface_stat *)((char *)&((wifi_radio_stat_internal *)data)->channels
+                    + radio_stat_ptr->num_channels * sizeof(wifi_channel_stat));
+            (*mHandler.on_link_stats_results)(id, iface_stat, num_radios, radio_stat_ptr);
+        }
+exit:
+        if (radio_stat_ptr) {
+            free(radio_stat_ptr);
+            radio_stat_ptr = NULL;
+        }
+        if (radioStatsBuf) {
+            free(radioStatsBuf);
+            radioStatsBuf = NULL;
+        }
         return NL_OK;
     }
 
 private:
-    wifi_radio_stat *convertToExternalRadioStatStructure(wifi_radio_stat_internal *internal_stat_ptr) {
+    wifi_radio_stat *convertToExternalRadioStatStructure(wifi_radio_stat *internal_stat_ptr,
+        uint32_t *per_radio_size) {
         wifi_radio_stat *external_stat_ptr = NULL;
-        if (internal_stat_ptr) {
+        if (!internal_stat_ptr) {
+            ALOGE("Incoming data is null\n");
+        } else {
+            uint32_t channel_size = internal_stat_ptr->num_channels * sizeof(wifi_channel_stat);
+            *per_radio_size = offsetof(wifi_radio_stat, channels) + channel_size;
+            external_stat_ptr = (wifi_radio_stat *)malloc(*per_radio_size);
+            if (external_stat_ptr) {
+                external_stat_ptr->radio = internal_stat_ptr->radio;
+                external_stat_ptr->on_time = internal_stat_ptr->on_time;
+                external_stat_ptr->tx_time = internal_stat_ptr->tx_time;
+                external_stat_ptr->num_tx_levels = internal_stat_ptr->num_tx_levels;
+                external_stat_ptr->tx_time_per_levels = NULL;
+                external_stat_ptr->rx_time = internal_stat_ptr->rx_time;
+                external_stat_ptr->on_time_scan = internal_stat_ptr->on_time_scan;
+                external_stat_ptr->on_time_nbd = internal_stat_ptr->on_time_nbd;
+                external_stat_ptr->on_time_gscan = internal_stat_ptr->on_time_gscan;
+                external_stat_ptr->on_time_roam_scan = internal_stat_ptr->on_time_roam_scan;
+                external_stat_ptr->on_time_pno_scan = internal_stat_ptr->on_time_pno_scan;
+                external_stat_ptr->on_time_hs20 = internal_stat_ptr->on_time_hs20;
+                external_stat_ptr->num_channels = internal_stat_ptr->num_channels;
+                if (internal_stat_ptr->num_channels) {
+                    memcpy(&(external_stat_ptr->channels), &(internal_stat_ptr->channels),
+                        channel_size);
+                }
+            }
+        }
+        return external_stat_ptr;
+    }
+
+    wifi_radio_stat *convertToExternalRadioStatStructureLegacy(wifi_radio_stat_internal *internal_stat_ptr) {
+        wifi_radio_stat *external_stat_ptr = NULL;
+        if (!internal_stat_ptr) {
+            ALOGE("Sta_ptr is null\n");
+        } else {
             uint32_t channel_size = internal_stat_ptr->num_channels * sizeof(wifi_channel_stat);
             uint32_t total_size = sizeof(wifi_radio_stat) + channel_size;
             external_stat_ptr = (wifi_radio_stat *)malloc(total_size);
diff --git a/bcmdhd/wifi_hal/nan.cpp b/bcmdhd/wifi_hal/nan.cpp
index cfabfa8..52f29e3 100755
--- a/bcmdhd/wifi_hal/nan.cpp
+++ b/bcmdhd/wifi_hal/nan.cpp
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2017 The Android Open Source Project
  *
- * Portions copyright (C) 2019 Broadcom Limited
+ * Portions copyright (C) 2017 Broadcom Limited
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -286,7 +286,12 @@
     NAN_ATTRIBUTE_DISCOVERY_BEACON_INTERVAL         = 224,
     NAN_ATTRIBUTE_NSS                               = 225,
     NAN_ATTRIBUTE_ENABLE_RANGING                    = 226,
-    NAN_ATTRIBUTE_DW_EARLY_TERM                     = 227
+    NAN_ATTRIBUTE_DW_EARLY_TERM                     = 227,
+    NAN_ATTRIBUTE_CHANNEL_INFO                      = 228,
+    NAN_ATTRIBUTE_NUM_CHANNELS                      = 229,
+    NAN_ATTRIBUTE_INSTANT_MODE_ENABLE               = 230,
+    NAN_ATTRIBUTE_INSTANT_COMM_CHAN                 = 231,
+    NAN_ATTRIBUTE_CHRE_REQUEST                      = 232,
 } NAN_ATTRIBUTE;
 
 typedef enum {
@@ -310,7 +315,6 @@
     NAN_DATA_PATH_IFACE_UP                      = 17,
     NAN_DATA_PATH_SEC_INFO                      = 18,
     NAN_VERSION_INFO                            = 19,
-    NAN_REQUEST_ENABLE_MERGE		    = 20,
     NAN_REQUEST_LAST                            = 0xFFFF
 } NanRequestType;
 
@@ -381,41 +385,7 @@
 static int get_svc_hash(unsigned char *svc_name, u16 svc_name_len,
         u8 *svc_hash, u16 svc_hash_len);
 NanResponseType get_response_type(WIFI_SUB_COMMAND nan_subcmd);
-static NanStatusType nan_map_term_status(u32 vendor_reason);
 static NanStatusType nan_map_response_status(int vendor_status);
-static int ioctl_sock = 0;
-
-static int setFlags(int s, struct ifreq *ifr, int set, int clr)
-{
-    if(ioctl(s, SIOCGIFFLAGS, ifr) < 0) {
-        return WIFI_ERROR_UNKNOWN;
-    }
-
-    ifr->ifr_flags = (ifr->ifr_flags & (~clr)) | set;
-    if (ioctl(s, SIOCSIFFLAGS, ifr) < 0) {
-        return WIFI_ERROR_UNKNOWN;
-    }
-
-    return WIFI_SUCCESS;
-}
-
-static inline void init_sockaddr_in(struct sockaddr_in *sin, const char *addr)
-{
-    sin->sin_family = AF_INET;
-    sin->sin_port = 0;
-    sin->sin_addr.s_addr = inet_addr(addr);
-}
-
-static int setAddr(int s, struct ifreq *ifr, const char *addr)
-{
-    init_sockaddr_in((struct sockaddr_in *) &ifr->ifr_addr, addr);
-
-    if (ioctl(s, SIOCSIFADDR, ifr) < 0) {
-        return WIFI_ERROR_UNKNOWN;
-    }
-
-    return WIFI_SUCCESS;
-}
 
 /* Function to separate the common events to NAN1.0 events */
 static int is_de_event(int cmd) {
@@ -429,6 +399,7 @@
         case NAN_EVENT_FOLLOWUP:
         case NAN_EVENT_TRANSMIT_FOLLOWUP_IND:
         case NAN_EVENT_PUBLISH_REPLIED_IND:
+        case NAN_EVENT_MATCH_EXPIRY:
             is_de_evt = true;
             break;
         default:
@@ -574,6 +545,30 @@
 
 };
 
+void HandleExpiryEvent(nan_hal_info_t info, nlattr *vendor_data) {
+    ALOGI("Received NAN_EVENT_MATCH_EXPIRY\n");
+    u16 attr_type;
+    NanMatchExpiredInd expired_event;
+    memset(&expired_event, 0, sizeof(NanMatchExpiredInd));
+
+    for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+        attr_type = it.get_type();
+        if (attr_type == NAN_ATTRIBUTE_SUBSCRIBE_ID) {
+            expired_event.publish_subscribe_id = it.get_u16();
+            ALOGI("pub_sub id = %u\n",
+            expired_event.publish_subscribe_id);
+        } else if (attr_type == NAN_ATTRIBUTE_PUBLISH_ID) {
+            expired_event.requestor_instance_id = it.get_u32();
+            ALOGI("req_inst id = %u\n", expired_event.requestor_instance_id);
+       }
+    }
+
+    if (expired_event.requestor_instance_id && expired_event.publish_subscribe_id) {
+        GET_NAN_HANDLE(info)->mHandlers.EventMatchExpired(&expired_event);
+    } else {
+        ALOGE("Invalid values for notifying the expired event, dropping the event\n");
+    }
+}
 
 ///////////////////////////////////////////////////////////////////////////////
 class NanDiscEnginePrimitive : public WifiCommand
@@ -664,7 +659,7 @@
         mInstId = mParams->publish_id;
         nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
 
-        result = request.put_u16(NAN_ATTRIBUTE_PUBLISH_ID, mInstId);
+        result = request.put_u32(NAN_ATTRIBUTE_PUBLISH_ID, mInstId);
         if (result < 0) {
             ALOGE("%s: Failed to fill pub id, result = %d\n", __func__, result);
             return result;
@@ -865,6 +860,11 @@
         }
 
         if (mParams->scid_len) {
+            if ((mParams->scid_len > NAN_MAX_SCID_BUF_LEN) ||
+                    (mParams->scid_len % NAN_SCID_INFO_LEN)) {
+                ALOGE("%s: Invalid scid len, = %d\n", __func__, mParams->scid_len);
+                return NAN_STATUS_INVALID_PARAM;
+            }
             result = request.put_u32(NAN_ATTRIBUTE_SCID_LEN,
                     mParams->scid_len);
             if (result < 0) {
@@ -967,7 +967,7 @@
         }
         ALOGI("%s: pub id = %d, inst_id = %d\n", __func__, mParams->publish_id, mInstId);
 
-        result = request.put_u16(NAN_ATTRIBUTE_PUBLISH_ID, mInstId);
+        result = request.put_u32(NAN_ATTRIBUTE_PUBLISH_ID, mInstId);
         if (result < 0) {
             ALOGE("%s: Failed to fill NAN_ATTRIBUTE_PUBLISH_ID, result = %d\n",
                     __func__, result);
@@ -1176,7 +1176,45 @@
             return result;
         }
 
+        result = request.put_u8(NAN_ATTRIBUTE_CIPHER_SUITE_TYPE,
+                mParams->cipher_type);
+        if (result < 0) {
+            ALOGE("%s: Failed to fill NAN_ATTRIBUTE_CIPHER_SUITE_TYPE, result = %d\n",
+                    __func__, result);
+            return result;
+        }
+
+        result = request.put_u8(NAN_ATTRIBUTE_KEY_TYPE,
+                mParams->key_info.key_type);
+        if (result < 0) {
+            ALOGE("%s: Failed to fill NAN_ATTRIBUTE_KEY_TYPE, result = %d\n",
+                    __func__, result);
+            return result;
+        }
+
+        if (mParams->key_info.key_type == NAN_SECURITY_KEY_INPUT_PMK) {
+            if (mParams->key_info.body.pmk_info.pmk_len) {
+                result = request.put_u32(NAN_ATTRIBUTE_KEY_LEN,
+                        mParams->key_info.body.pmk_info.pmk_len);
+                if (result < 0) {
+                    ALOGE("%s: Failed to fill pmk len, result = %d\n", __func__, result);
+                    return result;
+                }
+                result = request.put(NAN_ATTRIBUTE_KEY_DATA,
+                        (void *)mParams->key_info.body.pmk_info.pmk,
+                        mParams->key_info.body.pmk_info.pmk_len);
+                if (result < 0) {
+                    ALOGE("%s: Failed to fill pmk, result = %d\n", __func__, result);
+                    return result;
+                }
+            }
+        }
+
         if (mParams->scid_len) {
+            if (mParams->scid_len != NAN_SCID_INFO_LEN) {
+                ALOGE("%s: Invalid scid len, = %d\n", __func__, mParams->scid_len);
+                return NAN_STATUS_INVALID_PARAM;
+            }
             result = request.put_u32(NAN_ATTRIBUTE_SCID_LEN,
                     mParams->scid_len);
             if (result < 0) {
@@ -1184,7 +1222,6 @@
                 return result;
             }
 
-            prhex(NULL, mParams->scid, mParams->scid_len);
             result = request.put(NAN_ATTRIBUTE_SCID,
                     (void *)mParams->scid, mParams->scid_len);
             if (result < 0) {
@@ -1513,7 +1550,6 @@
     int handleEvent(WifiEvent& event) {
         int cmd = event.get_vendor_subcmd();
         u16 attr_type;
-        int result;
 
         ALOGI("Received NanDiscEnginePrimitive event: %d\n", event.get_cmd());
         nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
@@ -1528,15 +1564,16 @@
                     attr_type = it.get_type();
 
                     if (attr_type == NAN_ATTRIBUTE_PUBLISH_ID) {
-                        pub_term_event.publish_id = it.get_u16();
+                        pub_term_event.publish_id = it.get_u32();
                         ALOGI("pub id = %u", pub_term_event.publish_id);
                     } else if (attr_type == NAN_ATTRIBUTE_STATUS) {
                         pub_term_event.reason = (NanStatusType)it.get_u8();
                         ALOGI("pub termination status %u", pub_term_event.reason);
                     } else if (attr_type == NAN_ATTRIBUTE_REASON) {
-                        memcpy(pub_term_event.nan_reason, it.get_data(),
-                                sizeof(pub_term_event.nan_reason));
-                        ALOGI("pub termination reason: %s", pub_term_event.nan_reason);
+                        u8 len = min(it.get_len(), sizeof(pub_term_event.nan_reason));
+                        memcpy(pub_term_event.nan_reason, it.get_data(), len);
+                        ALOGI("pub termination reason: %s, len = %d\n",
+                            pub_term_event.nan_reason, len);
                     } else {
                         ALOGE("Unknown attr: %u\n", attr_type);
                     }
@@ -1560,7 +1597,7 @@
                         ALOGI("sub id: %u", it.get_u16());
                         subscribe_event.publish_subscribe_id = it.get_u8();
                     } else if (attr_type == NAN_ATTRIBUTE_PUBLISH_ID) {
-                        ALOGI("pub id: %u", it.get_u16());
+                        ALOGI("pub id: %u", it.get_u32());
                         subscribe_event.requestor_instance_id = it.get_u8();
                     } else if (attr_type == NAN_ATTRIBUTE_MAC_ADDR) {
                         memcpy(subscribe_event.addr, it.get_data(), NAN_MAC_ADDR_LEN);
@@ -1656,9 +1693,10 @@
                         sub_term_event.reason = (NanStatusType)it.get_u16();
                         ALOGI("sub termination status %u", sub_term_event.reason);
                     } else if (attr_type == NAN_ATTRIBUTE_REASON) {
-                        memcpy(sub_term_event.nan_reason, it.get_data(),
-                                sizeof(sub_term_event.nan_reason));
-                        ALOGI("sub termination reason: %s", sub_term_event.nan_reason);
+                        u8 len = min(it.get_len(), sizeof(sub_term_event.nan_reason));
+                        memcpy(sub_term_event.nan_reason, it.get_data(), len);
+                        ALOGI("sub termination nan reason: %s, len = %d\n",
+                            sub_term_event.nan_reason, len);
                     } else {
                         ALOGI("Unknown attr: %d\n", attr_type);
                     }
@@ -1666,7 +1704,9 @@
 
                 GET_NAN_HANDLE(info)->mHandlers.EventSubscribeTerminated(&sub_term_event);
                 break;
-
+            case NAN_EVENT_MATCH_EXPIRY:
+                HandleExpiryEvent(info, vendor_data);
+                break;
             case NAN_EVENT_FOLLOWUP:
                 NanFollowupInd followup_event;
                 memset(&followup_event, 0, sizeof(NanFollowupInd));
@@ -1705,9 +1745,10 @@
                     } else if (attr_type == NAN_ATTRIBUTE_STATUS) {
                         followup_ind.reason = (NanStatusType)it.get_u8();
                     } else if (attr_type == NAN_ATTRIBUTE_REASON) {
-                        memcpy(followup_ind.nan_reason, it.get_data(),
-                                sizeof(followup_ind.nan_reason));
-                        ALOGI("nan transmit followup ind: reason: %s", followup_ind.nan_reason);
+                        u8 len = min(it.get_len(), sizeof(followup_ind.nan_reason));
+                        memcpy(followup_ind.nan_reason, it.get_data(), len);
+                        ALOGI("nan transmit followup ind: reason: %s, len = %d\n",
+                            followup_ind.nan_reason, len);
                     }
                 }
                 GET_NAN_HANDLE(info)->mHandlers.EventTransmitFollowup(&followup_ind);
@@ -1845,7 +1886,7 @@
 
         nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
 
-        result = request.put_u8(NAN_ATTRIBUTE_PUBLISH_ID, mParams->requestor_instance_id);
+        result = request.put_u32(NAN_ATTRIBUTE_PUBLISH_ID, mParams->requestor_instance_id);
         if (result < 0) {
             ALOGE("%s: Failed to fill instance id = %d, result = %d\n",
                     __func__, mParams->requestor_instance_id, result);
@@ -2018,6 +2059,26 @@
             }
         }
 
+        if (mParams->scid_len) {
+            if (mParams->scid_len != NAN_SCID_INFO_LEN) {
+                ALOGE("%s: Invalid scid len, = %d\n", __func__, mParams->scid_len);
+                return NAN_STATUS_INVALID_PARAM;
+            }
+            result = request.put_u32(NAN_ATTRIBUTE_SCID_LEN,
+                    mParams->scid_len);
+            if (result < 0) {
+                ALOGE("%s: Failed to fill scid len, result = %d\n", __func__, result);
+                return result;
+            }
+
+            result = request.put(NAN_ATTRIBUTE_SCID,
+                    (void *)mParams->scid, mParams->scid_len);
+            if (result < 0) {
+                ALOGE("%s: Failed to fill scid, result = %d\n", __func__, result);
+                return result;
+            }
+        }
+
         request.attr_end(data);
         return WIFI_SUCCESS;
     }
@@ -2163,6 +2224,27 @@
             }
         }
 
+        if (mParams->scid_len) {
+            if (mParams->scid_len != NAN_SCID_INFO_LEN) {
+                ALOGE("%s: Invalid scid len, = %d\n", __func__, mParams->scid_len);
+                return NAN_STATUS_INVALID_PARAM;
+            }
+            result = request.put_u32(NAN_ATTRIBUTE_SCID_LEN,
+                    mParams->scid_len);
+            if (result < 0) {
+                ALOGE("%s: Failed to fill scid len, result = %d\n", __func__, result);
+                return result;
+            }
+
+            prhex(NULL, mParams->scid, mParams->scid_len);
+            result = request.put(NAN_ATTRIBUTE_SCID,
+                    (void *)mParams->scid, mParams->scid_len);
+            if (result < 0) {
+                ALOGE("%s: Failed to fill scid, result = %d\n", __func__, result);
+                return result;
+            }
+        }
+
         request.attr_end(data);
         return WIFI_SUCCESS;
     }
@@ -2226,10 +2308,10 @@
             case NAN_DP_INTERFACE_DELETE:
             case NAN_DP_INITIATOR_RESPONSE:
             case NAN_DP_RESPONDER_RESPONSE:
-            case NAN_DP_END: 
+            case NAN_DP_END:
                 valid = true;
                 break;
-            default: 
+            default:
                 ALOGE("NanDataPathPrmitive::Unknown cmd Response: %d\n", response_type);
                 break;
         }
@@ -2304,8 +2386,8 @@
                     attr_type = it.get_type();
 
                     if (attr_type == NAN_ATTRIBUTE_PUBLISH_ID) {
-                        ALOGI("publish_id: %u", it.get_u16());
-                        ndp_request_event.service_instance_id = it.get_u16();
+                        ALOGI("publish_id: %u\n", it.get_u32());
+                        ndp_request_event.service_instance_id = it.get_u32();
 
                     } else if (attr_type == NAN_ATTRIBUTE_MAC_ADDR) {
                         memcpy(ndp_request_event.peer_disc_mac_addr,
@@ -2314,17 +2396,17 @@
                                 MAC2STR(ndp_request_event.peer_disc_mac_addr));
 
                     } else if (attr_type == NAN_ATTRIBUTE_NDP_ID) {
-                        ALOGI("ndp id: %u", it.get_u32());
+                        ALOGI("ndp id: %u\n", it.get_u32());
                         ndp_request_event.ndp_instance_id = it.get_u32();
 
                     } else if (attr_type == NAN_ATTRIBUTE_SECURITY) {
-                        ALOGI("security: %u",
+                        ALOGI("security: %u\n",
                                 (NanDataPathSecurityCfgStatus)it.get_u8());
                         ndp_request_event.ndp_cfg.security_cfg =
                             (NanDataPathSecurityCfgStatus)it.get_u8();
 
                     } else if (attr_type == NAN_ATTRIBUTE_QOS) {
-                        ALOGI("QoS: %u", (NanDataPathQosCfg)it.get_u8());
+                        ALOGI("QoS: %u\n", (NanDataPathQosCfg)it.get_u8());
                         ndp_request_event.ndp_cfg.qos_cfg = (NanDataPathQosCfg)it.get_u8();
 
                     } else if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN) {
@@ -2336,7 +2418,17 @@
                                 ndp_ind_app_info_len);
                         ndp_request_event.app_info.ndp_app_info
                             [ndp_ind_app_info_len] = '\0';
-                        ALOGI("service info: %s", ndp_request_event.app_info.ndp_app_info);
+                        ALOGI("service info: %s\n", ndp_request_event.app_info.ndp_app_info);
+
+                    } else if (attr_type == NAN_ATTRIBUTE_SCID_LEN) {
+                        ALOGI("scid len: %u\n", it.get_u32());
+                        ndp_request_event.scid_len = it.get_u32();
+
+                    } else if (attr_type == NAN_ATTRIBUTE_SCID) {
+                        memcpy(ndp_request_event.scid, it.get_data(),
+                                ndp_request_event.scid_len);
+                        ndp_request_event.scid[ndp_request_event.scid_len] = '\0';
+                        ALOGI("scid : %s\n", ndp_request_event.scid);
 
                     }
                 }
@@ -2348,6 +2440,7 @@
                 NanDataPathConfirmInd ndp_create_confirmation_event;
                 memset(&ndp_create_confirmation_event, 0, sizeof(NanDataPathConfirmInd));
                 u16 ndp_conf_app_info_len = 0;
+                u8 chan_idx = 0;
                 counters.dp_confirm_evt++;
                 ALOGI("Received NAN_EVENT_DATA_CONFIRMATION\n");
 
@@ -2384,9 +2477,29 @@
                         ALOGI("reason code %u", (NanDataPathResponseCode)it.get_u8());
                         ndp_create_confirmation_event.rsp_code =
                             (NanDataPathResponseCode)it.get_u8();
+                    } else if (attr_type == NAN_ATTRIBUTE_NUM_CHANNELS) {
+                        ALOGI("num channels %u", it.get_u32());
+                        if (it.get_u32() <= NAN_MAX_CHANNEL_INFO_SUPPORTED) {
+                            ndp_create_confirmation_event.num_channels = it.get_u32();
+                        } else {
+                            ndp_create_confirmation_event.num_channels =
+                                NAN_MAX_CHANNEL_INFO_SUPPORTED;
+                            ALOGE("num channels reset to max allowed %u",
+                                ndp_create_confirmation_event.num_channels);
+                        }
+                    } else if (attr_type == NAN_ATTRIBUTE_CHANNEL_INFO) {
+                        ALOGI("Channel info \n");
+                        memcpy((u8 *)ndp_create_confirmation_event.channel_info, it.get_data(),
+                            ndp_create_confirmation_event.num_channels * sizeof(NanChannelInfo));
+                        while (chan_idx < ndp_create_confirmation_event.num_channels) {
+                            ALOGI("channel: %u, Bandwidth: %u, nss: %u\n",
+                                ndp_create_confirmation_event.channel_info[chan_idx].channel,
+                                ndp_create_confirmation_event.channel_info[chan_idx].bandwidth,
+                                ndp_create_confirmation_event.channel_info[chan_idx].nss);
+                            chan_idx++;
+                        }
                     }
                 }
-
                 GET_NAN_HANDLE(info)->mHandlers.EventDataConfirm(&ndp_create_confirmation_event);
                 break;
             }
@@ -2431,6 +2544,7 @@
     wifi_interface_handle mIface;
     NanRequestType mType;
     u32 mVersion;
+    u8 mChreNan;
 
     public:
     NanMacControl(wifi_interface_handle iface, int id,
@@ -2470,6 +2584,10 @@
         mParams = params;
     }
 
+    void setChreNan(u8 chre_nan) {
+        mChreNan = chre_nan;
+    }
+
     int createRequest(WifiRequest& request) {
         ALOGI("NAN CMD: %s\n", NanCmdToString(mType));
         if (mType == NAN_REQUEST_ENABLE) {
@@ -2484,10 +2602,6 @@
             /* TODO: Not yet implemented */
         } else if (mType == NAN_VERSION_INFO) {
             return createVersionRequest(request);
-#ifdef NAN_CLUSTER_MERGE
-        } else if (mType == NAN_REQUEST_ENABLE_MERGE) {
-            return createEnableMergeRequest(request, (NanEnableMergeRequest *)mParams);
-#endif /* NAN_CLUSTER_MERGE */
         } else {
             ALOGE("Unknown Nan request\n");
         }
@@ -2853,6 +2967,32 @@
             }
         }
 
+        if (mParams->config_enable_instant_mode) {
+            result = request.put_u32(NAN_ATTRIBUTE_INSTANT_MODE_ENABLE,
+                    mParams->enable_instant_mode);
+            if (result < 0) {
+                ALOGE("%s: Failing to fill enable instant mode, result = %d\n", __func__, result);
+                return result;
+            }
+        }
+
+        if (mParams->enable_instant_mode && mParams->config_instant_mode_channel
+            && mParams->instant_mode_channel) {
+            result = request.put_u32(NAN_ATTRIBUTE_INSTANT_COMM_CHAN,
+                    mParams->instant_mode_channel);
+            if (result < 0) {
+                ALOGE("%s: Failing in config instant channel, result = %d\n", __func__, result);
+                return result;
+            }
+            ALOGI("%s: instant mode channel = %d\n", __func__, mParams->instant_mode_channel);
+        }
+
+        result = request.put_u8(NAN_ATTRIBUTE_CHRE_REQUEST, mChreNan);
+        if (result < 0) {
+            ALOGE("%s: Failing in config chreNan, result = %d\n", __func__, result);
+            return result;
+        }
+
         request.attr_end(data);
         NAN_DBG_EXIT();
         return WIFI_SUCCESS;
@@ -2869,32 +3009,18 @@
 
         nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
 
+        result = request.put_u8(NAN_ATTRIBUTE_CHRE_REQUEST, mChreNan);
+        if (result < 0) {
+            ALOGE("%s: Failing in config chreNan, result = %d\n", __func__, result);
+            return result;
+        }
+
         request.attr_end(data);
 
         NAN_DBG_EXIT();
         return result;
     }
 
-#ifdef NAN_CLUSTER_MERGE
-    int createEnableMergeRequest(WifiRequest& request,
-            NanEnableMergeRequest *mParams) {
-        int result = request.create(GOOGLE_OUI, NAN_SUBCMD_ENABLE_MERGE);
-        if (result < 0) {
-            ALOGE("%s: Fail to create request\n", __func__);
-            return result;
-        }
-        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
-        result = request.put_u8(NAN_ATTRIBUTE_ENABLE_MERGE, mParams->enable);
-        if (result < 0) {
-            ALOGE("%s: Failing in enable merge, result = %d\n", __func__, result);
-            return result;
-        }
-        request.attr_end(data);
-        NAN_DBG_EXIT();
-        return WIFI_SUCCESS;
-    }
-#endif /* NAN_CLUSTER_MERGE */
-
     int createConfigRequest(WifiRequest& request, NanConfigRequest *mParams) {
 
         int result = request.create(GOOGLE_OUI, NAN_SUBCMD_CONFIG);
@@ -3136,6 +3262,27 @@
                 return result;
             }
         }
+
+        if (mParams->config_enable_instant_mode) {
+            result = request.put_u32(NAN_ATTRIBUTE_INSTANT_MODE_ENABLE,
+                    mParams->enable_instant_mode);
+            if (result < 0) {
+                ALOGE("%s: Failing to fill enable instant mode, result = %d\n", __func__, result);
+                return result;
+            }
+        }
+
+        if (mParams->enable_instant_mode && mParams->config_instant_mode_channel
+            && mParams->instant_mode_channel) {
+            result = request.put_u32(NAN_ATTRIBUTE_INSTANT_COMM_CHAN,
+                    mParams->instant_mode_channel);
+            if (result < 0) {
+                ALOGE("%s: Failing in config instant channel, result = %d\n", __func__, result);
+                return result;
+            }
+            ALOGI("%s: instant mode channel = %d\n", __func__, mParams->instant_mode_channel);
+        }
+
         request.attr_end(data);
         NAN_DBG_EXIT();
         return WIFI_SUCCESS;
@@ -3193,6 +3340,10 @@
             return NL_SKIP;
         }
 
+        if (mChreNan) {
+            return NL_SKIP;
+        }
+
         rsp_vndr_data = (nan_hal_resp_t *)reply.get_vendor_data();
         ALOGI("NanMacControl::handleResponse\n");
         if (mType == NAN_VERSION_INFO) {
@@ -3258,7 +3409,6 @@
     }
 
     int handleEvent(WifiEvent& event) {
-        u16 inst_id;
         u32 ndp_instance_id = 0;
         int event_id = event.get_vendor_subcmd();
         nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
@@ -3273,16 +3423,19 @@
             return NL_SKIP;
         }
 
+        if (mChreNan) {
+            return NL_SKIP;
+        }
+
         for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
             attr_type = it.get_type();
 
             if (it.get_type() == NAN_ATTRIBUTE_HANDLE) {
-                inst_id = it.get_u8();
             } else if (it.get_type() == NAN_ATTRIBUTE_NDP_ID) {
                 ndp_instance_id = it.get_u32();
                 ALOGI("handleEvent: ndp_instance_id = [%d]\n", ndp_instance_id);
             } else if (attr_type == NAN_ATTRIBUTE_CMD_RESP_DATA) {
-                ALOGI("sizeof cmd response data: %d, it.get_len() = %d\n",
+                ALOGI("sizeof cmd response data: %ld, it.get_len() = %d\n",
                         sizeof(nan_hal_resp_t), it.get_len());
                 if (it.get_len() == sizeof(nan_hal_resp_t)) {
                     rsp_vndr_data = (nan_hal_resp_t*)it.get_data();
@@ -3316,12 +3469,17 @@
                 ALOGE("%s: dp_primitive is no more available\n", __func__);
             }
             return NL_SKIP;
-        } else {
-            if (is_cmd_response(event_id)) {
-                ALOGE("Handling cmd response asynchronously\n");
-                handleAsyncResponse(rsp_vndr_data);
-            }
-        }
+	} else {
+		if (is_cmd_response(event_id)) {
+			ALOGE("Handling cmd response asynchronously\n");
+			if (rsp_vndr_data != NULL) {
+				handleAsyncResponse(rsp_vndr_data);
+			} else {
+				ALOGE("Wrong response data, rsp_vndr_data is NULL\n");
+				return NL_SKIP;
+			}
+		}
+	}
 
         switch(event_id) {
             case NAN_EVENT_DE_EVENT:
@@ -3395,9 +3553,10 @@
                         disabled_ind.reason = (NanStatusType)it.get_u8();
                         ALOGI("Nan Disable:status %u", disabled_ind.reason);
                     } else if (attr_type == NAN_ATTRIBUTE_REASON) {
-                        memcpy(disabled_ind.nan_reason, it.get_data(),
-                                sizeof(disabled_ind.nan_reason));
-                        ALOGI("Disable nan reason: %s", disabled_ind.nan_reason);
+                        u8 len = min(it.get_len(), sizeof(disabled_ind.nan_reason));
+                        memcpy(disabled_ind.nan_reason, it.get_data(), len);
+                        ALOGI("Disabled nan reason: %s, len = %d\n",
+                            disabled_ind.nan_reason, len);
                     }
                 }
 
@@ -3415,7 +3574,7 @@
                     attr_type = it.get_type();
 
                     if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN) {
-                        sdfInd.data.frame_len = it.get_u32();
+                        sdfInd.data.frame_len = it.get_u16();
                         if (sdfInd.data.frame_len > NAN_MAX_FRAME_DATA_LEN) {
                             sdfInd.data.frame_len = NAN_MAX_FRAME_DATA_LEN;
                         }
@@ -3450,6 +3609,7 @@
             unregisterVendorHandler(GOOGLE_OUI, i);
         }
         unregisterVendorHandler(GOOGLE_OUI, NAN_ASYNC_RESPONSE_DISABLED);
+        unregisterVendorHandler(GOOGLE_OUI, NAN_EVENT_MATCH_EXPIRY);
     }
     void registerNanVendorEvents()
     {
@@ -3458,6 +3618,7 @@
             registerVendorHandler(GOOGLE_OUI, i);
         }
         registerVendorHandler(GOOGLE_OUI, NAN_ASYNC_RESPONSE_DISABLED);
+        registerVendorHandler(GOOGLE_OUI, NAN_EVENT_MATCH_EXPIRY);
     }
 };
 
@@ -3550,8 +3711,6 @@
             C2S(NAN_DATA_PATH_IFACE_UP)
             C2S(NAN_DATA_PATH_SEC_INFO)
             C2S(NAN_VERSION_INFO)
-            C2S(NAN_REQUEST_ENABLE_MERGE)
-
         default:
             return "UNKNOWN_NAN_CMD";
     }
@@ -3737,7 +3896,6 @@
     return WIFI_SUCCESS;
 }
 
-#ifdef CONFIG_BRCM
 static int dump_NanEnableRequest(NanEnableRequest* msg)
 {
     ALOGI("%s: Dump NanEnableRequest msg:\n", __func__);
@@ -3831,10 +3989,19 @@
     if (msg->config_disc_mac_addr_randomization) {
         ALOGI("disc_mac_addr_rand_interval_sec =%u\n", msg->disc_mac_addr_rand_interval_sec);
     }
+    ALOGI("config_enable_instant_mode =%u\n", msg->config_enable_instant_mode);
+    if (msg->config_enable_instant_mode) {
+        ALOGI("enable_instant_mode =%u\n", msg->enable_instant_mode);
+    }
+    ALOGI("config_instant_mode_channel=%u\n", msg->config_instant_mode_channel);
+    if (msg->config_instant_mode_channel) {
+        ALOGI("instant_mode_channel=%u\n", msg->instant_mode_channel);
+    }
 
     return WIFI_SUCCESS;
 }
 
+#ifdef CONFIG_BRCM
 static int dump_NanConfigRequestRequest(NanConfigRequest* msg)
 {
     ALOGI("%s: Dump NanConfigRequest msg:\n", __func__);
@@ -3896,13 +4063,21 @@
     if (msg->config_disc_mac_addr_randomization) {
         ALOGI("disc_mac_addr_rand_interval_sec =%u\n", msg->disc_mac_addr_rand_interval_sec);
     }
+    ALOGI("config_enable_instant_mode =%u\n", msg->config_enable_instant_mode);
+    if (msg->config_enable_instant_mode) {
+        ALOGI("enable_instant_mode =%u\n", msg->enable_instant_mode);
+    }
+    ALOGI("config_instant_mode_channel=%u\n", msg->config_instant_mode_channel);
+    if (msg->config_instant_mode_channel) {
+        ALOGI("instant_mode_channel=%u\n", msg->instant_mode_channel);
+    }
+
     return WIFI_SUCCESS;
 }
 
 static int dump_NanPublishRequest(NanPublishRequest* msg)
 {
     ALOGI("%s: Dump NanPublishRequest msg:\n", __func__);
-    u8 i = 0;
     if (msg == NULL) {
         ALOGE("Invalid msg\n");
         return WIFI_ERROR_UNKNOWN;
@@ -3916,17 +4091,21 @@
     ALOGI("publish_match_indicator=%u\n", msg->publish_match_indicator);
     ALOGI("service_responder_policy=%u\n", msg->service_responder_policy);
     ALOGI("service_name_len=%u\n", msg->service_name_len);
-    if (msg->service_name_len)
+    if (msg->service_name_len) {
         ALOGI("service_name=%s\n", msg->service_name);
+    }
     ALOGI("service_specific_info_len=%u\n", msg->service_specific_info_len);
-    if (msg->service_specific_info_len)
+    if (msg->service_specific_info_len) {
         ALOGI("service_specific_info=%s\n", msg->service_specific_info);
+    }
     ALOGI("rx_match_filter_len=%u\n", msg->rx_match_filter_len);
-    if (msg->rx_match_filter_len)
+    if (msg->rx_match_filter_len) {
         prhex("rx_match_filter", msg->rx_match_filter, msg->rx_match_filter_len);
+    }
     ALOGI("tx_match_filter_len=%u\n", msg->tx_match_filter_len);
-    if (msg->tx_match_filter_len)
+    if (msg->tx_match_filter_len) {
         prhex("tx_match_filter", msg->tx_match_filter, msg->tx_match_filter_len);
+    }
     ALOGI("rssi_threshold_flag=%u\n", msg->rssi_threshold_flag);
     ALOGI("connmap=%u\n", msg->connmap);
     ALOGI("recv_indication_cfg=%u\n", msg->recv_indication_cfg);
@@ -3935,8 +4114,9 @@
     ALOGI("key_info: pmk info=%s\n", msg->key_info.body.pmk_info.pmk);
     ALOGI("key_info: passphrase_info=%s\n", msg->key_info.body.passphrase_info.passphrase);
     ALOGI("scid_len=%u\n", msg->scid_len);
-    if (msg->scid_len)
+    if (msg->scid_len) {
         ALOGI("scid=%s\n", msg->scid);
+    }
     ALOGI("NanSdeaCtrlParams NdpType=%u\n", msg->sdea_params.ndp_type);
     ALOGI("NanSdeaCtrlParams security_cfg=%u\n", msg->sdea_params.security_cfg);
     ALOGI("NanSdeaCtrlParams ranging_state=%u\n", msg->sdea_params.ranging_state);
@@ -3949,8 +4129,9 @@
     ALOGI("range_response_cfg=%u\n", msg->range_response_cfg.ranging_response);
 
     ALOGI("sdea_service_specific_info_len=%u\n", msg->sdea_service_specific_info_len);
-    if (msg->sdea_service_specific_info_len)
+    if (msg->sdea_service_specific_info_len) {
         ALOGI("sdea_service_specific_info=%s\n", msg->sdea_service_specific_info);
+    }
 
     return WIFI_SUCCESS;
 }
@@ -3999,8 +4180,9 @@
     ALOGI("key_info: pmk info=%s\n", msg->key_info.body.pmk_info.pmk);
     ALOGI("key_info: passphrase_info=%s\n", msg->key_info.body.passphrase_info.passphrase);
     ALOGI("scid_len=%u\n", msg->scid_len);
-    if (msg->scid_len)
+    if (msg->scid_len) {
         ALOGI("scid=%s\n", msg->scid);
+    }
     ALOGI("NanSdeaCtrlParams NdpType=%u\n", msg->sdea_params.ndp_type);
     ALOGI("NanSdeaCtrlParams security_cfg=%u\n", msg->sdea_params.security_cfg);
     ALOGI("NanSdeaCtrlParams ranging_state=%u\n", msg->sdea_params.ranging_state);
@@ -4022,7 +4204,6 @@
 static int dump_NanTransmitFollowupRequest(NanTransmitFollowupRequest* msg)
 {
     ALOGI("%s: Dump NanTransmitFollowupRequest msg:\n", __func__);
-    u8 i = 0;
     if (msg == NULL) {
         ALOGE("Invalid msg\n");
         return WIFI_ERROR_UNKNOWN;
@@ -4068,6 +4249,10 @@
     ALOGI("key_info: key_type =%u\n", msg->key_info.key_type);
     ALOGI("key_info: pmk info=%s\n", msg->key_info.body.pmk_info.pmk);
     ALOGI("key_info: passphrase_info=%s\n", msg->key_info.body.passphrase_info.passphrase);
+    ALOGI("scid_len=%u\n", msg->scid_len);
+    if (msg->scid_len) {
+        ALOGI("scid=%s\n", msg->scid);
+    }
     if (msg->service_name_len) {
         ALOGI("service_name=%s\n", msg->service_name);
     }
@@ -4098,6 +4283,10 @@
     ALOGI("key_info: pmk info=%s\n", msg->key_info.body.pmk_info.pmk);
     ALOGI("key_info: passphrase_info=%s\n", msg->key_info.body.passphrase_info.passphrase);
     ALOGI("service_name_len=%u\n", msg->service_name_len);
+    ALOGI("scid_len=%u\n", msg->scid_len);
+    if (msg->scid_len) {
+        ALOGI("scid=%s\n", msg->scid);
+    }
     if (msg->service_name_len) {
         ALOGI("service_name=%s\n", msg->service_name);
     }
@@ -4111,32 +4300,66 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-wifi_error nan_enable_request(transaction_id id,
-        wifi_interface_handle iface, NanEnableRequest* msg)
+wifi_error nan_cmn_enabe_request(transaction_id id,
+        NanMacControl *cmd, NanEnableRequest* msg)
 {
     wifi_error ret = WIFI_SUCCESS;
-    wifi_handle handle = getWifiHandle(iface);
-    NanRequestType cmdType = NAN_REQUEST_ENABLE;
-
-    ALOGI("Enabling Nan, Handle = %p\n", handle);
-
 #ifdef CONFIG_BRCM
     // check up nan enable params from Nan manager level
     dump_NanEnableRequest(msg);
 #endif /* CONFIG_BRCM */
     nan_reset_dbg_counters();
-    /* XXX: WAR posting async enable response */
-    //NanMacControl *cmd = new NanMacControl(iface, id, (void *)msg, cmdType);
-    NanMacControl *cmd = (NanMacControl*)(info.nan_mac_control);
-    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
-    cmd->setType(cmdType);
+
+    cmd->setType(NAN_REQUEST_ENABLE);
     cmd->setId(id);
     cmd->setMsg((void *)msg);
+
     ret = (wifi_error)cmd->start();
     if (ret != WIFI_SUCCESS) {
         ALOGE("%s : failed in start, error = %d\n", __func__, ret);
     }
-    //cmd->releaseRef();
+
+    return ret;
+}
+
+wifi_error nan_enable_request(transaction_id id,
+        wifi_interface_handle iface, NanEnableRequest* msg)
+{
+    wifi_error ret = WIFI_SUCCESS;
+   hal_info *h_info = getHalInfo(iface);
+
+	ALOGE("nan_enable_request: nan_state = %d\n", h_info->nan_state);
+
+#ifdef CHRE_NAN
+    //check if host NAN is pre-empting CHRE NAN
+    if (h_info->nan_state == NAN_STATE_CHRE) {
+        /* notify pre-empt to chre */
+        if (h_info->chre_nan_cb.on_chre_nan_rtt_change != NULL) {
+            h_info->chre_nan_cb.on_chre_nan_rtt_change(CHRE_PREMPTED);
+        }
+        /* first disable NAN for chre */
+        ret = nan_chre_disable_request(1, iface);
+        if (ret != WIFI_SUCCESS) {
+            ALOGE("Failed to disable NAN for CHRE ret %d\n", ret);
+            return ret;
+        }
+    }
+
+    /* notify unavailable status to chre */
+    if (h_info->chre_nan_cb.on_chre_nan_rtt_change != NULL) {
+        h_info->chre_nan_cb.on_chre_nan_rtt_change(CHRE_UNAVAILABLE);
+    }
+#endif /* CHRE_NAN */
+
+    NanMacControl *cmd = (NanMacControl*)(info.nan_mac_control);
+    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+    cmd->setChreNan(0);
+    ret = nan_cmn_enabe_request(id, cmd, msg);
+
+    if (ret == WIFI_SUCCESS) {
+        h_info->nan_state = NAN_STATE_AP;
+    }
+
     return ret;
 }
 
@@ -4151,16 +4374,40 @@
     ALOGI("Num Transmit Success %d\n", counters.transmit_txs);
 }
 
+wifi_error nan_cmn_disable_request(transaction_id id, NanMacControl *mac)
+{
+    wifi_error ret = WIFI_SUCCESS;
+
+    nan_dump_dbg_counters();
+
+    mac->setType(NAN_REQUEST_DISABLE);
+    ret = (wifi_error)mac->cancel();
+    if (ret != WIFI_SUCCESS) {
+        ALOGE("cancel failed, error = %d\n", ret);
+    } else {
+        ALOGE("Deinitializing Nan Mac Control = %p\n", mac);
+    }
+    mac->releaseRef();
+
+    return ret;
+}
 wifi_error nan_disable_request(transaction_id id,
         wifi_interface_handle iface)
 {
-    wifi_handle handle = getWifiHandle(iface);
-    NanRequestType cmdType = NAN_REQUEST_DISABLE;
     wifi_error ret = WIFI_SUCCESS;
+    hal_info *h_info = getHalInfo(iface);
 
-    ALOGI("Disabling Nan, Handle = %p\n", handle);
-    NanMacControl *cmd = new NanMacControl(iface, id, NULL, cmdType);
+    ALOGE("nan_disable_request: nan_state %d\n", h_info->nan_state);
+
+    if (h_info->nan_state == NAN_STATE_CHRE) {
+        ALOGE("nan_disable_request: Not enabled for AP.. return\n");
+        return ret;
+    }
+
     NanMacControl *mac_prim = (NanMacControl*)(info.nan_mac_control);
+    NanMacControl *cmd = new NanMacControl(iface, id, NULL, NAN_REQUEST_LAST);
+
+    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
 
     if (id != NAN_MAC_INVALID_TRANSID) {
         ALOGE("Disable NAN MAC transId= %d\n", id);
@@ -4169,17 +4416,15 @@
         ALOGE("Invalid transId= %d cur= %d\n", id, mac_prim->getId());
     }
 
-    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
-
-    nan_dump_dbg_counters();
-
-    ret = (wifi_error)cmd->cancel();
-    if (ret != WIFI_SUCCESS) {
-        ALOGE("cancel failed, error = %d\n", ret);
-    } else {
-        ALOGE("Deinitializing Nan Mac Control = %p\n", cmd);
+    cmd->setChreNan(0);
+    ret = nan_cmn_disable_request(id, cmd);
+    if (ret == WIFI_SUCCESS) {
+        h_info->nan_state = NAN_STATE_DISABLED;
+        /* notify pre-empt / unavailable status to chre */
+        if (h_info->chre_nan_cb.on_chre_nan_rtt_change != NULL) {
+            h_info->chre_nan_cb.on_chre_nan_rtt_change(CHRE_AVAILABLE);
+        }
     }
-    cmd->releaseRef();
     return ret;
 }
 
@@ -4211,7 +4456,6 @@
 {
     wifi_error ret = WIFI_SUCCESS;
     NanDiscEnginePrimitive *cmd;
-    wifi_handle handle = getWifiHandle(iface);
     NanRequestType cmdType = NAN_REQUEST_PUBLISH_CANCEL;
 
     ALOGE("Cancellling publish request %d\n", msg->publish_id);
@@ -4258,7 +4502,6 @@
 {
     wifi_error ret = WIFI_SUCCESS;
     NanDiscEnginePrimitive *cmd;
-    wifi_handle handle = getWifiHandle(iface);
     NanRequestType cmdType = NAN_REQUEST_SUBSCRIBE_CANCEL;
 
     ALOGE("creating new instance + %d\n", msg->subscribe_id);
@@ -4274,36 +4517,11 @@
     return ret;
 }
 
-#ifdef NAN_CLUSTER_MERGE
-/*  Function to send NAN cluster merge enable/disable request to the wifi driver.*/
-wifi_error nan_enable_cluster_merge_request(transaction_id id,
-        wifi_interface_handle iface, NanEnableMergeRequest* msg)
-{
-    wifi_error ret = WIFI_SUCCESS;
-    wifi_handle handle = getWifiHandle(iface);
-    NanRequestType cmdType = NAN_REQUEST_ENABLE_MERGE;
-
-    NanMacControl *cmd = new NanMacControl(iface, id, (void *)msg, cmdType);
-    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
-    cmd->setType(cmdType);
-    cmd->setId(id);
-    cmd->setMsg((void *)msg);
-    ret = (wifi_error)cmd->start();
-    if (ret != WIFI_SUCCESS) {
-        ALOGE("%s :enable nan cluster merge failed in start, error = %d\n", __func__, ret);
-    }
-    cmd->releaseRef();
-
-    return ret;
-}
-#endif /* NAN_CLUSTER_MERGE */
-
 /*  Function to send nan transmit followup Request to the wifi driver.*/
 wifi_error nan_transmit_followup_request(transaction_id id,
         wifi_interface_handle iface, NanTransmitFollowupRequest* msg)
 {
     NanDiscEnginePrimitive *cmd = NULL;
-    wifi_handle handle = getWifiHandle(iface);
     NanRequestType cmdType = NAN_REQUEST_TRANSMIT_FOLLOWUP;
     wifi_error ret = WIFI_SUCCESS;
 
@@ -4330,9 +4548,9 @@
     wifi_handle handle = getWifiHandle(iface);
 
     ALOGI("Nan Stats, halHandle = %p", handle);
-    NanRequestType cmdType = NAN_REQUEST_STATS;
 
 #ifdef NOT_SUPPORTED
+    NanRequestType cmdType = NAN_REQUEST_STATS;
     wifi_error ret = WIFI_SUCCESS;
     NanCommand *cmd = new NanCommand(iface, id, (void *)msg, cmdType);
     NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
@@ -4383,9 +4601,9 @@
     wifi_handle handle = getWifiHandle(iface);
 
     ALOGI("Nan TCA, halHandle = %p", handle);
-    NanRequestType cmdType = NAN_REQUEST_TCA;
 
 #ifdef NOT_SUPPORTED
+    NanRequestType cmdType = NAN_REQUEST_TCA;
     wifi_error ret = WIFI_SUCCESS;
     NanCommand *cmd = new NanCommand(iface, id, (void *)msg, cmdType);
     NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
@@ -4480,6 +4698,7 @@
         delete GET_NAN_HANDLE(info);
         NAN_HANDLE(info) = NULL;
     }
+    ALOGI("wifi nan internal clean up done");
     return WIFI_SUCCESS;
 }
 wifi_error nan_register_handler(wifi_interface_handle iface,
@@ -4552,6 +4771,7 @@
                 unregisterVendorHandler(GOOGLE_OUI, i);
             }
             unregisterVendorHandler(GOOGLE_OUI, NAN_ASYNC_RESPONSE_DISABLED);
+            unregisterVendorHandler(GOOGLE_OUI, NAN_EVENT_MATCH_EXPIRY);
         }
         void registerNanVendorEvents()
         {
@@ -4560,6 +4780,7 @@
                 registerVendorHandler(GOOGLE_OUI, i);
             }
             registerVendorHandler(GOOGLE_OUI, NAN_ASYNC_RESPONSE_DISABLED);
+            registerVendorHandler(GOOGLE_OUI, NAN_EVENT_MATCH_EXPIRY);
         }
 
         int handleEvent(WifiEvent& event) {
@@ -4623,9 +4844,10 @@
                             disabled_ind.reason = (NanStatusType)it.get_u8();
                             ALOGI("Nan Disable:status %u", disabled_ind.reason);
                         } else if (attr_type == NAN_ATTRIBUTE_REASON) {
-                            memcpy(disabled_ind.nan_reason, it.get_data(),
-                                    sizeof(disabled_ind.nan_reason));
-                            ALOGI("nan disable reason: %s", disabled_ind.nan_reason);
+                            u8 len = min(it.get_len(), sizeof(disabled_ind.nan_reason));
+                            memcpy(disabled_ind.nan_reason, it.get_data(), len);
+                            ALOGI("nan disabled reason: %s, len = %d\n",
+                                disabled_ind.nan_reason, len);
                         }
                     }
 
@@ -4642,15 +4864,16 @@
                         attr_type = it.get_type();
 
                         if (attr_type == NAN_ATTRIBUTE_PUBLISH_ID) {
-                            pub_term_event.publish_id = it.get_u16();
+                            pub_term_event.publish_id = it.get_u32();
                             ALOGI("pub id %u", pub_term_event.publish_id);
                         } else if (attr_type == NAN_ATTRIBUTE_STATUS) {
                             pub_term_event.reason = (NanStatusType)it.get_u8();
                             ALOGI("pub termination status %u", pub_term_event.reason);
                         } else if (attr_type == NAN_ATTRIBUTE_REASON) {
-                            memcpy(pub_term_event.nan_reason, it.get_data(),
-                                    sizeof(pub_term_event.nan_reason));
-                            ALOGI("Pub termination nan reason: %s", pub_term_event.nan_reason);
+                            u8 len = min(it.get_len(), sizeof(pub_term_event.nan_reason));
+                            memcpy(pub_term_event.nan_reason, it.get_data(), len);
+                            ALOGI("Pub termination nan reason: %s, len = %d\n",
+                                pub_term_event.nan_reason, len);
                         } else {
                             ALOGE("Unknown attr\n");
                         }
@@ -4778,9 +5001,10 @@
                             sub_term_event.reason = (NanStatusType)it.get_u8();
                             ALOGI("sub termination status %u", sub_term_event.reason);
                         } else if (attr_type == NAN_ATTRIBUTE_REASON) {
-                            memcpy(sub_term_event.nan_reason, it.get_data(),
-                                    sizeof(sub_term_event.nan_reason));
-                            ALOGI("sub termination nan reason: %s", sub_term_event.nan_reason);
+                            u8 len = min(it.get_len(), sizeof(sub_term_event.nan_reason));
+                            memcpy(sub_term_event.nan_reason, it.get_data(), len);
+                            ALOGI("sub termination nan reason: %s, len = %d\n",
+                                sub_term_event.nan_reason, len);
                         } else {
                             ALOGE("Unknown attr: %u\n", attr_type);
                         }
@@ -4789,6 +5013,9 @@
                     GET_NAN_HANDLE(info)->mHandlers.EventSubscribeTerminated(&sub_term_event);
                     break;
                 }
+                case NAN_EVENT_MATCH_EXPIRY:
+                    HandleExpiryEvent(info, vendor_data);
+                    break;
                 case NAN_EVENT_FOLLOWUP: {
                     NanFollowupInd followup_event;
                     memset(&followup_event, 0, sizeof(NanFollowupInd));
@@ -4837,7 +5064,7 @@
                         attr_type = it.get_type();
 
                         if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN) {
-                            sdfInd.data.frame_len = it.get_u32();
+                            sdfInd.data.frame_len = it.get_u16();
                             if (sdfInd.data.frame_len > NAN_MAX_FRAME_DATA_LEN) {
                                 sdfInd.data.frame_len = NAN_MAX_FRAME_DATA_LEN;
                             }
@@ -4893,8 +5120,8 @@
                         attr_type = it.get_type();
 
                         if (attr_type == NAN_ATTRIBUTE_PUBLISH_ID) {
-                            ALOGI("publish_id: %u\n", it.get_u16());
-                            ndp_request_event.service_instance_id = it.get_u16();
+                            ALOGI("publish_id: %u\n", it.get_u32());
+                            ndp_request_event.service_instance_id = it.get_u32();
 
                         } else if (attr_type == NAN_ATTRIBUTE_MAC_ADDR) {
                             memcpy(ndp_request_event.peer_disc_mac_addr,
@@ -4926,6 +5153,15 @@
                             ndp_request_event.app_info.ndp_app_info[ndp_ind_app_info_len] = '\0';
                             ALOGI("service info: %s\n", ndp_request_event.app_info.ndp_app_info);
 
+                        } else if (attr_type == NAN_ATTRIBUTE_SCID_LEN) {
+                            ALOGI("scid length %d\n", it.get_u32());
+                            ndp_request_event.scid_len= it.get_u32();
+
+                        } else if (attr_type == NAN_ATTRIBUTE_SCID) {
+                            memcpy(ndp_request_event.scid, it.get_data(),
+                                ndp_request_event.scid_len);
+                            ndp_request_event.scid[ndp_request_event.scid_len] = '\0';
+                            ALOGI("scid: %s\n", ndp_request_event.scid);
                         }
                     }
 
@@ -5014,9 +5250,10 @@
                         } else if (attr_type == NAN_ATTRIBUTE_STATUS) {
                             followup_ind.reason = (NanStatusType)it.get_u8();
                         } else if (attr_type == NAN_ATTRIBUTE_REASON) {
-                            memcpy(followup_ind.nan_reason, it.get_data(),
-                                    sizeof(followup_ind.nan_reason));
-                            ALOGI("nan transmit followup ind: reason: %s", followup_ind.nan_reason);
+                            u8 len = min(it.get_len(), sizeof(followup_ind.nan_reason));
+                            memcpy(followup_ind.nan_reason, it.get_data(), len);
+                            ALOGI("nan transmit followup ind: reason: %s, len = %d\n",
+                               followup_ind.nan_reason, len);
                         }
                     }
 
@@ -5034,7 +5271,6 @@
 /* To see event prints in console */
 wifi_error nan_event_check_request(transaction_id id, wifi_interface_handle iface)
 {
-    wifi_handle handle = getWifiHandle(iface);
     NanEventCap *cmd = new NanEventCap(iface, id);
     if (cmd == NULL) {
         return WIFI_ERROR_NOT_SUPPORTED;
@@ -5047,7 +5283,6 @@
         wifi_interface_handle iface, char* iface_name)
 {
     wifi_error ret = WIFI_SUCCESS;
-    wifi_handle handle = getWifiHandle(iface);
     NAN_DBG_ENTER();
 
     NanRequestType cmdType = NAN_DATA_PATH_IFACE_CREATE;
@@ -5070,7 +5305,6 @@
         wifi_interface_handle iface, char* iface_name)
 {
     wifi_error ret = WIFI_SUCCESS;
-    wifi_handle handle = getWifiHandle(iface);
     NAN_DBG_ENTER();
 
     NanRequestType cmdType = NAN_DATA_PATH_IFACE_DELETE;
@@ -5093,7 +5327,6 @@
         wifi_interface_handle iface, NanDataPathInitiatorRequest* msg)
 {
     wifi_error ret = WIFI_SUCCESS;
-    wifi_handle handle = getWifiHandle(iface);
 
     NAN_DBG_ENTER();
     NanRequestType cmdType;
@@ -5179,7 +5412,6 @@
         wifi_interface_handle iface, NanDataPathIndicationResponse* msg)
 {
     wifi_error ret = WIFI_SUCCESS;
-    wifi_handle handle = getWifiHandle(iface);
     NAN_DBG_ENTER();
     NanRequestType cmdType;
     u8 pub_nmi[NAN_MAC_ADDR_LEN] = {0};
@@ -5275,7 +5507,6 @@
 {
     wifi_error ret = WIFI_SUCCESS;
     NanDataPathPrimitive *cmd;
-    wifi_handle handle = getWifiHandle(iface);
     NanRequestType cmdType = NAN_DATA_PATH_END;
     NAN_DBG_ENTER();
 
@@ -5290,3 +5521,89 @@
     NAN_DBG_EXIT();
     return ret;
 }
+
+wifi_error nan_chre_enable_request(transaction_id id,
+        wifi_interface_handle iface, NanEnableRequest* msg)
+{
+    wifi_error ret = WIFI_SUCCESS;
+    NanEnableRequest def_msg;
+    hal_info *h_info = getHalInfo(iface);
+
+    ALOGI("nan_chre_enable_request: nan_state %d\n", h_info->nan_state);
+
+    if (h_info->nan_state == NAN_STATE_CHRE) {
+        return WIFI_SUCCESS;
+    } else if (h_info->nan_state == NAN_STATE_AP) {
+        ALOGE("nan_chre_enable_request: Nan is enabled for AP. Fail CHRE request\n");
+        return WIFI_ERROR_BUSY;
+    }
+
+    NanMacControl *mac = new NanMacControl(iface, 0, NULL, NAN_REQUEST_LAST);
+    NULL_CHECK_RETURN(mac, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+
+    mac->setChreNan(1);
+    if (msg == NULL) {
+        /* default enable params */
+        ALOGI("Input Enable config is NULL, use default config\n");
+        memset(&def_msg, 0, sizeof(def_msg));
+        def_msg.hop_count_limit_val = 5;
+        def_msg.config_2dot4g_support = 1;
+        def_msg.support_2dot4g_val = 1;
+        def_msg.config_2dot4g_beacons = 1;
+        def_msg.beacon_2dot4g_val = 1;
+        def_msg.config_2dot4g_sdf = 1;
+        def_msg.sdf_2dot4g_val = 1;
+        def_msg.config_disc_mac_addr_randomization = true;
+        def_msg.disc_mac_addr_rand_interval_sec = 0;
+        def_msg.config_ndpe_attr = false;
+        ret = nan_cmn_enabe_request(id, mac, &def_msg);
+    } else {
+        ret = nan_cmn_enabe_request(id, mac, msg);
+    }
+
+    if (ret == WIFI_SUCCESS) {
+        h_info->nan_state = NAN_STATE_CHRE;
+    }
+
+    return ret;
+}
+
+wifi_error nan_chre_disable_request(transaction_id id,
+        wifi_interface_handle iface)
+{
+    wifi_error ret = WIFI_SUCCESS;
+    hal_info *h_info = getHalInfo(iface);
+
+    ALOGI("nan_chre_disable_request: nan_state %d\n", h_info->nan_state);
+
+    if (h_info->nan_state == NAN_STATE_AP) {
+        ALOGE("nan_chre_disable_request: Not enabled for CHRE.. return\n");
+        return ret;
+    }
+
+    NanMacControl *cmd = new NanMacControl(iface, id, NULL, NAN_REQUEST_LAST);
+    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+
+    cmd->setChreNan(1);
+    ret = nan_cmn_disable_request(id, cmd);
+
+    if (ret == WIFI_SUCCESS) {
+        h_info->nan_state = NAN_STATE_DISABLED;
+    }
+
+    return ret;
+}
+
+wifi_error nan_chre_register_handler(wifi_interface_handle iface,
+        wifi_chre_handler handler)
+{
+    wifi_error ret = WIFI_SUCCESS;
+    hal_info *h_info = getHalInfo(iface);
+
+    if (h_info) {
+        ALOGE("Registering CHRE handler for Nan Status %p\n", handler.on_chre_nan_rtt_change);
+        h_info->chre_nan_cb = handler;
+    }
+
+    return ret;
+}
diff --git a/bcmdhd/wifi_hal/rtt.cpp b/bcmdhd/wifi_hal/rtt.cpp
index 81eb17f..6bb0a49 100644
--- a/bcmdhd/wifi_hal/rtt.cpp
+++ b/bcmdhd/wifi_hal/rtt.cpp
@@ -60,26 +60,30 @@
 } RTT_SUB_COMMAND;
 
 typedef enum {
-    RTT_ATTRIBUTE_TARGET_CNT = 0,
-    RTT_ATTRIBUTE_TARGET_INFO,
-    RTT_ATTRIBUTE_TARGET_MAC,
-    RTT_ATTRIBUTE_TARGET_TYPE,
-    RTT_ATTRIBUTE_TARGET_PEER,
-    RTT_ATTRIBUTE_TARGET_CHAN,
-    RTT_ATTRIBUTE_TARGET_PERIOD,
-    RTT_ATTRIBUTE_TARGET_NUM_BURST,
-    RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST,
-    RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM,
-    RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR,
-    RTT_ATTRIBUTE_TARGET_LCI,
-    RTT_ATTRIBUTE_TARGET_LCR,
-    RTT_ATTRIBUTE_TARGET_BURST_DURATION,
-    RTT_ATTRIBUTE_TARGET_PREAMBLE,
-    RTT_ATTRIBUTE_TARGET_BW,
-    RTT_ATTRIBUTE_RESULTS_COMPLETE = 30,
-    RTT_ATTRIBUTE_RESULTS_PER_TARGET,
-    RTT_ATTRIBUTE_RESULT_CNT,
-    RTT_ATTRIBUTE_RESULT
+    RTT_ATTRIBUTE_TARGET_INVALID            = 0,
+    RTT_ATTRIBUTE_TARGET_CNT                = 1,
+    RTT_ATTRIBUTE_TARGET_INFO               = 2,
+    RTT_ATTRIBUTE_TARGET_MAC                = 3,
+    RTT_ATTRIBUTE_TARGET_TYPE               = 4,
+    RTT_ATTRIBUTE_TARGET_PEER               = 5,
+    RTT_ATTRIBUTE_TARGET_CHAN               = 6,
+    RTT_ATTRIBUTE_TARGET_PERIOD             = 7,
+    RTT_ATTRIBUTE_TARGET_NUM_BURST          = 8,
+    RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST      = 9,
+    RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM      = 10,
+    RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR     = 11,
+    RTT_ATTRIBUTE_TARGET_LCI                = 12,
+    RTT_ATTRIBUTE_TARGET_LCR                = 13,
+    RTT_ATTRIBUTE_TARGET_BURST_DURATION     = 14,
+    RTT_ATTRIBUTE_TARGET_PREAMBLE           = 15,
+    RTT_ATTRIBUTE_TARGET_BW                 = 16,
+    RTT_ATTRIBUTE_RESULTS_COMPLETE          = 30,
+    RTT_ATTRIBUTE_RESULTS_PER_TARGET        = 31,
+    RTT_ATTRIBUTE_RESULT_CNT                = 32,
+    RTT_ATTRIBUTE_RESULT                    = 33,
+    RTT_ATTRIBUTE_RESUTL_DETAIL             = 34,
+    /* Add any new RTT_ATTRIBUTE prior to RTT_ATTRIBUTE_MAX */
+    RTT_ATTRIBUTE_MAX
 } RTT_ATTRIBUTE;
 typedef struct strmap_entry {
     int			id;
@@ -96,6 +100,7 @@
 #define DOT11_HDR_LEN 2
 #define DOT11_RM_IE_LEN       5
 #define DOT11_MNG_MEASURE_REQUEST_ID		38	/* 11H MeasurementRequest */
+#define DOT11_MNG_MEASURE_REPORT_ID		39	/* 11H MeasurementResponse */
 #define DOT11_MEASURE_TYPE_LCI		8   /* d11 measurement LCI type */
 #define DOT11_MEASURE_TYPE_CIVICLOC	11  /* d11 measurement location civic */
 
@@ -313,6 +318,7 @@
     unsigned numRttParams;
     int mCompleted;
     int currentIdx;
+    int currDtlIdx;
     int totalCnt;
     static const int MAX_RESULTS = 1024;
     wifi_rtt_result *rttResults[MAX_RESULTS];
@@ -328,6 +334,7 @@
         currentIdx = 0;
         mCompleted = 0;
         totalCnt = 0;
+        currDtlIdx = 0;
     }
 
     RttCommand(wifi_interface_handle iface, int id)
@@ -336,7 +343,11 @@
         currentIdx = 0;
         mCompleted = 0;
         totalCnt = 0;
+        currDtlIdx = 0;
         numRttParams = 0;
+	memset(rttResults, 0, sizeof(rttResults));
+	rttParams = NULL;
+	rttHandler.on_rtt_results = NULL;
     }
 
     int createSetupRequest(WifiRequest& request) {
@@ -451,7 +462,11 @@
         }
 
         nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
-        request.put_u8(RTT_ATTRIBUTE_TARGET_CNT, num_devices);
+	result = request.put_u8(RTT_ATTRIBUTE_TARGET_CNT, num_devices);
+
+	if (result < 0) {
+		return result;
+	}
         for(unsigned i = 0; i < num_devices; i++) {
             result = request.put_addr(RTT_ATTRIBUTE_TARGET_MAC, addr[i]);
             if (result < 0) {
@@ -470,13 +485,14 @@
             return result;
         }
 
+        registerVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE);
         result = requestResponse(request);
         if (result != WIFI_SUCCESS) {
+            unregisterVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE);
             ALOGE("failed to configure RTT setup; result = %d", result);
             return result;
         }
 
-        registerVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE);
         ALOGI("Successfully started RTT operation");
         return result;
     }
@@ -528,6 +544,7 @@
         int len = event.get_vendor_data_len();
         if (vendor_data == NULL || len == 0) {
             ALOGI("No rtt results found");
+            return NL_STOP;
         }
         for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
             if (it.get_type() == RTT_ATTRIBUTE_RESULTS_COMPLETE) {
@@ -561,19 +578,18 @@
                         memcpy(rtt_result, it2.get_data(), it2.get_len());
                         result_len -= sizeof(wifi_rtt_result);
                         if (result_len > 0) {
-                            result_len -= sizeof(wifi_rtt_result);
                             dot11_rm_ie_t *ele_1;
                             dot11_rm_ie_t *ele_2;
                             /* The result has LCI or LCR element */
                             ele_1 = (dot11_rm_ie_t *)(rtt_result + 1);
-                            if (ele_1->id == DOT11_MNG_MEASURE_REQUEST_ID) {
+                            if (ele_1->id == DOT11_MNG_MEASURE_REPORT_ID) {
                                 if (ele_1->type == DOT11_MEASURE_TYPE_LCI) {
                                     rtt_result->LCI = (wifi_information_element *)ele_1;
                                     result_len -= (ele_1->len + DOT11_HDR_LEN);
                                     /* get a next rm ie */
                                     if (result_len > 0) {
                                         ele_2 = (dot11_rm_ie_t *)((char *)ele_1 + (ele_1->len + DOT11_HDR_LEN));
-                                        if ((ele_2->id == DOT11_MNG_MEASURE_REQUEST_ID) &&
+                                        if ((ele_2->id == DOT11_MNG_MEASURE_REPORT_ID) &&
                                                 (ele_2->type == DOT11_MEASURE_TYPE_CIVICLOC)) {
                                             rtt_result->LCR = (wifi_information_element *)ele_2;
                                         }
@@ -584,7 +600,7 @@
                                     /* get a next rm ie */
                                     if (result_len > 0) {
                                         ele_2 = (dot11_rm_ie_t *)((char *)ele_1 + (ele_1->len + DOT11_HDR_LEN));
-                                        if ((ele_2->id == DOT11_MNG_MEASURE_REQUEST_ID) &&
+                                        if ((ele_2->id == DOT11_MNG_MEASURE_REPORT_ID) &&
                                                 (ele_2->type == DOT11_MEASURE_TYPE_LCI)) {
                                             rtt_result->LCI = (wifi_information_element *)ele_2;
                                         }
@@ -595,13 +611,14 @@
                         totalCnt++;
                         ALOGI("retrived rtt_result : \n\tburst_num :%d, measurement_number : %d, success_number : %d\n"
                                 "\tnumber_per_burst_peer : %d, status : %s, retry_after_duration : %d s\n"
-                                "\trssi : %d dbm, rx_rate : %d Kbps, rtt : %llu ns, rtt_sd : %llu\n"
-                                "\tdistance : %d, burst_duration : %d ms, negotiated_burst_num : %d\n",
+				"\trssi : %d dbm, rx_rate : %d Kbps, rtt : %lu ns, rtt_sd : %lu\n"
+				"\tdistance : %d cm, burst_duration : %d ms, negotiated_burst_num : %d\n",
                                 rtt_result->burst_num, rtt_result->measurement_number,
                                 rtt_result->success_number, rtt_result->number_per_burst_peer,
                                 get_err_info(rtt_result->status), rtt_result->retry_after_duration,
                                 rtt_result->rssi, rtt_result->rx_rate.bitrate * 100,
-                                rtt_result->rtt/10, rtt_result->rtt_sd, rtt_result->distance_mm / 10,
+				(unsigned long)rtt_result->rtt/1000, (unsigned long)rtt_result->rtt_sd,
+			       	rtt_result->distance_mm / 10,
                                 rtt_result->burst_duration, rtt_result->negotiated_burst_num);
                         currentIdx++;
                     }
@@ -611,7 +628,9 @@
         }
         if (mCompleted) {
             unregisterVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE);
-            (*rttHandler.on_rtt_results)(id(), totalCnt, rttResults);
+	    if (*rttHandler.on_rtt_results) {
+                (*rttHandler.on_rtt_results)(id(), totalCnt, rttResults);
+            }
             for (int i = 0; i < currentIdx; i++) {
                 free(rttResults[i]);
                 rttResults[i] = NULL;
@@ -630,7 +649,19 @@
 wifi_error wifi_rtt_range_request(wifi_request_id id, wifi_interface_handle iface,
         unsigned num_rtt_config, wifi_rtt_config rtt_config[], wifi_rtt_event_handler handler)
 {
+    if (iface == NULL) {
+	ALOGE("wifi_rtt_range_request: NULL iface pointer provided."
+		" Exit.");
+	return WIFI_ERROR_INVALID_ARGS;
+    }
+
     wifi_handle handle = getWifiHandle(iface);
+    if (handle == NULL) {
+	ALOGE("wifi_rtt_range_request: NULL handle pointer provided."
+	" Exit.");
+	return WIFI_ERROR_INVALID_ARGS;
+    }
+
     RttCommand *cmd = new RttCommand(iface, id, num_rtt_config, rtt_config, handler);
     NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
     wifi_error result = wifi_register_cmd(handle, id, cmd);
@@ -651,7 +682,19 @@
 wifi_error wifi_rtt_range_cancel(wifi_request_id id,  wifi_interface_handle iface,
         unsigned num_devices, mac_addr addr[])
 {
+   if (iface == NULL) {
+	ALOGE("wifi_rtt_range_cancel: NULL iface pointer provided."
+		" Exit.");
+	return WIFI_ERROR_INVALID_ARGS;
+   }
+
     wifi_handle handle = getWifiHandle(iface);
+    if (handle == NULL) {
+	ALOGE("wifi_rtt_range_cancel: NULL handle pointer provided."
+		" Exit.");
+	return WIFI_ERROR_INVALID_ARGS;
+    }
+
     RttCommand *cmd = new RttCommand(iface, id);
     NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
     cmd->cancel_specific(num_devices, addr);
@@ -663,6 +706,18 @@
 wifi_error wifi_get_rtt_capabilities(wifi_interface_handle iface,
         wifi_rtt_capabilities *capabilities)
 {
+    if (iface == NULL) {
+	ALOGE("wifi_get_rtt_capabilities: NULL iface pointer provided."
+		" Exit.");
+	return WIFI_ERROR_INVALID_ARGS;
+    }
+
+    if (capabilities == NULL) {
+	ALOGE("wifi_get_rtt_capabilities: NULL capabilities pointer provided."
+		" Exit.");
+	return WIFI_ERROR_INVALID_ARGS;
+    }
+
     GetRttCapabilitiesCommand command(iface, capabilities);
     return (wifi_error) command.requestResponse();
 }
@@ -671,6 +726,12 @@
 wifi_error wifi_rtt_get_responder_info(wifi_interface_handle iface,
         wifi_rtt_responder* responderInfo)
 {
+    if (iface == NULL) {
+	ALOGE("wifi_rtt_get_responder_info: NULL iface pointer provided."
+		" Exit.");
+	return WIFI_ERROR_INVALID_ARGS;
+    }
+
     GetRttResponderInfoCommand command(iface, responderInfo);
     return (wifi_error) command.requestResponse();
 
diff --git a/bcmdhd/wifi_hal/sync.h b/bcmdhd/wifi_hal/sync.h
index 64f8d39..1118c71 100644
--- a/bcmdhd/wifi_hal/sync.h
+++ b/bcmdhd/wifi_hal/sync.h
@@ -68,4 +68,4 @@
     }
 };
 
-#endif
\ No newline at end of file
+#endif
diff --git a/bcmdhd/wifi_hal/twt.cpp b/bcmdhd/wifi_hal/twt.cpp
new file mode 100755
index 0000000..15bb738
--- /dev/null
+++ b/bcmdhd/wifi_hal/twt.cpp
@@ -0,0 +1,947 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Portions copyright (C) 2020 Broadcom Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink/handlers.h>
+
+#include "sync.h"
+
+#define LOG_TAG  "WifiHAL"
+
+#include <utils/Log.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+
+static const char *TwtCmdToString(int cmd);
+static void EventGetAttributeData(u8 sub_event_type, nlattr *vendor_data);
+typedef void *TwtRequest;
+
+#define C2S(x)  case x: return #x;
+
+typedef struct _twt_hal_info {
+    void *twt_handle;
+    void *twt_feature_request;
+} twt_hal_info_t;
+
+twt_hal_info_t twt_info;
+
+#define TWT_HANDLE(twt_info)                  ((twt_info).twt_handle)
+#define GET_TWT_HANDLE(twt_info)              ((TwtHandle *)twt_info.twt_handle)
+
+#define WL_TWT_CAP_FLAGS_REQ_SUPPORT    (1u << 0u)
+#define WL_TWT_CAP_FLAGS_RESP_SUPPORT   (1u << 1u)
+#define WL_TWT_CAP_FLAGS_BTWT_SUPPORT   (1u << 2u)
+#define WL_TWT_CAP_FLAGS_FLEX_SUPPORT   (1u << 3u)
+
+class TwtHandle
+{
+    public:
+        TwtCallbackHandler mHandlers;
+        TwtHandle(wifi_handle handle, TwtCallbackHandler handlers):mHandlers(handlers)
+    {}
+
+};
+
+
+static const char *TwtCmdToString(int cmd)
+{
+    switch (cmd) {
+        C2S(TWT_SETUP_REQUEST);
+        C2S(TWT_INFO_FRAME_REQUEST);
+        C2S(TWT_TEAR_DOWN_REQUEST);
+        default:
+    return "UNKNOWN_NAN_CMD";
+    }
+}
+
+static bool is_twt_sub_event(int sub_event_type)
+{
+    bool is_twt_event = false;
+    switch (sub_event_type) {
+        case TWT_SETUP_RESPONSE:
+        case TWT_TEARDOWN_COMPLETION:
+        case TWT_INFORM_FRAME:
+        case TWT_NOTIFY:
+            is_twt_event = true;
+    }
+    return is_twt_event;
+}
+
+void EventGetAttributeData(u8 sub_event_type, nlattr *vendor_data)
+{
+    u8 attr_type = 0;
+
+    switch (sub_event_type) {
+        case TWT_SETUP_RESPONSE:
+            TwtSetupResponse setup_response;
+            for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+                attr_type = it.get_type();
+                switch (attr_type) {
+                    case TWT_ATTRIBUTE_CONFIG_ID:
+                        ALOGI("config_id = %u\n", it.get_u8());
+                        setup_response.config_id = it.get_u8();
+                        break;
+                    case TWT_ATTRIBUTE_NEG_TYPE:
+                        ALOGI("neg type = %u\n", it.get_u8());
+                        setup_response.negotiation_type = it.get_u8();
+                        break;
+                    case TWT_ATTRIBUTE_REASON_CODE:
+                        setup_response.reason_code = (TwtSetupReasonCode)it.get_u8();
+                        ALOGI("reason code = %u\n", setup_response.reason_code);
+                        break;
+                    case TWT_ATTRIBUTE_STATUS:
+                        setup_response.status = it.get_u8();
+                        ALOGI("status = %u\n", setup_response.status);
+                        break;
+                    case TWT_ATTRIBUTE_TRIGGER_TYPE:
+                        setup_response.trigger_type = it.get_u8();
+                        ALOGI("trigger type = %u\n", setup_response.trigger_type);
+                        break;
+                    case TWT_ATTRIBUTE_WAKE_DUR_US:
+                        setup_response.wake_dur_us = it.get_u32();
+                        ALOGI("wake_dur_us = %d\n", setup_response.wake_dur_us);
+                        break;
+                    case TWT_ATTRIBUTE_WAKE_INT_US:
+                        setup_response.wake_int_us = it.get_u32();
+                        ALOGI("wake_int_us = %d\n", setup_response.wake_int_us);
+                        break;
+                     case TWT_ATTRIBUTE_WAKE_TIME_OFF_US:
+                         setup_response.wake_time_off_us = it.get_u32();
+                         ALOGI("wake_time_off_us = %d\n", setup_response.wake_time_off_us);
+                         break;
+                     default:
+                         if (attr_type != TWT_ATTRIBUTE_SUB_EVENT) {
+                             ALOGE("Unknown attr_type: %d\n", attr_type);
+                         }
+                         break;
+                }
+            }
+            GET_TWT_HANDLE(twt_info)->mHandlers.EventTwtSetupResponse(&setup_response);
+            break;
+        case TWT_TEARDOWN_COMPLETION:
+            TwtTeardownCompletion teardown_event;
+            for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+                attr_type = it.get_type();
+                switch (attr_type) {
+                    case TWT_ATTRIBUTE_CONFIG_ID:
+                        ALOGI("config_id = %u\n", it.get_u8());
+                        teardown_event.config_id = it.get_u8();
+                        break;
+                    case TWT_ATTRIBUTE_STATUS:
+                        teardown_event.status = it.get_u8();
+                        ALOGI("status = %u\n", teardown_event.status);
+                        break;
+                    case TWT_ATTRIBUTE_ALL_TWT:
+                        teardown_event.all_twt = it.get_u8();
+                        ALOGI("all_twt = %d\n", teardown_event.all_twt);
+                        break;
+                    case TWT_ATTRIBUTE_REASON_CODE:
+                        teardown_event.reason = (TwtTeardownReason)it.get_u8();
+                        ALOGI("reason = %u\n", teardown_event.reason);
+                        break;
+                    default:
+                        if (attr_type != TWT_ATTRIBUTE_SUB_EVENT) {
+                            ALOGE("Unknown attr_type: %d\n", attr_type);
+                        }
+                        break;
+                }
+            }
+            GET_TWT_HANDLE(twt_info)->mHandlers.EventTwtTeardownCompletion(&teardown_event);
+            break;
+        case TWT_INFORM_FRAME:
+            TwtInfoFrameReceived info_frame_event;
+            for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+                attr_type = it.get_type();
+                switch (attr_type) {
+                    case TWT_ATTRIBUTE_CONFIG_ID:
+                        ALOGI("config_id = %u\n", it.get_u8());
+                        info_frame_event.config_id = it.get_u8();
+                        break;
+                    case TWT_ATTRIBUTE_REASON_CODE:
+                        info_frame_event.reason = (TwtInfoFrameReason)it.get_u8();
+                        ALOGI("reason = %u\n", info_frame_event.reason);
+                        break;
+                    case TWT_ATTRIBUTE_STATUS:
+                        info_frame_event.status = it.get_u8();
+                        ALOGI("status = %u\n", info_frame_event.status);
+                        break;
+                    case TWT_ATTRIBUTE_ALL_TWT:
+                        info_frame_event.all_twt = it.get_u8();
+                        ALOGI("all_twt = %d\n", info_frame_event.all_twt);
+                        break;
+                    case TWT_ATTRIBUTE_RESUMED:
+                        info_frame_event.twt_resumed = it.get_u8();
+                        ALOGI("twt_resumed = %u\n", info_frame_event.twt_resumed);
+                        break;
+                    default:
+                        if (attr_type != TWT_ATTRIBUTE_SUB_EVENT) {
+                            ALOGE("Unknown attr_type: %d\n", attr_type);
+                        }
+                        break;
+                }
+            }
+            GET_TWT_HANDLE(twt_info)->mHandlers.EventTwtInfoFrameReceived(&info_frame_event);
+            break;
+        case TWT_NOTIFY:
+            TwtDeviceNotify notif_event;
+            for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+                attr_type = it.get_type();
+                switch (attr_type) {
+                    case TWT_ATTRIBUTE_NOTIFICATION:
+                        notif_event.notification = (TwtNotification)it.get_u8();
+                        ALOGI("notification = %u\n", notif_event.notification);
+                        break;
+                    default:
+                        if (attr_type != TWT_ATTRIBUTE_SUB_EVENT) {
+                            ALOGE("Unknown attr_type: %d\n", attr_type);
+                        }
+                        break;
+                }
+            }
+            GET_TWT_HANDLE(twt_info)->mHandlers.EventTwtDeviceNotify(&notif_event);
+            break;
+        default:
+            ALOGE("Unknown event_type: %d\n", sub_event_type);
+            break;
+    }
+    return;
+}
+
+void HandleTwtEvent(nlattr *vendor_data) {
+    u8 sub_event_type = 0;
+    u8 event_type = 0;
+
+    for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+        event_type = it.get_type();
+        if (event_type == TWT_ATTRIBUTE_SUB_EVENT) {
+            sub_event_type = it.get_u8();
+            if (is_twt_sub_event(sub_event_type)) {
+                EventGetAttributeData(sub_event_type, vendor_data);
+            }
+        }
+    }
+    return;
+}
+
+class TwtEventCap : public WifiCommand
+{
+    public:
+        TwtEventCap(wifi_interface_handle iface, int id)
+            : WifiCommand("TwtCommand", iface, id)
+        {}
+
+        int start()
+        {
+            registerTwtVendorEvents();
+            return WIFI_SUCCESS;
+        }
+
+        int handleResponse(WifiEvent& reply) {
+            return NL_SKIP;
+        }
+
+        void registerTwtVendorEvents()
+        {
+            registerVendorHandler(BRCM_OUI, BRCM_VENDOR_EVENT_TWT);
+        }
+
+        void unregisterTwtVendorEvents()
+        {
+            unregisterVendorHandler(BRCM_OUI, BRCM_VENDOR_EVENT_TWT);
+        }
+
+        int handleEvent(WifiEvent& event) {
+            u16 attr_type;
+            TwtEventType twt_event;
+
+            nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+            int len = event.get_vendor_data_len();
+            int event_id = event.get_vendor_subcmd();
+
+            ALOGI("EventCapture: Received TWT event: %d\n", event_id);
+            if (!vendor_data || len == 0) {
+                ALOGE("No event data found");
+                return NL_SKIP;
+            }
+
+            switch (event_id) {
+                case BRCM_VENDOR_EVENT_TWT: {
+                    ALOGE("Handle TWT event: %d\n", event_id);
+                    HandleTwtEvent(vendor_data);
+                    break;
+                }
+                default:
+                    break;
+            }
+            return NL_SKIP;
+        }
+};
+
+/* To see event prints in console */
+wifi_error twt_event_check_request(transaction_id id, wifi_interface_handle iface)
+{
+    TwtEventCap *cmd = new TwtEventCap(iface, id);
+    if (cmd == NULL) {
+        return WIFI_ERROR_NOT_SUPPORTED;
+    }
+    return (wifi_error)cmd->start();
+}
+
+//////////////////////////////////////////////////////////////////////////
+class GetTwtCapabilitiesCommand : public WifiCommand
+{
+    TwtCapabilitySet *mCapabilities;
+public:
+    GetTwtCapabilitiesCommand(wifi_interface_handle iface, TwtCapabilitySet *capabilities)
+        : WifiCommand("GetTwtCapabilitiesCommand", iface, 0), mCapabilities(capabilities)
+    {
+        memset(mCapabilities, 0, sizeof(*mCapabilities));
+    }
+
+    virtual int create() {
+        ALOGD("Creating message to get twt capabilities; iface\n");
+
+        int ret = mMsg.create(GOOGLE_OUI, TWT_SUBCMD_GETCAPABILITY);
+        if (ret < 0) {
+            ALOGE("Failed to send the twt cap cmd, err = %d\n", ret);
+        }
+        ALOGD("Success to send twt cap cmd, err = %d\n", ret);
+        return ret;
+    }
+
+private:
+    TwtCapability parseTwtCap(uint32_t twt_peer_cap) {
+        TwtCapability cap;
+        cap.requester_supported = (twt_peer_cap & WL_TWT_CAP_FLAGS_REQ_SUPPORT) ? 1 : 0;
+        cap.responder_supported = (twt_peer_cap & WL_TWT_CAP_FLAGS_RESP_SUPPORT) ? 1 : 0;
+        cap.broadcast_twt_supported = (twt_peer_cap & WL_TWT_CAP_FLAGS_BTWT_SUPPORT) ? 1 : 0;
+        cap.flexibile_twt_supported = (twt_peer_cap & WL_TWT_CAP_FLAGS_FLEX_SUPPORT) ? 1 : 0;
+        return cap;
+    }
+
+protected:
+    virtual int handleResponse(WifiEvent& reply) {
+
+        ALOGI("In GetTwtCapabilitiesCommand::handleResponse");
+
+        if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+            ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+            return NL_SKIP;
+        }
+
+        int id = reply.get_vendor_id();
+        int subcmd = reply.get_vendor_subcmd();
+        uint32_t twt_device_cap, twt_peer_cap;
+
+        nlattr *data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+        int len = reply.get_vendor_data_len();
+
+        ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len);
+        if (data == NULL || len == 0) {
+            ALOGE("no vendor data in GetTwtCapabilitiesCommand response; ignoring it\n");
+            return NL_SKIP;
+        }
+
+        for (nl_iterator it(data); it.has_next(); it.next()) {
+            switch (it.get_type()) {
+                case TWT_ATTRIBUTE_DEVICE_CAP:
+                    twt_device_cap = it.get_u32();
+                    mCapabilities->device_capability = parseTwtCap(twt_device_cap);
+                    break;
+                case TWT_ATTRIBUTE_PEER_CAP:
+                    twt_peer_cap = it.get_u32();
+                    mCapabilities->peer_capability = parseTwtCap(twt_peer_cap);
+                    break;
+                default:
+                    ALOGE("Ignoring invalid attribute type = %d, size = %d\n",
+                            it.get_type(), it.get_len());
+                    break;
+            }
+        }
+
+        ALOGE("Out GetTwtCapabilitiesCommand::handleResponse\n");
+        return NL_OK;
+    }
+};
+
+/* API to get TWT capability */
+wifi_error twt_get_capability(wifi_interface_handle iface,
+        TwtCapabilitySet *twt_cap_set)
+{
+    if (iface == NULL) {
+        ALOGE("twt_get_capability: NULL iface pointer provided."
+            " Exit.");
+        return WIFI_ERROR_INVALID_ARGS;
+    }
+
+    if (twt_cap_set == NULL) {
+        ALOGE("twt_get_capability: NULL capabilities pointer provided."
+            " Exit.");
+        return WIFI_ERROR_INVALID_ARGS;
+    }
+
+    GetTwtCapabilitiesCommand command(iface, twt_cap_set);
+    return (wifi_error) command.requestResponse();
+}
+
+//////////////////////////////////////////////////////////////////////////
+class GetTwtStatsCommand : public WifiCommand
+{
+    TwtStats* mStats;
+    u8 mConfig_id;
+public:
+    GetTwtStatsCommand(wifi_interface_handle iface, u8 config_id, TwtStats *stats)
+        : WifiCommand("GetTwtStatsCommand", iface, 0), mConfig_id(config_id), mStats(stats)
+    {
+        memset(mStats, 0, sizeof(*mStats));
+    }
+
+    virtual int create() {
+        ALOGD("Creating message to get twt stats; iface = %d", mIfaceInfo->id);
+
+        int ret = mMsg.create(GOOGLE_OUI, TWT_SUBCMD_GETSTATS);
+        if (ret < 0) {
+            return ret;
+        }
+
+        nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);
+        ret = mMsg.put_u8(TWT_ATTRIBUTE_CONFIG_ID, mConfig_id);
+        if (ret < 0) {
+             ALOGE("Failed to set mConfig_id %d\n", mConfig_id);
+             return ret;
+        }
+
+        ALOGI("Successfully configured config id %d\n", mConfig_id);
+        mMsg.attr_end(data);
+        return WIFI_SUCCESS;
+    }
+
+protected:
+    virtual int handleResponse(WifiEvent& reply) {
+
+        ALOGI("In GetTwtStatsCommand::handleResponse");
+
+        if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+            ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+            return NL_SKIP;
+        }
+
+        int id = reply.get_vendor_id();
+        int subcmd = reply.get_vendor_subcmd();
+
+        nlattr *data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+        int len = reply.get_vendor_data_len();
+
+        ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len);
+        if (data == NULL || len == 0) {
+            ALOGE("no vendor data in GetTwtStatsCommand response; ignoring it\n");
+            return NL_SKIP;
+        }
+
+        for (nl_iterator it(data); it.has_next(); it.next()) {
+            switch (it.get_type()) {
+                case TWT_ATTRIBUTE_CONFIG_ID:
+                    mStats->config_id = it.get_u8();
+                    break;
+                case TWT_ATTRIBUTE_AVG_PKT_NUM_TX:
+                    mStats->avg_pkt_num_tx = it.get_u32();
+                    break;
+                case TWT_ATTRIBUTE_AVG_PKT_NUM_RX:
+                    mStats->avg_pkt_num_rx = it.get_u32();
+                    break;
+                case TWT_ATTRIBUTE_AVG_PKT_SIZE_TX:
+                    mStats->avg_tx_pkt_size = it.get_u32();
+                    break;
+                case TWT_ATTRIBUTE_AVG_PKT_SIZE_RX:
+                    mStats->avg_rx_pkt_size = it.get_u32();
+                    break;
+                case TWT_ATTRIBUTE_AVG_EOSP_DUR:
+                    mStats->avg_eosp_dur_us = it.get_u32();
+                    break;
+                case TWT_ATTRIBUTE_EOSP_COUNT:
+                    mStats->eosp_count = it.get_u32();
+                    break;
+                case TWT_ATTRIBUTE_NUM_SP:
+                    mStats->num_sp = it.get_u32();
+                    break;
+                default:
+                    ALOGE("Ignoring invalid attribute type = %d, size = %d\n",
+                            it.get_type(), it.get_len());
+                    break;
+            }
+        }
+
+        return NL_OK;
+    }
+};
+
+/* API to get TWT stats */
+wifi_error twt_get_stats(wifi_interface_handle iface, u8 config_id, TwtStats* stats)
+{
+    if (iface == NULL) {
+        ALOGE("twt_get_stats: NULL iface pointer provided."
+            " Exit.");
+        return WIFI_ERROR_INVALID_ARGS;
+    }
+
+    if (stats == NULL) {
+        ALOGE("TwtCapabilitySet: NULL capabilities pointer provided."
+            " Exit.");
+        return WIFI_ERROR_INVALID_ARGS;
+    }
+
+    GetTwtStatsCommand command(iface, config_id, stats);
+    return (wifi_error) command.requestResponse();
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+class ClearTwtStatsCommand : public WifiCommand
+{
+    u8 mConfig_id;
+public:
+    ClearTwtStatsCommand(wifi_interface_handle iface, u8 config_id)
+        : WifiCommand("ClearTwtStatsCommand", iface, 0), mConfig_id(config_id)
+    {
+    }
+
+    virtual int create() {
+        ALOGD("Creating message to clear twt stats; config_id = %d\n", mConfig_id);
+
+        int ret = mMsg.create(GOOGLE_OUI, TWT_SUBCMD_CLR_STATS);
+        if (ret < 0) {
+            return ret;
+        }
+
+        nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);
+        ret = mMsg.put_u8(TWT_ATTRIBUTE_CONFIG_ID, mConfig_id);
+        if (ret < 0) {
+             ALOGE("Failed to set mConfig_id %d\n", mConfig_id);
+             return ret;
+        }
+
+        ALOGI("Successfully configured config id %d\n", mConfig_id);
+        mMsg.attr_end(data);
+        return WIFI_SUCCESS;
+    }
+
+protected:
+    virtual int handleResponse(WifiEvent& reply) {
+        ALOGD("In ClearTwtStatsCommand::handleResponse");
+        /* Nothing to do on response! */
+        return NL_SKIP;
+    }
+};
+
+/* API to clear TWT stats */
+wifi_error twt_clear_stats(wifi_interface_handle iface, u8 config_id)
+{
+    if (iface == NULL || !config_id) {
+        ALOGE("twt_clear_stats: NULL iface pointer provided."
+            " Exit.");
+        return WIFI_ERROR_INVALID_ARGS;
+    }
+    ALOGE("twt_clear_stats: config id: %d\n", config_id);
+
+    ClearTwtStatsCommand command(iface, config_id);
+    return (wifi_error) command.requestResponse();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+class TwtFeatureRequest : public WifiCommand
+{
+    TwtRequest reqContext;
+    TwtRequestType mType;
+
+    public:
+    TwtFeatureRequest(wifi_interface_handle iface,
+            TwtRequest params, TwtRequestType cmdType)
+        : WifiCommand("TwtFeatureRequest", iface, 0), reqContext(params), mType(cmdType)
+    {
+    }
+
+    int createRequest(WifiRequest& request)
+    {
+        ALOGI("TWT CMD: %s\n", TwtCmdToString(mType));
+        if (mType == TWT_SETUP_REQUEST) {
+            return createTwtSetupRequest(request, (TwtSetupRequest *)reqContext);
+        } else if (mType == TWT_INFO_FRAME_REQUEST) {
+            return createInfoFrameRequest(request, (TwtInfoFrameRequest *)reqContext);
+        } else if (mType == TWT_TEAR_DOWN_REQUEST) {
+            return createTearDownRequest(request, (TwtTeardownRequest *)reqContext);
+        } else {
+            ALOGE("%s: Unknown TWT request: %d\n", __func__, mType);
+            return WIFI_ERROR_UNKNOWN;
+        }
+
+        return WIFI_SUCCESS;
+    }
+
+    int createTwtSetupRequest(WifiRequest& request, TwtSetupRequest *mParams)
+    {
+        int result = request.create(GOOGLE_OUI, TWT_SUBCMD_SETUP_REQUEST);
+        if (result < 0) {
+            ALOGE("%s Failed to create request, result = %d\n", __func__, result);
+            return result;
+        }
+
+        /* If handle is 0xFFFF, then update instance_id in response of this request
+         * otherwise, update not needed
+         */
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        if (mParams->config_id) {
+            result = request.put_u8(TWT_ATTRIBUTE_CONFIG_ID, mParams->config_id);
+            if (result < 0) {
+                ALOGE("%s: Failed to fill config_id = %d, result = %d\n",
+                    __func__, mParams->config_id, result);
+                return result;
+            }
+        }
+
+        if (mParams->negotiation_type) {
+            result = request.put_u8(TWT_ATTRIBUTE_NEG_TYPE, mParams->negotiation_type);
+            if (result < 0) {
+                ALOGE("%s: Failed to fill negotiation_type = %d, result = %d\n",
+                    __func__, mParams->negotiation_type, result);
+                return result;
+            }
+        }
+        if (mParams->trigger_type) {
+            result = request.put_u8(TWT_ATTRIBUTE_TRIGGER_TYPE, mParams->trigger_type);
+            if (result < 0) {
+                ALOGE("%s: Failed to fill trigger_type = %d, result = %d\n",
+                    __func__, mParams->trigger_type, result);
+                return result;
+            }
+        }
+        if (mParams->wake_dur_us) {
+            result = request.put_u32(TWT_ATTRIBUTE_WAKE_DUR_US, mParams->wake_dur_us);
+            if (result < 0) {
+                ALOGE("%s: Failed to fill wake_dur_us = %d, result = %d\n",
+                    __func__, mParams->wake_dur_us, result);
+                return result;
+            }
+        }
+        if (mParams->wake_int_us) {
+            result = request.put_u32(TWT_ATTRIBUTE_WAKE_INT_US, mParams->wake_int_us);
+            if (result < 0) {
+                ALOGE("%s: Failed to fill wake_int_us = %d, result = %d\n",
+                    __func__, mParams->wake_int_us, result);
+                return result;
+            }
+        }
+        if (mParams->wake_int_min_us) {
+            result = request.put_u32(TWT_ATTRIBUTE_WAKE_INT_MIN_US, mParams->wake_int_min_us);
+            if (result < 0) {
+                ALOGE("%s: Failed to fill wake_int_min_us = %d, result = %d\n",
+                    __func__, mParams->wake_int_min_us, result);
+                return result;
+            }
+        }
+        if (mParams->wake_int_max_us) {
+            result = request.put_u32(TWT_ATTRIBUTE_WAKE_INT_MAX_US, mParams->wake_int_max_us);
+            if (result < 0) {
+                ALOGE("%s: Failed to fill wake_int_max_us = %d, result = %d\n",
+                    __func__, mParams->wake_int_max_us, result);
+                return result;
+            }
+        }
+        if (mParams->wake_dur_min_us) {
+            result = request.put_u32(TWT_ATTRIBUTE_WAKE_DUR_MIN_US, mParams->wake_dur_min_us);
+            if (result < 0) {
+                ALOGE("%s: Failed to fill wake_dur_min_us = %d, result = %d\n",
+                    __func__, mParams->wake_dur_min_us, result);
+                return result;
+            }
+        }
+        if (mParams->wake_dur_max_us) {
+            result = request.put_u32(TWT_ATTRIBUTE_WAKE_DUR_MAX_US, mParams->wake_dur_max_us);
+            if (result < 0) {
+                ALOGE("%s: Failed to fill wake_dur_max_us = %d, result = %d\n",
+                    __func__, mParams->wake_dur_max_us, result);
+                return result;
+            }
+        }
+        if (mParams->avg_pkt_size) {
+            result = request.put_u32(TWT_ATTRIBUTE_AVG_PKT_SIZE, mParams->avg_pkt_size);
+            if (result < 0) {
+                ALOGE("%s: Failed to fill avg_pkt_size = %d, result = %d\n",
+                    __func__, mParams->avg_pkt_size, result);
+                return result;
+            }
+        }
+        if (mParams->avg_pkt_num) {
+            result = request.put_u32(TWT_ATTRIBUTE_AVG_PKT_NUM, mParams->avg_pkt_num);
+            if (result < 0) {
+                ALOGE("%s: Failed to fill avg_pkt_num = %d, result = %d\n",
+                    __func__, mParams->avg_pkt_num, result);
+                return result;
+            }
+        }
+        if (mParams->wake_time_off_us) {
+            result = request.put_u32(TWT_ATTRIBUTE_WAKE_TIME_OFF_US, mParams->wake_time_off_us);
+            if (result < 0) {
+                ALOGE("%s: Failed to fill wake_time_off_us = %d, result = %d\n",
+                    __func__, mParams->wake_time_off_us, result);
+                return result;
+            }
+        }
+        request.attr_end(data);
+
+        ALOGI("Returning successfully\n");
+        return result;
+    }
+
+    int createInfoFrameRequest(WifiRequest& request, TwtInfoFrameRequest *mParams)
+    {
+        int result = request.create(GOOGLE_OUI, TWT_SUBCMD_INFO_FRAME_REQUEST);
+        if (result < 0) {
+            ALOGE("%s: Failed to create request, result = %d\n", __func__, result);
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        if (mParams->config_id) {
+            result = request.put_u8(TWT_ATTRIBUTE_CONFIG_ID, mParams->config_id);
+            if (result < 0) {
+                ALOGE("%s: Failed to fill config_id = %d, result = %d\n",
+                    __func__, mParams->config_id, result);
+                return result;
+            }
+        }
+        if (mParams->resume_time_us) {
+            result = request.put_u32(TWT_ATTRIBUTE_RESUME_TIME_US, mParams->resume_time_us);
+            if (result < 0) {
+                ALOGE("%s: Failed to fill resume_time_us = %d, result = %d\n",
+                    __func__, mParams->resume_time_us, result);
+                return result;
+            }
+        }
+        if (mParams->all_twt) {
+            result = request.put_u8(TWT_ATTRIBUTE_ALL_TWT, mParams->all_twt);
+            if (result < 0) {
+                ALOGE("%s: Failed to fill all_twt = %d, result = %d\n",
+                    __func__, mParams->all_twt, result);
+                return result;
+            }
+        }
+        request.attr_end(data);
+        return WIFI_SUCCESS;
+    }
+
+    int createTearDownRequest(WifiRequest& request, TwtTeardownRequest *mParams)
+    {
+        int result = request.create(GOOGLE_OUI, TWT_SUBCMD_TEAR_DOWN_REQUEST);
+        if (result < 0) {
+            ALOGE("%s: Failed to create request, result = %d\n", __func__, result);
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        if (mParams->config_id) {
+            result = request.put_u8(TWT_ATTRIBUTE_CONFIG_ID, mParams->config_id);
+            if (result < 0) {
+                ALOGE("%s: Failed to fill config_id = %d, result = %d\n",
+                    __func__, mParams->config_id, result);
+                return result;
+            }
+        }
+        if (mParams->negotiation_type) {
+            result = request.put_u8(TWT_ATTRIBUTE_NEG_TYPE, mParams->negotiation_type);
+            if (result < 0) {
+                ALOGE("%s: Failed to fill negotiation_type = %d, result = %d\n",
+                        __func__, mParams->negotiation_type, result);
+                return result;
+            }
+        }
+        if (mParams->all_twt) {
+            result = request.put_u8(TWT_ATTRIBUTE_ALL_TWT, mParams->all_twt);
+            if (result < 0) {
+                ALOGE("%s: Failed to fill all_twt = %d, result = %d\n",
+                        __func__, mParams->all_twt, result);
+                return result;
+            }
+        }
+        request.attr_end(data);
+        return WIFI_SUCCESS;
+    }
+
+    int open()
+    {
+        WifiRequest request(familyId(), ifaceId());
+        int result = createRequest(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("%s: failed to create setup request; result = %d", __func__, result);
+            return result;
+        }
+
+        result = requestResponse(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("%s: failed to configure setup; result = %d", __func__, result);
+            return result;
+        }
+
+        request.destroy();
+        return WIFI_SUCCESS;
+    }
+
+    void registerTwtVendorEvents()
+    {
+        registerVendorHandler(BRCM_OUI, BRCM_VENDOR_EVENT_TWT);
+    }
+
+    void unregisterTwtVendorEvents()
+    {
+        unregisterVendorHandler(BRCM_OUI, BRCM_VENDOR_EVENT_TWT);
+    }
+
+    virtual int handleResponse(WifiEvent& reply) {
+         ALOGD("Request complete!");
+        /* Nothing to do on response! */
+        return NL_SKIP;
+    }
+
+    int handleEvent(WifiEvent& event) {
+        u16 attr_type;
+        TwtEventType twt_event;
+
+        nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+        int len = event.get_vendor_data_len();
+        int event_id = event.get_vendor_subcmd();
+        ALOGI("Received TWT event: %d\n", event_id);
+
+        if (!vendor_data || len == 0) {
+            ALOGE("No event data found");
+            return NL_SKIP;
+        }
+
+        switch (event_id) {
+            case BRCM_VENDOR_EVENT_TWT: {
+                HandleTwtEvent(vendor_data);
+                break;
+            }
+            default:
+                ALOGE("Unknown event: %d\n", event_id);
+                break;
+        }
+        return NL_SKIP;
+    }
+
+};
+
+void twt_deinit_handler()
+{
+    if (twt_info.twt_feature_request) {
+        /* register for Twt vendor events with info mac class*/
+        TwtFeatureRequest *cmd_event = (TwtFeatureRequest*)(twt_info.twt_feature_request);
+        cmd_event->unregisterTwtVendorEvents();
+        delete (TwtFeatureRequest*)twt_info.twt_feature_request;
+        twt_info.twt_feature_request = NULL;
+    }
+    if (TWT_HANDLE(twt_info)) {
+        delete GET_TWT_HANDLE(twt_info);
+        TWT_HANDLE(twt_info) = NULL;
+    }
+    ALOGI("wifi twt internal clean up done");
+    return;
+}
+
+wifi_error twt_register_handler(wifi_interface_handle iface,
+        TwtCallbackHandler handlers)
+{
+    wifi_handle handle = getWifiHandle(iface);
+    if (TWT_HANDLE(twt_info)) {
+        /* cleanup and re-register */
+        twt_deinit_handler();
+    }
+    memset(&twt_info, 0, sizeof(twt_info));
+    TWT_HANDLE(twt_info) = new TwtHandle(handle, handlers);
+    twt_info.twt_feature_request =
+        (void*)new TwtFeatureRequest(iface, NULL, TWT_LAST);
+    NULL_CHECK_RETURN(twt_info.twt_feature_request,
+        "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+    TwtFeatureRequest *cmd_event = (TwtFeatureRequest*)(twt_info.twt_feature_request);
+    cmd_event->registerTwtVendorEvents();
+    return WIFI_SUCCESS;
+}
+
+wifi_error twt_setup_request(wifi_interface_handle iface, TwtSetupRequest* msg)
+{
+    wifi_error ret = WIFI_SUCCESS;
+    TwtFeatureRequest *cmd;
+    TwtRequestType cmdType = TWT_SETUP_REQUEST;
+
+    cmd = new TwtFeatureRequest(iface, (void *)msg, cmdType);
+    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+
+    ret = (wifi_error)cmd->open();
+    if (ret != WIFI_SUCCESS) {
+        ALOGE("%s : failed in open, error = %d\n", __func__, ret);
+    }
+    cmd->releaseRef();
+    return ret;
+}
+
+wifi_error twt_info_frame_request(wifi_interface_handle iface, TwtInfoFrameRequest* msg)
+{
+    wifi_error ret = WIFI_SUCCESS;
+    TwtFeatureRequest *cmd;
+    TwtRequestType cmdType = TWT_INFO_FRAME_REQUEST;
+
+    cmd = new TwtFeatureRequest(iface, (void *)msg, cmdType);
+    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+
+    ret = (wifi_error)cmd->open();
+    if (ret != WIFI_SUCCESS) {
+        ALOGE("%s : failed in open, error = %d\n", __func__, ret);
+    }
+    cmd->releaseRef();
+    return ret;
+}
+
+wifi_error twt_teardown_request(wifi_interface_handle iface, TwtTeardownRequest* msg)
+{
+    wifi_error ret = WIFI_SUCCESS;
+    TwtFeatureRequest *cmd;
+    TwtRequestType cmdType = TWT_TEAR_DOWN_REQUEST;
+
+    cmd = new TwtFeatureRequest(iface, (void *)msg, cmdType);
+    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+
+    ret = (wifi_error)cmd->open();
+    if (ret != WIFI_SUCCESS) {
+        ALOGE("%s : failed in open, error = %d\n", __func__, ret);
+    }
+    cmd->releaseRef();
+    return ret;
+}
diff --git a/bcmdhd/wifi_hal/wifi_hal.cpp b/bcmdhd/wifi_hal/wifi_hal.cpp
index 258725c..fe679ab 100755
--- a/bcmdhd/wifi_hal/wifi_hal.cpp
+++ b/bcmdhd/wifi_hal/wifi_hal.cpp
@@ -53,6 +53,8 @@
 #include "rtt.h"
 #include "brcm_version.h"
 #include <stdio.h>
+#include <string>
+#include <vector>
 /*
  BUGBUG: normally, libnl allocates ports for all connections it makes; but
  being a static library, it doesn't really know how many other netlink connections
@@ -63,6 +65,8 @@
 
 #define WIFI_HAL_CMD_SOCK_PORT       644
 #define WIFI_HAL_EVENT_SOCK_PORT     645
+#define MAX_VIRTUAL_IFACES           5
+#define WIFI_HAL_EVENT_BUFFER_NOT_AVAILABLE 105
 
 /*
  * Defines for wifi_wait_for_driver_ready()
@@ -71,8 +75,8 @@
 #define POLL_DRIVER_DURATION_US (100000)
 #define POLL_DRIVER_MAX_TIME_MS (10000)
 #define EVENT_BUF_SIZE 2048
+#define C2S(x)  case x: return #x;
 
-static void internal_event_handler(wifi_handle handle, int events);
 static int internal_no_seq_check(nl_msg *msg, void *arg);
 static int internal_valid_message_handler(nl_msg *msg, void *arg);
 static int wifi_get_multicast_id(wifi_handle handle, const char *name, const char *group);
@@ -83,28 +87,51 @@
 static wifi_error wifi_stop_rssi_monitoring(wifi_request_id id, wifi_interface_handle iface);
 static wifi_error wifi_set_packet_filter(wifi_interface_handle handle,
                             const u8 *program, u32 len);
+static wifi_error wifi_read_packet_filter(wifi_interface_handle handle, u32 src_offset,
+                            u8 *host_dst, u32 length);
 static wifi_error wifi_get_packet_filter_capabilities(wifi_interface_handle handle,
                 u32 *version, u32 *max_len);
 static wifi_error wifi_configure_nd_offload(wifi_interface_handle iface, u8 enable);
+static wifi_error wifi_get_usable_channels(wifi_handle handle, u32 band_mask, u32 iface_mode_mask,
+		u32 filter_mask, u32 max_size, u32* size, wifi_usable_channel* channels);
+static wifi_error wifi_get_supported_radio_combinations_matrix(wifi_handle handle,
+		u32 max_size, u32* size, wifi_radio_combination_matrix *radio_combination_matrix);
 
+static void wifi_cleanup_dynamic_ifaces(wifi_handle handle);
 typedef enum wifi_attr {
-    ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET,
-    ANDR_WIFI_ATTRIBUTE_FEATURE_SET,
-    ANDR_WIFI_ATTRIBUTE_PNO_RANDOM_MAC_OUI,
-    ANDR_WIFI_ATTRIBUTE_NODFS_SET,
-    ANDR_WIFI_ATTRIBUTE_COUNTRY,
-    ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_VALUE,
-    ANDR_WIFI_ATTRIBUTE_TCPACK_SUP_VALUE,
-    ANDR_WIFI_ATTRIBUTE_LATENCY_MODE,
-    ANDR_WIFI_ATTRIBUTE_RANDOM_MAC,
-    ANDR_WIFI_ATTRIBUTE_TX_POWER_SCENARIO
-    // Add more attribute here
+    ANDR_WIFI_ATTRIBUTE_INVALID                    = 0,
+    ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET            = 1,
+    ANDR_WIFI_ATTRIBUTE_FEATURE_SET                = 2,
+    ANDR_WIFI_ATTRIBUTE_PNO_RANDOM_MAC_OUI         = 3,
+    ANDR_WIFI_ATTRIBUTE_NODFS_SET                  = 4,
+    ANDR_WIFI_ATTRIBUTE_COUNTRY                    = 5,
+    ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_VALUE           = 6,
+    ANDR_WIFI_ATTRIBUTE_TCPACK_SUP_VALUE           = 7,
+    ANDR_WIFI_ATTRIBUTE_LATENCY_MODE               = 8,
+    ANDR_WIFI_ATTRIBUTE_RANDOM_MAC                 = 9,
+    ANDR_WIFI_ATTRIBUTE_TX_POWER_SCENARIO          = 10,
+    ANDR_WIFI_ATTRIBUTE_THERMAL_MITIGATION         = 11,
+    ANDR_WIFI_ATTRIBUTE_THERMAL_COMPLETION_WINDOW  = 12,
+    ANDR_WIFI_ATTRIBUTE_VOIP_MODE                  = 13,
+    ANDR_WIFI_ATTRIBUTE_DTIM_MULTIPLIER            = 14,
+     // Add more attribute here
+    ANDR_WIFI_ATTRIBUTE_MAX
 } wifi_attr_t;
 
+enum wifi_radio_combo_attributes {
+    ANDR_WIFI_ATTRIBUTE_RADIO_COMBO_INVALID    = 0,
+    ANDR_WIFI_ATTRIBUTE_RADIO_COMBO_MATRIX     = 1,
+    // Add more attribute here
+    ANDR_WIFI_ATTRIBUTE_RADIO_COMBO_MAX
+};
+
 enum wifi_rssi_monitor_attr {
-    RSSI_MONITOR_ATTRIBUTE_MAX_RSSI,
-    RSSI_MONITOR_ATTRIBUTE_MIN_RSSI,
-    RSSI_MONITOR_ATTRIBUTE_START,
+    RSSI_MONITOR_ATTRIBUTE_INVALID	= 0,
+    RSSI_MONITOR_ATTRIBUTE_MAX_RSSI	= 1,
+    RSSI_MONITOR_ATTRIBUTE_MIN_RSSI	= 2,
+    RSSI_MONITOR_ATTRIBUTE_START	= 3,
+    // Add more attribute here
+    RSSI_MONITOR_ATTRIBUTE_MAX
 };
 
 enum wifi_apf_attr {
@@ -116,7 +143,57 @@
 
 enum apf_request_type {
     GET_APF_CAPABILITIES,
-    SET_APF_PROGRAM
+    SET_APF_PROGRAM,
+    READ_APF_PROGRAM
+};
+
+enum wifi_dscp_attr {
+    DSCP_ATTRIBUTE_INVALID	= 0,
+    DSCP_ATTRIBUTE_START	= 1,
+    DSCP_ATTRIBUTE_END		= 2,
+    DSCP_ATTRIBUTE_AC		= 3,
+    /* Add more attributes here */
+    DSCP_ATTRIBUTE_MAX
+};
+
+enum wifi_dscp_request_type {
+    SET_DSCP_TABLE,
+    RESET_DSCP_TABLE
+};
+
+enum wifi_chavoid_attr {
+    CHAVOID_ATTRIBUTE_INVALID   = 0,
+    CHAVOID_ATTRIBUTE_CNT       = 1,
+    CHAVOID_ATTRIBUTE_CONFIG    = 2,
+    CHAVOID_ATTRIBUTE_BAND      = 3,
+    CHAVOID_ATTRIBUTE_CHANNEL   = 4,
+    CHAVOID_ATTRIBUTE_PWRCAP    = 5,
+    CHAVOID_ATTRIBUTE_MANDATORY = 6,
+    /* Add more attributes here */
+    CHAVOID_ATTRIBUTE_MAX
+};
+
+enum wifi_usable_channel_attributes {
+    USABLECHAN_ATTRIBUTE_INVALID    = 0,
+    USABLECHAN_ATTRIBUTE_BAND       = 1,
+    USABLECHAN_ATTRIBUTE_IFACE      = 2,
+    USABLECHAN_ATTRIBUTE_FILTER     = 3,
+    USABLECHAN_ATTRIBUTE_MAX_SIZE   = 4,
+    USABLECHAN_ATTRIBUTE_SIZE       = 5,
+    USABLECHAN_ATTRIBUTE_CHANNELS   = 6,
+    USABLECHAN_ATTRIBUTE_MAX
+};
+
+enum wifi_multista_attr {
+    MULTISTA_ATTRIBUTE_PRIM_CONN_IFACE,
+    MULTISTA_ATTRIBUTE_USE_CASE,
+    /* Add more attributes here */
+    MULTISTA_ATTRIBUTE_MAX
+};
+
+enum multista_request_type {
+    SET_PRIMARY_CONNECTION,
+    SET_USE_CASE
 };
 
 /* Initialize/Cleanup */
@@ -138,28 +215,26 @@
 
     wifi_socket_set_local_port(sock, port);
 
-    struct sockaddr *addr = NULL;
-    // ALOGI("sizeof(sockaddr) = %d, sizeof(sockaddr_nl) = %d", sizeof(*addr), sizeof(*addr_nl));
-
-    // ALOGI("Connecting socket");
     if (nl_connect(sock, NETLINK_GENERIC)) {
         ALOGE("Could not connect handle");
         nl_socket_free(sock);
         return NULL;
     }
-
-    // ALOGI("Making socket nonblocking");
-    /*
-    if (nl_socket_set_nonblocking(sock)) {
-        ALOGE("Could make socket non-blocking");
-        nl_socket_free(sock);
-        return NULL;
-    }
-    */
-
     return sock;
 }
 
+static const char *IfaceTypeToString(wifi_interface_type iface_type)
+{
+    switch (iface_type) {
+        C2S(WIFI_INTERFACE_TYPE_STA)
+        C2S(WIFI_INTERFACE_TYPE_AP)
+        C2S(WIFI_INTERFACE_TYPE_P2P)
+        C2S(WIFI_INTERFACE_TYPE_NAN)
+    default:
+        return "UNKNOWN_WIFI_INTERFACE_TYPE";
+    }
+}
+
 /*initialize function pointer table with Broadcom HHAL API*/
 wifi_error init_wifi_vendor_hal_func_table(wifi_hal_fn *fn)
 {
@@ -242,14 +317,60 @@
     fn->wifi_nan_data_indication_response = nan_data_indication_response;
     fn->wifi_nan_data_end = nan_data_end;
     fn->wifi_set_latency_mode = wifi_set_latency_mode;
-#ifdef NAN_CLUSTER_MERGE
-    fn->wifi_nan_enable_merge_request = nan_enable_cluster_merge_request;
-#endif /* NAN_CLUSTER_MERGE */
     fn->wifi_select_tx_power_scenario = wifi_select_tx_power_scenario;
     fn->wifi_reset_tx_power_scenario = wifi_reset_tx_power_scenario;
+    fn->wifi_read_packet_filter = wifi_read_packet_filter;
+    fn->wifi_set_subsystem_restart_handler = wifi_set_subsystem_restart_handler;
+    fn->wifi_set_thermal_mitigation_mode = wifi_set_thermal_mitigation_mode;
+    fn->wifi_map_dscp_access_category = wifi_map_dscp_access_category;
+    fn->wifi_reset_dscp_mapping = wifi_reset_dscp_mapping;
+    fn->wifi_virtual_interface_create = wifi_virtual_interface_create;
+    fn->wifi_virtual_interface_delete = wifi_virtual_interface_delete;
+    fn->wifi_set_coex_unsafe_channels = wifi_set_coex_unsafe_channels;
+    fn->wifi_twt_get_capability = twt_get_capability;
+    fn->wifi_twt_register_handler = twt_register_handler;
+    fn->wifi_twt_setup_request = twt_setup_request;
+    fn->wifi_twt_teardown_request = twt_teardown_request;
+    fn->wifi_twt_info_frame_request = twt_info_frame_request;
+    fn->wifi_twt_get_stats = twt_get_stats;
+    fn->wifi_twt_clear_stats = twt_clear_stats;
+    fn->wifi_multi_sta_set_primary_connection = wifi_multi_sta_set_primary_connection;
+    fn->wifi_multi_sta_set_use_case = wifi_multi_sta_set_use_case;
+    fn->wifi_set_voip_mode = wifi_set_voip_mode;
+    fn->wifi_set_dtim_config = wifi_set_dtim_config;
+    fn->wifi_get_usable_channels = wifi_get_usable_channels;
+    fn->wifi_trigger_subsystem_restart = wifi_trigger_subsystem_restart;
+    fn->wifi_get_supported_radio_combinations_matrix = wifi_get_supported_radio_combinations_matrix;
+    fn->wifi_nan_rtt_chre_enable_request = nan_chre_enable_request;
+    fn->wifi_nan_rtt_chre_disable_request = nan_chre_disable_request;
+    fn->wifi_chre_register_handler = nan_chre_register_handler;
 
     return WIFI_SUCCESS;
 }
+#ifdef GOOGLE_WIFI_FW_CONFIG_VERSION_C_WRAPPER
+#include <google_wifi_firmware_config_version_info.h>
+
+static void
+wifi_check_valid_ota_version(wifi_interface_handle handle)
+{
+    bool valid = false;
+    int32_t default_ver = get_google_default_vendor_wifi_config_version();
+    int32_t ota_ver = get_google_ota_updated_wifi_config_version();
+    ALOGE("default_ver %d, ota_ver %d", default_ver, ota_ver);
+
+    if (ota_ver > default_ver) {
+        valid = verify_google_ota_updated_wifi_config_integrity();
+    }
+
+    if (valid) {
+        ALOGE("Valid config files of OTA.");
+        wifi_hal_ota_update(handle, ota_ver);
+    }
+    else {
+        ALOGE("Do not valid config files of OTA.");
+    }
+}
+#endif // GOOGLE_WIFI_FW_CONFIG_VERSION_C_WRAPPER
 
 hal_info *halInfo = NULL;
 wifi_error wifi_pre_initialize(void)
@@ -302,7 +423,7 @@
     }
 
     /* Set the socket buffer size */
-    if (nl_socket_set_buffer_size(event_sock, (512*1024), 0) < 0) {
+    if (nl_socket_set_buffer_size(event_sock, (4*1024*1024), 0) < 0) {
         ALOGE("Could not set size for event_sock: %s",
                strerror(errno));
     } else {
@@ -376,6 +497,9 @@
     if (wlan0Handle != NULL) {
         ALOGE("Calling preInit");
         if (!get_halutil_mode()) {
+#ifdef GOOGLE_WIFI_FW_CONFIG_VERSION_C_WRAPPER
+            (void) wifi_check_valid_ota_version(wlan0Handle);
+#endif // GOOGLE_WIFI_FW_CONFIG_VERSION_C_WRAPPER
             result = wifi_hal_preInit(wlan0Handle);
             if (result != WIFI_SUCCESS) {
                 ALOGE("wifi_hal_preInit failed");
@@ -416,18 +540,10 @@
             if (result != WIFI_SUCCESS) {
                 ALOGE("wifi_start_hal failed");
             }
-#ifdef FILE_DUMP
-            else {
-                ALOGE("Calling start file dump");
-                result = wifi_start_file_dump(wlan0Handle);
-                if (result != WIFI_SUCCESS) {
-                    ALOGE("wifi_start_file_dump failed");
-                }
-            }
-#endif /* FILE_DUMP */
         }
     } else {
         ALOGI("Not Calling set alert handler as global_iface is NULL");
+        return WIFI_ERROR_UNKNOWN;
     }
     return WIFI_SUCCESS;
 }
@@ -500,15 +616,21 @@
 
     ALOGI("Internal cleanup completed");
 }
+
 void wifi_internal_module_cleanup()
 {
     nan_deinit_handler();
+    twt_deinit_handler();
 }
 
 void wifi_cleanup(wifi_handle handle, wifi_cleaned_up_handler handler)
 {
+    if (!handle) {
+        ALOGE("Handle is null");
+        return;
+    }
+
     hal_info *info = getHalInfo(handle);
-    char buf[64];
     wifi_error result;
 
     int numIfaceHandles = 0;
@@ -528,39 +650,12 @@
             }
         }
 
-#ifdef FILE_DUMP
-        ALOGE("Calling stop file dump");
-        result = wifi_stop_file_dump(wlan0Handle);
-        if (result != WIFI_SUCCESS) {
-            ALOGE("wifi_stop_file_dump failed");
-        }
-#endif /* FILE_DUMP */
     } else {
         ALOGE("Not cleaning up hal as global_iface is NULL");
     }
 
-    if (TEMP_FAILURE_RETRY(write(info->cleanup_socks[0], "Exit", 4)) < 1) {
-        // As a fallback set the cleanup flag to TRUE
-        ALOGE("could not write to the cleanup socket");
-    } else {
-        // Listen to the response
-        // Hopefully we dont get errors or get hung up
-        // Not much can be done in that case, but assume that
-        // it has rx'ed the Exit message to exit the thread.
-        // As a fallback set the cleanup flag to TRUE
-        memset(buf, 0, sizeof(buf));
-        ssize_t result = TEMP_FAILURE_RETRY(read(info->cleanup_socks[0], buf, sizeof(buf)));
-        ALOGE("%s: Read after POLL returned %zd, error no = %d (%s)", __FUNCTION__,
-               result, errno, strerror(errno));
-        if (strncmp(buf, "Done", 4) == 0) {
-            ALOGE("Event processing terminated");
-        } else {
-            ALOGD("Rx'ed %s", buf);
-        }
-    }
-    info->clean_up = true;
+    /* calling internal modules or cleanup */
     wifi_internal_module_cleanup();
-    ALOGI("wifi nan internal clean up done");
     pthread_mutex_lock(&info->cb_lock);
 
     int bad_commands = 0;
@@ -608,8 +703,17 @@
         WifiCommand *cmd = (WifiCommand *)cbi->cb_arg;
         ALOGE("Leaked command %p", cmd);
     }
+    if (!get_halutil_mode()) {
+        wifi_cleanup_dynamic_ifaces(handle);
+    }
     pthread_mutex_unlock(&info->cb_lock);
-    internal_cleaned_up_handler(handle);
+
+    info->clean_up = true;
+
+    if (TEMP_FAILURE_RETRY(write(info->cleanup_socks[0], "Exit", 4)) < 1) {
+        // As a fallback set the cleanup flag to TRUE
+        ALOGE("could not write to the cleanup socket");
+    }
     ALOGE("wifi_clean_up done");
 }
 
@@ -657,31 +761,25 @@
             ssize_t result2 = TEMP_FAILURE_RETRY(read(pfd[0].fd, buf, sizeof(buf)));
             ALOGE("Read after POLL returned %zd, error no = %d (%s)", result2,
                   errno, strerror(errno));
+            if (errno == WIFI_HAL_EVENT_BUFFER_NOT_AVAILABLE) {
+                ALOGE("Exit, No buffer space");
+                break;
+            }
         } else if (pfd[0].revents & POLLHUP) {
             ALOGE("Remote side hung up");
             break;
-        } else if (pfd[0].revents & POLLIN) {
+        } else if (pfd[0].revents & POLLIN && !info->clean_up) {
             // ALOGI("Found some events!!!");
             internal_pollin_handler(handle);
         } else if (pfd[1].revents & POLLIN) {
-            memset(buf, 0, sizeof(buf));
-            ssize_t result2 = TEMP_FAILURE_RETRY(read(pfd[1].fd, buf, sizeof(buf)));
-            ALOGE("%s: Read after POLL returned %zd, error no = %d (%s)", __FUNCTION__,
-                   result2, errno, strerror(errno));
-            if (strncmp(buf, "Exit", 4) == 0) {
-                ALOGD("Got a signal to exit!!!");
-                if (TEMP_FAILURE_RETRY(write(pfd[1].fd, "Done", 4)) < 1) {
-                    ALOGE("could not write to the cleanup socket");
-                }
-                break;
-            } else {
-                ALOGD("Rx'ed %s on the cleanup socket\n", buf);
-            }
+            ALOGI("Got a signal to exit!!!");
         } else {
             ALOGE("Unknown event - %0x, %0x", pfd[0].revents, pfd[1].revents);
         }
     } while (!info->clean_up);
-    ALOGI("Exit %s", __FUNCTION__);
+
+    internal_cleaned_up_handler(handle);
+    ALOGE("Exit %s", __FUNCTION__);
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////
@@ -721,8 +819,6 @@
     // ALOGV("event received %s, vendor_id = 0x%0x", event.get_cmdString(), vendor_id);
     // event.log();
 
-    bool dispatched = false;
-
     pthread_mutex_lock(&info->cb_lock);
 
     for (int i = 0; i < info->num_event_cb; i++) {
@@ -794,7 +890,6 @@
         // ALOGI("handling reponse in %s", __func__);
 
         struct nlattr **tb = reply.attributes();
-        struct genlmsghdr *gnlh = reply.header();
         struct nlattr *mcgrp = NULL;
         int i;
 
@@ -961,7 +1056,36 @@
         : WifiCommand("SetRSSIMonitorCommand", handle, id), mMax_rssi(max_rssi), mMin_rssi
         (min_rssi), mHandler(eh)
         {
+            ALOGI("SetRSSIMonitorCommand %p created", this);
         }
+
+   virtual ~SetRSSIMonitorCommand() {
+        /*
+         * Mostly, this call will be no effect. However, this could be valid
+         * when object destroy without calling unregisterVendorHandler().
+         * This is added to protect hal crash due to use-after-free.
+         */
+        ALOGI("Try to remove event handler if exist, vendor 0x%0x, subcmd 0x%x",
+            GOOGLE_OUI, GOOGLE_RSSI_MONITOR_EVENT);
+        unregisterVendorHandlerWithoutLock(GOOGLE_OUI, GOOGLE_RSSI_MONITOR_EVENT);
+        ALOGI("SetRSSIMonitorCommand %p destroyed", this);
+   }
+
+   virtual void addRef() {
+        int refs = __sync_add_and_fetch(&mRefs, 1);
+        ALOGI("addRef: WifiCommand %p has %d references", this, refs);
+   }
+
+   virtual void releaseRef() {
+        int refs = __sync_sub_and_fetch(&mRefs, 1);
+        if (refs == 0) {
+            ALOGI("releaseRef: WifiCommand %p has deleted", this);
+            delete this;
+        } else {
+            ALOGI("releaseRef: WifiCommand %p has %d references", this, refs);
+        }
+   }
+
    int createRequest(WifiRequest& request, int enable) {
         int result = request.create(GOOGLE_OUI, WIFI_SUBCMD_SET_RSSI_MONITOR);
         if (result < 0) {
@@ -989,27 +1113,27 @@
     int start() {
         WifiRequest request(familyId(), ifaceId());
         int result = createRequest(request, 1);
-        if (result < 0) {
+        if (result != WIFI_SUCCESS) {
+            ALOGE("Failed to create request; result = %d", result);
             return result;
         }
+
+        registerVendorHandler(GOOGLE_OUI, GOOGLE_RSSI_MONITOR_EVENT);
+        ALOGI("Register GOOGLE_RSSI_MONITOR_EVENT handler");
+
         result = requestResponse(request);
-        if (result < 0) {
-            ALOGI("Failed to set RSSI Monitor, result = %d", result);
-            return result;
-        }
-        ALOGI("Successfully set RSSI monitoring");
-        result = registerVendorHandler(GOOGLE_OUI, GOOGLE_RSSI_MONITOR_EVENT);
-
-
-        if (result < 0) {
+        if (result != WIFI_SUCCESS) {
             unregisterVendorHandler(GOOGLE_OUI, GOOGLE_RSSI_MONITOR_EVENT);
+            ALOGE("Failed to set RSSI Monitor, result = %d", result);
             return result;
         }
-        ALOGI("Done!");
+
+        ALOGI("Successfully set RSSI monitoring");
         return result;
     }
 
     virtual int cancel() {
+        unregisterVendorHandler(GOOGLE_OUI, GOOGLE_RSSI_MONITOR_EVENT);
 
         WifiRequest request(familyId(), ifaceId());
         int result = createRequest(request, 0);
@@ -1021,7 +1145,6 @@
                 ALOGE("failed to stop RSSI monitoring = %d", result);
             }
         }
-        unregisterVendorHandler(GOOGLE_OUI, GOOGLE_RSSI_MONITOR_EVENT);
         return WIFI_SUCCESS;
     }
 
@@ -1069,6 +1192,7 @@
 class AndroidPktFilterCommand : public WifiCommand {
     private:
         const u8* mProgram;
+        u8* mReadProgram;
         u32 mProgramLen;
         u32* mVersion;
         u32* mMaxLen;
@@ -1094,13 +1218,24 @@
             mMaxLen = NULL;
         }
 
+        AndroidPktFilterCommand(wifi_interface_handle handle,
+            u8* host_dst, u32 length)
+            : WifiCommand("AndroidPktFilterCommand", handle, 0),
+                mReadProgram(host_dst), mProgramLen(length),
+                mReqType(READ_APF_PROGRAM)
+        {
+        }
+
     int createRequest(WifiRequest& request) {
         if (mReqType == SET_APF_PROGRAM) {
             ALOGI("\n%s: APF set program request\n", __FUNCTION__);
             return createSetPktFilterRequest(request);
         } else if (mReqType == GET_APF_CAPABILITIES) {
             ALOGI("\n%s: APF get capabilities request\n", __FUNCTION__);
-            return createGetPktFilterCapabilitesRequest(request);
+	    return createGetPktFilterCapabilitesRequest(request);
+        } else if (mReqType == READ_APF_PROGRAM) {
+            ALOGI("\n%s: APF read packet filter request\n", __FUNCTION__);
+            return createReadPktFilterRequest(request);
         } else {
             ALOGE("\n%s Unknown APF request\n", __FUNCTION__);
             return WIFI_ERROR_NOT_SUPPORTED;
@@ -1143,6 +1278,16 @@
         return result;
     }
 
+    int createReadPktFilterRequest(WifiRequest& request) {
+        int result = request.create(GOOGLE_OUI, APF_SUBCMD_READ_FILTER);
+            if (result < 0) {
+                return result;
+            }
+            nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+            request.attr_end(data);
+            return result;
+    }
+
     int start() {
         WifiRequest request(familyId(), ifaceId());
         int result = createRequest(request);
@@ -1182,11 +1327,11 @@
             return NL_SKIP;
         }
         if( mReqType == SET_APF_PROGRAM) {
-            ALOGD("Response recieved for set packet filter command\n");
+            ALOGD("Response received for set packet filter command\n");
         } else if (mReqType == GET_APF_CAPABILITIES) {
             *mVersion = 0;
             *mMaxLen = 0;
-            ALOGD("Response recieved for get packet filter capabilities command\n");
+            ALOGD("Response received for get packet filter capabilities command\n");
             for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
                 if (it.get_type() == APF_ATTRIBUTE_VERSION) {
                     *mVersion = it.get_u32();
@@ -1199,12 +1344,24 @@
                             it.get_type(), it.get_len());
                 }
             }
+        } else if (mReqType == READ_APF_PROGRAM) {
+            ALOGD("Read packet filter, mProgramLen = %d\n", mProgramLen);
+            for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+                if (it.get_type() == APF_ATTRIBUTE_PROGRAM) {
+                    u8 *buffer = NULL;
+                    buffer = (u8 *)it.get_data();
+                    memcpy(mReadProgram, buffer, mProgramLen);
+                } else if (it.get_type() == APF_ATTRIBUTE_PROGRAM_LEN) {
+                    int apf_length = it.get_u32();
+                    ALOGD("apf program length = %d\n", apf_length);
+                }
+            }
         }
         return NL_OK;
     }
 
     int handleEvent(WifiEvent& event) {
-        /* No Event to recieve for APF commands */
+        /* No Event to receive for APF commands */
         return NL_SKIP;
     }
 };
@@ -1335,6 +1492,93 @@
     }
 
 };
+/////////////////////////////////////////////////////////////////////
+class GetRadioComboCommand : public WifiCommand {
+private:
+    wifi_radio_combination_matrix *rcmatrix;
+    u32* rc_size;
+    u32 set_size_max;
+    int ret = 0;
+
+public:
+    GetRadioComboCommand(wifi_interface_handle handle, u32 max_size, u32* size,
+        wifi_radio_combination_matrix *radio_combination_matrix)
+        : WifiCommand("GetRadioComboCommand", handle, 0), rcmatrix(radio_combination_matrix),
+        rc_size(size), set_size_max(max_size)
+    {
+    }
+
+    virtual int createRequest(WifiRequest& mMsg) {
+        ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_GET_RADIO_COMBO_MATRIX);
+        if (ret < 0) {
+            ALOGE("Can't create message to send to driver - %d", ret);
+        }
+        nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);
+        mMsg.attr_end(data);
+
+        return ret;
+    }
+
+    int start() {
+        WifiRequest request(familyId(), ifaceId());
+        ret = createRequest(request);
+        if (ret < 0) {
+            ALOGE("Request failed for radio_combo_matrix, result = %d", ret);
+            return ret;
+        }
+        ret = requestResponse(request);
+        if (ret < 0) {
+            ALOGE("Request Response failed for radio_combo_matrix, result = %d", ret);
+            return ret;
+        }
+        ALOGD("Done! %s", __FUNCTION__);
+        return ret;
+    }
+
+protected:
+   virtual int handleResponse(WifiEvent& reply) {
+        ALOGD("In GetRadioComboCommand::handleResponse");
+        if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+            ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+            return NL_SKIP;
+        }
+
+        int id = reply.get_vendor_id();
+        int subcmd = reply.get_vendor_subcmd();
+
+        nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+        int len = reply.get_vendor_data_len();
+
+        ALOGV("Id = %0x, subcmd = %d, len = %d", id, subcmd, len);
+        if (vendor_data == NULL || len == 0) {
+            ALOGE("no vendor data in GetRadioComboCommand response; ignoring it");
+            return NL_SKIP;
+        }
+
+        for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+            if (it.get_type() == ANDR_WIFI_ATTRIBUTE_RADIO_COMBO_MATRIX) {
+                void *data = it.get_data();
+                *rc_size = it.get_len();
+                if (!data || !*rc_size) {
+                    ALOGE("Buffers pointers not set");
+                    return NL_SKIP;
+                }
+                if (set_size_max < *rc_size) {
+                    ALOGE("Unexpected buffers size");
+                    return NL_SKIP;
+                }
+                memcpy(rcmatrix, data, min(len, *rc_size));
+            } else {
+                ALOGW("Ignoring invalid attribute type = %d, size = %d",
+                        it.get_type(), it.get_len());
+            }
+        }
+
+        ALOGD("GetRadioComboCommand::Success");
+        return NL_OK;
+    }
+};
+/////////////////////////////////////////////////////////////////////
 
 class SetLatencyModeCommand : public WifiCommand {
 private:
@@ -1385,7 +1629,8 @@
 
 static bool is_wifi_interface(const char *name)
 {
-    if (strncmp(name, "wlan", 4) != 0 && strncmp(name, "swlan", 5) != 0 && strncmp(name, "p2p", 3) != 0) {
+    if (strncmp(name, "wlan", 4) != 0 && strncmp(name, "swlan", 5) != 0 &&
+        strncmp(name, "p2p", 3) != 0 && strncmp(name, "aware", 5) != 0) {
         /* not a wifi interface; ignore it */
         return false;
     } else {
@@ -1395,7 +1640,11 @@
 
 static int get_interface(const char *name, interface_info *info)
 {
-    strlcpy(info->name, name, sizeof(info->name));
+    int size = 0;
+    size = strlcpy(info->name, name, sizeof(info->name));
+    if (size >= sizeof(info->name)) {
+        return WIFI_ERROR_OUT_OF_MEMORY;
+    }
     info->id = if_nametoindex(name);
     // ALOGI("found an interface : %s, id = %d", name, info->id);
     return WIFI_SUCCESS;
@@ -1429,7 +1678,9 @@
     if (d == 0)
         return WIFI_ERROR_UNKNOWN;
 
-    info->interfaces = (interface_info **)malloc(sizeof(interface_info *) * n);
+    /* Have place holder for 3 virtual interfaces */
+    n += MAX_VIRTUAL_IFACES;
+    info->interfaces = (interface_info **)calloc(n, sizeof(interface_info *) * n);
     if (!info->interfaces) {
         info->num_interfaces = 0;
         closedir(d);
@@ -1448,10 +1699,12 @@
                 closedir(d);
                 return WIFI_ERROR_OUT_OF_MEMORY;
             }
+            memset(ifinfo, 0, sizeof(interface_info));
             if (get_interface(de->d_name, ifinfo) != WIFI_SUCCESS) {
-                free(ifinfo);
                 continue;
             }
+            /* Mark as static iface */
+            ifinfo->is_virtual = false;
             ifinfo->handle = handle;
             info->interfaces[i] = ifinfo;
             i++;
@@ -1460,7 +1713,8 @@
 
     closedir(d);
 
-    info->num_interfaces = n;
+    info->num_interfaces = i;
+    info->max_num_interfaces = n;
     return WIFI_SUCCESS;
 }
 
@@ -1474,6 +1728,74 @@
     return WIFI_SUCCESS;
 }
 
+wifi_error wifi_add_iface_hal_info(wifi_handle handle, const char* ifname)
+{
+    hal_info *info = NULL;
+    int i = 0;
+
+    info = (hal_info *)handle;
+    if (info == NULL) {
+        ALOGE("Could not find info\n");
+        return WIFI_ERROR_UNKNOWN;
+    }
+
+    ALOGI("%s: add interface_info for iface: %s\n", __FUNCTION__, ifname);
+    if (info->num_interfaces == MAX_VIRTUAL_IFACES) {
+        ALOGE("No space. max limit reached for virtual interfaces %d\n", info->num_interfaces);
+        return WIFI_ERROR_OUT_OF_MEMORY;
+    }
+
+    interface_info *ifinfo = (interface_info *)malloc(sizeof(interface_info));
+    if (!ifinfo) {
+        free(info->interfaces);
+        info->num_interfaces = 0;
+        return WIFI_ERROR_OUT_OF_MEMORY;
+    }
+
+    ifinfo->handle = handle;
+    while (i < info->max_num_interfaces) {
+        if (info->interfaces[i] == NULL) {
+            if (get_interface(ifname, ifinfo) != WIFI_SUCCESS) {
+                continue;
+            }
+            ifinfo->is_virtual = true;
+            info->interfaces[i] = ifinfo;
+            info->num_interfaces++;
+            ALOGI("%s: Added iface: %s at the index %d\n", __FUNCTION__, ifname, i);
+            break;
+        }
+        i++;
+    }
+    return WIFI_SUCCESS;
+}
+
+wifi_error wifi_clear_iface_hal_info(wifi_handle handle, const char* ifname)
+{
+    hal_info *info = (hal_info *)handle;
+    int i = 0;
+
+    ALOGI("%s: clear hal info for iface: %s\n", __FUNCTION__, ifname);
+    while (i < info->max_num_interfaces) {
+        if ((info->interfaces[i] != NULL) &&
+            strncmp(info->interfaces[i]->name, ifname,
+            sizeof(info->interfaces[i]->name)) == 0) {
+            free(info->interfaces[i]);
+            info->interfaces[i] = NULL;
+            info->num_interfaces--;
+            ALOGI("%s: Cleared the index = %d for iface: %s\n", __FUNCTION__, i, ifname);
+            break;
+        }
+        i++;
+    }
+    if (i < info->num_interfaces) {
+        for (int j = i; j < info->num_interfaces; j++) {
+            info->interfaces[j] = info->interfaces[j+1];
+        }
+        info->interfaces[info->num_interfaces] = NULL;
+    }
+    return WIFI_SUCCESS;
+}
+
 wifi_interface_handle wifi_get_wlan_interface(wifi_handle info, wifi_interface_handle *ifaceHandles, int numIfaceHandles)
 {
     char buf[EVENT_BUF_SIZE];
@@ -1484,7 +1806,7 @@
     }
     for (int i = 0; i < numIfaceHandles; i++) {
         if (wifi_get_iface_name(ifaceHandles[i], buf, sizeof(buf)) == WIFI_SUCCESS) {
-            if (strcmp(buf, "wlan0") == 0) {
+            if (strncmp(buf, "wlan0", 5) == 0) {
                 ALOGI("found interface %s\n", buf);
                 wlan0Handle = ifaceHandles[i];
                 return wlan0Handle;
@@ -1501,6 +1823,29 @@
     return WIFI_SUCCESS;
 }
 
+wifi_interface_handle wifi_get_iface_handle(wifi_handle handle, char *name)
+{
+    char buf[EVENT_BUF_SIZE];
+    wifi_interface_handle *ifaceHandles;
+    int numIfaceHandles;
+    wifi_interface_handle ifHandle;
+
+    wifi_error res = wifi_get_ifaces((wifi_handle)handle, &numIfaceHandles, &ifaceHandles);
+    if (res < 0) {
+        return NULL;
+    }
+    for (int i = 0; i < numIfaceHandles; i++) {
+        if (wifi_get_iface_name(ifaceHandles[i], buf, sizeof(buf)) == WIFI_SUCCESS) {
+            if (strcmp(buf, name) == 0) {
+                ALOGI("found interface %s\n", buf);
+                ifHandle = ifaceHandles[i];
+                return ifHandle;
+            }
+        }
+    }
+    return NULL;
+}
+
 wifi_error wifi_get_supported_feature_set(wifi_interface_handle handle, feature_set *set)
 {
     GetFeatureSetCommand command(handle, ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET, set, NULL, NULL, 1);
@@ -1515,6 +1860,27 @@
     return (wifi_error) command.requestResponse();
 }
 
+wifi_error wifi_get_supported_radio_combinations_matrix(wifi_handle handle,
+    u32 max_size, u32* size, wifi_radio_combination_matrix *radio_combination_matrix)
+{
+    int numIfaceHandles = 0;
+    wifi_interface_handle *ifaceHandles = NULL;
+    wifi_interface_handle wlan0Handle;
+
+    wlan0Handle = wifi_get_wlan_interface((wifi_handle)handle, ifaceHandles, numIfaceHandles);
+    GetRadioComboCommand *cmd = new GetRadioComboCommand(wlan0Handle, max_size,
+        size, radio_combination_matrix);
+    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+    wifi_error result = (wifi_error)cmd->start();
+    if (result == WIFI_SUCCESS) {
+        ALOGD("Get radio combo matrix success");
+    } else {
+        ALOGE("Get radio combo matrix failed\n");
+    }
+    cmd->releaseRef();
+    return result;
+}
+
 wifi_error wifi_set_scanning_mac_oui(wifi_interface_handle handle, oui scan_oui)
 {
     SetPnoMacAddrOuiCommand command(handle, scan_oui);
@@ -1537,17 +1903,19 @@
 static wifi_error wifi_start_rssi_monitoring(wifi_request_id id, wifi_interface_handle
                         iface, s8 max_rssi, s8 min_rssi, wifi_rssi_event_handler eh)
 {
-    ALOGD("Start RSSI monitor %d", id);
+    ALOGI("Starting RSSI monitor %d", id);
     wifi_handle handle = getWifiHandle(iface);
     SetRSSIMonitorCommand *cmd = new SetRSSIMonitorCommand(id, iface, max_rssi, min_rssi, eh);
     NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
     wifi_error result = wifi_register_cmd(handle, id, cmd);
     if (result != WIFI_SUCCESS) {
+        ALOGI("wifi_register_cmd() is failed %d", id);
         cmd->releaseRef();
         return result;
     }
     result = (wifi_error)cmd->start();
     if (result != WIFI_SUCCESS) {
+        ALOGI("start() is failed %d", id);
         wifi_unregister_cmd(handle, id);
         cmd->releaseRef();
         return result;
@@ -1557,12 +1925,11 @@
 
 static wifi_error wifi_stop_rssi_monitoring(wifi_request_id id, wifi_interface_handle iface)
 {
-    ALOGD("Stopping RSSI monitor");
+    ALOGI("Stopping RSSI monitor %d", id);
 
     if(id == -1) {
         wifi_rssi_event_handler handler;
         s8 max_rssi = 0, min_rssi = 0;
-        wifi_handle handle = getWifiHandle(iface);
         memset(&handler, 0, sizeof(handler));
         SetRSSIMonitorCommand *cmd = new SetRSSIMonitorCommand(id, iface,
                                                     max_rssi, min_rssi, handler);
@@ -1599,6 +1966,19 @@
     return result;
 }
 
+static wifi_error wifi_read_packet_filter(wifi_interface_handle handle,
+    u32 src_offset, u8 *host_dst, u32 length)
+{
+    ALOGD("Read APF program, halHandle = %p, length = %d\n", handle, length);
+    AndroidPktFilterCommand *cmd = new AndroidPktFilterCommand(handle, host_dst, length);
+    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+    wifi_error result = (wifi_error)cmd->start();
+    if (result == WIFI_SUCCESS) {
+        ALOGI("Read APF program success\n");
+    }
+    cmd->releaseRef();
+    return result;
+}
 static wifi_error wifi_configure_nd_offload(wifi_interface_handle handle, u8 enable)
 {
     SetNdoffloadCommand command(handle, enable);
@@ -1636,7 +2016,7 @@
         }
 
         if ((mScenario <= WIFI_POWER_SCENARIO_INVALID) ||
-           (mScenario > WIFI_POWER_SCENARIO_ON_BODY_BT)) {
+           (mScenario >= SAR_CONFIG_SCENARIO_COUNT)) {
             ALOGE("Unsupported tx power value:%d\n", mScenario);
             return WIFI_ERROR_NOT_SUPPORTED;
         }
@@ -1690,3 +2070,934 @@
 }
 
 /////////////////////////////////////////////////////////////////////////////
+
+class ThermalMitigation : public WifiCommand {
+private:
+    wifi_thermal_mode mMitigation;
+    u32 mCompletionWindow;
+public:
+    // constructor for thermal mitigation setting
+    ThermalMitigation(wifi_interface_handle handle,
+		    wifi_thermal_mode mitigation, u32 completion_window)
+    : WifiCommand("ThermalMitigation", handle, 0)
+    {
+        mMitigation = mitigation;
+		mCompletionWindow = completion_window;
+    }
+
+    int createRequest(WifiRequest& request, int subcmd,
+		    wifi_thermal_mode mitigation, u32 completion_window) {
+        int result = request.create(GOOGLE_OUI, subcmd);
+        if (result < 0) {
+            return result;
+        }
+
+        if ((mitigation < WIFI_MITIGATION_NONE) ||
+           (mitigation > WIFI_MITIGATION_EMERGENCY)) {
+            ALOGE("Unsupported tx mitigation value:%d\n", mitigation);
+            return WIFI_ERROR_NOT_SUPPORTED;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        result = request.put_s8(ANDR_WIFI_ATTRIBUTE_THERMAL_MITIGATION, mitigation);
+        if (result < 0) {
+            ALOGE("Failed to put tx power scenario request; result = %d", result);
+            return result;
+        }
+        result = request.put_u32(ANDR_WIFI_ATTRIBUTE_THERMAL_COMPLETION_WINDOW,
+		       	completion_window);
+        if (result < 0) {
+            ALOGE("Failed to put tx power scenario request; result = %d", result);
+            return result;
+        }
+
+        request.attr_end(data);
+        return WIFI_SUCCESS;
+    }
+
+    int start() {
+        WifiRequest request(familyId(), ifaceId());
+        int result = createRequest(request, WIFI_SUBCMD_THERMAL_MITIGATION, mMitigation,
+		       	mCompletionWindow);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to create request; result = %d", result);
+            return result;
+        }
+
+        ALOGD("try to get resp; mitigation=%d, delay=%d", mMitigation, mCompletionWindow);
+        result = requestResponse(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to send thermal mitigation; result = %d", result);
+        }
+        return result;
+    }
+protected:
+    virtual int handleResponse(WifiEvent& reply) {
+        ALOGD("Request complete!");
+        /* Nothing to do on response! */
+        return NL_SKIP;
+    }
+};
+
+wifi_error wifi_set_thermal_mitigation_mode(wifi_handle handle,
+                                            wifi_thermal_mode mode,
+                                            u32 completion_window)
+{
+    int numIfaceHandles = 0;
+    wifi_interface_handle *ifaceHandles = NULL;
+    wifi_interface_handle wlan0Handle;
+
+    wlan0Handle = wifi_get_wlan_interface((wifi_handle)handle, ifaceHandles, numIfaceHandles);
+    ThermalMitigation command(wlan0Handle, mode, completion_window);
+    return (wifi_error)command.start();
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+class ChAvoidCommand : public WifiCommand {
+    private:
+        u32 mNumParams;
+        wifi_coex_unsafe_channel *chavoidParams;
+        u32 mMandatory;
+
+    public:
+        ChAvoidCommand(wifi_interface_handle handle,
+            u32 num, wifi_coex_unsafe_channel channels[], u32 mandatory)
+            : WifiCommand("ChAvoidCommand", handle, 0),
+                mNumParams(num), chavoidParams(channels), mMandatory(mandatory)
+        {
+        }
+
+    int createRequest(WifiRequest& request) {
+        return createSetChAvoidRequest(request);
+    }
+
+    int createSetChAvoidRequest(WifiRequest& request) {
+        int result = request.create(GOOGLE_OUI, CHAVOID_SUBCMD_SET_CONFIG);
+        if (result < 0) {
+            ALOGE("%s : Failed to create SUBCMD\n", __func__);
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        result = request.put_u32(CHAVOID_ATTRIBUTE_CNT, mNumParams);
+        if (result < 0) {
+            ALOGE("%s : Failed to set cound\n", __func__);
+            return result;
+        }
+        result = request.put_u32(CHAVOID_ATTRIBUTE_MANDATORY, mMandatory);
+        if (result < 0) {
+            ALOGE("%s : Failed to set mandatory cap\n", __func__);
+            return result;
+        }
+
+        nlattr *chavoid_config = request.attr_start(CHAVOID_ATTRIBUTE_CONFIG);
+        for (int i = 0; i< mNumParams; i++) {
+            nlattr *item = request.attr_start(i);
+            if (item == NULL) {
+                ALOGE("%s : Failed to alloc item\n", __func__);
+                return WIFI_ERROR_OUT_OF_MEMORY;
+            }
+            result = request.put_u32(CHAVOID_ATTRIBUTE_BAND, chavoidParams[i].band);
+            if (result < 0) {
+                ALOGE("%s : Failed to set band\n", __func__);
+                return result;
+            }
+            result = request.put_u32(CHAVOID_ATTRIBUTE_CHANNEL, chavoidParams[i].channel);
+            if (result < 0) {
+                ALOGE("%s : Failed to set channel\n", __func__);
+                return result;
+            }
+            result = request.put_u32(CHAVOID_ATTRIBUTE_PWRCAP, chavoidParams[i].power_cap_dbm);
+            if (result < 0) {
+                ALOGE("%s : Failed to set power cap\n", __func__);
+                return result;
+            }
+            request.attr_end(item);
+        }
+        request.attr_end(chavoid_config);
+        request.attr_end(data);
+        return WIFI_SUCCESS;
+    }
+
+    int start() {
+        WifiRequest request(familyId(), ifaceId());
+        int result = createRequest(request);
+        if (result < 0) {
+            return result;
+        }
+        result = requestResponse(request);
+        if (result < 0) {
+            ALOGI("Request Response failed for ChAvoid, result = %d", result);
+            return result;
+        }
+        return result;
+    }
+
+    int handleResponse(WifiEvent& reply) {
+        ALOGD("In ChAvoidCommand::handleResponse");
+
+        if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+            ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+            return NL_SKIP;
+        }
+
+        nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+        int len = reply.get_vendor_data_len();
+
+        if (vendor_data == NULL || len == 0) {
+            ALOGE("no vendor data in ChAvoidCommand response; ignoring it");
+            return NL_SKIP;
+        }
+        ALOGD("Response received for ChAvoid command\n");
+        return NL_OK;
+    }
+
+    int handleEvent(WifiEvent& event) {
+        /* No Event to receive for ChAvoid commands */
+        ALOGD("ChAvoid command %s\n", __FUNCTION__);
+        return NL_SKIP;
+    }
+};
+
+wifi_error wifi_set_coex_unsafe_channels(wifi_handle handle,
+        u32 num, wifi_coex_unsafe_channel channels[], u32 mandatory)
+{
+    int numIfaceHandles = 0;
+    wifi_interface_handle *ifaceHandles = NULL;
+    wifi_interface_handle wlan0Handle;
+
+    wlan0Handle = wifi_get_wlan_interface((wifi_handle)handle, ifaceHandles, numIfaceHandles);
+
+    ChAvoidCommand *cmd = new ChAvoidCommand(wlan0Handle, num, channels, mandatory);
+    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+    wifi_error result = (wifi_error)cmd->start();
+    if (result == WIFI_SUCCESS) {
+        ALOGI("Setting Channel Avoidance success\n");
+    } else {
+        ALOGE("Setting Channel Avoidance failed\n");
+    }
+    cmd->releaseRef();
+    return result;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+class DscpCommand : public WifiCommand {
+    private:
+	u32 mStart;
+	u32 mEnd;
+	u32 mAc;
+        int mReqType;
+    public:
+        DscpCommand(wifi_interface_handle handle,
+                u32 start, u32 end, u32 ac)
+            : WifiCommand("DscpCommand", handle, 0),
+                    mStart(start), mEnd(end), mAc(ac),
+                    mReqType(SET_DSCP_TABLE)
+        {
+        }
+
+        DscpCommand(wifi_interface_handle handle)
+            : WifiCommand("DscpCommand", handle, 0),
+                    mReqType(RESET_DSCP_TABLE)
+        {
+        }
+
+    int createRequest(WifiRequest& request) {
+        if (mReqType == SET_DSCP_TABLE) {
+            ALOGI("\n%s: DSCP set table request\n", __FUNCTION__);
+            return createSetDscpRequest(request);
+        } else if (mReqType == RESET_DSCP_TABLE) {
+            ALOGI("\n%s: DSCP reset table request\n", __FUNCTION__);
+            return createResetDscpRequest(request);
+        } else {
+            ALOGE("\n%s Unknown DSCP request\n", __FUNCTION__);
+            return WIFI_ERROR_NOT_SUPPORTED;
+        }
+        return WIFI_SUCCESS;
+    }
+
+    int createSetDscpRequest(WifiRequest& request) {
+        int result = request.create(GOOGLE_OUI, DSCP_SUBCMD_SET_TABLE);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        result = request.put_u32(DSCP_ATTRIBUTE_START, mStart);
+        if (result < 0) {
+            goto exit;
+        }
+        result = request.put_u32(DSCP_ATTRIBUTE_END, mEnd);
+        if (result < 0) {
+            goto exit;
+        }
+        result = request.put_u32(DSCP_ATTRIBUTE_AC, mAc);
+        if (result < 0) {
+            goto exit;
+        }
+        request.attr_end(data);
+exit:
+        return result;
+    }
+
+    int createResetDscpRequest(WifiRequest& request) {
+        int result = request.create(GOOGLE_OUI, DSCP_SUBCMD_RESET_TABLE);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        request.attr_end(data);
+        return result;
+    }
+
+    int start() {
+        WifiRequest request(familyId(), ifaceId());
+        int result = createRequest(request);
+        if (result < 0) {
+            return result;
+        }
+        result = requestResponse(request);
+        if (result < 0) {
+            ALOGI("Request Response failed for DSCP, result = %d", result);
+            return result;
+        }
+        return result;
+    }
+
+    int handleResponse(WifiEvent& reply) {
+        ALOGD("In DscpCommand::handleResponse");
+
+        if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+            ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+            return NL_SKIP;
+        }
+
+        nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+        int len = reply.get_vendor_data_len();
+
+        if (vendor_data == NULL || len == 0) {
+            ALOGE("no vendor data in DscpCommand response; ignoring it");
+            return NL_SKIP;
+        }
+        if( mReqType == SET_DSCP_TABLE) {
+            ALOGD("Response received for Set DSCP command\n");
+        } else if (mReqType == RESET_DSCP_TABLE) {
+            ALOGD("Response received for Reset DSCP command\n");
+        }
+        return NL_OK;
+    }
+
+    int handleEvent(WifiEvent& event) {
+        /* No Event to receive for DSCP commands */
+        ALOGD("DSCP command %s\n", __FUNCTION__);
+        return NL_SKIP;
+    }
+};
+
+wifi_error wifi_map_dscp_access_category(wifi_handle handle,
+        u32 start, u32 end, u32 ac)
+{
+    int numIfaceHandles = 0;
+    wifi_interface_handle *ifaceHandles = NULL;
+    wifi_interface_handle wlan0Handle;
+
+    wlan0Handle = wifi_get_wlan_interface((wifi_handle)handle, ifaceHandles, numIfaceHandles);
+
+    DscpCommand *cmd = new DscpCommand(wlan0Handle, start, end, ac);
+    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+    wifi_error result = (wifi_error)cmd->start();
+    if (result == WIFI_SUCCESS) {
+        ALOGI("Mapping DSCP table success\n");
+    } else {
+        ALOGE("Mapping DSCP table fail\n");
+    }
+    cmd->releaseRef();
+    return result;
+}
+
+wifi_error wifi_reset_dscp_mapping(wifi_handle handle)
+{
+    int numIfaceHandles = 0;
+    wifi_interface_handle *ifaceHandles = NULL;
+    wifi_interface_handle wlan0Handle;
+
+    wlan0Handle = wifi_get_wlan_interface((wifi_handle)handle, ifaceHandles, numIfaceHandles);
+
+    DscpCommand *cmd = new DscpCommand(wlan0Handle);
+    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+    wifi_error result = (wifi_error)cmd->start();
+    if (result == WIFI_SUCCESS) {
+        ALOGI("Resetting DSCP table success\n");
+    } else {
+        ALOGE("Resetting DSCP table fail\n");
+    }
+    cmd->releaseRef();
+    return result;
+}
+
+class VirtualIfaceConfig : public WifiCommand {
+    const char *mIfname;
+    nl80211_iftype mType;
+    u32 mwlan0_id;
+
+public:
+    VirtualIfaceConfig(wifi_interface_handle handle, const char* ifname,
+        nl80211_iftype iface_type, u32 wlan0_id)
+    : WifiCommand("VirtualIfaceConfig", handle, 0), mIfname(ifname), mType(iface_type),
+        mwlan0_id(wlan0_id)
+    {
+        mIfname = ifname;
+        mType = iface_type;
+        mwlan0_id = wlan0_id;
+    }
+    int createRequest(WifiRequest& request, const char* ifname,
+        nl80211_iftype iface_type, u32 wlan0_id) {
+        ALOGD("add ifname = %s, iface_type = %d, wlan0_id = %d",
+        ifname, iface_type, wlan0_id);
+
+        int result = request.create(NL80211_CMD_NEW_INTERFACE);
+        if (result < 0) {
+            ALOGE("failed to create NL80211_CMD_NEW_INTERFACE; result = %d", result);
+            return result;
+        }
+
+        result = request.put_u32(NL80211_ATTR_IFINDEX, wlan0_id);
+        if (result < 0) {
+            ALOGE("failed to put NL80211_ATTR_IFINDEX; result = %d", result);
+            return result;
+        }
+
+        result = request.put_string(NL80211_ATTR_IFNAME, ifname);
+        if (result < 0) {
+            ALOGE("failed to put NL80211_ATTR_IFNAME = %s; result = %d", ifname, result);
+            return result;
+        }
+
+        result = request.put_u32(NL80211_ATTR_IFTYPE, iface_type);
+        if (result < 0) {
+            ALOGE("failed to put NL80211_ATTR_IFTYPE = %d; result = %d", iface_type, result);
+            return result;
+        }
+        return WIFI_SUCCESS;
+    }
+
+    int deleteRequest(WifiRequest& request, const char* ifname) {
+        ALOGD("delete ifname = %s\n", ifname);
+        int result = request.create(NL80211_CMD_DEL_INTERFACE);
+        if (result < 0) {
+            ALOGE("failed to create NL80211_CMD_DEL_INTERFACE; result = %d", result);
+            return result;
+        }
+        result = request.put_u32(NL80211_ATTR_IFINDEX, if_nametoindex(ifname));
+        if (result < 0) {
+            ALOGE("failed to put NL80211_ATTR_IFINDEX = %d; result = %d",
+                if_nametoindex(ifname), result);
+            return result;
+        }
+        result = request.put_string(NL80211_ATTR_IFNAME, ifname);
+        if (result < 0) {
+            ALOGE("failed to put NL80211_ATTR_IFNAME = %s; result = %d", ifname, result);
+            return result;
+        }
+        return WIFI_SUCCESS;
+    }
+
+    int createIface() {
+        ALOGE("Creating virtual interface");
+        WifiRequest request(familyId(), ifaceId());
+        int result = createRequest(request, mIfname, mType, mwlan0_id);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to create virtual iface request; result = %d\n", result);
+            return result;
+        }
+
+        result = requestResponse(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to get the virtual iface create response; result = %d\n", result);
+            return result;
+        }
+        ALOGE("Created virtual interface");
+        return WIFI_SUCCESS;
+    }
+
+    int deleteIface() {
+        ALOGD("Deleting virtual interface");
+        WifiRequest request(familyId(), ifaceId());
+        int result = deleteRequest(request, mIfname);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to create virtual iface delete request; result = %d\n", result);
+            return result;
+        }
+
+        result = requestResponse(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to get response of delete virtual interface; result = %d\n", result);
+            return result;
+        }
+        return WIFI_SUCCESS;
+    }
+protected:
+    virtual int handleResponse(WifiEvent& reply) {
+         ALOGD("Request complete!");
+        /* Nothing to do on response! */
+        return NL_SKIP;
+    }
+};
+
+static std::vector<std::string> added_ifaces;
+
+static void wifi_cleanup_dynamic_ifaces(wifi_handle handle)
+{
+    int len = added_ifaces.size();
+    while (len--) {
+        wifi_virtual_interface_delete(handle, added_ifaces.front().c_str());
+    }
+    added_ifaces.clear();
+}
+
+wifi_error wifi_virtual_interface_create(wifi_handle handle, const char* ifname,
+        wifi_interface_type iface_type)
+{
+    int numIfaceHandles = 0;
+    wifi_error ret = WIFI_SUCCESS;
+    wifi_interface_handle *ifaceHandles = NULL;
+    wifi_interface_handle wlan0Handle;
+    nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
+    u32 wlan0_id = if_nametoindex("wlan0");
+
+    if (!handle || !wlan0_id) {
+        ALOGE("%s: Error wifi_handle NULL or wlan0 not present\n", __FUNCTION__);
+        return WIFI_ERROR_UNKNOWN;
+    }
+
+    /* Do not create interface if already exist. */
+    if (if_nametoindex(ifname)) {
+        ALOGD("%s: if_nametoindex(%s) = %d already exists, skip create \n",
+            __FUNCTION__, ifname, if_nametoindex(ifname));
+        return WIFI_SUCCESS;
+    }
+
+    ALOGD("%s: ifname name = %s, type = %s\n", __FUNCTION__, ifname,
+        IfaceTypeToString(iface_type));
+
+    switch (iface_type) {
+        case WIFI_INTERFACE_TYPE_STA:
+            type = NL80211_IFTYPE_STATION;
+            break;
+        case WIFI_INTERFACE_TYPE_AP:
+            type = NL80211_IFTYPE_AP;
+            break;
+        case WIFI_INTERFACE_TYPE_P2P:
+            type = NL80211_IFTYPE_P2P_DEVICE;
+            break;
+        case WIFI_INTERFACE_TYPE_NAN:
+            type = NL80211_IFTYPE_NAN;
+            break;
+        default:
+            ALOGE("%s: Wrong interface type %u\n", __FUNCTION__, iface_type);
+            return WIFI_ERROR_UNKNOWN;
+    }
+
+    wlan0Handle = wifi_get_wlan_interface((wifi_handle)handle, ifaceHandles, numIfaceHandles);
+    VirtualIfaceConfig command(wlan0Handle, ifname, type, wlan0_id);
+
+    ret = (wifi_error)command.createIface();
+    if (ret != WIFI_SUCCESS) {
+        ALOGE("%s: Iface add Error:%d", __FUNCTION__,ret);
+        return ret;
+    }
+    /* Update dynamic interface list */
+    added_ifaces.push_back(std::string(ifname));
+    ret = wifi_add_iface_hal_info((wifi_handle)handle, ifname);
+    return ret;
+}
+
+wifi_error wifi_virtual_interface_delete(wifi_handle handle, const char* ifname)
+{
+    int numIfaceHandles = 0;
+    int i = 0;
+    wifi_error ret = WIFI_SUCCESS;
+    wifi_interface_handle *ifaceHandles = NULL;
+    wifi_interface_handle wlan0Handle;
+    hal_info *info = (hal_info *)handle;
+    u32 wlan0_id = if_nametoindex("wlan0");
+
+    if (!handle || !wlan0_id) {
+        ALOGE("%s: Error wifi_handle NULL or wlan0 not present\n", __FUNCTION__);
+        return WIFI_ERROR_UNKNOWN;
+    }
+
+    while (i < info->max_num_interfaces) {
+        if (info->interfaces[i] != NULL &&
+            strncmp(info->interfaces[i]->name,
+            ifname, sizeof(info->interfaces[i]->name)) == 0) {
+            if (info->interfaces[i]->is_virtual == false) {
+                ALOGI("%s: %s is static iface, skip delete\n",
+                    __FUNCTION__, ifname);
+                    return WIFI_SUCCESS;
+        }
+    }
+        i++;
+    }
+
+    ALOGD("%s: iface name=%s\n", __FUNCTION__, ifname);
+    wlan0Handle = wifi_get_wlan_interface((wifi_handle)handle, ifaceHandles, numIfaceHandles);
+    VirtualIfaceConfig command(wlan0Handle, ifname, (nl80211_iftype)0, 0);
+    ret = (wifi_error)command.deleteIface();
+    if (ret != WIFI_SUCCESS) {
+        ALOGE("%s: Iface delete Error:%d", __FUNCTION__,ret);
+        return ret;
+    }
+    /* Update dynamic interface list */
+    added_ifaces.erase(std::remove(added_ifaces.begin(), added_ifaces.end(), std::string(ifname)),
+        added_ifaces.end());
+    ret = wifi_clear_iface_hal_info((wifi_handle)handle, ifname);
+    return ret;
+}
+/////////////////////////////////////////////////////////////////////////////
+
+class MultiStaConfig : public WifiCommand {
+    wifi_multi_sta_use_case mUseCase;
+    int mReqType;
+
+public:
+    MultiStaConfig(wifi_interface_handle handle)
+    : WifiCommand("MultiStaConfig", handle, 0), mReqType(SET_PRIMARY_CONNECTION)
+    {
+    }
+    MultiStaConfig(wifi_interface_handle handle, wifi_multi_sta_use_case use_case)
+    : WifiCommand("MultiStaConfig", handle, 0), mUseCase(use_case), mReqType(SET_USE_CASE)
+    {
+        mUseCase = use_case;
+    }
+
+    int createRequest(WifiRequest& request) {
+        if (mReqType == SET_PRIMARY_CONNECTION) {
+            ALOGI("\n%s: MultiSta set primary connection\n", __FUNCTION__);
+            return createSetPrimaryConnectionRequest(request);
+        } else if (mReqType == SET_USE_CASE) {
+            ALOGI("\n%s: MultiSta set use case\n", __FUNCTION__);
+            return createSetUsecaseRequest(request);
+        } else {
+            ALOGE("\n%s Unknown MultiSta request\n", __FUNCTION__);
+            return WIFI_ERROR_NOT_SUPPORTED;
+        }
+        return WIFI_SUCCESS;
+    }
+
+    int createSetPrimaryConnectionRequest(WifiRequest& request) {
+        int result = request.create(GOOGLE_OUI, WIFI_SUBCMD_SET_MULTISTA_PRIMARY_CONNECTION);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        request.attr_end(data);
+
+        return result;
+    }
+
+    int createSetUsecaseRequest(WifiRequest& request) {
+        int result = request.create(GOOGLE_OUI, WIFI_SUBCMD_SET_MULTISTA_USE_CASE);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        result = request.put_u32(MULTISTA_ATTRIBUTE_USE_CASE, mUseCase);
+        if (result < 0) {
+            ALOGE("failed to put MULTISTA_ATTRIBUTE_USE_CASE = %d; result = %d", mUseCase, result);
+            goto exit;
+        }
+
+exit:   request.attr_end(data);
+        return result;
+    }
+
+    int start() {
+        WifiRequest request(familyId(), ifaceId());
+        int result = createRequest(request);
+        if (result < 0) {
+            return result;
+        }
+        result = requestResponse(request);
+        if (result < 0) {
+            ALOGI("Request Response failed for MultiSta, result = %d", result);
+            return result;
+        }
+        ALOGI("Done!");
+        return result;
+    }
+protected:
+    virtual int handleResponse(WifiEvent& reply) {
+        ALOGD("Request complete!");
+        /* Nothing to do on response! */
+        return NL_SKIP;
+    }
+};
+
+wifi_error wifi_multi_sta_set_primary_connection(wifi_handle handle, wifi_interface_handle iface)
+{
+    wifi_error ret = WIFI_SUCCESS;
+    char buf[IFNAMSIZ];
+
+    if (!handle || !iface) {
+        ALOGE("%s: Error wifi_handle NULL or invalid wifi interface handle\n", __FUNCTION__);
+        return WIFI_ERROR_UNKNOWN;
+    }
+
+    if (wifi_get_iface_name(iface, buf, sizeof(buf)) != WIFI_SUCCESS) {
+        ALOGE("%s : Invalid interface handle\n", __func__);
+        return WIFI_ERROR_INVALID_ARGS;
+    }
+
+    ALOGD("Setting Multista primary connection for iface = %s\n", buf);
+
+    MultiStaConfig *cmd = new MultiStaConfig(iface);
+    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+    ret = (wifi_error)cmd->start();
+    cmd->releaseRef();
+    return ret;
+}
+
+wifi_error wifi_multi_sta_set_use_case(wifi_handle handle, wifi_multi_sta_use_case use_case)
+{
+    int numIfaceHandles = 0;
+    wifi_error ret = WIFI_SUCCESS;
+    wifi_interface_handle *ifaceHandles = NULL;
+    wifi_interface_handle wlan0Handle;
+
+    if (!handle) {
+        ALOGE("%s: Error wifi_handle NULL\n", __FUNCTION__);
+        return WIFI_ERROR_UNKNOWN;
+    }
+
+    if (!(use_case >= WIFI_DUAL_STA_TRANSIENT_PREFER_PRIMARY &&
+	    use_case <= WIFI_DUAL_STA_NON_TRANSIENT_UNBIASED)) {
+        ALOGE("%s: Invalid  multi_sta usecase %d\n", __FUNCTION__, use_case);
+        return WIFI_ERROR_INVALID_ARGS;
+    }
+
+    wlan0Handle = wifi_get_wlan_interface((wifi_handle)handle, ifaceHandles, numIfaceHandles);
+    ALOGD("Setting Multista usecase = %d\n", use_case);
+    MultiStaConfig *cmd = new MultiStaConfig(wlan0Handle, use_case);
+    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+    ret = (wifi_error)cmd->start();
+    cmd->releaseRef();
+    return ret;
+}
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+class SetVoipModeCommand : public WifiCommand {
+
+private:
+    wifi_voip_mode mMode;
+public:
+    SetVoipModeCommand(wifi_interface_handle handle, wifi_voip_mode mode)
+        : WifiCommand("SetVoipModeCommand", handle, 0) {
+        mMode = mode;
+    }
+    virtual int create() {
+        int ret;
+
+        ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_CONFIG_VOIP_MODE);
+        if (ret < 0) {
+            ALOGE("Can't create message to send to driver - %d", ret);
+            return ret;
+        }
+
+        nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);
+        ret = mMsg.put_u32(ANDR_WIFI_ATTRIBUTE_VOIP_MODE, mMode);
+        ALOGE("mMode - %d", mMode);
+        if (ret < 0) {
+	    ALOGE("Failed to set voip mode %d\n", mMode);
+	    return ret;
+        }
+
+	ALOGI("Successfully configured voip mode %d\n", mMode);
+        mMsg.attr_end(data);
+        return WIFI_SUCCESS;
+    }
+};
+
+wifi_error wifi_set_voip_mode(wifi_interface_handle handle, wifi_voip_mode mode)
+{
+    ALOGD("Setting VOIP mode, halHandle = %p Mode = %d\n", handle, mode);
+    SetVoipModeCommand command(handle, mode);
+    return (wifi_error) command.requestResponse();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+class SetDtimConfigCommand : public WifiCommand {
+
+private:
+    uint32_t multiplier;
+public:
+    SetDtimConfigCommand(wifi_interface_handle handle, u32 dtim_multiplier)
+        : WifiCommand("SetDtimConfigCommand", handle, 0) {
+        multiplier = dtim_multiplier;
+    }
+    virtual int create() {
+        int ret;
+
+        ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_SET_DTIM_CONFIG);
+        if (ret < 0) {
+            ALOGE("Can't create message to send to driver - %d", ret);
+            return ret;
+        }
+
+        nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);
+        ret = mMsg.put_u32(ANDR_WIFI_ATTRIBUTE_DTIM_MULTIPLIER, multiplier);
+        if (ret < 0) {
+             ALOGE("Failed to set dtim mutiplier %d\n", multiplier);
+             return ret;
+        }
+
+        ALOGI("Successfully configured dtim multiplier %d\n", multiplier);
+        mMsg.attr_end(data);
+        return WIFI_SUCCESS;
+    }
+};
+
+wifi_error wifi_set_dtim_config(wifi_interface_handle handle, u32 multiplier)
+{
+    ALOGD("Setting DTIM config , halHandle = %p Multiplier = %d\n", handle, multiplier);
+    SetDtimConfigCommand command(handle, multiplier);
+    return (wifi_error) command.requestResponse();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+class UsableChannelCommand : public WifiCommand {
+
+private:
+    u32 mBandMask;
+    u32 mIfaceModeMask;
+    u32 mFilterMask;
+    u32 mMaxSize;
+    u32* mSize;
+    wifi_usable_channel* mChannels;
+
+public:
+    UsableChannelCommand(wifi_interface_handle handle, u32 band_mask, u32 iface_mode_mask,
+                   u32 filter_mask, u32 max_size, u32* size, wifi_usable_channel* channels)
+        : WifiCommand("UsableChannelCommand", handle, 0),
+                       mBandMask(band_mask), mIfaceModeMask(iface_mode_mask),
+                       mFilterMask(filter_mask), mMaxSize(max_size),
+		       mSize(size), mChannels(channels)
+    {
+    }
+
+    int createRequest(WifiRequest& request) {
+        createUsableChannelRequest(request);
+        return WIFI_SUCCESS;
+    }
+
+    int createUsableChannelRequest(WifiRequest& request) {
+        int result = request.create(GOOGLE_OUI, WIFI_SUBCMD_USABLE_CHANNEL);
+        if (result < 0) {
+            ALOGE("Failed to create UsableChannel request; result = %d", result);
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+        result = request.put_u32(USABLECHAN_ATTRIBUTE_BAND, mBandMask);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("Failed to put log level; result = %d", result);
+            return result;
+        }
+        result = request.put_u32(USABLECHAN_ATTRIBUTE_IFACE, mIfaceModeMask);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("Failed to put ring flags; result = %d", result);
+            return result;
+        }
+        result = request.put_u32(USABLECHAN_ATTRIBUTE_FILTER, mFilterMask);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("Failed to put usablechan filter; result = %d", result);
+            return result;
+        }
+        result = request.put_u32(USABLECHAN_ATTRIBUTE_MAX_SIZE, mMaxSize);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("Failed to put usablechan max_size; result = %d", result);
+            return result;
+        }
+        request.attr_end(data);
+
+        return WIFI_SUCCESS;
+    }
+
+    int start() {
+        WifiRequest request(familyId(), ifaceId());
+        int result = createRequest(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to create request; result = %d", result);
+            return result;
+        }
+
+        result = requestResponse(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to set scanning mac OUI; result = %d", result);
+        }
+
+        return result;
+    }
+
+    virtual int handleResponse(WifiEvent& reply) {
+        ALOGD("In DebugCommand::handleResponse");
+
+        if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+            ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+            return NL_SKIP;
+        }
+
+        nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+        int len = reply.get_vendor_data_len();
+        wifi_usable_channel *channels(mChannels);
+
+        if (vendor_data == NULL || len == 0) {
+            ALOGE("No Debug data found");
+            return NL_SKIP;
+        }
+
+        nl_iterator it(vendor_data);
+        if (it.get_type() == USABLECHAN_ATTRIBUTE_SIZE) {
+            *mSize = it.get_u32();
+        } else {
+            ALOGE("Unknown attribute: %d expecting %d",
+                it.get_type(), USABLECHAN_ATTRIBUTE_SIZE);
+            return NL_SKIP;
+        }
+
+        it.next();
+        if (it.get_type() == USABLECHAN_ATTRIBUTE_CHANNELS) {
+            memcpy(channels, it.get_data(), sizeof(wifi_usable_channel) * *mSize);
+        } else {
+            ALOGE("Unknown attribute: %d expecting %d",
+                it.get_type(), USABLECHAN_ATTRIBUTE_SIZE);
+            return NL_SKIP;
+        }
+
+        return NL_OK;
+    }
+
+    virtual int handleEvent(WifiEvent& event) {
+        /* NO events! */
+        return NL_SKIP;
+    }
+};
+
+wifi_error wifi_get_usable_channels(wifi_handle handle, u32 band_mask, u32 iface_mode_mask,
+		u32 filter_mask, u32 max_size, u32* size, wifi_usable_channel* channels)
+{
+    int numIfaceHandles = 0;
+    wifi_interface_handle *ifaceHandles = NULL;
+    wifi_interface_handle wlan0Handle;
+
+    wlan0Handle = wifi_get_wlan_interface((wifi_handle)handle, ifaceHandles, numIfaceHandles);
+    UsableChannelCommand command(wlan0Handle, band_mask, iface_mode_mask,
+                                    filter_mask, max_size, size, channels);
+    return (wifi_error)command.start();
+}
diff --git a/bcmdhd/wifi_hal/wifi_logger.cpp b/bcmdhd/wifi_hal/wifi_logger.cpp
index e35bf9b..4d2d8dd 100755
--- a/bcmdhd/wifi_hal/wifi_logger.cpp
+++ b/bcmdhd/wifi_hal/wifi_logger.cpp
@@ -26,6 +26,7 @@
 #include <netpacket/packet.h>
 #include <linux/filter.h>
 #include <linux/errqueue.h>
+#include <errno.h>
 
 #include <linux/pkt_sched.h>
 #include <netlink/object-api.h>
@@ -34,6 +35,7 @@
 #include <netlink-private/object-api.h>
 #include <netlink-private/types.h>
 #include <unistd.h>
+#include <cutils/properties.h>
 
 
 #include "nl80211_copy.h"
@@ -46,6 +48,7 @@
 #include "wifi_hal.h"
 #include "common.h"
 #include "cpp_bindings.h"
+#include <sys/stat.h>
 #include "brcm_version.h"
 #define WIFI_HAL_EVENT_SOCK_PORT     645
 
@@ -69,28 +72,58 @@
     LOGGER_FILE_DUMP_DONE_IND,
     LOGGER_SET_HAL_START,
     LOGGER_HAL_STOP,
-    LOGGER_SET_HAL_PID
+    LOGGER_SET_HAL_PID,
+    LOGGER_SET_TPUT_DEBUG_DUMP_CMD,
+    LOGGER_GET_BUF_RING_MAP
 } DEBUG_SUB_COMMAND;
 
+#define MAX_NV_FILE 4
+#define MAX_SKU_NAME_LEN 5
+#define OTA_PATH "/data/vendor/firmware/wifi/"
+#define OTA_CLM_FILE "bcmdhd_clm.blob"
+#define OTA_NVRAM_FILE "bcmdhd.cal"
+#define HW_DEV_PROP "ro.revision"
+#define HW_SKU_PROP "ro.boot.hardware.sku"
+
 typedef enum {
-    LOGGER_ATTRIBUTE_DRIVER_VER,
-    LOGGER_ATTRIBUTE_FW_VER,
-    LOGGER_ATTRIBUTE_RING_ID,
-    LOGGER_ATTRIBUTE_RING_NAME,
-    LOGGER_ATTRIBUTE_RING_FLAGS,
-    LOGGER_ATTRIBUTE_LOG_LEVEL,
-    LOGGER_ATTRIBUTE_LOG_TIME_INTVAL,
-    LOGGER_ATTRIBUTE_LOG_MIN_DATA_SIZE,
-    LOGGER_ATTRIBUTE_FW_DUMP_LEN,
-    LOGGER_ATTRIBUTE_FW_DUMP_DATA,
-    LOGGER_ATTRIBUTE_FW_ERR_CODE,
-    LOGGER_ATTRIBUTE_RING_DATA,
-    LOGGER_ATTRIBUTE_RING_STATUS,
-    LOGGER_ATTRIBUTE_RING_NUM,
-    LOGGER_ATTRIBUTE_DRIVER_DUMP_LEN,
-    LOGGER_ATTRIBUTE_DRIVER_DUMP_DATA,
-    LOGGER_ATTRIBUTE_PKT_FATE_NUM,
-    LOGGER_ATTRIBUTE_PKT_FATE_DATA,
+    NVRAM,
+    CLM_BLOB
+} OTA_TYPE;
+
+char ota_nvram_ext[10];
+typedef struct ota_info_buf {
+    u32 ota_clm_len;
+    const void *ota_clm_buf[1];
+    u32 ota_nvram_len;
+    const void *ota_nvram_buf[1];
+} ota_info_buf_t;
+u32 applied_ota_version = 0;
+
+typedef enum {
+    LOGGER_ATTRIBUTE_INVALID			= 0,
+    LOGGER_ATTRIBUTE_DRIVER_VER			= 1,
+    LOGGER_ATTRIBUTE_FW_VER			= 2,
+    LOGGER_ATTRIBUTE_RING_ID			= 3,
+    LOGGER_ATTRIBUTE_RING_NAME			= 4,
+    LOGGER_ATTRIBUTE_RING_FLAGS			= 5,
+    LOGGER_ATTRIBUTE_LOG_LEVEL			= 6,
+    LOGGER_ATTRIBUTE_LOG_TIME_INTVAL		= 7,
+    LOGGER_ATTRIBUTE_LOG_MIN_DATA_SIZE		= 8,
+    LOGGER_ATTRIBUTE_FW_DUMP_LEN		= 9,
+    LOGGER_ATTRIBUTE_FW_DUMP_DATA		= 10,
+    LOGGER_ATTRIBUTE_FW_ERR_CODE		= 11,
+    LOGGER_ATTRIBUTE_RING_DATA			= 12,
+    LOGGER_ATTRIBUTE_RING_STATUS		= 13,
+    LOGGER_ATTRIBUTE_RING_NUM			= 14,
+    LOGGER_ATTRIBUTE_DRIVER_DUMP_LEN		= 15,
+    LOGGER_ATTRIBUTE_DRIVER_DUMP_DATA		= 16,
+    LOGGER_ATTRIBUTE_PKT_FATE_NUM		= 17,
+    LOGGER_ATTRIBUTE_PKT_FATE_DATA		= 18,
+    LOGGER_ATTRIBUTE_HANG_REASON		= 19,
+    LOGGER_ATTRIBUTE_BUF_RING_NUM		= 20,
+    LOGGER_ATTRIBUTE_BUF_RING_MAP		= 21,
+    /* Add new attributes just above this */
+    LOGGER_ATTRIBUTE_MAX
 } LOGGER_ATTRIBUTE;
 
 typedef enum {
@@ -108,6 +141,7 @@
     GET_RING_STATUS,
     GET_FEATURE,
     START_RING_LOG,
+    GET_BUF_RING_MAP,
 } GetCmdType;
 
 typedef enum {
@@ -117,9 +151,10 @@
 } PktFateReqType;
 
 enum wake_stat_attributes {
-    WAKE_STAT_ATTRIBUTE_TOTAL_CMD_EVENT,
-    WAKE_STAT_ATTRIBUTE_CMD_EVENT_WAKE,
-    WAKE_STAT_ATTRIBUTE_CMD_EVENT_COUNT,
+    WAKE_STAT_ATTRIBUTE_INVALID,
+    WAKE_STAT_ATTRIBUTE_TOTAL,
+    WAKE_STAT_ATTRIBUTE_WAKE,
+    WAKE_STAT_ATTRIBUTE_COUNT,
     WAKE_STAT_ATTRIBUTE_CMD_COUNT_USED,
     WAKE_STAT_ATTRIBUTE_TOTAL_DRIVER_FW,
     WAKE_STAT_ATTRIBUTE_DRIVER_FW_WAKE,
@@ -136,8 +171,9 @@
     WAKE_STAT_ATTRIBUTE_RX_ICMP6_NS,
     WAKE_STAT_ATTRIBUTE_IPV4_RX_MULTICAST_ADD_CNT,
     WAKE_STAT_ATTRIBUTE_IPV6_RX_MULTICAST_ADD_CNT,
-    WAKE_STAT_ATTRIBUTE_OTHER__RX_MULTICAST_ADD_CNT,
-    WAKE_STAT_ATTRIBUTE_RX_MULTICAST_PKT_INFO
+    WAKE_STAT_ATTRIBUTE_OTHER_RX_MULTICAST_ADD_CNT,
+    WAKE_STAT_ATTRIBUTE_RX_MULTICAST_PKT_INFO,
+    WAKE_STAT_ATTRIBUTE_MAX
 };
 
 typedef enum {
@@ -146,8 +182,362 @@
     SET_HAL_START_ATTRIBUTE_EVENT_SOCK_PID = 0x0003
 } SET_HAL_START_ATTRIBUTE;
 
-#define HAL_START_REQUEST_ID 2
+typedef enum {
+    OTA_DOWNLOAD_CLM_LENGTH_ATTR    = 0x0001,
+    OTA_DOWNLOAD_CLM_ATTR           = 0x0002,
+    OTA_DOWNLOAD_NVRAM_LENGTH_ATTR  = 0x0003,
+    OTA_DOWNLOAD_NVRAM_ATTR         = 0x0004,
+    OTA_SET_FORCE_REG_ON            = 0x0005,
+    OTA_CUR_NVRAM_EXT_ATTR          = 0x0006,
+} OTA_DOWNLOAD_ATTRIBUTE;
 
+#define HAL_START_REQUEST_ID 2
+#define HAL_RESTART_ID 3
+#define FILE_NAME_LEN 256
+#define RING_NAME_LEN 32
+#if defined(RING_DUMP)
+/* Loglevel */
+#define DUMP_DEBUG(x)
+#define DUMP_INFO(x) ALOGI x
+#define FILE_DUMP_REQUEST_ID 2
+#define C2S(x)  case x: return #x;
+static const char *EWP_EventAttrToString(int len_attr);
+static const char *EWP_CmdAttrToString(int data_attr);
+
+typedef struct buf_data {
+    u32 ver; /* version of struct */
+    u32 len; /* Total len */
+    /* size of each buffer in case of split buffers (0 - single buffer). */
+    u32 buf_threshold;
+    const void *data_buf[1]; /* array of user space buffer pointers.*/
+} buf_data_t;
+
+/* Attributes associated with GOOGLE_FILE_DUMP_EVENT */
+typedef enum {
+    DUMP_LEN_ATTR_INVALID                       = 0,
+    DUMP_LEN_ATTR_MEMDUMP                       = 1,
+    DUMP_LEN_ATTR_SSSR_C0_BEFORE                = 2,
+    DUMP_LEN_ATTR_SSSR_C0_AFTER                 = 3,
+    DUMP_LEN_ATTR_SSSR_C1_BEFORE                = 4,
+    DUMP_LEN_ATTR_SSSR_C1_AFTER                 = 5,
+    DUMP_LEN_ATTR_SSSR_C2_BEFORE                = 6,
+    DUMP_LEN_ATTR_SSSR_C2_AFTER                 = 7,
+    DUMP_LEN_ATTR_SSSR_DIG_BEFORE               = 8,
+    DUMP_LEN_ATTR_SSSR_DIG_AFTER                = 9,
+    DUMP_LEN_ATTR_TIMESTAMP                     = 10,
+    DUMP_LEN_ATTR_GENERAL_LOG                   = 11,
+    DUMP_LEN_ATTR_ECNTRS                        = 12,
+    DUMP_LEN_ATTR_SPECIAL_LOG                   = 13,
+    DUMP_LEN_ATTR_DHD_DUMP                      = 14,
+    DUMP_LEN_ATTR_EXT_TRAP                      = 15,
+    DUMP_LEN_ATTR_HEALTH_CHK                    = 16,
+    DUMP_LEN_ATTR_PRESERVE_LOG                  = 17,
+    DUMP_LEN_ATTR_COOKIE                        = 18,
+    DUMP_LEN_ATTR_FLOWRING_DUMP                 = 19,
+    DUMP_LEN_ATTR_PKTLOG                        = 20,
+    DUMP_LEN_ATTR_PKTLOG_DEBUG                  = 21,
+    DUMP_FILENAME_ATTR_DEBUG_DUMP               = 22,
+    DUMP_FILENAME_ATTR_MEM_DUMP                 = 23,
+    DUMP_FILENAME_ATTR_SSSR_CORE_0_BEFORE_DUMP  = 24,
+    DUMP_FILENAME_ATTR_SSSR_CORE_0_AFTER_DUMP   = 25,
+    DUMP_FILENAME_ATTR_SSSR_CORE_1_BEFORE_DUMP  = 26,
+    DUMP_FILENAME_ATTR_SSSR_CORE_1_AFTER_DUMP   = 27,
+    DUMP_FILENAME_ATTR_SSSR_CORE_2_BEFORE_DUMP  = 28,
+    DUMP_FILENAME_ATTR_SSSR_CORE_2_AFTER_DUMP   = 29,
+    DUMP_FILENAME_ATTR_SSSR_DIG_BEFORE_DUMP     = 30,
+    DUMP_FILENAME_ATTR_SSSR_DIG_AFTER_DUMP      = 31,
+    DUMP_FILENAME_ATTR_PKTLOG_DUMP              = 32,
+    DUMP_FILENAME_ATTR_PKTLOG_DEBUG_DUMP        = 33,
+    DUMP_LEN_ATTR_STATUS_LOG                    = 34,
+    DUMP_LEN_ATTR_AXI_ERROR                     = 35,
+    DUMP_FILENAME_ATTR_AXI_ERROR_DUMP           = 36,
+    DUMP_LEN_ATTR_RTT_LOG                       = 37,
+    DUMP_LEN_ATTR_SDTC_ETB_DUMP                 = 38,
+    DUMP_FILENAME_ATTR_SDTC_ETB_DUMP            = 39,
+    DUMP_LEN_ATTR_PKTID_MAP_LOG                 = 40,
+    DUMP_LEN_ATTR_PKTID_UNMAP_LOG               = 41,
+    DUMP_LEN_ATTR_EWP_HW_INIT_LOG               = 42,
+    DUMP_LEN_ATTR_EWP_HW_MOD_DUMP               = 43,
+    DUMP_LEN_ATTR_EWP_HW_REG_DUMP               = 44,
+    /*  Please add new attributes from here to sync up old DHD */
+    DUMP_EVENT_ATTR_MAX                         = 45,
+} EWP_DUMP_EVENT_ATTRIBUTE;
+
+/* Attributes associated with DEBUG_GET_DUMP_BUF */
+typedef enum {
+    DUMP_BUF_ATTR_INVALID               = 0,
+    DUMP_BUF_ATTR_MEMDUMP               = 1,
+    DUMP_BUF_ATTR_SSSR_C0_BEFORE        = 2,
+    DUMP_BUF_ATTR_SSSR_C0_AFTER         = 3,
+    DUMP_BUF_ATTR_SSSR_C1_BEFORE        = 4,
+    DUMP_BUF_ATTR_SSSR_C1_AFTER         = 5,
+    DUMP_BUF_ATTR_SSSR_C2_BEFORE        = 6,
+    DUMP_BUF_ATTR_SSSR_C2_AFTER         = 7,
+    DUMP_BUF_ATTR_SSSR_DIG_BEFORE       = 8,
+    DUMP_BUF_ATTR_SSSR_DIG_AFTER        = 9,
+    DUMP_BUF_ATTR_TIMESTAMP             = 10,
+    DUMP_BUF_ATTR_GENERAL_LOG           = 11,
+    DUMP_BUF_ATTR_ECNTRS                = 12,
+    DUMP_BUF_ATTR_SPECIAL_LOG           = 13,
+    DUMP_BUF_ATTR_DHD_DUMP              = 14,
+    DUMP_BUF_ATTR_EXT_TRAP              = 15,
+    DUMP_BUF_ATTR_HEALTH_CHK            = 16,
+    DUMP_BUF_ATTR_PRESERVE_LOG          = 17,
+    DUMP_BUF_ATTR_COOKIE                = 18,
+    DUMP_BUF_ATTR_FLOWRING_DUMP         = 19,
+    DUMP_BUF_ATTR_PKTLOG                = 20,
+    DUMP_BUF_ATTR_PKTLOG_DEBUG          = 21,
+    DUMP_BUF_ATTR_STATUS_LOG            = 22,
+    DUMP_BUF_ATTR_AXI_ERROR             = 23,
+    DUMP_BUF_ATTR_RTT_LOG               = 24,
+    DUMP_BUF_ATTR_SDTC_ETB_DUMP         = 25,
+    DUMP_BUF_ATTR_PKTID_MAP_LOG         = 26,
+    DUMP_BUF_ATTR_PKTID_UNMAP_LOG       = 27,
+    DUMP_BUF_ATTR_EWP_HW_INIT_LOG       = 28,
+    DUMP_BUF_ATTR_EWP_HW_MOD_DUMP       = 29,
+    DUMP_BUF_ATTR_EWP_HW_REG_DUMP       = 30,
+    /*  Please add new attributes from here to sync up old DHD */
+    DUMP_BUF_ATTR_MAX		        = 31,
+} EWP_DUMP_CMD_ATTRIBUTE;
+
+typedef enum {
+    DUMP_TYPE_MEM_DUMP                  = 0,
+    DUMP_TYPE_DEBUG_DUMP                = 1,
+    DUMP_TYPE_SSSR_CORE0_BEF_DUMP       = 2,
+    DUMP_TYPE_SSSR_CORE0_AFT_DUMP       = 3,
+    DUMP_TYPE_SSSR_CORE1_BEF_DUMP       = 4,
+    DUMP_TYPE_SSSR_CORE1_AFT_DUMP       = 5,
+    DUMP_TYPE_SSSR_CORE2_BEF_DUMP       = 6,
+    DUMP_TYPE_SSSR_CORE2_AFT_DUMP       = 7,
+    DUMP_TYPE_SSSR_DIG_BEF_DUMP         = 8,
+    DUMP_TYPE_SSSR_DIG_AFT_DUMP         = 9,
+    DUMP_TYPE_PKTLOG_DUMP               = 10,
+    DUMP_TYPE_PKTLOG_DEBUG_DUMP         = 11,
+    DUMP_TYPE_AXI_ERROR_DUMP            = 12,
+    DUMP_TYPE_D2H_MINI_DUMP             = 13,
+    DUMP_TYPE_SDTC_ETB_DUMP             = 14,
+    /*  Please add new attributes from here to sync up old DHD */
+    DUMP_TYPE_MAX                       = 15,
+} EWP_DUMP_TYPE;
+
+/* Struct for table which has len_attr, data_attr and dump file type attr */
+typedef struct logger_attr_entry {
+    u8 attr_type; /* Type of attribute */
+    u8 buf_attr; /* Buffer associated with the attribute */
+    u8 dump_type; /* Each attribute will be linked to a dump type */
+} logger_attr_entry_t;
+
+logger_attr_entry_t attr_lookup_tbl[] = {
+    /* Mem Dump Block */
+    {DUMP_FILENAME_ATTR_MEM_DUMP, 0, DUMP_TYPE_MEM_DUMP},
+    {DUMP_LEN_ATTR_MEMDUMP, DUMP_BUF_ATTR_MEMDUMP, DUMP_TYPE_MEM_DUMP},
+    /* SSSR Dump Block */
+    {DUMP_FILENAME_ATTR_SSSR_CORE_0_BEFORE_DUMP, 0, DUMP_TYPE_SSSR_CORE0_BEF_DUMP},
+    {DUMP_LEN_ATTR_SSSR_C0_BEFORE, DUMP_BUF_ATTR_SSSR_C0_BEFORE, DUMP_TYPE_SSSR_CORE0_BEF_DUMP},
+
+    {DUMP_FILENAME_ATTR_SSSR_CORE_0_AFTER_DUMP, 0, DUMP_TYPE_SSSR_CORE0_AFT_DUMP},
+    {DUMP_LEN_ATTR_SSSR_C0_AFTER, DUMP_BUF_ATTR_SSSR_C0_AFTER, DUMP_TYPE_SSSR_CORE0_AFT_DUMP},
+
+    {DUMP_FILENAME_ATTR_SSSR_CORE_1_BEFORE_DUMP, 0, DUMP_TYPE_SSSR_CORE1_BEF_DUMP},
+    {DUMP_LEN_ATTR_SSSR_C1_BEFORE, DUMP_BUF_ATTR_SSSR_C1_BEFORE, DUMP_TYPE_SSSR_CORE1_BEF_DUMP},
+
+    {DUMP_FILENAME_ATTR_SSSR_CORE_1_AFTER_DUMP, 0, DUMP_TYPE_SSSR_CORE1_AFT_DUMP},
+    {DUMP_LEN_ATTR_SSSR_C1_AFTER, DUMP_BUF_ATTR_SSSR_C1_AFTER, DUMP_TYPE_SSSR_CORE1_AFT_DUMP},
+
+    {DUMP_FILENAME_ATTR_SSSR_CORE_2_BEFORE_DUMP, 0, DUMP_TYPE_SSSR_CORE2_BEF_DUMP},
+    {DUMP_LEN_ATTR_SSSR_C2_BEFORE, DUMP_BUF_ATTR_SSSR_C2_BEFORE, DUMP_TYPE_SSSR_CORE2_BEF_DUMP},
+
+    {DUMP_FILENAME_ATTR_SSSR_CORE_2_AFTER_DUMP, 0, DUMP_TYPE_SSSR_CORE2_AFT_DUMP},
+    {DUMP_LEN_ATTR_SSSR_C2_AFTER, DUMP_BUF_ATTR_SSSR_C2_AFTER, DUMP_TYPE_SSSR_CORE2_AFT_DUMP},
+
+    {DUMP_FILENAME_ATTR_SSSR_DIG_BEFORE_DUMP, 0, DUMP_TYPE_SSSR_DIG_BEF_DUMP},
+    {DUMP_LEN_ATTR_SSSR_DIG_BEFORE, DUMP_BUF_ATTR_SSSR_DIG_BEFORE, DUMP_TYPE_SSSR_DIG_BEF_DUMP},
+
+    {DUMP_FILENAME_ATTR_SSSR_DIG_AFTER_DUMP, 0, DUMP_TYPE_SSSR_DIG_AFT_DUMP},
+    {DUMP_LEN_ATTR_SSSR_DIG_AFTER, DUMP_BUF_ATTR_SSSR_DIG_AFTER, DUMP_TYPE_SSSR_DIG_AFT_DUMP},
+
+    /* Debug Dump Block */
+    {DUMP_FILENAME_ATTR_DEBUG_DUMP, 0, DUMP_TYPE_DEBUG_DUMP},
+    {DUMP_LEN_ATTR_TIMESTAMP, DUMP_BUF_ATTR_TIMESTAMP, DUMP_TYPE_DEBUG_DUMP},
+    {DUMP_LEN_ATTR_GENERAL_LOG, DUMP_BUF_ATTR_GENERAL_LOG, DUMP_TYPE_DEBUG_DUMP},
+    {DUMP_LEN_ATTR_ECNTRS, DUMP_BUF_ATTR_ECNTRS, DUMP_TYPE_DEBUG_DUMP},
+    {DUMP_LEN_ATTR_SPECIAL_LOG, DUMP_BUF_ATTR_SPECIAL_LOG, DUMP_TYPE_DEBUG_DUMP},
+    {DUMP_LEN_ATTR_DHD_DUMP, DUMP_BUF_ATTR_DHD_DUMP, DUMP_TYPE_DEBUG_DUMP},
+    {DUMP_LEN_ATTR_EXT_TRAP, DUMP_BUF_ATTR_EXT_TRAP, DUMP_TYPE_DEBUG_DUMP},
+    {DUMP_LEN_ATTR_HEALTH_CHK, DUMP_BUF_ATTR_HEALTH_CHK, DUMP_TYPE_DEBUG_DUMP},
+    {DUMP_LEN_ATTR_PRESERVE_LOG, DUMP_BUF_ATTR_PRESERVE_LOG, DUMP_TYPE_DEBUG_DUMP},
+    {DUMP_LEN_ATTR_COOKIE, DUMP_BUF_ATTR_COOKIE, DUMP_TYPE_DEBUG_DUMP},
+    {DUMP_LEN_ATTR_FLOWRING_DUMP, DUMP_BUF_ATTR_FLOWRING_DUMP, DUMP_TYPE_DEBUG_DUMP},
+    {DUMP_LEN_ATTR_STATUS_LOG, DUMP_BUF_ATTR_STATUS_LOG, DUMP_TYPE_DEBUG_DUMP},
+    {DUMP_LEN_ATTR_RTT_LOG, DUMP_BUF_ATTR_RTT_LOG, DUMP_TYPE_DEBUG_DUMP},
+    {DUMP_LEN_ATTR_PKTID_MAP_LOG, DUMP_BUF_ATTR_PKTID_MAP_LOG, DUMP_TYPE_DEBUG_DUMP},
+    {DUMP_LEN_ATTR_PKTID_UNMAP_LOG, DUMP_BUF_ATTR_PKTID_UNMAP_LOG, DUMP_TYPE_DEBUG_DUMP},
+    {DUMP_LEN_ATTR_EWP_HW_INIT_LOG, DUMP_BUF_ATTR_EWP_HW_INIT_LOG, DUMP_TYPE_DEBUG_DUMP},
+    {DUMP_LEN_ATTR_EWP_HW_MOD_DUMP, DUMP_BUF_ATTR_EWP_HW_MOD_DUMP, DUMP_TYPE_DEBUG_DUMP},
+    {DUMP_LEN_ATTR_EWP_HW_REG_DUMP, DUMP_BUF_ATTR_EWP_HW_REG_DUMP, DUMP_TYPE_DEBUG_DUMP},
+
+    /* PKT log dump block */
+    {DUMP_FILENAME_ATTR_PKTLOG_DUMP, 0, DUMP_TYPE_PKTLOG_DUMP},
+    {DUMP_LEN_ATTR_PKTLOG, DUMP_BUF_ATTR_PKTLOG, DUMP_TYPE_PKTLOG_DUMP},
+    {DUMP_FILENAME_ATTR_PKTLOG_DEBUG_DUMP, 0, DUMP_TYPE_PKTLOG_DEBUG_DUMP},
+    {DUMP_LEN_ATTR_PKTLOG_DEBUG, DUMP_BUF_ATTR_PKTLOG_DEBUG, DUMP_TYPE_PKTLOG_DEBUG_DUMP},
+    /* AXI error log dump block */
+    {DUMP_FILENAME_ATTR_AXI_ERROR_DUMP, 0, DUMP_TYPE_AXI_ERROR_DUMP},
+    {DUMP_LEN_ATTR_AXI_ERROR, DUMP_BUF_ATTR_AXI_ERROR, DUMP_TYPE_AXI_ERROR_DUMP},
+    /* SDTC etb log dump block */
+    {DUMP_FILENAME_ATTR_SDTC_ETB_DUMP, 0, DUMP_TYPE_SDTC_ETB_DUMP},
+    {DUMP_LEN_ATTR_SDTC_ETB_DUMP, DUMP_BUF_ATTR_SDTC_ETB_DUMP, DUMP_TYPE_SDTC_ETB_DUMP},
+    {DUMP_EVENT_ATTR_MAX, 0, 0},
+};
+
+static const char *EWP_EventAttrToString(int len_attr)
+{
+    switch (len_attr) {
+        C2S(DUMP_LEN_ATTR_MEMDUMP)
+        C2S(DUMP_LEN_ATTR_SSSR_C0_BEFORE)
+        C2S(DUMP_LEN_ATTR_SSSR_C0_AFTER)
+        C2S(DUMP_LEN_ATTR_SSSR_C1_BEFORE)
+        C2S(DUMP_LEN_ATTR_SSSR_C1_AFTER)
+        C2S(DUMP_LEN_ATTR_SSSR_C2_BEFORE)
+        C2S(DUMP_LEN_ATTR_SSSR_C2_AFTER)
+        C2S(DUMP_LEN_ATTR_SSSR_DIG_BEFORE)
+        C2S(DUMP_LEN_ATTR_SSSR_DIG_AFTER)
+        C2S(DUMP_LEN_ATTR_TIMESTAMP)
+        C2S(DUMP_LEN_ATTR_GENERAL_LOG)
+        C2S(DUMP_LEN_ATTR_ECNTRS)
+        C2S(DUMP_LEN_ATTR_SPECIAL_LOG)
+        C2S(DUMP_LEN_ATTR_DHD_DUMP)
+        C2S(DUMP_LEN_ATTR_EXT_TRAP)
+        C2S(DUMP_LEN_ATTR_HEALTH_CHK)
+        C2S(DUMP_LEN_ATTR_PRESERVE_LOG)
+        C2S(DUMP_LEN_ATTR_COOKIE)
+        C2S(DUMP_LEN_ATTR_FLOWRING_DUMP)
+        C2S(DUMP_LEN_ATTR_PKTLOG)
+        C2S(DUMP_LEN_ATTR_PKTLOG_DEBUG)
+        C2S(DUMP_LEN_ATTR_STATUS_LOG)
+        C2S(DUMP_FILENAME_ATTR_DEBUG_DUMP)
+        C2S(DUMP_FILENAME_ATTR_MEM_DUMP)
+        C2S(DUMP_FILENAME_ATTR_SSSR_CORE_0_BEFORE_DUMP)
+        C2S(DUMP_FILENAME_ATTR_SSSR_CORE_0_AFTER_DUMP)
+        C2S(DUMP_FILENAME_ATTR_SSSR_CORE_1_BEFORE_DUMP)
+        C2S(DUMP_FILENAME_ATTR_SSSR_CORE_1_AFTER_DUMP)
+        C2S(DUMP_FILENAME_ATTR_SSSR_CORE_2_BEFORE_DUMP)
+        C2S(DUMP_FILENAME_ATTR_SSSR_CORE_2_AFTER_DUMP)
+        C2S(DUMP_FILENAME_ATTR_SSSR_DIG_BEFORE_DUMP)
+        C2S(DUMP_FILENAME_ATTR_SSSR_DIG_AFTER_DUMP)
+        C2S(DUMP_FILENAME_ATTR_PKTLOG_DUMP)
+        C2S(DUMP_FILENAME_ATTR_PKTLOG_DEBUG_DUMP)
+        C2S(DUMP_LEN_ATTR_AXI_ERROR)
+        C2S(DUMP_FILENAME_ATTR_AXI_ERROR_DUMP)
+        C2S(DUMP_LEN_ATTR_RTT_LOG)
+        C2S(DUMP_FILENAME_ATTR_SDTC_ETB_DUMP)
+        C2S(DUMP_LEN_ATTR_SDTC_ETB_DUMP)
+        C2S(DUMP_LEN_ATTR_PKTID_MAP_LOG)
+        C2S(DUMP_LEN_ATTR_PKTID_UNMAP_LOG)
+        C2S(DUMP_LEN_ATTR_EWP_HW_INIT_LOG)
+        C2S(DUMP_LEN_ATTR_EWP_HW_MOD_DUMP)
+        C2S(DUMP_LEN_ATTR_EWP_HW_REG_DUMP)
+        default:
+            return "DUMP_LEN_ATTR_INVALID";
+    }
+}
+
+static const char *EWP_CmdAttrToString(int attr)
+{
+    switch (attr) {
+        C2S(DUMP_BUF_ATTR_MEMDUMP)
+        C2S(DUMP_BUF_ATTR_SSSR_C0_BEFORE)
+        C2S(DUMP_BUF_ATTR_SSSR_C0_AFTER)
+        C2S(DUMP_BUF_ATTR_SSSR_C1_BEFORE)
+        C2S(DUMP_BUF_ATTR_SSSR_C1_AFTER)
+        C2S(DUMP_BUF_ATTR_SSSR_C2_BEFORE)
+        C2S(DUMP_BUF_ATTR_SSSR_C2_AFTER)
+        C2S(DUMP_BUF_ATTR_SSSR_DIG_BEFORE)
+        C2S(DUMP_BUF_ATTR_SSSR_DIG_AFTER)
+        C2S(DUMP_BUF_ATTR_TIMESTAMP)
+        C2S(DUMP_BUF_ATTR_GENERAL_LOG)
+        C2S(DUMP_BUF_ATTR_ECNTRS)
+        C2S(DUMP_BUF_ATTR_SPECIAL_LOG)
+        C2S(DUMP_BUF_ATTR_DHD_DUMP)
+        C2S(DUMP_BUF_ATTR_EXT_TRAP)
+        C2S(DUMP_BUF_ATTR_HEALTH_CHK)
+        C2S(DUMP_BUF_ATTR_PRESERVE_LOG)
+        C2S(DUMP_BUF_ATTR_COOKIE)
+        C2S(DUMP_BUF_ATTR_FLOWRING_DUMP)
+        C2S(DUMP_BUF_ATTR_PKTLOG)
+        C2S(DUMP_BUF_ATTR_PKTLOG_DEBUG)
+        C2S(DUMP_BUF_ATTR_STATUS_LOG)
+        C2S(DUMP_BUF_ATTR_AXI_ERROR)
+        C2S(DUMP_BUF_ATTR_RTT_LOG)
+        C2S(DUMP_BUF_ATTR_SDTC_ETB_DUMP)
+        C2S(DUMP_BUF_ATTR_PKTID_MAP_LOG)
+        C2S(DUMP_BUF_ATTR_PKTID_UNMAP_LOG)
+        C2S(DUMP_BUF_ATTR_EWP_HW_INIT_LOG)
+        C2S(DUMP_BUF_ATTR_EWP_HW_MOD_DUMP)
+        C2S(DUMP_BUF_ATTR_EWP_HW_REG_DUMP)
+        default:
+            return "DUMP_BUF_ATTR_INVALID";
+    }
+}
+
+/* Return index for matching buffer attribute */
+static int logger_attr_buffer_lookup(u8 attr) {
+    for (u8 i = 0; i < ARRAYSIZE(attr_lookup_tbl); i++) {
+        if (attr == attr_lookup_tbl[i].buf_attr) {
+            return i;
+        }
+    }
+    ALOGE("Lookup for buf attr = %s failed\n",
+    EWP_CmdAttrToString(attr));
+    return -1;
+}
+
+/* Return index matching the length attribute */
+static int logger_attr_lookup(u8 attr) {
+    for (u8 i = 0; i < ARRAYSIZE(attr_lookup_tbl); i++) {
+        if (attr == attr_lookup_tbl[i].attr_type) {
+            return i;
+        }
+    }
+    ALOGE("Lookup for len attr = %s failed\n",
+        EWP_EventAttrToString(attr));
+    return -1;
+}
+#endif /* RING_DUMP */
+
+#define DBGRING_NAME_MAX 32  //Copy from legacy hal
+typedef struct wifi_buf_ring_map_entry {
+    uint32_t type;
+    uint32_t ring_id;
+    char ring_name[DBGRING_NAME_MAX];
+} wifi_buf_ring_map_entry_t;
+
+typedef struct {
+    char hw_id[PROPERTY_VALUE_MAX];
+    char sku[MAX_SKU_NAME_LEN];
+} sku_info_t;
+
+sku_info_t sku_table[] = {
+    { {"G9S9B"}, {"MMW"} },
+    { {"G8V0U"}, {"MMW"} },
+    { {"GFQM1"}, {"MMW"} },
+    { {"GB62Z"}, {"MMW"} },
+    { {"GE2AE"}, {"MMW"} },
+    { {"GQML3"}, {"MMW"} },
+    { {"GB7N6"}, {"ROW"} },
+    { {"GLU0G"}, {"ROW"} },
+    { {"GNA8F"}, {"ROW"} },
+    { {"GX7AS"}, {"ROW"} },
+    { {"GP4BC"}, {"ROW"} },
+    { {"GVU6C"}, {"ROW"} },
+    { {"GR1YH"}, {"JPN"} },
+    { {"GF5KQ"}, {"JPN"} },
+    { {"GPQ72"}, {"JPN"} },
+    { {"GB17L"}, {"JPN"} },
+    { {"GFE4J"}, {"JPN"} },
+    { {"G03Z5"}, {"JPN"} },
+    { {"G1AZG"}, {"EU"} }
+};
 ///////////////////////////////////////////////////////////////////////////////
 class DebugCommand : public WifiCommand
 {
@@ -155,6 +545,8 @@
     int *mBuffSize;
     u32 *mNumRings;
     wifi_ring_buffer_status *mStatus;
+    u32 *mNumMaps;
+    wifi_buf_ring_map_entry_t *mMaps;
     unsigned int *mSupport;
     u32 mVerboseLevel;
     u32 mFlags;
@@ -228,6 +620,14 @@
         mRingName = NULL;
     }
 
+    // constructor for buf ring map
+    DebugCommand(wifi_interface_handle iface, u32 *num_maps,
+            wifi_buf_ring_map_entry_t *map, GetCmdType cmdType)
+        : WifiCommand("DebugCommand", iface, 0), mNumMaps(num_maps), mMaps(map), mType(cmdType)
+    {
+        memset(mMaps, 0, sizeof(wifi_buf_ring_map_entry_t) * (*mNumMaps));
+    }
+
     // constructor for ring params
     DebugCommand(wifi_interface_handle iface, u32 verbose_level, u32 flags,
             u32 max_interval_sec, u32 min_data_size, char *ring_name, GetCmdType cmdType)
@@ -366,6 +766,16 @@
                 break;
             }
 
+            case GET_BUF_RING_MAP:
+            {
+                result = request.create(GOOGLE_OUI, LOGGER_GET_BUF_RING_MAP);
+                if (result != WIFI_SUCCESS) {
+                    ALOGE("Failed to create get ring status request; result = %d", result);
+                    return result;
+                }
+                break;
+            }
+
             case START_RING_LOG:
                 result = createRingRequest(request);
                 break;
@@ -378,7 +788,7 @@
     }
 
     int start() {
-        // ALOGD("Start debug command");
+        ALOGD("Start debug command");
         WifiRequest request(familyId(), ifaceId());
         int result = createRequest(request);
         if (result != WIFI_SUCCESS) {
@@ -394,7 +804,7 @@
     }
 
     virtual int handleResponse(WifiEvent& reply) {
-        ALOGD("In DebugCommand::handleResponse");
+        ALOGD("In DebugCommand::handleResponse, mType:%d\n", mType);
 
         if (reply.get_cmd() != NL80211_CMD_VENDOR) {
             ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
@@ -449,9 +859,15 @@
                 it.next();
                 for (unsigned int i = 0; it.has_next() && i < *mNumRings; it.next()) {
                     if (it.get_type() == LOGGER_ATTRIBUTE_RING_STATUS) {
-                        memcpy(status, it.get_data(), sizeof(wifi_ring_buffer_status));
-                        i++;
-                        status++;
+                        if (it.get_len() > sizeof(wifi_ring_buffer_status)) {
+                            ALOGE("ring status unexpected len = %d, dest len = %lu",
+                                it.get_len(), sizeof(wifi_ring_buffer_status));
+                            return NL_SKIP;
+                        } else {
+                            memcpy(status, it.get_data(), sizeof(wifi_ring_buffer_status));
+                            i++;
+                            status++;
+                        }
                     } else {
                         ALOGW("Ignoring invalid attribute type = %d, size = %d",
                                 it.get_type(), it.get_len());
@@ -465,11 +881,57 @@
                 void *data = reply.get_vendor_data();
                 int len = reply.get_vendor_data_len();
 
-                ALOGD("len = %d, expected len = %d", len, sizeof(unsigned int));
+                ALOGD("len = %d, expected len = %lu", len, sizeof(unsigned int));
                 memcpy(mSupport, data, sizeof(unsigned int));
                 break;
             }
 
+            case GET_BUF_RING_MAP:
+            {
+                nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+                int len = reply.get_vendor_data_len();
+                wifi_buf_ring_map_entry_t *map(mMaps);
+
+                if (vendor_data == NULL || len == 0) {
+                    ALOGE("No Debug data found");
+                    return NL_SKIP;
+                }
+
+                nl_iterator it(vendor_data);
+                if (it.get_type() == LOGGER_ATTRIBUTE_BUF_RING_NUM) {
+                    unsigned int num_maps = it.get_u32();
+                    if (*mNumMaps < num_maps) {
+                        ALOGE("Not enough status buffers provided, available: %d required: %d",
+                            *mNumMaps, num_maps);
+                    } else {
+                        *mNumMaps = num_maps;
+                    }
+                } else {
+                    ALOGE("Unknown attribute: %d expecting %d",
+                        it.get_type(), LOGGER_ATTRIBUTE_BUF_RING_NUM);
+                    return NL_SKIP;
+                }
+
+                it.next();
+                for (unsigned int i = 0; it.has_next() && i < *mNumMaps; it.next()) {
+                    if (it.get_type() == LOGGER_ATTRIBUTE_BUF_RING_MAP) {
+                        if (it.get_len() > sizeof(wifi_buf_ring_map_entry_t)) {
+                            ALOGE("GET_BUF_RING_MAP: unexpected len = %d, dest len = %lu",
+                                it.get_len(), sizeof(wifi_buf_ring_map_entry_t));
+                            return NL_SKIP;
+                        } else {
+                            memcpy(map, it.get_data(), sizeof(wifi_buf_ring_map_entry_t));
+                        }
+                        i++;
+                        map++;
+                    } else {
+                        ALOGW("Ignoring invalid attribute type = %d, size = %d",
+                            it.get_type(), it.get_len());
+                    }
+                }
+                break;
+            }
+
             default:
                 ALOGW("Unknown Debug command");
         }
@@ -559,6 +1021,8 @@
         u32 flags, u32 max_interval_sec, u32 min_data_size, char *ring_name)
 {
     if (ring_name) {
+        ALOGE("Ring name: level:%d sec:%d ring_name:%s",
+                verbose_level, max_interval_sec, ring_name);
         DebugCommand *cmd = new DebugCommand(iface, verbose_level, flags, max_interval_sec,
                     min_data_size, ring_name, START_RING_LOG);
         NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
@@ -586,7 +1050,6 @@
         ALOGV("Register loghandler");
         int result;
         uint32_t event_sock_pid = getpid() + (WIFI_HAL_EVENT_SOCK_PORT << 22);
-        registerVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_RING_EVENT);
 
         WifiRequest request(familyId(), ifaceId());
 
@@ -596,14 +1059,18 @@
             ALOGV("Failed to set Hal preInit; result = %d", result);
             return result;
         }
+        registerVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_RING_EVENT);
+
         nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
         result = request.put_u32(SET_HAL_START_ATTRIBUTE_EVENT_SOCK_PID, event_sock_pid);
         if (result != WIFI_SUCCESS) {
+            unregisterVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_RING_EVENT);
             ALOGV("Hal preInit Failed to put pic = %d", result);
             return result;
         }
 
         if (result != WIFI_SUCCESS) {
+            unregisterVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_RING_EVENT);
             ALOGV("Hal preInit Failed to put pid= %d", result);
             return result;
         } 
@@ -612,6 +1079,7 @@
 
         result = requestResponse(request);
         if (result != WIFI_SUCCESS) {
+            unregisterVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_RING_EVENT);
             ALOGE("Failed to register set Hal preInit; result = %d", result);
             return result;
         }
@@ -624,6 +1092,7 @@
 
         /* unregister event handler */
         unregisterVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_RING_EVENT);
+        wifi_unregister_cmd(wifiHandle(), id());
 
         WifiRequest request(familyId(), ifaceId());
         int result = request.create(GOOGLE_OUI, LOGGER_RESET_LOGGING);
@@ -657,16 +1126,23 @@
             return NL_SKIP;
         }
 
-        if(event_id == GOOGLE_DEBUG_RING_EVENT) {
+        if (event_id == GOOGLE_DEBUG_RING_EVENT) {
             wifi_ring_buffer_status status;
             memset(&status, 0, sizeof(status));
 
             for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
                 if (it.get_type() == LOGGER_ATTRIBUTE_RING_STATUS) {
-                    memcpy(&status, it.get_data(), sizeof(status));
+                    if (it.get_len() > sizeof(wifi_ring_buffer_status)) {
+                        ALOGE("SetLogHandler: ring status unexpected len = %d, dest len = %lu",
+                           it.get_len(), sizeof(wifi_ring_buffer_status));
+                        return NL_SKIP;
+                    } else {
+                        memcpy(&status, it.get_data(), sizeof(wifi_ring_buffer_status));
+                    }
                 } else if (it.get_type() == LOGGER_ATTRIBUTE_RING_DATA) {
                     buffer_size = it.get_len();
                     buffer = (char *)it.get_data();
+                    ALOGV("SetLogHandler: ring data size = %d", buffer_size);
                 } else {
                     ALOGW("Ignoring invalid attribute type = %d, size = %d",
                             it.get_type(), it.get_len());
@@ -695,7 +1171,7 @@
         wifi_ring_buffer_data_handler handler)
 {
     wifi_handle handle = getWifiHandle(iface);
-    ALOGV("Loghandler start, handle = %p", handle);
+    ALOGE("Loghandler start, handle = %p", handle);
 
     SetLogHandler *cmd = new SetLogHandler(iface, id, handler);
     NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
@@ -710,13 +1186,17 @@
         cmd->releaseRef();
         return result;
     }
+
+#ifdef RING_DUMP
+    wifi_start_ring_dump(iface, handler);
+#endif /* RING_DUMP */
     return result;
 }
 
 wifi_error wifi_reset_log_handler(wifi_request_id id, wifi_interface_handle iface)
 {
     wifi_handle handle = getWifiHandle(iface);
-    ALOGV("Loghandler reset, wifi_request_id = %d, handle = %p", id, handle);
+    ALOGE("Loghandler reset, wifi_request_id = %d, handle = %p", id, handle);
 
     if (id == -1) {
         wifi_ring_buffer_data_handler handler;
@@ -726,10 +1206,14 @@
         NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
         cmd->cancel();
         cmd->releaseRef();
+
+#ifdef RING_DUMP
+        wifi_stop_ring_dump(iface, handler);
+#endif /* RING_DUMP */
         return WIFI_SUCCESS;
     }
 
-    return wifi_cancel_cmd(id, iface);
+    return wifi_get_cancel_cmd(id, iface);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -795,7 +1279,6 @@
     }
 
     virtual int handleEvent(WifiEvent& event) {
-        wifi_ring_buffer_id ring_id;
         char *buffer = NULL;
         int buffer_size = 0;
         bool is_err_alert = false;
@@ -827,7 +1310,7 @@
                 }
             }
 
-            if(is_err_alert) {
+            if (is_err_alert) {
                 mBuffSize = sizeof(mErrCode);
                 if (mBuff) free(mBuff);
                 mBuff = (char *)malloc(mBuffSize);
@@ -896,6 +1379,114 @@
     }
 };
 
+class SetRestartHandler : public WifiCommand
+{
+    wifi_subsystem_restart_handler mHandler;
+    char *mBuff;
+public:
+    SetRestartHandler(wifi_handle handle, wifi_request_id id, wifi_subsystem_restart_handler handler)
+        : WifiCommand("SetRestartHandler", handle, id), mHandler(handler), mBuff(NULL)
+    { }
+    int start() {
+        ALOGI("Start Restart Handler handler");
+        registerVendorHandler(BRCM_OUI, BRCM_VENDOR_EVENT_HANGED);
+        return WIFI_SUCCESS;
+    }
+    virtual int cancel() {
+        ALOGI("Clear Restart Handler");
+
+        /* unregister alert handler */
+        unregisterVendorHandler(BRCM_OUI, BRCM_VENDOR_EVENT_HANGED);
+        wifi_unregister_cmd(wifiHandle(), id());
+        ALOGI("Success to clear restarthandler");
+        return WIFI_SUCCESS;
+    }
+
+    virtual int handleResponse(WifiEvent& reply) {
+        /* Nothing to do on response! */
+        return NL_OK;
+    }
+
+    virtual int handleEvent(WifiEvent& event) {
+        nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+        int len = event.get_vendor_data_len();
+        int event_id = event.get_vendor_subcmd();
+        ALOGI("Got event: %d", event_id);
+
+        if (vendor_data == NULL || len == 0) {
+            ALOGE("No Debug data found");
+            return NL_SKIP;
+        }
+        if (event_id == BRCM_VENDOR_EVENT_HANGED) {
+            for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+                if (it.get_type() == LOGGER_ATTRIBUTE_HANG_REASON) {
+                    mBuff = (char *)it.get_data();
+                } else {
+                    ALOGI("Ignoring invalid attribute type = %d, size = %d",
+                            it.get_type(), it.get_len());
+                }
+            }
+
+            if (*mHandler.on_subsystem_restart) {
+                (*mHandler.on_subsystem_restart)(mBuff);
+                ALOGI("Hang event received. Trigger SSR handler:%p",
+                    mHandler.on_subsystem_restart);
+            } else {
+                ALOGI("No Restart handler registered");
+            }
+        }
+        return NL_OK;
+    }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+class SubSystemRestart : public WifiCommand
+{
+    public:
+    SubSystemRestart(wifi_interface_handle iface)
+        : WifiCommand("SubSystemRestart", iface, 0)
+    { }
+
+    int createRequest(WifiRequest& request) {
+        int result = request.create(GOOGLE_OUI, WIFI_SUBCMD_TRIGGER_SSR);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+        request.attr_end(data);
+        return WIFI_SUCCESS;
+    }
+
+    int create() {
+        WifiRequest request(familyId(), ifaceId());
+
+        int result = createRequest(request);
+        if (result < 0) {
+            ALOGE("Failed to create ssr request result = %d\n", result);
+            return result;
+        }
+
+        result = requestResponse(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("Failed to register ssr response; result = %d\n", result);
+        }
+        return result;
+    }
+
+    protected:
+    int handleResponse(WifiEvent& reply) {
+        /* Nothing to do on response! */
+        return NL_OK;
+    }
+
+    int handleEvent(WifiEvent& event) {
+        /* NO events to handle here! */
+        return NL_SKIP;
+    }
+
+};
 ///////////////////////////////////////////////////////////////////////////////
 class HalInit : public WifiCommand
 {
@@ -939,6 +1530,7 @@
             ALOGE("Failed to register set hal start response; result = %d", result);
         }
         wifi_unregister_cmd(wifiHandle(), id());
+	ALOGV("Stop HAL Successfully Completed, mErrCode = %d\n", mErrCode);
         return result;
     }
 
@@ -983,6 +1575,338 @@
     }
 };
 
+#ifdef RING_DUMP
+///////////////////////////////////////////////////////////////////////////////
+class RingDump : public WifiCommand
+{
+    int mLargestBuffSize;
+    char *mBuff;
+    int mErrCode;
+    int mNumMaps;
+    wifi_buf_ring_map_entry_t *mMap;
+    int attr_type_len[DUMP_EVENT_ATTR_MAX];
+    char *ring_name[DUMP_BUF_ATTR_MAX];
+    wifi_ring_buffer_data_handler mHandle;
+
+public:
+    RingDump(wifi_interface_handle iface, int id, int num_maps, wifi_buf_ring_map_entry_t *map,
+        wifi_ring_buffer_data_handler ring_handle)
+        : WifiCommand("RingDump", iface, id), mLargestBuffSize(0), mBuff(NULL),
+        mErrCode(0), mNumMaps(num_maps), mMap(map), mHandle(ring_handle)
+    {
+        memset(attr_type_len, 0, sizeof(attr_type_len));
+        for (int i = 0; i < DUMP_BUF_ATTR_MAX; i++) {
+            ring_name[i] = NULL;
+        }
+    }
+    RingDump(wifi_interface_handle iface, int id)
+        : WifiCommand("RingDump", iface, id), mLargestBuffSize(0), mBuff(NULL),
+        mErrCode(0)
+    {
+    }
+
+    int start() {
+        DUMP_INFO(("Start Ring Dump Map_cnt:%d\n", mNumMaps));
+        registerVendorHandler(GOOGLE_OUI, GOOGLE_FILE_DUMP_EVENT);
+
+        //Set ringname to buf hashmap
+        for (int i = 0; i < mNumMaps; i++) {
+            int type = mMap[i].type;
+            ring_name[type] = (char *)malloc(DBGRING_NAME_MAX);
+            memset(ring_name[type], 0, DBGRING_NAME_MAX);
+            memcpy(ring_name[type], mMap[i].ring_name, strlen(mMap[i].ring_name));
+            DUMP_DEBUG(("Set ringname Buf:%s Ringname:%s len:%lu",
+                EWP_CmdAttrToString(type), ring_name[type], strlen(mMap[i].ring_name)));
+        }
+        return WIFI_SUCCESS;
+    }
+
+    virtual int freeup() {
+        DUMP_DEBUG(("freeup:Enter\n"));
+        if (mBuff) {
+            free(mBuff);
+            mBuff = NULL;
+            DUMP_INFO(("freed allocated memory\n"));
+        }
+        return WIFI_SUCCESS;
+    }
+
+    virtual int cancel() {
+        /* unregister file dump handler */
+        unregisterVendorHandler(GOOGLE_OUI, GOOGLE_FILE_DUMP_EVENT);
+        wifi_unregister_cmd(wifiHandle(), id());
+
+        /* Free up the ring names allocated */
+        for (u8 i = 0; i < DUMP_BUF_ATTR_MAX; i++) {
+            if (ring_name[i]) {
+                free(ring_name[i]);
+                ring_name[i] = NULL;
+            }
+        }
+        if (mBuff) {
+            free(mBuff);
+        }
+
+        DUMP_INFO(("Stop Ring Dump Successfully Completed, mErrCode = %d\n", mErrCode));
+        return WIFI_SUCCESS;
+    }
+
+    virtual int handleResponse(WifiEvent& reply) {
+        DUMP_DEBUG(("RingDump::handleResponse\n"));
+        int buf_attr = DUMP_BUF_ATTR_INVALID;
+        int len_attr = DUMP_LEN_ATTR_INVALID;
+        int index = -1;
+
+        if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+            ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+            return NL_SKIP;
+        }
+
+        nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+        int len = reply.get_vendor_data_len();
+
+        if (vendor_data == NULL || len == 0) {
+            ALOGE("no vendor data in memory dump response; ignoring it");
+            return NL_SKIP;
+        }
+
+        for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+            buf_attr = it.get_type();
+            switch (buf_attr) {
+                case DUMP_BUF_ATTR_MEMDUMP:
+                case DUMP_BUF_ATTR_TIMESTAMP:
+                case DUMP_BUF_ATTR_ECNTRS:
+                case DUMP_BUF_ATTR_DHD_DUMP:
+                case DUMP_BUF_ATTR_EXT_TRAP:
+                case DUMP_BUF_ATTR_HEALTH_CHK:
+                case DUMP_BUF_ATTR_COOKIE:
+                case DUMP_BUF_ATTR_FLOWRING_DUMP:
+                case DUMP_BUF_ATTR_STATUS_LOG:
+                case DUMP_BUF_ATTR_RTT_LOG:
+                case DUMP_BUF_ATTR_PKTID_MAP_LOG:
+                case DUMP_BUF_ATTR_PKTID_UNMAP_LOG: {
+                    if (it.get_u32()) {
+                        ALOGE("Copying data to userspace failed, status = %d\n", it.get_u32());
+                        return WIFI_ERROR_UNKNOWN;
+                    }
+                    index = logger_attr_buffer_lookup(buf_attr);
+                    if (index == -1) {
+                        ALOGE("Invalid index. buf attr = %s\n", EWP_CmdAttrToString(buf_attr));
+                        return WIFI_ERROR_UNKNOWN;
+                    }
+                    len_attr = attr_lookup_tbl[index].attr_type;
+                    if (len_attr == DUMP_EVENT_ATTR_MAX) {
+                        ALOGE("Invalid len attr = %s\n", EWP_EventAttrToString(len_attr));
+                        return WIFI_ERROR_UNKNOWN;
+                    }
+                    if (!mBuff || attr_type_len[len_attr] <= 0) {
+                        return WIFI_ERROR_UNKNOWN;
+                    }
+
+                    if (!ring_name[buf_attr]) {
+                        ALOGE("Not allocated buf attr = %s\n", EWP_CmdAttrToString(buf_attr));
+                        return WIFI_ERROR_UNKNOWN;
+                    }
+                    DUMP_INFO(("RingDump:: buf_attr:%s size = %d ring_name:%s\n",
+                        EWP_CmdAttrToString(buf_attr), attr_type_len[len_attr],
+                        ring_name[buf_attr]));
+                    if (mHandle.on_ring_buffer_data) {
+                        /* on_ring_buffer_data callback requires status memory
+                         * so should pass status memory */
+                        wifi_ring_buffer_status status;
+                        memset(&status, 0, sizeof(status));
+                        /* Skip msg header. Retrieved log */
+                        (*mHandle.on_ring_buffer_data)(ring_name[buf_attr], mBuff,
+                            attr_type_len[len_attr], &status);
+                    }
+                    if (mBuff) {
+                        memset(mBuff, 0, mLargestBuffSize);
+                    }
+                    break;
+                }
+                default: {
+                    DUMP_DEBUG(("Ignoring invalid attribute buf_attr = %d, size = %d",
+                        buf_attr, it.get_len()));
+                    break;
+                }
+            }
+        }
+        return NL_OK;
+    }
+
+    virtual int request_logger_dump(WifiRequest& request,
+            buf_data_t *buf, int len_attr) {
+
+        int result = 0;
+        int buf_attr = DUMP_BUF_ATTR_INVALID;
+        int index = -1;
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+        index = logger_attr_lookup(len_attr);
+        if (index == -1) {
+            ALOGE("Invalid index\n");
+            return WIFI_ERROR_UNKNOWN;
+        }
+        buf_attr = attr_lookup_tbl[index].buf_attr;
+
+        if (buf_attr != DUMP_BUF_ATTR_INVALID) {
+            result = request.put(buf_attr, buf, sizeof(buf_data_t));
+            if (result != WIFI_SUCCESS) {
+                ALOGE("Failed to put get memory dump request; result = %d", result);
+                return result;
+            }
+        } else {
+            ALOGE("Invalid buf attr = %s, index = %d\n",
+                EWP_CmdAttrToString(buf_attr), index);
+            return WIFI_ERROR_UNKNOWN;
+        }
+        DUMP_INFO(("Trigger get dump for buf attr = %s\n",
+                EWP_CmdAttrToString(buf_attr)));
+
+        request.attr_end(data);
+        return result;
+    }
+
+    virtual int handleEvent(WifiEvent& event) {
+        mLargestBuffSize = 0;
+        mBuff = NULL;
+        memset(attr_type_len, 0, sizeof(attr_type_len));
+        u8 i = 0;
+        int result = 0;
+        int mActualBuffSize = 0;
+        int index = -1;
+
+        nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+        int len = event.get_vendor_data_len();
+        int event_id = event.get_vendor_subcmd();
+        int req_attr_cnt = 0;
+        int req_attr[DUMP_EVENT_ATTR_MAX];
+        int buf_attr = DUMP_BUF_ATTR_INVALID;
+
+        if (vendor_data == NULL || len == 0) {
+            ALOGE("No Debug data found");
+            return NL_SKIP;
+        }
+        DUMP_INFO(("Ring Dump handler. Got event: %d", event_id));
+
+        buf_data_t buf;
+
+        memset(&buf, 0, sizeof(buf_data_t));
+        buf.ver = 0;
+        buf.buf_threshold = 0;
+
+        if (event_id == GOOGLE_FILE_DUMP_EVENT) {
+            for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+                int attr = it.get_type();
+                switch (attr) {
+                    case DUMP_LEN_ATTR_MEMDUMP:
+                    case DUMP_LEN_ATTR_TIMESTAMP:
+                    case DUMP_LEN_ATTR_ECNTRS:
+                    case DUMP_LEN_ATTR_DHD_DUMP:
+                    case DUMP_LEN_ATTR_EXT_TRAP:
+                    case DUMP_LEN_ATTR_HEALTH_CHK:
+                    case DUMP_LEN_ATTR_COOKIE:
+                    case DUMP_LEN_ATTR_FLOWRING_DUMP:
+                    case DUMP_LEN_ATTR_STATUS_LOG:
+                    case DUMP_LEN_ATTR_RTT_LOG:
+                    case DUMP_LEN_ATTR_PKTID_MAP_LOG:
+                    case DUMP_LEN_ATTR_PKTID_UNMAP_LOG: {
+                        mActualBuffSize = it.get_u32();
+                        DUMP_DEBUG(("len attr %s, len %d\n",
+                            EWP_EventAttrToString(attr), mActualBuffSize));
+                        if (mActualBuffSize > mLargestBuffSize)
+                            mLargestBuffSize = mActualBuffSize;
+                            attr_type_len[attr] = mActualBuffSize;
+
+                            /* Store the order in which attributes are received
+                             * so that file dump can be done in the same order
+                             */
+                            req_attr[req_attr_cnt++] = attr;
+                            break;
+                    }
+                    default: {
+                        ALOGE("Ignoring invalid attribute type = %d, size = %d",
+                            attr, it.get_len());
+                            break;
+                        }
+                }
+            }
+            /* Allocation for the largest buffer size to use it recursively for other buf attr. */
+            if (mLargestBuffSize) {
+                DUMP_INFO(("Max dump size: %d", mLargestBuffSize));
+                mBuff = (char *)malloc(mLargestBuffSize);
+                if (!mBuff) {
+                    ALOGE("Buffer allocation failed");
+                    return NL_SKIP;
+                }
+                memset(mBuff, 0, mLargestBuffSize);
+            }
+
+            WifiRequest request(familyId(), ifaceId());
+            result = request.create(GOOGLE_OUI, LOGGER_DEBUG_GET_DUMP);
+            if (result != WIFI_SUCCESS) {
+                ALOGE("Failed to create get memory dump request; result = %d", result);
+                freeup();
+                goto exit;
+            }
+
+            /* Requesting logger dump for each received attr */
+            for (i = 0; i < req_attr_cnt; i++) {
+                int attr = req_attr[i];
+
+                if (attr_type_len[attr] == 0) {
+                    continue;
+                }
+
+                index = logger_attr_lookup(attr);
+                buf_attr = attr_lookup_tbl[index].buf_attr;
+                if (!ring_name[buf_attr]) {
+                    ALOGE("Failed to find ringname index:%d buf_attr:%d", index, buf_attr);
+                    continue;
+                }
+
+                buf.len = attr_type_len[attr];
+                buf.data_buf[0] = mBuff;
+                DUMP_DEBUG(("buf len = %d, buf ptr= %p for attr = %s\n",
+                    buf.len, buf.data_buf[0], EWP_EventAttrToString(attr)));
+                result = request_logger_dump(request, &buf, attr);
+                if (result != WIFI_SUCCESS) {
+                    /* Proceeding further for other attributes */
+                    ALOGE("Failed to request the logger dump for attr = %s; result = %d",
+                        EWP_EventAttrToString(attr), result);
+                    continue;
+                }
+                result = requestResponse(request);
+                if (result != WIFI_SUCCESS) {
+                    ALOGE("Failed to register get memory dump response for attr = %s; result = %d",
+                        EWP_EventAttrToString(attr), result);
+                        /* Proceeding further for other attributes */
+                        continue;
+                }
+            }
+
+            WifiRequest request2(familyId(), ifaceId());
+            result = request2.create(GOOGLE_OUI, LOGGER_FILE_DUMP_DONE_IND);
+            if (result != WIFI_SUCCESS) {
+                ALOGE("Failed to trigger dev close; result = %d", result);
+                freeup();
+                goto exit;
+            }
+            requestResponse(request2);
+            freeup();
+        } else {
+            ALOGE("dump event missing dump length attribute");
+            return NL_SKIP;
+        }
+    exit:
+        if (result != WIFI_SUCCESS) {
+            return NL_SKIP;
+        }
+        return NL_OK;
+    }
+};
+///////////////////////////////////////////////////////////////////////////////
+#endif /* RING_DUMP */
 
 wifi_error wifi_start_hal(wifi_interface_handle iface)
 {
@@ -1026,10 +1950,54 @@
     return result;
 }
 
-wifi_error wifi_stop_hal(wifi_interface_handle iface)
+#ifdef RING_DUMP
+wifi_error wifi_start_ring_dump(wifi_interface_handle iface,
+    wifi_ring_buffer_data_handler ring_handle)
 {
     wifi_handle handle = getWifiHandle(iface);
+    DUMP_INFO(("start ring dump, handle = %p", handle));
+    wifi_buf_ring_map_entry_t map[DUMP_BUF_ATTR_MAX];
+    unsigned int num_maps = DUMP_BUF_ATTR_MAX;
+    wifi_error result;
 
+    /* Get mapping table from driver */
+    DebugCommand *debug_cmd = new DebugCommand(iface, &num_maps, map, GET_BUF_RING_MAP);
+    NULL_CHECK_RETURN(debug_cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+    result = (wifi_error)debug_cmd->start();
+    debug_cmd->releaseRef();
+
+    /* Set ringname to corresponding buf attr */
+    RingDump *cmd = new RingDump(iface, FILE_DUMP_REQUEST_ID, num_maps, map, ring_handle);
+    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+    result = wifi_register_cmd(handle, FILE_DUMP_REQUEST_ID, cmd);
+    if (result != WIFI_SUCCESS) {
+        cmd->releaseRef();
+        return result;
+    }
+
+    result = (wifi_error)cmd->start();
+    if (result != WIFI_SUCCESS) {
+        wifi_unregister_cmd(handle, FILE_DUMP_REQUEST_ID);
+        cmd->releaseRef();
+        return result;
+    }
+    return result;
+}
+
+wifi_error wifi_stop_ring_dump(wifi_interface_handle iface,
+    wifi_ring_buffer_data_handler ring_handle)
+{
+    RingDump *cmd = new RingDump(iface, FILE_DUMP_REQUEST_ID);
+    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+    DUMP_INFO(("stop ring dump"));
+    cmd->cancel();
+    cmd->releaseRef();
+    return WIFI_SUCCESS;
+}
+#endif /* RING_DUMP */
+
+wifi_error wifi_stop_hal(wifi_interface_handle iface)
+{
     HalInit *cmd = new HalInit(iface, HAL_START_REQUEST_ID);
     NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
     cmd->cancel();
@@ -1037,6 +2005,85 @@
     return WIFI_SUCCESS;
 }
 
+
+wifi_error wifi_set_subsystem_restart_handler(wifi_handle handle,
+                                              wifi_subsystem_restart_handler handler)
+{
+    hal_info *info = NULL;
+
+    info = (hal_info *)handle;
+    if (info == NULL) {
+        ALOGE("Could not find hal info\n");
+        return WIFI_ERROR_UNKNOWN;
+    }
+
+    SetRestartHandler *cmd = new SetRestartHandler(handle, HAL_RESTART_ID, handler);
+    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+    wifi_error result = wifi_register_cmd(handle, HAL_RESTART_ID, cmd);
+    if (result != WIFI_SUCCESS) {
+        cmd->releaseRef();
+        return result;
+    }
+
+    result = (wifi_error)cmd->start();
+    if (result != WIFI_SUCCESS) {
+        wifi_unregister_cmd(handle, HAL_RESTART_ID);
+        cmd->releaseRef();
+        return result;
+    }
+
+    /* Cache the handler to use it for trigger subsystem restart */
+    ALOGI("Register SSR handler:%p", handler);
+    info->restart_handler = handler;
+    return result;
+}
+
+wifi_error wifi_trigger_subsystem_restart(wifi_handle handle)
+{
+    wifi_error result = WIFI_SUCCESS;
+    hal_info *info = NULL;
+    char error_str[20];
+    SubSystemRestart *cmd = NULL;
+    wifi_interface_handle *ifaceHandles = NULL;
+    wifi_interface_handle wlan0Handle;
+    int numIfaceHandles = 0;
+
+    info = (hal_info *)handle;
+    if (handle == NULL || info == NULL) {
+        ALOGE("Could not find hal info\n");
+        result = WIFI_ERROR_UNKNOWN;
+        goto exit;
+    }
+
+    ALOGI("Trigger subsystem restart\n");
+
+    wlan0Handle = wifi_get_wlan_interface((wifi_handle)handle, ifaceHandles, numIfaceHandles);
+
+    cmd = new SubSystemRestart(wlan0Handle);
+    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+
+    result = (wifi_error)cmd->create();
+    if (result != WIFI_SUCCESS) {
+        cmd->releaseRef();
+        strncpy(error_str, "WIFI_ERROR_UNKNOWN", sizeof(error_str));
+        ALOGE("Failed to create SSR");
+        goto exit;
+    }
+
+    strncpy(error_str, "WIFI_SUCCESS", sizeof(error_str));
+
+exit:
+    if (info->restart_handler.on_subsystem_restart) {
+        ALOGI("Trigger ssr handler registered handler:%p",
+            info->restart_handler.on_subsystem_restart);
+        (info->restart_handler.on_subsystem_restart)(error_str);
+    } else {
+        ALOGI("No trigger ssr handler registered");
+    }
+
+    return result;
+}
+
 wifi_error wifi_set_alert_handler(wifi_request_id id, wifi_interface_handle iface,
         wifi_alert_handler handler)
 {
@@ -1075,7 +2122,7 @@
         return WIFI_SUCCESS;
     }
 
-    return wifi_cancel_cmd(id, iface);
+    return wifi_get_cancel_cmd(id, iface);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1345,7 +2392,7 @@
         for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
             if (it.get_type() == LOGGER_ATTRIBUTE_PKT_FATE_NUM) {
                 *mNoProvidedFates = it.get_u32();
-                ALOGI("No: of pkt fates provided is %d\n", *mNoProvidedFates);
+                ALOGI("No: of pkt fates provided is %zu\n", *mNoProvidedFates);
             } else {
                 ALOGE("Ignoring invalid attribute type = %d, size = %d\n",
                         it.get_type(), it.get_len());
@@ -1429,7 +2476,7 @@
                     mWakeReasonCnt->total_driver_fw_local_wake =
                         it.get_u32();
                     break;
-                case WAKE_STAT_ATTRIBUTE_TOTAL_CMD_EVENT:
+                case WAKE_STAT_ATTRIBUTE_TOTAL:
                     mWakeReasonCnt->total_cmd_event_wake =
                         it.get_u32();
                     break;
@@ -1437,7 +2484,7 @@
                     mWakeReasonCnt->cmd_event_wake_cnt_used =
                         it.get_u32();
                     break;
-                case WAKE_STAT_ATTRIBUTE_CMD_EVENT_WAKE:
+                case WAKE_STAT_ATTRIBUTE_WAKE:
                     memcpy(mCmdEventWakeCount, it.get_data(),
                             (mWakeReasonCnt->cmd_event_wake_cnt_used * sizeof(int)));
                     break;
@@ -1485,7 +2532,7 @@
                     mWakeReasonCnt->rx_multicast_wake_pkt_info.ipv6_rx_multicast_addr_cnt =
                         it.get_u32();
                     break;
-                case WAKE_STAT_ATTRIBUTE_OTHER__RX_MULTICAST_ADD_CNT:
+                case WAKE_STAT_ATTRIBUTE_OTHER_RX_MULTICAST_ADD_CNT:
                     mWakeReasonCnt->rx_multicast_wake_pkt_info.other_rx_multicast_addr_cnt =
                         it.get_u32();
                     break;
@@ -1540,3 +2587,253 @@
     cmd->releaseRef();
     return result;
 }
+
+///////////////////////////////////////////////////////////////////////////////
+class OtaUpdateCommand : public WifiCommand
+{
+
+    public:
+    OtaUpdateCommand(wifi_interface_handle iface)
+        : WifiCommand("OtaUpdateCommand", iface, 0)
+    { }
+
+    int start() {
+        ALOGE("Start OtaUpdateCommand");
+        WifiRequest request(familyId(), ifaceId());
+
+        int result = request.create(GOOGLE_OUI, WIFI_SUBCMD_GET_OTA_CURRUNT_INFO);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("Failed to set hal start; result = %d", result);
+            return result;
+        }
+
+        result = requestResponse(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("Failed to register set hal start response; result = %d", result);
+        }
+        return result;
+    }
+
+    int otaDownload(ota_info_buf_t* buf, uint32_t ota_version) {
+        u32 force_reg_on = false;
+        WifiRequest request(familyId(), ifaceId());
+        int result = request.create(GOOGLE_OUI, WIFI_SUBCMD_OTA_UPDATE);
+
+        ALOGE("Download the OTA configuration");
+        if (result != WIFI_SUCCESS) {
+            ALOGE("Failed to set Hal preInit; result = %d", result);
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+        result = request.put_u32(OTA_DOWNLOAD_CLM_LENGTH_ATTR, buf->ota_clm_len);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("otaDownload Failed to put data= %d", result);
+            return result;
+        }
+
+        result = request.put(OTA_DOWNLOAD_CLM_ATTR, buf->ota_clm_buf, sizeof(*buf->ota_clm_buf));
+        if (result != WIFI_SUCCESS) {
+            ALOGE("otaDownload Failed to put data= %d", result);
+            return result;
+        }
+
+        result = request.put_u32(OTA_DOWNLOAD_NVRAM_LENGTH_ATTR, buf->ota_nvram_len);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("otaDownload Failed to put data= %d", result);
+            return result;
+        }
+
+        result = request.put(OTA_DOWNLOAD_NVRAM_ATTR,
+                buf->ota_nvram_buf, sizeof(*buf->ota_nvram_buf));
+        if (result != WIFI_SUCCESS) {
+            ALOGE("otaDownload Failed to put data= %d", result);
+            return result;
+        }
+
+        if (applied_ota_version != ota_version) {
+            force_reg_on = true;
+            applied_ota_version = ota_version;
+        }
+        result = request.put_u32(OTA_SET_FORCE_REG_ON, force_reg_on);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("otaDownload Failed to put data= %d", result);
+            return result;
+        }
+
+        request.attr_end(data);
+
+        result = requestResponse(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("Failed to register set otaDownload; result = %d", result);
+        }
+
+        return result;
+    }
+
+    virtual int handleResponse(WifiEvent& reply) {
+        ALOGD("In OtaUpdateCommand::handleResponse");
+
+        if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+            ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+            return NL_SKIP;
+        }
+
+        int id = reply.get_vendor_id();
+        int subcmd = reply.get_vendor_subcmd();
+        nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+        int len = reply.get_vendor_data_len();
+
+        ALOGI("Id = %0x, subcmd = %d, len = %d", id, subcmd, len);
+
+        if (vendor_data == NULL || len == 0) {
+            ALOGE("no vendor data in GetPktFateCommand response; ignoring it\n");
+            return NL_SKIP;
+        }
+
+        for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+            switch (it.get_type()) {
+                case OTA_CUR_NVRAM_EXT_ATTR:
+                    strncpy(ota_nvram_ext, (char*)it.get_string(), it.get_len());
+                    ALOGI("Current Nvram ext [%s]\n", ota_nvram_ext);
+                    break;
+                default:
+                    ALOGE("Ignoring invalid attribute type = %d, size = %d\n",
+                            it.get_type(), it.get_len());
+                    break;
+            }
+        }
+        return NL_OK;
+    }
+
+    virtual int handleEvent(WifiEvent& event) {
+        /* NO events! */
+        return NL_SKIP;
+    }
+};
+
+wifi_error read_ota_file(char* file, char** buffer, uint32_t* size)
+{
+    FILE* fp = NULL;
+    int file_size;
+    char* buf;
+    fp = fopen(file, "r");
+
+    if (fp == NULL) {
+        ALOGI("File [%s] doesn't exist.", file);
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+
+    fseek(fp, 0, SEEK_END);
+    file_size = ftell(fp);
+
+    buf = (char *)malloc(file_size + 1);
+    if (buf == NULL) {
+        fclose(fp);
+        return WIFI_ERROR_UNKNOWN;
+    }
+    memset(buf, 0, file_size + 1);
+    fseek(fp, 0, SEEK_SET);
+    fread(buf, file_size, 1, fp);
+
+    *buffer = (char*) buf;
+    *size = file_size;
+    fclose(fp);
+    return WIFI_SUCCESS;
+}
+
+wifi_error check_multiple_nvram_clm(uint32_t type, char* hw_revision, char* hw_sku,
+        char** buffer, uint32_t* buffer_len)
+{
+    char file_name[MAX_NV_FILE][FILE_NAME_LEN];
+    char nvram_clmblob_default_file[FILE_NAME_LEN] = {0,};
+    wifi_error result = WIFI_SUCCESS;
+
+    if (type == CLM_BLOB) {
+        sprintf(nvram_clmblob_default_file, "%s%s", OTA_PATH, OTA_CLM_FILE);
+    }
+    else if (type == NVRAM) {
+        sprintf(nvram_clmblob_default_file, "%s%s", OTA_PATH, OTA_NVRAM_FILE);
+    }
+    for (unsigned int i = 0; i < MAX_NV_FILE; i++) {
+        memset(file_name[i], 0, FILE_NAME_LEN);
+    }
+
+    sprintf(file_name[0], "%s_%s_%s", nvram_clmblob_default_file, hw_revision, hw_sku);
+    sprintf(file_name[1], "%s_%s", nvram_clmblob_default_file, hw_revision);
+    sprintf(file_name[2], "%s_%s", nvram_clmblob_default_file, hw_sku);
+    sprintf(file_name[3], "%s", nvram_clmblob_default_file);
+
+    for (unsigned int i = 0; i < MAX_NV_FILE; i++) {
+        result = read_ota_file(file_name[i], buffer, buffer_len);
+        if (result == WIFI_SUCCESS) {
+            ALOGI("[OTA] %s PATH %s", type == NVRAM ? "NVRAM" : "CLM", file_name[i]);
+            break;
+        }
+    }
+    return result;
+}
+
+wifi_error wifi_hal_ota_update(wifi_interface_handle iface, uint32_t ota_version)
+{
+    wifi_handle handle = getWifiHandle(iface);
+    wifi_error result = WIFI_SUCCESS;
+    ota_info_buf_t buf;
+    char *buffer_nvram = NULL;
+    char *buffer_clm = NULL;
+    char prop_revision_buf[PROPERTY_VALUE_MAX] = {0,};
+    char prop_sku_buf[PROPERTY_VALUE_MAX] = {0,};
+    char sku_name[MAX_SKU_NAME_LEN] = {0,};
+
+    OtaUpdateCommand *cmd = new OtaUpdateCommand(iface);
+    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+
+    ALOGD("wifi_hal_ota_update, handle = %p, ota_version %d\n", handle, ota_version);
+
+    result = (wifi_error)cmd->start();
+    if (result != WIFI_SUCCESS) {
+        cmd->releaseRef();
+        return result;
+    }
+
+    property_get(HW_DEV_PROP, prop_revision_buf, NULL);
+    property_get(HW_SKU_PROP, prop_sku_buf, NULL);
+
+    strncpy(sku_name, "NA", MAX_SKU_NAME_LEN);
+    for (int i = 0; i < ARRAYSIZE(sku_table); i ++) {
+        if (strcmp(prop_sku_buf, sku_table[i].hw_id) == 0) {
+            strncpy(sku_name, sku_table[i].sku, MAX_SKU_NAME_LEN);
+            break;
+        }
+    }
+    ALOGD("prop_sku_buf is %s, sku_name is %s", prop_sku_buf, sku_name);
+
+    check_multiple_nvram_clm(CLM_BLOB, prop_revision_buf, sku_name, &buffer_clm, &buf.ota_clm_len);
+    if (buffer_clm == NULL) {
+        ALOGE("buffer_clm is null");
+        goto exit;
+    }
+    buf.ota_clm_buf[0] = buffer_clm;
+
+    check_multiple_nvram_clm(NVRAM, prop_revision_buf, sku_name,
+            &buffer_nvram, &buf.ota_nvram_len);
+    if (buffer_nvram == NULL) {
+        ALOGE("buffer_nvram is null");
+        goto exit;
+    }
+    buf.ota_nvram_buf[0] = buffer_nvram;
+    cmd->otaDownload(&buf, ota_version);
+
+exit:
+    if (buffer_clm != NULL) {
+        free(buffer_clm);
+    }
+    if (buffer_nvram != NULL) {
+        free(buffer_nvram);
+    }
+
+    cmd->releaseRef();
+
+    return result;
+}
diff --git a/bcmdhd/wifi_hal/wifi_offload.cpp b/bcmdhd/wifi_hal/wifi_offload.cpp
index 8054f49..1702ffd 100644
--- a/bcmdhd/wifi_hal/wifi_offload.cpp
+++ b/bcmdhd/wifi_hal/wifi_offload.cpp
@@ -52,13 +52,16 @@
 } WIFI_OFFLOAD_SUB_COMMAND;
 
 typedef enum {
-    MKEEP_ALIVE_ATTRIBUTE_ID,
-    MKEEP_ALIVE_ATTRIBUTE_IP_PKT,
-    MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN,
-    MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR,
-    MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR,
-    MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC,
-    MKEEP_ALIVE_ATTRIBUTE_ETHER_TYPE
+    MKEEP_ALIVE_ATTRIBUTE_INVALID		= 0,
+    MKEEP_ALIVE_ATTRIBUTE_ID			= 1,
+    MKEEP_ALIVE_ATTRIBUTE_IP_PKT		= 2,
+    MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN		= 3,
+    MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR		= 4,
+    MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR		= 5,
+    MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC		= 6,
+    MKEEP_ALIVE_ATTRIBUTE_ETHER_TYPE		= 7,
+    /* Add new attributes just above this */
+    MKEEP_ALIVE_ATTRIBUTE_MAX
 } WIFI_MKEEP_ALIVE_ATTRIBUTE;
 
 typedef enum {
diff --git a/bcmdhd/wpa_supplicant_8_lib/Android.mk b/bcmdhd/wpa_supplicant_8_lib/Android.mk
index 518f0ca..448a7ca 100644
--- a/bcmdhd/wpa_supplicant_8_lib/Android.mk
+++ b/bcmdhd/wpa_supplicant_8_lib/Android.mk
@@ -66,6 +66,9 @@
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := lib_driver_cmd_bcmdhd
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-BSD
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/NOTICE
 LOCAL_SHARED_LIBRARIES := libc libcutils
 LOCAL_CFLAGS := $(L_CFLAGS)
 LOCAL_SRC_FILES := $(WPA_SRC_FILE)