Merge "Merge Android 13 QPR1"
diff --git a/bcmdhd/wifi_hal/common.h b/bcmdhd/wifi_hal/common.h
index e9df748..f1a541f 100755
--- a/bcmdhd/wifi_hal/common.h
+++ b/bcmdhd/wifi_hal/common.h
@@ -233,6 +233,7 @@
     WIFI_SUBCMD_USABLE_CHANNEL = ANDROID_NL80211_SUBCMD_USABLE_CHANNEL_START,
     WIFI_SUBCMD_TRIGGER_SSR = ANDROID_NL80211_SUBCMD_INIT_DEINIT_RANGE_START,
     WIFI_SUBCMD_GET_RADIO_COMBO_MATRIX,
+    WIFI_SUBCMD_ENABLE_TX_POWER_LIMIT,
 } WIFI_SUB_COMMAND;
 
 typedef enum {
diff --git a/bcmdhd/wifi_hal/link_layer_stats.cpp b/bcmdhd/wifi_hal/link_layer_stats.cpp
index 850b8fd..04b89b5 100644
--- a/bcmdhd/wifi_hal/link_layer_stats.cpp
+++ b/bcmdhd/wifi_hal/link_layer_stats.cpp
@@ -79,7 +79,7 @@
     { }
 
     virtual int create() {
-        // ALOGI("Creating message to get link statistics; iface = %d", mIfaceInfo->id);
+        ALOGI("Creating message to get link statistics; iface = %d", mIfaceInfo->id);
 
         int ret = mMsg.create(GOOGLE_OUI, LSTATS_SUBCMD_GET_INFO);
         if (ret < 0) {
@@ -99,7 +99,7 @@
         uint32_t total_size = 0, per_radio_size = 0, data_len = 0, rem_len = 0;
         int num_radios = 0, id = 0, subcmd = 0, len = 0;
 
-        // ALOGI("In GetLinkStatsCommand::handleResponse");
+        ALOGI("In GetLinkStatsCommand::handleResponse");
 
         if (reply.get_cmd() != NL80211_CMD_VENDOR) {
             ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
@@ -126,6 +126,7 @@
             } else {
                 ALOGW("Ignoring invalid attribute type = %d, size = %d\n",
                 it.get_type(), it.get_len());
+                return NL_SKIP;
             }
         }
 
@@ -176,32 +177,6 @@
             }
             (*mHandler.on_link_stats_results)(id, (wifi_iface_stat *)iface_stat,
             num_radios, (wifi_radio_stat *)radioStatsBuf);
-        } else {
-            /* To be deprecated, adding it to keep it backward compatible */
-            ALOGD("GetLinkStatCommand: zero radio case\n");
-            data = reply.get_vendor_data();
-            if (!data) {
-                ALOGE("Invalid vendor data received\n");
-                return NL_SKIP;
-            }
-
-            num_radios = 1;
-            data = reply.get_vendor_data();
-            len = reply.get_vendor_data_len();
-            if (!data || !len) {
-                ALOGE("Invalid vendor data received\n");
-                return NL_SKIP;
-            }
-            radio_stat_ptr =
-                convertToExternalRadioStatStructureLegacy((wifi_radio_stat_internal *)data);
-            if (!radio_stat_ptr) {
-                ALOGE("Invalid stats pointer received\n");
-                return NL_SKIP;
-            }
-            wifi_iface_stat *iface_stat =
-                (wifi_iface_stat *)((char *)&((wifi_radio_stat_internal *)data)->channels
-                    + radio_stat_ptr->num_channels * sizeof(wifi_channel_stat));
-            (*mHandler.on_link_stats_results)(id, iface_stat, num_radios, radio_stat_ptr);
         }
 exit:
         if (radio_stat_ptr) {
@@ -247,37 +222,6 @@
         }
         return external_stat_ptr;
     }
