diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index e28aedf5d94b..02a4e01a4f7b 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -2093,7 +2093,7 @@ void hdd_bus_bw_compute_timer_try_stop(struct hdd_context *hdd_ctx); /** * hdd_bus_bandwidth_init() - Initialize bus bandwidth data structures. - * hdd_ctx: HDD context + * @hdd_ctx: HDD context * * Initialize bus bandwidth related data structures like spinlock and timer. * @@ -2103,13 +2103,23 @@ int hdd_bus_bandwidth_init(struct hdd_context *hdd_ctx); /** * hdd_bus_bandwidth_destroy() - Destroy bus bandwidth data structures. - * hdd_ctx: HDD context + * @hdd_ctx: HDD context * * Destroy bus bandwidth related data structures like timer. * * Return: None. */ void hdd_bus_bandwidth_destroy(struct hdd_context *hdd_ctx); + +/** + * hdd_bus_bw_cancel_work() - Cancel the bus_bw_work worker + * @hdd_ctx: HDD context + * + * Cancel the bus_bw_work to stop monitor link state. + * + * Return: None. + */ +void hdd_bus_bw_cancel_work(struct hdd_context *hdd_ctx); #else static inline void hdd_bus_bw_compute_timer_start(struct hdd_context *hdd_ctx) @@ -2136,6 +2146,10 @@ static inline int hdd_bus_bandwidth_init(struct hdd_context *hdd_ctx) static inline void hdd_bus_bandwidth_destroy(struct hdd_context *hdd_ctx) { } + +static inline void hdd_bus_bw_cancel_work(struct hdd_context *hdd_ctx) +{ +} #endif int hdd_qdf_trace_enable(QDF_MODULE_ID module_id, uint32_t bitmask); diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 60742b6889a1..e19d713999d9 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -4205,9 +4205,18 @@ QDF_STATUS hdd_close_adapter(struct hdd_context *hdd_ctx, struct hdd_adapter *ad } adapterNode = pCurrent; if (QDF_STATUS_SUCCESS == status) { + /* + * Here we are stopping global bus_bw timer & work per adapter. + * + * The reason is to fix one race condition between + * bus bandwidth work and cleaning up an adapter. + * Under some conditions, it is possible for the bus bandwidth + * work to access a particularly destroyed adapter, leading to + * use-after-free. + */ hdd_debug("wait for bus bw work to flush"); hdd_bus_bw_compute_timer_stop(hdd_ctx); - cancel_work_sync(&hdd_ctx->bus_bw_work); + hdd_bus_bw_cancel_work(hdd_ctx); /* cleanup adapter */ policy_mgr_clear_concurrency_mode(hdd_ctx->hdd_psoc, @@ -6630,6 +6639,12 @@ void hdd_bus_bandwidth_destroy(struct hdd_context *hdd_ctx) hdd_ctx->bus_bw_timer_running = false; qdf_spinlock_destroy(&hdd_ctx->bus_bw_timer_lock); } + +void hdd_bus_bw_cancel_work(struct hdd_context *hdd_ctx) +{ + if (hdd_ctx) + cancel_work_sync(&hdd_ctx->bus_bw_work); +} #endif /**