Parcourir la source

qcacld-3.0: Pass p2p psoc obj to tx timer callback

When forming P2P connection, mgmt tx timer timeout when tx ack event
queued in scheduler but not processed, and then wild pointer access
in tx timer timeout callback since processed tx ack event and tx
context is freed.

Change-Id: I598e611a9e1d72bbaddbbe3541f37479f3cb9bbb
CRs-Fixed: 2372686
Wu Gao il y a 6 ans
Parent
commit
530adb5158
1 fichiers modifiés avec 32 ajouts et 17 suppressions
  1. 32 17
      components/p2p/core/src/wlan_p2p_off_chan_tx.c

+ 32 - 17
components/p2p/core/src/wlan_p2p_off_chan_tx.c

@@ -1337,18 +1337,38 @@ end:
  */
 static void p2p_tx_timeout(void *pdata)
 {
-	struct tx_action_context *tx_ctx = pdata;
+	QDF_STATUS status, ret;
+	qdf_list_node_t *p_node;
+	struct tx_action_context *tx_ctx;
+	struct p2p_soc_priv_obj *p2p_soc_obj;
 
 	p2p_info("pdata:%pK", pdata);
-
-	if (!tx_ctx || !(tx_ctx->p2p_soc_obj)) {
-		p2p_err("invalid tx context or p2p soc object");
+	p2p_soc_obj = (struct p2p_soc_priv_obj *)pdata;
+	if (!p2p_soc_obj) {
+		p2p_err("null p2p soc obj");
 		return;
 	}
 
-	qdf_mc_timer_destroy(&tx_ctx->tx_timer);
-	p2p_send_tx_conf(tx_ctx, false);
-	p2p_remove_tx_context(tx_ctx);
+	status = qdf_list_peek_front(&p2p_soc_obj->tx_q_ack, &p_node);
+	while (QDF_IS_STATUS_SUCCESS(status)) {
+		tx_ctx = qdf_container_of(p_node,
+					  struct tx_action_context, node);
+		status = qdf_list_peek_next(&p2p_soc_obj->tx_q_ack,
+					    p_node, &p_node);
+		if (QDF_TIMER_STATE_STOPPED ==
+		    qdf_mc_timer_get_current_state(&tx_ctx->tx_timer)) {
+			ret = qdf_list_remove_node(&p2p_soc_obj->tx_q_ack,
+						   &tx_ctx->node);
+			if (ret == QDF_STATUS_SUCCESS) {
+				qdf_mc_timer_destroy(&tx_ctx->tx_timer);
+				p2p_send_tx_conf(tx_ctx, false);
+				qdf_mem_free(tx_ctx->buf);
+				qdf_mem_free(tx_ctx);
+			} else
+				p2p_err("remove %pK from roc_q fail",
+					tx_ctx);
+		}
+	}
 }
 
 /**
@@ -1366,15 +1386,15 @@ static QDF_STATUS p2p_enable_tx_timer(struct tx_action_context *tx_ctx)
 	p2p_debug("tx context:%pK", tx_ctx);
 
 	status = qdf_mc_timer_init(&tx_ctx->tx_timer,
-			QDF_TIMER_TYPE_SW, p2p_tx_timeout,
-			tx_ctx);
+				   QDF_TIMER_TYPE_SW, p2p_tx_timeout,
+				   tx_ctx->p2p_soc_obj);
 	if (status != QDF_STATUS_SUCCESS) {
 		p2p_err("failed to init tx timer");
 		return status;
 	}
 
 	status = qdf_mc_timer_start(&tx_ctx->tx_timer,
-			P2P_ACTION_FRAME_TX_TIMEOUT);
+				    P2P_ACTION_FRAME_TX_TIMEOUT);
 	if (status != QDF_STATUS_SUCCESS)
 		p2p_err("tx timer start failed");
 
@@ -1648,10 +1668,6 @@ struct tx_action_context *p2p_find_tx_ctx_by_nbuf(
 			qdf_container_of(p_node, struct tx_action_context, node);
 		if (cur_tx_ctx->nbuf == nbuf) {
 			p2p_debug("find tx ctx, nbuf:%pK", nbuf);
-			status = qdf_mc_timer_stop(&cur_tx_ctx->tx_timer);
-			if (status != QDF_STATUS_SUCCESS)
-				p2p_err("Failed to stop tx timer, status:%d",
-					status);
 			return cur_tx_ctx;
 		}
 		status = qdf_list_peek_next(&p2p_soc_obj->tx_q_ack,
@@ -2902,6 +2918,8 @@ QDF_STATUS p2p_process_mgmt_tx_ack_cnf(
 		return QDF_STATUS_SUCCESS;
 	}
 
+	/* disable tx timer */
+	p2p_disable_tx_timer(tx_ctx);
 	tx_cnf.vdev_id = tx_ctx->vdev_id;
 	tx_cnf.action_cookie = (uint64_t)tx_ctx->id;
 	tx_cnf.buf = tx_ctx->buf;
@@ -2915,9 +2933,6 @@ QDF_STATUS p2p_process_mgmt_tx_ack_cnf(
 
 	p2p_rand_mac_tx_done(p2p_soc_obj->soc, tx_ctx);
 
-	/* disable tx timer */
-	p2p_disable_tx_timer(tx_ctx);
-
 	start_param = p2p_soc_obj->start_param;
 	if (start_param->tx_cnf_cb)
 		start_param->tx_cnf_cb(start_param->tx_cnf_cb_data,