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

qcacmn: Enqueue scan request only after scan scheduling is success

Currently, vendor scan request is enqueued in the scan queue first and
then posted into the scheduler queue. Now if there is an SSR in between,
then scan request will be freed twice. Once in SSR context and again
in the caller context because scan scheduling fails due to user disabled
the scan.

To resolve this, post the scan request in scheduler queue first. Once
scan request scheduling is success, then enqueue the scan request in
scan queue. This approach can lead to a race condition like after
scheduling scan request, host may get scan response from firmware even
before the scan request is queued. To avoid this race, scan request
scheduling and enqueue should be protected by scan_req_q_lock.

Change-Id: Ic26da0181fb9a902a8a4abb8f68d9fc668f1b3f2
CRs-Fixed: 2714495
Bapiraju Alla 5 жил өмнө
parent
commit
1081eb4b63

+ 33 - 33
os_if/linux/scan/src/wlan_cfg80211_scan.c

@@ -649,20 +649,22 @@ wlan_copy_bssid_scan_request(struct scan_start_request *scan_req,
 #endif
 
 /**
- * wlan_scan_request_enqueue() - enqueue Scan Request
+ * wlan_schedule_scan_start_request() - Schedule scan start request
  * @pdev: pointer to pdev object
  * @req: Pointer to the scan request
  * @source: source of the scan request
- * @scan_id: scan identifier
+ * @scan_start_req: pointer to scan start request
  *
- * Enqueue scan request in the global  scan list.This list
- * stores the active scan request information.
+ * Schedule scan start request and enqueue scan request in the global scan
+ * list. This list stores the active scan request information.
  *
  * Return: 0 on success, error number otherwise
  */
-static int wlan_scan_request_enqueue(struct wlan_objmgr_pdev *pdev,
-			struct cfg80211_scan_request *req,
-			uint8_t source, uint32_t scan_id)
+static int
+wlan_schedule_scan_start_request(struct wlan_objmgr_pdev *pdev,
+				 struct cfg80211_scan_request *req,
+				 uint8_t source,
+				 struct scan_start_request *scan_start_req)
 {
 	struct scan_req *scan_req;
 	QDF_STATUS status;
@@ -670,23 +672,35 @@ static int wlan_scan_request_enqueue(struct wlan_objmgr_pdev *pdev,
 	struct osif_scan_pdev *osif_scan;
 
 	scan_req = qdf_mem_malloc(sizeof(*scan_req));
-	if (!scan_req)
+	if (!scan_req) {
+		ucfg_scm_scan_free_scan_request_mem(scan_start_req);
 		return -ENOMEM;
+	}
 
 	/* Get NL global context from objmgr*/
 	osif_ctx = wlan_pdev_get_ospriv(pdev);
 	osif_scan = osif_ctx->osif_scan;
 	scan_req->scan_request = req;
 	scan_req->source = source;
-	scan_req->scan_id = scan_id;
+	scan_req->scan_id = scan_start_req->scan_req.scan_id;
 	scan_req->dev = req->wdev->netdev;
 
 	qdf_mutex_acquire(&osif_scan->scan_req_q_lock);
-	if (qdf_list_size(&osif_scan->scan_req_q) < WLAN_MAX_SCAN_COUNT)
-		status = qdf_list_insert_back(&osif_scan->scan_req_q,
-					      &scan_req->node);
-	else
+	if (qdf_list_size(&osif_scan->scan_req_q) < WLAN_MAX_SCAN_COUNT) {
+		status = ucfg_scan_start(scan_start_req);
+		if (QDF_IS_STATUS_SUCCESS(status)) {
+			qdf_list_insert_back(&osif_scan->scan_req_q,
+					     &scan_req->node);
+		} else {
+			osif_err("scan req failed with error %d", status);
+			if (status == QDF_STATUS_E_RESOURCES)
+				osif_err("HO is in progress.So defer the scan by informing busy");
+		}
+	} else {
+		ucfg_scm_scan_free_scan_request_mem(scan_start_req);
 		status = QDF_STATUS_E_RESOURCES;
+	}
+
 	qdf_mutex_release(&osif_scan->scan_req_q_lock);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		osif_rl_debug("Failed to enqueue Scan Req as max scan %d already queued",
@@ -1291,7 +1305,6 @@ int wlan_cfg80211_scan(struct wlan_objmgr_vdev *vdev,
 	wlan_scan_id scan_id;
 	bool is_p2p_scan = false;
 	enum wlan_band band;
-	struct net_device *netdev = NULL;
 	QDF_STATUS qdf_status;
 	enum QDF_OPMODE opmode;
 	uint32_t extra_ie_len = 0;
@@ -1346,14 +1359,6 @@ int wlan_cfg80211_scan(struct wlan_objmgr_vdev *vdev,
 	req->scan_req.scan_id = scan_id;
 	req->scan_req.scan_req_id = req_id;
 
-	/* Enqueue the scan request */
-	ret = wlan_scan_request_enqueue(pdev, request, params->source,
-					req->scan_req.scan_id);
-	if (ret) {
-		qdf_mem_free(req);
-		return ret;
-	}
-
 	/* Update scan policy type flags according to cfg scan request */
 	wlan_cfg80211_update_scan_policy_type_flags(request,
 					     &req->scan_req);
@@ -1561,18 +1566,15 @@ int wlan_cfg80211_scan(struct wlan_objmgr_vdev *vdev,
 	qdf_runtime_pm_prevent_suspend(
 		&osif_priv->osif_scan->runtime_pm_lock);
 
-	qdf_status = ucfg_scan_start(req);
+	qdf_status = wlan_schedule_scan_start_request(pdev, request,
+						      params->source, req);
 	if (QDF_IS_STATUS_ERROR(qdf_status)) {
-		osif_err("scan req failed with error %d", qdf_status);
-		if (qdf_status == QDF_STATUS_E_RESOURCES)
-			osif_err("HO is in progress.So defer the scan by informing busy");
-		wlan_scan_request_dequeue(pdev, scan_id, &request,
-					  &params->source, &netdev);
 		if (qdf_list_empty(&osif_priv->osif_scan->scan_req_q)) {
 			qdf_runtime_pm_allow_suspend(
-				&osif_priv->osif_scan->runtime_pm_lock);
-			wlan_scan_release_wake_lock(psoc,
-				&osif_priv->osif_scan->scan_wake_lock);
+					&osif_priv->osif_scan->runtime_pm_lock);
+			wlan_scan_release_wake_lock(
+					psoc,
+					&osif_priv->osif_scan->scan_wake_lock);
 		}
 	}
 
@@ -1580,8 +1582,6 @@ int wlan_cfg80211_scan(struct wlan_objmgr_vdev *vdev,
 
 err:
 	qdf_mem_free(req);
-	wlan_scan_request_dequeue(pdev, scan_id, &request,
-				  &params->source, &netdev);
 	return ret;
 }
 

+ 8 - 0
umac/scan/dispatcher/inc/wlan_scan_ucfg_api.h

@@ -162,6 +162,14 @@ ucfg_scan_get_pno_match(struct wlan_objmgr_vdev *vdev)
 	return false;
 }
 #endif /* FEATURE_WLAN_SCAN_PNO */
+/**
+ * ucfg_scm_scan_free_scan_request_mem() - Free scan request memory
+ * @req: scan_start_request object
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ucfg_scm_scan_free_scan_request_mem(struct scan_start_request *req);
+
 /**
  * ucfg_scan_start() - Public API to start a scan
  * @req: start scan req params

+ 6 - 0
umac/scan/dispatcher/src/wlan_scan_ucfg_api.c

@@ -429,6 +429,12 @@ ucfg_scan_set_custom_scan_chan_list(struct wlan_objmgr_pdev *pdev,
 	return QDF_STATUS_SUCCESS;
 }
 
+QDF_STATUS
+ucfg_scm_scan_free_scan_request_mem(struct scan_start_request *req)
+{
+	return scm_scan_free_scan_request_mem(req);
+}
+
 QDF_STATUS
 ucfg_scan_start(struct scan_start_request *req)
 {