Преглед изворни кода

qcacld-3.0: Add serialization command to get disconnect stats

Currently for SAP case on the disconnection with the
client, host driver sends get stats command for the
disconnected peer to the FW and proceeds with the peer
deletion. There is a race condition where if the peer
gets deleted in the object manager before FW sends the
requested stats in that case host driver drops the
response from the FW.

To resolve above issue send the get stats request command
in serialization before peer delete command gets serialized
which will ensure that get stats response is processed
before peer delete in the object manager.

Change-Id: I1aa4be329a06e261222c0f9dccc36e08bd6b137a
CRs-Fixed:  2656842
Ashish Kumar Dhanotiya пре 5 година
родитељ
комит
e98592f479

+ 2 - 0
core/sme/inc/sme_api.h

@@ -121,6 +121,8 @@
 #define SME_CMD_PEER_DISCONNECT_TIMEOUT (SIR_DELETE_STA_TIMEOUT + 1000)
 #define SME_CMD_PEER_DISCONNECT_TIMEOUT (SIR_DELETE_STA_TIMEOUT + 1000)
 #define SME_PEER_DISCONNECT_TIMEOUT (SME_CMD_PEER_DISCONNECT_TIMEOUT + 1000)
 #define SME_PEER_DISCONNECT_TIMEOUT (SME_CMD_PEER_DISCONNECT_TIMEOUT + 1000)
 
 
+#define SME_CMD_GET_DISCONNECT_STATS_TIMEOUT 200
+
 /* Roam cmds timeout = vdev start + peer assoc + 1 sec */
 /* Roam cmds timeout = vdev start + peer assoc + 1 sec */
 #define SME_CMD_ROAM_CMD_TIMEOUT (START_RESPONSE_TIMER + \
 #define SME_CMD_ROAM_CMD_TIMEOUT (START_RESPONSE_TIMER + \
 				  SIR_PEER_ASSOC_TIMEOUT + 1000)
 				  SIR_PEER_ASSOC_TIMEOUT + 1000)

+ 32 - 0
core/sme/inc/sme_inside.h

@@ -80,6 +80,15 @@ struct s_nss_update_cmd {
 	uint32_t original_vdev_id;
 	uint32_t original_vdev_id;
 };
 };
 
 
+/**
+ * struct sir_disconnect_stats_cmd: command structure to get disconnect stats
+ * @peer_mac_addr: MAC address of the peer disconnected
+ *
+ */
+struct sir_disconnect_stats_cmd {
+	struct qdf_mac_addr peer_mac_addr;
+};
+
 typedef struct tagSmeCmd {
 typedef struct tagSmeCmd {
 	tListElem Link;
 	tListElem Link;
 	eSmeCommandType command;
 	eSmeCommandType command;
@@ -94,6 +103,7 @@ typedef struct tagSmeCmd {
 		struct s_nss_update_cmd nss_update_cmd;
 		struct s_nss_update_cmd nss_update_cmd;
 		struct policy_mgr_dual_mac_config set_dual_mac_cmd;
 		struct policy_mgr_dual_mac_config set_dual_mac_cmd;
 		struct sir_antenna_mode_param set_antenna_mode_cmd;
 		struct sir_antenna_mode_param set_antenna_mode_cmd;
+		struct sir_disconnect_stats_cmd disconnect_stats_cmd;
 	} u;
 	} u;
 } tSmeCmd;
 } tSmeCmd;
 
 
@@ -144,6 +154,28 @@ void csr_roam_wm_status_change_complete(struct mac_context *mac_ctx,
 					uint8_t session_id);
 					uint8_t session_id);
 void csr_roam_process_wm_status_change_command(struct mac_context *mac,
 void csr_roam_process_wm_status_change_command(struct mac_context *mac,
 		tSmeCmd *pCommand);
 		tSmeCmd *pCommand);
+
+/**
+ * csr_roam_get_disconnect_stats_complete() - Remove get disconnect stats
+ * command from SME active command list
+ * @mac_ctx: global mac context
+ * This API removes get disconnect stats command from SME active command list
+ * if present.
+ *
+ * Return: void
+ */
+void csr_roam_get_disconnect_stats_complete(struct mac_context *mac_ctx);
+
+/**
+ * csr_roam_process_get_disconnect_stats_command() - Process get disconnect
+ * stats
+ * @mac_ctx: global mac context
+ * @pCommand: Command to be processed
+ *
+ * Return: void
+ */
+void csr_roam_process_get_disconnect_stats_command(struct mac_context *mac,
+						   tSmeCmd *cmd);
 void csr_reinit_roam_cmd(struct mac_context *mac, tSmeCmd *pCommand);
 void csr_reinit_roam_cmd(struct mac_context *mac, tSmeCmd *pCommand);
 void csr_reinit_wm_status_change_cmd(struct mac_context *mac,
 void csr_reinit_wm_status_change_cmd(struct mac_context *mac,
 				     tSmeCmd *pCommand);
 				     tSmeCmd *pCommand);

