From b5783cfcb2d00f6e22322453d1b0975c65e1cf7e Mon Sep 17 00:00:00 2001 From: Ryan Hsu Date: Mon, 14 May 2018 12:13:15 -0700 Subject: [PATCH] qcacld-3.0: clean up to avoid NULL pointer dereference IPA Fix a few things in one shot. - clean up some code to avoid potential NULL pointer dereference. - add a helper function - wlan_ipa_free_tx_desc_list() to avoid duplication. - rearrage wlan_ipa_teardown_sys_pipe() to allow others' reference Change-Id: I9d6391a7f20ae427bf59f07958bd13f349e61d83 CRs-Fixed: 2233867 --- components/ipa/core/src/wlan_ipa_core.c | 144 ++++++++++++++---------- core/dp/txrx/ol_txrx_ipa.c | 20 +++- 2 files changed, 101 insertions(+), 63 deletions(-) diff --git a/components/ipa/core/src/wlan_ipa_core.c b/components/ipa/core/src/wlan_ipa_core.c index 3a54833fc48b..332f93f735ab 100644 --- a/components/ipa/core/src/wlan_ipa_core.c +++ b/components/ipa/core/src/wlan_ipa_core.c @@ -1360,6 +1360,7 @@ static QDF_STATUS __wlan_ipa_wlan_evt(qdf_netdev_t net_dev, uint8_t device_mode, qdf_ipa_wlan_msg_ex_t *msg_ex = NULL; int i; QDF_STATUS status; + uint8_t sta_session_id = WLAN_IPA_MAX_SESSION; ipa_debug("%s: EVT: %d, MAC: %pM, sta_id: %d", net_dev->name, type, mac_addr, sta_id); @@ -1373,6 +1374,14 @@ static QDF_STATUS __wlan_ipa_wlan_evt(qdf_netdev_t net_dev, uint8_t device_mode, return QDF_STATUS_SUCCESS; } + if (ipa_ctx->sta_connected) { + iface_ctx = wlan_ipa_get_iface(ipa_ctx, QDF_STA_MODE); + if (iface_ctx) + sta_session_id = iface_ctx->session_id; + else + ipa_err("sta iface_ctx is NULL"); + } + /* * During IPA UC resource loading/unloading new events can be issued. */ @@ -1644,14 +1653,10 @@ static QDF_STATUS __wlan_ipa_wlan_evt(qdf_netdev_t net_dev, uint8_t device_mode, /* Enable IPA UC Data PIPEs when first STA connected */ if (ipa_ctx->sap_num_connected_sta == 0 && ipa_ctx->uc_loaded == true) { - struct wlan_ipa_iface_context *iface_ctx; - uint8_t sta_session_id; if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) && ipa_ctx->sta_connected) { qdf_mutex_release(&ipa_ctx->event_lock); - iface_ctx = wlan_ipa_get_iface(ipa_ctx, QDF_STA_MODE); - sta_session_id = iface_ctx->session_id; wlan_ipa_uc_offload_enable_disable(ipa_ctx, SIR_STA_RX_DATA_OFFLOAD, sta_session_id, true); @@ -1667,9 +1672,6 @@ static QDF_STATUS __wlan_ipa_wlan_evt(qdf_netdev_t net_dev, uint8_t device_mode, ipa_ctx->config) && ipa_ctx->sta_connected) { qdf_mutex_release(&ipa_ctx->event_lock); - iface_ctx = wlan_ipa_get_iface(ipa_ctx, - QDF_STA_MODE); - sta_session_id = iface_ctx->session_id; wlan_ipa_uc_offload_enable_disable( ipa_ctx, SIR_STA_RX_DATA_OFFLOAD, @@ -1760,13 +1762,6 @@ static QDF_STATUS __wlan_ipa_wlan_evt(qdf_netdev_t net_dev, uint8_t device_mode, if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) && ipa_ctx->sta_connected) { - struct wlan_ipa_iface_context *iface_ctx; - uint8_t sta_session_id; - - iface_ctx = wlan_ipa_get_iface(ipa_ctx, - QDF_STA_MODE); - sta_session_id = iface_ctx->session_id; - qdf_mutex_release(&ipa_ctx->event_lock); wlan_ipa_uc_offload_enable_disable(ipa_ctx, SIR_STA_RX_DATA_OFFLOAD, @@ -1925,13 +1920,39 @@ wlan_ipa_uc_proc_pending_event(struct wlan_ipa_priv *ipa_ctx, bool is_loading) } } +/** + * wlan_ipa_free_tx_desc_list() - Free IPA Tx desc list + * @ipa_ctx: IPA context + * + * Return: None + */ +static inline void wlan_ipa_free_tx_desc_list(struct wlan_ipa_priv *ipa_ctx) +{ + struct wlan_ipa_tx_desc *tmp_desc; + qdf_ipa_rx_data_t *ipa_tx_desc; + qdf_list_node_t *node; + + while (qdf_list_remove_front(&ipa_ctx->tx_desc_list, &node) == + QDF_STATUS_SUCCESS) { + tmp_desc = qdf_container_of(node, struct wlan_ipa_tx_desc, + node); + + ipa_tx_desc = tmp_desc->ipa_tx_desc_ptr; + if (ipa_tx_desc) + qdf_ipa_free_skb(ipa_tx_desc); + + qdf_mem_free(tmp_desc); + tmp_desc = NULL; + } +} + /** * wlan_ipa_alloc_tx_desc_list() - Allocate IPA Tx desc list * @ipa_ctx: IPA context * * Return: QDF_STATUS */ -static int wlan_ipa_alloc_tx_desc_list(struct wlan_ipa_priv *ipa_ctx) +static QDF_STATUS wlan_ipa_alloc_tx_desc_list(struct wlan_ipa_priv *ipa_ctx) { int i; uint32_t max_desc_cnt; @@ -1944,6 +1965,12 @@ static int wlan_ipa_alloc_tx_desc_list(struct wlan_ipa_priv *ipa_ctx) qdf_spin_lock_bh(&ipa_ctx->q_lock); for (i = 0; i < max_desc_cnt; i++) { tmp_desc = qdf_mem_malloc(sizeof(*tmp_desc)); + + if (!tmp_desc) { + qdf_spin_unlock_bh(&ipa_ctx->q_lock); + goto alloc_fail; + } + tmp_desc->id = i; tmp_desc->ipa_tx_desc_ptr = NULL; qdf_list_insert_back(&ipa_ctx->tx_desc_list, @@ -1957,6 +1984,11 @@ static int wlan_ipa_alloc_tx_desc_list(struct wlan_ipa_priv *ipa_ctx) qdf_spin_unlock_bh(&ipa_ctx->q_lock); return QDF_STATUS_SUCCESS; + +alloc_fail: + wlan_ipa_free_tx_desc_list(ipa_ctx); + return QDF_STATUS_E_NOMEM; + } #ifndef QCA_LL_TX_FLOW_CONTROL_V2 @@ -2068,6 +2100,33 @@ static int wlan_ipa_setup_rx_sys_pipe(struct wlan_ipa_priv *ipa_ctx, return ret; } +/** + * wlan_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes + * @ipa_ctx: Global IPA IPA context + * + * Return: None + */ +static void wlan_ipa_teardown_sys_pipe(struct wlan_ipa_priv *ipa_ctx) +{ + int ret, i; + + if (!ipa_ctx) + return; + + for (i = 0; i < WLAN_IPA_MAX_SYSBAM_PIPE; i++) { + if (ipa_ctx->sys_pipe[i].conn_hdl_valid) { + ret = wlan_ipa_wdi_teardown_sys_pipe(ipa_ctx, + ipa_ctx->sys_pipe[i].conn_hdl); + if (ret) + ipa_err("Failed:%d", ret); + + ipa_ctx->sys_pipe[i].conn_hdl_valid = 0; + } + } + + wlan_ipa_free_tx_desc_list(ipa_ctx); +} + /** * wlan_ipa_setup_sys_pipe() - Setup all IPA system pipes * @ipa_ctx: Global IPA IPA context @@ -2076,7 +2135,7 @@ static int wlan_ipa_setup_rx_sys_pipe(struct wlan_ipa_priv *ipa_ctx, */ static int wlan_ipa_setup_sys_pipe(struct wlan_ipa_priv *ipa_ctx) { - int i = WLAN_IPA_MAX_IFACE, ret = 0; + int ret = 0; uint32_t desc_fifo_sz; /* The maximum number of descriptors that can be provided to a BAM at @@ -2113,54 +2172,11 @@ static int wlan_ipa_setup_sys_pipe(struct wlan_ipa_priv *ipa_ctx) return ret; setup_sys_pipe_fail: - - for (i = 0; i < WLAN_IPA_MAX_SYSBAM_PIPE; i++) { - if (ipa_ctx->sys_pipe[i].conn_hdl_valid) - qdf_ipa_teardown_sys_pipe( - ipa_ctx->sys_pipe[i].conn_hdl); - qdf_mem_zero(&ipa_ctx->sys_pipe[i], - sizeof(struct wlan_ipa_sys_pipe)); - } + wlan_ipa_teardown_sys_pipe(ipa_ctx); return ret; } -/** - * wlan_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes - * @ipa_ctx: Global IPA IPA context - * - * Return: None - */ -static void wlan_ipa_teardown_sys_pipe(struct wlan_ipa_priv *ipa_ctx) -{ - int ret = 0, i; - struct wlan_ipa_tx_desc *tmp_desc; - qdf_ipa_rx_data_t *ipa_tx_desc; - qdf_list_node_t *node; - - for (i = 0; i < WLAN_IPA_MAX_SYSBAM_PIPE; i++) { - if (ipa_ctx->sys_pipe[i].conn_hdl_valid) { - ret = wlan_ipa_wdi_teardown_sys_pipe(ipa_ctx, - ipa_ctx->sys_pipe[i].conn_hdl); - if (ret) - ipa_err("Failed:%d", ret); - - ipa_ctx->sys_pipe[i].conn_hdl_valid = 0; - } - } - - while (qdf_list_remove_front(&ipa_ctx->tx_desc_list, &node) == - QDF_STATUS_SUCCESS) { - tmp_desc = qdf_container_of(node, struct wlan_ipa_tx_desc, - node); - ipa_tx_desc = tmp_desc->ipa_tx_desc_ptr; - if (ipa_tx_desc) - qdf_ipa_free_skb(ipa_tx_desc); - - qdf_mem_free(tmp_desc); - } -} - #ifndef QCA_LL_TX_FLOW_CONTROL_V2 QDF_STATUS wlan_ipa_send_mcc_scc_msg(struct wlan_ipa_priv *ipa_ctx, bool mcc_mode) @@ -2294,7 +2310,7 @@ QDF_STATUS wlan_ipa_setup(struct wlan_ipa_priv *ipa_ctx, if (status == QDF_STATUS_E_BUSY) status = wlan_ipa_uc_send_wdi_control_msg(false); if (status != QDF_STATUS_SUCCESS) { - ipa_err("IPA WDI init failed: ret=%d", ret); + ipa_err("IPA WDI init failed: ret=%d", status); goto fail_create_sys_pipe; } } else { @@ -2442,6 +2458,12 @@ static void wlan_ipa_uc_loaded_handler(struct wlan_ipa_priv *ipa_ctx) QDF_STATUS status; ipa_info("UC READY"); + + if (!qdf_dev) { + ipa_err("qdf device is NULL!"); + return; + } + if (true == ipa_ctx->uc_loaded) { ipa_info("UC already loaded"); return; diff --git a/core/dp/txrx/ol_txrx_ipa.c b/core/dp/txrx/ol_txrx_ipa.c index 896bcabb0a95..a5038b3c2212 100644 --- a/core/dp/txrx/ol_txrx_ipa.c +++ b/core/dp/txrx/ol_txrx_ipa.c @@ -126,6 +126,12 @@ QDF_STATUS ol_txrx_ipa_uc_get_resource(struct cdp_pdev *ppdev) struct ol_txrx_ipa_resources *ipa_res = &pdev->ipa_resource; qdf_device_t osdev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + if (!osdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: qdf device is null!", __func__); + return QDF_STATUS_E_NOENT; + } + htt_ipa_uc_get_resource(pdev->htt_pdev, &ipa_res->ce_sr, &ipa_res->tx_comp_ring, @@ -414,6 +420,12 @@ static inline void ol_txrx_ipa_wdi_tx_params( { qdf_device_t osdev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + if (!osdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: qdf device is null!", __func__); + return; + } + QDF_IPA_WDI_SETUP_INFO_CLIENT(tx) = IPA_CLIENT_WLAN1_CONS; QDF_IPA_WDI_SETUP_INFO_TRANSFER_RING_BASE_PA(tx) = qdf_mem_get_dma_addr(osdev, @@ -496,8 +508,12 @@ QDF_STATUS ol_txrx_ipa_setup(struct cdp_pdev *ppdev, void *ipa_i2w_cb, uint32_t tx_comp_db_dmaaddr = 0, rx_rdy_db_dmaaddr = 0; int ret; - qdf_mem_zero(&tx, sizeof(qdf_ipa_wdi_pipe_setup_info_t)); - qdf_mem_zero(&rx, sizeof(qdf_ipa_wdi_pipe_setup_info_t)); + if (!osdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: qdf device is null!", __func__); + return QDF_STATUS_E_NOENT; + } + qdf_mem_zero(&pipe_in, sizeof(pipe_in)); qdf_mem_zero(&pipe_out, sizeof(pipe_out));