diff options
| author | Govind Singh <govinds@codeaurora.org> | 2017-08-12 13:31:00 +0530 |
|---|---|---|
| committer | snandini <snandini@codeaurora.org> | 2017-08-14 18:02:18 -0700 |
| commit | b3b593bdb46808d55ef0c0f5a63b76dd370f8a1d (patch) | |
| tree | 65fb0b6a340bf1792e4113dfe7a7f0fffe7d1838 | |
| parent | ae6844a2fc7e9d13e82395af682f0c49f29f4ca5 (diff) | |
qcacld-3.0: Flush ipa_pm work during the stop adapter
The IPA SKB's stuck in exception path are flushed after
adapter is deleted can lead to null pointer dereference of
adapter as IPA skb's have reference to this adapter in
their CB struct.
Flush ipa_pm work during the stop adapter and ensure the queue
is emptied and no outstanding buffer from IPA exception path.
CRs-Fixed: 2092131
Change-Id: I24f0c166cee1b5e0fed1c0c49a53c1a2117c900c
| -rw-r--r-- | core/hdd/inc/wlan_hdd_ipa.h | 5 | ||||
| -rw-r--r-- | core/hdd/src/wlan_hdd_ipa.c | 62 | ||||
| -rw-r--r-- | core/hdd/src/wlan_hdd_main.c | 1 |
3 files changed, 52 insertions, 16 deletions
diff --git a/core/hdd/inc/wlan_hdd_ipa.h b/core/hdd/inc/wlan_hdd_ipa.h index ec2ed4756f34..4715abff9833 100644 --- a/core/hdd/inc/wlan_hdd_ipa.h +++ b/core/hdd/inc/wlan_hdd_ipa.h @@ -85,6 +85,7 @@ static inline hdd_ipa_nbuf_cb_fn wlan_hdd_stub_ipa_fn(void) }; QDF_STATUS hdd_ipa_init(hdd_context_t *hdd_ctx); +void hdd_ipa_flush(hdd_context_t *hdd_ctx); QDF_STATUS hdd_ipa_cleanup(hdd_context_t *hdd_ctx); QDF_STATUS hdd_ipa_process_rxt(void *cds_context, qdf_nbuf_t rxBuf, uint8_t sta_id); @@ -141,6 +142,10 @@ static inline QDF_STATUS hdd_ipa_init(hdd_context_t *hdd_ctx) return QDF_STATUS_SUCCESS; } +static inline void hdd_ipa_flush(hdd_context_t *hdd_ctx) +{ +} + static inline QDF_STATUS hdd_ipa_cleanup(hdd_context_t *hdd_ctx) { return QDF_STATUS_SUCCESS; diff --git a/core/hdd/src/wlan_hdd_ipa.c b/core/hdd/src/wlan_hdd_ipa.c index b4e7a979af1d..c1bcbf36e240 100644 --- a/core/hdd/src/wlan_hdd_ipa.c +++ b/core/hdd/src/wlan_hdd_ipa.c @@ -4649,7 +4649,9 @@ static void hdd_ipa_pm_flush(struct work_struct *work) if (pm_tx_cb->exception) { HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "FLUSH EXCEPTION"); - hdd_softap_hard_start_xmit(skb, pm_tx_cb->adapter->dev); + if (pm_tx_cb->adapter->dev) + hdd_softap_hard_start_xmit(skb, + pm_tx_cb->adapter->dev); } else { hdd_ipa_send_pkt_to_tl(pm_tx_cb->iface_context, pm_tx_cb->ipa_tx_desc); @@ -6383,6 +6385,35 @@ static void hdd_ipa_cleanup_pending_event(struct hdd_ipa_priv *hdd_ipa) } /** + * __hdd_ipa_flush - flush IPA exception path SKB's + * @hdd_ctx: HDD global context + * + * Return: none + */ +static void __hdd_ipa_flush(hdd_context_t *hdd_ctx) +{ + struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa; + qdf_nbuf_t skb; + struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL; + + cancel_work_sync(&hdd_ipa->pm_work); + qdf_spin_lock_bh(&hdd_ipa->pm_lock); + + while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head)) + != NULL)) { + qdf_spin_unlock_bh(&hdd_ipa->pm_lock); + + pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb; + if (pm_tx_cb->ipa_tx_desc) + ipa_free_skb(pm_tx_cb->ipa_tx_desc); + + qdf_spin_lock_bh(&hdd_ipa->pm_lock); + } + qdf_spin_unlock_bh(&hdd_ipa->pm_lock); + +} + +/** * __hdd_ipa_cleanup - IPA cleanup function * @hdd_ctx: HDD global context * @@ -6393,8 +6424,6 @@ static QDF_STATUS __hdd_ipa_cleanup(hdd_context_t *hdd_ctx) struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa; int i; struct hdd_ipa_iface_context *iface_context = NULL; - qdf_nbuf_t skb; - struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL; if (!hdd_ipa_is_enabled(hdd_ctx)) return QDF_STATUS_SUCCESS; @@ -6410,20 +6439,8 @@ static QDF_STATUS __hdd_ipa_cleanup(hdd_context_t *hdd_ctx) hdd_ipa_destroy_rm_resource(hdd_ipa); - cancel_work_sync(&hdd_ipa->pm_work); - qdf_spin_lock_bh(&hdd_ipa->pm_lock); - - while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head)) - != NULL)) { - qdf_spin_unlock_bh(&hdd_ipa->pm_lock); - - pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb; - if (pm_tx_cb->ipa_tx_desc) - ipa_free_skb(pm_tx_cb->ipa_tx_desc); - qdf_spin_lock_bh(&hdd_ipa->pm_lock); - } - qdf_spin_unlock_bh(&hdd_ipa->pm_lock); + __hdd_ipa_flush(hdd_ctx); qdf_spinlock_destroy(&hdd_ipa->pm_lock); qdf_spinlock_destroy(&hdd_ipa->q_lock); @@ -6456,6 +6473,19 @@ static QDF_STATUS __hdd_ipa_cleanup(hdd_context_t *hdd_ctx) } /** + * hdd_ipa_cleanup - SSR wrapper for __hdd_ipa_flush + * @hdd_ctx: HDD global context + * + * Return: None + */ +void hdd_ipa_flush(hdd_context_t *hdd_ctx) +{ + cds_ssr_protect(__func__); + __hdd_ipa_flush(hdd_ctx); + cds_ssr_unprotect(__func__); +} + +/** * hdd_ipa_cleanup - SSR wrapper for __hdd_ipa_cleanup * @hdd_ctx: HDD global context * diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 46057ae22ad2..d66434af74a8 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -4043,6 +4043,7 @@ QDF_STATUS hdd_stop_adapter(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter, break; case QDF_SAP_MODE: + hdd_ipa_flush(hdd_ctx); case QDF_P2P_GO_MODE: if (hdd_ctx->config->conc_custom_rule1 && (QDF_SAP_MODE == adapter->device_mode)) { |
