Kaynağa Gözat

qcacld-3.0: Disconnect the other sta vdev before vdev destroy

During vdev destroy, if any STA is in connecting state the
roam command will be in active queue and thus vdev destroy is
queued in pending queue. In case STA tries to connect to
multiple BSSID and fails to connect, due to auth/assoc
timeouts it may take more than vdev destroy time to get
completed. If vdev destroy timeout vdev is moved to logically
deleted state. Once connection is completed, vdev destroy is
activated and to release the self-peer ref count it try to
get the ref of the vdev, which fails as vdev is logically
deleted and this leads to peer ref leak.

So before vdev destroy is queued abort any STA ongoing connection
to avoid vdev destroy timeout.

Change-Id: Ibd1ea555616ba22179f3663a082f5281220ab918
CRs-Fixed: 2375712
Pragaspathi Thilagaraj 6 yıl önce
ebeveyn
işleme
e6f37e066e

+ 10 - 0
core/hdd/inc/wlan_hdd_assoc.h

@@ -278,6 +278,16 @@ enum band_info hdd_conn_get_connected_band(struct hdd_station_ctx *sta_ctx);
 struct hdd_adapter *hdd_get_sta_connection_in_progress(
 			struct hdd_context *hdd_ctx);
 
+/**
+ * hdd_abort_ongoing_sta_connection() - Disconnect the sta for which the
+ * connection is in progress.
+ *
+ * @hdd_ctx: hdd context
+ *
+ * Return: none
+ */
+void hdd_abort_ongoing_sta_connection(struct hdd_context *hdd_ctx);
+
 /**
  * hdd_sme_roam_callback() - hdd sme roam callback
  * @pContext: pointer to adapter context

+ 20 - 2
core/hdd/src/wlan_hdd_assoc.c

@@ -381,7 +381,7 @@ struct hdd_adapter *hdd_get_sta_connection_in_progress(
 		    (QDF_P2P_DEVICE_MODE == adapter->device_mode)) {
 			if (eConnectionState_Connecting ==
 			    hdd_sta_ctx->conn_info.connState) {
-				hdd_debug("session_id %d: Connection is in progress",
+				hdd_debug("vdev_id %d: Connection is in progress",
 					  adapter->session_id);
 				return adapter;
 			} else if ((eConnectionState_Associated ==
@@ -389,7 +389,7 @@ struct hdd_adapter *hdd_get_sta_connection_in_progress(
 				   sme_is_sta_key_exchange_in_progress(
 							hdd_ctx->mac_handle,
 							adapter->session_id)) {
-				hdd_debug("session_id %d: Key exchange is in progress",
+				hdd_debug("vdev_id %d: Key exchange is in progress",
 					  adapter->session_id);
 				return adapter;
 			}
@@ -398,6 +398,24 @@ struct hdd_adapter *hdd_get_sta_connection_in_progress(
 	return NULL;
 }
 
+void hdd_abort_ongoing_sta_connection(struct hdd_context *hdd_ctx)
+{
+	struct hdd_adapter *sta_adapter;
+	QDF_STATUS status;
+
+	sta_adapter = hdd_get_sta_connection_in_progress(hdd_ctx);
+	if (sta_adapter) {
+		hdd_debug("Disconnecting STA on vdev: %d",
+			  sta_adapter->session_id);
+		status = wlan_hdd_disconnect(sta_adapter,
+					     eCSR_DISCONNECT_REASON_DEAUTH);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			hdd_err("wlan_hdd_disconnect failed, status: %d",
+				status);
+		}
+	}
+}
+
 /**
  * hdd_remove_beacon_filter() - remove beacon filter
  * @adapter: Pointer to the hdd adapter

+ 3 - 15
core/hdd/src/wlan_hdd_hostapd.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2019 The Linux Foundation. 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
@@ -4720,7 +4720,6 @@ int wlan_hdd_cfg80211_start_bss(struct hdd_adapter *adapter,
 	bool MFPRequired = false;
 	uint16_t prev_rsn_length = 0;
 	enum dfs_mode mode;
-	struct hdd_adapter *sta_adapter;
 	bool ignore_cac = 0;
 	uint8_t is_overlap_enable = 0, scc_on_dfs_chan = 0;
 	uint8_t beacon_fixed_len, indoor_chnl_marking = 0;
@@ -4769,12 +4768,7 @@ int wlan_hdd_cfg80211_start_bss(struct hdd_adapter *adapter,
 	 * disconnect the STA interface first if connection or key exchange is
 	 * in progress and then start SAP interface.
 	 */