+ 1 - 0
core/sme/inc/sme_internal.h

@@ -51,6 +51,7 @@ typedef enum eSmeCommandType {
 	eSmeCsrCommandMask = 0x10000,
 	eSmeCsrCommandMask = 0x10000,
 	eSmeCommandRoam,
 	eSmeCommandRoam,
 	eSmeCommandWmStatusChange,
 	eSmeCommandWmStatusChange,
+	eSmeCommandGetdisconnectStats,
 	/* QOS */
 	/* QOS */
 	eSmeQosCommandMask = 0x40000,   /* To identify Qos commands */
 	eSmeQosCommandMask = 0x40000,   /* To identify Qos commands */
 	eSmeCommandAddTs,
 	eSmeCommandAddTs,

+ 5 - 0
core/sme/src/common/sme_api.c

@@ -518,6 +518,11 @@ QDF_STATUS sme_ser_handle_active_cmd(struct wlan_serialization_command *cmd)
 		csr_roam_process_wm_status_change_command(mac_ctx,
 		csr_roam_process_wm_status_change_command(mac_ctx,
 					sme_cmd);
 					sme_cmd);
 		break;
 		break;
+	case eSmeCommandGetdisconnectStats:
+		csr_roam_process_get_disconnect_stats_command(mac_ctx,
+							      sme_cmd);
+		break;
+
 	case eSmeCommandAddTs:
 	case eSmeCommandAddTs:
 	case eSmeCommandDelTs:
 	case eSmeCommandDelTs:
 #ifndef WLAN_MDM_CODE_REDUCTION_OPT
 #ifndef WLAN_MDM_CODE_REDUCTION_OPT

+ 89 - 14
core/sme/src/csr/csr_api_roam.c

@@ -4164,6 +4164,26 @@ csr_is_deauth_disassoc_already_active(struct mac_context *mac_ctx,
 	return ret;
 	return ret;
 }
 }
 
 
