Skip to content

Commit

Permalink
Bluetooth: controller: split: Fix buffer leak on disconnect
Browse files Browse the repository at this point in the history
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 17, 2019
1 parent ac8e810 commit 3e56c2c
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 34 deletions.
33 changes: 11 additions & 22 deletions subsys/bluetooth/controller/ll_sw/ull.c
Expand Up @@ -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)
Expand Down
29 changes: 19 additions & 10 deletions subsys/bluetooth/controller/ll_sw/ull_conn.c
Expand Up @@ -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;

Expand All @@ -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);

Expand All @@ -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)
Expand Down Expand Up @@ -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;
}
}
Expand Down
4 changes: 2 additions & 2 deletions subsys/bluetooth/controller/ll_sw/ull_conn_internal.h
Expand Up @@ -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.