Browse Source

qcacmn: Handle late tx ack in P2P component

In some special case, ota tx ack of P2P action frame comes more than
2 second and tx context is free due to tx time out, than crash happens
since of invalid pointer access. Solution is search tx context by nbuf,
do not process the ota tx ack if not find tx context from waiting for
ack queue.

Change-Id: I0778d0f22d963b00af5212b9d6080a95a4888e73
CRs-Fixed: 2142870
Wu Gao 7 years ago
parent
commit
002e799c94

+ 37 - 6
umac/p2p/core/src/wlan_p2p_off_chan_tx.c

@@ -932,9 +932,10 @@ static QDF_STATUS p2p_mgmt_tx(struct tx_action_context *tx_ctx,
 		mgmt_param.frm_len, mgmt_param.vdev_id,
 		mgmt_param.chanfreq, tx_ctx->no_ack);
 
-	status = wlan_mgmt_txrx_mgmt_frame_tx(peer, tx_ctx,
-			(qdf_nbuf_t)packet,
-			tx_comp_cb, tx_ota_comp_cb,
+	tx_ctx->nbuf = packet;
+
+	status = wlan_mgmt_txrx_mgmt_frame_tx(peer, tx_ctx->p2p_soc_obj,
+			(qdf_nbuf_t)packet, tx_comp_cb, tx_ota_comp_cb,
 			WLAN_UMAC_COMP_P2P, &mgmt_param);
 
 	wlan_objmgr_peer_release_ref(peer, WLAN_P2P_ID);
@@ -1138,7 +1139,6 @@ static QDF_STATUS p2p_move_tx_context_to_ack_queue(
 				&tx_ctx->node);
 	if (status != QDF_STATUS_SUCCESS)
 		p2p_err("Failed to insert off chan tx context to wait ack req queue");
-
 	p2p_debug("insert tx context to wait for roc queue, status:%d",
 		status);
 
@@ -1286,8 +1286,8 @@ static void p2p_tx_timeout(void *pdata)
 
 	p2p_debug("pdata:%pK", pdata);
 
-	if (!tx_ctx) {
-		p2p_err("invalid tx context");
+	if (!tx_ctx || !(tx_ctx->p2p_soc_obj)) {
+		p2p_err("invalid tx context or p2p soc object");
 		return;
 	}
 
@@ -1456,6 +1456,37 @@ static QDF_STATUS p2p_execute_tx_action_frame(
 	return status;
 }
 
+struct tx_action_context *p2p_find_tx_ctx_by_nbuf(
+	struct p2p_soc_priv_obj *p2p_soc_obj, void *nbuf)
+{
+	struct tx_action_context *cur_tx_ctx;
+	qdf_list_node_t *p_node;
+	QDF_STATUS status;
+
+	if (!p2p_soc_obj) {
+		p2p_err("invalid p2p soc object");
+		return NULL;
+	}
+
+	status = qdf_list_peek_front(&p2p_soc_obj->tx_q_ack, &p_node);
+	while (QDF_IS_STATUS_SUCCESS(status)) {
+		cur_tx_ctx =
+			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,
+						p_node, &p_node);
+	}
+
+	return NULL;
+}
+
 void p2p_dump_tx_queue(struct p2p_soc_priv_obj *p2p_soc_obj)
 {
 	struct tx_action_context *tx_ctx;

+ 13 - 0
umac/p2p/core/src/wlan_p2p_off_chan_tx.h

@@ -173,6 +173,7 @@ struct tx_action_context {
 	uint32_t duration;
 	qdf_mc_timer_t tx_timer;
 	struct p2p_frame_info frame_info;
+	void *nbuf;
 };
 
 /**
@@ -255,4 +256,16 @@ QDF_STATUS p2p_process_mgmt_tx_ack_cnf(
 QDF_STATUS p2p_process_rx_mgmt(
 	struct p2p_rx_mgmt_event *rx_mgmt_event);
 
+/**
+ * p2p_find_tx_ctx_by_nbuf() - find tx context by nbuf
+ * @p2p_soc_obj:        p2p soc object
+ * @nbuf:               pointer to nbuf
+ *
+ * This function finds out tx context by nbuf.
+ *
+ * Return: pointer to tx context
+ */
+struct tx_action_context *p2p_find_tx_ctx_by_nbuf(
+	struct p2p_soc_priv_obj *p2p_soc_obj, void *nbuf);
+
 #endif /* _WLAN_P2P_OFF_CHAN_TX_H_ */

+ 7 - 2
umac/p2p/dispatcher/src/wlan_p2p_tgt_api.c

@@ -137,8 +137,13 @@ QDF_STATUS tgt_p2p_mgmt_ota_comp_cb(void *context, qdf_nbuf_t buf,
 		qdf_nbuf_free(buf);
 		return QDF_STATUS_E_INVAL;
 	}
-	tx_ctx = (struct tx_action_context *)context;
-	p2p_soc_obj = tx_ctx->p2p_soc_obj;
+	p2p_soc_obj = (struct p2p_soc_priv_obj *)context;
+	tx_ctx = p2p_find_tx_ctx_by_nbuf(p2p_soc_obj, buf);
+	if (!tx_ctx) {
+		p2p_err("can't find tx_ctx, tx ack comes late");
+		qdf_nbuf_free(buf);
+		return QDF_STATUS_E_FAULT;
+	}
 
 	tx_conf_event = qdf_mem_malloc(sizeof(*tx_conf_event));
 	if (!tx_conf_event) {

+ 1 - 0
umac/p2p/dispatcher/src/wlan_p2p_ucfg_api.c

@@ -271,6 +271,7 @@ QDF_STATUS ucfg_p2p_mgmt_tx(struct wlan_objmgr_psoc *soc,
 		return QDF_STATUS_E_NOMEM;
 	}
 	qdf_mem_copy(tx_action->buf, mgmt_frm->buf, tx_action->buf_len);
+	tx_action->nbuf = NULL;
 	msg.type = P2P_MGMT_TX;
 	msg.bodyptr = tx_action;
 	msg.callback = p2p_process_cmd;