Skip to content

Commit a3ca8d0

Browse files
erbr-othenrikbrixandersen
authored andcommitted
Bluetooth: controller: fixing rx node leak on CPR reject of parallel CPR
In case a CPR is intiated but rejected due to CPR active on other connection, rx nodes are leaked due to retained node not being properly released. Signed-off-by: Erik Brockhoff <[email protected]> (cherry picked from commit edef1b7) Signed-off-by: Vinayak Kariappa Chettimada <[email protected]>
1 parent e8cc179 commit a3ca8d0

File tree

8 files changed

+41
-7
lines changed

8 files changed

+41
-7
lines changed

subsys/bluetooth/controller/ll_sw/ull_llcp.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -291,17 +291,30 @@ void llcp_rx_node_retain(struct proc_ctx *ctx)
291291
ctx->node_ref.rx->hdr.link = ctx->node_ref.link;
292292
}
293293

294+
void llcp_rx_node_release(struct proc_ctx *ctx)
295+
{
296+
LL_ASSERT(ctx->node_ref.rx);
297+
298+
if (ctx->node_ref.rx->hdr.type == NODE_RX_TYPE_RETAIN) {
299+
/* Mark RX node to release and release */
300+
ctx->node_ref.rx->hdr.type = NODE_RX_TYPE_RELEASE;
301+
ll_rx_put_sched(ctx->node_ref.rx->hdr.link, ctx->node_ref.rx);
302+
}
303+
}
304+
294305
void llcp_nodes_release(struct ll_conn *conn, struct proc_ctx *ctx)
295306
{
296307
if (ctx->node_ref.rx && ctx->node_ref.rx->hdr.type == NODE_RX_TYPE_RETAIN) {
297308
/* RX node retained, so release */
298309
ctx->node_ref.rx->hdr.link->mem = conn->llcp.rx_node_release;
310+
ctx->node_ref.rx->hdr.type = NODE_RX_TYPE_RELEASE;
299311
conn->llcp.rx_node_release = ctx->node_ref.rx;
300312
}
301313
#if defined(CONFIG_BT_CTLR_PHY) && defined(CONFIG_BT_CTLR_DATA_LENGTH)
302314
if (ctx->proc == PROC_PHY_UPDATE && ctx->data.pu.ntf_dle_node) {
303315
/* RX node retained, so release */
304316
ctx->data.pu.ntf_dle_node->hdr.link->mem = conn->llcp.rx_node_release;
317+
ctx->data.pu.ntf_dle_node->hdr.type = NODE_RX_TYPE_RELEASE;
305318
conn->llcp.rx_node_release = ctx->data.pu.ntf_dle_node;
306319
}
307320
#endif
@@ -706,9 +719,6 @@ void ull_cp_release_nodes(struct ll_conn *conn)
706719
hdr = &rx->hdr;
707720
rx = hdr->link->mem;
708721

709-
/* Mark for buffer for release */
710-
hdr->type = NODE_RX_TYPE_RELEASE;
711-
712722
/* enqueue rx node towards Thread */
713723
ll_rx_put(hdr->link, hdr);
714724
}

subsys/bluetooth/controller/ll_sw/ull_llcp_common.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1139,6 +1139,7 @@ static void rp_comm_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t gene
11391139

11401140
/* Allocate ntf node */
11411141
ntf = ctx->node_ref.rx;
1142+
ctx->node_ref.rx = NULL;
11421143
LL_ASSERT(ntf);
11431144

11441145
/* This should be an 'old' RX node, so put/sched when done */

