summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGovind Singh <govinds@codeaurora.org>2017-08-12 13:31:00 +0530
committersnandini <snandini@codeaurora.org>2017-08-14 18:02:18 -0700
commitb3b593bdb46808d55ef0c0f5a63b76dd370f8a1d (patch)
tree65fb0b6a340bf1792e4113dfe7a7f0fffe7d1838
parentae6844a2fc7e9d13e82395af682f0c49f29f4ca5 (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.h5
-rw-r--r--core/hdd/src/wlan_hdd_ipa.c62
-rw-r--r--core/hdd/src/wlan_hdd_main.c1
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)) {