-
-    wifi_radio_stat *convertToExternalRadioStatStructureLegacy(wifi_radio_stat_internal *internal_stat_ptr) {
-        wifi_radio_stat *external_stat_ptr = NULL;
-        if (!internal_stat_ptr) {
-            ALOGE("Sta_ptr is null\n");
-        } else {
-            uint32_t channel_size = internal_stat_ptr->num_channels * sizeof(wifi_channel_stat);
-            uint32_t total_size = sizeof(wifi_radio_stat) + channel_size;
-            external_stat_ptr = (wifi_radio_stat *)malloc(total_size);
-            if (external_stat_ptr) {
-                external_stat_ptr->radio = internal_stat_ptr->radio;
-                external_stat_ptr->on_time = internal_stat_ptr->on_time;
-                external_stat_ptr->tx_time = internal_stat_ptr->tx_time;
-                external_stat_ptr->rx_time = internal_stat_ptr->rx_time;
-                external_stat_ptr->tx_time_per_levels = NULL;
-                external_stat_ptr->num_tx_levels = 0;
-                external_stat_ptr->on_time_scan = internal_stat_ptr->on_time_scan;
-                external_stat_ptr->on_time_nbd = internal_stat_ptr->on_time_nbd;
-                external_stat_ptr->on_time_gscan = internal_stat_ptr->on_time_gscan;
-                external_stat_ptr->on_time_roam_scan = internal_stat_ptr->on_time_roam_scan;
-                external_stat_ptr->on_time_pno_scan = internal_stat_ptr->on_time_pno_scan;
-                external_stat_ptr->on_time_hs20 = internal_stat_ptr->on_time_hs20;
-                external_stat_ptr->num_channels = internal_stat_ptr->num_channels;
-                if (internal_stat_ptr->num_channels) {
-                    memcpy(&(external_stat_ptr->channels), &(internal_stat_ptr->channels),
-                        channel_size);
-                }
-            }
-        }
-        return external_stat_ptr;
-    }
 };
 
 wifi_error wifi_get_link_stats(wifi_request_id id,
diff --git a/bcmdhd/wifi_hal/nan.cpp b/bcmdhd/wifi_hal/nan.cpp
index e74d9a1..b83f10a 100755
--- a/bcmdhd/wifi_hal/nan.cpp
+++ b/bcmdhd/wifi_hal/nan.cpp
@@ -4413,7 +4413,8 @@
         ALOGE("Disable NAN MAC transId= %d\n", id);
         mac_prim->setId(id);
     } else {
-        ALOGE("Invalid transId= %d cur= %d\n", id, mac_prim->getId());
+        ALOGE("Invalid transId= %d cur= %d\n", id,
+              mac_prim ? mac_prim->getId() : -1);
     }
 
     cmd->setChreNan(0);
diff --git a/bcmdhd/wifi_hal/wifi_hal.cpp b/bcmdhd/wifi_hal/wifi_hal.cpp
index e250b6d..e6a14e7 100755
--- a/bcmdhd/wifi_hal/wifi_hal.cpp
+++ b/bcmdhd/wifi_hal/wifi_hal.cpp
@@ -98,6 +98,9 @@
 		u32 max_size, u32* size, wifi_radio_combination_matrix *radio_combination_matrix);
 
 static void wifi_cleanup_dynamic_ifaces(wifi_handle handle);
+static wifi_error wifi_enable_tx_power_limits(wifi_interface_handle iface,
+        bool isEnable);
+
 typedef enum wifi_attr {
     ANDR_WIFI_ATTRIBUTE_INVALID                    = 0,
     ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET            = 1,
@@ -196,6 +199,13 @@
     SET_USE_CASE
 };
 
+enum wifi_tx_power_limits {
+    TX_POWER_CAP_ATTRIBUTE_INVALID    = 0,
+    TX_POWER_CAP_ENABLE_ATTRIBUTE     = 1,
+    /* Add more attributes here */
+    TX_POWER_ATTRIBUTE_MAX
+};
+
 /* Initialize/Cleanup */
 
 void wifi_socket_set_local_port(struct nl_sock *sock, uint32_t port)
@@ -344,6 +354,7 @@
     fn->wifi_nan_rtt_chre_enable_request = nan_chre_enable_request;
     fn->wifi_nan_rtt_chre_disable_request = nan_chre_disable_request;
     fn->wifi_chre_register_handler = nan_chre_register_handler;
