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 commitbff76b4cce
("Bluetooth: controller: split: Fix control tx queue handling") and to the commit6991d09977
("Bluetooth: controller: Fix control tx queue handling"). Fixes #32898. Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
This commit is contained in:
parent
7d35a8c93d
commit
7f727ac322
1 changed files with 26 additions and 12 deletions
|
@ -91,6 +91,7 @@ static inline void event_ch_map_prep(struct ll_conn *conn,
|
||||||
uint16_t event_counter);
|
uint16_t event_counter);
|
||||||
|
|
||||||
#if defined(CONFIG_BT_CTLR_LE_ENC)
|
#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 bool is_enc_req_pause_tx(struct ll_conn *conn);
|
||||||
static inline void event_enc_prep(struct ll_conn *conn);
|
static inline void event_enc_prep(struct ll_conn *conn);
|
||||||
#if defined(CONFIG_BT_PERIPHERAL)
|
#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)
|
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)) {
|
if (!conn->tx_ctrl && (conn->tx_head != conn->tx_data)) {
|
||||||
struct pdu_data *pdu_data_tx;
|
ctrl_tx_check_and_resume(conn);
|
||||||
|
|
||||||
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 */
|
||||||
|
|
||||||
if (conn->tx_head == conn->tx_ctrl) {
|
if (conn->tx_head == conn->tx_ctrl) {
|
||||||
conn->tx_head = conn->tx_head->next;
|
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 */
|
#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)
|
struct node_tx *tx)
|
||||||
{
|
{
|
||||||
tx->next = conn->tx_ctrl_last->next;
|
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) {
|
if (conn->tx_head == conn->tx_data) {
|
||||||
conn->tx_data = conn->tx_data->next;
|
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
|
/* if no ctrl packet already queued, new ctrl added will be
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue