qcacld-3.0: Set HW mode before issuing connect for Hidden SSID

Set the HW mode if needed before connecting to an SSID that
is hidden.

CRs-Fixed: 928208
Change-Id: Ibefd207327da1b85ae26a91afd27fc6baf98cf14
diff --git a/core/cds/inc/cds_concurrency.h b/core/cds/inc/cds_concurrency.h
index 9cf3ec0..ff9f30b 100644
--- a/core/cds/inc/cds_concurrency.h
+++ b/core/cds/inc/cds_concurrency.h
@@ -600,6 +600,9 @@
 		return true;
 }
 #endif /* FEATURE_WLAN_CH_AVOID */
+uint8_t cds_search_and_check_for_session_conc(uint8_t session_id,
+		tCsrRoamProfile * roam_profile);
+bool cds_check_for_session_conc(uint8_t session_id, uint8_t channel);
 bool cds_handle_conc_multiport(uint8_t session_id, uint8_t channel);
 
 #ifdef FEATURE_WLAN_FORCE_SAP_SCC
@@ -681,8 +684,9 @@
 					   uint32_t vdev_id);
 CDF_STATUS cds_decr_connection_count(hdd_context_t *hdd_ctx,
 					  uint32_t vdev_id);
-CDF_STATUS cds_current_connections_update(
-				hdd_context_t *hdd_ctx, uint8_t channel);
+CDF_STATUS cds_current_connections_update(uint32_t session_id,
+				uint8_t channel,
+				enum cds_conn_update_reason);
 #ifdef MPC_UT_FRAMEWORK
 CDF_STATUS cds_incr_connection_count_utfw(hdd_context_t *hdd_ctx,
 		uint32_t vdev_id, uint32_t tx_streams, uint32_t rx_streams,
@@ -738,16 +742,20 @@
 				device_mode_t device_mode);
 uint32_t cds_get_connection_count(hdd_context_t *hdd_ctx);
 CDF_STATUS cds_soc_set_hw_mode(hdd_context_t *hdd_ctx,
+		uint32_t session_id,
 		enum hw_mode_ss_config mac0_ss,
 		enum hw_mode_bandwidth mac0_bw,
 		enum hw_mode_ss_config mac1_ss,
 		enum hw_mode_bandwidth mac1_bw,
 		enum hw_mode_dbs_capab dbs,
-		enum hw_mode_agile_dfs_capab dfs);
+		enum hw_mode_agile_dfs_capab dfs,
+		enum cds_conn_update_reason reason);
 enum cds_conc_next_action cds_need_opportunistic_upgrade(
 		hdd_context_t *hdd_ctx);
 CDF_STATUS cds_next_actions(
-		hdd_context_t *hdd_ctx, enum cds_conc_next_action action);
+		hdd_context_t *hdd_ctx, uint32_t session_id,
+		enum cds_conc_next_action action,
+		enum cds_conn_update_reason reason);
 void cds_set_dual_mac_scan_config(hdd_context_t *hdd_ctx,
 		uint8_t dbs_val,
 		uint8_t dbs_plus_agile_scan_val,
diff --git a/core/cds/src/cds_concurrency.c b/core/cds/src/cds_concurrency.c
index 28c0d3b..6792d11 100644
--- a/core/cds/src/cds_concurrency.c
+++ b/core/cds/src/cds_concurrency.c
@@ -2377,12 +2377,14 @@
 /**
  * cds_soc_set_hw_mode() - Set HW mode command to SME
  * @hdd_ctx: HDD context
+ * @session_id: Session ID
  * @mac0_ss: MAC0 spatial stream configuration
  * @mac0_bw: MAC0 bandwidth configuration
  * @mac1_ss: MAC1 spatial stream configuration
  * @mac1_bw: MAC1 bandwidth configuration
  * @dbs: HW DBS capability
  * @dfs: HW Agile DFS capability
+ * @reason: Reason for connection update
  *
  * Sends the set hw mode to the SME module which will pass on
  * this message to WMA layer
@@ -2403,12 +2405,14 @@
  * Return: Success if the message made it down to the next layer
  */
 CDF_STATUS cds_soc_set_hw_mode(hdd_context_t *hdd_ctx,
+		uint32_t session_id,
 		enum hw_mode_ss_config mac0_ss,
 		enum hw_mode_bandwidth mac0_bw,
 		enum hw_mode_ss_config mac1_ss,
 		enum hw_mode_bandwidth mac1_bw,
 		enum hw_mode_dbs_capab dbs,
-		enum hw_mode_agile_dfs_capab dfs)
+		enum hw_mode_agile_dfs_capab dfs,
+		enum cds_conn_update_reason reason)
 {
 	int8_t hw_mode_index;
 	struct sir_hw_mode msg;
@@ -2428,6 +2432,8 @@
 
 	msg.hw_mode_index = hw_mode_index;
 	msg.set_hw_mode_cb = (void *)cds_soc_set_hw_mode_cb;
+	msg.reason = reason;
+	msg.session_id = session_id;
 
 	cds_info("set hw mode to sme: hw_mode_index: %d",
 		msg.hw_mode_index);
@@ -3625,7 +3631,12 @@
 	action = cds_need_opportunistic_upgrade(hdd_ctx);
 	if (action) {
 		/* lets call for action */
-		cds_next_actions(hdd_ctx, action);
+		/* session id is being used only
+		 * in hidden ssid case for now.
+		 * So, session id 0 is ok here.
+		 */
+		cds_next_actions(hdd_ctx, 0, action,
+				CDS_UPDATE_REASON_OPPORTUNISTIC);
 	}
 	cdf_mutex_release(&hdd_ctx->hdd_conc_list_lock);
 
@@ -5240,8 +5251,9 @@
  * cds_current_connections_update() - initiates actions
  * needed on current connections once channel has been decided
  * for the new connection
- * @hdd_ctx:	HDD Context
+ * @session_id: Session id
  * @channel: Channel on which new connection will be
+ * @reason: Reason for which connection update is required
  *
  * This function initiates initiates actions
  * needed on current connections once channel has been decided
@@ -5249,17 +5261,24 @@
  *
  * Return: CDF_STATUS enum
  */
-CDF_STATUS cds_current_connections_update(
-				hdd_context_t *hdd_ctx,
-				uint8_t channel)
+CDF_STATUS cds_current_connections_update(uint32_t session_id,
+				uint8_t channel,
+				enum cds_conn_update_reason reason)
 {
 	enum cds_conc_next_action next_action = CDS_NOP;
 	uint32_t num_connections = 0;
 	enum cds_one_connection_mode second_index = 0;
 	enum cds_two_connection_mode third_index = 0;
 	enum cds_band band;
+	hdd_context_t *hdd_ctx;
 	CDF_STATUS status = CDF_STATUS_E_FAILURE;
 
+	hdd_ctx = cds_get_context(CDF_MODULE_ID_HDD);
+	if (!hdd_ctx) {
+		cds_err("Invalid HDD context");
+		return CDF_STATUS_E_FAILURE;
+	}
+
 	if (wma_is_hw_dbs_capable() == false) {
 		cds_err("driver isn't dbs capable, no further action needed");
 		return CDF_STATUS_E_NOSUPPORT;
@@ -5315,12 +5334,14 @@
 	}
 
 	if (CDS_NOP != next_action)
-		status = cds_next_actions(hdd_ctx, next_action);
+		status = cds_next_actions(hdd_ctx, session_id,
+						next_action, reason);
 	else
 		status = CDF_STATUS_E_NOSUPPORT;
 
-	cds_debug("index2=%d index3=%d next_action=%d, band=%d status=%d",
-		second_index, third_index, next_action, band, status);
+	cds_debug("index2=%d index3=%d next_action=%d, band=%d status=%d reason=%d session_id=%d",
+		second_index, third_index, next_action, band, status,
+		reason, session_id);
 
 done:
 	cdf_mutex_release(&hdd_ctx->hdd_conc_list_lock);
@@ -5437,7 +5458,9 @@
 		break;
 	}
 	if (!wait)
-		cds_next_actions(hdd_ctx, next_action);
+		cds_next_actions(hdd_ctx, vdev_id,
+				next_action,
+				CDS_UPDATE_REASON_NSS_UPDATE);
 	cdf_mutex_release(&hdd_ctx->hdd_conc_list_lock);
 	return;
 }
