Browse Source

qcacld-3.0: Fix deadlock when SAP interface down during pre_cac failure

While pre cac is in progress and if the SAP is stopped from UI, It may
lead to dead-lock due to rtnl lock. This is because, stopping SAP will
trigger the stop_ap first and then hostapd_stop. Stop_ap will schedule
a work to handle pre_cac failure (Thread1). hostapd_stop will be
triggered in parallel (Thread2). This will result in a below dead-lock
scenario.
   Thread1: Waiting to acquire rtnl_lock to unregister pre_cac adapter.
   Thread2: Acquired the rtnl_lock and waiting for Thread1 to complete

To resolve this dead-lock, unregister pre_cac_adapter during
hostapd_stop without requesting for rtnl_lock.

Change-Id: I222df9ee0d75b16f79c28b7cdd86369c340a15c2
CRs-Fixed: 2832256
Bapiraju Alla 4 years ago
parent
commit
549f5cb438

+ 2 - 0
core/hdd/inc/wlan_hdd_main.h

@@ -1521,6 +1521,8 @@ struct hdd_adapter {
 
 	qdf_work_t netdev_features_update_work;
 	uint8_t net_dev_hold_ref_count[NET_DEV_HOLD_ID_MAX];
+	/* Flag to indicate whether it is a pre cac adapter or not */
+	bool is_pre_cac_adapter;
 };
 
 #define WLAN_HDD_GET_STATION_CTX_PTR(adapter) (&(adapter)->session.station)

+ 0 - 6
core/hdd/src/wlan_hdd_hostapd.c

@@ -1082,9 +1082,7 @@ static void __wlan_hdd_sap_pre_cac_failure(struct hdd_adapter *adapter)
 	if (wlan_hdd_validate_context(hdd_ctx))
 		return;
 
-	wlan_hdd_release_intf_addr(hdd_ctx, adapter->mac_addr.bytes);
 	hdd_stop_adapter(hdd_ctx, adapter);
-	hdd_close_adapter(hdd_ctx, adapter, false);
 
 	hdd_exit();
 }
@@ -1107,13 +1105,10 @@ void wlan_hdd_sap_pre_cac_failure(void *data)
 	if (errno)
 		return;
 
-	osif_vdev_sync_unregister(adapter->dev);
-	osif_vdev_sync_wait_for_ops(vdev_sync);
 
 	__wlan_hdd_sap_pre_cac_failure(data);
 
 	osif_vdev_sync_trans_stop(vdev_sync);
-	osif_vdev_sync_destroy(vdev_sync);
 }
 
 /**
@@ -1141,7 +1136,6 @@ static void __wlan_hdd_sap_pre_cac_success(struct hdd_adapter *adapter)
 
 	wlan_hdd_release_intf_addr(hdd_ctx, adapter->mac_addr.bytes);
 	hdd_stop_adapter(hdd_ctx, adapter);
-	hdd_close_adapter(hdd_ctx, adapter, false);
 
 	/* Prepare to switch AP from 2.4GHz channel to the pre CAC channel */
 	ap_adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE);

+ 45 - 5
core/hdd/src/wlan_hdd_main.c

@@ -6783,6 +6783,8 @@ struct hdd_adapter *hdd_open_adapter(struct hdd_context *hdd_ctx, uint8_t sessio
 
 	hdd_periodic_sta_stats_init(adapter);
 
+	adapter->is_pre_cac_adapter = false;
+
 	return adapter;
 
 err_destroy_adapter_features_update_work:
@@ -6975,6 +6977,32 @@ static inline void hdd_dump_func_call_map(void)
 }
 #endif
 
