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
This commit is contained in:
Ryan Hsu
2018-05-14 12:13:15 -07:00
committed by nshrivas
parent 0342407471
commit b5783cfcb2
2 changed files with 101 additions and 63 deletions

View File

@@ -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; qdf_ipa_wlan_msg_ex_t *msg_ex = NULL;
int i; int i;
QDF_STATUS status; QDF_STATUS status;
uint8_t sta_session_id = WLAN_IPA_MAX_SESSION;
ipa_debug("%s: EVT: %d, MAC: %pM, sta_id: %d", ipa_debug("%s: EVT: %d, MAC: %pM, sta_id: %d",
net_dev->name, type, mac_addr, sta_id); 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; 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. * 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 */ /* Enable IPA UC Data PIPEs when first STA connected */
if (ipa_ctx->sap_num_connected_sta == 0 && if (ipa_ctx->sap_num_connected_sta == 0 &&
ipa_ctx->uc_loaded == true) { 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) && if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) &&
ipa_ctx->sta_connected) { ipa_ctx->sta_connected) {
qdf_mutex_release(&ipa_ctx->event_lock); 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, wlan_ipa_uc_offload_enable_disable(ipa_ctx,
SIR_STA_RX_DATA_OFFLOAD, SIR_STA_RX_DATA_OFFLOAD,
sta_session_id, true); 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->config) &&
ipa_ctx->sta_connected) { ipa_ctx->sta_connected) {
qdf_mutex_release(&ipa_ctx->event_lock); 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( wlan_ipa_uc_offload_enable_disable(
ipa_ctx, ipa_ctx,
SIR_STA_RX_DATA_OFFLOAD, 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) && if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) &&
ipa_ctx->sta_connected) { 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); qdf_mutex_release(&ipa_ctx->event_lock);
wlan_ipa_uc_offload_enable_disable(ipa_ctx, wlan_ipa_uc_offload_enable_disable(ipa_ctx,
SIR_STA_RX_DATA_OFFLOAD, 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 * wlan_ipa_alloc_tx_desc_list() - Allocate IPA Tx desc list
* @ipa_ctx: IPA context * @ipa_ctx: IPA context
* *
* Return: QDF_STATUS * 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; int i;
uint32_t max_desc_cnt; 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); qdf_spin_lock_bh(&ipa_ctx->q_lock);
for (i = 0; i < max_desc_cnt; i++) { for (i = 0; i < max_desc_cnt; i++) {
tmp_desc = qdf_mem_malloc(sizeof(*tmp_desc)); 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->id = i;
tmp_desc->ipa_tx_desc_ptr = NULL; tmp_desc->ipa_tx_desc_ptr = NULL;
qdf_list_insert_back(&ipa_ctx->tx_desc_list, 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); qdf_spin_unlock_bh(&ipa_ctx->q_lock);
return QDF_STATUS_SUCCESS; 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 #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; 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 * wlan_ipa_setup_sys_pipe() - Setup all IPA system pipes
* @ipa_ctx: Global IPA IPA context * @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) 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; uint32_t desc_fifo_sz;
/* The maximum number of descriptors that can be provided to a BAM at /* 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; return ret;
setup_sys_pipe_fail: setup_sys_pipe_fail:
wlan_ipa_teardown_sys_pipe(ipa_ctx);
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));
}
return ret; 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 #ifndef QCA_LL_TX_FLOW_CONTROL_V2
QDF_STATUS wlan_ipa_send_mcc_scc_msg(struct wlan_ipa_priv *ipa_ctx, QDF_STATUS wlan_ipa_send_mcc_scc_msg(struct wlan_ipa_priv *ipa_ctx,
bool mcc_mode) bool mcc_mode)
@@ -2294,7 +2310,7 @@ QDF_STATUS wlan_ipa_setup(struct wlan_ipa_priv *ipa_ctx,
if (status == QDF_STATUS_E_BUSY) if (status == QDF_STATUS_E_BUSY)
status = wlan_ipa_uc_send_wdi_control_msg(false); status = wlan_ipa_uc_send_wdi_control_msg(false);
if (status != QDF_STATUS_SUCCESS) { 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; goto fail_create_sys_pipe;
} }
} else { } else {
@@ -2442,6 +2458,12 @@ static void wlan_ipa_uc_loaded_handler(struct wlan_ipa_priv *ipa_ctx)
QDF_STATUS status; QDF_STATUS status;
ipa_info("UC READY"); ipa_info("UC READY");
if (!qdf_dev) {
ipa_err("qdf device is NULL!");
return;
}
if (true == ipa_ctx->uc_loaded) { if (true == ipa_ctx->uc_loaded) {
ipa_info("UC already loaded"); ipa_info("UC already loaded");
return; return;

View File

@@ -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; struct ol_txrx_ipa_resources *ipa_res = &pdev->ipa_resource;
qdf_device_t osdev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); 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, htt_ipa_uc_get_resource(pdev->htt_pdev,
&ipa_res->ce_sr, &ipa_res->ce_sr,
&ipa_res->tx_comp_ring, &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); 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_CLIENT(tx) = IPA_CLIENT_WLAN1_CONS;
QDF_IPA_WDI_SETUP_INFO_TRANSFER_RING_BASE_PA(tx) = QDF_IPA_WDI_SETUP_INFO_TRANSFER_RING_BASE_PA(tx) =
qdf_mem_get_dma_addr(osdev, 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; uint32_t tx_comp_db_dmaaddr = 0, rx_rdy_db_dmaaddr = 0;
int ret; int ret;
qdf_mem_zero(&tx, sizeof(qdf_ipa_wdi_pipe_setup_info_t)); if (!osdev) {
qdf_mem_zero(&rx, sizeof(qdf_ipa_wdi_pipe_setup_info_t)); 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_in, sizeof(pipe_in));
qdf_mem_zero(&pipe_out, sizeof(pipe_out)); qdf_mem_zero(&pipe_out, sizeof(pipe_out));