+    fn->wifi_enable_tx_power_limits = wifi_enable_tx_power_limits;
 
     return WIFI_SUCCESS;
 }
@@ -554,12 +565,13 @@
     // Function times out after 10 seconds
     int count = (POLL_DRIVER_MAX_TIME_MS * 1000) / POLL_DRIVER_DURATION_US;
     FILE *fd;
+    wifi_error status = WIFI_SUCCESS;
 
     do {
         if ((fd = fopen("/sys/class/net/wlan0", "r")) != NULL) {
             fclose(fd);
-            wifi_pre_initialize();
-            return WIFI_SUCCESS;
+            status = wifi_pre_initialize();
+            return status;
         }
         usleep(POLL_DRIVER_DURATION_US);
     } while(--count > 0);
@@ -644,10 +656,13 @@
     if (wlan0Handle != NULL) {
         ALOGE("Calling hal cleanup");
         if (!get_halutil_mode()) {
+            wifi_cleanup_dynamic_ifaces(handle);
+            ALOGI("Cleaned dynamic virtual ifaces\n");
             result = wifi_stop_hal(wlan0Handle);
             if (result != WIFI_SUCCESS) {
                 ALOGE("wifi_stop_hal failed");
             }
+            ALOGI("wifi_stop_hal success");
         }
 
     } else {
@@ -703,9 +718,6 @@
         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);
 
     info->clean_up = true;
@@ -2506,7 +2518,7 @@
     }
 
     int createIface() {
-        ALOGE("Creating virtual interface");
+        ALOGD("Creating virtual interface");
         WifiRequest request(familyId(), ifaceId());
         int result = createRequest(request, mIfname, mType, mwlan0_id);
         if (result != WIFI_SUCCESS) {
@@ -2519,7 +2531,7 @@
             ALOGE("failed to get the virtual iface create response; result = %d\n", result);
             return result;
         }
-        ALOGE("Created virtual interface");
+        ALOGD("Created virtual interface");
         return WIFI_SUCCESS;
     }
 
@@ -2537,6 +2549,7 @@
             ALOGE("failed to get response of delete virtual interface; result = %d\n", result);
             return result;
         }
+        ALOGD("Deleted virtual interface");
         return WIFI_SUCCESS;
     }
 protected:
@@ -2552,8 +2565,11 @@
 static void wifi_cleanup_dynamic_ifaces(wifi_handle handle)
 {
     int len = added_ifaces.size();
+    ALOGI("%s: virtual iface size %d\n", __FUNCTION__, len);
     while (len--) {
         wifi_virtual_interface_delete(handle, added_ifaces.front().c_str());
+        ALOGI("%s: deleted virtual iface %s\n",
+            __FUNCTION__, added_ifaces.front().c_str());
     }
     added_ifaces.clear();
 }
@@ -3001,3 +3017,42 @@
                                     filter_mask, max_size, size, channels);
     return (wifi_error)command.start();
 }
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+class EnableTxPowerLimit : public WifiCommand {
+private:
+    bool mEnableTxLimits;
+public:
+    EnableTxPowerLimit(wifi_interface_handle handle, bool enable_tx_pwr_limits)
+        : WifiCommand("EnableTxPowerLimit", handle, 0)
+    {
+        mEnableTxLimits = enable_tx_pwr_limits;
+    }
+
+    virtual int create() {
+        int ret;
+
+        ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_ENABLE_TX_POWER_LIMIT);
+        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_u8(TX_POWER_CAP_ENABLE_ATTRIBUTE, mEnableTxLimits);
+        if (ret < 0) {
+             ALOGE("Failed to put enable tx power limit param %d\n", mEnableTxLimits);
+             return ret;
+        }
+        mMsg.attr_end(data);
+        return WIFI_SUCCESS;
+    }
+};
+
+wifi_error wifi_enable_tx_power_limits(wifi_interface_handle handle, bool isEnable)
+{
+    ALOGD("Configuring the tx power limits , halHandle = %p\n", handle);
+
+    EnableTxPowerLimit command(handle, isEnable);
+    return (wifi_error) command.requestResponse();
+}