Merge "Merge Android 12"
diff --git a/bcmdhd/wifi_hal/Android.mk b/bcmdhd/wifi_hal/Android.mk
index 6b79524..580a730 100755
--- a/bcmdhd/wifi_hal/Android.mk
+++ b/bcmdhd/wifi_hal/Android.mk
@@ -41,6 +41,12 @@
 
 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
+endif
+
 LOCAL_SRC_FILES := \
 	wifi_hal.cpp \
 	rtt.cpp \
@@ -50,7 +56,8 @@
 	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
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..887b530 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;
     }
 
@@ -157,7 +177,7 @@
         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));
@@ -263,6 +283,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..d5bc971 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 */
 
 
@@ -54,6 +55,7 @@
 #define NMRSTR "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
 #define NAN_MASTER_RANK_LEN 8
 
+#define SAR_CONFIG_SCENARIO_COUNT      100
 
 /*
  This enum defines ranges for various commands; commands themselves
@@ -102,8 +104,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 +181,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 +209,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_SUB_COMMAND;
 
 typedef enum {
@@ -212,10 +269,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,6 +300,7 @@
     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 struct {
@@ -265,6 +327,8 @@
 
     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
 
 
     // add other details
@@ -302,6 +366,59 @@
     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);
@@ -321,18 +438,91 @@
 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);
+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);
 // 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..698789d 100755
--- a/bcmdhd/wifi_hal/cpp_bindings.cpp
+++ b/bcmdhd/wifi_hal/cpp_bindings.cpp
@@ -619,7 +619,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)
diff --git a/bcmdhd/wifi_hal/cpp_bindings.h b/bcmdhd/wifi_hal/cpp_bindings.h
index 8839a72..456f31c 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() {
diff --git a/bcmdhd/wifi_hal/gscan.cpp b/bcmdhd/wifi_hal/gscan.cpp
index f5722f2..f012423 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);
@@ -616,6 +575,10 @@
             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) {
             ALOGE("failed to configure setup; result = %d", result);
@@ -644,10 +607,6 @@
             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) {
             ALOGE("failed to start scan; result = %d", result);
@@ -744,7 +703,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 +761,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 +776,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 +788,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));
@@ -1109,6 +1065,9 @@
             return result;
         }
 
+        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND);
+        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST);
+
         result = requestResponse(request);
         if (result < 0) {
             ALOGI("Failed to execute hotlist setup request, result = %d", result);
@@ -1123,9 +1082,6 @@
             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);
@@ -1329,6 +1285,7 @@
             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);
@@ -1337,7 +1294,6 @@
         }
 
         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 +1324,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,6 +1492,8 @@
             return result;
         }
 
+        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
+
         result = requestResponse(request);
         if (result < 0) {
             ALOGI("failed to set significant wifi change config %d", result);
@@ -1550,8 +1507,6 @@
             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 +1616,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 +1631,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 +1718,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();
@@ -2004,11 +1959,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..a2aabe3 100644
--- a/bcmdhd/wifi_hal/link_layer_stats.cpp
+++ b/bcmdhd/wifi_hal/link_layer_stats.cpp
@@ -37,7 +37,7 @@
 
 #define LOG_TAG  "WifiHAL"
 
-#include <log/log.h>
+#include <utils/Log.h>
 
 #include "wifi_hal.h"
 #include "common.h"
@@ -93,13 +93,14 @@
             return NL_SKIP;
         }
 
-        int id = reply.get_vendor_id();
-        int subcmd = reply.get_vendor_subcmd();
-
-        // ALOGI("Id = %0x, subcmd = %d", id, subcmd);
+	int id = reply.get_vendor_id();
 
         void *data = reply.get_vendor_data();
         int len = reply.get_vendor_data_len();
+	if (!data || !len) {
+		ALOGE("Invalid vendor data received");
+		return NL_SKIP;
+	}
         wifi_radio_stat *radio_stat =
             convertToExternalRadioStatStructure((wifi_radio_stat_internal *)data);
         if (!radio_stat) {
@@ -117,7 +118,9 @@
 private:
     wifi_radio_stat *convertToExternalRadioStatStructure(wifi_radio_stat_internal *internal_stat_ptr) {
         wifi_radio_stat *external_stat_ptr = NULL;
-        if (internal_stat_ptr) {
+	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..0805128 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,9 @@
     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;
 
 typedef enum {
@@ -310,7 +312,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 +382,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 +396,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 +542,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 +656,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;
@@ -967,7 +959,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);
@@ -1513,7 +1505,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 +1519,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 +1552,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 +1648,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 +1659,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 +1700,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 +1841,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);
@@ -2226,10 +2222,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 +2300,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", 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,
@@ -2348,6 +2344,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 +2381,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;
             }
@@ -2484,10 +2501,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");
         }
@@ -2875,26 +2888,6 @@
         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);
@@ -3282,7 +3275,7 @@
                 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 +3309,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 +3393,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 +3414,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 +3449,7 @@
             unregisterVendorHandler(GOOGLE_OUI, i);
         }
         unregisterVendorHandler(GOOGLE_OUI, NAN_ASYNC_RESPONSE_DISABLED);
+        unregisterVendorHandler(GOOGLE_OUI, NAN_EVENT_MATCH_EXPIRY);
     }
     void registerNanVendorEvents()
     {
@@ -3458,6 +3458,7 @@
             registerVendorHandler(GOOGLE_OUI, i);
         }
         registerVendorHandler(GOOGLE_OUI, NAN_ASYNC_RESPONSE_DISABLED);
+        registerVendorHandler(GOOGLE_OUI, NAN_EVENT_MATCH_EXPIRY);
     }
 };
 
@@ -3550,8 +3551,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";
     }
@@ -3902,7 +3901,6 @@
 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;
@@ -4022,7 +4020,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;
@@ -4211,7 +4208,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 +4254,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 +4269,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 +4300,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 +4353,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 +4450,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 +4523,7 @@
                 unregisterVendorHandler(GOOGLE_OUI, i);
             }
             unregisterVendorHandler(GOOGLE_OUI, NAN_ASYNC_RESPONSE_DISABLED);
+            unregisterVendorHandler(GOOGLE_OUI, NAN_EVENT_MATCH_EXPIRY);
         }
         void registerNanVendorEvents()
         {
@@ -4560,6 +4532,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 +4596,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 +4616,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 +4753,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 +4765,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 +4816,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 +4872,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,
@@ -5014,9 +4993,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 +5014,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 +5026,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 +5048,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 +5070,6 @@
         wifi_interface_handle iface, NanDataPathInitiatorRequest* msg)
 {
     wifi_error ret = WIFI_SUCCESS;
-    wifi_handle handle = getWifiHandle(iface);
 
     NAN_DBG_ENTER();
     NanRequestType cmdType;
@@ -5179,7 +5155,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 +5250,6 @@
 {
     wifi_error ret = WIFI_SUCCESS;
     NanDataPathPrimitive *cmd;
-    wifi_handle handle = getWifiHandle(iface);
     NanRequestType cmdType = NAN_DATA_PATH_END;
     NAN_DBG_ENTER();
 
diff --git a/bcmdhd/wifi_hal/rtt.cpp b/bcmdhd/wifi_hal/rtt.cpp
index 81eb17f..43a49e8 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,13 @@
             return result;
         }
 
+        registerVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE);
         result = requestResponse(request);
         if (result != WIFI_SUCCESS) {
             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 +543,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 +577,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 +599,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 +610,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 +627,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 +648,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 +681,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 +705,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 +725,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..0ba633b 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,7 @@
 
 #define WIFI_HAL_CMD_SOCK_PORT       644
 #define WIFI_HAL_EVENT_SOCK_PORT     645
+#define MAX_VIRTUAL_IFACES           5
 
 /*
  * Defines for wifi_wait_for_driver_ready()
@@ -71,8 +74,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 +86,42 @@
 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 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_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 +133,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 +205,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 +307,56 @@
     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;
 
     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 +409,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 +483,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,15 +526,6 @@
             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");
@@ -500,13 +601,20 @@
 
     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;
@@ -528,39 +636,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 +689,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");
 }
 
@@ -660,28 +750,18 @@
         } 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 +801,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 +872,6 @@
         // ALOGI("handling reponse in %s", __func__);
 
         struct nlattr **tb = reply.attributes();
-        struct genlmsghdr *gnlh = reply.header();
         struct nlattr *mcgrp = NULL;
         int i;
 
@@ -989,27 +1066,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 +1098,6 @@
                 ALOGE("failed to stop RSSI monitoring = %d", result);
             }
         }
-        unregisterVendorHandler(GOOGLE_OUI, GOOGLE_RSSI_MONITOR_EVENT);
         return WIFI_SUCCESS;
     }
 
@@ -1069,6 +1145,7 @@
 class AndroidPktFilterCommand : public WifiCommand {
     private:
         const u8* mProgram;
+        u8* mReadProgram;
         u32 mProgramLen;
         u32* mVersion;
         u32* mMaxLen;
@@ -1094,13 +1171,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 +1231,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 +1280,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 +1297,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;
     }
 };
@@ -1385,7 +1495,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 +1506,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 +1544,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 +1565,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 +1579,8 @@
 
     closedir(d);
 
-    info->num_interfaces = n;
+    info->num_interfaces = i;
+    info->max_num_interfaces = n;
     return WIFI_SUCCESS;
 }
 
@@ -1474,6 +1594,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 +1672,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 +1689,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);
@@ -1537,7 +1748,7 @@
 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);
@@ -1557,12 +1768,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 +1809,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 +1859,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 +1913,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..a9f9506 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
 
@@ -72,25 +75,51 @@
     LOGGER_SET_HAL_PID
 } 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,
+    /* Add new attributes just above this */
+    LOGGER_ATTRIBUTE_MAX
 } LOGGER_ATTRIBUTE;
 
 typedef enum {
@@ -117,9 +146,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 +166,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 +177,18 @@
     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
 ///////////////////////////////////////////////////////////////////////////////
 class DebugCommand : public WifiCommand
 {
@@ -465,7 +506,7 @@
                 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;
             }
@@ -624,6 +665,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);
@@ -729,7 +771,7 @@
         return WIFI_SUCCESS;
     }
 
