wlan: Implement Private NL CMD handling for roaming

When supplicant issue enabled / disable firmware based
roaming on the basis of the Bssid modification in network
block for an (e.g. AutoJoin modify Network Block N/W),
That time middle-ware will issue this pvt cmd to Driver.
Driver need to disable / enable firmware roaming.
(in our current design we can enable firmware roaming
by offload scan to firmware so firmware can scan and
find candidate ap when rssi threshold meet the criteria,
same way driver can stop firmware roaming by stop offload
scan to firmware).

Change-Id: I00334b2190d20397518946018c4e5f3f644f3754
CRs-Fixed: 737976
diff --git a/CORE/HDD/inc/wlan_hdd_cfg80211.h b/CORE/HDD/inc/wlan_hdd_cfg80211.h
index cfef68f..1728ff0 100644
--- a/CORE/HDD/inc/wlan_hdd_cfg80211.h
+++ b/CORE/HDD/inc/wlan_hdd_cfg80211.h
@@ -116,7 +116,10 @@
 enum qca_nl80211_vendor_subcmds {
     QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
     QCA_NL80211_VENDOR_SUBCMD_TEST = 1,
-    /* subcmds 2..9 not yet allocated */
+
+    /* subcmds 2..8 not yet allocated */
+    QCA_NL80211_VENDOR_SUBCMD_ROAMING = 9,
+
     QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY = 10,
     QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY =  11,
     QCA_NL80211_VENDOR_SUBCMD_NAN =  12,
@@ -192,17 +195,23 @@
 enum qca_wlan_vendor_attr
 {
     QCA_WLAN_VENDOR_ATTR_INVALID = 0,
-    /* used by QCOM_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY */
+    /* used by QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY */
     QCA_WLAN_VENDOR_ATTR_DFS     = 1,
-    /* used by QCOM_NL80211_VENDOR_SUBCMD_NAN */
+    /* used by QCA_NL80211_VENDOR_SUBCMD_NAN */
     QCA_WLAN_VENDOR_ATTR_NAN     = 2,
-
+    /* used by QCA_NL80211_VENDOR_SUBCMD_STATS_EXT */
+    QCA_WLAN_VENDOR_ATTR_STATS_EXT     = 3,
+    /* used by QCA_NL80211_VENDOR_SUBCMD_STATS_EXT */
+    QCA_WLAN_VENDOR_ATTR_IFINDEX     = 4,
+    /* used by QCA_NL80211_VENDOR_SUBCMD_ROAMING, u32 with values defined
+     * by enum qca_roaming_policy. */
+    QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY = 5,
+    QCA_WLAN_VENDOR_ATTR_MAC_ADDR = 6,
     /* keep last */
     QCA_WLAN_VENDOR_ATTR_AFTER_LAST,
-    QCA_WLAN_VENDOR_ATTR_MAX       = QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1,
+    QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1,
 };
 
-
 /*EXT TDLS*/
 enum qca_wlan_vendor_attr_tdls_enable
 {
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index bad6ebe..8d28350 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -4503,8 +4503,75 @@
     return 0;
 }
 
+const struct
+nla_policy qca_wlan_vendor_attr[QCA_WLAN_VENDOR_ATTR_MAX+1] =
+{
+    [QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY] = { .type = NLA_U32 },
+    [QCA_WLAN_VENDOR_ATTR_MAC_ADDR]       = { .type = NLA_UNSPEC },
+};
+
+static int wlan_hdd_cfg80211_firmware_roaming(struct wiphy *wiphy,
+            struct wireless_dev *wdev, void *data, int data_len)
+{
+
+    u8 bssid[6]                                 = {0};
+    hdd_context_t *pHddCtx                      = wiphy_priv(wiphy);
+    struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX + 1];
+    eHalStatus status = eHAL_STATUS_SUCCESS;
+    v_U32_t isFwrRoamEnabled = FALSE;
+    int ret;
+
+    if (NULL == pHddCtx) {
+        hddLog(VOS_TRACE_LEVEL_ERROR,
+               FL("HDD context is not valid"));
+        return -EINVAL;
+    }
+
+    ret = nla_parse(tb, QCA_WLAN_VENDOR_ATTR_MAX,
+                    data, data_len,
+                    qca_wlan_vendor_attr);
+    if (ret){
+        hddLog(VOS_TRACE_LEVEL_ERROR, FL("Invalid ATTR"));
+        return -EINVAL;
+    }
+
+    /* Parse and fetch Enable flag */
+    if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY]) {
+        hddLog(VOS_TRACE_LEVEL_ERROR, FL("attr enable failed"));
+        return -EINVAL;
+    }
+
+    isFwrRoamEnabled = nla_get_u32(
+         tb[QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY]);
+
+    hddLog(VOS_TRACE_LEVEL_INFO, FL("isFwrRoamEnabled (%d)"), isFwrRoamEnabled);
+
+    /* Parse and fetch bssid */
+    if (!tb[QCA_WLAN_VENDOR_ATTR_MAC_ADDR]) {
+        hddLog(VOS_TRACE_LEVEL_ERROR, FL("attr bss id failed"));
+        return -EINVAL;
+    }
+
+    memcpy(bssid, nla_data(
+                tb[QCA_WLAN_VENDOR_ATTR_MAC_ADDR]),
+                sizeof(bssid));
+    hddLog(VOS_TRACE_LEVEL_INFO, FL(MAC_ADDRESS_STR),MAC_ADDR_ARRAY(bssid));
+
+    //Update roaming
+    status = sme_ConfigFwrRoaming((tHalHandle)(pHddCtx->hHal), isFwrRoamEnabled);
+    return status;
+}
+
 const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] =
 {
+    {
+        .info.vendor_id = QCA_NL80211_VENDOR_ID,
+        .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_ROAMING,
+        .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+                 WIPHY_VENDOR_CMD_NEED_NETDEV |
+                 WIPHY_VENDOR_CMD_NEED_RUNNING,
+        .doit = wlan_hdd_cfg80211_firmware_roaming
+    },
 #ifdef WLAN_FEATURE_LINK_LAYER_STATS
     {
         .info.vendor_id = QCA_NL80211_VENDOR_ID,
diff --git a/CORE/SME/inc/sme_Api.h b/CORE/SME/inc/sme_Api.h
index 5fda00e..60edfd0 100644
--- a/CORE/SME/inc/sme_Api.h
+++ b/CORE/SME/inc/sme_Api.h
@@ -2785,6 +2785,21 @@
         const v_BOOL_t isFastRoamIniFeatureEnabled);
 
 /*--------------------------------------------------------------------------
+  \brief sme_ConfigFwrRoaming() - enable/disable LFR support at runtime
+  When Supplicant issue enabled / disable fwr based roaming on the basis
+  of the Bssid modification in network block ( e.g. AutoJoin mody N/W block)
+
+  This is a synchronous call
+  \param hHal - The handle returned by macOpen.
+  \return eHAL_STATUS_SUCCESS - SME (enabled/disabled) offload scan successfully.
+          Other status means SME is failed to (enabled/disabled) offload scan.
+  \sa
+  --------------------------------------------------------------------------*/
+
+eHalStatus sme_ConfigFwrRoaming(tHalHandle hHal,
+        const v_BOOL_t isFastRoamEnabled);
+
+/*--------------------------------------------------------------------------
   \brief sme_UpdateIsMAWCIniFeatureEnabled() -
   Enable/disable LFR MAWC support at runtime
   It is used at in the REG_DYNAMIC_VARIABLE macro definition of
diff --git a/CORE/SME/src/sme_common/sme_Api.c b/CORE/SME/src/sme_common/sme_Api.c
index c9bf231..de1e309 100644
--- a/CORE/SME/src/sme_common/sme_Api.c
+++ b/CORE/SME/src/sme_common/sme_Api.c
@@ -9039,6 +9039,32 @@
 }
 
 /*--------------------------------------------------------------------------
+  \brief sme_ConfigFwrRoaming() - enable/disable LFR support at runtime
+  When Supplicant issue enabled / disable fwr based roaming on the basis
+  of the Bssid modification in network block ( e.g. AutoJoin mody N/W block)
+
+  This is a synchronous call
+  \param hHal - The handle returned by macOpen.
+  \return eHAL_STATUS_SUCCESS - SME (enabled/disabled) offload scan successfully.
+          Other status means SME is failed to (enabled/disabled) offload scan.
+  \sa
+  --------------------------------------------------------------------------*/
+
+eHalStatus sme_ConfigFwrRoaming(tHalHandle hHal,
+        const v_BOOL_t isFastRoamEnabled)
+{
+  tpAniSirGlobal pMac = PMAC_STRUCT( hHal );
+  if (!pMac->roam.configParam.isFastRoamIniFeatureEnabled)
+  {
+      VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO,
+                 "%s: FastRoam is disabled through ini", __func__);
+      return  eHAL_STATUS_FAILURE;
+  }
+  csrNeighborRoamUpdateFastRoamingEnabled(pMac, isFastRoamEnabled);
+  return eHAL_STATUS_SUCCESS;
+}
+
+/*--------------------------------------------------------------------------
   \brief sme_UpdateIsMAWCIniFeatureEnabled() -
   Enable/disable LFR MAWC support at runtime
   It is used at in the REG_DYNAMIC_VARIABLE macro definition of