Selaa lähdekoodia

qcacld-3.0: Process NAN enable/disable synchronously

In the current implementation, NAN enable and disable request are
processed asynchronously, because of which some race conditions
are seen.
	Example: If NDI is having multiple NDPs and without terminating
	NDPs if NAN disable and NDI delete are issued back to back then,
	NDP_END sequence is not initiated and causing deviation from
	NAN spec. Root-cause is firmware deleting NDP peer as a part of
	NDI delete before initiating NDP end sequence.

To fix this, process NAN enable and disable requests synchronously.

Change-Id: I467419370187b0dc8d879e1806347c9f21ebb23a
CRs-Fixed: 2528599
Rajeev Kumar Sirasanagandla 5 vuotta sitten
vanhempi
sitoutus
cbc6c3b8d1

+ 3 - 3
components/nan/core/inc/nan_public_structs.h

@@ -722,8 +722,8 @@ struct nan_datapath_host_event {
  * struct nan_callbacks - struct containing callback to non-converged driver
  * @os_if_nan_event_handler: OS IF Callback for handling NAN Discovery events
  * @os_if_ndp_event_handler: OS IF Callback for handling NAN Datapath events
- * @ucfg_explicit_disable_cb: UCFG Callback to indicate NAN explicit disable is
- * complete
+ * @ucfg_nan_request_process_cb: Callback to indicate NAN enable/disable
+ * request processing is complete
  * @ndi_open: HDD callback for creating the NAN Datapath Interface
  * @ndi_start: HDD callback for starting the NAN Datapath Interface
  * @ndi_close: HDD callback for closing the NAN Datapath Interface
@@ -743,7 +743,7 @@ struct nan_callbacks {
 	void (*os_if_ndp_event_handler)(struct wlan_objmgr_psoc *psoc,
 					struct wlan_objmgr_vdev *vdev,
 					uint32_t type, void *msg);
-	void (*ucfg_explicit_disable_cb)(void *cookie);
+	void (*ucfg_nan_request_process_cb)(void *cookie);
 	int (*ndi_open)(char *iface_name);
 	int (*ndi_start)(char *iface_name, uint16_t);
 	void (*ndi_close)(uint8_t);

+ 18 - 6
components/nan/core/src/nan_main.c

@@ -51,6 +51,12 @@ QDF_STATUS nan_set_discovery_state(struct wlan_objmgr_psoc *psoc,
 
 	qdf_spin_lock_bh(&psoc_priv->lock);
 	cur_state = psoc_priv->disc_state;
+	if (cur_state == new_state) {
+		qdf_spin_unlock_bh(&psoc_priv->lock);
+		nan_err("curr_state: %u and new state: %u are same",
+			cur_state, new_state);
+		return status;
+	}
 
 	switch (new_state) {
 	case NAN_DISC_DISABLED:
@@ -804,6 +810,7 @@ static QDF_STATUS nan_handle_enable_rsp(struct nan_event_params *nan_event)
 	struct nan_psoc_priv_obj *psoc_nan_obj;
 	struct wlan_objmgr_psoc *psoc;
 	QDF_STATUS status;
+	void (*call_back)(void *cookie);
 
 	psoc = nan_event->psoc;
 	psoc_nan_obj = nan_get_psoc_priv_obj(psoc);
@@ -843,6 +850,10 @@ static QDF_STATUS nan_handle_enable_rsp(struct nan_event_params *nan_event)
 		policy_mgr_check_n_start_opportunistic_timer(psoc);
 	}
 
+	call_back = psoc_nan_obj->cb_obj.ucfg_nan_request_process_cb;
+	if (call_back)
+		call_back(psoc_nan_obj->request_context);
+
 	return QDF_STATUS_SUCCESS;
 }
 
@@ -862,16 +873,17 @@ static QDF_STATUS nan_handle_disable_ind(struct nan_event_params *nan_event)
 	status = nan_set_discovery_state(nan_event->psoc,
 					 NAN_DISC_DISABLED);
 	if (QDF_IS_STATUS_SUCCESS(status)) {
+		void (*call_back)(void *cookie);
+
+		call_back = psoc_nan_obj->cb_obj.ucfg_nan_request_process_cb;
 		policy_mgr_decr_session_set_pcl(psoc, QDF_NAN_DISC_MODE,
 						NAN_PSEUDO_VDEV_ID);
-
 		if (psoc_nan_obj->is_explicit_disable) {
-			if (psoc_nan_obj->cb_obj.ucfg_explicit_disable_cb)
-				psoc_nan_obj->cb_obj.ucfg_explicit_disable_cb(
-				psoc_nan_obj->disable_context);
-		} else {
-			policy_mgr_nan_sap_post_disable_conc_check(psoc);
+			if (call_back)
+				call_back(psoc_nan_obj->request_context);
 		}
+
+		policy_mgr_nan_sap_post_disable_conc_check(psoc);
 	} else {
 		/* Should not happen, NAN state can always be disabled */
 		nan_err("Cannot set NAN state to disabled!");

+ 3 - 3
components/nan/core/src/nan_main_i.h

@@ -102,8 +102,8 @@ struct nan_cfg_params {
  * @nan_social_ch_5g: NAN 5G Social channel for discovery
  * @nan_disc_mac_id: MAC id used for NAN Discovery
  * @is_explicit_disable: Flag to indicate that NAN is being explicitly
- * disabled by driver
- * @disable_context: Explicit disable context
+ * disabled by driver or user-space
+ * @request_context: NAN enable/disable request context
  */
 struct nan_psoc_priv_obj {
 	qdf_spinlock_t lock;
@@ -117,7 +117,7 @@ struct nan_psoc_priv_obj {
 	uint8_t nan_social_ch_5g;
 	uint8_t nan_disc_mac_id;
 	bool is_explicit_disable;
-	void *disable_context;
+	void *request_context;
 };
 
 /**

+ 62 - 29
components/nan/dispatcher/src/nan_ucfg_api.c

@@ -419,13 +419,13 @@ void ucfg_nan_datapath_event_handler(struct wlan_objmgr_psoc *psoc,
 	psoc_obj->cb_obj.os_if_ndp_event_handler(psoc, vdev, type, msg);
 }
 
-static void ucfg_concurrency_nan_disable_callback(void *cookie)
+static void ucfg_nan_request_process_cb(void *cookie)
 {
 	struct osif_request *request;
 
 	request = osif_request_get(cookie);
-
 	if (request) {
+		nan_debug("request (cookie:0x%pK) completed", cookie);
 		osif_request_complete(request);
 		osif_request_put(request);
 	} else {
@@ -458,8 +458,8 @@ int ucfg_nan_register_hdd_callbacks(struct wlan_objmgr_psoc *psoc,
 				cb_obj->os_if_ndp_event_handler;
 	psoc_obj->cb_obj.os_if_nan_event_handler =
 				cb_obj->os_if_nan_event_handler;
-	psoc_obj->cb_obj.ucfg_explicit_disable_cb =
-				ucfg_concurrency_nan_disable_callback;
+	psoc_obj->cb_obj.ucfg_nan_request_process_cb =
+				ucfg_nan_request_process_cb;
 
 	return 0;
 }
@@ -564,6 +564,13 @@ QDF_STATUS ucfg_nan_discovery_req(void *in_req, uint32_t req_type)
 	struct scheduler_msg msg = {0};
 	uint32_t len;
 	QDF_STATUS status;
+	struct nan_psoc_priv_obj *psoc_priv;
+	struct osif_request *request = NULL;
+	static const struct osif_request_params params = {
+		.priv_size = 0,
+		.timeout_ms = 1000,
+	};
+	int err;
 
 	if (!in_req) {
 		nan_alert("NAN Discovery req is null");
@@ -575,6 +582,12 @@ QDF_STATUS ucfg_nan_discovery_req(void *in_req, uint32_t req_type)
 			struct nan_enable_req *req = in_req;
 
 			psoc = req->psoc;
+			psoc_priv = nan_get_psoc_priv_obj(psoc);
+			if (!psoc_priv) {
+				nan_err("nan psoc priv object is NULL");
+				return QDF_STATUS_E_INVAL;
+			}
+
 			/*
 			 * Take a psoc reference while it is being used by the
 			 * NAN requests.
@@ -602,6 +615,12 @@ QDF_STATUS ucfg_nan_discovery_req(void *in_req, uint32_t req_type)
 			struct nan_disable_req *req = in_req;
 
 			psoc = req->psoc;
+			psoc_priv = nan_get_psoc_priv_obj(psoc);
+			if (!psoc_priv) {
+				nan_err("nan psoc priv object is NULL");
+				return QDF_STATUS_E_INVAL;
+			}
+
 			status =  wlan_objmgr_psoc_try_get_ref(psoc,
 							       WLAN_NAN_ID);
 			if (QDF_IS_STATUS_ERROR(status)) {
@@ -626,6 +645,12 @@ QDF_STATUS ucfg_nan_discovery_req(void *in_req, uint32_t req_type)
 			struct nan_generic_req *req = in_req;
 
 			psoc = req->psoc;
+			psoc_priv = nan_get_psoc_priv_obj(psoc);
+			if (!psoc_priv) {
+				nan_err("nan psoc priv object is NULL");
+				return QDF_STATUS_E_INVAL;
+			}
+
 			status =  wlan_objmgr_psoc_try_get_ref(psoc,
 							       WLAN_NAN_ID);
 			if (QDF_IS_STATUS_ERROR(status)) {
@@ -651,6 +676,23 @@ QDF_STATUS ucfg_nan_discovery_req(void *in_req, uint32_t req_type)
 	msg.type = req_type;
 	msg.callback = nan_discovery_scheduled_handler;
 	msg.flush_callback = nan_discovery_flush_callback;
+
+	if (req_type == NAN_GENERIC_REQ)
+		goto post_msg;
+
+	request = osif_request_alloc(&params);
+	if (!request) {
+		nan_err("Request allocation failure");
+		nan_discovery_flush_callback(&msg);
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	psoc_priv->request_context = osif_request_cookie(request);
+	if (req_type == NAN_DISABLE_REQ)
+		psoc_priv->is_explicit_disable = true;
+
+post_msg:
+	nan_debug("posting request: %u", req_type);
 	status = scheduler_post_message(QDF_MODULE_ID_NAN,
 					QDF_MODULE_ID_NAN,
 					QDF_MODULE_ID_OS_IF, &msg);
@@ -660,6 +702,21 @@ QDF_STATUS ucfg_nan_discovery_req(void *in_req, uint32_t req_type)
 		nan_discovery_flush_callback(&msg);
 	}
 
+	if (req_type != NAN_GENERIC_REQ) {
+		err = osif_request_wait_for_response(request);
+		if (err)
+			nan_err("NAN request: %u timed out: %d",
+				req_type, err);
+		else
+			nan_debug("NAN request: %u serviced successfully",
+				  req_type);
+
+		if (req_type == NAN_DISABLE_REQ)
+			psoc_priv->is_explicit_disable = false;
+
+		osif_request_put(request);
+	}
+
 	return status;
 }
 
@@ -668,13 +725,7 @@ void ucfg_nan_disable_concurrency(struct wlan_objmgr_psoc *psoc)
 	struct nan_disable_req nan_req = {0};
 	enum nan_disc_state curr_nan_state;
 	struct nan_psoc_priv_obj *psoc_priv;
-	struct osif_request *request;
-	static const struct osif_request_params params = {
-		.priv_size = 0,
-		.timeout_ms = 1000,
-	};
 	QDF_STATUS status;
-	int err;
 
 	if (!psoc) {
 		nan_err("psoc object is NULL, no action will be taken");
@@ -700,35 +751,17 @@ void ucfg_nan_disable_concurrency(struct wlan_objmgr_psoc *psoc)
 	}
 	qdf_spin_unlock_bh(&psoc_priv->lock);
 
-	request = osif_request_alloc(&params);
-	if (!request) {
-		nan_err("Request allocation failure");
-		return;
-	}
-
 	nan_req.psoc = psoc;
 	nan_req.disable_2g_discovery = true;
 	nan_req.disable_5g_discovery = true;
-	psoc_priv->disable_context = osif_request_cookie(request);
 
 	status = ucfg_nan_discovery_req(&nan_req, NAN_DISABLE_REQ);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		nan_err("Unable to disable NAN Discovery");
-		osif_request_put(request);
 		return;
 	}
 
-	psoc_priv->is_explicit_disable = true;
-	nan_debug("Successfully sent NAN Disable request");
-
-	err = osif_request_wait_for_response(request);
-	if (err)
-		nan_err("NAN Disable timed out waiting for disable ind-%d",
-			err);
-	else
-		nan_debug("NAN Disabled successfully");
-	psoc_priv->is_explicit_disable = false;
-	osif_request_put(request);
+	nan_debug("NAN Disabled successfully");
 }
 
 static QDF_STATUS