From 3bdf380c03c06018010418abea29e7f1b1521ce7 Mon Sep 17 00:00:00 2001 From: Krunal Soni Date: Wed, 20 Jun 2018 16:45:03 -0700 Subject: [PATCH] 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 --- umac/scan/core/src/wlan_scan_main.h | 2 + umac/scan/core/src/wlan_scan_manager.c | 39 +++++++++++++------ umac/scan/dispatcher/inc/wlan_scan_ucfg_api.h | 15 +++++++ umac/scan/dispatcher/src/wlan_scan_ucfg_api.c | 32 +++++++++++++++ 4 files changed, 76 insertions(+), 12 deletions(-) diff --git a/umac/scan/core/src/wlan_scan_main.h b/umac/scan/core/src/wlan_scan_main.h index caa38c6de7..2da8cdad83 100644 --- a/umac/scan/core/src/wlan_scan_main.h +++ b/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; }; /** diff --git a/umac/scan/core/src/wlan_scan_manager.c b/umac/scan/core/src/wlan_scan_manager.c index 3bbe50564d..5dbe64cf4e 100644 --- a/umac/scan/core/src/wlan_scan_manager.c +++ b/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; diff --git a/umac/scan/dispatcher/inc/wlan_scan_ucfg_api.h b/umac/scan/dispatcher/inc/wlan_scan_ucfg_api.h index 5eb8f371f3..e9b9bb50c4 100644 --- a/umac/scan/dispatcher/inc/wlan_scan_ucfg_api.h +++ b/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 diff --git a/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c b/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c index 556f4147f9..0cbfba94e1 100644 --- a/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c +++ b/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)