@@ -5450,6 +5473,8 @@
  * @new_nss: the new nss value
  * @next_action: next action to happen at policy mgr after
  *		beacon update
+ * @reason: Reason for connection update
+ * @session_id: Session id
  *
  * This function initiates initiates actions
  * needed on current connections once channel has been decided
@@ -5458,7 +5483,9 @@
  * Return: CDF_STATUS enum
  */
 CDF_STATUS cds_complete_action(hdd_context_t *hdd_ctx,
-				uint8_t  new_nss, uint8_t next_action)
+				uint8_t  new_nss, uint8_t next_action,
+				enum cds_conn_update_reason reason,
+				uint32_t session_id)
 {
 	CDF_STATUS status = CDF_STATUS_E_FAILURE;
 	uint32_t index = 0, count = 0;
@@ -5518,7 +5545,8 @@
 		index++;
 	}
 	if (!CDF_IS_STATUS_SUCCESS(status))
-		status = cds_next_actions(hdd_ctx, next_action);
+		status = cds_next_actions(hdd_ctx, session_id,
+						next_action, reason);
 
 	return status;
 }
@@ -5528,7 +5556,9 @@
  * connections once channel has been decided for the new
  * connection
  * @hdd_ctx:	HDD Context
+ * @session_id: Session id
  * @action: action to be executed
+ * @reason: Reason for connection update
  *
  * This function initiates initiates actions
  * needed on current connections once channel has been decided
