WiFi-HAL: Add user hint sub-type to set country code commmand

Add new user hint sub-type NL80211_USER_REG_HINT_CELL_BASE to
wifi_set_country_code command if the feature is supported by
host driver.

Bug: 121154896
Test: Regression test

Change-Id: Ie1c0da1cc75aba02809ffd0f5d76bdb4f2ec680c
CRs-fixed: 2205885
diff --git a/qcwcn/wifi_hal/common.h b/qcwcn/wifi_hal/common.h
index 5604669..3ea962d 100644
--- a/qcwcn/wifi_hal/common.h
+++ b/qcwcn/wifi_hal/common.h
@@ -89,6 +89,11 @@
     wifi_roaming_capabilities roaming_capa;
 } wifi_capa;
 
+typedef struct {
+    u8 *flags;
+    size_t flags_len;
+} features_info;
+
 struct gscan_event_handlers_s;
 struct rssi_monitor_event_handler_s;
 struct cld80211_ctx;
@@ -115,6 +120,9 @@
     int num_interfaces;                             // number of interfaces
 
     feature_set supported_feature_set;
+    /* driver supported features defined by enum qca_wlan_vendor_features that
+       can be queried by vendor command QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES */
+    features_info driver_supported_features;
     u32 supported_logger_feature_set;
     // add other details
     int user_sock_arg;
diff --git a/qcwcn/wifi_hal/ifaceeventhandler.cpp b/qcwcn/wifi_hal/ifaceeventhandler.cpp
index b0133c0..8750999 100644
--- a/qcwcn/wifi_hal/ifaceeventhandler.cpp
+++ b/qcwcn/wifi_hal/ifaceeventhandler.cpp
@@ -205,11 +205,16 @@
     mCapa = &(info->capa);
     mfilter_packet_read_buffer = NULL;
     mfilter_packet_length = 0;
+    memset(&mDriverFeatures, 0, sizeof(mDriverFeatures));
 }
 
 WifihalGeneric::~WifihalGeneric()
 {
     mCapa = NULL;
+    if (mDriverFeatures.flags != NULL) {
+        free(mDriverFeatures.flags);
+        mDriverFeatures.flags = NULL;
+    }
 }
 
 wifi_error WifihalGeneric::requestResponse()
@@ -243,6 +248,23 @@
 
                 break;
             }
+        case QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES:
+            {
+                struct nlattr *attr;
+                struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1];
+                nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX,
+                          (struct nlattr *)mVendorData, mDataLen, NULL);
+                attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS];
+                if (attr) {
+                    int len = nla_len(attr);
+                    mDriverFeatures.flags = (u8 *)malloc(len);
+                    if (mDriverFeatures.flags != NULL) {
+                        memcpy(mDriverFeatures.flags, nla_data(attr), len);
+                        mDriverFeatures.flags_len = len;
+                    }
+                 }
+                 break;
+            }
         case QCA_NL80211_VENDOR_SUBCMD_GET_CONCURRENCY_MATRIX:
             {
                 struct nlattr *tb_vendor[
@@ -543,6 +565,25 @@
     *pset = mSet;
 }
 
+void WifihalGeneric::getDriverFeatures(features_info *pfeatures)
+{
+    if (!pfeatures)
+        return;
+
+    if (mDriverFeatures.flags != NULL) {
+        pfeatures->flags = (u8 *)malloc(mDriverFeatures.flags_len);
+        if (pfeatures->flags) {
+            memcpy(pfeatures->flags, mDriverFeatures.flags,
+                   mDriverFeatures.flags_len);
+            pfeatures->flags_len = mDriverFeatures.flags_len;
+            return;
+        }
+    }
+
+    pfeatures->flags_len = 0;
+    pfeatures->flags = NULL;
+}
+
 void WifihalGeneric::setMaxSetSize(int set_size_max) {
     mSetSizeMax = set_size_max;
 }
diff --git a/qcwcn/wifi_hal/ifaceeventhandler.h b/qcwcn/wifi_hal/ifaceeventhandler.h
index cdbd59d..c993a7e 100644
--- a/qcwcn/wifi_hal/ifaceeventhandler.h
+++ b/qcwcn/wifi_hal/ifaceeventhandler.h
@@ -83,6 +83,7 @@
 {
 private:
     feature_set mSet;
+    features_info mDriverFeatures;
     int mSetSizeMax;
     int *mSetSizePtr;
     feature_set *mConcurrencySet;
@@ -101,6 +102,7 @@
     virtual wifi_error requestResponse();
     virtual int handleResponse(WifiEvent &reply);
     virtual void getResponseparams(feature_set *pset);
+    virtual void getDriverFeatures(features_info *pfeatures);
     virtual void setMaxSetSize(int set_size_max);
     virtual void setSizePtr(int *set_size);
     virtual void setPacketBufferParams(u8 *host_packet_buffer, int packet_length);
diff --git a/qcwcn/wifi_hal/qca-vendor_copy.h b/qcwcn/wifi_hal/qca-vendor_copy.h
index 6d2f0c7..3f5163f 100644
--- a/qcwcn/wifi_hal/qca-vendor_copy.h
+++ b/qcwcn/wifi_hal/qca-vendor_copy.h
@@ -944,6 +944,10 @@
 	QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY     = 1,
 	QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS = 2,
 	QCA_WLAN_VENDOR_FEATURE_P2P_LISTEN_OFFLOAD	= 3,
+	QCA_WLAN_VENDOR_FEATURE_OCE_STA                 = 4,
+	QCA_WLAN_VENDOR_FEATURE_OCE_AP                  = 5,
+	QCA_WLAN_VENDOR_FEATURE_OCE_STA_CFON            = 6,
+	QCA_WLAN_VENDOR_FEATURE_SELF_MANAGED_REGULATORY = 7,
 	NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
 };
 
diff --git a/qcwcn/wifi_hal/wifi_hal.cpp b/qcwcn/wifi_hal/wifi_hal.cpp
index 315c814..8e8367c 100644
--- a/qcwcn/wifi_hal/wifi_hal.cpp
+++ b/qcwcn/wifi_hal/wifi_hal.cpp
@@ -195,6 +195,38 @@
     return ret;
 }
 