+static void csr_roam_issue_disconnect_stats(struct mac_context *mac,
+					    uint32_t session_id,
+					    struct qdf_mac_addr peer_mac)
+{
+	tSmeCmd *cmd;
+
+	cmd = csr_get_command_buffer(mac);
+	if (!cmd) {
+		sme_err(" fail to get command buffer");
+		return;
+	}
+
+	cmd->command = eSmeCommandGetdisconnectStats;
+	cmd->vdev_id = session_id;
+	qdf_mem_copy(&cmd->u.disconnect_stats_cmd.peer_mac_addr, &peer_mac,
+		     QDF_MAC_ADDR_SIZE);
+	if (QDF_IS_STATUS_ERROR(csr_queue_sme_command(mac, cmd, true)))
+		sme_err("fail to queue get disconnect stats");
+}
+
 /**
 /**
  * csr_roam_issue_disassociate_sta_cmd() - disassociate a associated station
  * csr_roam_issue_disassociate_sta_cmd() - disassociate a associated station
  * @sessionId:     Session Id for Soft AP
  * @sessionId:     Session Id for Soft AP
@@ -4200,6 +4220,11 @@ QDF_STATUS csr_roam_issue_disassociate_sta_cmd(struct mac_context *mac,
 				sizeof(pCommand->u.roamCmd.peerMac));
 				sizeof(pCommand->u.roamCmd.peerMac));
 		pCommand->u.roamCmd.reason =
 		pCommand->u.roamCmd.reason =
 			(tSirMacReasonCodes)p_del_sta_params->reason_code;
 			(tSirMacReasonCodes)p_del_sta_params->reason_code;
+
+		csr_roam_issue_disconnect_stats(
+					mac, sessionId,
+					p_del_sta_params->peerMacAddr);
+
 		status = csr_queue_sme_command(mac, pCommand, true);
 		status = csr_queue_sme_command(mac, pCommand, true);
 		if (!QDF_IS_STATUS_SUCCESS(status))
 		if (!QDF_IS_STATUS_SUCCESS(status))
 			sme_err("fail to send message status: %d", status);
 			sme_err("fail to send message status: %d", status);
@@ -4242,6 +4267,10 @@ QDF_STATUS csr_roam_issue_deauth_sta_cmd(struct mac_context *mac,
 			     sizeof(tSirMacAddr));
 			     sizeof(tSirMacAddr));
 		pCommand->u.roamCmd.reason =
 		pCommand->u.roamCmd.reason =
 			(tSirMacReasonCodes)pDelStaParams->reason_code;
 			(tSirMacReasonCodes)pDelStaParams->reason_code;
+
+		csr_roam_issue_disconnect_stats(mac, sessionId,
+						pDelStaParams->peerMacAddr);
+
 		status = csr_queue_sme_command(mac, pCommand, true);
 		status = csr_queue_sme_command(mac, pCommand, true);
 		if (!QDF_IS_STATUS_SUCCESS(status))
 		if (!QDF_IS_STATUS_SUCCESS(status))
 			sme_err("fail to send message status: %d", status);
 			sme_err("fail to send message status: %d", status);
@@ -6318,19 +6347,22 @@ static void csr_get_peer_rssi_cb(struct stats_event *ev, void *cookie)
 	struct mac_context *mac = (struct mac_context *)cookie;
 	struct mac_context *mac = (struct mac_context *)cookie;
 
 
 	if (!mac)
 	if (!mac)
-		return;
+		goto disconnect_stats_complete;
 	if (!ev->peer_stats) {
 	if (!ev->peer_stats) {
 		sme_debug("%s no peer stats\n", __func__);
 		sme_debug("%s no peer stats\n", __func__);
-		return;
+		goto disconnect_stats_complete;
 	}
 	}
 	mac->peer_rssi = ev->peer_stats->peer_rssi;
 	mac->peer_rssi = ev->peer_stats->peer_rssi;
 	mac->peer_txrate = ev->peer_stats->tx_rate;
 	mac->peer_txrate = ev->peer_stats->tx_rate;
 	mac->peer_rxrate = ev->peer_stats->rx_rate;
 	mac->peer_rxrate = ev->peer_stats->rx_rate;
 	if (!ev->peer_extended_stats) {
 	if (!ev->peer_extended_stats) {
 		sme_debug("%s no peer extended stats\n", __func__);
 		sme_debug("%s no peer extended stats\n", __func__);
-		return;
+		goto disconnect_stats_complete;
 	}
 	}
 	mac->rx_mc_bc_cnt = ev->peer_extended_stats->rx_mc_bc_cnt;
 	mac->rx_mc_bc_cnt = ev->peer_extended_stats->rx_mc_bc_cnt;
+
+disconnect_stats_complete:
+	csr_roam_get_disconnect_stats_complete(mac);
 }
 }
 
 
 static void csr_get_peer_rssi(struct mac_context *mac, uint32_t session_id,
 static void csr_get_peer_rssi(struct mac_context *mac, uint32_t session_id,
@@ -6368,7 +6400,6 @@ QDF_STATUS csr_roam_process_command(struct mac_context *mac, tSmeCmd *pCommand)
 	QDF_STATUS lock_status, status = QDF_STATUS_SUCCESS;
 	QDF_STATUS lock_status, status = QDF_STATUS_SUCCESS;
 	uint32_t sessionId = pCommand->vdev_id;
 	uint32_t sessionId = pCommand->vdev_id;
 	struct csr_roam_session *pSession = CSR_GET_SESSION(mac, sessionId);
 	struct csr_roam_session *pSession = CSR_GET_SESSION(mac, sessionId);
-	struct qdf_mac_addr peer_mac;
 
 
 	if (!pSession) {
 	if (!pSession) {
 		sme_err("session %d not found", sessionId);
 		sme_err("session %d not found", sessionId);
@@ -6457,10 +6488,6 @@ QDF_STATUS csr_roam_process_command(struct mac_context *mac, tSmeCmd *pCommand)
 		sme_debug("Disassociate issued with reason: %d",
 		sme_debug("Disassociate issued with reason: %d",
 			pCommand->u.roamCmd.reason);
 			pCommand->u.roamCmd.reason);
 
 
-		qdf_mem_copy(&peer_mac, &pCommand->u.roamCmd.peerMac,
-			     QDF_MAC_ADDR_SIZE);
-		csr_get_peer_rssi(mac, sessionId, peer_mac);
-
 		status = csr_send_mb_disassoc_req_msg(mac, sessionId,
 		status = csr_send_mb_disassoc_req_msg(mac, sessionId,
 				pCommand->u.roamCmd.peerMac,
 				pCommand->u.roamCmd.peerMac,
 				pCommand->u.roamCmd.reason);
 				pCommand->u.roamCmd.reason);
@@ -6474,10 +6501,6 @@ QDF_STATUS csr_roam_process_command(struct mac_context *mac, tSmeCmd *pCommand)
 		sme_debug("Deauth issued with reason: %d",
 		sme_debug("Deauth issued with reason: %d",
 			  pCommand->u.roamCmd.reason);
 			  pCommand->u.roamCmd.reason);
 
 
-		qdf_mem_copy(&peer_mac, &pCommand->u.roamCmd.peerMac,
-			     QDF_MAC_ADDR_SIZE);
-		csr_get_peer_rssi(mac, sessionId, peer_mac);
-
 		status = csr_send_mb_deauth_req_msg(mac, sessionId,
 		status = csr_send_mb_deauth_req_msg(mac, sessionId,
 				pCommand->u.roamCmd.peerMac,
 				pCommand->u.roamCmd.peerMac,
 				pCommand->u.roamCmd.reason);
 				pCommand->u.roamCmd.reason);
@@ -11408,6 +11431,12 @@ bool csr_roam_issue_wm_status_change(struct mac_context *mac, uint32_t sessionId
 {
 {
 	bool fCommandQueued = false;
 	bool fCommandQueued = false;
 	tSmeCmd *pCommand;
 	tSmeCmd *pCommand;
+	struct qdf_mac_addr peer_mac;
+	struct csr_roam_session *session;
+
+	session = CSR_GET_SESSION(mac, sessionId);
+	if (!session)
+		return false;
 
 
 	do {
 	do {
 		/* Validate the type is ok... */
 		/* Validate the type is ok... */