@@ -5537,7 +5567,9 @@
  * Return: CDF_STATUS enum
  */
 CDF_STATUS cds_next_actions(hdd_context_t *hdd_ctx,
-				enum cds_conc_next_action action)
+				uint32_t session_id,
+				enum cds_conc_next_action action,
+				enum cds_conn_update_reason reason)
 {
 	CDF_STATUS status = CDF_STATUS_E_FAILURE;
 	struct sir_hw_mode_params hw_mode;
@@ -5574,14 +5606,17 @@
 		* update the beacon template & notify FW. Once FW confirms
 		*  beacon updated, send down the HW mode change req
 		*/
-		status = cds_complete_action(hdd_ctx, 1, CDS_DBS);
+		status = cds_complete_action(hdd_ctx, 1, CDS_DBS, reason,
+						session_id);
 		break;
 	case CDS_DBS:
-		status = cds_soc_set_hw_mode(hdd_ctx, HW_MODE_SS_1x1,
+		status = cds_soc_set_hw_mode(hdd_ctx, session_id,
+						HW_MODE_SS_1x1,
 						HW_MODE_80_MHZ,
 						HW_MODE_SS_1x1, HW_MODE_40_MHZ,
 						HW_MODE_DBS,
-						HW_MODE_AGILE_DFS_NONE);
+						HW_MODE_AGILE_DFS_NONE,
+						reason);
 		break;
 	case CDS_MCC_UPGRADE:
 		/*
@@ -5589,14 +5624,17 @@
 		* intially. If yes, update the beacon template & notify FW.
 		* Once FW confirms beacon updated, send the HW mode change req
 		*/
-		status = cds_complete_action(hdd_ctx, 0, CDS_MCC);
+		status = cds_complete_action(hdd_ctx, 0, CDS_MCC, reason,
+						session_id);
 		break;
 	case CDS_MCC:
-		status = cds_soc_set_hw_mode(hdd_ctx, HW_MODE_SS_2x2,
+		status = cds_soc_set_hw_mode(hdd_ctx, session_id,
+						HW_MODE_SS_2x2,
 						HW_MODE_80_MHZ,
 						HW_MODE_SS_0x0, HW_MODE_BW_NONE,
 						HW_MODE_DBS_NONE,
-						HW_MODE_AGILE_DFS_NONE);
+						HW_MODE_AGILE_DFS_NONE,
+						reason);
 		break;
 	default:
 		/* err msg */
@@ -6118,29 +6156,72 @@
 }
 
 /**
- * cds_handle_conc_multiport() - to handle multiport concurrency
+ * cds_search_and_check_for_session_conc() - Checks if concurrecy is allowed
+ * @session_id: Session id
+ * @roam_profile: Pointer to the roam profile
+ *
+ * Searches and gets the channel number from the scan results and checks if
+ * concurrency is allowed for the given session ID
+ *
+ * Non zero channel number if concurrency is allowed, zero otherwise
+ */
+uint8_t cds_search_and_check_for_session_conc(uint8_t session_id,
+		tCsrRoamProfile *roam_profile)
+{
+	uint8_t channel = 0;
+	CDF_STATUS status;
+	hdd_context_t *hdd_ctx;
+	hdd_adapter_t *adapter;
+	bool ret;
+
+	hdd_ctx = cds_get_context(CDF_MODULE_ID_HDD);
+	if (!hdd_ctx) {
+		cds_err("Invalid HDD context");
+		return channel;
+	}
+
+	adapter = hdd_get_adapter_by_vdev(hdd_ctx, session_id);
+	if (!adapter) {
+		cds_err("Invalid HDD adapter");
+		return channel;
+	}
+
+	status = cds_get_channel_from_scan_result(adapter,
+			roam_profile, &channel);
+	if ((CDF_STATUS_SUCCESS != status) || (channel == 0)) {
+		cds_err("%s error %d %d",
+			__func__, status, channel);
+		return 0;
+	}
+
+	/* Take care of 160MHz and 80+80Mhz later */
+	ret = cds_allow_concurrency(hdd_ctx,
+		cds_convert_device_mode_to_hdd_type(
+			adapter->device_mode),
+		channel, HW_MODE_20_MHZ);
+	if (false == ret) {
+		cds_err("Connection failed due to conc check fail");
+		return 0;
+	}
+
+	return channel;
+}
+
+/**
+ * cds_check_for_session_conc() - Check if concurrency is allowed for a session
  * @session_id: Session ID
  * @channel: Channel number
  *
- * This routine will handle STA side concurrency when policy manager
- * is enabled.
+ * Checks if connection is allowed for a given session_id
  *
- * Return: true or false
+ * True if the concurrency is allowed, false otherwise
  */