+static void hdd_close_pre_cac_adapter(struct hdd_context *hdd_ctx)
+{
+	struct hdd_adapter *pre_cac_adapter;
+	struct osif_vdev_sync *vdev_sync;
+	int errno;
+
+	pre_cac_adapter = hdd_get_adapter_by_iface_name(hdd_ctx,
+							SAP_PRE_CAC_IFNAME);
+	if (!pre_cac_adapter)
+		return;
+
+	errno = osif_vdev_sync_trans_start_wait(pre_cac_adapter->dev,
+						&vdev_sync);
+	if (errno)
+		return;
+
+	osif_vdev_sync_unregister(pre_cac_adapter->dev);
+	osif_vdev_sync_wait_for_ops(vdev_sync);
+
+	wlan_hdd_release_intf_addr(hdd_ctx, pre_cac_adapter->mac_addr.bytes);
+	hdd_close_adapter(hdd_ctx, pre_cac_adapter, true);
+
+	osif_vdev_sync_trans_stop(vdev_sync);
+	osif_vdev_sync_destroy(vdev_sync);
+}
+
 QDF_STATUS hdd_stop_adapter(struct hdd_context *hdd_ctx,
 			    struct hdd_adapter *adapter)
 {
@@ -7172,11 +7200,23 @@ QDF_STATUS hdd_stop_adapter(struct hdd_context *hdd_ctx,
 
 		ucfg_ipa_flush(hdd_ctx->pdev);
 
-		/* don't flush pre-cac destroy if we are destroying pre-cac */
-		sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(adapter);
-		if (!wlan_sap_is_pre_cac_context(sap_ctx) &&
-		    (hdd_ctx->sap_pre_cac_work.fn))
-			cds_flush_work(&hdd_ctx->sap_pre_cac_work);
+		if (!adapter->is_pre_cac_adapter) {
+			/**
+			 * don't flush pre-cac destroy if we are destroying
+			 * pre-cac adapter
+			 */
+			sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(adapter);
+			if (!wlan_sap_is_pre_cac_context(sap_ctx) &&
+			    (hdd_ctx->sap_pre_cac_work.fn))
+				cds_flush_work(&hdd_ctx->sap_pre_cac_work);
+
+			hdd_close_pre_cac_adapter(hdd_ctx);
+
+		} else {
+			if (wlan_sap_set_pre_cac_status(
+				   WLAN_HDD_GET_SAP_CTX_PTR(adapter), false))
+				hdd_err("Failed to set is_pre_cac_on to false");
+		}
 
 		/* fallthrough */
 

+ 39 - 29
core/hdd/src/wlan_hdd_sap_cond_chan_switch.c

@@ -165,7 +165,7 @@ static int __wlan_hdd_request_pre_cac(struct hdd_context *hdd_ctx,
 				      uint32_t chan_freq,
 				      struct hdd_adapter **out_adapter)
 {
-	uint8_t *mac_addr;
+	uint8_t *mac_addr = NULL;
 	uint32_t pre_cac_chan_freq = 0;
 	int ret;
 	struct hdd_adapter *ap_adapter, *pre_cac_adapter;
@@ -216,12 +216,6 @@ static int __wlan_hdd_request_pre_cac(struct hdd_context *hdd_ctx,
 		return -EINVAL;
 	}
 
-	mac_addr = wlan_hdd_get_intf_addr(hdd_ctx, QDF_SAP_MODE);
-	if (!mac_addr) {
-		hdd_err("can't add virtual intf: Not getting valid mac addr");
-		return -EINVAL;
-	}
-
 	hdd_debug("channel: %d", chan_freq);
 
 	ret = wlan_hdd_validate_and_get_pre_cac_ch(
@@ -233,28 +227,42 @@ static int __wlan_hdd_request_pre_cac(struct hdd_context *hdd_ctx,
 
 	hdd_debug("starting pre cac SAP  adapter");
 
-	/* Starting a SAP adapter:
-	 * Instead of opening an adapter, we could just do a SME open session
-	 * for AP type. But, start BSS would still need an adapter.
-	 * So, this option is not taken.
-	 *
-	 * hdd open adapter is going to register this precac interface with
-	 * user space. This interface though exposed to user space will be in
-	 * DOWN state. Consideration was done to avoid this registration to the
-	 * user space. But, as part of SAP operations multiple events are sent
-	 * to user space. Some of these events received from unregistered
-	 * interface was causing crashes. So, retaining the registration.
-	 *
-	 * So, this interface would remain registered and will remain in DOWN
-	 * state for the CAC duration. We will add notes in the feature
-	 * announcement to not use this temporary interface for any activity
-	 * from user space.
-	 */
-	pre_cac_adapter = hdd_open_adapter(hdd_ctx, QDF_SAP_MODE, "precac%d",
-					   mac_addr, NET_NAME_UNKNOWN, true);
+	pre_cac_adapter = hdd_get_adapter_by_iface_name(hdd_ctx,
+							SAP_PRE_CAC_IFNAME);
 	if (!pre_cac_adapter) {
-		hdd_err("error opening the pre cac adapter");
-		goto release_intf_addr_and_return_failure;
+		mac_addr = wlan_hdd_get_intf_addr(hdd_ctx, QDF_SAP_MODE);
+		if (!mac_addr) {
+			hdd_err("can't add virtual intf: Not getting valid mac addr");
+			return -EINVAL;
+		}
+
+		/**
+		 * Starting a SAP adapter:
+		 * Instead of opening an adapter, we could just do a SME open
+		 * session for AP type. But, start BSS would still need an
+		 * adapter. So, this option is not taken.
+		 *
+		 * hdd open adapter is going to register this precac interface
+		 * with user space. This interface though exposed to user space
+		 * will be in DOWN state. Consideration was done to avoid this
+		 * registration to the user space. But, as part of SAP
+		 * operations multiple events are sent to user space. Some of
+		 * these events received from unregistered interface was
+		 * causing crashes. So, retaining the registration.
+		 *
+		 * So, this interface would remain registered and will remain
+		 * in DOWN state for the CAC duration. We will add notes in the
+		 * feature announcement to not use this temporary interface for
+		 * any activity from user space.
+		 */
+		pre_cac_adapter = hdd_open_adapter(hdd_ctx, QDF_SAP_MODE,
+						   SAP_PRE_CAC_IFNAME, mac_addr,
+						   NET_NAME_UNKNOWN, true);
+
+		if (!pre_cac_adapter) {
+			hdd_err("error opening the pre cac adapter");
+			goto release_intf_addr_and_return_failure;
+		}
 	}
 
 	/*
@@ -370,6 +378,7 @@ static int __wlan_hdd_request_pre_cac(struct hdd_context *hdd_ctx,
 	}
 
 	ap_adapter->pre_cac_freq = pre_cac_chan_freq;
+	pre_cac_adapter->is_pre_cac_adapter = true;
 
 	*out_adapter = pre_cac_adapter;
 
@@ -388,7 +397,8 @@ release_intf_addr_and_return_failure:
 	 * adapter which is trying to come wouldn't get valid
 	 * mac address. Remember we have limited pool of mac addresses
 	 */
-	wlan_hdd_release_intf_addr(hdd_ctx, mac_addr);
+	if (mac_addr)
+		wlan_hdd_release_intf_addr(hdd_ctx, mac_addr);
 	return -EINVAL;
 }
 

+ 17 - 0
core/sap/inc/sap_api.h

@@ -67,6 +67,8 @@ extern "C" {
 #define SAP_DEFAULT_5GHZ_CHANNEL      (40)
 #define SAP_CHANNEL_NOT_SELECTED (0)
 
+#define SAP_PRE_CAC_IFNAME "precac"
+
 /*--------------------------------------------------------------------------
  * reasonCode taken from 802.11 standard.
  * ------------------------------------------------------------------------*/
@@ -832,6 +834,7 @@ QDF_STATUS wlan_sap_update_next_channel(struct sap_context *sap_ctx,
 					uint8_t channel,
 					enum phy_ch_width chan_bw);
 
+#ifdef FEATURE_SAP_COND_CHAN_SWITCH
 /**
  * wlan_sap_set_pre_cac_status() - Set the pre cac status
  * @sap_ctx: SAP context
@@ -855,6 +858,20 @@ QDF_STATUS wlan_sap_set_pre_cac_status(struct sap_context *sap_ctx,
  */
 QDF_STATUS wlan_sap_set_chan_before_pre_cac(struct sap_context *sap_ctx,
 					    uint8_t chan_before_pre_cac);
+#else
+static inline QDF_STATUS
+wlan_sap_set_pre_cac_status(struct sap_context *sap_ctx, bool status)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline QDF_STATUS
+wlan_sap_set_chan_before_pre_cac(struct sap_context *sap_ctx,
+				 uint8_t chan_before_pre_cac)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
 
 /**
  * wlan_sap_set_pre_cac_complete_status() - Sets pre cac complete status