@@ -11433,12 +11462,24 @@ bool csr_roam_issue_wm_status_change(struct mac_context *mac, uint32_t sessionId
 				     DisassocIndMsg, pSmeRsp,
 				     DisassocIndMsg, pSmeRsp,
 				     sizeof(pCommand->u.wmStatusChangeCmd.u.
 				     sizeof(pCommand->u.wmStatusChangeCmd.u.
 					    DisassocIndMsg));
 					    DisassocIndMsg));
+			qdf_mem_copy(&peer_mac, &pCommand->u.wmStatusChangeCmd.
+						u.DisassocIndMsg.peer_macaddr,
+				     QDF_MAC_ADDR_SIZE);
+
 		} else {
 		} else {
 			qdf_mem_copy(&pCommand->u.wmStatusChangeCmd.u.
 			qdf_mem_copy(&pCommand->u.wmStatusChangeCmd.u.
 				     DeauthIndMsg, pSmeRsp,
 				     DeauthIndMsg, pSmeRsp,
 				     sizeof(pCommand->u.wmStatusChangeCmd.u.
 				     sizeof(pCommand->u.wmStatusChangeCmd.u.
 					    DeauthIndMsg));
 					    DeauthIndMsg));
+			qdf_mem_copy(&peer_mac, &pCommand->u.wmStatusChangeCmd.
+						u.DeauthIndMsg.peer_macaddr,
+				     QDF_MAC_ADDR_SIZE);
 		}
 		}
+
+		if (CSR_IS_INFRA_AP(&session->connectedProfile))
+			csr_roam_issue_disconnect_stats(mac, sessionId,
+							peer_mac);
+
 		if (QDF_IS_STATUS_SUCCESS
 		if (QDF_IS_STATUS_SUCCESS
 			    (csr_queue_sme_command(mac, pCommand, false)))
 			    (csr_queue_sme_command(mac, pCommand, false)))
 			fCommandQueued = true;
 			fCommandQueued = true;
@@ -13345,8 +13386,6 @@ QDF_STATUS csr_roam_lost_link(struct mac_context *mac, uint32_t sessionId,
 	mlme_set_discon_reason_n_from_ap(mac->psoc, sessionId, from_ap,
 	mlme_set_discon_reason_n_from_ap(mac->psoc, sessionId, from_ap,
 				      pSession->joinFailStatusCode.reasonCode);
 				      pSession->joinFailStatusCode.reasonCode);
 
 
-	if (type == eWNI_SME_DISASSOC_IND || type == eWNI_SME_DEAUTH_IND)
-		csr_get_peer_rssi(mac, sessionId, roam_info->peerMac);
 
 
 	csr_roam_call_callback(mac, sessionId, NULL, 0,
 	csr_roam_call_callback(mac, sessionId, NULL, 0,
 			       eCSR_ROAM_LOSTLINK_DETECTED, result);
 			       eCSR_ROAM_LOSTLINK_DETECTED, result);
@@ -13380,6 +13419,28 @@ QDF_STATUS csr_roam_lost_link(struct mac_context *mac, uint32_t sessionId,
 	return status;
 	return status;
 }
 }
 
 
