From 2cbc99c3029abd85a6c73e7613c3fa4d72401076 Mon Sep 17 00:00:00 2001 From: Sourav Mohapatra Date: Tue, 28 Jan 2020 16:29:11 +0530 Subject: [PATCH] qcacld-3.0: Free link_layer_stats results properly As per the logic implemented in the FW, it will send a dummy event for link layer stats in case the buffer allocation fails. In this case, there can occur a scenario in host wherein we are not properly freeing the previously allocated memory. In the event handler wma_unified_link_radio_stats_event_handler, if the event is dummy, we are updating the value of the num_radios inside wma_handle->link_layer_results. This num_radios is later used to free any allocated memory. On setting it to zero, we are preventing that memfree to occur; leading to a memleak. To fix this, in case there is a dummy event, first free any possible previous results before setting the num_radios to be zero. Change-Id: Ibe4ddf1a137a33130100483cefb004b7dae4ce02 CRs-Fixed: 2610754 --- core/wma/inc/wma_api.h | 13 ++++++++++++- core/wma/src/wma_utils.c | 40 ++++++++++++++++++++++++++++++++-------- 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/core/wma/inc/wma_api.h b/core/wma/inc/wma_api.h index d37c2e1c6524..7789ec41f768 100644 --- a/core/wma/inc/wma_api.h +++ b/core/wma/inc/wma_api.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -186,6 +186,17 @@ bool wma_is_rx_ldpc_supported_for_channel(uint32_t ch_freq); #ifdef WLAN_FEATURE_LINK_LAYER_STATS int wma_unified_radio_tx_mem_free(void *handle); + +/* + * wma_unified_link_stats_results_mem_free() - Free the memory for + * link_stats_results->results allocated when event comes. + * @link_stats_results: pointer to the memory that is to be freed + * + * Return: None + */ +void +wma_unified_link_stats_results_mem_free(tSirLLStatsResults *link_stats_results); + #else /* WLAN_FEATURE_LINK_LAYER_STATS */ static inline int wma_unified_radio_tx_mem_free(void *handle) { diff --git a/core/wma/src/wma_utils.c b/core/wma/src/wma_utils.c index 5b815f62333c..69ba6c0807b2 100644 --- a/core/wma/src/wma_utils.c +++ b/core/wma/src/wma_utils.c @@ -1699,23 +1699,23 @@ static int wma_unified_link_peer_stats_event_handler(void *handle, } /** - * wma_unified_radio_tx_mem_free() - Free radio tx power stats memory - * @handle: WMI handle + * wma_unified_link_stats_results_mem_free() - Free link stats results memory + * #link_stats_results: pointer to link stats result * * Return: 0 on success, error number otherwise. */ -int wma_unified_radio_tx_mem_free(void *handle) +void wma_unified_link_stats_results_mem_free( + tSirLLStatsResults *link_stats_results) { - tp_wma_handle wma_handle = (tp_wma_handle) handle; struct wifi_radio_stats *rs_results; uint32_t i = 0; - if (!wma_handle->link_stats_results) - return 0; + if (!link_stats_results) + return; rs_results = (struct wifi_radio_stats *) - &wma_handle->link_stats_results->results[0]; - for (i = 0; i < wma_handle->link_stats_results->num_radio; i++) { + &link_stats_results->results[0]; + for (i = 0; i < link_stats_results->num_radio; i++) { if (rs_results->tx_time_per_power_level) { qdf_mem_free(rs_results->tx_time_per_power_level); rs_results->tx_time_per_power_level = NULL; @@ -1727,6 +1727,22 @@ int wma_unified_radio_tx_mem_free(void *handle) } rs_results++; } +} + +/** + * wma_unified_radio_tx_mem_free() - Free radio tx power stats memory + * @handle: WMI handle + * + * Return: 0 on success, error number otherwise. + */ +int wma_unified_radio_tx_mem_free(void *handle) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + + if (!wma_handle->link_stats_results) + return 0; + + wma_unified_link_stats_results_mem_free(wma_handle->link_stats_results); qdf_mem_free(wma_handle->link_stats_results); wma_handle->link_stats_results = NULL; @@ -1961,6 +1977,14 @@ static int wma_unified_link_radio_stats_event_handler(void *handle, if (!wma_handle->link_stats_results) return -ENOMEM; } + + /* + * Free the already allocated memory, if any, before setting + * the num_radio to 0 + */ + wma_unified_link_stats_results_mem_free( + wma_handle->link_stats_results); + link_stats_results = wma_handle->link_stats_results; link_stats_results->num_radio = fixed_param->num_radio; goto link_radio_stats_cb;