+static wifi_error acquire_driver_supported_features(wifi_interface_handle iface,
+                                          features_info *driver_features)
+{
+    wifi_error ret;
+    interface_info *iinfo = getIfaceInfo(iface);
+    wifi_handle handle = getWifiHandle(iface);
+
+    WifihalGeneric driverFeatures(handle, 0,
+            OUI_QCA,
+            QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES);
+
+    /* create the message */
+    ret = driverFeatures.create();
+    if (ret != WIFI_SUCCESS)
+        goto cleanup;
+
+    ret = driverFeatures.set_iface_id(iinfo->name);
+    if (ret != WIFI_SUCCESS)
+        goto cleanup;
+
+    ret = driverFeatures.requestResponse();
+    if (ret != WIFI_SUCCESS) {
+        ALOGE("%s: requestResponse Error:%d",__func__, ret);
+        goto cleanup;
+    }
+
+    driverFeatures.getDriverFeatures(driver_features);
+
+cleanup:
+    return mapKernelErrortoWifiHalError(ret);
+}
+
 static wifi_error wifi_get_capabilities(wifi_interface_handle handle)
 {
     wifi_error ret;
@@ -626,6 +658,13 @@
         ret = WIFI_SUCCESS;
     }
 
+    ret = acquire_driver_supported_features(iface_handle,
+                                  &info->driver_supported_features);
+    if (ret != WIFI_SUCCESS) {
+        ALOGI("Failed to get vendor feature set : %d", ret);
+        ret = WIFI_SUCCESS;
+    }
+
     ret =  wifi_get_logger_supported_feature_set(iface_handle,
                          &info->supported_logger_feature_set);
     if (ret != WIFI_SUCCESS)
@@ -715,6 +754,10 @@
             cleanupGscanHandlers(info);
             cleanupRSSIMonitorHandler(info);
             free(info->event_cb);
+            if (info->driver_supported_features.flags) {
+                free(info->driver_supported_features.flags);
+                info->driver_supported_features.flags = NULL;
+            }
             free(info);
         }
     }
@@ -812,6 +855,11 @@
         info->pkt_fate_stats = NULL;
     }
 
+    if (info->driver_supported_features.flags) {
+        free(info->driver_supported_features.flags);
+        info->driver_supported_features.flags = NULL;
+    }
+
     (*cleaned_up_handler)(handle);
     pthread_mutex_destroy(&info->cb_lock);
     pthread_mutex_destroy(&info->pkt_fate_stats_lock);
diff --git a/qcwcn/wifi_hal/wificonfig.cpp b/qcwcn/wifi_hal/wificonfig.cpp
index 40d765f..2c2d1cd 100644
--- a/qcwcn/wifi_hal/wificonfig.cpp
+++ b/qcwcn/wifi_hal/wificonfig.cpp
@@ -105,6 +105,14 @@
     return ret;
 }
 
+int check_feature(enum qca_wlan_vendor_features feature, features_info *info)
+{
+    size_t idx = feature / 8;
+
+    return (idx < info->flags_len) &&
+            (info->flags[idx] & BIT(feature % 8));
+}
+
 /* Set the country code to driver. */
 wifi_error wifi_set_country_code(wifi_interface_handle iface,
                                  const char* country_code)
@@ -113,6 +121,7 @@
     wifi_error ret;
     WiFiConfigCommand *wifiConfigCommand;
     wifi_handle wifiHandle = getWifiHandle(iface);
+    hal_info *info = getHalInfo(wifiHandle);
 
     ALOGV("%s: %s", __FUNCTION__, country_code);
 
@@ -144,6 +153,18 @@
         goto cleanup;
     }
 
+    if (check_feature(QCA_WLAN_VENDOR_FEATURE_SELF_MANAGED_REGULATORY,
+                      &info->driver_supported_features)) {
+        ret = wifiConfigCommand->put_u32(NL80211_ATTR_USER_REG_HINT_TYPE,
+                                         NL80211_USER_REG_HINT_CELL_BASE);
+        if (ret != WIFI_SUCCESS) {
+            ALOGE("wifi_set_country_code: put reg hint type failed. Error:%d",
+                  ret);
+            goto cleanup;
+        }
+    }
+
+
     /* Send the NL msg. */
     wifiConfigCommand->waitForRsp(false);
     ret = wifiConfigCommand->requestEvent();