-    return wifi_cancel_cmd(id, iface);
+    return wifi_get_cancel_cmd(id, iface);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -795,7 +837,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 +868,7 @@
                 }
             }
 
-            if(is_err_alert) {
+            if (is_err_alert) {
                 mBuffSize = sizeof(mErrCode);
                 if (mBuff) free(mBuff);
                 mBuff = (char *)malloc(mBuffSize);
@@ -896,6 +937,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:%p", mHandler);
+        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 +1088,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;
     }
 
@@ -1028,8 +1178,6 @@
 
 wifi_error wifi_stop_hal(wifi_interface_handle iface)
 {
-    wifi_handle handle = getWifiHandle(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 +1185,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 +1302,7 @@
         return WIFI_SUCCESS;
     }
 
-    return wifi_cancel_cmd(id, iface);
+    return wifi_get_cancel_cmd(id, iface);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1345,7 +1572,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 +1656,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 +1664,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 +1712,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 +1767,261 @@
     cmd->releaseRef();
     return result;
 }
+
+///////////////////////////////////////////////////////////////////////////////
+class OtaUpdateCommand : public WifiCommand
+{
+    int mErrCode;
+
+    public:
+    OtaUpdateCommand(wifi_interface_handle iface)
+        : WifiCommand("OtaUpdateCommand", iface, 0), mErrCode(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, count;
+    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);
+    count = 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);
+
+    if (strcmp(prop_sku_buf, "G9S9B") == 0 ||
+        strcmp(prop_sku_buf, "G8V0U") == 0 ||
+        strcmp(prop_sku_buf, "GFQM1") == 0) {
+        strncpy(sku_name, "MMW", MAX_SKU_NAME_LEN);
+    } else if (strcmp(prop_sku_buf, "GR1YH") == 0 ||
+               strcmp(prop_sku_buf, "GF5KQ") == 0 ||
+               strcmp(prop_sku_buf, "GPQ72") == 0) {
+        strncpy(sku_name, "JPN", MAX_SKU_NAME_LEN);
+    } else if (strcmp(prop_sku_buf, "GB7N6") == 0 ||
+               strcmp(prop_sku_buf, "GLU0G") == 0 ||
+               strcmp(prop_sku_buf, "GNA8F") == 0) {
+        strncpy(sku_name, "ROW", MAX_SKU_NAME_LEN);
+    } else {
+        strncpy(sku_name, "NA", MAX_SKU_NAME_LEN);
+    }
+
+    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 {