wlan: Get the supported features by driver/firmware

Get the supported features by driver/firmware using vendor
commands. Middleware can query for the feature capability and
respond to the upper layers based on the result.

Change-Id: Ib78a91a66c1abc3c49f5879edd8331dc0b9485a0
CRs-Fixed: 718716
diff --git a/CORE/HDD/inc/wlan_hdd_cfg80211.h b/CORE/HDD/inc/wlan_hdd_cfg80211.h
index a0c9486..f8287cc 100644
--- a/CORE/HDD/inc/wlan_hdd_cfg80211.h
+++ b/CORE/HDD/inc/wlan_hdd_cfg80211.h
@@ -149,11 +149,13 @@
     QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SIGNIFICANT_CHANGE = 31,
     QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SIGNIFICANT_CHANGE = 32,
     QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SIGNIFICANT_CHANGE = 33,
-    /*EXT TDLS*/
+    /* EXT TDLS */
     QCA_NL80211_VENDOR_SUBCMD_TDLS_ENABLE = 34,
     QCA_NL80211_VENDOR_SUBCMD_TDLS_DISABLE = 35,
     QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_STATUS = 36,
     QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE = 37,
+    /* Get supported features */
+    QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_FEATURES = 38,
     QCA_NL80211_VENDOR_SUBCMD_MAC_OUI = 39
 };
 
@@ -789,6 +791,39 @@
         QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI_AFTER_LAST - 1,
 };
 
