Bluetooth: controller: use RX node piggy-back for NTF when possible

When possible re-use the already allocated RX node for notifications.
Store (retain) RX node and Link element on RX if NTF could occur.
Pass link element to LLCP (ull_cp_rx()) together with RX node.
New RX node type RETAIN introduced to signal retention

When no RX node is available allocate one and hold off TX on procedures
until such time that a node is available for NTF.

In case waiting for NTF buffer avail is needed, allocate and store TX
node to use for TX once NTF becomes available.

CIS Established (incl. timeout handling) is now handled entirely as a
specific event driven by ull_conn_iso - ie removal of procedure check
of cis->established and cis->expire, as this is doubling mechanism
in the conn_iso context.

Unit test and helpers updated to handle new node type.
Function ull_cp_release_ntf() was used only in unit test, so moved to
helper context.
Updating release_ntf to handle the fact that with piggy-backing in test
context the node used for NTF can be from two different memory pools

Signed-off-by: Erik Brockhoff <erbr@oticon.com>
This commit is contained in:
Erik Brockhoff 2022-12-01 16:24:38 +01:00 committed by Fabio Baltieri
commit 6dbc446342
26 changed files with 860 additions and 824 deletions

View file

@ -59,7 +59,6 @@ enum {
LP_ENC_STATE_WAIT_RX_START_ENC_REQ,
LP_ENC_STATE_WAIT_TX_START_ENC_RSP,
LP_ENC_STATE_WAIT_RX_START_ENC_RSP,
LP_ENC_STATE_WAIT_NTF,
/* Pause Procedure */
LP_ENC_STATE_ENCRYPTED,
LP_ENC_STATE_WAIT_TX_PAUSE_ENC_REQ,
@ -99,12 +98,10 @@ enum {
RP_ENC_STATE_UNENCRYPTED,
RP_ENC_STATE_WAIT_RX_ENC_REQ,
RP_ENC_STATE_WAIT_TX_ENC_RSP,
RP_ENC_STATE_WAIT_NTF_LTK_REQ,
RP_ENC_STATE_WAIT_LTK_REPLY,
RP_ENC_STATE_WAIT_TX_START_ENC_REQ,
RP_ENC_STATE_WAIT_TX_REJECT_IND,
RP_ENC_STATE_WAIT_RX_START_ENC_RSP,
RP_ENC_STATE_WAIT_NTF,
RP_ENC_STATE_WAIT_TX_START_ENC_RSP,
/* Pause Procedure */
RP_ENC_STATE_ENCRYPTED,
@ -225,8 +222,8 @@ static void lp_enc_ntf(struct ll_conn *conn, struct proc_ctx *ctx)
struct node_rx_pdu *ntf;
struct pdu_data *pdu;
/* Allocate ntf node */
ntf = llcp_ntf_alloc();
/* Piggy-back on RX node */
ntf = ctx->node_ref.rx;
LL_ASSERT(ntf);
ntf->hdr.type = NODE_RX_TYPE_DC_PDU;
@ -248,20 +245,13 @@ static void lp_enc_ntf(struct ll_conn *conn, struct proc_ctx *ctx)
} else {
llcp_pdu_encode_reject_ind(pdu, ctx->data.enc.error);
}
/* Enqueue notification towards LL */
ll_rx_put_sched(ntf->hdr.link, ntf);
}
static void lp_enc_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param)
{
if (!llcp_ntf_alloc_is_available()) {
ctx->state = LP_ENC_STATE_WAIT_NTF;
} else {
lp_enc_ntf(conn, ctx);
llcp_lr_complete(conn);
ctx->state = LP_ENC_STATE_UNENCRYPTED;
}
lp_enc_ntf(conn, ctx);
llcp_lr_complete(conn);
ctx->state = LP_ENC_STATE_UNENCRYPTED;
}
static void lp_enc_store_m(struct ll_conn *conn, struct proc_ctx *ctx, struct pdu_data *pdu)
@ -519,18 +509,6 @@ static void lp_enc_st_wait_rx_start_enc_rsp(struct ll_conn *conn, struct proc_ct
}
}
static void lp_enc_st_wait_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param)
{
switch (evt) {
case LP_ENC_EVT_RUN:
lp_enc_complete(conn, ctx, evt, param);
break;
default:
/* Ignore other evts */
break;
}
}
static void lp_enc_state_encrypted(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt,
void *param)
{
@ -612,9 +590,6 @@ static void lp_enc_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8
case LP_ENC_STATE_WAIT_RX_START_ENC_RSP:
lp_enc_st_wait_rx_start_enc_rsp(conn, ctx, evt, param);
break;
case LP_ENC_STATE_WAIT_NTF:
lp_enc_st_wait_ntf(conn, ctx, evt, param);
break;
/* Pause Procedure */
case LP_ENC_STATE_ENCRYPTED:
lp_enc_state_encrypted(conn, ctx, evt, param);
@ -755,19 +730,26 @@ static void rp_enc_ntf_ltk(struct ll_conn *conn, struct proc_ctx *ctx)
{
struct node_rx_pdu *ntf;
struct pdu_data *pdu;
uint8_t piggy_back;
/* Allocate ntf node */
ntf = llcp_ntf_alloc();
/* Piggy-back on RX node */
ntf = ctx->node_ref.rx;
ctx->node_ref.rx = NULL;
LL_ASSERT(ntf);
piggy_back = (ntf->hdr.type != NODE_RX_TYPE_RETAIN);
ntf->hdr.type = NODE_RX_TYPE_DC_PDU;
ntf->hdr.handle = conn->lll.handle;
pdu = (struct pdu_data *)ntf->pdu;
llcp_ntf_encode_enc_req(ctx, pdu);
/* Enqueue notification towards LL */
ll_rx_put_sched(ntf->hdr.link, ntf);
if (!piggy_back) {
/* Enqueue notification towards LL unless it's piggybacked */
ll_rx_put_sched(ntf->hdr.link, ntf);
}
}
static void rp_enc_ntf(struct ll_conn *conn, struct proc_ctx *ctx)
@ -775,8 +757,9 @@ static void rp_enc_ntf(struct ll_conn *conn, struct proc_ctx *ctx)
struct node_rx_pdu *ntf;
struct pdu_data *pdu;
/* Allocate ntf node */
ntf = llcp_ntf_alloc();
/* Piggy-back on RX node */
ntf = ctx->node_ref.rx;
ctx->node_ref.rx = NULL;
LL_ASSERT(ntf);
ntf->hdr.type = NODE_RX_TYPE_DC_PDU;
@ -794,9 +777,6 @@ static void rp_enc_ntf(struct ll_conn *conn, struct proc_ctx *ctx)
/* Should never happen */
LL_ASSERT(0);
}
/* Enqueue notification towards LL */
ll_rx_put_sched(ntf->hdr.link, ntf);
}
static void rp_enc_send_start_enc_rsp(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt,
@ -804,23 +784,8 @@ static void rp_enc_send_start_enc_rsp(struct ll_conn *conn, struct proc_ctx *ctx
static void rp_enc_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param)
{
if (!llcp_ntf_alloc_is_available()) {
ctx->state = RP_ENC_STATE_WAIT_NTF;
} else {
rp_enc_ntf(conn, ctx);
rp_enc_send_start_enc_rsp(conn, ctx, evt, param);
}
}
static void rp_enc_send_ltk_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt,
void *param)
{
if (!llcp_ntf_alloc_is_available()) {
ctx->state = RP_ENC_STATE_WAIT_NTF_LTK_REQ;
} else {
rp_enc_ntf_ltk(conn, ctx);
ctx->state = RP_ENC_STATE_WAIT_LTK_REPLY;
}
rp_enc_ntf(conn, ctx);
rp_enc_send_start_enc_rsp(conn, ctx, evt, param);
}
static void rp_enc_store_s(struct ll_conn *conn, struct proc_ctx *ctx, struct pdu_data *pdu)
@ -840,11 +805,15 @@ static void rp_enc_send_enc_rsp(struct ll_conn *conn, struct proc_ctx *ctx, uint
struct node_tx *tx;
if (!llcp_tx_alloc_peek(conn, ctx)) {
/* Mark RX node to not release, needed for LTK NTF */
llcp_rx_node_retain(ctx);
ctx->state = RP_ENC_STATE_WAIT_TX_ENC_RSP;
} else {
tx = llcp_rp_enc_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_ENC_RSP);
rp_enc_store_s(conn, ctx, (struct pdu_data *)tx->pdu);
rp_enc_send_ltk_ntf(conn, ctx, evt, param);
rp_enc_ntf_ltk(conn, ctx);
ctx->state = RP_ENC_STATE_WAIT_LTK_REPLY;
}
}
@ -969,6 +938,7 @@ static void rp_enc_state_wait_rx_enc_req(struct ll_conn *conn, struct proc_ctx *
llcp_lr_pause(conn);
rp_enc_store_m(conn, ctx, param);
rp_enc_send_enc_rsp(conn, ctx, evt, param);
break;
default:
@ -990,19 +960,6 @@ static void rp_enc_state_wait_tx_enc_rsp(struct ll_conn *conn, struct proc_ctx *
}
}
static void rp_enc_state_wait_ntf_ltk_req(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt,
void *param)
{
switch (evt) {
case RP_ENC_EVT_RUN:
rp_enc_send_ltk_ntf(conn, ctx, evt, param);
break;
default:
/* Ignore other evts */
break;
}
}
static void rp_enc_state_wait_ltk_reply(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt,
void *param)
{
@ -1058,19 +1015,6 @@ static void rp_enc_state_wait_rx_start_enc_rsp(struct ll_conn *conn, struct proc
}
}
static void rp_enc_state_wait_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt,
void *param)
{
switch (evt) {
case RP_ENC_EVT_RUN:
rp_enc_complete(conn, ctx, evt, param);
break;
default:
/* Ignore other evts */
break;
}
}
static void rp_enc_state_wait_tx_start_enc_rsp(struct ll_conn *conn, struct proc_ctx *ctx,
uint8_t evt, void *param)
{
@ -1162,9 +1106,6 @@ static void rp_enc_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8
case RP_ENC_STATE_WAIT_TX_ENC_RSP:
rp_enc_state_wait_tx_enc_rsp(conn, ctx, evt, param);
break;
case RP_ENC_STATE_WAIT_NTF_LTK_REQ:
rp_enc_state_wait_ntf_ltk_req(conn, ctx, evt, param);
break;
case RP_ENC_STATE_WAIT_LTK_REPLY:
rp_enc_state_wait_ltk_reply(conn, ctx, evt, param);
break;
@ -1177,9 +1118,6 @@ static void rp_enc_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8
case RP_ENC_STATE_WAIT_RX_START_ENC_RSP:
rp_enc_state_wait_rx_start_enc_rsp(conn, ctx, evt, param);
break;
case RP_ENC_STATE_WAIT_NTF:
rp_enc_state_wait_ntf(conn, ctx, evt, param);
break;
case RP_ENC_STATE_WAIT_TX_START_ENC_RSP:
rp_enc_state_wait_tx_start_enc_rsp(conn, ctx, evt, param);
break;