Skip to content
Permalink
Browse files

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>
  • Loading branch information...
cvinayak authored and aescolar committed Jun 7, 2019
1 parent ac8e810 commit 3e56c2cf16114f3952603dbd553c570edcc25e45
@@ -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;

/* Get the conn instance */
conn = ll_conn_get(handle);

/* Process Tx ack */
ull_conn_tx_ack(conn, link, node_tx);
/* Process Tx ack */
conn = ull_conn_tx_ack(handle, link, node_tx);

/* Release link mem */
ull_conn_link_tx_release(link);
/* Release link mem */
ull_conn_link_tx_release(link);

/* De-mux 1 tx node from FIFO */
ull_conn_tx_demux(1);
/* 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)
@@ -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;
}
}
@@ -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);

0 comments on commit 3e56c2c

Please sign in to comment.
You can’t perform that action at this time.