Browse Source

qcacld-3.0: On CSA complete, check if all peer need to be disconnected

CSA on DFS channels requires CAC period after RESTART response, peers
can leave during CAC period due to HB failure. But peers remain
connected in SAP and are not deleted.
Now if vdev down is called during CAC wait period, the peer delete
all is not called, and vdev delete is sent without sending peer
delete to firmare leading to assert.

This change adds the logic to internally disconnect all peers before
channel switch if CAC is required on new channel, i.e new channel is
DFS and pre-CAC is not done and ignore cac is not set.

Change-Id: I923fd11d1b9d4a2c606b19ff94baaf44397d3e20
CRs-Fixed: 2449104
Abhishek Singh 6 years ago
parent
commit
06522c56cd

+ 2 - 0
components/mlme/core/inc/wlan_mlme_main.h

@@ -72,6 +72,7 @@ enum vdev_assoc_type {
  *                                   in progress
  * @vdev_start_failed: flag to indicate that vdev start failed.
  * @connection_fail: flag to indicate connection failed
+ * @cac_required_for_new_channel: if CAC is required for new channel
  * @assoc_type: vdev associate/reassociate type
  * @dynamic_cfg: current configuration of nss, chains for vdev.
  * @ini_cfg: Max configuration of nss, chains supported for vdev.
@@ -82,6 +83,7 @@ struct mlme_legacy_priv {
 	bool hidden_ssid_restart_in_progress;
 	bool vdev_start_failed;
 	bool connection_fail;
+	bool cac_required_for_new_channel;
 	enum vdev_assoc_type assoc_type;
 	struct wlan_mlme_nss_chains dynamic_cfg;
 	struct wlan_mlme_nss_chains ini_cfg;

+ 18 - 0
components/mlme/core/inc/wlan_mlme_vdev_mgr_interface.h

@@ -129,6 +129,24 @@ mlme_set_connection_fail(struct wlan_objmgr_vdev *vdev, bool val);
  */
 bool mlme_get_vdev_start_failed(struct wlan_objmgr_vdev *vdev);
 
+/**
+ * mlme_get_cac_required() - get if cac is required for new channel
+ * @vdev: vdev pointer
+ *
+ * Return: if cac is required
+ */
+bool mlme_get_cac_required(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * mlme_set_cac_required() - set if cac is required for new channel
+ * @vdev: vdev pointer
+ * @val: value to be set
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+mlme_set_cac_required(struct wlan_objmgr_vdev *vdev, bool val);
+
 /**
  * mlme_is_vdev_in_beaconning_mode() - check if vdev is beaconing mode
  * @vdev_opmode: vdev opmode

+ 63 - 0
components/mlme/core/src/wlan_mlme_vdev_mgr_interface.c

@@ -424,6 +424,33 @@ static QDF_STATUS ap_mlme_vdev_stop_send(struct vdev_mlme_obj *vdev_mlme,
 	return lim_ap_mlme_vdev_stop_send(vdev_mlme, data_len, data);
 }
 
+/**
+ * ap_mlme_vdev_is_newchan_no_cac - VDEV SM CSA complete notification
+ * @vdev_mlme:  VDEV MLME comp object
+ *
+ * On CSA complete, checks whether Channel does not needs CAC period, if
+ * it doesn't need cac return SUCCESS else FAILURE
+ *
+ * Return: SUCCESS if new channel doesn't need cac
+ *         else FAILURE
+ */
+static QDF_STATUS
+ap_mlme_vdev_is_newchan_no_cac(struct vdev_mlme_obj *vdev_mlme)
+{
+	bool cac_required;
+
+	cac_required = mlme_get_cac_required(vdev_mlme->vdev);
+	mlme_legacy_debug("vdev id = %d cac_required %d",
+			  vdev_mlme->vdev->vdev_objmgr.vdev_id, cac_required);
+
+	if (!cac_required)
+		return QDF_STATUS_SUCCESS;
+
+	mlme_set_cac_required(vdev_mlme->vdev, false);
+
+	return QDF_STATUS_E_FAILURE;
+}
+
 /**
  * ap_mlme_vdev_down_send() - callback to send vdev down req
  * @vdev_mlme: vdev mlme object
@@ -691,6 +718,39 @@ bool mlme_get_vdev_start_failed(struct wlan_objmgr_vdev *vdev)
 	return mlme_priv->vdev_start_failed;
 }
 
+QDF_STATUS mlme_set_cac_required(struct wlan_objmgr_vdev *vdev, bool val)
+{
+	struct vdev_mlme_obj *vdev_mlme;
+	struct mlme_legacy_priv *mlme_priv;
+
+	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
+	if (!vdev_mlme) {
+		mlme_legacy_err("vdev component object is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	mlme_priv = (struct mlme_legacy_priv *)vdev_mlme->ext_vdev_ptr;
+
+	mlme_priv->cac_required_for_new_channel = val;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+bool mlme_get_cac_required(struct wlan_objmgr_vdev *vdev)
+{
+	struct vdev_mlme_obj *vdev_mlme;
+	struct mlme_legacy_priv *mlme_priv;
+
+	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
+	if (!vdev_mlme) {
+		mlme_legacy_err("vdev component object is NULL");
+		return false;
+	}
+
+	mlme_priv = (struct mlme_legacy_priv *)vdev_mlme->ext_vdev_ptr;
+
+	return mlme_priv->cac_required_for_new_channel;
+}
 
 /**
  * vdevmgr_mlme_ext_hdl_create () - Create mlme legacy priv object
@@ -818,6 +878,8 @@ static struct vdev_mlme_ops sta_mlme_ops = {
  *                                      MLME down operation
  * @mlme_vdev_notify_down_complete:     callback to notify VDEV MLME on moving
  *                                      to INIT state
+ * @mlme_vdev_is_newchan_no_cac:        callback to check if new channel is DFS
+ *                                      and cac is not required
  */
 static struct vdev_mlme_ops ap_mlme_ops = {
 	.mlme_vdev_start_send = ap_mlme_vdev_start_send,
@@ -834,6 +896,7 @@ static struct vdev_mlme_ops ap_mlme_ops = {
 	.mlme_vdev_stop_continue = vdevmgr_mlme_stop_continue,
 	.mlme_vdev_down_send = vdevmgr_mlme_vdev_down_send,
 	.mlme_vdev_notify_down_complete = vdevmgr_notify_down_complete,
+	.mlme_vdev_is_newchan_no_cac = ap_mlme_vdev_is_newchan_no_cac,
 };
 
 /**

+ 1 - 0
core/mac/src/pe/include/lim_session.h

@@ -578,6 +578,7 @@ struct pe_session {
 #endif
 	bool enable_session_twt_support;
 	uint32_t cac_duration_ms;
+	tSirResultCodes stop_bss_reason;
 	uint32_t dfs_regdomain;
 };
 

+ 14 - 14
core/mac/src/pe/lim/lim_process_sme_req_messages.c

@@ -2783,6 +2783,19 @@ void lim_delete_all_peers(struct pe_session *session)
 	struct mac_context *mac_ctx = session->mac_ctx;
 	tpDphHashNode sta_ds = NULL;
 	QDF_STATUS status;
+	tSirMacAddr bc_addr = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
+	/* IBSS and NDI doesn't send Disassoc frame */
+	if (!LIM_IS_IBSS_ROLE(session) &&
+	    !LIM_IS_NDI_ROLE(session)) {
+		pe_debug("stop_bss_reason: %d", session->stop_bss_reason);
+		if (session->stop_bss_reason == eSIR_SME_MIC_COUNTER_MEASURES)
+			__lim_counter_measures(mac_ctx, session);
+		else
+			lim_send_disassoc_mgmt_frame(mac_ctx,
+				eSIR_MAC_DEAUTH_LEAVING_BSS_REASON,
+				bc_addr, session, false);
+	}
 
 	for (i = 1; i < session->dph.dphHashTable.size; i++) {
 		sta_ds = dph_get_hash_entry(mac_ctx, i,
@@ -2940,20 +2953,7 @@ __lim_handle_sme_stop_bss_request(struct mac_context *mac, uint32_t *pMsgBuf)
 		       pe_session->limSmeState));
 
 	pe_session->smeSessionId = smesessionId;
-
-	/* STA_IN_IBSS and NDI should NOT send Disassoc frame */
-	if (!LIM_IS_IBSS_ROLE(pe_session) &&
-	    !LIM_IS_NDI_ROLE(pe_session)) {
-		tSirMacAddr bcAddr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
-
-		if (stop_bss_req.reasonCode == eSIR_SME_MIC_COUNTER_MEASURES)
-			/* Send disassoc all stations associated thru TKIP */
-			__lim_counter_measures(mac, pe_session);
-		else
-			lim_send_disassoc_mgmt_frame(mac,
-				eSIR_MAC_DEAUTH_LEAVING_BSS_REASON,
-				bcAddr, pe_session, false);
-	}
+	pe_session->stop_bss_reason = stop_bss_req.reasonCode;
 
 	if (!LIM_IS_NDI_ROLE(pe_session)) {
 		/* Free the buffer allocated in START_BSS_REQ */

+ 12 - 0
core/mac/src/pe/lim/lim_send_management_frames.c

@@ -2940,6 +2940,8 @@ lim_send_disassoc_mgmt_frame(struct mac_context *mac,
 		QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO,
 			  FL
 				  ("CAC timer is running, drop disassoc from going out"));
+		if (waitForAck)
+			lim_send_disassoc_cnf(mac);
 		return;
 	}
 	smeSessionId = pe_session->smeSessionId;
@@ -2966,6 +2968,8 @@ lim_send_disassoc_mgmt_frame(struct mac_context *mac,
 	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
 		pe_err("Failed to allocate %d bytes for a Disassociation",
 			nBytes);
+		if (waitForAck)
+			lim_send_disassoc_cnf(mac);
 		return;
 	}
 	/* Paranoia: */
@@ -2988,6 +2992,8 @@ lim_send_disassoc_mgmt_frame(struct mac_context *mac,
 		pe_err("Failed to pack a Disassociation (0x%08x)",
 			nStatus);
 		cds_packet_free((void *)pPacket);
+		if (waitForAck)
+			lim_send_disassoc_cnf(mac);
 		return;
 	} else if (DOT11F_WARNED(nStatus)) {
 		pe_warn("There were warnings while packing a Disassociation (0x%08x)",
@@ -3117,6 +3123,8 @@ lim_send_deauth_mgmt_frame(struct mac_context *mac,
 		QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO,
 			  FL
 				  ("CAC timer is running, drop the deauth from going out"));
+		if (waitForAck)
+			lim_send_deauth_cnf(mac);
 		return;
 	}
 	smeSessionId = pe_session->smeSessionId;
@@ -3143,6 +3151,8 @@ lim_send_deauth_mgmt_frame(struct mac_context *mac,
 	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
 		pe_err("Failed to allocate %d bytes for a De-Authentication",
 			nBytes);
+		if (waitForAck)
+			lim_send_deauth_cnf(mac);
 		return;
 	}
 	/* Paranoia: */
@@ -3164,6 +3174,8 @@ lim_send_deauth_mgmt_frame(struct mac_context *mac,
 		pe_err("Failed to pack a DeAuthentication (0x%08x)",
 			nStatus);
 		cds_packet_free((void *)pPacket);
+		if (waitForAck)
+			lim_send_deauth_cnf(mac);
 		return;
 	} else if (DOT11F_WARNED(nStatus)) {
 		pe_warn("There were warnings while packing a De-Authentication (0x%08x)",

+ 49 - 0
core/sap/src/sap_module.c

@@ -54,6 +54,7 @@
 #include <wlan_crypto_global_api.h>
 #include "cfg_ucfg_api.h"
 #include "wlan_mlme_ucfg_api.h"
+#include "wlan_mlme_vdev_mgr_interface.h"
 
 #define SAP_DEBUG
 static struct sap_context *gp_sap_ctx[SAP_MAX_NUM_SESSION];
@@ -1758,6 +1759,53 @@ void wlansap_get_sec_channel(uint8_t sec_ch_offset,
 		  __func__, sec_ch_offset, *sec_channel);
 }
 
+#ifdef CONFIG_VDEV_SM
+static void
+wlansap_set_cac_required_for_chan(struct mac_context *mac_ctx,
+				  struct sap_context *sap_ctx)
+{
+	bool is_ch_dfs = false;
+	bool cac_required;
+
+	if (sap_ctx->ch_params.ch_width == CH_WIDTH_160MHZ) {
+		is_ch_dfs = true;
+	} else if (sap_ctx->ch_params.ch_width == CH_WIDTH_80P80MHZ) {
+		if ((wlan_reg_get_channel_state(mac_ctx->pdev,
+						sap_ctx->channel) ==
+						CHANNEL_STATE_DFS) ||
+		    (wlan_reg_get_channel_state(mac_ctx->pdev,
+					sap_ctx->ch_params.center_freq_seg1 -
+					SIR_80MHZ_START_CENTER_CH_DIFF) ==
+					CHANNEL_STATE_DFS))
+			is_ch_dfs = true;
+	} else if (wlan_reg_get_channel_state(mac_ctx->pdev,
+					      sap_ctx->channel) ==
+					      CHANNEL_STATE_DFS) {
+		is_ch_dfs = true;
+	}
+	QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG,
+		  "%s: vdev id %d chan %d is_ch_dfs %d pre_cac_complete %d ignore_cac %d cac_state %d",
+		  __func__, sap_ctx->sessionId, sap_ctx->channel, is_ch_dfs,
+		  sap_ctx->pre_cac_complete, mac_ctx->sap.SapDfsInfo.ignore_cac,
+		  mac_ctx->sap.SapDfsInfo.cac_state);
+
+	if (!is_ch_dfs || sap_ctx->pre_cac_complete ||
+	    mac_ctx->sap.SapDfsInfo.ignore_cac ||
+	    (mac_ctx->sap.SapDfsInfo.cac_state == eSAP_DFS_SKIP_CAC))
+		cac_required = false;
+	else
+		cac_required = true;
+
+	mlme_set_cac_required(sap_ctx->vdev, cac_required);
+}
+#else
+static inline void
+wlansap_set_cac_required_for_chan(struct mac_context *mac_ctx,
+				  struct sap_context *sap_ctx)
+{
+}
+#endif
+
 QDF_STATUS wlansap_channel_change_request(struct sap_context *sap_ctx,
 					  uint8_t target_channel)
 {
@@ -1831,6 +1879,7 @@ QDF_STATUS wlansap_channel_change_request(struct sap_context *sap_ctx,
 	sap_ctx->csr_roamProfile.ch_params.center_freq_seg1 =
 						ch_params->center_freq_seg1;
 	sap_dfs_set_current_channel(sap_ctx);
+	wlansap_set_cac_required_for_chan(mac_ctx, sap_ctx);
 
 	status = sme_roam_channel_change_req(MAC_HANDLE(mac_ctx),
 					     sap_ctx->bssid,