Эх сурвалжийг харах

qcacmn: Drop disconnect req in INIT state

In case the vdev is already disconnected, the indication to
the upper layer, would have been sent as part of previous
disconnect/connect failure.

If the upper layer is in process of connecting, sending
the disconnect indication back again may cause it to incorrectly
think it as connect failure. So sending a disconnect indication
again is not advisable.

So if a new disconnect is received in INIT state, drop the
disconnect and return failure.

Also remove osif_cm_reset_id_and_src() from osif disconnect
to avoid race between disconnect complete of old disconnect
and new disconnect request. With osif_cm_reset_id_and_src()
old disconnect might also get dropped in osif and with this
fix new disconnect will also get dropped, so make sure that
last/old disconnect indication is sent to upper layer.

Change-Id: Icf7352d8904473329edff9ec124c6197f214f88b
CRs-Fixed: 3074093
Abhishek Singh 3 жил өмнө
parent
commit
3915bd37fb

+ 2 - 15
os_if/linux/mlme/src/osif_cm_req.c

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2012-2015,2020-2021 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -554,20 +555,6 @@ connect_start_fail:
 	return qdf_status_to_os_return(status);
 }
 
-static QDF_STATUS osif_cm_send_disconnect(struct wlan_objmgr_vdev *vdev,
-					  uint16_t reason)
-{
-	QDF_STATUS status;
-
-	status = osif_cm_reset_id_and_src(vdev);
-	if (QDF_IS_STATUS_ERROR(status))
-		return qdf_status_to_os_return(status);
-
-	status = mlo_disconnect(vdev, CM_OSIF_DISCONNECT, reason, NULL);
-
-	return status;
-}
-
 int osif_cm_disconnect(struct net_device *dev, struct wlan_objmgr_vdev *vdev,
 		       uint16_t reason)
 {
@@ -578,7 +565,7 @@ int osif_cm_disconnect(struct net_device *dev, struct wlan_objmgr_vdev *vdev,
 		  dev->name, vdev_id, reason,
 		  ucfg_cm_reason_code_to_str(reason));
 
-	status = osif_cm_send_disconnect(vdev, reason);
+	status = mlo_disconnect(vdev, CM_OSIF_DISCONNECT, reason, NULL);
 	if (QDF_IS_STATUS_ERROR(status))
 		osif_err("Disconnect failed with status %d", status);
 

+ 17 - 0
umac/mlme/connection_mgr/core/src/wlan_cm_disconnect.c

@@ -602,6 +602,23 @@ cm_handle_discon_req_in_non_connected_state(struct cnx_mgr *cm_ctx,
 		cm_flush_pending_request(cm_ctx, CONNECT_REQ_PREFIX, false);
 		cm_flush_pending_request(cm_ctx, DISCONNECT_REQ_PREFIX, false);
 		break;
+	case WLAN_CM_S_INIT:
+		/*
+		 * In this case the vdev is already disconnected and thus the
+		 * indication to upper layer, would have been sent as part of
+		 * previous disconnect/connect failure.
+		 *
+		 * If upper layer is in process of connecting, sending
+		 * disconnect indication back again may cause it to incorrectly
+		 * think it as a connect failure. So sending disconnect
+		 * indication again is not advisable.
+		 *
+		 * So no need to do anything here, just return failure and drop
+		 * disconnect.
+		 */
+		mlme_info("vdev %d droping disconnect req from source %d in INIT state",
+			  wlan_vdev_get_id(cm_ctx->vdev), cm_req->req.source);
+		return QDF_STATUS_E_ALREADY;
 	default:
 		mlme_err("Vdev %d disconnect req in invalid state %d",
 			 wlan_vdev_get_id(cm_ctx->vdev),

+ 8 - 10
umac/mlme/connection_mgr/core/src/wlan_cm_sm.c

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2012-2015,2020-2021 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -92,7 +93,6 @@ static bool cm_state_init_event(void *ctx, uint16_t event,
 	struct cnx_mgr *cm_ctx = ctx;
 	bool event_handled = true;
 	QDF_STATUS status;
-	struct cm_disconnect_req *req;
 
 	switch (event) {
 	case WLAN_CM_SM_EV_CONNECT_REQ:
@@ -113,15 +113,13 @@ static bool cm_state_init_event(void *ctx, uint16_t event,
 		cm_disconnect_complete(cm_ctx, data);
 		break;
 	case WLAN_CM_SM_EV_DISCONNECT_REQ:
-		status = cm_add_disconnect_req_to_list(cm_ctx, data);
-		if (QDF_IS_STATUS_ERROR(status)) {
-			/* if fail to add req return failure */
-			event_handled = false;
-			break;
-		}
-
-		req = data;
-		cm_send_disconnect_resp(cm_ctx, req->cm_id);
+		cm_handle_discon_req_in_non_connected_state(cm_ctx, data,
+							    WLAN_CM_S_INIT);
+		/*
+		 * Return not handled as this req need to be dropped and return
+		 * failure to the requester
+		 */
+		event_handled = false;
 		break;
 	default:
 		event_handled = false;