Browse Source

qcacld-3.0: Remove peer disconnect command from serialization

Consider a case when CSA happens and south bound disconnect
command(WLAN_SER_CMD_WM_STATUS_CHANGE) got queue in serialization
at same time. Later peer tries to connect and south bound
diconnect command becomes active for same peer.

As part of CSA, peer gets deleted directly without going through
serializtion. So when south bound disconnection command becomes
active, it may lead to race where peer tries to connect and
driver tries to disconnect the same peer which may cause
deauth/disconnect(WLAN_SER_CMD_WM_STATUS_CHANGE) active command
timeout.

As part of fix, flush all peer disconnect/deauth pending commands
from serialization during CSA.

Change-Id: I9b0af7deb7f2123850f3535f2d3258440af381f1
CRs-Fixed: 3148874
Jyoti Kumari 3 years ago
parent
commit
930f8637fb
2 changed files with 107 additions and 17 deletions
  1. 76 16
      core/mac/src/pe/lim/lim_process_sme_req_messages.c
  2. 31 1
      core/sme/src/common/sme_api.c

+ 76 - 16
core/mac/src/pe/lim/lim_process_sme_req_messages.c

@@ -5624,10 +5624,11 @@ void __lim_process_sme_disassoc_cnf(struct mac_context *mac, uint32_t *msg_buf)
 
 	if (!lim_is_sme_disassoc_cnf_valid(mac, &smeDisassocCnf, pe_session)) {
 		pe_err("received invalid SME_DISASSOC_CNF message");
-		status = lim_prepare_disconnect_done_ind(mac, &msg,
-						pe_session->smeSessionId,
-						eSIR_SME_INVALID_PARAMETERS,
-						&smeDisassocCnf.bssid.bytes[0]);
+		status = lim_prepare_disconnect_done_ind(
+					mac, &msg,
+					pe_session->smeSessionId,
+					eSIR_SME_INVALID_PARAMETERS,
+					&smeDisassocCnf.peer_macaddr.bytes[0]);
 		if (QDF_IS_STATUS_SUCCESS(status))
 			lim_send_sme_disassoc_deauth_ntf(mac,
 							 QDF_STATUS_SUCCESS,
@@ -5661,10 +5662,11 @@ void __lim_process_sme_disassoc_cnf(struct mac_context *mac, uint32_t *msg_buf)
 				pe_session->limSmeState);
 			lim_print_sme_state(mac, LOGE,
 					    pe_session->limSmeState);
-			status = lim_prepare_disconnect_done_ind(mac, &msg,
-						pe_session->smeSessionId,
-						eSIR_SME_INVALID_STATE,
-						&smeDisassocCnf.bssid.bytes[0]);
+			status = lim_prepare_disconnect_done_ind(
+					mac, &msg,
+					pe_session->smeSessionId,
+					eSIR_SME_INVALID_STATE,
+					&smeDisassocCnf.peer_macaddr.bytes[0]);
 			if (QDF_IS_STATUS_SUCCESS(status))
 				lim_send_sme_disassoc_deauth_ntf(mac,
 							QDF_STATUS_SUCCESS,
@@ -5679,10 +5681,11 @@ void __lim_process_sme_disassoc_cnf(struct mac_context *mac, uint32_t *msg_buf)
 	default:                /* eLIM_UNKNOWN_ROLE */
 		pe_err("received unexpected SME_DISASSOC_CNF role %d",
 			GET_LIM_SYSTEM_ROLE(pe_session));
-		status = lim_prepare_disconnect_done_ind(mac, &msg,
-						pe_session->smeSessionId,
-						eSIR_SME_INVALID_STATE,
-						&smeDisassocCnf.bssid.bytes[0]);
+		status = lim_prepare_disconnect_done_ind(
+					mac, &msg,
+					pe_session->smeSessionId,
+					eSIR_SME_INVALID_STATE,
+					&smeDisassocCnf.peer_macaddr.bytes[0]);
 		if (QDF_IS_STATUS_SUCCESS(status))
 			lim_send_sme_disassoc_deauth_ntf(mac,
 							 QDF_STATUS_SUCCESS,
@@ -5700,10 +5703,11 @@ void __lim_process_sme_disassoc_cnf(struct mac_context *mac, uint32_t *msg_buf)
 			pe_err("DISASSOC_CNF for a STA with no context, addr= "
 				QDF_MAC_ADDR_FMT,
 				QDF_MAC_ADDR_REF(smeDisassocCnf.peer_macaddr.bytes));
-			status = lim_prepare_disconnect_done_ind(mac, &msg,
-						pe_session->smeSessionId,
-						eSIR_SME_INVALID_PARAMETERS,
-						&smeDisassocCnf.bssid.bytes[0]);
+			status = lim_prepare_disconnect_done_ind(
+					mac, &msg,
+					pe_session->smeSessionId,
+					eSIR_SME_INVALID_PARAMETERS,
+					&smeDisassocCnf.peer_macaddr.bytes[0]);
 			if (QDF_IS_STATUS_SUCCESS(status))
 				lim_send_sme_disassoc_deauth_ntf(mac,
 							QDF_STATUS_SUCCESS,
@@ -5974,6 +5978,51 @@ void lim_send_stop_bss_failure_resp(struct mac_context *mac_ctx,
 #endif
 }
 
+static void lim_flush_all_peer_from_serialization_queue(
+				struct mac_context *mac_ctx,
+				struct pe_session *session)
+{
+	struct wlan_serialization_queued_cmd_info cmd = {0};
+	struct wlan_objmgr_vdev *vdev;
+
+	vdev = session->vdev;
+	if (!vdev) {
+		pe_err("vdev is null");
+		return;
+	}
+
+	pe_debug("vdev id is %d for disconnect/deauth cmd", session->vdev_id);
+
+	/* Flush any pending NB peer deauth command */
+	cmd.vdev = vdev;
+	cmd.cmd_type = WLAN_SER_CMD_FORCE_DEAUTH_STA;
+	cmd.req_type = WLAN_SER_CANCEL_VDEV_NON_SCAN_CMD_TYPE;
+	cmd.requestor = WLAN_UMAC_COMP_MLME;
+	cmd.queue_type = WLAN_SERIALIZATION_PENDING_QUEUE;
+
+	wlan_serialization_cancel_request(&cmd);
+
+	/* Flush any pending NB peer disassoc command */
+	qdf_mem_zero(&cmd, sizeof(cmd));
+	cmd.vdev = vdev;
+	cmd.cmd_type = WLAN_SER_CMD_FORCE_DISASSOC_STA;
+	cmd.req_type = WLAN_SER_CANCEL_VDEV_NON_SCAN_CMD_TYPE;
+	cmd.requestor = WLAN_UMAC_COMP_MLME;
+	cmd.queue_type = WLAN_SERIALIZATION_PENDING_QUEUE;
+
+	wlan_serialization_cancel_request(&cmd);
+
+	/* Flush any pending SB peer deauth/disconnect command */
+	qdf_mem_zero(&cmd, sizeof(cmd));
+	cmd.vdev = vdev;
+	cmd.cmd_type = WLAN_SER_CMD_WM_STATUS_CHANGE;
+	cmd.req_type = WLAN_SER_CANCEL_VDEV_NON_SCAN_CMD_TYPE;
+	cmd.requestor = WLAN_UMAC_COMP_MLME;
+	cmd.queue_type = WLAN_SERIALIZATION_PENDING_QUEUE;
+
+	wlan_serialization_cancel_request(&cmd);
+}
+
 void lim_delete_all_peers(struct pe_session *session)
 {
 	uint8_t i = 0;
@@ -6015,6 +6064,17 @@ void lim_delete_all_peers(struct pe_session *session)
 			QDF_ASSERT(0);
 		}
 	}
+
+	/**
+	 * Scenario: CSA happens and south bound disconnection got queued
+	 * in serialization parallelly.
+	 * As part of CSA, remove all peer from serialization, so that when
+	 * south bound disconnection becomes active, it should not lead to a
+	 * race where the peer is trying to connect and the driver is trying
+	 * to disconnect the same peer, leading to an active command timeout
+	 */
+	lim_flush_all_peer_from_serialization_queue(mac_ctx, session);
+
 	lim_disconnect_complete(session, false);
 	if (mac_ctx->del_peers_ind_cb)
 		mac_ctx->del_peers_ind_cb(mac_ctx->psoc, session->vdev_id);

+ 31 - 1
core/sme/src/common/sme_api.c

@@ -549,6 +549,34 @@ QDF_STATUS sme_ser_handle_active_cmd(struct wlan_serialization_command *cmd)
 	return status;
 }
 
+static void sme_dump_peer_disconnect_timeout_info(tSmeCmd *sme_cmd)
+{
+	struct wmstatus_changecmd *wms_cmd;
+	struct qdf_mac_addr peer_macaddr = QDF_MAC_ADDR_ZERO_INIT;
+
+	if (sme_cmd->command == eSmeCommandRoam &&
+	    (sme_cmd->u.roamCmd.roamReason == eCsrForcedDisassocSta ||
+	    sme_cmd->u.roamCmd.roamReason == eCsrForcedDeauthSta)) {
+		qdf_mem_copy(peer_macaddr.bytes, sme_cmd->u.roamCmd.peerMac,
+			     QDF_MAC_ADDR_SIZE);
+	} else if (sme_cmd->command == eSmeCommandWmStatusChange) {
+		wms_cmd = &sme_cmd->u.wmStatusChangeCmd;
+		if (wms_cmd->Type == eCsrDisassociated)
+			qdf_copy_macaddr(
+				&peer_macaddr,
+				&wms_cmd->u.DisassocIndMsg.peer_macaddr);
+		else if (wms_cmd->Type == eCsrDeauthenticated)
+			qdf_copy_macaddr(
+				&peer_macaddr,
+				&wms_cmd->u.DeauthIndMsg.peer_macaddr);
+	}
+
+	if (!qdf_is_macaddr_zero(&peer_macaddr))
+		sme_err("vdev %d cmd %d timeout for peer " QDF_MAC_ADDR_FMT,
+			sme_cmd->vdev_id, sme_cmd->command,
+			QDF_MAC_ADDR_REF(peer_macaddr.bytes));
+}
+
 QDF_STATUS sme_ser_cmd_callback(struct wlan_serialization_command *cmd,
 				enum wlan_serialization_cb_reason reason)
 {
@@ -588,9 +616,11 @@ QDF_STATUS sme_ser_cmd_callback(struct wlan_serialization_command *cmd,
 	case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT:
 		sme_cmd = cmd->umac_cmd;
 		if (sme_cmd && (sme_cmd->command == eSmeCommandRoam ||
-		    sme_cmd->command == eSmeCommandWmStatusChange))
+		    sme_cmd->command == eSmeCommandWmStatusChange)) {
+			sme_dump_peer_disconnect_timeout_info(sme_cmd);
 			qdf_trigger_self_recovery(mac_ctx->psoc,
 						  QDF_ACTIVE_LIST_TIMEOUT);
+		}
 		break;
 	default:
 		sme_debug("unknown reason code");