Parcourir la source

qcacmn: Don't process scan command when vdev delete is in process

When driver performs vdev delete operation, it changes vdev state
to logically deleted or physically deleted only after receiving vdev
delete command's response from FW. In between (sending vdev del req
and receiving vdev del rsp) if thread gets pre-empted and other thread
start posting command (like scan command) to process then it could
lead to use after free scenario.

Notify scan component when vdev delete is intiated and let scan
component record that in to vdev's scan private object as one of the
flags.

check this flag before processing the scan command.

CRs-Fixed: 2261704
Change-Id: Id884d6c42cd8766e70835808863632e096158487
Krunal Soni il y a 6 ans
Parent
commit
3bdf380c03

+ 2 - 0
umac/scan/core/src/wlan_scan_main.h

@@ -219,10 +219,12 @@ struct pdev_scan_info {
  * struct scan_vdev_obj - scan vdev obj
  * @pno_match_evt_received: pno match received
  * @pno_in_progress: pno in progress
+ * @is_vdev_delete_in_progress: flag to indicate if vdev del is in progress
  */
 struct scan_vdev_obj {
 	bool pno_match_evt_received;
 	bool pno_in_progress;
+	bool is_vdev_delete_in_progress;
 };
 
 /**

+ 27 - 12
umac/scan/core/src/wlan_scan_manager.c

@@ -369,8 +369,9 @@ scm_scan_start_req(struct scheduler_msg *msg)
 {
 	struct wlan_serialization_command cmd = {0, };
 	enum wlan_serialization_status ser_cmd_status;
-	struct scan_start_request *req;
+	struct scan_start_request *req = NULL;
 	struct wlan_scan_obj *scan_obj;
+	struct scan_vdev_obj *scan_vdev_priv_obj;
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
 
 	if (!msg) {
@@ -388,7 +389,8 @@ scm_scan_start_req(struct scheduler_msg *msg)
 	scan_obj = wlan_vdev_get_scan_obj(req->vdev);
 	if (!scan_obj) {
 		scm_debug("Couldn't find scan object");
-		return QDF_STATUS_E_NULL_VALUE;
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto err;
 	}
 
 	cmd.cmd_type = WLAN_SER_CMD_SCAN;
@@ -409,6 +411,18 @@ scm_scan_start_req(struct scheduler_msg *msg)
 		req, req->scan_req.scan_req_id, req->scan_req.scan_id,
 		req->scan_req.vdev_id);
 
+	scan_vdev_priv_obj = wlan_get_vdev_scan_obj(req->vdev);
+	if (!scan_vdev_priv_obj) {
+		scm_debug("Couldn't find scan priv object");
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto err;
+	}
+	if (scan_vdev_priv_obj->is_vdev_delete_in_progress) {
+		scm_err("Can't allow scan on vdev_id:%d",
+			wlan_vdev_get_id(req->vdev));
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto err;
+	}
 	ser_cmd_status = wlan_serialization_request(&cmd);
 	scm_info("wlan_serialization_request status:%d", ser_cmd_status);
 
@@ -427,21 +441,22 @@ scm_scan_start_req(struct scheduler_msg *msg)
 		 */
 		scm_post_internal_scan_complete_event(req,
 				SCAN_REASON_INTERNAL_FAILURE);
-		/* cmd can't be serviced.
-		 * release vdev reference and free scan_start_request memory
-		 */
-		wlan_objmgr_vdev_release_ref(req->vdev, WLAN_SCAN_ID);
-		scm_scan_free_scan_request_mem(req);
-		break;
+		goto err;
 	default:
 		QDF_ASSERT(0);
 		status = QDF_STATUS_E_INVAL;
-		/* cmd can't be serviced.
-		 * release vdev reference and free scan_start_request memory
-		 */
+		goto err;
+	}
+
+	return status;
+err:
+	/*
+	 * cmd can't be serviced.
+	 * release vdev reference and free scan_start_request memory
+	 */
+	if (req) {
 		wlan_objmgr_vdev_release_ref(req->vdev, WLAN_SCAN_ID);
 		scm_scan_free_scan_request_mem(req);
-		break;
 	}
 
 	return status;

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

@@ -590,4 +590,19 @@ void ucfg_scan_set_bt_activity(struct wlan_objmgr_psoc *psoc,
  * Return: true if enabled else false.
  */
 bool ucfg_scan_get_bt_activity(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * ucfg_scan_set_vdev_del_in_progress() - API to mark vdev delete in progress
+ * @vdev: pointer to vdev object
+ *
+ * Return: none
+ */
+void ucfg_scan_set_vdev_del_in_progress(struct wlan_objmgr_vdev *vdev);
+/**
+ * ucfg_scan_clear_vdev_del_in_progress() - API to reset vdev delete in progress
+ * @vdev: pointer to vdev object
+ *
+ * Return: none
+ */
+void ucfg_scan_clear_vdev_del_in_progress(struct wlan_objmgr_vdev *vdev);
 #endif

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

@@ -2178,6 +2178,38 @@ bool ucfg_scan_get_bt_activity(struct wlan_objmgr_psoc *psoc)
 	return scan_obj->bt_a2dp_enabled;
 }
 
+void ucfg_scan_set_vdev_del_in_progress(struct wlan_objmgr_vdev *vdev)
+{
+	struct scan_vdev_obj *scan_vdev_obj;
+
+	if (!vdev) {
+		scm_err("invalid vdev");
+		return;
+	}
+	scan_vdev_obj = wlan_get_vdev_scan_obj(vdev);
+	if (!scan_vdev_obj) {
+		scm_err("null scan_vdev_obj");
+		return;
+	}
+	scan_vdev_obj->is_vdev_delete_in_progress = true;
+}
+
+void ucfg_scan_clear_vdev_del_in_progress(struct wlan_objmgr_vdev *vdev)
+{
+	struct scan_vdev_obj *scan_vdev_obj;
+
+	if (!vdev) {
+		scm_err("invalid vdev");
+		return;
+	}
+	scan_vdev_obj = wlan_get_vdev_scan_obj(vdev);
+	if (!scan_vdev_obj) {
+		scm_err("null scan_vdev_obj");
+		return;
+	}
+	scan_vdev_obj->is_vdev_delete_in_progress = false;
+}
+
 QDF_STATUS
 ucfg_scan_set_global_config(struct wlan_objmgr_psoc *psoc,
 			       enum scan_config config, uint32_t val)