wlan: Force scc with ecsa channel switch once STA connect to new chan

Adds INI force_scc_with_ecsa and if force_scc_with_ecsa is set
use ECSA to force scc and change channel instead of SAP restart.

Change-Id: If8f47225ea729b7b2e1868fdd98d418af8ef16c9
CRs-Fixed: 2143138
diff --git a/CORE/HDD/inc/wlan_hdd_cfg.h b/CORE/HDD/inc/wlan_hdd_cfg.h
index a305ad7..30a8f4b 100644
--- a/CORE/HDD/inc/wlan_hdd_cfg.h
+++ b/CORE/HDD/inc/wlan_hdd_cfg.h
@@ -3108,6 +3108,16 @@
 #define CFG_TRIGGER_NULLFRAME_BEFORE_HB_MAX        (1)
 #define CFG_TRIGGER_NULLFRAME_BEFORE_HB_DEFAULT    (0)
 
+/*
+ * If enabled ecsa will be used to switch channel to force scc else SAP
+ * will be restarted.
+ */
+#define CFG_FORCE_SCC_WITH_ECSA_NAME       "force_scc_with_ecsa"
+#define CFG_FORCE_SCC_WITH_ECSA_MIN        (0)
+#define CFG_FORCE_SCC_WITH_ECSA_MAX        (1)
+#define CFG_FORCE_SCC_WITH_ECSA_DEFAULT    (0)
+
+
 /*--------------------------------------------------------------------------- 
   Type declarations
   -------------------------------------------------------------------------*/ 
@@ -3709,6 +3719,7 @@
    uint32_t                    max_sched_scan_plan_iterations;
    uint32_t                    sta_auth_retries_for_code17;
    uint32_t                    trigger_nullframe_before_hb;
+   bool                        force_scc_with_ecsa;
    uint8_t                     enable_rtt_support;
 } hdd_config_t;
 
diff --git a/CORE/HDD/src/wlan_hdd_assoc.c b/CORE/HDD/src/wlan_hdd_assoc.c
index 287b29c..6e15164 100644
--- a/CORE/HDD/src/wlan_hdd_assoc.c
+++ b/CORE/HDD/src/wlan_hdd_assoc.c
@@ -2659,10 +2659,19 @@
                 hddLog(VOS_TRACE_LEVEL_INFO,"Restart Sap as SAP channel is %d "
                        "and STA channel is %d", pHostapdAdapter->sessionCtx.ap.operatingChannel,
                        (int)pRoamInfo->pBssDesc->channelId);
-                hdd_hostapd_stop(pHostapdAdapter->dev);
-                if (pHddCtx->cfg_ini->enable_sap_auth_offload)
-                  hdd_force_scc_restart_sap(pHostapdAdapter,
-                      pHddCtx, (int)pRoamInfo->pBssDesc->channelId);
+                if (pHddCtx->cfg_ini->force_scc_with_ecsa)
+                {
+                    wlansap_set_channel_change(
+                       (WLAN_HDD_GET_CTX(pHostapdAdapter))->pvosContext,
+                        (int)pRoamInfo->pBssDesc->channelId, true);
+               }
+               else
+               {
+                    hdd_hostapd_stop(pHostapdAdapter->dev);
+                    if (pHddCtx->cfg_ini->enable_sap_auth_offload)
+                       hdd_force_scc_restart_sap(pHostapdAdapter,
+                             pHddCtx, (int)pRoamInfo->pBssDesc->channelId);
+                }
 
              }
         }
diff --git a/CORE/HDD/src/wlan_hdd_cfg.c b/CORE/HDD/src/wlan_hdd_cfg.c
index c761ef2..465ba6a 100644
--- a/CORE/HDD/src/wlan_hdd_cfg.c
+++ b/CORE/HDD/src/wlan_hdd_cfg.c
@@ -3943,6 +3943,13 @@
                 CFG_TRIGGER_NULLFRAME_BEFORE_HB_DEFAULT,
                 CFG_TRIGGER_NULLFRAME_BEFORE_HB_MIN,
                 CFG_TRIGGER_NULLFRAME_BEFORE_HB_MAX ),