subsys/bluetooth/controller/ll_sw/ull_llcp_conn_upd.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -633,8 +633,7 @@ static void lp_cu_check_instant(struct ll_conn *conn, struct proc_ctx *ctx, uint
633633
lp_cu_ntf_complete(conn, ctx, evt, param);
634634
} else {
635635
/* Release RX node kept for NTF */
636-
ctx->node_ref.rx->hdr.type = NODE_RX_TYPE_RELEASE;
637-
ll_rx_put_sched(ctx->node_ref.rx->hdr.link, ctx->node_ref.rx);
636+
llcp_rx_node_release(ctx);
638637
ctx->node_ref.rx = NULL;
639638

640639
lp_cu_complete(conn, ctx);
@@ -973,11 +972,18 @@ static void rp_cu_st_wait_conn_param_req_available(struct ll_conn *conn, struct
973972
case RP_CU_EVT_RUN:
974973
if (cpr_active_is_set(conn)) {
975974
ctx->state = RP_CU_STATE_WAIT_CONN_PARAM_REQ_AVAILABLE;
975+
976976
if (!llcp_rr_ispaused(conn) && llcp_tx_alloc_peek(conn, ctx)) {
977977
/* We're good to reject immediately */
978978
ctx->data.cu.rejected_opcode = PDU_DATA_LLCTRL_TYPE_CONN_PARAM_REQ;
979979
ctx->data.cu.error = BT_HCI_ERR_UNSUPP_LL_PARAM_VAL;
980980
rp_cu_send_reject_ext_ind(conn, ctx, evt, param);
981+
982+
/* Possibly retained rx node to be released as we won't need it */
983+
llcp_rx_node_release(ctx);
984+
ctx->node_ref.rx = NULL;
985+
986+
break;
981987
}
982988
/* In case we have to defer NTF */
983989
llcp_rx_node_retain(ctx);
@@ -992,6 +998,9 @@ static void rp_cu_st_wait_conn_param_req_available(struct ll_conn *conn, struct
992998
rp_cu_conn_param_req_ntf(conn, ctx);
993999
ctx->state = RP_CU_STATE_WAIT_CONN_PARAM_REQ_REPLY;
9941000
} else {
1001+
/* Possibly retained rx node to be released as we won't need it */
1002+
llcp_rx_node_release(ctx);
1003+
ctx->node_ref.rx = NULL;
9951004
#if defined(CONFIG_BT_CTLR_USER_CPR_ANCHOR_POINT_MOVE)
9961005
/* Handle APM as a vendor specific user extension */
9971006
if (conn->lll.role == BT_HCI_ROLE_PERIPHERAL &&
@@ -1177,8 +1186,7 @@ static void rp_cu_check_instant(struct ll_conn *conn, struct proc_ctx *ctx, uint
11771186
cu_ntf(conn, ctx);
11781187
} else {
11791188
/* Release RX node kept for NTF */
1180-
ctx->node_ref.rx->hdr.type = NODE_RX_TYPE_RELEASE;
1181-
ll_rx_put_sched(ctx->node_ref.rx->hdr.link, ctx->node_ref.rx);
1189+
llcp_rx_node_release(ctx);
11821190
ctx->node_ref.rx = NULL;
11831191
}
11841192
rp_cu_complete(conn, ctx);

subsys/bluetooth/controller/ll_sw/ull_llcp_enc.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ static void lp_enc_ntf(struct ll_conn *conn, struct proc_ctx *ctx)
225225

226226
/* Piggy-back on RX node */
227227
ntf = ctx->node_ref.rx;
228+
ctx->node_ref.rx = NULL;
228229
LL_ASSERT(ntf);
229230

230231
ntf->hdr.type = NODE_RX_TYPE_DC_PDU;

subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,7 @@ void llcp_ntf_set_pending(struct ll_conn *conn);
413413
void llcp_ntf_clear_pending(struct ll_conn *conn);
414414
bool llcp_ntf_pending(struct ll_conn *conn);
415415
void llcp_rx_node_retain(struct proc_ctx *ctx);
416+
void llcp_rx_node_release(struct proc_ctx *ctx);
416417

417418
/*
418419
* ULL -> LLL Interface

subsys/bluetooth/controller/ll_sw/ull_llcp_local.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,12 @@ void llcp_lr_check_done(struct ll_conn *conn, struct proc_ctx *ctx)
8181
ctx_header = llcp_lr_peek(conn);
8282
LL_ASSERT(ctx_header == ctx);
8383

84+
/* If we have a node rx it must not be marked RETAIN as
85+
* the memory referenced would leak
86+
*/
87+
LL_ASSERT(ctx->node_ref.rx == NULL ||
88+
ctx->node_ref.rx->hdr.type != NODE_RX_TYPE_RETAIN);
89+
8490
lr_dequeue(conn);
8591

8692
llcp_proc_ctx_release(ctx);

subsys/bluetooth/controller/ll_sw/ull_llcp_phy.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,7 @@ static void pu_ntf(struct ll_conn *conn, struct proc_ctx *ctx)
433433

434434
/* Piggy-back on stored RX node */
435435
ntf = ctx->node_ref.rx;
436+
ctx->node_ref.rx = NULL;
436437
LL_ASSERT(ntf);
437438

438439
if (ctx->data.pu.ntf_pu) {

subsys/bluetooth/controller/ll_sw/ull_llcp_remote.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,12 @@ void llcp_rr_check_done(struct ll_conn *conn, struct proc_ctx *ctx)
118118
ctx_header = llcp_rr_peek(conn);
119119
LL_ASSERT(ctx_header == ctx);
120120

121+
/* If we have a node rx it must not be marked RETAIN as
122+
* the memory referenced would leak
123+
*/
124+
LL_ASSERT(ctx->node_ref.rx == NULL ||
125+
ctx->node_ref.rx->hdr.type != NODE_RX_TYPE_RETAIN);
126+
121127
rr_dequeue(conn);
122128

123129
llcp_proc_ctx_release(ctx);

0 commit comments

Comments
 (0)