-	sta_adapter = hdd_get_sta_connection_in_progress(hdd_ctx);
-	if (sta_adapter) {
-		hdd_debug("Disconnecting STA with session id: %d",
-			  sta_adapter->session_id);
-		wlan_hdd_disconnect(sta_adapter, eCSR_DISCONNECT_REASON_DEAUTH);
-	}
+	hdd_abort_ongoing_sta_connection(hdd_ctx);
 
 	/*
 	 * Reject start bss if reassoc in progress on any adapter.
@@ -5520,7 +5514,6 @@ static int __wlan_hdd_cfg80211_stop_ap(struct wiphy *wiphy,
 					struct net_device *dev)
 {
 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
-	struct hdd_adapter *sta_adapter;
 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
 	QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE;
@@ -5571,12 +5564,7 @@ static int __wlan_hdd_cfg80211_stop_ap(struct wiphy *wiphy,
 	 * the STA and complete the SAP operation. STA will reconnect
 	 * after SAP stop is done.
 	 */
-	sta_adapter = hdd_get_sta_connection_in_progress(hdd_ctx);
-	if (sta_adapter) {
-		hdd_debug("Disconnecting STA with session id: %d",
-			  sta_adapter->session_id);
-		wlan_hdd_disconnect(sta_adapter, eCSR_DISCONNECT_REASON_DEAUTH);
-	}
+	hdd_abort_ongoing_sta_connection(hdd_ctx);
 
 	if (adapter->device_mode == QDF_SAP_MODE)
 		wlan_hdd_del_station(adapter);

+ 33 - 4
core/hdd/src/wlan_hdd_main.c

@@ -5453,10 +5453,22 @@ QDF_STATUS hdd_stop_adapter_ext(struct hdd_context *hdd_ctx,
 			}
 		}
 
-		if (wlan_hdd_try_disconnect(adapter)) {
-			hdd_err("Can't disconnect adapter");
-			return QDF_STATUS_E_FAILURE;
-		}
+		/*
+		 * During vdev destroy, if any STA is in connecting state the
+		 * roam command will be in active queue and thus vdev destroy is
+		 * queued in pending queue. In case STA tries to connect to
+		 * multiple BSSID and fails to connect, due to auth/assoc
+		 * timeouts it may take more than vdev destroy time to get
+		 * completed. On vdev destroy timeout vdev is moved to logically
+		 * deleted state. Once connection is completed, vdev destroy is
+		 * activated and to release the self-peer ref count it try to
+		 * get the ref of the vdev, which fails as vdev is logically
+		 * deleted and this leads to peer ref leak. So before vdev
+		 * destroy is queued abort any STA ongoing connection to avoid
+		 * vdev destroy timeout.
+		 */
+		if (test_bit(SME_SESSION_OPENED, &adapter->event_flags))
+			hdd_abort_ongoing_sta_connection(hdd_ctx);
 
 		hdd_vdev_destroy(adapter);
 		break;
@@ -5495,6 +5507,23 @@ QDF_STATUS hdd_stop_adapter_ext(struct hdd_context *hdd_ctx,
 		hdd_deregister_tx_flow_control(adapter);
 		hdd_destroy_acs_timer(adapter);
 
+		/**
+		 * During vdev destroy, If any STA is in connecting state the
+		 * roam command will be in active queue and thus vdev destroy is
+		 * queued in pending queue. In case STA is tries to connected to
+		 * multiple BSSID and fails to connect, due to auth/assoc
+		 * timeouts it may take more than vdev destroy time to get
+		 * completes. If vdev destroy timeout vdev is moved to logically
+		 * deleted state. Once connection is completed, vdev destroy is
+		 * activated and to release the self-peer ref count it try to
+		 * get the ref of the vdev, which fails as vdev is logically
+		 * deleted and this leads to peer ref leak. So before vdev
+		 * destroy is queued abort any STA ongoing connection to avoid
+		 * vdev destroy timeout.
+		 */
+		if (test_bit(SME_SESSION_OPENED, &adapter->event_flags))
+			hdd_abort_ongoing_sta_connection(hdd_ctx);
+
 		mutex_lock(&hdd_ctx->sap_lock);
 		if (test_bit(SOFTAP_BSS_STARTED, &adapter->event_flags)) {
 			status = wlansap_stop_bss(