+
+  REG_VARIABLE(CFG_FORCE_SCC_WITH_ECSA_NAME, WLAN_PARAM_Integer,
+               hdd_config_t, force_scc_with_ecsa,
+               VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
+               CFG_FORCE_SCC_WITH_ECSA_DEFAULT,
+               CFG_FORCE_SCC_WITH_ECSA_MIN,
+               CFG_FORCE_SCC_WITH_ECSA_MAX ),
 };
 
 /*
@@ -4593,6 +4600,11 @@
             "Name = [%s] Value = [%u] ",
             CFG_TRIGGER_NULLFRAME_BEFORE_HB_NAME,
             pHddCtx->cfg_ini->trigger_nullframe_before_hb);
+
+    VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH,
+            "Name = [%s] Value = [%u] ",
+            CFG_FORCE_SCC_WITH_ECSA_NAME,
+            pHddCtx->cfg_ini->force_scc_with_ecsa);
 }
 
 
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index 53bbdfa..422e200 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -20832,7 +20832,7 @@
         return -ENOTSUPP;
 
    channel = vos_freq_to_chan(csa_params->chandef.chan->center_freq);
-   ret = wlansap_set_channel_change(vos_ctx, channel);
+   ret = wlansap_set_channel_change(vos_ctx, channel, false);
 
    return ret;
 }
diff --git a/CORE/HDD/src/wlan_hdd_hostapd.c b/CORE/HDD/src/wlan_hdd_hostapd.c
index 2a5e376..40b3aa9 100644
--- a/CORE/HDD/src/wlan_hdd_hostapd.c
+++ b/CORE/HDD/src/wlan_hdd_hostapd.c
@@ -2321,7 +2321,7 @@
                 (WLAN_HDD_P2P_GO == pHostapdAdapter->device_mode)) {
                 hddLog(LOG1, FL("ET Channel Change to new channel= %d"),
                        set_value);
-                ret = wlansap_set_channel_change(pVosContext, set_value);
+                ret = wlansap_set_channel_change(pVosContext, set_value, false);
             } else {
                 hddLog(LOGE, FL("Channel %d Change Failed, Device in not in SAP/GO mode"),
                        set_value);
diff --git a/CORE/SAP/inc/sapApi.h b/CORE/SAP/inc/sapApi.h
index d8a8f2b..ca1e3fa 100644
--- a/CORE/SAP/inc/sapApi.h
+++ b/CORE/SAP/inc/sapApi.h
@@ -1634,10 +1634,12 @@
  *
  * @vos_ctx: vos context.
  * @new_channel: target channel number.
+ * @allow_dfs_chan: dont allow dfs channel
  *
  * Return: 0 for success, non zero for failure
  */
-int wlansap_set_channel_change(v_PVOID_t vos_ctx, uint32_t new_channel);
+int wlansap_set_channel_change(v_PVOID_t vos_ctx,
+    uint32_t new_channel, bool allow_dfs_chan);
 
 #ifdef __cplusplus
  }
diff --git a/CORE/SAP/src/sapModule.c b/CORE/SAP/src/sapModule.c
index de981ca..212db39 100644
--- a/CORE/SAP/src/sapModule.c
+++ b/CORE/SAP/src/sapModule.c
@@ -2488,12 +2488,14 @@
   return true;
 }
 
-int wlansap_set_channel_change(v_PVOID_t vos_ctx, uint32_t new_channel)
+int wlansap_set_channel_change(v_PVOID_t vos_ctx,
+    uint32_t new_channel, bool allow_dfs_chan)
 {
    ptSapContext sap_ctx;
    tWLAN_SAPEvent sap_event = {0};
    v_PVOID_t hal;
    tpAniSirGlobal mac_ctx;
+   eNVChannelEnabledType chan_state;
 
    sap_ctx = VOS_GET_SAP_CB(vos_ctx);
 
@@ -2516,8 +2518,15 @@
         hddLog(LOGE, FL("channel switch already in progress ignore"));
         return -EALREADY;
    }
-   if (NV_CHANNEL_ENABLE != vos_nv_getChannelEnabledState(new_channel)) {
-        hddLog(LOGE, FL("Invalid channel Ignore channel switch "));
+   chan_state = vos_nv_getChannelEnabledState(new_channel);
+   if ((chan_state == NV_CHANNEL_DISABLE) ||
+       (chan_state == NV_CHANNEL_INVALID)) {
+        hddLog(LOGE,
+               FL("Channel is disabled, Ignore channel switch "));
+        return -EINVAL;
+   } else if (!allow_dfs_chan && (chan_state == NV_CHANNEL_DFS)) {
+        hddLog(LOGE,
+               FL("DFS channel ignore channel switch as allow_dfs_chan is false"));
         return -EINVAL;
    }