Bluetooth: controller: split: Fix buffer leak on disconnect

Fix pending Tx control buffer leak on supervision timeout.
Queued tx buffers in LLL consists of both data and control
PDUs but only data buffers got correctly released.

Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
This commit is contained in:
Vinayak Kariappa Chettimada 2019-06-07 16:27:48 +02:00 committed by Alberto Escolar
commit 3e56c2cf16
3 changed files with 32 additions and 34 deletions

View file

@ -1350,37 +1350,26 @@ static inline void rx_demux_conn_tx_ack(u8_t ack_last, u16_t handle,
#if !defined(CONFIG_BT_CTLR_LOW_LAT_ULL)
do {
#endif /* CONFIG_BT_CTLR_LOW_LAT_ULL */
struct ll_conn *conn;
/* Dequeue node */
ull_conn_ack_dequeue();
if (handle != 0xFFFF) {
struct ll_conn *conn;
/* Process Tx ack */
conn = ull_conn_tx_ack(handle, link, node_tx);
/* Get the conn instance */
conn = ll_conn_get(handle);
/* Release link mem */
ull_conn_link_tx_release(link);
/* Process Tx ack */
ull_conn_tx_ack(conn, link, node_tx);
/* De-mux 1 tx node from FIFO */
ull_conn_tx_demux(1);
/* Release link mem */
ull_conn_link_tx_release(link);
/* De-mux 1 tx node from FIFO */
ull_conn_tx_demux(1);
/* Enqueue towards LLL */
/* Enqueue towards LLL */
if (conn) {
ull_conn_tx_lll_enqueue(conn, 1);
} else {
/* Pass through Tx ack */
ll_tx_ack_put(0xFFFF, node_tx);
/* Release link mem */
ull_conn_link_tx_release(link);
/* De-mux 1 tx node from FIFO */
ull_conn_tx_demux(1);
}
/* check for more rx ack */
link = ull_conn_ack_by_last_peek(ack_last, &handle, &node_tx);
#if defined(CONFIG_BT_CTLR_LOW_LAT_ULL)

View file

@ -1308,7 +1308,6 @@ void ull_conn_lll_tx_flush(void *param)
link = memq_dequeue(lll->memq_tx.tail, &lll->memq_tx.head,
(void **)&tx);
while (link) {
struct pdu_data *p;
struct lll_tx *lll_tx;
u8_t idx;
@ -1319,8 +1318,6 @@ void ull_conn_lll_tx_flush(void *param)
lll_tx->node = tx;
link->next = tx->next;
tx->link = link;
p = (void *)tx->pdu;
p->ll_id = PDU_DATA_LLID_RESV;
MFIFO_ENQUEUE(conn_ack, idx);
@ -1329,27 +1326,39 @@ void ull_conn_lll_tx_flush(void *param)
}
}
void ull_conn_tx_ack(struct ll_conn *conn, memq_link_t *link,
struct node_tx *tx)
struct ll_conn *ull_conn_tx_ack(u16_t handle, memq_link_t *link,
struct node_tx *tx)
{
struct ll_conn *conn = NULL;
struct pdu_data *pdu_tx;
pdu_tx = (void *)tx->pdu;
LL_ASSERT(pdu_tx->len);
if (pdu_tx->ll_id == PDU_DATA_LLID_CTRL) {
ctrl_tx_ack(conn, &tx, pdu_tx);
if (handle != 0xFFFF) {
conn = ll_conn_get(handle);
ctrl_tx_ack(conn, &tx, pdu_tx);
}
/* release mem if points to itself */
if (link->next == (void *)tx) {
mem_release(tx, &mem_conn_tx_ctrl.free);
return;
return conn;
} else if (!tx) {
return;
return conn;
}
} else if (handle != 0xFFFF) {
conn = ll_conn_get(handle);
} else {
pdu_tx->ll_id = PDU_DATA_LLID_RESV;
}
ll_tx_ack_put(conn->lll.handle, tx);
ll_tx_ack_put(handle, tx);
return conn;
}
u8_t ull_conn_llcp_req(void *conn)
@ -1564,7 +1573,7 @@ static void ctrl_tx_enqueue(struct ll_conn *conn, struct node_tx *tx)
}
/* Update last pointer if ctrl added at end of tx list */
if (tx->next == 0) {
if (!tx->next) {
conn->tx_data_last = tx;
}
}

View file

@ -45,6 +45,6 @@ memq_link_t *ull_conn_ack_by_last_peek(u8_t last, u16_t *handle,
struct node_tx **tx);
void *ull_conn_ack_dequeue(void);
void ull_conn_lll_tx_flush(void *param);
void ull_conn_tx_ack(struct ll_conn *conn, memq_link_t *link,
struct node_tx *tx);
struct ll_conn *ull_conn_tx_ack(u16_t handle, memq_link_t *link,
struct node_tx *tx);
u8_t ull_conn_llcp_req(void *conn);