+void csr_roam_get_disconnect_stats_complete(struct mac_context *mac)
+{
+	tListElem *entry;
+	tSmeCmd *cmd;
+
+	entry = csr_nonscan_active_ll_peek_head(mac, LL_ACCESS_LOCK);
+	if (!entry) {
+		sme_err("NO commands are ACTIVE ...");
+		return;
+	}
+
+	cmd = GET_BASE_ADDR(entry, tSmeCmd, Link);
+	if (cmd->command != eSmeCommandGetdisconnectStats) {
+		sme_err("Get disconn stats cmd is not ACTIVE ...");
+		return;
+	}
+
+	if (csr_nonscan_active_ll_remove_entry(mac, entry, LL_ACCESS_LOCK))
+		csr_release_command(mac, cmd);
+	else
+		sme_err("Failed to release command");
+}
 
 
 void csr_roam_wm_status_change_complete(struct mac_context *mac,
 void csr_roam_wm_status_change_complete(struct mac_context *mac,
 					uint8_t session_id)
 					uint8_t session_id)
@@ -13407,6 +13468,13 @@ void csr_roam_wm_status_change_complete(struct mac_context *mac,
 	}
 	}
 }
 }
 
 
+void csr_roam_process_get_disconnect_stats_command(struct mac_context *mac,
+						   tSmeCmd *cmd)
+{
+	csr_get_peer_rssi(mac, cmd->vdev_id,
+			  cmd->u.disconnect_stats_cmd.peer_mac_addr);
+}
+
 void csr_roam_process_wm_status_change_command(
 void csr_roam_process_wm_status_change_command(
 		struct mac_context *mac, tSmeCmd *pCommand)
 		struct mac_context *mac, tSmeCmd *pCommand)
 {
 {
@@ -19783,6 +19851,9 @@ enum wlan_serialization_cmd_type csr_get_cmd_type(tSmeCmd *sme_cmd)
 	case eSmeCommandWmStatusChange:
 	case eSmeCommandWmStatusChange:
 		cmd_type = WLAN_SER_CMD_WM_STATUS_CHANGE;
 		cmd_type = WLAN_SER_CMD_WM_STATUS_CHANGE;
 		break;
 		break;
+	case eSmeCommandGetdisconnectStats:
+		cmd_type =  WLAN_SER_CMD_GET_DISCONNECT_STATS;
+		break;
 	case eSmeCommandAddTs:
 	case eSmeCommandAddTs:
 		cmd_type = WLAN_SER_CMD_ADDTS;
 		cmd_type = WLAN_SER_CMD_ADDTS;
 		break;
 		break;
@@ -19838,6 +19909,10 @@ static void csr_fill_cmd_timeout(struct wlan_serialization_command *cmd)
 	case WLAN_SER_CMD_FORCE_DEAUTH_STA:
 	case WLAN_SER_CMD_FORCE_DEAUTH_STA:
 		cmd->cmd_timeout_duration = SME_CMD_PEER_DISCONNECT_TIMEOUT;
 		cmd->cmd_timeout_duration = SME_CMD_PEER_DISCONNECT_TIMEOUT;
 		break;
 		break;
+	case WLAN_SER_CMD_GET_DISCONNECT_STATS:
+		cmd->cmd_timeout_duration =
+					SME_CMD_GET_DISCONNECT_STATS_TIMEOUT;
+		break;
 	case WLAN_SER_CMD_HDD_ISSUE_REASSOC_SAME_AP:
 	case WLAN_SER_CMD_HDD_ISSUE_REASSOC_SAME_AP:
 	case WLAN_SER_CMD_SME_ISSUE_REASSOC_SAME_AP:
 	case WLAN_SER_CMD_SME_ISSUE_REASSOC_SAME_AP:
 	case WLAN_SER_CMD_SME_ISSUE_DISASSOC_FOR_HANDOFF:
 	case WLAN_SER_CMD_SME_ISSUE_DISASSOC_FOR_HANDOFF: