Commit 7f727ac3 authored by Vinayak Kariappa Chettimada's avatar Vinayak Kariappa Chettimada Committed by Anas Nashif
Browse files

Bluetooth: controller: Fix regression in ctrl tx queue handling



Fix control Tx buffer leak into data Tx pool that happens
after a cross-over control procedure response was paused due
to currently active encryption setup procedure, and a new
control Tx PDU in addition to the paused one is enqueued
thereafter.

When the control tx PDUs is resumed but not yet enqueued
towards the radio, if there is a new control Tx PDU enqueued
then the paused control Tx PDU is not set as the head of the
control PDUs in the Tx queue. This caused the paused control
Tx PDU to be associated with data Tx pool, hence causing the
incorrect release into data Tx pool.

Relates to the commit bff76b4c ("Bluetooth: controller:
split: Fix control tx queue handling") and to the
commit 6991d099 ("Bluetooth: controller: Fix control tx
queue handling").

Fixes #32898.

Signed-off-by: default avatarVinayak Kariappa Chettimada <vich@nordicsemi.no>
parent 7d35a8c9
Loading
Loading
Loading
Loading
+26 −12
Original line number Diff line number Diff line
@@ -91,6 +91,7 @@ static inline void event_ch_map_prep(struct ll_conn *conn,
				     uint16_t event_counter);

#if defined(CONFIG_BT_CTLR_LE_ENC)
static inline void ctrl_tx_check_and_resume(struct ll_conn *conn);
static bool is_enc_req_pause_tx(struct ll_conn *conn);
static inline void event_enc_prep(struct ll_conn *conn);
#if defined(CONFIG_BT_PERIPHERAL)
@@ -1868,18 +1869,11 @@ static void tx_demux(void *param)

static struct node_tx *tx_ull_dequeue(struct ll_conn *conn, struct node_tx *tx)
{
#if defined(CONFIG_BT_CTLR_LE_ENC)
	if (!conn->tx_ctrl && (conn->tx_head != conn->tx_data)) {
		struct pdu_data *pdu_data_tx;

		pdu_data_tx = (void *)conn->tx_head->pdu;
		if ((pdu_data_tx->ll_id != PDU_DATA_LLID_CTRL) ||
		    ((pdu_data_tx->llctrl.opcode !=
		      PDU_DATA_LLCTRL_TYPE_ENC_REQ) &&
		     (pdu_data_tx->llctrl.opcode !=
		      PDU_DATA_LLCTRL_TYPE_PAUSE_ENC_REQ))) {
			conn->tx_ctrl = conn->tx_ctrl_last = conn->tx_head;
		}
		ctrl_tx_check_and_resume(conn);
	}
#endif /* CONFIG_BT_CTLR_LE_ENC */

	if (conn->tx_head == conn->tx_ctrl) {
		conn->tx_head = conn->tx_head->next;
@@ -1990,7 +1984,23 @@ static int empty_data_start_release(struct ll_conn *conn, struct node_tx *tx)
}
#endif /* CONFIG_BT_CTLR_LLID_DATA_START_EMPTY */

static void ctrl_tx_last_enqueue(struct ll_conn *conn,
#if defined(CONFIG_BT_CTLR_LE_ENC)
static inline void  ctrl_tx_check_and_resume(struct ll_conn *conn)
{
	struct pdu_data *pdu_data_tx;

	pdu_data_tx = (void *)conn->tx_head->pdu;
	if ((pdu_data_tx->ll_id != PDU_DATA_LLID_CTRL) ||
	    ((pdu_data_tx->llctrl.opcode !=
	      PDU_DATA_LLCTRL_TYPE_ENC_REQ) &&
	     (pdu_data_tx->llctrl.opcode !=
	      PDU_DATA_LLCTRL_TYPE_PAUSE_ENC_REQ))) {
		conn->tx_ctrl = conn->tx_ctrl_last = conn->tx_head;
	}
}
#endif /* CONFIG_BT_CTLR_LE_ENC */

static inline void ctrl_tx_last_enqueue(struct ll_conn *conn,
					struct node_tx *tx)
{
	tx->next = conn->tx_ctrl_last->next;
@@ -2022,6 +2032,10 @@ static inline void ctrl_tx_pause_enqueue(struct ll_conn *conn,
		 */
		if (conn->tx_head == conn->tx_data) {
			conn->tx_data = conn->tx_data->next;
#if defined(CONFIG_BT_CTLR_LE_ENC)
		} else if (!conn->tx_ctrl) {
			ctrl_tx_check_and_resume(conn);
#endif /* CONFIG_BT_CTLR_LE_ENC */
		}

		/* if no ctrl packet already queued, new ctrl added will be