+enum qca_wlan_vendor_attr_get_supported_features {
+    QCA_WLAN_VENDOR_ATTR_FEATURE_SET_INVALID = 0,
+    /* Unsigned 32-bit value */
+    QCA_WLAN_VENDOR_ATTR_FEATURE_SET = 1,
+    /* keep last */
+    QCA_WLAN_VENDOR_ATTR_FEATURE_SET_AFTER_LAST,
+    QCA_WLAN_VENDOR_ATTR_FEATURE_SET_MAX =
+        QCA_WLAN_VENDOR_ATTR_FEATURE_SET_AFTER_LAST - 1,
+};
+
+/* Feature defines */
+#define WIFI_FEATURE_INFRA              0x0001   /* Basic infrastructure mode */
+#define WIFI_FEATURE_INFRA_5G           0x0002   /* Support for 5 GHz Band */
+#define WIFI_FEATURE_HOTSPOT            0x0004   /* Support for GAS/ANQP */
+#define WIFI_FEATURE_P2P                0x0008   /* Wifi-Direct */
+#define WIFI_FEATURE_SOFT_AP            0x0010   /* Soft AP */
+#define WIFI_FEATURE_EXTSCAN            0x0020   /* Extended Scan APIs */
+#define WIFI_FEATURE_NAN                0x0040   /* Neighbor Awareness
+                                                    Networking */
+#define WIFI_FEATURE_D2D_RTT            0x0080   /* Device-to-device RTT */
+#define WIFI_FEATURE_D2AP_RTT           0x0100   /* Device-to-AP RTT */
+#define WIFI_FEATURE_BATCH_SCAN         0x0200   /* Batched Scan (legacy) */
+#define WIFI_FEATURE_PNO                0x0400   /* Preferred network offload */
+#define WIFI_FEATURE_ADDITIONAL_STA     0x0800   /* Support for two STAs */
+#define WIFI_FEATURE_TDLS               0x1000   /* Tunnel directed link
+                                                    setup */
+#define WIFI_FEATURE_TDLS_OFFCHANNEL    0x2000   /* Support for TDLS off
+                                                    channel */
+#define WIFI_FEATURE_EPR                0x4000   /* Enhanced power reporting */
+#define WIFI_FEATURE_AP_STA             0x8000   /* Support for AP STA
+                                                    Concurrency */
+/* Add more features here */
+
 /* Vendor id to be used in vendor specific command and events
  * to user space. Use QCA OUI 00:13:74 to match with define in
  * supplicant code.
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index 6c31f3e..5e3be45 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -566,6 +566,9 @@
 };
 
 extern struct net_device_ops net_ops_struct;
+#ifdef FEATURE_WLAN_SCAN_PNO
+static eHalStatus wlan_hdd_is_pno_allowed(hdd_adapter_t *pAdapter);
+#endif
 
 #ifdef WLAN_NL80211_TESTMODE
 enum wlan_hdd_tm_attr
@@ -4295,6 +4298,116 @@
     return (wlan_hdd_tdls_extctrl_deconfig_peer(pAdapter, peer));
 }
 
+static int
+wlan_hdd_cfg80211_get_supported_features(struct wiphy *wiphy,
+                                         struct wireless_dev *wdev,
+                                         void *data, int data_len)
+{
+    struct net_device *dev                     = wdev->netdev;
+    hdd_adapter_t *pAdapter                    = WLAN_HDD_GET_PRIV_PTR(dev);
+    hdd_context_t *pHddCtx      = wiphy_priv(wiphy);
+    struct sk_buff *skb         = NULL;
+    tANI_U32       fset         = 0;
+
+    if (wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION)) {
+        hddLog(LOG1, FL("Infra Station mode is supported by driver"));
+        fset |= WIFI_FEATURE_INFRA;
+    }
+
+    if (TRUE == hdd_is_5g_supported(pHddCtx)) {
+        hddLog(LOG1, FL("INFRA_5G is supported by firmware"));
+        fset |= WIFI_FEATURE_INFRA_5G;
+    }
+
+#ifdef WLAN_FEATURE_P2P
+    if ((wiphy->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)) &&
+        (wiphy->interface_modes & BIT(NL80211_IFTYPE_P2P_GO))) {
+        hddLog(LOG1, FL("WiFi-Direct is supported by driver"));
+        fset |= WIFI_FEATURE_P2P;
+    }
+#endif
+
+    /* Soft-AP is supported currently by default */
+    fset |= WIFI_FEATURE_SOFT_AP;
+
+#ifdef WLAN_FEATURE_EXTSCAN
+    if ((TRUE == pHddCtx->cfg_ini->fEnableEXTScan) &&
+            sme_IsFeatureSupportedByFW(EXTENDED_SCAN)) {
+        hddLog(LOG1, FL("EXTScan is supported by firmware"));
+        fset |= WIFI_FEATURE_EXTSCAN;
+    }
+#endif
+
+#ifdef WLAN_FEATURE_NAN
+    if (sme_IsFeatureSupportedByFW(NAN)) {
+        hddLog(LOG1, FL("NAN is supported by firmware"));
+        fset |= WIFI_FEATURE_NAN;
+    }
+#endif
+
+    /* D2D RTT is not supported currently by default */
+    if (sme_IsFeatureSupportedByFW(RTT)) {
+        hddLog(LOG1, FL("RTT is supported by firmware"));
+        fset |= WIFI_FEATURE_D2AP_RTT;
+    }
+
+#ifdef FEATURE_WLAN_BATCH_SCAN
+    if (fset & WIFI_FEATURE_EXTSCAN) {
+        hddLog(LOG1, FL("Batch scan is supported as extscan is supported"));
+        fset &= ~WIFI_FEATURE_BATCH_SCAN;
+    } else if (sme_IsFeatureSupportedByFW(BATCH_SCAN)) {
+        hddLog(LOG1, FL("Batch scan is supported by firmware"));
+        fset |= WIFI_FEATURE_BATCH_SCAN;
+    }
+#endif
+
+#ifdef FEATURE_WLAN_SCAN_PNO
+    if (pHddCtx->cfg_ini->configPNOScanSupport &&
+        (eHAL_STATUS_SUCCESS == wlan_hdd_is_pno_allowed(pAdapter))) {
+        hddLog(LOG1, FL("PNO is supported by firmware"));
+        fset |= WIFI_FEATURE_PNO;
+    }
+#endif
+
+    /* STA+STA is supported currently by default */
+    fset |= WIFI_FEATURE_ADDITIONAL_STA;
+
+#ifdef FEATURE_WLAN_TDLS
+    if ((TRUE == pHddCtx->cfg_ini->fEnableTDLSSupport) &&
+        sme_IsFeatureSupportedByFW(TDLS)) {
+        hddLog(LOG1, FL("TDLS is supported by firmware"));
+        fset |= WIFI_FEATURE_TDLS;
+    }
+
+    /* TDLS_OFFCHANNEL is not supported currently by default */
+#endif
+
+#ifdef WLAN_AP_STA_CONCURRENCY
+    /* AP+STA concurrency is supported currently by default */
+    fset |= WIFI_FEATURE_AP_STA;
+#endif
+
+    skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(fset) +
+                                              NLMSG_HDRLEN);
+
+    if (!skb) {
+        hddLog(LOGE, FL("cfg80211_vendor_cmd_alloc_reply_skb failed"));
+        return -EINVAL;
+    }
+    hddLog(LOG1, FL("Supported Features : 0x%x"), fset);
+
+    if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_FEATURE_SET, fset)) {
+        hddLog(LOGE, FL("nla put fail"));
+        goto nla_put_failure;
+    }
+
+    return cfg80211_vendor_cmd_reply(skb);
+
+nla_put_failure:
+    kfree_skb(skb);
+    return -EINVAL;
+}
+
 
 const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] =
 {
@@ -4423,6 +4536,13 @@
                  WIPHY_VENDOR_CMD_NEED_NETDEV,
         .doit = wlan_hdd_cfg80211_exttdls_get_status
     },
+    {
+        .info.vendor_id = QCA_NL80211_VENDOR_ID,
+        .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_FEATURES,
+        .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+                 WIPHY_VENDOR_CMD_NEED_NETDEV,
+        .doit = wlan_hdd_cfg80211_get_supported_features
+    },
 
     {
         .info.vendor_id = QCA_NL80211_VENDOR_ID,
diff --git a/CORE/MAC/src/include/sirParams.h b/CORE/MAC/src/include/sirParams.h
index 7ccab86..872a919 100644
--- a/CORE/MAC/src/include/sirParams.h
+++ b/CORE/MAC/src/include/sirParams.h
@@ -83,6 +83,7 @@
    TDLS = 6,
    P2P_GO_NOA_DECOUPLE_INIT_SCAN = 7,
    WLANACTIVE_OFFLOAD = 8,
+   RTT = 20,
    WOW = 22,
 #ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD
    WLAN_ROAM_SCAN_OFFLOAD = 23,
@@ -103,6 +104,9 @@
    UPDATE_CHANNEL_LIST    = 35,
    WLAN_MCADDR_FLT        = 36,
    WLAN_CH144             = 37,
+#ifdef WLAN_FEATURE_NAN
+   NAN = 38,
+#endif
 #ifdef FEATURE_WLAN_TDLS
    TDLS_SCAN_COEXISTENCE  = 39,
 #endif