-bool cds_handle_conc_multiport(uint8_t session_id,
+bool cds_check_for_session_conc(uint8_t session_id,
 		uint8_t channel)
 {
-	bool ret = true;
-	CDF_STATUS status;
-	p_cds_contextType cds_context;
-	hdd_adapter_t *adapter;
 	hdd_context_t *hdd_ctx;
-
-	cds_context = cds_get_global_context();
-	if (!cds_context) {
-		cds_err("Invalid CDS context");
-		return false;
-	}
+	hdd_adapter_t *adapter;
+	bool ret;
 
 	hdd_ctx = cds_get_context(CDF_MODULE_ID_HDD);
 	if (!hdd_ctx) {
@@ -6158,6 +6239,7 @@
 		cds_err("Invalid channel number 0");
 		return false;
 	}
+
 	/* Take care of 160MHz and 80+80Mhz later */
 	ret = cds_allow_concurrency(hdd_ctx,
 		cds_convert_device_mode_to_hdd_type(
@@ -6165,6 +6247,36 @@
 		channel, HW_MODE_20_MHZ);
 	if (false == ret) {
 		cds_err("Connection failed due to conc check fail");
+		return 0;
+	}
+
+	return true;
+}
+
+/**
+ * cds_handle_conc_multiport() - to handle multiport concurrency
+ * @session_id: Session ID
+ * @channel: Channel number
+ *
+ * This routine will handle STA side concurrency when policy manager
+ * is enabled.
+ *
+ * Return: true or false
+ */
+bool cds_handle_conc_multiport(uint8_t session_id,
+		uint8_t channel)
+{
+	CDF_STATUS status;
+	p_cds_contextType cds_context;
+
+	cds_context = cds_get_global_context();
+	if (!cds_context) {
+		cds_err("Invalid CDS context");
+		return false;
+	}
+
+	if (!cds_check_for_session_conc(session_id, channel)) {
+		cds_err("Conc not allowed for the session %d", session_id);
 		return false;
 	}
 
@@ -6172,7 +6284,9 @@
 	if (!CDF_IS_STATUS_SUCCESS(status))
 		cds_err("clearing event failed");
 
-	status = cds_current_connections_update(hdd_ctx, channel);
+	status = cds_current_connections_update(session_id,
+			channel,
+			CDS_UPDATE_REASON_NORMAL_STA);
 	if (CDF_STATUS_E_FAILURE == status) {
 		cds_err("connections update failed");
 		return false;
diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c
index 9012628..c78b8bf 100644
--- a/core/hdd/src/wlan_hdd_cfg80211.c
+++ b/core/hdd/src/wlan_hdd_cfg80211.c
@@ -4107,7 +4107,8 @@
 						const void *data,
 						int data_len)
 {
-
+	struct net_device *ndev = wdev->netdev;
+	hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(ndev);
 	hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
 	int ret = 0;
 	enum cds_con_mode intf_mode;
@@ -4165,8 +4166,9 @@
 		if (!CDF_IS_STATUS_SUCCESS(ret))
 			hdd_err("clearing event failed");
 
-		ret = cds_current_connections_update(hdd_ctx,
-				channel_hint);
+		ret = cds_current_connections_update(adapter->sessionId,
+					channel_hint,
+					CDS_UPDATE_REASON_SET_OPER_CHAN);
 		if (CDF_STATUS_E_FAILURE == ret) {
 			/* return in the failure case */
 			hdd_err("ERROR: connections update failed!!");
@@ -8807,8 +8809,9 @@
 		if (!CDF_IS_STATUS_SUCCESS(status))
 			hdd_err("ERR: clear event failed");
 
-		status = cds_current_connections_update(pHddCtx,
-								channelNum);
+		status = cds_current_connections_update(pAdapter->sessionId,
+						channelNum,
+						CDS_UPDATE_REASON_JOIN_IBSS);
 		if (CDF_STATUS_E_FAILURE == status) {
 			hdd_err("ERROR: connections update failed!!");
 			return -EINVAL;
diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c
index 2727e12..437a541 100644
--- a/core/hdd/src/wlan_hdd_hostapd.c
+++ b/core/hdd/src/wlan_hdd_hostapd.c
@@ -8241,7 +8241,9 @@
 		if (!CDF_IS_STATUS_SUCCESS(status))
 			hdd_err("ERR: clear event failed");
 
-		status = cds_current_connections_update(pHddCtx, channel);
+		status = cds_current_connections_update(pAdapter->sessionId,
+				channel,
+				CDS_UPDATE_REASON_START_AP);
 		if (CDF_STATUS_E_FAILURE == status) {
 			hdd_err("ERROR: connections update failed!!");
 			return -EINVAL;
diff --git a/core/hdd/src/wlan_hdd_wext.c b/core/hdd/src/wlan_hdd_wext.c
index 9110a2b..1f7cc49 100644
--- a/core/hdd/src/wlan_hdd_wext.c
+++ b/core/hdd/src/wlan_hdd_wext.c
@@ -7692,19 +7692,25 @@
 		if (apps_args[0] == 0) {
 			hddLog(LOGE,
 				FL("set hw mode for single mac\n"));
-			cds_soc_set_hw_mode(hdd_ctx, HW_MODE_SS_2x2,
+			cds_soc_set_hw_mode(hdd_ctx,
+					pAdapter->sessionId,
+					HW_MODE_SS_2x2,
 					HW_MODE_80_MHZ,
 					HW_MODE_SS_0x0, HW_MODE_BW_NONE,
 					HW_MODE_DBS_NONE,
-					HW_MODE_AGILE_DFS_NONE);
+					HW_MODE_AGILE_DFS_NONE,
+					CDS_UPDATE_REASON_UT);
 		} else if (apps_args[0] == 1) {
 			hddLog(LOGE,
 				FL("set hw mode for dual mac\n"));
-			cds_soc_set_hw_mode(hdd_ctx, HW_MODE_SS_1x1,
+			cds_soc_set_hw_mode(hdd_ctx,
+					pAdapter->sessionId,
+					HW_MODE_SS_1x1,
 					HW_MODE_80_MHZ,
 					HW_MODE_SS_1x1, HW_MODE_40_MHZ,
 					HW_MODE_DBS,
-					HW_MODE_AGILE_DFS_NONE);
+					HW_MODE_AGILE_DFS_NONE,
+					CDS_UPDATE_REASON_UT);
 		}
 	}
 	break;
@@ -7714,8 +7720,9 @@
 		enum cds_conc_next_action action;
 		hddLog(LOGE,
 			FL("<iwpriv wlan0 pm_query_action> is called\n"));
-		action = cds_current_connections_update(hdd_ctx,
-				apps_args[0]);
+		action = cds_current_connections_update(pAdapter->sessionId,
+						apps_args[0],
+						CDS_UPDATE_REASON_UT);
 		pr_info("next action is %d {HDD_NOP = 0, HDD_DBS, HDD_DBS_DOWNGRADE, HDD_MCC, HDD_MCC_UPGRADE}", action);
 	}
 	break;
diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h
index 887901b..ba16dd9 100644
--- a/core/mac/inc/sir_api.h
+++ b/core/mac/inc/sir_api.h
@@ -95,6 +95,28 @@
 /* This should not be greater than MAX_NUMBER_OF_CONC_CONNECTIONS */
 #define MAX_VDEV_SUPPORTED                        4
 
+/**
+ * enum cds_conn_update_reason: Reason for conc connection update
+ * @CDS_UPDATE_REASON_SET_OPER_CHAN: Set probable operating channel
+ * @CDS_UPDATE_REASON_JOIN_IBSS: Join IBSS
+ * @CDS_UPDATE_REASON_UT: Unit test related
+ * @CDS_UPDATE_REASON_START_AP: Start AP
+ * @CDS_UPDATE_REASON_NORMAL_STA: Connection to Normal STA
+ * @CDS_UPDATE_REASON_HIDDEN_STA: Connection to Hidden STA
+ * @CDS_UPDATE_REASON_OPPORTUNISTIC: Opportunistic HW mode update
+ * @CDS_UPDATE_REASON_NSS_UPDATE: NSS update
+ */
+enum cds_conn_update_reason {
+	CDS_UPDATE_REASON_SET_OPER_CHAN,
+	CDS_UPDATE_REASON_JOIN_IBSS,
+	CDS_UPDATE_REASON_UT,
+	CDS_UPDATE_REASON_START_AP,
+	CDS_UPDATE_REASON_NORMAL_STA,
+	CDS_UPDATE_REASON_HIDDEN_STA,
+	CDS_UPDATE_REASON_OPPORTUNISTIC,
+	CDS_UPDATE_REASON_NSS_UPDATE,
+};
+
 typedef enum {
 	eSIR_EXTSCAN_INVALID,
 	eSIR_EXTSCAN_START_RSP,
@@ -397,10 +419,14 @@
  * struct sir_hw_mode - Format of set HW mode
  * @hw_mode_index: Index of HW mode to be set
  * @set_hw_mode_cb: HDD set HW mode callback
+ * @reason: Reason for HW mode change
+ * @session_id: Session id
  */
 struct sir_hw_mode {
 	uint32_t hw_mode_index;
 	void *set_hw_mode_cb;
+	enum cds_conn_update_reason reason;
+	uint32_t session_id;
 };
 
 /**
diff --git a/core/mac/src/pe/lim/lim_process_sme_req_messages.c b/core/mac/src/pe/lim/lim_process_sme_req_messages.c
index 0db6d07..b06e32d 100644
--- a/core/mac/src/pe/lim/lim_process_sme_req_messages.c
+++ b/core/mac/src/pe/lim/lim_process_sme_req_messages.c
@@ -156,6 +156,7 @@
 	cdf_mem_zero(req_msg, len);
 
 	req_msg->hw_mode_index = buf->set_hw.hw_mode_index;
+	req_msg->reason = buf->set_hw.reason;
 	/* Other parameters are not needed for WMA */
 
 	cds_message.bodyptr = req_msg;
diff --git a/core/sme/inc/sme_internal.h b/core/sme/inc/sme_internal.h
index 4ff54c7..adc01cb 100644
--- a/core/sme/inc/sme_internal.h
+++ b/core/sme/inc/sme_internal.h
@@ -218,6 +218,7 @@
 	void *dcc_stats_event_context;
 	ocb_callback dcc_stats_event_callback;
 	sme_set_thermal_level_callback set_thermal_level_cb;
+	void *saved_scan_cmd;
 } tSmeStruct, *tpSmeStruct;
 
 #endif /* #if !defined( __SMEINTERNAL_H ) */
diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c
index c436ce5..60c8729 100644
--- a/core/sme/src/common/sme_api.c
+++ b/core/sme/src/common/sme_api.c
@@ -156,7 +156,10 @@
 	bool found;
 	hw_mode_cb callback = NULL;
 	struct sir_set_hw_mode_resp *param;
+	enum cds_conn_update_reason reason;
+	tSmeCmd *saved_cmd;
 
+	sms_log(mac, LOG1, FL("%s"), __func__);
 	param = (struct sir_set_hw_mode_resp *)msg;
 	if (!param) {
 		sms_log(mac, LOGE, FL("HW mode resp param is NULL"));
@@ -184,10 +187,48 @@
 	}
 
 	callback = command->u.set_hw_mode_cmd.set_hw_mode_cb;
+	reason = command->u.set_hw_mode_cmd.reason;
 	if (callback) {
 		if (!param) {
 			sms_log(mac, LOGE,
 			    FL("Callback failed since HW mode params is NULL"));
+		} else if (reason == CDS_UPDATE_REASON_HIDDEN_STA) {
+			/* In the case of hidden SSID, connection update
+			 * (set hw mode) is done after the scan with reason
+			 * code eCsrScanForSsid completes. The connect/failure
+			 * needs to be handled after the response of set hw
+			 * mode
+			 */
+			saved_cmd = (tSmeCmd *)mac->sme.saved_scan_cmd;
+			if (!saved_cmd) {
+				sms_log(mac, LOGP,
+					FL("saved cmd is NULL, Check this"));
+				goto end;
+			}
+			if (param->status == SET_HW_MODE_STATUS_OK) {
+				sms_log(mac, LOG1,
+					FL("search for ssid success"));
+				csr_scan_handle_search_for_ssid(mac,
+					saved_cmd);
+			} else {
+				sms_log(mac, LOG1,
+					FL("search for ssid failure"));
+				csr_scan_handle_search_for_ssid_failure(mac,
+					saved_cmd);
+			}
+			if (saved_cmd->u.roamCmd.pRoamBssEntry)
+				cdf_mem_free(
+					saved_cmd->u.roamCmd.pRoamBssEntry);
+			if (saved_cmd->u.scanCmd.u.scanRequest.SSIDs.SSIDList)
+				cdf_mem_free(saved_cmd->u.scanCmd.u.
+						scanRequest.SSIDs.SSIDList);
+			if (saved_cmd->u.scanCmd.pToRoamProfile)
+				cdf_mem_free(saved_cmd->u.scanCmd.
+						pToRoamProfile);
+			if (saved_cmd) {
+				cdf_mem_free(saved_cmd);
+				saved_cmd = NULL;
+			}
 		} else {
 			sms_log(mac, LOGE,
 			      FL("Calling HDD callback for HW mode response"));
@@ -200,6 +241,7 @@
 		sms_log(mac, LOGE, FL("Callback does not exist"));
 	}
 
+end:
 	found = csr_ll_remove_entry(&mac->sme.smeCmdActiveList, entry,
 			LL_ACCESS_LOCK);
 	if (found) {
@@ -14391,6 +14433,8 @@
 	cmd->command = e_sme_command_set_hw_mode;
 	cmd->u.set_hw_mode_cmd.hw_mode_index = msg.hw_mode_index;
 	cmd->u.set_hw_mode_cmd.set_hw_mode_cb = msg.set_hw_mode_cb;
+	cmd->u.set_hw_mode_cmd.reason = msg.reason;
+	cmd->u.set_hw_mode_cmd.session_id = msg.session_id;
 
 	sms_log(mac, LOG1, FL("Queuing e_sme_command_set_hw_mode to CSR"));
 	csr_queue_sme_command(mac, cmd, false);
diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c
index f4dfbbe..b6125f0 100644
--- a/core/sme/src/csr/csr_api_roam.c
+++ b/core/sme/src/csr/csr_api_roam.c
@@ -453,6 +453,10 @@
 	csr_ll_close(&pMac->roam.statsClientReqList);
 	csr_ll_close(&pMac->roam.peStatsReqList);
 	csr_ll_close(&pMac->roam.roamCmdPendingList);
+	if (pMac->sme.saved_scan_cmd) {
+		cdf_mem_free(pMac->sme.saved_scan_cmd);
+		pMac->sme.saved_scan_cmd = NULL;
+	}
 	/* DeInit Globals */
 	csr_roam_de_init_globals(pMac);
 	return status;
@@ -18818,11 +18822,25 @@
 		goto fail;
 	}
 
+	/* For hidden SSID case, if there is any scan command pending
+	 * it needs to be cleared before issuing set HW mode
+	 */
+	if (command->u.set_hw_mode_cmd.reason == CDS_UPDATE_REASON_HIDDEN_STA) {
+		sms_log(mac, LOGE, FL("clear any pending scan command"));
+		status = csr_scan_abort_mac_scan_not_for_connect(mac,
+				command->u.set_hw_mode_cmd.session_id);
+		if (!CDF_IS_STATUS_SUCCESS(status)) {
+			sms_log(mac, LOGE, FL("Failed to clear scan cmd"));
+			goto fail;
+		}
+	}
+
 	cdf_mem_set(cmd, len, 0);
 
 	cmd->messageType = eWNI_SME_SET_HW_MODE_REQ;
 	cmd->length = len;
 	cmd->set_hw.hw_mode_index = command->u.set_hw_mode_cmd.hw_mode_index;
+	cmd->set_hw.reason = command->u.set_hw_mode_cmd.reason;
 	/*
 	 * Below callback and context info are not needed for PE as of now.
 	 * Storing the passed value in the same s_sir_set_hw_mode format.
diff --git a/core/sme/src/csr/csr_api_scan.c b/core/sme/src/csr/csr_api_scan.c
index 68f0aee..e66a541 100644
--- a/core/sme/src/csr/csr_api_scan.c
+++ b/core/sme/src/csr/csr_api_scan.c
@@ -2022,8 +2022,11 @@
 		pNewIes = NULL;
 		status = csr_save_ies(pMac, pFilter, pBssDesc, &pNewIes,
 				      &fMatch, &uc, &mc, &auth);
-		if (!CDF_IS_STATUS_SUCCESS(status))
+		if (!CDF_IS_STATUS_SUCCESS(status)) {
+			sms_log(pMac, LOG1, FL("save ies fail %d"),
+				status);
 			break;
+		}
 		/*
 		 * Modify the prefer value to honor PCL list
 		 */
@@ -2032,8 +2035,11 @@
 		status = csr_save_scan_entry(pMac, pFilter, fMatch, pBssDesc,
 					     pNewIes, pRetList, count, uc, mc,
 					     &auth);
-		if (!CDF_IS_STATUS_SUCCESS(status))
+		if (!CDF_IS_STATUS_SUCCESS(status)) {
+			sms_log(pMac, LOG1, FL("save entry fail %d"),
+				status);
 			break;
+		}
 		pEntry = csr_ll_next(&pMac->scan.scanResultList, pEntry,
 				     LL_ACCESS_NOLOCK);
 	} /* while */
@@ -2055,14 +2061,17 @@
 	csr_prefer_5ghz(pMac, pFilter);
 
 	pRetList = cdf_mem_malloc(sizeof(tScanResultList));
-	if (NULL == pRetList)
+	if (NULL == pRetList) {
+		sms_log(pMac, LOGE, FL("pRetList is NULL"));
 		return CDF_STATUS_E_NOMEM;
+	}
 
 	cdf_mem_set(pRetList, sizeof(tScanResultList), 0);
 	csr_ll_open(pMac->hHdd, &pRetList->List);
 	pRetList->pCurEntry = NULL;
 	status = csr_parse_scan_results(pMac, pFilter, pRetList, &count);
-	sms_log(pMac, LOG2, FL("return %d BSS"), csr_ll_count(&pRetList->List));
+	sms_log(pMac, LOG1, FL("return %d BSS %d"),
+		csr_ll_count(&pRetList->List), status);
 	if (!CDF_IS_STATUS_SUCCESS(status) || (phResult == NULL)) {
 		/* Fail or No one wants the result. */
 		csr_scan_result_purge(pMac, (tScanResultHandle) pRetList);
@@ -3654,9 +3663,11 @@
 
 eCsrScanCompleteNextCommand csr_scan_get_next_command_state(tpAniSirGlobal pMac,
 							    tSmeCmd *pCommand,
-							    bool fSuccess)
+							    bool fSuccess,
+							    uint8_t *chan)
 {
 	eCsrScanCompleteNextCommand NextCommand = eCsrNextScanNothing;
+	int8_t channel;
 
 	switch (pCommand->u.scanCmd.reason) {
 	case eCsrScan11d1:
@@ -3688,9 +3699,35 @@
 			eCsrNextLostLinkScan3Failed;
 		break;
 	case eCsrScanForSsid:
-		NextCommand =
-			(fSuccess) ? eCsrNexteScanForSsidSuccess :
-			eCsrNexteScanForSsidFailure;
+		/* When policy manager is disabled:
+		 * success: csr_scan_handle_search_for_ssid
+		 * failure: csr_scan_handle_search_for_ssid_failure
+		 *
+		 * When policy manager is enabled:
+		 * success:
+		 *   set hw_mode success -> csr_scan_handle_search_for_ssid
+		 *   set hw_mode fail -> csr_scan_handle_search_for_ssid_failure
+		 * failure: csr_scan_handle_search_for_ssid_failure
+		 */
+		if (pMac->policy_manager_enabled) {
+			sms_log(pMac, LOG1, FL("Resp for eCsrScanForSsid"));
+			channel = cds_search_and_check_for_session_conc(
+					pCommand->sessionId,
+					pCommand->u.scanCmd.pToRoamProfile);
+			if ((!channel) || !fSuccess) {
+				NextCommand = eCsrNexteScanForSsidFailure;
+				sms_log(pMac, LOG1,
+					FL("next ScanForSsidFailure %d %d"),
+					channel, fSuccess);
+			} else {
+				NextCommand = eCsrNextCheckAllowConc;
+				*chan = channel;
+				sms_log(pMac, LOG1, FL("next CheckAllowConc"));
+			}
+		} else  {
+			NextCommand = (fSuccess) ? eCsrNexteScanForSsidSuccess :
+				eCsrNexteScanForSsidFailure;
+		}
 		break;
 	default:
 		NextCommand = eCsrNextScanNothing;
@@ -3789,12 +3826,122 @@
 }
 #endif /* #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR */
 
+/**
+ * csr_save_profile() - Save the profile info from sme command
+ * @mac_ctx: Global MAC context
+ * @save_cmd: Pointer where the command will be saved
+ * @command: Command from which the profile will be saved
+ *
+ * Saves the profile information from the SME's scan command
+ *
+ * Return: CDF_STATUS
+ */
+CDF_STATUS csr_save_profile(tpAniSirGlobal mac_ctx,
+			    tSmeCmd *save_cmd, tSmeCmd *command)
+{
+	tCsrScanResult *scan_result;
+	tCsrScanResult *temp;
+	uint32_t bss_len;
+	CDF_STATUS status;
+
+	save_cmd->u.scanCmd.pToRoamProfile =
+		cdf_mem_malloc(sizeof(tCsrRoamProfile));
+	if (!save_cmd->u.scanCmd.pToRoamProfile) {
+		sms_log(mac_ctx, LOGE, FL("pToRoamProfile mem fail"));
+		goto error;
+	}
+
+	status = csr_roam_copy_profile(mac_ctx,
+			save_cmd->u.scanCmd.pToRoamProfile,
+			command->u.scanCmd.pToRoamProfile);
+	if (!CDF_IS_STATUS_SUCCESS(status)) {
+		sms_log(mac_ctx, LOGE, FL("csr_roam_copy_profile fail"));
+		goto error;
+	}
+
+	save_cmd->sessionId = command->sessionId;
+	save_cmd->u.scanCmd.roamId = command->u.scanCmd.roamId;
+	save_cmd->u.scanCmd.u.scanRequest.SSIDs.numOfSSIDs =
+		command->u.scanCmd.u.scanRequest.SSIDs.numOfSSIDs;
+	save_cmd->u.scanCmd.u.scanRequest.SSIDs.SSIDList =
+		cdf_mem_malloc(
+			save_cmd->u.scanCmd.u.scanRequest.SSIDs.numOfSSIDs *
+			sizeof(tCsrSSIDInfo));
+	if (!save_cmd->u.scanCmd.u.scanRequest.SSIDs.SSIDList) {
+		sms_log(mac_ctx, LOGE, FL("SSIDList mem fail"));
+		goto error;
+	}
+
+	cdf_mem_copy(save_cmd->u.scanCmd.u.scanRequest.SSIDs.SSIDList,
+			command->u.scanCmd.u.scanRequest.SSIDs.SSIDList,
+			save_cmd->u.scanCmd.u.scanRequest.SSIDs.numOfSSIDs *
+			sizeof(tCsrSSIDInfo));
+
+	if (!command->u.roamCmd.pRoamBssEntry)
+		return CDF_STATUS_SUCCESS;
+
+	scan_result = GET_BASE_ADDR(command->u.roamCmd.pRoamBssEntry,
+			tCsrScanResult, Link);
+
+	bss_len = scan_result->Result.BssDescriptor.length +
+		sizeof(scan_result->Result.BssDescriptor.length);
+
+	temp = cdf_mem_malloc(sizeof(tCsrScanResult) + bss_len);
+	if (!temp) {
+		sms_log(mac_ctx, LOGE, FL("bss mem fail"));
+		goto error;
+	}
+
+	temp->AgingCount = scan_result->AgingCount;
+	temp->preferValue = scan_result->preferValue;
+	temp->capValue = scan_result->capValue;
+	temp->ucEncryptionType = scan_result->ucEncryptionType;
+	temp->mcEncryptionType = scan_result->mcEncryptionType;
+	temp->authType = scan_result->authType;
+	/* pvIes is unsued in success/failure */
+	temp->Result.pvIes = NULL;
+
+	cdf_mem_copy(temp->Result.pvIes,
+			scan_result->Result.pvIes,
+			sizeof(*scan_result->Result.pvIes));
+	temp->Result.ssId.length = scan_result->Result.ssId.length;
+	cdf_mem_copy(temp->Result.ssId.ssId,
+			scan_result->Result.ssId.ssId,
+			sizeof(scan_result->Result.ssId.ssId));
+	temp->Result.timer = scan_result->Result.timer;
+	cdf_mem_copy(&temp->Result.BssDescriptor,
+			&scan_result->Result.BssDescriptor,
+			sizeof(temp->Result.BssDescriptor));
+	temp->Link.last = temp->Link.next = NULL;
+	save_cmd->u.roamCmd.pRoamBssEntry = (tListElem *)temp;
+
+	return CDF_STATUS_SUCCESS;
+error:
+	csr_scan_handle_search_for_ssid_failure(mac_ctx,
+			command);
+	if (save_cmd->u.roamCmd.pRoamBssEntry)
+		cdf_mem_free(save_cmd->u.roamCmd.pRoamBssEntry);
+	if (save_cmd->u.scanCmd.u.scanRequest.SSIDs.SSIDList)
+		cdf_mem_free(save_cmd->u.scanCmd.u.scanRequest.SSIDs.SSIDList);
+	if (save_cmd->u.scanCmd.pToRoamProfile)
+		cdf_mem_free(save_cmd->u.scanCmd.pToRoamProfile);
+	if (save_cmd) {
+		cdf_mem_free(save_cmd);
+		save_cmd = NULL;
+	}
+
+	return CDF_STATUS_E_FAILURE;
+}
+
 static void
 csr_handle_nxt_cmd(tpAniSirGlobal mac_ctx, tSmeCmd *pCommand,
 		   eCsrScanCompleteNextCommand *nxt_cmd,
-		   bool *remove_cmd, uint32_t session_id)
+		   bool *remove_cmd, uint32_t session_id,
+		   uint8_t chan)
 {
-	CDF_STATUS status;
+	CDF_STATUS status, ret;
+	tSmeCmd *save_cmd = NULL;
+
 	switch (*nxt_cmd) {
 	case eCsrNext11dScan1Success:
 	case eCsrNext11dScan2Success:
@@ -3852,6 +3999,54 @@
 	case eCsrNexteScanForSsidFailure:
 		csr_scan_handle_search_for_ssid_failure(mac_ctx, pCommand);
 		break;
+	case eCsrNextCheckAllowConc:
+		ret = cds_current_connections_update(pCommand->sessionId,
+					chan,
+					CDS_UPDATE_REASON_HIDDEN_STA);
+		sms_log(mac_ctx, LOG1, FL("chan: %d session: %d status: %d"),
+					chan, pCommand->sessionId, ret);
+		if (mac_ctx->sme.saved_scan_cmd) {
+			cdf_mem_free(mac_ctx->sme.saved_scan_cmd);
+			mac_ctx->sme.saved_scan_cmd = NULL;
+			sms_log(mac_ctx, LOGE,
+				FL("memory should have been free. Check!"));
+		}
+
+		save_cmd = (tSmeCmd *) cdf_mem_malloc(sizeof(*pCommand));
+		if (!save_cmd) {
+			sms_log(mac_ctx, LOGE, FL("save_cmd mem fail"));
+			goto error;
+		}
+
+		status = csr_save_profile(mac_ctx, save_cmd, pCommand);
+		if (!CDF_IS_STATUS_SUCCESS(status) ||
+				!save_cmd) {
+			/* csr_save_profile should report error */
+			sms_log(mac_ctx, LOGE, FL("profile save failed %d"),
+					status);
+			return;
+		}
+
+		mac_ctx->sme.saved_scan_cmd = (void *)save_cmd;
+
+		if (CDF_STATUS_E_FAILURE == ret) {
+error:
+			sms_log(mac_ctx, LOGE, FL("conn update fail %d"), chan);
+			csr_scan_handle_search_for_ssid_failure(mac_ctx,
+								pCommand);
+			if (mac_ctx->sme.saved_scan_cmd) {
+				cdf_mem_free(mac_ctx->sme.saved_scan_cmd);
+				mac_ctx->sme.saved_scan_cmd = NULL;
+			}
+		} else if (CDF_STATUS_E_NOSUPPORT == ret) {
+			sms_log(mac_ctx, LOGE, FL("conn update not supported"));
+			csr_scan_handle_search_for_ssid(mac_ctx, pCommand);
+			if (mac_ctx->sme.saved_scan_cmd) {
+				cdf_mem_free(mac_ctx->sme.saved_scan_cmd);
+				mac_ctx->sme.saved_scan_cmd = NULL;
+			}
+		}
+		break;
 	default:
 		break;
 	}
@@ -3916,6 +4111,7 @@
 	bool fRemoveCommand = true;
 	bool fSuccess;
 	uint32_t sessionId = 0;
+	uint8_t chan;
 
 	csr_get_active_scan_entry(pMac, pScanRsp->scan_id, &pEntry);
 	if (!pEntry) {
@@ -3966,10 +4162,11 @@
 #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
 	csr_diag_scan_complete(pMac, pCommand, pScanRsp);
 #endif /* #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR */
-	NextCommand = csr_scan_get_next_command_state(pMac, pCommand, fSuccess);
+	NextCommand = csr_scan_get_next_command_state(pMac, pCommand, fSuccess,
+							&chan);
 	/* We reuse the command here instead reissue a new command */
 	csr_handle_nxt_cmd(pMac, pCommand, &NextCommand,
-			   &fRemoveCommand, sessionId);
+			   &fRemoveCommand, sessionId, chan);
 	return fRemoveCommand;
 }
 
diff --git a/core/sme/src/csr/csr_inside_api.h b/core/sme/src/csr/csr_inside_api.h
index 1679784..0c7fef8 100644
--- a/core/sme/src/csr/csr_inside_api.h
+++ b/core/sme/src/csr/csr_inside_api.h
@@ -123,6 +123,7 @@
 	eCsrNext11dScan2Success,
 	eCsrNext11dScanComplete,
 	eCsrNexteScanForSsidFailure,
+	eCsrNextCheckAllowConc,
 
 } eCsrScanCompleteNextCommand;
 
@@ -1060,6 +1061,10 @@
 CDF_STATUS csr_set_ht2040_mode(tpAniSirGlobal pMac, uint32_t sessionId,
 			       ePhyChanBondState cbMode, bool obssEnabled);
 #endif
+CDF_STATUS csr_scan_handle_search_for_ssid(tpAniSirGlobal mac,
+		tSmeCmd *command);
+CDF_STATUS csr_scan_handle_search_for_ssid_failure(tpAniSirGlobal mac,
+		tSmeCmd *command);
 tSirBssDescription*
 csr_get_bssdescr_from_scan_handle(tScanResultHandle result_handle,
 				  tSirBssDescription *bss_descr);