Browse Source

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
Govind Singh 7 years ago
parent
commit
1dab23b24c
3 changed files with 56 additions and 18 deletions
  1. 5 0
      core/hdd/inc/wlan_hdd_ipa.h
  2. 49 18
      core/hdd/src/wlan_hdd_ipa.c
  3. 2 0
      core/hdd/src/wlan_hdd_main.c

+ 5 - 0
core/hdd/inc/wlan_hdd_ipa.h

@@ -86,6 +86,7 @@ static inline hdd_ipa_nbuf_cb_fn wlan_hdd_stub_ipa_fn(void)
 
 QDF_STATUS hdd_ipa_init(struct hdd_context *hdd_ctx);
 QDF_STATUS hdd_ipa_cleanup(struct hdd_context *hdd_ctx);
+void hdd_ipa_flush(struct hdd_context *hdd_ctx);
 QDF_STATUS hdd_ipa_process_rxt(void *cds_context, qdf_nbuf_t rxBuf,
 	uint8_t sta_id);
 int hdd_ipa_wlan_evt(struct hdd_adapter *adapter, uint8_t sta_id,
@@ -134,6 +135,10 @@ static inline QDF_STATUS hdd_ipa_cleanup(struct hdd_context *hdd_ctx)
 	return QDF_STATUS_SUCCESS;
 }
 
+static inline void hdd_ipa_flush(struct hdd_context *hdd_ctx)
+{
+}
+
 static inline QDF_STATUS hdd_ipa_process_rxt(void *cds_context,
 	qdf_nbuf_t rxBuf, uint8_t sta_id)
 {

+ 49 - 18
core/hdd/src/wlan_hdd_ipa.c

@@ -4212,7 +4212,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);
@@ -5594,32 +5596,19 @@ static void hdd_ipa_cleanup_pending_event(struct hdd_ipa_priv *hdd_ipa)
 }
 
 /**
- * __hdd_ipa_cleanup - IPA cleanup function
+ * __hdd_ipa_flush - flush IPA exception path SKB's
  * @hdd_ctx: HDD global context
  *
- * Return: QDF_STATUS enumeration
+ * Return: none
  */
-static QDF_STATUS __hdd_ipa_cleanup(struct hdd_context *hdd_ctx)
+static void __hdd_ipa_flush(struct hdd_context *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;
-
-	if (!hdd_ipa_uc_is_enabled(hdd_ctx)) {
-		unregister_inetaddr_notifier(&hdd_ipa->ipv4_notifier);
-		hdd_ipa_teardown_sys_pipe(hdd_ipa);
-	}
-
-	/* Teardown IPA sys_pipe for MCC */
-	if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
-		hdd_ipa_teardown_sys_pipe(hdd_ipa);
-
-	hdd_ipa_destroy_rm_resource(hdd_ipa);
+		return;
 
 	cancel_work_sync(&hdd_ipa->pm_work);
 
@@ -5636,6 +5625,35 @@ static QDF_STATUS __hdd_ipa_cleanup(struct hdd_context *hdd_ctx)
 		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
+ *
+ * Return: QDF_STATUS enumeration
+ */
+static QDF_STATUS __hdd_ipa_cleanup(struct hdd_context *hdd_ctx)
+{
+	struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa;
+	int i;
+	struct hdd_ipa_iface_context *iface_context = NULL;
+
+	if (!hdd_ipa_is_enabled(hdd_ctx))
+		return QDF_STATUS_SUCCESS;
+
+	if (!hdd_ipa_uc_is_enabled(hdd_ctx)) {
+		unregister_inetaddr_notifier(&hdd_ipa->ipv4_notifier);
+		hdd_ipa_teardown_sys_pipe(hdd_ipa);
+	}
+
+	/* Teardown IPA sys_pipe for MCC */
+	if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx))
+		hdd_ipa_teardown_sys_pipe(hdd_ipa);
+
+	hdd_ipa_destroy_rm_resource(hdd_ipa);
+
+	__hdd_ipa_flush(hdd_ctx);
 
 	qdf_spinlock_destroy(&hdd_ipa->pm_lock);
 	qdf_spinlock_destroy(&hdd_ipa->q_lock);
@@ -5667,6 +5685,19 @@ static QDF_STATUS __hdd_ipa_cleanup(struct hdd_context *hdd_ctx)
 	return QDF_STATUS_SUCCESS;
 }
 
+/**
+ * hdd_ipa_cleanup - SSR wrapper for __hdd_ipa_flush
+ * @hdd_ctx: HDD global context
+ *
+ * Return: None
+ */
+void hdd_ipa_flush(struct hdd_context *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

+ 2 - 0
core/hdd/src/wlan_hdd_main.c

@@ -4350,6 +4350,8 @@ QDF_STATUS hdd_stop_adapter(struct hdd_context *hdd_ctx, struct hdd_adapter *ada
 		break;
 
 	case QDF_SAP_MODE:
+		/* Flush IPA exception path packets */
+		hdd_ipa_flush(hdd_ctx);
 	case QDF_P2P_GO_MODE:
 		/* Any softap specific cleanup here... */
 		if (adapter->device_mode == QDF_P2P_GO_MODE)