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

This reverts commit 6dbc446342.

Signed-off-by: Erik Brockhoff <erbr@oticon.com>
This commit is contained in:
Erik Brockhoff 2023-03-09 12:36:02 +01:00 committed by Carles Cufí
commit 1028cab11e
26 changed files with 825 additions and 861 deletions

View file

@ -316,8 +316,6 @@ enum node_rx_type {
NODE_RX_TYPE_DTM_IQ_SAMPLE_REPORT, NODE_RX_TYPE_DTM_IQ_SAMPLE_REPORT,
NODE_RX_TYPE_IQ_SAMPLE_REPORT_ULL_RELEASE, NODE_RX_TYPE_IQ_SAMPLE_REPORT_ULL_RELEASE,
NODE_RX_TYPE_IQ_SAMPLE_REPORT_LLL_RELEASE, NODE_RX_TYPE_IQ_SAMPLE_REPORT_LLL_RELEASE,
/* Signals retention (ie non-release) of rx node */
NODE_RX_TYPE_RETAIN,
#if defined(CONFIG_BT_CTLR_USER_EXT) #if defined(CONFIG_BT_CTLR_USER_EXT)
/* No entries shall be added after the NODE_RX_TYPE_USER_START/END */ /* No entries shall be added after the NODE_RX_TYPE_USER_START/END */

View file

@ -2829,8 +2829,7 @@ static inline int rx_demux_rx(memq_link_t *link, struct node_rx_hdr *rx)
(void)memq_dequeue(memq_ull_rx.tail, &memq_ull_rx.head, NULL); (void)memq_dequeue(memq_ull_rx.tail, &memq_ull_rx.head, NULL);
/* Only schedule node if not marked as retain by LLCP */ if (rx) {
if (rx && rx->type != NODE_RX_TYPE_RETAIN) {
ll_rx_put_sched(link, rx); ll_rx_put_sched(link, rx);
} }
} }

View file

@ -1144,7 +1144,6 @@ int ull_conn_rx(memq_link_t *link, struct node_rx_pdu **rx)
#endif /* CONFIG_BT_CTLR_RX_ENQUEUE_HOLD */ #endif /* CONFIG_BT_CTLR_RX_ENQUEUE_HOLD */
#if !defined(CONFIG_BT_LL_SW_LLCP_LEGACY) #if !defined(CONFIG_BT_LL_SW_LLCP_LEGACY)
/* Handle possibly pending NTF/complete */
ull_cp_tx_ntf(conn); ull_cp_tx_ntf(conn);
#endif /* CONFIG_BT_LL_SW_LLCP_LEGACY */ #endif /* CONFIG_BT_LL_SW_LLCP_LEGACY */
@ -1159,13 +1158,13 @@ int ull_conn_rx(memq_link_t *link, struct node_rx_pdu **rx)
nack = ctrl_rx(link, rx, pdu_rx, conn); nack = ctrl_rx(link, rx, pdu_rx, conn);
return nack; return nack;
#else /* CONFIG_BT_LL_SW_LLCP_LEGACY */ #else /* CONFIG_BT_LL_SW_LLCP_LEGACY */
ARG_UNUSED(link);
ARG_UNUSED(pdu_rx); ARG_UNUSED(pdu_rx);
ull_cp_rx(conn, *rx);
/* Mark buffer for release */ /* Mark buffer for release */
(*rx)->hdr.type = NODE_RX_TYPE_RELEASE; (*rx)->hdr.type = NODE_RX_TYPE_RELEASE;
ull_cp_rx(conn, link, *rx);
return 0; return 0;
#endif /* CONFIG_BT_LL_SW_LLCP_LEGACY */ #endif /* CONFIG_BT_LL_SW_LLCP_LEGACY */
} }
@ -1556,7 +1555,6 @@ void ull_conn_done(struct node_rx_event_done *done)
#endif /* CONFIG_BT_CTLR_RX_ENQUEUE_HOLD */ #endif /* CONFIG_BT_CTLR_RX_ENQUEUE_HOLD */
#if !defined(CONFIG_BT_LL_SW_LLCP_LEGACY) #if !defined(CONFIG_BT_LL_SW_LLCP_LEGACY)
/* Handle possibly pending NTF/complete */
ull_cp_tx_ntf(conn); ull_cp_tx_ntf(conn);
#endif /* CONFIG_BT_LL_SW_LLCP_LEGACY */ #endif /* CONFIG_BT_LL_SW_LLCP_LEGACY */

View file

@ -279,17 +279,6 @@ void llcp_tx_resume_data(struct ll_conn *conn, enum llcp_tx_q_pause_data_mask re
} }
} }
void llcp_rx_node_retain(struct proc_ctx *ctx)
{
LL_ASSERT(ctx->node_ref.rx);
/* Mark RX node to NOT release */
ctx->node_ref.rx->hdr.type = NODE_RX_TYPE_RETAIN;
/* store link element reference to use once this node is moved up */
ctx->node_ref.rx->hdr.link = ctx->node_ref.link;
}
/* /*
* LLCP Procedure Creation * LLCP Procedure Creation
*/ */
@ -307,8 +296,7 @@ static struct proc_ctx *create_procedure(enum llcp_proc proc, struct llcp_mem_po
ctx->collision = 0U; ctx->collision = 0U;
ctx->done = 0U; ctx->done = 0U;
ctx->rx_greedy = 0U; ctx->rx_greedy = 0U;
ctx->node_ref.rx = NULL; ctx->tx_ack = NULL;
ctx->node_ref.tx_ack = NULL;
/* Clear procedure data */ /* Clear procedure data */
memset((void *)&ctx->data, 0, sizeof(ctx->data)); memset((void *)&ctx->data, 0, sizeof(ctx->data));
@ -587,6 +575,12 @@ void ull_cp_release_tx(struct ll_conn *conn, struct node_tx *tx)
tx_release(tx); tx_release(tx);
} }
void ull_cp_release_ntf(struct node_rx_pdu *ntf)
{
ntf->hdr.next = NULL;
ll_rx_mem_release((void **)&ntf);
}
static int prt_elapse(uint16_t *expire, uint16_t elapsed_event) static int prt_elapse(uint16_t *expire, uint16_t elapsed_event)
{ {
if (*expire != 0U) { if (*expire != 0U) {
@ -1668,13 +1662,13 @@ void ull_cp_tx_ack(struct ll_conn *conn, struct node_tx *tx)
struct proc_ctx *ctx; struct proc_ctx *ctx;
ctx = llcp_lr_peek(conn); ctx = llcp_lr_peek(conn);
if (ctx && ctx->node_ref.tx_ack == tx) { if (ctx && ctx->tx_ack == tx) {
/* TX ack re. local request */ /* TX ack re. local request */
llcp_lr_tx_ack(conn, ctx, tx); llcp_lr_tx_ack(conn, ctx, tx);
} }
ctx = llcp_rr_peek(conn); ctx = llcp_rr_peek(conn);
if (ctx && ctx->node_ref.tx_ack == tx) { if (ctx && ctx->tx_ack == tx) {
/* TX ack re. remote response */ /* TX ack re. remote response */
llcp_rr_tx_ack(conn, ctx, tx); llcp_rr_tx_ack(conn, ctx, tx);
} }
@ -1697,7 +1691,7 @@ void ull_cp_tx_ntf(struct ll_conn *conn)
} }
} }
void ull_cp_rx(struct ll_conn *conn, memq_link_t *link, struct node_rx_pdu *rx) void ull_cp_rx(struct ll_conn *conn, struct node_rx_pdu *rx)
{ {
struct proc_ctx *ctx_l; struct proc_ctx *ctx_l;
struct proc_ctx *ctx_r; struct proc_ctx *ctx_r;
@ -1768,7 +1762,7 @@ void ull_cp_rx(struct ll_conn *conn, memq_link_t *link, struct node_rx_pdu *rx)
*/ */
/* Process PDU in remote procedure */ /* Process PDU in remote procedure */
llcp_rr_rx(conn, ctx_r, link, rx); llcp_rr_rx(conn, ctx_r, rx);
} else if (unexpected_r) { } else if (unexpected_r) {
/* Local active procedure /* Local active procedure
* Expected local procedure PDU * Expected local procedure PDU
@ -1777,7 +1771,7 @@ void ull_cp_rx(struct ll_conn *conn, memq_link_t *link, struct node_rx_pdu *rx)
*/ */
/* Process PDU in local procedure */ /* Process PDU in local procedure */
llcp_lr_rx(conn, ctx_l, link, rx); llcp_lr_rx(conn, ctx_l, rx);
} else { } else {
/* Local active procedure /* Local active procedure
* Expected local procedure PDU * Expected local procedure PDU
@ -1805,7 +1799,7 @@ void ull_cp_rx(struct ll_conn *conn, memq_link_t *link, struct node_rx_pdu *rx)
/* Process PDU as a new remote request */ /* Process PDU as a new remote request */
LL_ASSERT(pdu_valid); LL_ASSERT(pdu_valid);
llcp_rr_new(conn, link, rx, true); llcp_rr_new(conn, rx, true);
} else { } else {
/* Local active procedure /* Local active procedure
* Expected local procedure PDU * Expected local procedure PDU
@ -1813,7 +1807,7 @@ void ull_cp_rx(struct ll_conn *conn, memq_link_t *link, struct node_rx_pdu *rx)
*/ */
/* Process PDU in local procedure */ /* Process PDU in local procedure */
llcp_lr_rx(conn, ctx_l, link, rx); llcp_lr_rx(conn, ctx_l, rx);
} }
} }
} else if (ctx_r) { } else if (ctx_r) {
@ -1822,14 +1816,14 @@ void ull_cp_rx(struct ll_conn *conn, memq_link_t *link, struct node_rx_pdu *rx)
*/ */
/* Process PDU in remote procedure */ /* Process PDU in remote procedure */
llcp_rr_rx(conn, ctx_r, link, rx); llcp_rr_rx(conn, ctx_r, rx);
} else { } else {
/* No local active procedure /* No local active procedure
* No remote active procedure * No remote active procedure
*/ */
/* Process PDU as a new remote request */ /* Process PDU as a new remote request */
llcp_rr_new(conn, link, rx, pdu_valid); llcp_rr_new(conn, rx, pdu_valid);
} }
} }

View file

@ -35,6 +35,11 @@ void ull_cp_update_tx_buffer_queue(struct ll_conn *conn);
*/ */
void ull_cp_release_tx(struct ll_conn *conn, struct node_tx *tx); void ull_cp_release_tx(struct ll_conn *conn, struct node_tx *tx);
/**
*
*/
void ull_cp_release_ntf(struct node_rx_pdu *ntf);
/** /**
* @brief Procedure Response Timeout Check * @brief Procedure Response Timeout Check
* @param elapsed_event The number of elapsed events. * @param elapsed_event The number of elapsed events.
@ -63,7 +68,7 @@ void ull_cp_tx_ntf(struct ll_conn *conn);
/** /**
* @brief Handle received LL Control PDU. * @brief Handle received LL Control PDU.
*/ */
void ull_cp_rx(struct ll_conn *conn, memq_link_t *link, struct node_rx_pdu *rx); void ull_cp_rx(struct ll_conn *conn, struct node_rx_pdu *rx);
#if defined(CONFIG_BT_CTLR_LE_PING) #if defined(CONFIG_BT_CTLR_LE_PING)
/** /**

View file

@ -52,18 +52,31 @@
#include <soc.h> #include <soc.h>
#include "hal/debug.h" #include "hal/debug.h"
static bool cc_check_cis_established_or_timeout_lll(struct proc_ctx *ctx)
{
const struct ll_conn_iso_stream *cis =
ll_conn_iso_stream_get(ctx->data.cis_create.cis_handle);
if (cis->established) {
return true;
}
if (!cis->event_expire) {
ctx->data.cis_create.error = BT_HCI_ERR_CONN_FAIL_TO_ESTAB;
return true;
}
return false;
}
static void cc_ntf_established(struct ll_conn *conn, struct proc_ctx *ctx) static void cc_ntf_established(struct ll_conn *conn, struct proc_ctx *ctx)
{ {
struct node_rx_conn_iso_estab *pdu;
struct node_rx_pdu *ntf; struct node_rx_pdu *ntf;
uint8_t piggy_back; struct node_rx_conn_iso_estab *pdu;
/* Allocate ntf node */ /* Allocate ntf node */
ntf = ctx->node_ref.rx; ntf = llcp_ntf_alloc();
LL_ASSERT(ntf); LL_ASSERT(ntf);
ctx->node_ref.rx = NULL;
piggy_back = (ntf->hdr.type != NODE_RX_TYPE_RETAIN);
ntf->hdr.type = NODE_RX_TYPE_CIS_ESTABLISHED; ntf->hdr.type = NODE_RX_TYPE_CIS_ESTABLISHED;
ntf->hdr.handle = conn->lll.handle; ntf->hdr.handle = conn->lll.handle;
@ -74,10 +87,8 @@ static void cc_ntf_established(struct ll_conn *conn, struct proc_ctx *ctx)
pdu->cis_handle = ctx->data.cis_create.cis_handle; pdu->cis_handle = ctx->data.cis_create.cis_handle;
pdu->status = ctx->data.cis_create.error; pdu->status = ctx->data.cis_create.error;
if (!piggy_back) { /* Enqueue notification towards LL */
/* Enqueue notification towards LL */ ll_rx_put_sched(ntf->hdr.link, ntf);
ll_rx_put_sched(ntf->hdr.link, ntf);
}
} }
#if defined(CONFIG_BT_PERIPHERAL) #if defined(CONFIG_BT_PERIPHERAL)
@ -86,13 +97,14 @@ enum {
/* Establish Procedure */ /* Establish Procedure */
RP_CC_STATE_IDLE, RP_CC_STATE_IDLE,
RP_CC_STATE_WAIT_RX_CIS_REQ, RP_CC_STATE_WAIT_RX_CIS_REQ,
RP_CC_STATE_WAIT_NTF_CIS_CREATE,
RP_CC_STATE_WAIT_REPLY, RP_CC_STATE_WAIT_REPLY,
RP_CC_STATE_WAIT_TX_CIS_RSP, RP_CC_STATE_WAIT_TX_CIS_RSP,
RP_CC_STATE_WAIT_TX_REJECT_IND, RP_CC_STATE_WAIT_TX_REJECT_IND,
RP_CC_STATE_WAIT_RX_CIS_IND, RP_CC_STATE_WAIT_RX_CIS_IND,
RP_CC_STATE_WAIT_INSTANT, RP_CC_STATE_WAIT_INSTANT,
RP_CC_STATE_WAIT_CIS_ESTABLISHED, RP_CC_STATE_WAIT_CIS_ESTABLISHED,
RP_CC_STATE_WAIT_NTF_AVAIL, RP_CC_STATE_WAIT_NTF,
}; };
/* LLCP Remote Procedure FSM events */ /* LLCP Remote Procedure FSM events */
@ -190,9 +202,8 @@ static void llcp_rp_cc_tx_reject(struct ll_conn *conn, struct proc_ctx *ctx, uin
struct pdu_data *pdu; struct pdu_data *pdu;
/* Allocate tx node */ /* Allocate tx node */
tx = ctx->node_ref.tx_ack; tx = llcp_tx_alloc(conn, ctx);
LL_ASSERT(tx); LL_ASSERT(tx);
ctx->node_ref.tx_ack = NULL;
pdu = (struct pdu_data *)tx->pdu; pdu = (struct pdu_data *)tx->pdu;
@ -209,8 +220,8 @@ static void rp_cc_ntf_create(struct ll_conn *conn, struct proc_ctx *ctx)
struct node_rx_pdu *ntf; struct node_rx_pdu *ntf;
struct node_rx_conn_iso_req *pdu; struct node_rx_conn_iso_req *pdu;
ntf = ctx->node_ref.rx; /* Allocate ntf node */
ctx->node_ref.rx = NULL; ntf = llcp_ntf_alloc();
LL_ASSERT(ntf); LL_ASSERT(ntf);
ntf->hdr.type = NODE_RX_TYPE_CIS_REQUEST; ntf->hdr.type = NODE_RX_TYPE_CIS_REQUEST;
@ -222,13 +233,20 @@ static void rp_cc_ntf_create(struct ll_conn *conn, struct proc_ctx *ctx)
pdu->cis_handle = ctx->data.cis_create.cis_handle; pdu->cis_handle = ctx->data.cis_create.cis_handle;
ctx->data.cis_create.host_request_to = 0U; ctx->data.cis_create.host_request_to = 0U;
/* Enqueue notification towards LL */
ll_rx_put_sched(ntf->hdr.link, ntf);
} }
static void rp_cc_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) static void rp_cc_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param)
{ {
cc_ntf_established(conn, ctx); if (!llcp_ntf_alloc_is_available()) {
llcp_rr_complete(conn); ctx->state = RP_CC_STATE_WAIT_NTF;
ctx->state = RP_CC_STATE_IDLE; } else {
cc_ntf_established(conn, ctx);
llcp_rr_complete(conn);
ctx->state = RP_CC_STATE_IDLE;
}
} }
static void rp_cc_send_cis_rsp(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, static void rp_cc_send_cis_rsp(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt,
@ -245,28 +263,23 @@ static void rp_cc_send_cis_rsp(struct ll_conn *conn, struct proc_ctx *ctx, uint8
} }
} }
static void rp_cc_send_create_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt,
void *param)
{
if (!llcp_ntf_alloc_is_available()) {
ctx->state = RP_CC_STATE_WAIT_NTF_CIS_CREATE;
} else {
rp_cc_ntf_create(conn, ctx);
ctx->state = RP_CC_STATE_WAIT_REPLY;
}
}
static void rp_cc_send_reject_ind(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, static void rp_cc_send_reject_ind(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt,
void *param) void *param)
{ {
if (llcp_rr_ispaused(conn) || !llcp_tx_alloc_peek(conn, ctx)) { if (llcp_rr_ispaused(conn) || !llcp_tx_alloc_peek(conn, ctx)) {
ctx->state = RP_CC_STATE_WAIT_TX_REJECT_IND; ctx->state = RP_CC_STATE_WAIT_TX_REJECT_IND;
} else { } else {
/* Allocate TX node to use, store in case we need to wait for NTF node */
ctx->node_ref.tx_ack = llcp_tx_alloc(conn, ctx);
if (ctx->data.cis_create.error == BT_HCI_ERR_CONN_ACCEPT_TIMEOUT) {
/* We complete with error, so we must generate NTF, thus we must make sure
* we have a node to use for NTF before TX'ing
*/
if (!llcp_ntf_alloc_is_available()) {
ctx->state = RP_CC_STATE_WAIT_NTF_AVAIL;
return;
}
ctx->node_ref.rx = llcp_ntf_alloc();
/* Mark node as RETAIN to trigger put/sched */
ctx->node_ref.rx->hdr.type = NODE_RX_TYPE_RETAIN;
}
llcp_rp_cc_tx_reject(conn, ctx, PDU_DATA_LLCTRL_TYPE_CIS_REQ); llcp_rp_cc_tx_reject(conn, ctx, PDU_DATA_LLCTRL_TYPE_CIS_REQ);
if (ctx->data.cis_create.error == BT_HCI_ERR_CONN_ACCEPT_TIMEOUT) { if (ctx->data.cis_create.error == BT_HCI_ERR_CONN_ACCEPT_TIMEOUT) {
@ -344,8 +357,7 @@ static void rp_cc_state_wait_rx_cis_req(struct ll_conn *conn, struct proc_ctx *c
if (ctx->data.cis_create.error == BT_HCI_ERR_SUCCESS) { if (ctx->data.cis_create.error == BT_HCI_ERR_SUCCESS) {
/* Now controller accepts, so go ask the host to accept or decline */ /* Now controller accepts, so go ask the host to accept or decline */
rp_cc_ntf_create(conn, ctx); rp_cc_send_create_ntf(conn, ctx, evt, param);
ctx->state = RP_CC_STATE_WAIT_REPLY;
} else { } else {
/* Now controller rejects, right out */ /* Now controller rejects, right out */
rp_cc_send_reject_ind(conn, ctx, evt, param); rp_cc_send_reject_ind(conn, ctx, evt, param);
@ -398,9 +410,6 @@ static void rp_cc_state_wait_rx_cis_ind(struct ll_conn *conn, struct proc_ctx *c
/* CIS has been setup, go wait for 'instant' before starting */ /* CIS has been setup, go wait for 'instant' before starting */
ctx->state = RP_CC_STATE_WAIT_INSTANT; ctx->state = RP_CC_STATE_WAIT_INSTANT;
/* Mark node as RETAIN to keep until we need for NTF */
llcp_rx_node_retain(ctx);
/* Check if this connection event is where we need to start the CIS */ /* Check if this connection event is where we need to start the CIS */
rp_cc_check_instant(conn, ctx, evt, param); rp_cc_check_instant(conn, ctx, evt, param);
break; break;
@ -418,20 +427,12 @@ static void rp_cc_state_wait_rx_cis_ind(struct ll_conn *conn, struct proc_ctx *c
} }
} }
static void rp_cc_state_wait_ntf_avail(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, static void rp_cc_state_wait_ntf_cis_create(struct ll_conn *conn, struct proc_ctx *ctx,
void *param) uint8_t evt, void *param)
{ {
switch (evt) { switch (evt) {
case RP_CC_EVT_RUN: case RP_CC_EVT_RUN:
if (llcp_ntf_alloc_is_available()) { rp_cc_send_create_ntf(conn, ctx, evt, param);
ctx->node_ref.rx = llcp_ntf_alloc();
/* Mark node as RETAIN to trigger put/sched */
ctx->node_ref.rx->hdr.type = NODE_RX_TYPE_RETAIN;
/* Now we're good to TX reject and complete procedure*/
llcp_rp_cc_tx_reject(conn, ctx, PDU_DATA_LLCTRL_TYPE_CIS_REQ);
rp_cc_complete(conn, ctx, evt, param);
}
break; break;
default: default:
/* Ignore other evts */ /* Ignore other evts */
@ -439,6 +440,18 @@ static void rp_cc_state_wait_ntf_avail(struct ll_conn *conn, struct proc_ctx *ct
} }
} }
static void rp_cc_state_wait_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt,
void *param)
{
switch (evt) {
case RP_CC_EVT_RUN:
rp_cc_complete(conn, ctx, evt, param);
break;
default:
/* Ignore other evts */
break;
}
}
static void rp_cc_check_instant(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, static void rp_cc_check_instant(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt,
void *param) void *param)
@ -511,7 +524,18 @@ static void rp_cc_state_wait_cis_established(struct ll_conn *conn, struct proc_c
uint8_t evt, void *param) uint8_t evt, void *param)
{ {
switch (evt) { switch (evt) {
case RP_CC_EVT_RUN:
/* Check for CIS state */
if (cc_check_cis_established_or_timeout_lll(ctx)) {
/* CIS was established or establishement timed out,
* In either case complete procedure and generate
* notification
*/
rp_cc_complete(conn, ctx, evt, param);
}
break;
case RP_CC_EVT_CIS_ESTABLISHED: case RP_CC_EVT_CIS_ESTABLISHED:
/* CIS was established, so let's go ahead and complete procedure */
rp_cc_complete(conn, ctx, evt, param); rp_cc_complete(conn, ctx, evt, param);
break; break;
default: default:
@ -531,6 +555,9 @@ static void rp_cc_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_
case RP_CC_STATE_WAIT_RX_CIS_REQ: case RP_CC_STATE_WAIT_RX_CIS_REQ:
rp_cc_state_wait_rx_cis_req(conn, ctx, evt, param); rp_cc_state_wait_rx_cis_req(conn, ctx, evt, param);
break; break;
case RP_CC_STATE_WAIT_NTF_CIS_CREATE:
rp_cc_state_wait_ntf_cis_create(conn, ctx, evt, param);
break;
case RP_CC_STATE_WAIT_TX_REJECT_IND: case RP_CC_STATE_WAIT_TX_REJECT_IND:
rp_cc_state_wait_tx_reject_ind(conn, ctx, evt, param); rp_cc_state_wait_tx_reject_ind(conn, ctx, evt, param);
break; break;
@ -549,8 +576,8 @@ static void rp_cc_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_
case RP_CC_STATE_WAIT_CIS_ESTABLISHED: case RP_CC_STATE_WAIT_CIS_ESTABLISHED:
rp_cc_state_wait_cis_established(conn, ctx, evt, param); rp_cc_state_wait_cis_established(conn, ctx, evt, param);
break; break;
case RP_CC_STATE_WAIT_NTF_AVAIL: case RP_CC_STATE_WAIT_NTF:
rp_cc_state_wait_ntf_avail(conn, ctx, evt, param); rp_cc_state_wait_ntf(conn, ctx, evt, param);
break; break;
default: default:
/* Unknown state */ /* Unknown state */
@ -641,6 +668,7 @@ enum {
LP_CC_STATE_WAIT_TX_CIS_IND, LP_CC_STATE_WAIT_TX_CIS_IND,
LP_CC_STATE_WAIT_INSTANT, LP_CC_STATE_WAIT_INSTANT,
LP_CC_STATE_WAIT_ESTABLISHED, LP_CC_STATE_WAIT_ESTABLISHED,
LP_CC_STATE_WAIT_NTF,
}; };
/* LLCP Local Procedure CIS Creation FSM events */ /* LLCP Local Procedure CIS Creation FSM events */
@ -795,9 +823,13 @@ static void lp_cc_send_cis_ind(struct ll_conn *conn, struct proc_ctx *ctx, uint8
static void lp_cc_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) static void lp_cc_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param)
{ {
cc_ntf_established(conn, ctx); if (!llcp_ntf_alloc_is_available()) {
llcp_lr_complete(conn); ctx->state = LP_CC_STATE_WAIT_NTF;
ctx->state = LP_CC_STATE_IDLE; } else {
cc_ntf_established(conn, ctx);
llcp_lr_complete(conn);
ctx->state = LP_CC_STATE_IDLE;
}
} }
static void lp_cc_st_wait_rx_cis_rsp(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, static void lp_cc_st_wait_rx_cis_rsp(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt,
@ -809,10 +841,6 @@ static void lp_cc_st_wait_rx_cis_rsp(struct ll_conn *conn, struct proc_ctx *ctx,
case LP_CC_EVT_CIS_RSP: case LP_CC_EVT_CIS_RSP:
/* TODO: Reject response if outside offset range? */ /* TODO: Reject response if outside offset range? */
llcp_pdu_decode_cis_rsp(ctx, param); llcp_pdu_decode_cis_rsp(ctx, param);
/* Mark RX node to NOT release */
llcp_rx_node_retain(ctx);
lp_cc_send_cis_ind(conn, ctx, evt, param); lp_cc_send_cis_ind(conn, ctx, evt, param);
break; break;
case LP_CC_EVT_UNKNOWN: case LP_CC_EVT_UNKNOWN:
@ -887,6 +915,12 @@ static void lp_cc_st_wait_established(struct ll_conn *conn, struct proc_ctx *ctx
void *param) void *param)
{ {
switch (evt) { switch (evt) {
case LP_CC_EVT_RUN:
if (cc_check_cis_established_or_timeout_lll(ctx)) {
/* CIS was established, so let's got ahead and complete procedure */
lp_cc_complete(conn, ctx, evt, param);
}
break;
case LP_CC_EVT_ESTABLISHED: case LP_CC_EVT_ESTABLISHED:
/* CIS was established, so let's go ahead and complete procedure */ /* CIS was established, so let's go ahead and complete procedure */
lp_cc_complete(conn, ctx, evt, param); lp_cc_complete(conn, ctx, evt, param);
@ -897,6 +931,18 @@ static void lp_cc_st_wait_established(struct ll_conn *conn, struct proc_ctx *ctx
} }
} }
static void lp_cc_st_wait_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param)
{
switch (evt) {
case LP_CC_EVT_RUN:
lp_cc_complete(conn, ctx, evt, param);
break;
default:
/* Ignore other evts */
break;
}
}
static void lp_cc_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) static void lp_cc_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param)
{ {
switch (ctx->state) { switch (ctx->state) {
@ -918,6 +964,9 @@ static void lp_cc_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_
case LP_CC_STATE_WAIT_ESTABLISHED: case LP_CC_STATE_WAIT_ESTABLISHED:
lp_cc_st_wait_established(conn, ctx, evt, param); lp_cc_st_wait_established(conn, ctx, evt, param);
break; break;
case LP_CC_STATE_WAIT_NTF:
lp_cc_st_wait_ntf(conn, ctx, evt, param);
break;
default: default:
/* Unknown state */ /* Unknown state */
LL_ASSERT(0); LL_ASSERT(0);

View file

@ -57,7 +57,7 @@ enum {
LP_COMMON_STATE_WAIT_TX, LP_COMMON_STATE_WAIT_TX,
LP_COMMON_STATE_WAIT_TX_ACK, LP_COMMON_STATE_WAIT_TX_ACK,
LP_COMMON_STATE_WAIT_RX, LP_COMMON_STATE_WAIT_RX,
LP_COMMON_STATE_WAIT_NTF_AVAIL, LP_COMMON_STATE_WAIT_NTF,
}; };
/* LLCP Local Procedure Common FSM events */ /* LLCP Local Procedure Common FSM events */
@ -88,6 +88,7 @@ enum {
RP_COMMON_STATE_POSTPONE_TERMINATE, RP_COMMON_STATE_POSTPONE_TERMINATE,
RP_COMMON_STATE_WAIT_TX, RP_COMMON_STATE_WAIT_TX,
RP_COMMON_STATE_WAIT_TX_ACK, RP_COMMON_STATE_WAIT_TX_ACK,
RP_COMMON_STATE_WAIT_NTF,
}; };
/* LLCP Remote Procedure Common FSM events */ /* LLCP Remote Procedure Common FSM events */
enum { enum {
@ -150,11 +151,6 @@ static void lp_comm_tx(struct ll_conn *conn, struct proc_ctx *ctx)
pdu = (struct pdu_data *)tx->pdu; pdu = (struct pdu_data *)tx->pdu;
/* Clear tx_ack/rx node reference due to dual/union functionality
* rx node might be !=NULL and thus tx_ack !=NULL
*/
ctx->node_ref.tx_ack = NULL;
/* Encode LL Control PDU */ /* Encode LL Control PDU */
switch (ctx->proc) { switch (ctx->proc) {
#if defined(CONFIG_BT_CTLR_LE_PING) #if defined(CONFIG_BT_CTLR_LE_PING)
@ -170,7 +166,7 @@ static void lp_comm_tx(struct ll_conn *conn, struct proc_ctx *ctx)
#if defined(CONFIG_BT_CTLR_MIN_USED_CHAN) && defined(CONFIG_BT_PERIPHERAL) #if defined(CONFIG_BT_CTLR_MIN_USED_CHAN) && defined(CONFIG_BT_PERIPHERAL)
case PROC_MIN_USED_CHANS: case PROC_MIN_USED_CHANS:
llcp_pdu_encode_min_used_chans_ind(ctx, pdu); llcp_pdu_encode_min_used_chans_ind(ctx, pdu);
ctx->node_ref.tx_ack = tx; ctx->tx_ack = tx;
ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED; ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED;
break; break;
#endif /* CONFIG_BT_CTLR_MIN_USED_CHAN && CONFIG_BT_PERIPHERAL */ #endif /* CONFIG_BT_CTLR_MIN_USED_CHAN && CONFIG_BT_PERIPHERAL */
@ -180,13 +176,13 @@ static void lp_comm_tx(struct ll_conn *conn, struct proc_ctx *ctx)
break; break;
case PROC_TERMINATE: case PROC_TERMINATE:
llcp_pdu_encode_terminate_ind(ctx, pdu); llcp_pdu_encode_terminate_ind(ctx, pdu);
ctx->node_ref.tx_ack = tx; ctx->tx_ack = tx;
ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED; ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED;
break; break;
#if defined(CONFIG_BT_CTLR_CENTRAL_ISO) || defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) #if defined(CONFIG_BT_CTLR_CENTRAL_ISO) || defined(CONFIG_BT_CTLR_PERIPHERAL_ISO)
case PROC_CIS_TERMINATE: case PROC_CIS_TERMINATE:
llcp_pdu_encode_cis_terminate_ind(ctx, pdu); llcp_pdu_encode_cis_terminate_ind(ctx, pdu);
ctx->node_ref.tx_ack = tx; ctx->tx_ack = tx;
ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED; ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED;
break; break;
#endif /* CONFIG_BT_CTLR_CENTRAL_ISO || CONFIG_BT_CTLR_PERIPHERAL_ISO */ #endif /* CONFIG_BT_CTLR_CENTRAL_ISO || CONFIG_BT_CTLR_PERIPHERAL_ISO */
@ -303,9 +299,13 @@ static void lp_comm_ntf_cte_req(struct ll_conn *conn, struct proc_ctx *ctx, stru
static void lp_comm_ntf_cte_req_tx(struct ll_conn *conn, struct proc_ctx *ctx) static void lp_comm_ntf_cte_req_tx(struct ll_conn *conn, struct proc_ctx *ctx)
{ {
lp_comm_ntf(conn, ctx); if (llcp_ntf_alloc_is_available()) {
ull_cp_cte_req_set_disable(conn); lp_comm_ntf(conn, ctx);
ctx->state = LP_COMMON_STATE_IDLE; ull_cp_cte_req_set_disable(conn);
ctx->state = LP_COMMON_STATE_IDLE;
} else {
ctx->state = LP_COMMON_STATE_WAIT_NTF;
}
} }
static void lp_comm_complete_cte_req(struct ll_conn *conn, struct proc_ctx *ctx) static void lp_comm_complete_cte_req(struct ll_conn *conn, struct proc_ctx *ctx)
@ -376,18 +376,12 @@ static void lp_comm_ntf_sca(struct node_rx_pdu *ntf, struct proc_ctx *ctx, struc
static void lp_comm_ntf(struct ll_conn *conn, struct proc_ctx *ctx) static void lp_comm_ntf(struct ll_conn *conn, struct proc_ctx *ctx)
{ {
uint8_t piggy_back = 1U;
struct node_rx_pdu *ntf; struct node_rx_pdu *ntf;
struct pdu_data *pdu; struct pdu_data *pdu;
ntf = ctx->node_ref.rx; /* Allocate ntf node */
ctx->node_ref.rx = NULL; ntf = llcp_ntf_alloc();
if (!ntf) { LL_ASSERT(ntf);
/* Allocate ntf node */
ntf = llcp_ntf_alloc();
LL_ASSERT(ntf);
piggy_back = 0U;
}
ntf->hdr.type = NODE_RX_TYPE_DC_PDU; ntf->hdr.type = NODE_RX_TYPE_DC_PDU;
ntf->hdr.handle = conn->lll.handle; ntf->hdr.handle = conn->lll.handle;
@ -420,14 +414,8 @@ static void lp_comm_ntf(struct ll_conn *conn, struct proc_ctx *ctx)
break; break;
} }
if (!piggy_back) { /* Enqueue notification towards LL */
/* Enqueue notification towards LL, unless we re-use RX node, ll_rx_put_sched(ntf->hdr.link, ntf);
* in which case it is handled on the ull_cp_rx return path
*/
ll_rx_put_sched(ntf->hdr.link, ntf);
}
} }
static void lp_comm_terminate_invalid_pdu(struct ll_conn *conn, struct proc_ctx *ctx) static void lp_comm_terminate_invalid_pdu(struct ll_conn *conn, struct proc_ctx *ctx)
@ -439,6 +427,23 @@ static void lp_comm_terminate_invalid_pdu(struct ll_conn *conn, struct proc_ctx
ctx->state = LP_COMMON_STATE_IDLE; ctx->state = LP_COMMON_STATE_IDLE;
} }
static void lp_comm_ntf_complete_proxy(struct ll_conn *conn, struct proc_ctx *ctx,
const bool valid_pdu)
{
if (valid_pdu) {
if (!llcp_ntf_alloc_is_available()) {
ctx->state = LP_COMMON_STATE_WAIT_NTF;
} else {
lp_comm_ntf(conn, ctx);
llcp_lr_complete(conn);
ctx->state = LP_COMMON_STATE_IDLE;
}
} else {
/* Illegal response opcode */
lp_comm_terminate_invalid_pdu(conn, ctx);
}
}
static void lp_comm_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) static void lp_comm_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param)
{ {
switch (ctx->proc) { switch (ctx->proc) {
@ -455,15 +460,9 @@ static void lp_comm_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t
break; break;
#endif /* CONFIG_BT_CTLR_LE_PING */ #endif /* CONFIG_BT_CTLR_LE_PING */
case PROC_FEATURE_EXCHANGE: case PROC_FEATURE_EXCHANGE:
if ((ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_UNKNOWN_RSP || lp_comm_ntf_complete_proxy(conn, ctx,
ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_FEATURE_RSP)) { (ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_UNKNOWN_RSP ||
lp_comm_ntf(conn, ctx); ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_FEATURE_RSP));
llcp_lr_complete(conn);
ctx->state = LP_COMMON_STATE_IDLE;
} else {
/* Illegal response opcode */
lp_comm_terminate_invalid_pdu(conn, ctx);
}
break; break;
#if defined(CONFIG_BT_CTLR_MIN_USED_CHAN) && defined(CONFIG_BT_PERIPHERAL) #if defined(CONFIG_BT_CTLR_MIN_USED_CHAN) && defined(CONFIG_BT_PERIPHERAL)
case PROC_MIN_USED_CHANS: case PROC_MIN_USED_CHANS:
@ -472,25 +471,8 @@ static void lp_comm_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t
break; break;
#endif /* CONFIG_BT_CTLR_MIN_USED_CHAN && CONFIG_BT_PERIPHERAL */ #endif /* CONFIG_BT_CTLR_MIN_USED_CHAN && CONFIG_BT_PERIPHERAL */
case PROC_VERSION_EXCHANGE: case PROC_VERSION_EXCHANGE:
if (ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_VERSION_IND) { lp_comm_ntf_complete_proxy(conn, ctx,
if (ctx->node_ref.rx || llcp_ntf_alloc_is_available()) { (ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_VERSION_IND));
/* Either this is a piggy-back or there is a NTF node avail */
lp_comm_ntf(conn, ctx);
llcp_lr_complete(conn);
ctx->state = LP_COMMON_STATE_IDLE;
} else {
/* Handle procedure TO, in case we end up waiting 'forever' for
* NTF buffer. This is a simple way to implement mechanism to
* trigger disconnect in case NTF buffer 'never' becomes avail
* see elaborate note in lp_comm_st_wait_ntf_avail()
*/
llcp_lr_prt_restart(conn);
ctx->state = LP_COMMON_STATE_WAIT_NTF_AVAIL;
}
} else {
/* Illegal response opcode */
lp_comm_terminate_invalid_pdu(conn, ctx);
}
break; break;
case PROC_TERMINATE: case PROC_TERMINATE:
/* No notification */ /* No notification */
@ -513,11 +495,16 @@ static void lp_comm_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t
/* Apply changes in data lengths/times */ /* Apply changes in data lengths/times */
uint8_t dle_changed = ull_dle_update_eff(conn); uint8_t dle_changed = ull_dle_update_eff(conn);
if (dle_changed) { if (dle_changed && !llcp_ntf_alloc_is_available()) {
lp_comm_ntf(conn, ctx); /* We need to generate NTF but no buffers avail so wait for one */
ctx->state = LP_COMMON_STATE_WAIT_NTF;
} else {
if (dle_changed) {
lp_comm_ntf(conn, ctx);
}
llcp_lr_complete(conn);
ctx->state = LP_COMMON_STATE_IDLE;
} }
llcp_lr_complete(conn);
ctx->state = LP_COMMON_STATE_IDLE;
} else if (ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_UNKNOWN_RSP) { } else if (ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_UNKNOWN_RSP) {
/* Peer does not accept DLU, so disable on current connection */ /* Peer does not accept DLU, so disable on current connection */
feature_unmask_features(conn, LL_FEAT_BIT_DLE); feature_unmask_features(conn, LL_FEAT_BIT_DLE);
@ -563,9 +550,13 @@ static void lp_comm_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t
#endif /* defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) */ #endif /* defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) */
} }
#endif /* CONFIG_BT_PERIPHERAL */ #endif /* CONFIG_BT_PERIPHERAL */
lp_comm_ntf(conn, ctx); if (!llcp_ntf_alloc_is_available()) {
llcp_lr_complete(conn); ctx->state = LP_COMMON_STATE_WAIT_NTF;
ctx->state = LP_COMMON_STATE_IDLE; } else {
lp_comm_ntf(conn, ctx);
llcp_lr_complete(conn);
ctx->state = LP_COMMON_STATE_IDLE;
}
break; break;
default: default:
/* Illegal response opcode */ /* Illegal response opcode */
@ -594,8 +585,7 @@ static bool lp_comm_tx_proxy(struct ll_conn *conn, struct proc_ctx *ctx, const b
lp_comm_tx(conn, ctx); lp_comm_tx(conn, ctx);
/* Select correct state, depending on TX ack handling 'request' */ /* Select correct state, depending on TX ack handling 'request' */
ctx->state = ctx->node_ref.tx_ack ? ctx->state = ctx->tx_ack ? LP_COMMON_STATE_WAIT_TX_ACK : LP_COMMON_STATE_WAIT_RX;
LP_COMMON_STATE_WAIT_TX_ACK : LP_COMMON_STATE_WAIT_RX;
return true; return true;
} }
return false; return false;
@ -627,8 +617,6 @@ static void lp_comm_send_req(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t
} }
} else { } else {
ctx->response_opcode = PDU_DATA_LLCTRL_TYPE_VERSION_IND; ctx->response_opcode = PDU_DATA_LLCTRL_TYPE_VERSION_IND;
/* Clear node_ref to signal no NTF piggy-backing */
ctx->node_ref.rx = NULL;
lp_comm_complete(conn, ctx, evt, param); lp_comm_complete(conn, ctx, evt, param);
} }
break; break;
@ -679,7 +667,7 @@ static void lp_comm_send_req(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t
1) { 1) {
#endif /* CONFIG_BT_CTLR_PHY */ #endif /* CONFIG_BT_CTLR_PHY */
lp_comm_tx_proxy(conn, ctx, lp_comm_tx_proxy(conn, ctx,
llcp_rr_get_paused_cmd(conn) == PROC_CTE_REQ); (llcp_rr_get_paused_cmd(conn) == PROC_CTE_REQ));
} else { } else {
/* The PHY was changed to CODED when the request was waiting in a local /* The PHY was changed to CODED when the request was waiting in a local
* request queue. * request queue.
@ -721,7 +709,11 @@ static void lp_comm_st_idle(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t
ctx->data.cis_term.error_code); ctx->data.cis_term.error_code);
} }
#endif /* CONFIG_BT_CTLR_CENTRAL_ISO || CONFIG_BT_CTLR_PERIPHERAL_ISO */ #endif /* CONFIG_BT_CTLR_CENTRAL_ISO || CONFIG_BT_CTLR_PERIPHERAL_ISO */
lp_comm_send_req(conn, ctx, evt, param); if (llcp_lr_ispaused(conn)) {
ctx->state = LP_COMMON_STATE_WAIT_TX;
} else {
lp_comm_send_req(conn, ctx, evt, param);
}
break; break;
default: default:
/* Ignore other evts */ /* Ignore other evts */
@ -750,14 +742,17 @@ static void lp_comm_st_wait_tx_ack(struct ll_conn *conn, struct proc_ctx *ctx, u
switch (ctx->proc) { switch (ctx->proc) {
#if defined(CONFIG_BT_CTLR_MIN_USED_CHAN) && defined(CONFIG_BT_PERIPHERAL) #if defined(CONFIG_BT_CTLR_MIN_USED_CHAN) && defined(CONFIG_BT_PERIPHERAL)
case PROC_MIN_USED_CHANS: case PROC_MIN_USED_CHANS:
ctx->tx_ack = NULL;
lp_comm_complete(conn, ctx, evt, param); lp_comm_complete(conn, ctx, evt, param);
break; break;
#endif /* CONFIG_BT_CTLR_MIN_USED_CHAN && CONFIG_BT_PERIPHERAL */ #endif /* CONFIG_BT_CTLR_MIN_USED_CHAN && CONFIG_BT_PERIPHERAL */
case PROC_TERMINATE: case PROC_TERMINATE:
ctx->tx_ack = NULL;
lp_comm_complete(conn, ctx, evt, param); lp_comm_complete(conn, ctx, evt, param);
break; break;
#if defined(CONFIG_BT_CTLR_CENTRAL_ISO) || defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) #if defined(CONFIG_BT_CTLR_CENTRAL_ISO) || defined(CONFIG_BT_CTLR_PERIPHERAL_ISO)
case PROC_CIS_TERMINATE: case PROC_CIS_TERMINATE:
ctx->tx_ack = NULL;
lp_comm_complete(conn, ctx, evt, param); lp_comm_complete(conn, ctx, evt, param);
break; break;
#endif /* CONFIG_BT_CTLR_CENTRAL_ISO || CONFIG_BT_CTLR_PERIPHERAL_ISO */ #endif /* CONFIG_BT_CTLR_CENTRAL_ISO || CONFIG_BT_CTLR_PERIPHERAL_ISO */
@ -848,34 +843,36 @@ static void lp_comm_st_wait_rx(struct ll_conn *conn, struct proc_ctx *ctx, uint8
} }
} }
static void lp_comm_st_wait_ntf_avail(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, static void lp_comm_st_wait_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt,
void *param) void *param)
{ {
switch (evt) { switch (evt) {
case LP_COMMON_EVT_RUN: case LP_COMMON_EVT_RUN:
switch (ctx->proc) { switch (ctx->proc) {
case PROC_FEATURE_EXCHANGE:
case PROC_VERSION_EXCHANGE: case PROC_VERSION_EXCHANGE:
/* Note re. procedure timeout handling: #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
* Procedure TO is specifically NOT reset while in wait state, since case PROC_DATA_LENGTH_UPDATE:
* the mechanism is being 'hi-jacked' to implement a TO on the NTF wait #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
* This to catch the very unlikely case: #if defined(CONFIG_BT_CTLR_SCA_UPDATE)
* local VERSION IND started after a VERSION IND had already been TX'ed case PROC_SCA_UPDATE:
* in which case the local procedure should complete with NTF without #endif /* CONFIG_BT_CTLR_SCA_UPDATE) */
* prior TX (ie no procedure TO handling initiated). IF this NTF never
* finds buffer avail it would wait forever, but not with proc TO active
*/
if (llcp_ntf_alloc_is_available()) { if (llcp_ntf_alloc_is_available()) {
lp_comm_ntf(conn, ctx); lp_comm_ntf(conn, ctx);
llcp_lr_complete(conn); llcp_lr_complete(conn);
ctx->state = LP_COMMON_STATE_IDLE; ctx->state = LP_COMMON_STATE_IDLE;
} }
break; break;
#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ)
case PROC_CTE_REQ:
if (llcp_ntf_alloc_is_available()) {
lp_comm_ntf(conn, ctx);
ctx->state = LP_COMMON_STATE_IDLE;
lp_comm_complete_cte_req_finalize(conn);
}
break;
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */
default: default:
/* If we get here it is not good since only VERSION EXCHANGE procedure
* out of the ones handled in ull_llcp_common should end up waiting for
* non-piggy-back'ed NTF
*/
LL_ASSERT(0);
break; break;
} }
break; break;
@ -900,8 +897,8 @@ static void lp_comm_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint
case LP_COMMON_STATE_WAIT_RX: case LP_COMMON_STATE_WAIT_RX:
lp_comm_st_wait_rx(conn, ctx, evt, param); lp_comm_st_wait_rx(conn, ctx, evt, param);
break; break;
case LP_COMMON_STATE_WAIT_NTF_AVAIL: case LP_COMMON_STATE_WAIT_NTF:
lp_comm_st_wait_ntf_avail(conn, ctx, evt, param); lp_comm_st_wait_ntf(conn, ctx, evt, param);
break; break;
default: default:
/* Unknown state */ /* Unknown state */
@ -1008,9 +1005,6 @@ static void rp_comm_rx_decode(struct ll_conn *conn, struct proc_ctx *ctx, struct
*/ */
llcp_tx_pause_data(conn, LLCP_TX_QUEUE_PAUSE_DATA_DATA_LENGTH); llcp_tx_pause_data(conn, LLCP_TX_QUEUE_PAUSE_DATA_DATA_LENGTH);
ctx->data.dle.ntf_dle = ull_dle_update_eff_rx(conn); ctx->data.dle.ntf_dle = ull_dle_update_eff_rx(conn);
/* Mark RX pdu to be removed from RX queue, but NOT be released */
llcp_rx_node_retain(ctx);
break; break;
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */ #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP)
@ -1040,9 +1034,6 @@ static void rp_comm_tx(struct ll_conn *conn, struct proc_ctx *ctx)
pdu = (struct pdu_data *)tx->pdu; pdu = (struct pdu_data *)tx->pdu;
/* Clear tx_ack/rx node reference */
ctx->node_ref.tx_ack = NULL;
/* Encode LL Control PDU */ /* Encode LL Control PDU */
switch (ctx->proc) { switch (ctx->proc) {
#if defined(CONFIG_BT_CTLR_LE_PING) #if defined(CONFIG_BT_CTLR_LE_PING)
@ -1062,7 +1053,7 @@ static void rp_comm_tx(struct ll_conn *conn, struct proc_ctx *ctx)
#if defined(CONFIG_BT_CTLR_DATA_LENGTH) #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
case PROC_DATA_LENGTH_UPDATE: case PROC_DATA_LENGTH_UPDATE:
llcp_pdu_encode_length_rsp(conn, pdu); llcp_pdu_encode_length_rsp(conn, pdu);
ctx->node_ref.tx_ack = tx; ctx->tx_ack = tx;
ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED; ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED;
break; break;
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */ #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
@ -1095,7 +1086,7 @@ static void rp_comm_tx(struct ll_conn *conn, struct proc_ctx *ctx)
ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED; ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED;
} }
ctx->node_ref.tx_ack = tx; ctx->tx_ack = tx;
break; break;
} }
@ -1103,7 +1094,7 @@ static void rp_comm_tx(struct ll_conn *conn, struct proc_ctx *ctx)
#if defined(CONFIG_BT_CTLR_SCA_UPDATE) #if defined(CONFIG_BT_CTLR_SCA_UPDATE)
case PROC_SCA_UPDATE: case PROC_SCA_UPDATE:
llcp_pdu_encode_clock_accuracy_rsp(ctx, pdu); llcp_pdu_encode_clock_accuracy_rsp(ctx, pdu);
ctx->node_ref.tx_ack = tx; ctx->tx_ack = tx;
ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED; ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED;
break; break;
#endif /* CONFIG_BT_CTLR_SCA_UPDATE */ #endif /* CONFIG_BT_CTLR_SCA_UPDATE */
@ -1133,31 +1124,40 @@ static void rp_comm_st_idle(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t
} }
} }
#if defined(CONFIG_BT_CTLR_DATA_LENGTH) #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
static void rp_comm_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t generate_ntf) static void rp_comm_ntf_length_change(struct ll_conn *conn, struct proc_ctx *ctx,
struct pdu_data *pdu)
{
llcp_ntf_encode_length_change(conn, pdu);
}
static void rp_comm_ntf(struct ll_conn *conn, struct proc_ctx *ctx)
{ {
struct node_rx_pdu *ntf; struct node_rx_pdu *ntf;
struct pdu_data *pdu; struct pdu_data *pdu;
ARG_UNUSED(pdu); ARG_UNUSED(pdu);
/* Allocate ntf node */ /* Allocate ntf node */
ntf = ctx->node_ref.rx; ntf = llcp_ntf_alloc();
LL_ASSERT(ntf); LL_ASSERT(ntf);
/* This should be an 'old' RX node, so put/sched when done */ ntf->hdr.type = NODE_RX_TYPE_DC_PDU;
LL_ASSERT(ntf->hdr.type == NODE_RX_TYPE_RETAIN); ntf->hdr.handle = conn->lll.handle;
pdu = (struct pdu_data *)ntf->pdu;
/* And release memory if no NTF to be generated */ switch (ctx->proc) {
ntf->hdr.type = NODE_RX_TYPE_RELEASE; /* Note: the 'double' ifdef in case this switch case expands
* in the future and the function is re-instated
if (generate_ntf) { */
ntf->hdr.type = NODE_RX_TYPE_DC_PDU; #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
ntf->hdr.handle = conn->lll.handle; case PROC_DATA_LENGTH_UPDATE:
pdu = (struct pdu_data *)ntf->pdu; rp_comm_ntf_length_change(conn, ctx, pdu);
LL_ASSERT(ctx->proc == PROC_DATA_LENGTH_UPDATE); break;
llcp_ntf_encode_length_change(conn, pdu); #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
default:
LL_ASSERT(0);
break;
} }
/* Enqueue notification towards LL - releases mem if no ntf */ /* Enqueue notification towards LL */
ll_rx_put_sched(ntf->hdr.link, ntf); ll_rx_put_sched(ntf->hdr.link, ntf);
} }
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */ #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
@ -1266,8 +1266,7 @@ static void rp_comm_send_rsp(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */ #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP)
case PROC_CTE_REQ: case PROC_CTE_REQ:
if (llcp_rr_ispaused(conn) || if (llcp_rr_ispaused(conn) || !llcp_tx_alloc_peek(conn, ctx) ||
!llcp_tx_alloc_peek(conn, ctx) ||
(llcp_rr_get_paused_cmd(conn) == PROC_CTE_REQ)) { (llcp_rr_get_paused_cmd(conn) == PROC_CTE_REQ)) {
ctx->state = RP_COMMON_STATE_WAIT_TX; ctx->state = RP_COMMON_STATE_WAIT_TX;
} else { } else {
@ -1345,20 +1344,25 @@ static void rp_comm_st_wait_tx_ack(struct ll_conn *conn, struct proc_ctx *ctx, u
/* Apply changes in data lengths/times */ /* Apply changes in data lengths/times */
uint8_t dle_changed = ull_dle_update_eff_tx(conn); uint8_t dle_changed = ull_dle_update_eff_tx(conn);
ctx->node_ref.tx_ack = NULL;
dle_changed |= ctx->data.dle.ntf_dle; dle_changed |= ctx->data.dle.ntf_dle;
llcp_tx_resume_data(conn, LLCP_TX_QUEUE_PAUSE_DATA_DATA_LENGTH); llcp_tx_resume_data(conn, LLCP_TX_QUEUE_PAUSE_DATA_DATA_LENGTH);
rp_comm_ntf(conn, ctx, dle_changed); if (dle_changed && !llcp_ntf_alloc_is_available()) {
llcp_rr_complete(conn); ctx->state = RP_COMMON_STATE_WAIT_NTF;
ctx->state = RP_COMMON_STATE_IDLE; } else {
if (dle_changed) {
rp_comm_ntf(conn, ctx);
}
llcp_rr_complete(conn);
ctx->state = RP_COMMON_STATE_IDLE;
}
break; break;
} }
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */ #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP)
case PROC_CTE_REQ: { case PROC_CTE_REQ: {
/* add PHY update pause = false here */ /* add PHY update pause = false here */
ctx->node_ref.tx_ack = NULL; ctx->tx_ack = NULL;
llcp_rr_set_paused_cmd(conn, PROC_NONE); llcp_rr_set_paused_cmd(conn, PROC_NONE);
llcp_rr_complete(conn); llcp_rr_complete(conn);
ctx->state = RP_COMMON_STATE_IDLE; ctx->state = RP_COMMON_STATE_IDLE;
@ -1366,7 +1370,7 @@ static void rp_comm_st_wait_tx_ack(struct ll_conn *conn, struct proc_ctx *ctx, u
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */ #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */
#if defined(CONFIG_BT_CTLR_SCA_UPDATE) #if defined(CONFIG_BT_CTLR_SCA_UPDATE)
case PROC_SCA_UPDATE: { case PROC_SCA_UPDATE: {
ctx->node_ref.tx_ack = NULL; ctx->tx_ack = NULL;
#if defined(CONFIG_BT_PERIPHERAL) #if defined(CONFIG_BT_PERIPHERAL)
if (conn->lll.role == BT_HCI_ROLE_PERIPHERAL) { if (conn->lll.role == BT_HCI_ROLE_PERIPHERAL) {
conn->periph.sca = ctx->data.sca_update.sca; conn->periph.sca = ctx->data.sca_update.sca;
@ -1391,6 +1395,18 @@ static void rp_comm_st_wait_tx_ack(struct ll_conn *conn, struct proc_ctx *ctx, u
} }
} }
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
static void rp_comm_st_wait_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt,
void *param)
{
if (llcp_ntf_alloc_is_available()) {
rp_comm_ntf(conn, ctx);
llcp_rr_complete(conn);
ctx->state = RP_COMMON_STATE_IDLE;
}
}
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
static void rp_comm_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, static void rp_comm_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt,
void *param) void *param)
{ {
@ -1410,6 +1426,11 @@ static void rp_comm_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint
case RP_COMMON_STATE_WAIT_TX_ACK: case RP_COMMON_STATE_WAIT_TX_ACK:
rp_comm_st_wait_tx_ack(conn, ctx, evt, param); rp_comm_st_wait_tx_ack(conn, ctx, evt, param);
break; break;
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
case RP_COMMON_STATE_WAIT_NTF:
rp_comm_st_wait_ntf(conn, ctx, evt, param);
break;
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
default: default:
/* Unknown state */ /* Unknown state */
LL_ASSERT(0); LL_ASSERT(0);

View file

@ -85,7 +85,7 @@ enum {
LP_CU_STATE_WAIT_RX_CONN_UPDATE_IND, LP_CU_STATE_WAIT_RX_CONN_UPDATE_IND,
LP_CU_STATE_WAIT_TX_REJECT_EXT_IND, LP_CU_STATE_WAIT_TX_REJECT_EXT_IND,
LP_CU_STATE_WAIT_INSTANT, LP_CU_STATE_WAIT_INSTANT,
LP_CU_STATE_WAIT_NTF_AVAIL, LP_CU_STATE_WAIT_NTF,
}; };
/* LLCP Local Procedure Connection Update FSM events */ /* LLCP Local Procedure Connection Update FSM events */
@ -120,7 +120,7 @@ enum {
RP_CU_STATE_WAIT_TX_CONN_UPDATE_IND, RP_CU_STATE_WAIT_TX_CONN_UPDATE_IND,
RP_CU_STATE_WAIT_RX_CONN_UPDATE_IND, RP_CU_STATE_WAIT_RX_CONN_UPDATE_IND,
RP_CU_STATE_WAIT_INSTANT, RP_CU_STATE_WAIT_INSTANT,
RP_CU_STATE_WAIT_NTF_AVAIL, RP_CU_STATE_WAIT_NTF,
RP_CU_STATE_WAIT_TX_UNKNOWN_RSP RP_CU_STATE_WAIT_TX_UNKNOWN_RSP
}; };
@ -238,15 +238,11 @@ static void cu_ntf(struct ll_conn *conn, struct proc_ctx *ctx)
{ {
struct node_rx_pdu *ntf; struct node_rx_pdu *ntf;
struct node_rx_cu *pdu; struct node_rx_cu *pdu;
uint8_t piggy_back;
/* Allocate ntf node */ /* Allocate ntf node */
ntf = ctx->node_ref.rx; ntf = llcp_ntf_alloc();
ctx->node_ref.rx = NULL;
LL_ASSERT(ntf); LL_ASSERT(ntf);
piggy_back = (ntf->hdr.type != NODE_RX_TYPE_RETAIN);
ntf->hdr.type = NODE_RX_TYPE_CONN_UPDATE; ntf->hdr.type = NODE_RX_TYPE_CONN_UPDATE;
ntf->hdr.handle = conn->lll.handle; ntf->hdr.handle = conn->lll.handle;
pdu = (struct node_rx_cu *)ntf->pdu; pdu = (struct node_rx_cu *)ntf->pdu;
@ -262,12 +258,8 @@ static void cu_ntf(struct ll_conn *conn, struct proc_ctx *ctx)
pdu->timeout = conn->supervision_timeout; pdu->timeout = conn->supervision_timeout;
} }
if (!piggy_back) { /* Enqueue notification towards LL */
/* Enqueue notification towards LL, unless piggy-backing, ll_rx_put_sched(ntf->hdr.link, ntf);
* in which case this is done on the rx return path
*/
ll_rx_put_sched(ntf->hdr.link, ntf);
}
} }
#if defined(CONFIG_BT_CENTRAL) || defined(CONFIG_BT_CTLR_CONN_PARAM_REQ) #if defined(CONFIG_BT_CENTRAL) || defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
@ -276,16 +268,9 @@ static void lp_cu_tx(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t opcode)
struct node_tx *tx; struct node_tx *tx;
struct pdu_data *pdu; struct pdu_data *pdu;
/* Get pre-allocated tx node */ /* Allocate tx node */
tx = ctx->node_ref.tx_ack; tx = llcp_tx_alloc(conn, ctx);
/* Clear to not trigger tx-ack*/ LL_ASSERT(tx);
ctx->node_ref.tx_ack = NULL;
if (!tx) {
/* Allocate tx node if non pre-alloc'ed */
tx = llcp_tx_alloc(conn, ctx);
LL_ASSERT(tx);
}
pdu = (struct pdu_data *)tx->pdu; pdu = (struct pdu_data *)tx->pdu;
@ -338,11 +323,15 @@ static void lp_cu_complete(struct ll_conn *conn, struct proc_ctx *ctx)
ctx->state = LP_CU_STATE_IDLE; ctx->state = LP_CU_STATE_IDLE;
} }
static void lp_cu_ntf_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, static void lp_cu_wait_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt,
void *param) void *param)
{ {
cu_ntf(conn, ctx); if (!llcp_ntf_alloc_is_available()) {
lp_cu_complete(conn, ctx); ctx->state = LP_CU_STATE_WAIT_NTF;
} else {
cu_ntf(conn, ctx);
lp_cu_complete(conn, ctx);
}
} }
#if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ) #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
@ -400,54 +389,16 @@ static void lp_cu_send_conn_param_req(struct ll_conn *conn, struct proc_ctx *ctx
#endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */ #endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
#if defined(CONFIG_BT_CENTRAL) #if defined(CONFIG_BT_CENTRAL)
static void lp_cu_send_conn_update_ind_finalize(struct ll_conn *conn, struct proc_ctx *ctx,
uint8_t evt, void *param)
{
if (ctx->node_ref.rx == NULL) {
/* If we get here without RX node we know one is avail to be allocated,
* so pre-alloc NTF node
*/
ctx->node_ref.rx = llcp_ntf_alloc();
}
/* Signal put/sched on NTF - ie non-RX node piggy */
ctx->node_ref.rx->hdr.type = NODE_RX_TYPE_RETAIN;
cu_prepare_update_ind(conn, ctx);
lp_cu_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_CONN_UPDATE_IND);
ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED;
ctx->state = LP_CU_STATE_WAIT_INSTANT;
}
static void lp_cu_send_conn_update_ind(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, static void lp_cu_send_conn_update_ind(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt,
void *param) void *param)
{ {
if (llcp_lr_ispaused(conn) || !llcp_tx_alloc_peek(conn, ctx)) { if (llcp_lr_ispaused(conn) || !llcp_tx_alloc_peek(conn, ctx)) {
ctx->state = LP_CU_STATE_WAIT_TX_CONN_UPDATE_IND; ctx->state = LP_CU_STATE_WAIT_TX_CONN_UPDATE_IND;
} else { } else {
/* ensure alloc of TX node, before possibly waiting for NTF node */ cu_prepare_update_ind(conn, ctx);
ctx->node_ref.tx_ack = llcp_tx_alloc(conn, ctx); lp_cu_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_CONN_UPDATE_IND);
if (ctx->node_ref.rx == NULL && !llcp_ntf_alloc_is_available()) { ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED;
/* No RX node piggy, and no NTF avail, so go wait for one, before TX'ing */ ctx->state = LP_CU_STATE_WAIT_INSTANT;
ctx->state = LP_CU_STATE_WAIT_NTF_AVAIL;
} else {
lp_cu_send_conn_update_ind_finalize(conn, ctx, evt, param);
}
}
}
static void lp_cu_st_wait_ntf_avail(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt,
void *param)
{
switch (evt) {
case LP_CU_EVT_RUN:
if (llcp_ntf_alloc_is_available()) {
lp_cu_send_conn_update_ind_finalize(conn, ctx, evt, param);
}
break;
default:
/* Ignore other evts */
break;
} }
} }
#endif /* CONFIG_BT_CENTRAL */ #endif /* CONFIG_BT_CENTRAL */
@ -464,8 +415,6 @@ static void lp_cu_st_idle(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t ev
#endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */ #endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
#if defined(CONFIG_BT_CENTRAL) #if defined(CONFIG_BT_CENTRAL)
case PROC_CONN_UPDATE: case PROC_CONN_UPDATE:
/* Ensure the non-piggy-back'ing is signaled */
ctx->node_ref.rx = NULL;
lp_cu_send_conn_update_ind(conn, ctx, evt, param); lp_cu_send_conn_update_ind(conn, ctx, evt, param);
break; break;
#endif /* CONFIG_BT_CENTRAL */ #endif /* CONFIG_BT_CENTRAL */
@ -528,16 +477,12 @@ static void lp_cu_st_wait_rx_conn_param_rsp(struct ll_conn *conn, struct proc_ct
lp_cu_send_reject_ext_ind(conn, ctx, evt, param); lp_cu_send_reject_ext_ind(conn, ctx, evt, param);
break; break;
} }
/* Keep RX node to use for NTF */
llcp_rx_node_retain(ctx);
lp_cu_send_conn_update_ind(conn, ctx, evt, param); lp_cu_send_conn_update_ind(conn, ctx, evt, param);
break; break;
case LP_CU_EVT_UNKNOWN: case LP_CU_EVT_UNKNOWN:
llcp_rr_set_incompat(conn, INCOMPAT_RESERVED); llcp_rr_set_incompat(conn, INCOMPAT_RESERVED);
/* Unsupported in peer, so disable locally for this connection */ /* Unsupported in peer, so disable locally for this connection */
feature_unmask_features(conn, LL_FEAT_BIT_CONN_PARAM_REQ); feature_unmask_features(conn, LL_FEAT_BIT_CONN_PARAM_REQ);
/* Keep RX node to use for NTF */
llcp_rx_node_retain(ctx);
lp_cu_send_conn_update_ind(conn, ctx, evt, param); lp_cu_send_conn_update_ind(conn, ctx, evt, param);
break; break;
case LP_CU_EVT_REJECT: case LP_CU_EVT_REJECT:
@ -546,13 +491,11 @@ static void lp_cu_st_wait_rx_conn_param_rsp(struct ll_conn *conn, struct proc_ct
llcp_rr_set_incompat(conn, INCOMPAT_RESERVED); llcp_rr_set_incompat(conn, INCOMPAT_RESERVED);
/* Unsupported in peer, so disable locally for this connection */ /* Unsupported in peer, so disable locally for this connection */
feature_unmask_features(conn, LL_FEAT_BIT_CONN_PARAM_REQ); feature_unmask_features(conn, LL_FEAT_BIT_CONN_PARAM_REQ);
/* Keep RX node to use for NTF */
llcp_rx_node_retain(ctx);
lp_cu_send_conn_update_ind(conn, ctx, evt, param); lp_cu_send_conn_update_ind(conn, ctx, evt, param);
} else { } else {
llcp_rr_set_incompat(conn, INCOMPAT_NO_COLLISION); llcp_rr_set_incompat(conn, INCOMPAT_NO_COLLISION);
ctx->data.cu.error = pdu->llctrl.reject_ext_ind.error_code; ctx->data.cu.error = pdu->llctrl.reject_ext_ind.error_code;
lp_cu_ntf_complete(conn, ctx, evt, param); lp_cu_wait_complete(conn, ctx, evt, param);
} }
break; break;
default: default:
@ -585,19 +528,17 @@ static void lp_cu_st_wait_rx_conn_update_ind(struct ll_conn *conn, struct proc_c
switch (evt) { switch (evt) {
case LP_CU_EVT_CONN_UPDATE_IND: case LP_CU_EVT_CONN_UPDATE_IND:
llcp_pdu_decode_conn_update_ind(ctx, param); llcp_pdu_decode_conn_update_ind(ctx, param);
/* Keep RX node to use for NTF */
llcp_rx_node_retain(ctx);
ctx->state = LP_CU_STATE_WAIT_INSTANT; ctx->state = LP_CU_STATE_WAIT_INSTANT;
break; break;
case LP_CU_EVT_UNKNOWN: case LP_CU_EVT_UNKNOWN:
/* Unsupported in peer, so disable locally for this connection */ /* Unsupported in peer, so disable locally for this connection */
feature_unmask_features(conn, LL_FEAT_BIT_CONN_PARAM_REQ); feature_unmask_features(conn, LL_FEAT_BIT_CONN_PARAM_REQ);
ctx->data.cu.error = BT_HCI_ERR_UNSUPP_REMOTE_FEATURE; ctx->data.cu.error = BT_HCI_ERR_UNSUPP_REMOTE_FEATURE;
lp_cu_ntf_complete(conn, ctx, evt, param); lp_cu_wait_complete(conn, ctx, evt, param);
break; break;
case LP_CU_EVT_REJECT: case LP_CU_EVT_REJECT:
ctx->data.cu.error = pdu->llctrl.reject_ext_ind.error_code; ctx->data.cu.error = pdu->llctrl.reject_ext_ind.error_code;
lp_cu_ntf_complete(conn, ctx, evt, param); lp_cu_wait_complete(conn, ctx, evt, param);
break; break;
default: default:
/* Ignore other evts */ /* Ignore other evts */
@ -630,13 +571,8 @@ static void lp_cu_check_instant(struct ll_conn *conn, struct proc_ctx *ctx, uint
notify = cu_should_notify_host(ctx); notify = cu_should_notify_host(ctx);
if (notify) { if (notify) {
ctx->data.cu.error = BT_HCI_ERR_SUCCESS; ctx->data.cu.error = BT_HCI_ERR_SUCCESS;
lp_cu_ntf_complete(conn, ctx, evt, param); lp_cu_wait_complete(conn, ctx, evt, param);
} else { } else {
/* Release RX node kept for NTF */
ctx->node_ref.rx->hdr.type = NODE_RX_TYPE_RELEASE;
ll_rx_put_sched(ctx->node_ref.rx->hdr.link, ctx->node_ref.rx);
ctx->node_ref.rx = NULL;
lp_cu_complete(conn, ctx); lp_cu_complete(conn, ctx);
} }
} }
@ -655,6 +591,18 @@ static void lp_cu_st_wait_instant(struct ll_conn *conn, struct proc_ctx *ctx, ui
} }
} }
static void lp_cu_st_wait_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param)
{
switch (evt) {
case LP_CU_EVT_RUN:
lp_cu_wait_complete(conn, ctx, evt, param);
break;
default:
/* Ignore other evts */
break;
}
}
static void lp_cu_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) static void lp_cu_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param)
{ {
switch (ctx->state) { switch (ctx->state) {
@ -675,9 +623,6 @@ static void lp_cu_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_
case LP_CU_STATE_WAIT_TX_CONN_UPDATE_IND: case LP_CU_STATE_WAIT_TX_CONN_UPDATE_IND:
lp_cu_st_wait_tx_conn_update_ind(conn, ctx, evt, param); lp_cu_st_wait_tx_conn_update_ind(conn, ctx, evt, param);
break; break;
case LP_CU_STATE_WAIT_NTF_AVAIL:
lp_cu_st_wait_ntf_avail(conn, ctx, evt, param);
break;
#endif /* CONFIG_BT_CENTRAL */ #endif /* CONFIG_BT_CENTRAL */
#if defined(CONFIG_BT_PERIPHERAL) #if defined(CONFIG_BT_PERIPHERAL)
case LP_CU_STATE_WAIT_RX_CONN_UPDATE_IND: case LP_CU_STATE_WAIT_RX_CONN_UPDATE_IND:
@ -692,6 +637,9 @@ static void lp_cu_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_
case LP_CU_STATE_WAIT_INSTANT: case LP_CU_STATE_WAIT_INSTANT:
lp_cu_st_wait_instant(conn, ctx, evt, param); lp_cu_st_wait_instant(conn, ctx, evt, param);
break; break;
case LP_CU_STATE_WAIT_NTF:
lp_cu_st_wait_ntf(conn, ctx, evt, param);
break;
default: default:
/* Unknown state */ /* Unknown state */
LL_ASSERT(0); LL_ASSERT(0);
@ -746,15 +694,9 @@ static void rp_cu_tx(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t opcode)
struct node_tx *tx; struct node_tx *tx;
struct pdu_data *pdu; struct pdu_data *pdu;
/* Get pre-allocated tx node */ /* Allocate tx node */
tx = ctx->node_ref.tx_ack; tx = llcp_tx_alloc(conn, ctx);
ctx->node_ref.tx_ack = NULL; LL_ASSERT(tx);
if (!tx) {
/* Allocate tx node if non pre-alloc'ed */
tx = llcp_tx_alloc(conn, ctx);
LL_ASSERT(tx);
}
pdu = (struct pdu_data *)tx->pdu; pdu = (struct pdu_data *)tx->pdu;
@ -801,28 +743,19 @@ static void rp_cu_conn_param_req_ntf(struct ll_conn *conn, struct proc_ctx *ctx)
{ {
struct node_rx_pdu *ntf; struct node_rx_pdu *ntf;
struct pdu_data *pdu; struct pdu_data *pdu;
uint8_t piggy_back;
/* Allocate ntf node */ /* Allocate ntf node */
ntf = ctx->node_ref.rx; ntf = llcp_ntf_alloc();
ctx->node_ref.rx = NULL;
LL_ASSERT(ntf); LL_ASSERT(ntf);
piggy_back = (ntf->hdr.type != NODE_RX_TYPE_RETAIN);
ntf->hdr.type = NODE_RX_TYPE_DC_PDU; ntf->hdr.type = NODE_RX_TYPE_DC_PDU;
ntf->hdr.handle = conn->lll.handle; ntf->hdr.handle = conn->lll.handle;
pdu = (struct pdu_data *)ntf->pdu; pdu = (struct pdu_data *)ntf->pdu;
llcp_pdu_encode_conn_param_req(ctx, pdu); llcp_pdu_encode_conn_param_req(ctx, pdu);
if (!piggy_back) { /* Enqueue notification towards LL */
/* Enqueue notification towards LL, unless piggy-backing, ll_rx_put_sched(ntf->hdr.link, ntf);
* in which case this is done on the rx return path
*/
ll_rx_put_sched(ntf->hdr.link, ntf);
}
} }
#endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */ #endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
@ -837,21 +770,15 @@ static void rp_cu_complete(struct ll_conn *conn, struct proc_ctx *ctx)
ctx->state = RP_CU_STATE_IDLE; ctx->state = RP_CU_STATE_IDLE;
} }
static void rp_cu_send_conn_update_ind_finalize(struct ll_conn *conn, struct proc_ctx *ctx, static void rp_cu_wait_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt,
uint8_t evt, void *param) void *param)
{ {
/* Central role path, should not get here with !=NULL rx-node reference */ if (!llcp_ntf_alloc_is_available()) {
LL_ASSERT(ctx->node_ref.rx == NULL); ctx->state = RP_CU_STATE_WAIT_NTF;
/* We pre-alloc NTF node */ } else {
ctx->node_ref.rx = llcp_ntf_alloc(); cu_ntf(conn, ctx);
rp_cu_complete(conn, ctx);
/* Signal put/sched on NTF - ie non-RX node piggy */ }
ctx->node_ref.rx->hdr.type = NODE_RX_TYPE_RETAIN;
cu_prepare_update_ind(conn, ctx);
rp_cu_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_CONN_UPDATE_IND);
ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED;
ctx->state = RP_CU_STATE_WAIT_INSTANT;
} }
static void rp_cu_send_conn_update_ind(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, static void rp_cu_send_conn_update_ind(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt,
@ -860,30 +787,10 @@ static void rp_cu_send_conn_update_ind(struct ll_conn *conn, struct proc_ctx *ct
if (llcp_rr_ispaused(conn) || !llcp_tx_alloc_peek(conn, ctx)) { if (llcp_rr_ispaused(conn) || !llcp_tx_alloc_peek(conn, ctx)) {
ctx->state = RP_CU_STATE_WAIT_TX_CONN_UPDATE_IND; ctx->state = RP_CU_STATE_WAIT_TX_CONN_UPDATE_IND;
} else { } else {
/* ensure alloc of TX node, before possibly waiting for NTF node */ cu_prepare_update_ind(conn, ctx);
ctx->node_ref.tx_ack = llcp_tx_alloc(conn, ctx); rp_cu_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_CONN_UPDATE_IND);
if (!llcp_ntf_alloc_is_available()) { ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED;
/* No RX node piggy, and no NTF avail, so go wait for one, before TX'ing */ ctx->state = RP_CU_STATE_WAIT_INSTANT;
ctx->state = RP_CU_STATE_WAIT_NTF_AVAIL;
} else {
rp_cu_send_conn_update_ind_finalize(conn, ctx, evt, param);
}
}
}
static void rp_cu_st_wait_ntf_avail(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt,
void *param)
{
switch (evt) {
case RP_CU_EVT_RUN:
if (llcp_ntf_alloc_is_available()) {
/* If NTF node is now avail, so pick it up and continue */
rp_cu_send_conn_update_ind_finalize(conn, ctx, evt, param);
}
break;
default:
/* Ignore other evts */
break;
} }
} }
@ -979,8 +886,6 @@ static void rp_cu_st_wait_conn_param_req_available(struct ll_conn *conn, struct
ctx->data.cu.error = BT_HCI_ERR_UNSUPP_LL_PARAM_VAL; ctx->data.cu.error = BT_HCI_ERR_UNSUPP_LL_PARAM_VAL;
rp_cu_send_reject_ext_ind(conn, ctx, evt, param); rp_cu_send_reject_ext_ind(conn, ctx, evt, param);
} }
/* In case we have to defer NTF */
llcp_rx_node_retain(ctx);
} else { } else {
cpr_active_set(conn); cpr_active_set(conn);
const bool params_changed = const bool params_changed =
@ -989,8 +894,7 @@ static void rp_cu_st_wait_conn_param_req_available(struct ll_conn *conn, struct
/* notify Host if conn parameters changed, else respond */ /* notify Host if conn parameters changed, else respond */
if (params_changed) { if (params_changed) {
rp_cu_conn_param_req_ntf(conn, ctx); rp_cu_send_conn_param_req_ntf(conn, ctx, evt, param);
ctx->state = RP_CU_STATE_WAIT_CONN_PARAM_REQ_REPLY;
} else { } else {
#if defined(CONFIG_BT_CTLR_USER_CPR_ANCHOR_POINT_MOVE) #if defined(CONFIG_BT_CTLR_USER_CPR_ANCHOR_POINT_MOVE)
/* Handle APM as a vendor specific user extension */ /* Handle APM as a vendor specific user extension */
@ -1073,8 +977,6 @@ static void rp_cu_state_wait_conn_param_req_reply_continue(struct ll_conn *conn,
switch (evt) { switch (evt) {
case RP_CU_EVT_RUN: case RP_CU_EVT_RUN:
if (conn->lll.role == BT_HCI_ROLE_CENTRAL) { if (conn->lll.role == BT_HCI_ROLE_CENTRAL) {
/* Ensure that node_ref does not indicate RX node for piggyback */
ctx->node_ref.rx = NULL;
rp_cu_send_conn_update_ind(conn, ctx, evt, param); rp_cu_send_conn_update_ind(conn, ctx, evt, param);
} else if (conn->lll.role == BT_HCI_ROLE_PERIPHERAL) { } else if (conn->lll.role == BT_HCI_ROLE_PERIPHERAL) {
if (!ctx->data.cu.error) { if (!ctx->data.cu.error) {
@ -1174,14 +1076,10 @@ static void rp_cu_check_instant(struct ll_conn *conn, struct proc_ctx *ctx, uint
notify = cu_should_notify_host(ctx); notify = cu_should_notify_host(ctx);
if (notify) { if (notify) {
ctx->data.cu.error = BT_HCI_ERR_SUCCESS; ctx->data.cu.error = BT_HCI_ERR_SUCCESS;
cu_ntf(conn, ctx); rp_cu_wait_complete(conn, ctx, evt, param);
} else { } else {
/* Release RX node kept for NTF */ rp_cu_complete(conn, ctx);
ctx->node_ref.rx->hdr.type = NODE_RX_TYPE_RELEASE;
ll_rx_put_sched(ctx->node_ref.rx->hdr.link, ctx->node_ref.rx);
ctx->node_ref.rx = NULL;
} }
rp_cu_complete(conn, ctx);
} }
} }
@ -1201,8 +1099,6 @@ static void rp_cu_st_wait_rx_conn_update_ind(struct ll_conn *conn, struct proc_c
if (is_instant_not_passed(ctx->data.cu.instant, if (is_instant_not_passed(ctx->data.cu.instant,
ull_conn_event_counter(conn))) { ull_conn_event_counter(conn))) {
llcp_rx_node_retain(ctx);
ctx->state = RP_CU_STATE_WAIT_INSTANT; ctx->state = RP_CU_STATE_WAIT_INSTANT;
/* In case we only just received it in time */ /* In case we only just received it in time */
rp_cu_check_instant(conn, ctx, evt, param); rp_cu_check_instant(conn, ctx, evt, param);
@ -1235,6 +1131,18 @@ static void rp_cu_st_wait_instant(struct ll_conn *conn, struct proc_ctx *ctx, ui
} }
} }
static void rp_cu_st_wait_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param)
{
switch (evt) {
case RP_CU_EVT_RUN:
rp_cu_wait_complete(conn, ctx, evt, param);
break;
default:
/* Ignore other evts */
break;
}
}
static void rp_cu_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) static void rp_cu_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param)
{ {
switch (ctx->state) { switch (ctx->state) {
@ -1278,8 +1186,8 @@ static void rp_cu_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_
case RP_CU_STATE_WAIT_INSTANT: case RP_CU_STATE_WAIT_INSTANT:
rp_cu_st_wait_instant(conn, ctx, evt, param); rp_cu_st_wait_instant(conn, ctx, evt, param);
break; break;
case RP_CU_STATE_WAIT_NTF_AVAIL: case RP_CU_STATE_WAIT_NTF:
rp_cu_st_wait_ntf_avail(conn, ctx, evt, param); rp_cu_st_wait_ntf(conn, ctx, evt, param);
break; break;
default: default:
/* Unknown state */ /* Unknown state */

View file

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

View file

@ -156,14 +156,9 @@ struct proc_ctx {
enum llcp_wait_reason wait_reason; enum llcp_wait_reason wait_reason;
#endif /* LLCP_TX_CTRL_BUF_QUEUE_ENABLE */ #endif /* LLCP_TX_CTRL_BUF_QUEUE_ENABLE */
struct { /* TX node awaiting ack */
/* Rx node link element */ struct node_tx *tx_ack;
memq_link_t *link;
/* TX node awaiting ack */
struct node_tx *tx_ack;
/* most recent RX node */
struct node_rx_pdu *rx;
} node_ref;
/* /*
* This flag is set to 1 when we are finished with the control * This flag is set to 1 when we are finished with the control
* procedure and it is safe to release the context ctx * procedure and it is safe to release the context ctx
@ -195,7 +190,6 @@ struct proc_ctx {
uint8_t ntf_pu:1; uint8_t ntf_pu:1;
#if defined(CONFIG_BT_CTLR_DATA_LENGTH) #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
uint8_t ntf_dle:1; uint8_t ntf_dle:1;
struct node_rx_pdu *ntf_dle_node;
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */ #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
uint8_t error; uint8_t error;
uint16_t instant; uint16_t instant;
@ -402,10 +396,6 @@ bool llcp_tx_alloc_peek(struct ll_conn *conn, struct proc_ctx *ctx);
void llcp_tx_alloc_unpeek(struct proc_ctx *ctx); void llcp_tx_alloc_unpeek(struct proc_ctx *ctx);
struct node_tx *llcp_tx_alloc(struct ll_conn *conn, struct proc_ctx *ctx); struct node_tx *llcp_tx_alloc(struct ll_conn *conn, struct proc_ctx *ctx);
void llcp_proc_ctx_release(struct proc_ctx *ctx); void llcp_proc_ctx_release(struct proc_ctx *ctx);
void llcp_ntf_set_pending(struct ll_conn *conn);
void llcp_ntf_clear_pending(struct ll_conn *conn);
bool llcp_ntf_pending(struct ll_conn *conn);
void llcp_rx_node_retain(struct proc_ctx *ctx);
/* /*
* ULL -> LLL Interface * ULL -> LLL Interface
@ -526,8 +516,7 @@ void llcp_lr_pause(struct ll_conn *conn);
void llcp_lr_resume(struct ll_conn *conn); void llcp_lr_resume(struct ll_conn *conn);
void llcp_lr_tx_ack(struct ll_conn *conn, struct proc_ctx *ctx, struct node_tx *tx); void llcp_lr_tx_ack(struct ll_conn *conn, struct proc_ctx *ctx, struct node_tx *tx);
void llcp_lr_tx_ntf(struct ll_conn *conn, struct proc_ctx *ctx); void llcp_lr_tx_ntf(struct ll_conn *conn, struct proc_ctx *ctx);
void llcp_lr_rx(struct ll_conn *conn, struct proc_ctx *ctx, memq_link_t *link, void llcp_lr_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pdu *rx);
struct node_rx_pdu *rx);
void llcp_lr_enqueue(struct ll_conn *conn, struct proc_ctx *ctx); void llcp_lr_enqueue(struct ll_conn *conn, struct proc_ctx *ctx);
void llcp_lr_init(struct ll_conn *conn); void llcp_lr_init(struct ll_conn *conn);
void llcp_lr_run(struct ll_conn *conn); void llcp_lr_run(struct ll_conn *conn);
@ -550,16 +539,14 @@ void llcp_rr_pause(struct ll_conn *conn);
void llcp_rr_resume(struct ll_conn *conn); void llcp_rr_resume(struct ll_conn *conn);
void llcp_rr_tx_ack(struct ll_conn *conn, struct proc_ctx *ctx, struct node_tx *tx); void llcp_rr_tx_ack(struct ll_conn *conn, struct proc_ctx *ctx, struct node_tx *tx);
void llcp_rr_tx_ntf(struct ll_conn *conn, struct proc_ctx *ctx); void llcp_rr_tx_ntf(struct ll_conn *conn, struct proc_ctx *ctx);
void llcp_rr_rx(struct ll_conn *conn, struct proc_ctx *ctx, memq_link_t *link, void llcp_rr_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pdu *rx);
struct node_rx_pdu *rx);
void llcp_rr_init(struct ll_conn *conn); void llcp_rr_init(struct ll_conn *conn);
void llcp_rr_prepare(struct ll_conn *conn, struct node_rx_pdu *rx); void llcp_rr_prepare(struct ll_conn *conn, struct node_rx_pdu *rx);
void llcp_rr_run(struct ll_conn *conn); void llcp_rr_run(struct ll_conn *conn);
void llcp_rr_complete(struct ll_conn *conn); void llcp_rr_complete(struct ll_conn *conn);
void llcp_rr_connect(struct ll_conn *conn); void llcp_rr_connect(struct ll_conn *conn);
void llcp_rr_disconnect(struct ll_conn *conn); void llcp_rr_disconnect(struct ll_conn *conn);
void llcp_rr_new(struct ll_conn *conn, memq_link_t *link, struct node_rx_pdu *rx, void llcp_rr_new(struct ll_conn *conn, struct node_rx_pdu *rx, bool valid_pdu);
bool valid_pdu);
void llcp_rr_check_done(struct ll_conn *conn, struct proc_ctx *ctx); void llcp_rr_check_done(struct ll_conn *conn, struct proc_ctx *ctx);
#if defined(CONFIG_BT_CTLR_LE_PING) #if defined(CONFIG_BT_CTLR_LE_PING)

View file

@ -171,7 +171,7 @@ struct proc_ctx *llcp_lr_peek(struct ll_conn *conn)
bool llcp_lr_ispaused(struct ll_conn *conn) bool llcp_lr_ispaused(struct ll_conn *conn)
{ {
return (conn->llcp.local.pause == 1U); return conn->llcp.local.pause == 1U;
} }
void llcp_lr_pause(struct ll_conn *conn) void llcp_lr_pause(struct ll_conn *conn)
@ -199,13 +199,8 @@ void llcp_lr_prt_stop(struct ll_conn *conn)
conn->llcp.local.prt_expire = 0U; conn->llcp.local.prt_expire = 0U;
} }
void llcp_lr_rx(struct ll_conn *conn, struct proc_ctx *ctx, memq_link_t *link, void llcp_lr_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pdu *rx)
struct node_rx_pdu *rx)
{ {
/* Store RX node and link */
ctx->node_ref.rx = rx;
ctx->node_ref.link = link;
switch (ctx->proc) { switch (ctx->proc) {
#if defined(CONFIG_BT_CTLR_LE_PING) #if defined(CONFIG_BT_CTLR_LE_PING)
case PROC_LE_PING: case PROC_LE_PING:
@ -310,10 +305,6 @@ void llcp_lr_tx_ack(struct ll_conn *conn, struct proc_ctx *ctx, struct node_tx *
break; break;
/* Ignore tx_ack */ /* Ignore tx_ack */
} }
/* Clear TX node reference */
ctx->node_ref.tx_ack = NULL;
llcp_lr_check_done(conn, ctx); llcp_lr_check_done(conn, ctx);
} }

View file

@ -57,9 +57,9 @@ enum {
LP_PU_STATE_WAIT_TX_PHY_UPDATE_IND, LP_PU_STATE_WAIT_TX_PHY_UPDATE_IND,
LP_PU_STATE_WAIT_TX_ACK_PHY_UPDATE_IND, LP_PU_STATE_WAIT_TX_ACK_PHY_UPDATE_IND,
LP_PU_STATE_WAIT_RX_PHY_UPDATE_IND, LP_PU_STATE_WAIT_RX_PHY_UPDATE_IND,
LP_PU_STATE_WAIT_NTF_AVAIL,
LP_PU_STATE_WAIT_INSTANT, LP_PU_STATE_WAIT_INSTANT,
LP_PU_STATE_WAIT_INSTANT_ON_AIR, LP_PU_STATE_WAIT_INSTANT_ON_AIR,
LP_PU_STATE_WAIT_NTF,
}; };
/* LLCP Local Procedure PHY Update FSM events */ /* LLCP Local Procedure PHY Update FSM events */
@ -95,9 +95,9 @@ enum {
RP_PU_STATE_WAIT_TX_PHY_UPDATE_IND, RP_PU_STATE_WAIT_TX_PHY_UPDATE_IND,
RP_PU_STATE_WAIT_TX_ACK_PHY_UPDATE_IND, RP_PU_STATE_WAIT_TX_ACK_PHY_UPDATE_IND,
RP_PU_STATE_WAIT_RX_PHY_UPDATE_IND, RP_PU_STATE_WAIT_RX_PHY_UPDATE_IND,
RP_PU_STATE_WAIT_NTF_AVAIL,
RP_PU_STATE_WAIT_INSTANT, RP_PU_STATE_WAIT_INSTANT,
RP_PU_STATE_WAIT_INSTANT_ON_AIR, RP_PU_STATE_WAIT_INSTANT_ON_AIR,
RP_PU_STATE_WAIT_NTF,
}; };
/* LLCP Remote Procedure PHY Update FSM events */ /* LLCP Remote Procedure PHY Update FSM events */
@ -372,56 +372,38 @@ static void pu_prepare_instant(struct ll_conn *conn, struct proc_ctx *ctx)
* LLCP Local Procedure PHY Update FSM * LLCP Local Procedure PHY Update FSM
*/ */
static void lp_pu_tx(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) static void lp_pu_tx(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t opcode)
{ {
struct node_tx *tx; struct node_tx *tx;
struct pdu_data *pdu; struct pdu_data *pdu;
/* Allocate tx node, but only do it if not already done */ /* Allocate tx node */
if (ctx->node_ref.tx_ack == NULL) { tx = llcp_tx_alloc(conn, ctx);
ctx->node_ref.tx_ack = llcp_tx_alloc(conn, ctx); LL_ASSERT(tx);
LL_ASSERT(ctx->node_ref.tx_ack);
}
#if defined(CONFIG_BT_CENTRAL)
if (!((ctx->tx_opcode == PDU_DATA_LLCTRL_TYPE_PHY_REQ) &&
(conn->lll.role == BT_HCI_ROLE_CENTRAL))) {
if (!llcp_ntf_alloc_is_available()) {
/* No NTF nodes avail, so we need to hold off TX */
ctx->state = LP_PU_STATE_WAIT_NTF_AVAIL;
return;
}
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
ctx->data.pu.ntf_dle_node = llcp_ntf_alloc();
LL_ASSERT(ctx->data.pu.ntf_dle_node);
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
}
#endif
tx = ctx->node_ref.tx_ack;
pdu = (struct pdu_data *)tx->pdu; pdu = (struct pdu_data *)tx->pdu;
/* Encode LL Control PDU */ /* Encode LL Control PDU */
switch (ctx->tx_opcode) { switch (opcode) {
case PDU_DATA_LLCTRL_TYPE_PHY_REQ: case PDU_DATA_LLCTRL_TYPE_PHY_REQ:
pu_set_preferred_phys(conn, ctx); pu_set_preferred_phys(conn, ctx);
llcp_pdu_encode_phy_req(ctx, pdu); llcp_pdu_encode_phy_req(ctx, pdu);
llcp_tx_pause_data(conn, LLCP_TX_QUEUE_PAUSE_DATA_PHY_UPDATE);
ctx->state = LP_PU_STATE_WAIT_TX_ACK_PHY_REQ;
break; break;
#if defined(CONFIG_BT_CENTRAL) #if defined(CONFIG_BT_CENTRAL)
case PDU_DATA_LLCTRL_TYPE_PHY_UPD_IND: case PDU_DATA_LLCTRL_TYPE_PHY_UPD_IND:
pu_prep_update_ind(conn, ctx); pu_prep_update_ind(conn, ctx);
pu_prepare_instant(conn, ctx); pu_prepare_instant(conn, ctx);
llcp_pdu_encode_phy_update_ind(ctx, pdu); llcp_pdu_encode_phy_update_ind(ctx, pdu);
ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED;
ctx->state = LP_PU_STATE_WAIT_TX_ACK_PHY_UPDATE_IND;
break; break;
#endif /* CONFIG_BT_CENTRAL */ #endif /* CONFIG_BT_CENTRAL */
default: default:
LL_ASSERT(0); LL_ASSERT(0);
} }
/* Always 'request' the ACK signal */
ctx->tx_ack = tx;
ctx->tx_opcode = pdu->llctrl.opcode;
/* Enqueue LL Control PDU towards LLL */ /* Enqueue LL Control PDU towards LLL */
llcp_tx_enqueue(conn, tx); llcp_tx_enqueue(conn, tx);
@ -434,33 +416,21 @@ static void pu_ntf(struct ll_conn *conn, struct proc_ctx *ctx)
struct node_rx_pdu *ntf; struct node_rx_pdu *ntf;
struct node_rx_pu *pdu; struct node_rx_pu *pdu;
/* Piggy-back on stored RX node */ /* Allocate ntf node */
ntf = ctx->node_ref.rx; ntf = llcp_ntf_alloc();
LL_ASSERT(ntf); LL_ASSERT(ntf);
if (ctx->data.pu.ntf_pu) { ntf->hdr.type = NODE_RX_TYPE_PHY_UPDATE;
LL_ASSERT(ntf->hdr.type == NODE_RX_TYPE_RETAIN); ntf->hdr.handle = conn->lll.handle;
ntf->hdr.type = NODE_RX_TYPE_PHY_UPDATE; pdu = (struct node_rx_pu *)ntf->pdu;
ntf->hdr.handle = conn->lll.handle;
pdu = (struct node_rx_pu *)ntf->pdu;
pdu->status = ctx->data.pu.error; pdu->status = ctx->data.pu.error;
pdu->rx = conn->lll.phy_rx; pdu->rx = conn->lll.phy_rx;
pdu->tx = conn->lll.phy_tx; pdu->tx = conn->lll.phy_tx;
} else {
ntf->hdr.type = NODE_RX_TYPE_RELEASE;
}
/* Enqueue notification towards LL */ /* Enqueue notification towards LL */
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
/* only 'put' as the 'sched' is handled when handling DLE ntf */
ll_rx_put(ntf->hdr.link, ntf);
#else
ll_rx_put_sched(ntf->hdr.link, ntf); ll_rx_put_sched(ntf->hdr.link, ntf);
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
ctx->data.pu.ntf_pu = 0; ctx->data.pu.ntf_pu = 0;
ctx->node_ref.rx = NULL;
} }
#if defined(CONFIG_BT_CTLR_DATA_LENGTH) #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
@ -469,69 +439,82 @@ static void pu_dle_ntf(struct ll_conn *conn, struct proc_ctx *ctx)
struct node_rx_pdu *ntf; struct node_rx_pdu *ntf;
struct pdu_data *pdu; struct pdu_data *pdu;
/* Retrieve DLE ntf node */ /* Allocate ntf node */
ntf = ctx->data.pu.ntf_dle_node; ntf = llcp_ntf_alloc();
LL_ASSERT(ntf);
if (!ctx->data.pu.ntf_dle) { ntf->hdr.type = NODE_RX_TYPE_DC_PDU;
if (!ntf) { ntf->hdr.handle = conn->lll.handle;
/* If no DLE ntf was pre-allocated there is nothing more to do */ pdu = (struct pdu_data *)ntf->pdu;
/* This will happen in case of a completion on UNKNOWN_RSP to PHY_REQ
* in Central case.
*/
return;
}
/* Signal to release pre-allocated node in case there is no DLE ntf */
ntf->hdr.type = NODE_RX_TYPE_RELEASE;
} else {
LL_ASSERT(ntf);
ntf->hdr.type = NODE_RX_TYPE_DC_PDU; llcp_ntf_encode_length_change(conn, pdu);
ntf->hdr.handle = conn->lll.handle;
pdu = (struct pdu_data *)ntf->pdu;
llcp_ntf_encode_length_change(conn, pdu);
}
/* Enqueue notification towards LL */ /* Enqueue notification towards LL */
ll_rx_put_sched(ntf->hdr.link, ntf); ll_rx_put_sched(ntf->hdr.link, ntf);
ctx->data.pu.ntf_dle = 0;
ctx->data.pu.ntf_dle_node = NULL;
} }
#endif #endif
static void lp_pu_complete_finalize(struct ll_conn *conn, struct proc_ctx *ctx) static void lp_pu_tx_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt)
{ {
llcp_lr_complete(conn);
llcp_rr_set_paused_cmd(conn, PROC_NONE);
ctx->state = LP_PU_STATE_IDLE;
}
static void lp_pu_tx_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param)
{
pu_ntf(conn, ctx);
#if defined(CONFIG_BT_CTLR_DATA_LENGTH) #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
pu_dle_ntf(conn, ctx); #define NTF_DLE (ctx->data.pu.ntf_dle)
#else
#define NTF_DLE 0
#endif #endif
lp_pu_complete_finalize(conn, ctx); uint8_t ntf_count = ctx->data.pu.ntf_pu + NTF_DLE;
/* if we need to send both PHY and DLE notification, but we
* do not have 2 buffers available we serialize the sending
* of notifications
*/
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
if ((ntf_count > 1) && !llcp_ntf_alloc_num_available(ntf_count)) {
ntf_count = 1;
}
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
if (ntf_count && !llcp_ntf_alloc_num_available(ntf_count)) {
ctx->state = LP_PU_STATE_WAIT_NTF;
} else {
if (ctx->data.pu.ntf_pu) {
pu_ntf(conn, ctx);
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
if (ntf_count == 1 && NTF_DLE == 1) {
ctx->state = LP_PU_STATE_WAIT_NTF;
return;
}
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
}
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
if (ctx->data.pu.ntf_dle) {
pu_dle_ntf(conn, ctx);
}
#endif
llcp_lr_complete(conn);
ctx->state = LP_PU_STATE_IDLE;
llcp_rr_set_paused_cmd(conn, PROC_NONE);
}
}
static void lp_pu_complete_after_inst_on_air(struct ll_conn *conn, struct proc_ctx *ctx,
uint8_t evt, void *param)
{
/* When complete reset timing restrictions - idempotent
* (so no problem if we need to wait for NTF buffer)
*/
pu_reset_timing_restrict(conn);
/* Wait for instant on air to send notification */
ctx->state = LP_PU_STATE_WAIT_INSTANT_ON_AIR;
} }
static void lp_pu_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) static void lp_pu_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param)
{ {
/* when complete reset timing restrictions - idempotent
* (so no problem if we need to wait for NTF buffer)
*/
pu_reset_timing_restrict(conn); pu_reset_timing_restrict(conn);
/* Postpone procedure completion (and possible NTF generation) to actual 'air instant' lp_pu_tx_ntf(conn, ctx, evt);
* Since LLCP STM is driven from LLL prepare this actually happens BEFORE instant
* and thus NTFs are generated and propagated up prior to actual instant on air.
* Instead postpone completion/NTF to the beginning of RX handling
*/
ctx->state = LP_PU_STATE_WAIT_INSTANT_ON_AIR;
if (ctx->node_ref.rx) {
/* Mark RX node to NOT release */
llcp_rx_node_retain(ctx);
}
} }
static void lp_pu_send_phy_req(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) static void lp_pu_send_phy_req(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param)
@ -543,8 +526,9 @@ static void lp_pu_send_phy_req(struct ll_conn *conn, struct proc_ctx *ctx, uint8
} else { } else {
llcp_rr_set_incompat(conn, INCOMPAT_RESOLVABLE); llcp_rr_set_incompat(conn, INCOMPAT_RESOLVABLE);
llcp_rr_set_paused_cmd(conn, PROC_CTE_REQ); llcp_rr_set_paused_cmd(conn, PROC_CTE_REQ);
ctx->tx_opcode = PDU_DATA_LLCTRL_TYPE_PHY_REQ; lp_pu_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_PHY_REQ);
lp_pu_tx(conn, ctx, evt, param); llcp_tx_pause_data(conn, LLCP_TX_QUEUE_PAUSE_DATA_PHY_UPDATE);
ctx->state = LP_PU_STATE_WAIT_TX_ACK_PHY_REQ;
} }
} }
@ -555,8 +539,9 @@ static void lp_pu_send_phy_update_ind(struct ll_conn *conn, struct proc_ctx *ctx
if (llcp_lr_ispaused(conn) || !llcp_tx_alloc_peek(conn, ctx)) { if (llcp_lr_ispaused(conn) || !llcp_tx_alloc_peek(conn, ctx)) {
ctx->state = LP_PU_STATE_WAIT_TX_PHY_UPDATE_IND; ctx->state = LP_PU_STATE_WAIT_TX_PHY_UPDATE_IND;
} else { } else {
ctx->tx_opcode = PDU_DATA_LLCTRL_TYPE_PHY_UPD_IND; lp_pu_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_PHY_UPD_IND);
lp_pu_tx(conn, ctx, evt, param); ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED;
ctx->state = LP_PU_STATE_WAIT_TX_ACK_PHY_UPDATE_IND;
} }
} }
#endif /* CONFIG_BT_CENTRAL */ #endif /* CONFIG_BT_CENTRAL */
@ -602,10 +587,6 @@ static void lp_pu_st_wait_rx_phy_rsp(struct ll_conn *conn, struct proc_ctx *ctx,
llcp_tx_pause_data(conn, LLCP_TX_QUEUE_PAUSE_DATA_PHY_UPDATE); llcp_tx_pause_data(conn, LLCP_TX_QUEUE_PAUSE_DATA_PHY_UPDATE);
/* Combine with the 'Preferred' phys */ /* Combine with the 'Preferred' phys */
pu_combine_phys(conn, ctx, tx_pref, rx_pref); pu_combine_phys(conn, ctx, tx_pref, rx_pref);
/* Mark RX node to NOT release */
llcp_rx_node_retain(ctx);
lp_pu_send_phy_update_ind(conn, ctx, evt, param); lp_pu_send_phy_update_ind(conn, ctx, evt, param);
break; break;
case LP_PU_EVT_UNKNOWN: case LP_PU_EVT_UNKNOWN:
@ -614,10 +595,6 @@ static void lp_pu_st_wait_rx_phy_rsp(struct ll_conn *conn, struct proc_ctx *ctx,
* Peer does not accept PHY UPDATE, so disable non 1M phys on current connection * Peer does not accept PHY UPDATE, so disable non 1M phys on current connection
*/ */
feature_unmask_features(conn, LL_FEAT_BIT_PHY_2M | LL_FEAT_BIT_PHY_CODED); feature_unmask_features(conn, LL_FEAT_BIT_PHY_2M | LL_FEAT_BIT_PHY_CODED);
/* Mark RX node to NOT release */
llcp_rx_node_retain(ctx);
ctx->data.pu.error = BT_HCI_ERR_UNSUPP_REMOTE_FEATURE; ctx->data.pu.error = BT_HCI_ERR_UNSUPP_REMOTE_FEATURE;
ctx->data.pu.ntf_pu = 1; ctx->data.pu.ntf_pu = 1;
lp_pu_complete(conn, ctx, evt, param); lp_pu_complete(conn, ctx, evt, param);
@ -722,9 +699,6 @@ static void lp_pu_st_wait_rx_phy_update_ind(struct ll_conn *conn, struct proc_ct
llcp_pdu_decode_phy_update_ind(ctx, (struct pdu_data *)param); llcp_pdu_decode_phy_update_ind(ctx, (struct pdu_data *)param);
const uint8_t end_procedure = pu_check_update_ind(conn, ctx); const uint8_t end_procedure = pu_check_update_ind(conn, ctx);
/* Mark RX node to NOT release */
llcp_rx_node_retain(ctx);
if (!end_procedure) { if (!end_procedure) {
if (ctx->data.pu.p_to_c_phy) { if (ctx->data.pu.p_to_c_phy) {
/* If periph to central phy changes apply tx timing restriction */ /* If periph to central phy changes apply tx timing restriction */
@ -751,10 +725,6 @@ static void lp_pu_st_wait_rx_phy_update_ind(struct ll_conn *conn, struct proc_ct
case LP_PU_EVT_REJECT: case LP_PU_EVT_REJECT:
llcp_rr_set_incompat(conn, INCOMPAT_NO_COLLISION); llcp_rr_set_incompat(conn, INCOMPAT_NO_COLLISION);
llcp_pdu_decode_reject_ext_ind(ctx, (struct pdu_data *) param); llcp_pdu_decode_reject_ext_ind(ctx, (struct pdu_data *) param);
/* Mark RX node to NOT release */
llcp_rx_node_retain(ctx);
ctx->data.pu.error = ctx->reject_ext_ind.error_code; ctx->data.pu.error = ctx->reject_ext_ind.error_code;
ctx->data.pu.ntf_pu = 1; ctx->data.pu.ntf_pu = 1;
lp_pu_complete(conn, ctx, evt, param); lp_pu_complete(conn, ctx, evt, param);
@ -766,10 +736,6 @@ static void lp_pu_st_wait_rx_phy_update_ind(struct ll_conn *conn, struct proc_ct
* Peer does not accept PHY UPDATE, so disable non 1M phys on current connection * Peer does not accept PHY UPDATE, so disable non 1M phys on current connection
*/ */
feature_unmask_features(conn, LL_FEAT_BIT_PHY_2M | LL_FEAT_BIT_PHY_CODED); feature_unmask_features(conn, LL_FEAT_BIT_PHY_2M | LL_FEAT_BIT_PHY_CODED);
/* Mark RX node to NOT release */
llcp_rx_node_retain(ctx);
ctx->data.pu.error = BT_HCI_ERR_UNSUPP_REMOTE_FEATURE; ctx->data.pu.error = BT_HCI_ERR_UNSUPP_REMOTE_FEATURE;
ctx->data.pu.ntf_pu = 1; ctx->data.pu.ntf_pu = 1;
lp_pu_complete(conn, ctx, evt, param); lp_pu_complete(conn, ctx, evt, param);
@ -795,7 +761,7 @@ static void lp_pu_check_instant(struct ll_conn *conn, struct proc_ctx *ctx, uint
llcp_rr_set_incompat(conn, INCOMPAT_NO_COLLISION); llcp_rr_set_incompat(conn, INCOMPAT_NO_COLLISION);
ctx->data.pu.error = BT_HCI_ERR_SUCCESS; ctx->data.pu.error = BT_HCI_ERR_SUCCESS;
ctx->data.pu.ntf_pu = (phy_changed || ctx->data.pu.host_initiated); ctx->data.pu.ntf_pu = (phy_changed || ctx->data.pu.host_initiated);
lp_pu_complete(conn, ctx, evt, param); lp_pu_complete_after_inst_on_air(conn, ctx, evt, param);
} }
} }
@ -812,12 +778,11 @@ static void lp_pu_st_wait_instant(struct ll_conn *conn, struct proc_ctx *ctx, ui
} }
} }
static void lp_pu_st_wait_instant_on_air(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, static void lp_pu_st_wait_instant_on_air(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt)
void *param)
{ {
switch (evt) { switch (evt) {
case LP_PU_EVT_NTF: case LP_PU_EVT_NTF:
lp_pu_tx_ntf(conn, ctx, evt, param); lp_pu_tx_ntf(conn, ctx, evt);
break; break;
default: default:
/* Ignore other evts */ /* Ignore other evts */
@ -825,12 +790,11 @@ static void lp_pu_st_wait_instant_on_air(struct ll_conn *conn, struct proc_ctx *
} }
} }
static void lp_pu_st_wait_ntf_avail(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, static void lp_pu_st_wait_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param)
void *param)
{ {
switch (evt) { switch (evt) {
case LP_PU_EVT_RUN: case LP_PU_EVT_RUN:
lp_pu_tx(conn, ctx, evt, param); lp_pu_tx_ntf(conn, ctx, evt);
break; break;
default: default:
/* Ignore other evts */ /* Ignore other evts */
@ -870,10 +834,10 @@ static void lp_pu_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_
lp_pu_st_wait_instant(conn, ctx, evt, param); lp_pu_st_wait_instant(conn, ctx, evt, param);
break; break;
case LP_PU_STATE_WAIT_INSTANT_ON_AIR: case LP_PU_STATE_WAIT_INSTANT_ON_AIR:
lp_pu_st_wait_instant_on_air(conn, ctx, evt, param); lp_pu_st_wait_instant_on_air(conn, ctx, evt);
break; break;
case LP_PU_STATE_WAIT_NTF_AVAIL: case LP_PU_STATE_WAIT_NTF:
lp_pu_st_wait_ntf_avail(conn, ctx, evt, param); lp_pu_st_wait_ntf(conn, ctx, evt, param);
break; break;
default: default:
/* Unknown state */ /* Unknown state */
@ -940,38 +904,22 @@ bool llcp_lp_pu_awaiting_instant(struct proc_ctx *ctx)
/* /*
* LLCP Remote Procedure PHY Update FSM * LLCP Remote Procedure PHY Update FSM
*/ */
static void rp_pu_tx(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) static void rp_pu_tx(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t opcode)
{ {
struct node_tx *tx; struct node_tx *tx;
struct pdu_data *pdu; struct pdu_data *pdu;
/* (pre)allocate tx node, but only do it if not already done */ /* Allocate tx node */
if (ctx->node_ref.tx_ack == NULL) { tx = llcp_tx_alloc(conn, ctx);
ctx->node_ref.tx_ack = llcp_tx_alloc(conn, ctx); LL_ASSERT(tx);
LL_ASSERT(ctx->node_ref.tx_ack);
}
if (!llcp_ntf_alloc_is_available()) {
/* No NTF nodes avail, so we need to hold off TX */
ctx->state = RP_PU_STATE_WAIT_NTF_AVAIL;
return;
}
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
ctx->data.pu.ntf_dle_node = llcp_ntf_alloc();
LL_ASSERT(ctx->data.pu.ntf_dle_node);
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
tx = ctx->node_ref.tx_ack;
pdu = (struct pdu_data *)tx->pdu; pdu = (struct pdu_data *)tx->pdu;
/* Encode LL Control PDU */ /* Encode LL Control PDU */
switch (ctx->tx_opcode) { switch (opcode) {
#if defined(CONFIG_BT_PERIPHERAL) #if defined(CONFIG_BT_PERIPHERAL)
case PDU_DATA_LLCTRL_TYPE_PHY_RSP: case PDU_DATA_LLCTRL_TYPE_PHY_RSP:
llcp_pdu_encode_phy_rsp(conn, pdu); llcp_pdu_encode_phy_rsp(conn, pdu);
ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_PHY_UPD_IND;
ctx->state = RP_PU_STATE_WAIT_TX_ACK_PHY_RSP;
break; break;
#endif /* CONFIG_BT_PERIPHERAL */ #endif /* CONFIG_BT_PERIPHERAL */
#if defined(CONFIG_BT_CENTRAL) #if defined(CONFIG_BT_CENTRAL)
@ -979,14 +927,15 @@ static void rp_pu_tx(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, vo
pu_prep_update_ind(conn, ctx); pu_prep_update_ind(conn, ctx);
pu_prepare_instant(conn, ctx); pu_prepare_instant(conn, ctx);
llcp_pdu_encode_phy_update_ind(ctx, pdu); llcp_pdu_encode_phy_update_ind(ctx, pdu);
ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED;
ctx->state = RP_PU_STATE_WAIT_TX_ACK_PHY_UPDATE_IND;
break; break;
#endif /* CONFIG_BT_CENTRAL */ #endif /* CONFIG_BT_CENTRAL */
default: default:
LL_ASSERT(0); LL_ASSERT(0);
} }
ctx->tx_ack = tx;
ctx->tx_opcode = pdu->llctrl.opcode;
/* Enqueue LL Control PDU towards LLL */ /* Enqueue LL Control PDU towards LLL */
llcp_tx_enqueue(conn, tx); llcp_tx_enqueue(conn, tx);
@ -996,29 +945,65 @@ static void rp_pu_tx(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, vo
static void rp_pu_complete_finalize(struct ll_conn *conn, struct proc_ctx *ctx) static void rp_pu_complete_finalize(struct ll_conn *conn, struct proc_ctx *ctx)
{ {
llcp_rr_complete(conn);
llcp_rr_set_paused_cmd(conn, PROC_NONE); llcp_rr_set_paused_cmd(conn, PROC_NONE);
llcp_rr_complete(conn);
ctx->state = RP_PU_STATE_IDLE; ctx->state = RP_PU_STATE_IDLE;
} }
static void rp_pu_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) static void rp_pu_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param)
{ {
pu_reset_timing_restrict(conn); /* when complete reset timing restrictions - idempotent
/* Postpone procedure completion (and possible NTF generation) to actual 'air instant' * (so no problem if we need to wait for NTF buffer)
* Since LLCP STM is driven from LLL prepare this actually happens BEFORE instant
* and thus NTFs are generated and propagated up prior to actual instant on air.
* Instead postpone completion/NTF to the beginning of RX handling
*/ */
ctx->state = RP_PU_STATE_WAIT_INSTANT_ON_AIR; pu_reset_timing_restrict(conn);
/* For remote initiated PHY update Host is notified only if a PHY changes */
if (ctx->data.pu.ntf_pu) {
/* Notification may be send after instant is on air */
ctx->state = RP_PU_STATE_WAIT_INSTANT_ON_AIR;
} else {
rp_pu_complete_finalize(conn, ctx);
}
} }
static void rp_pu_tx_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) void rp_pu_tx_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param)
{ {
pu_ntf(conn, ctx);
#if defined(CONFIG_BT_CTLR_DATA_LENGTH) #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
pu_dle_ntf(conn, ctx); #define NTF_DLE (ctx->data.pu.ntf_dle)
#else
#define NTF_DLE 0
#endif #endif
rp_pu_complete_finalize(conn, ctx); uint8_t ntf_count = ctx->data.pu.ntf_pu + NTF_DLE;
/* if we need to send both PHY and DLE notification, but we
* do not have 2 buffers available we serialize the sending
* of notifications
*/
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
if ((ntf_count > 1) && !llcp_ntf_alloc_num_available(ntf_count)) {
ntf_count = 1;
}
#endif /* CONFIG_BT_CTLR_DATA_LENGTH) */
if ((ntf_count > 0) && !llcp_ntf_alloc_num_available(ntf_count)) {
ctx->state = RP_PU_STATE_WAIT_NTF;
} else {
if (ctx->data.pu.ntf_pu) {
pu_ntf(conn, ctx);
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
if (ntf_count == 1 && NTF_DLE == 1) {
ctx->state = RP_PU_STATE_WAIT_NTF;
return;
}
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
}
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
if (ctx->data.pu.ntf_dle) {
pu_dle_ntf(conn, ctx);
}
#endif
rp_pu_complete_finalize(conn, ctx);
}
} }
#if defined(CONFIG_BT_CENTRAL) #if defined(CONFIG_BT_CENTRAL)
@ -1026,14 +1011,15 @@ static void rp_pu_send_phy_update_ind(struct ll_conn *conn, struct proc_ctx *ctx
void *param) void *param)
{ {
if (llcp_rr_ispaused(conn) || !llcp_tx_alloc_peek(conn, ctx) || if (llcp_rr_ispaused(conn) || !llcp_tx_alloc_peek(conn, ctx) ||
(llcp_rr_get_paused_cmd(conn) == PROC_PHY_UPDATE) || (llcp_rr_get_paused_cmd(conn) == PROC_PHY_UPDATE) ||
!ull_is_lll_tx_queue_empty(conn)) { !ull_is_lll_tx_queue_empty(conn)) {
ctx->state = RP_PU_STATE_WAIT_TX_PHY_UPDATE_IND; ctx->state = RP_PU_STATE_WAIT_TX_PHY_UPDATE_IND;
} else { } else {
llcp_rr_set_paused_cmd(conn, PROC_CTE_REQ); llcp_rr_set_paused_cmd(conn, PROC_CTE_REQ);
ctx->tx_opcode = PDU_DATA_LLCTRL_TYPE_PHY_UPD_IND; rp_pu_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_PHY_UPD_IND);
rp_pu_tx(conn, ctx, evt, param);
ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED;
ctx->state = RP_PU_STATE_WAIT_TX_ACK_PHY_UPDATE_IND;
} }
} }
#endif /* CONFIG_BT_CENTRAL */ #endif /* CONFIG_BT_CENTRAL */
@ -1046,8 +1032,9 @@ static void rp_pu_send_phy_rsp(struct ll_conn *conn, struct proc_ctx *ctx, uint8
ctx->state = RP_PU_STATE_WAIT_TX_PHY_RSP; ctx->state = RP_PU_STATE_WAIT_TX_PHY_RSP;
} else { } else {
llcp_rr_set_paused_cmd(conn, PROC_CTE_REQ); llcp_rr_set_paused_cmd(conn, PROC_CTE_REQ);
ctx->tx_opcode = PDU_DATA_LLCTRL_TYPE_PHY_RSP; rp_pu_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_PHY_RSP);
rp_pu_tx(conn, ctx, evt, param); ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_PHY_UPD_IND;
ctx->state = RP_PU_STATE_WAIT_TX_ACK_PHY_RSP;
} }
} }
#endif /* CONFIG_BT_CENTRAL */ #endif /* CONFIG_BT_CENTRAL */
@ -1077,8 +1064,6 @@ static void rp_pu_st_wait_rx_phy_req(struct ll_conn *conn, struct proc_ctx *ctx,
switch (conn->lll.role) { switch (conn->lll.role) {
#if defined(CONFIG_BT_CENTRAL) #if defined(CONFIG_BT_CENTRAL)
case BT_HCI_ROLE_CENTRAL: case BT_HCI_ROLE_CENTRAL:
/* Mark RX node to NOT release */
llcp_rx_node_retain(ctx);
rp_pu_send_phy_update_ind(conn, ctx, evt, param); rp_pu_send_phy_update_ind(conn, ctx, evt, param);
break; break;
#endif /* CONFIG_BT_CENTRAL */ #endif /* CONFIG_BT_CENTRAL */
@ -1180,14 +1165,12 @@ static void rp_pu_st_wait_rx_phy_update_ind(struct ll_conn *conn, struct proc_ct
llcp_pdu_decode_phy_update_ind(ctx, (struct pdu_data *)param); llcp_pdu_decode_phy_update_ind(ctx, (struct pdu_data *)param);
const uint8_t end_procedure = pu_check_update_ind(conn, ctx); const uint8_t end_procedure = pu_check_update_ind(conn, ctx);
/* Mark RX node to NOT release */
llcp_rx_node_retain(ctx);
if (!end_procedure) { if (!end_procedure) {
/* Since at least one phy will change, /* Since at least one phy will change,
* stop the procedure response timeout * stop the procedure response timeout
*/ */
llcp_rr_prt_stop(conn); llcp_rr_prt_stop(conn);
ctx->state = RP_PU_STATE_WAIT_INSTANT; ctx->state = RP_PU_STATE_WAIT_INSTANT;
} else { } else {
if (ctx->data.pu.error == BT_HCI_ERR_INSTANT_PASSED) { if (ctx->data.pu.error == BT_HCI_ERR_INSTANT_PASSED) {
@ -1247,12 +1230,11 @@ static void rp_pu_st_wait_instant_on_air(struct ll_conn *conn, struct proc_ctx *
} }
} }
static void rp_pu_st_wait_ntf_avail(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, static void rp_pu_st_wait_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param)
void *param)
{ {
switch (evt) { switch (evt) {
case RP_PU_EVT_RUN: case RP_PU_EVT_RUN:
rp_pu_tx(conn, ctx, evt, param); rp_pu_tx_ntf(conn, ctx, evt, param);
break; break;
default: default:
/* Ignore other evts */ /* Ignore other evts */
@ -1294,8 +1276,8 @@ static void rp_pu_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_
case RP_PU_STATE_WAIT_INSTANT_ON_AIR: case RP_PU_STATE_WAIT_INSTANT_ON_AIR:
rp_pu_st_wait_instant_on_air(conn, ctx, evt, param); rp_pu_st_wait_instant_on_air(conn, ctx, evt, param);
break; break;
case RP_PU_STATE_WAIT_NTF_AVAIL: case RP_PU_STATE_WAIT_NTF:
rp_pu_st_wait_ntf_avail(conn, ctx, evt, param); rp_pu_st_wait_ntf(conn, ctx, evt, param);
break; break;
default: default:
/* Unknown state */ /* Unknown state */

View file

@ -190,7 +190,7 @@ struct proc_ctx *llcp_rr_peek(struct ll_conn *conn)
bool llcp_rr_ispaused(struct ll_conn *conn) bool llcp_rr_ispaused(struct ll_conn *conn)
{ {
return (conn->llcp.remote.pause == 1U); return conn->llcp.remote.pause == 1U;
} }
void llcp_rr_pause(struct ll_conn *conn) void llcp_rr_pause(struct ll_conn *conn)
@ -213,13 +213,8 @@ void llcp_rr_prt_stop(struct ll_conn *conn)
conn->llcp.remote.prt_expire = 0U; conn->llcp.remote.prt_expire = 0U;
} }
void llcp_rr_rx(struct ll_conn *conn, struct proc_ctx *ctx, memq_link_t *link, void llcp_rr_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pdu *rx)
struct node_rx_pdu *rx)
{ {
/* Store RX node and link */
ctx->node_ref.rx = rx;
ctx->node_ref.link = link;
switch (ctx->proc) { switch (ctx->proc) {
case PROC_UNKNOWN: case PROC_UNKNOWN:
/* Do nothing */ /* Do nothing */
@ -324,15 +319,17 @@ void llcp_rr_tx_ack(struct ll_conn *conn, struct proc_ctx *ctx, struct node_tx *
break; break;
} }
/* Clear TX node reference */
ctx->node_ref.tx_ack = NULL;
llcp_rr_check_done(conn, ctx); llcp_rr_check_done(conn, ctx);
} }
void llcp_rr_tx_ntf(struct ll_conn *conn, struct proc_ctx *ctx) void llcp_rr_tx_ntf(struct ll_conn *conn, struct proc_ctx *ctx)
{ {
switch (ctx->proc) { switch (ctx->proc) {
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
case PROC_DATA_LENGTH_UPDATE:
/* llcp_rp_comm_tx_ntf(conn, ctx); */
break;
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
#ifdef CONFIG_BT_CTLR_PHY #ifdef CONFIG_BT_CTLR_PHY
case PROC_PHY_UPDATE: case PROC_PHY_UPDATE:
llcp_rp_pu_tx_ntf(conn, ctx); llcp_rp_pu_tx_ntf(conn, ctx);
@ -862,7 +859,7 @@ static const struct proc_role new_proc_lut[] = {
#endif /* CONFIG_BT_CTLR_SCA_UPDATE */ #endif /* CONFIG_BT_CTLR_SCA_UPDATE */
}; };
void llcp_rr_new(struct ll_conn *conn, memq_link_t *link, struct node_rx_pdu *rx, bool valid_pdu) void llcp_rr_new(struct ll_conn *conn, struct node_rx_pdu *rx, bool valid_pdu)
{ {
struct proc_ctx *ctx; struct proc_ctx *ctx;
struct pdu_data *pdu; struct pdu_data *pdu;
@ -901,7 +898,7 @@ void llcp_rr_new(struct ll_conn *conn, memq_link_t *link, struct node_rx_pdu *rx
/* Handle PDU */ /* Handle PDU */
ctx = llcp_rr_peek(conn); ctx = llcp_rr_peek(conn);
if (ctx) { if (ctx) {
llcp_rr_rx(conn, ctx, link, rx); llcp_rr_rx(conn, ctx, rx);
} }
} }

View file

@ -42,5 +42,4 @@ void ut_rx_node_real(const char *file, uint32_t line, enum helper_node_opcode op
struct node_rx_pdu **ntf_ref, void *param); struct node_rx_pdu **ntf_ref, void *param);
void ut_rx_q_is_empty_real(const char *file, uint32_t line); void ut_rx_q_is_empty_real(const char *file, uint32_t line);
void release_ntf(struct node_rx_pdu *ntf);
void encode_pdu(enum helper_pdu_opcode opcode, struct pdu_data *pdu, void *param); void encode_pdu(enum helper_pdu_opcode opcode, struct pdu_data *pdu, void *param);

View file

@ -40,7 +40,6 @@
#include "ull_conn_iso_internal.h" #include "ull_conn_iso_internal.h"
#include "ull_conn_types.h" #include "ull_conn_types.h"
#include "ull_internal.h"
#include "ull_conn_internal.h" #include "ull_conn_internal.h"
#include "ull_llcp_internal.h" #include "ull_llcp_internal.h"
#include "ull_llcp.h" #include "ull_llcp.h"
@ -355,25 +354,14 @@ void event_done(struct ll_conn *conn)
zassert_equal(*evt_active, 1, "Called outside an active event"); zassert_equal(*evt_active, 1, "Called outside an active event");
*evt_active = 0; *evt_active = 0;
/* Notify all control procedures that wait with Host notifications for instant to be on /* Notify all conotrol procedures that wait with Host notifications for instant to be on
* air. This is done here because UT does not maintain actual connection events. * air. This is done here because UT does not maintain actual connection events.
*/ */
ull_cp_tx_ntf(conn); ull_cp_tx_ntf(conn);
while ((rx = (struct node_rx_pdu *)sys_slist_get(&lt_tx_q))) { while ((rx = (struct node_rx_pdu *)sys_slist_get(&lt_tx_q))) {
ull_cp_rx(conn, rx);
/* Mark buffer for release */ free(rx);
rx->hdr.type = NODE_RX_TYPE_RELEASE;
ull_cp_rx(conn, NULL, rx);
if (rx->hdr.type == NODE_RX_TYPE_RELEASE) {
/* Only release if node was not hi-jacked by LLCP */
ll_rx_release(rx);
} else if (rx->hdr.type != NODE_RX_TYPE_RETAIN) {
/* Otherwise put/sched to emulate ull_cp_rx return path */
ll_rx_put_sched(rx->hdr.link, rx);
}
} }
} }
@ -395,8 +383,6 @@ uint16_t event_counter(struct ll_conn *conn)
return event_counter; return event_counter;
} }
static struct node_rx_pdu *rx_malloc_store;
void lt_tx_real(const char *file, uint32_t line, enum helper_pdu_opcode opcode, void lt_tx_real(const char *file, uint32_t line, enum helper_pdu_opcode opcode,
struct ll_conn *conn, void *param) struct ll_conn *conn, void *param)
{ {
@ -406,9 +392,6 @@ void lt_tx_real(const char *file, uint32_t line, enum helper_pdu_opcode opcode,
rx = malloc(PDU_RX_NODE_SIZE); rx = malloc(PDU_RX_NODE_SIZE);
zassert_not_null(rx, "Out of memory.\nCalled at %s:%d\n", file, line); zassert_not_null(rx, "Out of memory.\nCalled at %s:%d\n", file, line);
/* Remember RX node to allow for correct release */
rx_malloc_store = rx;
/* Encode node_rx_pdu if required by particular procedure */ /* Encode node_rx_pdu if required by particular procedure */
if (helper_node_encode[opcode]) { if (helper_node_encode[opcode]) {
helper_node_encode[opcode](rx, param); helper_node_encode[opcode](rx, param);
@ -428,25 +411,10 @@ void lt_tx_real_no_encode(const char *file, uint32_t line, struct pdu_data *pdu,
rx = malloc(PDU_RX_NODE_SIZE); rx = malloc(PDU_RX_NODE_SIZE);
zassert_not_null(rx, "Out of memory.\nCalled at %s:%d\n", file, line); zassert_not_null(rx, "Out of memory.\nCalled at %s:%d\n", file, line);
/* Remember RX node to allow for correct release */
rx_malloc_store = rx;
memcpy((struct pdu_data *)rx->pdu, pdu, sizeof(struct pdu_data)); memcpy((struct pdu_data *)rx->pdu, pdu, sizeof(struct pdu_data));
sys_slist_append(&lt_tx_q, (sys_snode_t *)rx); sys_slist_append(&lt_tx_q, (sys_snode_t *)rx);
} }
void release_ntf(struct node_rx_pdu *ntf)
{
if (ntf == rx_malloc_store) {
free(ntf);
return;
}
ntf->hdr.next = NULL;
ll_rx_mem_release((void **)&ntf);
}
void lt_rx_real(const char *file, uint32_t line, enum helper_pdu_opcode opcode, void lt_rx_real(const char *file, uint32_t line, enum helper_pdu_opcode opcode,
struct ll_conn *conn, struct node_tx **tx_ref, void *param) struct ll_conn *conn, struct node_tx **tx_ref, void *param)
{ {

View file

@ -153,7 +153,7 @@ ZTEST(cis_create, test_cc_create_periph_rem_host_accept)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/* Accept request */ /* Accept request */
ull_cp_cc_accept(&conn); ull_cp_cc_accept(&conn);
@ -195,15 +195,7 @@ ZTEST(cis_create, test_cc_create_periph_rem_host_accept)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
} }
/* Prepare */
event_prepare(&conn);
/* Done */
event_done(&conn);
/* Emulate CIS becoming established */ /* Emulate CIS becoming established */
ull_cp_cc_established(&conn, 0);
/* Prepare */ /* Prepare */
event_prepare(&conn); event_prepare(&conn);
@ -281,9 +273,6 @@ ZTEST(cis_create, test_cc_create_periph_rem_host_reject)
ut_rx_node(NODE_CIS_REQUEST, &ntf, &cis_req); ut_rx_node(NODE_CIS_REQUEST, &ntf, &cis_req);
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */
release_ntf(ntf);
/* Decline request */ /* Decline request */
ull_cp_cc_reject(&conn, ERROR_CODE); ull_cp_cc_reject(&conn, ERROR_CODE);
@ -338,10 +327,6 @@ ZTEST(cis_create, test_cc_create_periph_rem_host_accept_to)
.error_code = BT_HCI_ERR_CONN_ACCEPT_TIMEOUT, .error_code = BT_HCI_ERR_CONN_ACCEPT_TIMEOUT,
.reject_opcode = PDU_DATA_LLCTRL_TYPE_CIS_REQ .reject_opcode = PDU_DATA_LLCTRL_TYPE_CIS_REQ
}; };
struct node_rx_conn_iso_estab cis_estab = {
.cis_handle = 0x00,
.status = BT_HCI_ERR_CONN_ACCEPT_TIMEOUT
};
/* Role */ /* Role */
test_set_role(&conn, BT_HCI_ROLE_PERIPHERAL); test_set_role(&conn, BT_HCI_ROLE_PERIPHERAL);
@ -362,9 +347,6 @@ ZTEST(cis_create, test_cc_create_periph_rem_host_accept_to)
ut_rx_node(NODE_CIS_REQUEST, &ntf, &cis_req); ut_rx_node(NODE_CIS_REQUEST, &ntf, &cis_req);
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */
release_ntf(ntf);
/* Emulate that time passes real fast re. timeout */ /* Emulate that time passes real fast re. timeout */
conn.connect_accept_to = 0; conn.connect_accept_to = 0;
@ -384,13 +366,6 @@ ZTEST(cis_create, test_cc_create_periph_rem_host_accept_to)
/* Done */ /* Done */
event_done(&conn); event_done(&conn);
/* There should be excactly one host notification */
ut_rx_node(NODE_CIS_ESTABLISHED, &ntf, &cis_estab);
ut_rx_q_is_empty();
/* Release Ntf */
release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free()); "Free CTX buffers %d", llcp_ctx_buffers_free());
} }

View file

@ -309,7 +309,7 @@ ZTEST(collision, test_phy_update_central_loc_collision)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free()); "Free CTX buffers %d", llcp_ctx_buffers_free());
@ -430,7 +430,7 @@ ZTEST(collision, test_phy_update_central_rem_collision)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/* Prepare */ /* Prepare */
event_prepare(&conn); event_prepare(&conn);
@ -481,7 +481,7 @@ ZTEST(collision, test_phy_update_central_rem_collision)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free()); "Free CTX buffers %d", llcp_ctx_buffers_free());
@ -551,19 +551,13 @@ ZTEST(collision, test_phy_update_periph_loc_collision)
/* Done */ /* Done */
event_done(&conn); event_done(&conn);
/* Prepare */
event_prepare(&conn);
/* Done */
event_done(&conn);
/* There should be one host notification */ /* There should be one host notification */
pu.status = BT_HCI_ERR_LL_PROC_COLLISION; pu.status = BT_HCI_ERR_LL_PROC_COLLISION;
ut_rx_node(NODE_PHY_UPDATE, &ntf, &pu); ut_rx_node(NODE_PHY_UPDATE, &ntf, &pu);
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/* Prepare */ /* Prepare */
event_prepare(&conn); event_prepare(&conn);
@ -611,7 +605,7 @@ ZTEST(collision, test_phy_update_periph_loc_collision)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free()); "Free CTX buffers %d", llcp_ctx_buffers_free());
@ -750,7 +744,7 @@ ZTEST(collision, test_phy_conn_update_central_loc_collision)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free()); "Free CTX buffers %d", llcp_ctx_buffers_free());
} }

View file

@ -323,7 +323,7 @@ ZTEST(central_loc, test_conn_update_central_loc_accept)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free()); "Free CTX buffers %d", llcp_ctx_buffers_free());
} }
@ -581,7 +581,7 @@ ZTEST(central_loc, test_conn_update_central_loc_accept_reject_2nd_cpr)
ull_cp_release_tx(&conn_3rd, tx); ull_cp_release_tx(&conn_3rd, tx);
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/* One less CTXs as the conn_3rd CPR is still 'running' */ /* One less CTXs as the conn_3rd CPR is still 'running' */
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt()-1, zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt()-1,
@ -794,7 +794,7 @@ ZTEST(central_loc, test_conn_update_central_loc_reject)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free()); "Free CTX buffers %d", llcp_ctx_buffers_free());
} }
@ -919,7 +919,7 @@ ZTEST(central_loc, test_conn_update_central_loc_remote_legacy)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free()); "Free CTX buffers %d", llcp_ctx_buffers_free());
} }
@ -1044,7 +1044,7 @@ ZTEST(central_loc, test_conn_update_central_loc_unsupp_wo_feat_exch)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free()); "Free CTX buffers %d", llcp_ctx_buffers_free());
} }
@ -1140,7 +1140,7 @@ ZTEST(central_loc, test_conn_update_central_loc_unsupp_w_feat_exch)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free()); "Free CTX buffers %d", llcp_ctx_buffers_free());
} }
@ -1307,7 +1307,7 @@ ZTEST(central_loc, test_conn_update_central_loc_collision)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free()); "Free CTX buffers %d", llcp_ctx_buffers_free());
} }
@ -1372,7 +1372,7 @@ ZTEST(central_rem, test_conn_update_central_rem_accept)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/*******************/ /*******************/
@ -1427,7 +1427,7 @@ ZTEST(central_rem, test_conn_update_central_rem_accept)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free()); "Free CTX buffers %d", llcp_ctx_buffers_free());
} }
@ -1544,7 +1544,7 @@ ZTEST(central_rem, test_conn_update_central_rem_reject)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/*******************/ /*******************/
@ -1683,7 +1683,7 @@ ZTEST(central_rem, test_conn_update_central_rem_collision)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/*******************/ /*******************/
@ -1744,7 +1744,7 @@ ZTEST(central_rem, test_conn_update_central_rem_collision)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/* Prepare */ /* Prepare */
event_prepare(&conn); event_prepare(&conn);
@ -1802,7 +1802,7 @@ ZTEST(central_rem, test_conn_update_central_rem_collision)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free()); "Free CTX buffers %d", llcp_ctx_buffers_free());
} }
@ -1906,7 +1906,7 @@ ZTEST(periph_loc, test_conn_update_periph_loc_accept)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free()); "Free CTX buffers %d", llcp_ctx_buffers_free());
} }
@ -1986,7 +1986,7 @@ ZTEST(periph_loc, test_conn_update_periph_loc_reject)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free()); "Free CTX buffers %d", llcp_ctx_buffers_free());
} }
@ -2066,7 +2066,7 @@ ZTEST(periph_loc, test_conn_update_periph_loc_unsupp_feat_wo_feat_exch)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free()); "Free CTX buffers %d", llcp_ctx_buffers_free());
} }
@ -2234,7 +2234,7 @@ ZTEST(periph_loc, test_conn_update_periph_loc_collision)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/*******************/ /*******************/
@ -2262,7 +2262,7 @@ ZTEST(periph_loc, test_conn_update_periph_loc_collision)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/* Prepare */ /* Prepare */
event_prepare(&conn); event_prepare(&conn);
@ -2306,7 +2306,7 @@ ZTEST(periph_loc, test_conn_update_periph_loc_collision)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free()); "Free CTX buffers %d", llcp_ctx_buffers_free());
} }
@ -2376,7 +2376,7 @@ ZTEST(periph_rem, test_conn_update_periph_rem_accept)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/*******************/ /*******************/
@ -2437,7 +2437,7 @@ ZTEST(periph_rem, test_conn_update_periph_rem_accept)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free()); "Free CTX buffers %d", llcp_ctx_buffers_free());
} }
@ -3213,7 +3213,7 @@ ZTEST(periph_loc, test_conn_update_periph_loc_collision_reject_2nd_cpr)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/*******************/ /*******************/
@ -3241,7 +3241,7 @@ ZTEST(periph_loc, test_conn_update_periph_loc_collision_reject_2nd_cpr)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
{ {
/* Initiate a parallel local Connection Parameter Request Procedure */ /* Initiate a parallel local Connection Parameter Request Procedure */
@ -3326,7 +3326,7 @@ ZTEST(periph_loc, test_conn_update_periph_loc_collision_reject_2nd_cpr)
} }
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/* One less CTXs as the conn_2nd CPR is still 'running' */ /* One less CTXs as the conn_2nd CPR is still 'running' */
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt()-1, zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt()-1,
@ -3487,7 +3487,7 @@ ZTEST(periph_rem, test_conn_update_periph_rem_accept_reject_2nd_cpr)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/*******************/ /*******************/
@ -3587,7 +3587,7 @@ ZTEST(periph_rem, test_conn_update_periph_rem_accept_reject_2nd_cpr)
} }
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/* One less CTXs as the conn_2nd CPR is still 'running' */ /* One less CTXs as the conn_2nd CPR is still 'running' */
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt()-1, zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt()-1,
@ -3720,7 +3720,7 @@ ZTEST(periph_rem, test_conn_update_periph_rem_invalid_ind)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/*******************/ /*******************/
@ -3781,7 +3781,7 @@ ZTEST(periph_rem, test_conn_update_periph_rem_invalid_ind)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/*******************/ /*******************/
@ -3843,7 +3843,7 @@ ZTEST(periph_rem, test_conn_update_periph_rem_invalid_ind)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/*******************/ /*******************/
@ -3942,7 +3942,7 @@ ZTEST(periph_rem, test_conn_update_periph_rem_reject)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/*******************/ /*******************/
@ -4081,7 +4081,7 @@ ZTEST(periph_rem, test_conn_update_periph_rem_collision)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/*******************/ /*******************/
@ -4146,7 +4146,7 @@ ZTEST(periph_rem, test_conn_update_periph_rem_collision)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/* Prepare */ /* Prepare */
event_prepare(&conn); event_prepare(&conn);
@ -4190,7 +4190,7 @@ ZTEST(periph_rem, test_conn_update_periph_rem_collision)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free()); "Free CTX buffers %d", llcp_ctx_buffers_free());
} }
@ -4296,7 +4296,7 @@ ZTEST(central_loc_no_param_req, test_conn_update_central_loc_accept_no_param_req
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
} }
} while (parameters_changed-- > 0U); } while (parameters_changed-- > 0U);
@ -4539,7 +4539,7 @@ ZTEST(periph_rem_no_param_req, test_conn_update_periph_rem_accept_no_param_req)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
} }
} while (parameters_changed-- > 0U); } while (parameters_changed-- > 0U);

View file

@ -133,7 +133,7 @@ ZTEST(cte_req_after_fex, test_cte_req_central_local)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/* Release tx node */ /* Release tx node */
ull_cp_release_tx(&conn, tx); ull_cp_release_tx(&conn, tx);
@ -208,7 +208,7 @@ ZTEST(cte_req_after_fex, test_cte_req_peripheral_local)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/* Release tx node */ /* Release tx node */
ull_cp_release_tx(&conn, tx); ull_cp_release_tx(&conn, tx);
@ -427,7 +427,7 @@ ZTEST(cte_req_after_fex, test_cte_req_rejected_inv_ll_param_central_local)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/* Release tx node */ /* Release tx node */
ull_cp_release_tx(&conn, tx); ull_cp_release_tx(&conn, tx);
@ -506,7 +506,7 @@ ZTEST(cte_req_after_fex, test_cte_req_rejected_inv_ll_param_peripheral_local)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/* Release tx node */ /* Release tx node */
ull_cp_release_tx(&conn, tx); ull_cp_release_tx(&conn, tx);
@ -726,7 +726,7 @@ static void test_cte_req_ll_unknown_rsp_local(uint8_t role)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/* Release tx node */ /* Release tx node */
ull_cp_release_tx(&conn, tx); ull_cp_release_tx(&conn, tx);
@ -861,7 +861,7 @@ static void run_local_cte_req(struct pdu_data_llctrl_cte_req *cte_req)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/* Release tx node */ /* Release tx node */
ull_cp_release_tx(&conn, tx); ull_cp_release_tx(&conn, tx);
@ -918,7 +918,7 @@ static void check_phy_update(bool is_local, struct pdu_data_llctrl_phy_req *phy_
} }
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/* The RX queue should be empty now */ /* The RX queue should be empty now */
ut_rx_q_is_empty(); ut_rx_q_is_empty();

View file

@ -97,6 +97,13 @@ ZTEST(dle_central, test_data_length_update_central_loc)
ull_conn_default_tx_time_set(2120); ull_conn_default_tx_time_set(2120);
ull_dle_init(&conn, PHY_1M); ull_dle_init(&conn, PHY_1M);
/* Steal all ntf buffers, so as to check that the wait_ntf mechanism works */
while (ll_pdu_rx_alloc_peek(1)) {
ntf = ll_pdu_rx_alloc();
/* Make sure we use a correct type or the release won't work */
ntf->hdr.type = NODE_RX_TYPE_DC_PDU;
}
/* Initiate a Data Length Update Procedure */ /* Initiate a Data Length Update Procedure */
err = ull_cp_data_length_update(&conn, 211, 1800); err = ull_cp_data_length_update(&conn, 211, 1800);
zassert_equal(err, BT_HCI_ERR_SUCCESS); zassert_equal(err, BT_HCI_ERR_SUCCESS);
@ -114,14 +121,19 @@ ZTEST(dle_central, test_data_length_update_central_loc)
event_done(&conn); event_done(&conn);
ut_rx_q_is_empty();
/* Release Ntf, so next cycle will generate NTF and complete procedure */
ull_cp_release_ntf(ntf);
event_prepare(&conn);
event_done(&conn);
/* There should be one host notification */ /* There should be one host notification */
ut_rx_pdu(LL_LENGTH_RSP, &ntf, &length_ntf); ut_rx_pdu(LL_LENGTH_RSP, &ntf, &length_ntf);
ut_rx_q_is_empty(); ut_rx_q_is_empty();
zassert_equal(conn.lll.event_counter, 1, "Wrong event-count %d\n", zassert_equal(conn.lll.event_counter, 2, "Wrong event-count %d\n",
conn.lll.event_counter); conn.lll.event_counter);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free());
} }
/* /*
@ -601,6 +613,13 @@ ZTEST(dle_periph, test_data_length_update_periph_rem)
ull_conn_default_tx_time_set(1800); ull_conn_default_tx_time_set(1800);
ull_dle_init(&conn, PHY_1M); ull_dle_init(&conn, PHY_1M);
/* Steal all ntf buffers, so as to check that the wait_ntf mechanism works */
while (ll_pdu_rx_alloc_peek(1)) {
ntf = ll_pdu_rx_alloc();
/* Make sure we use a correct type or the release won't work */
ntf->hdr.type = NODE_RX_TYPE_DC_PDU;
}
event_prepare(&conn); event_prepare(&conn);
/* Tx Queue should have one LL Control PDU */ /* Tx Queue should have one LL Control PDU */
@ -617,6 +636,13 @@ ZTEST(dle_periph, test_data_length_update_periph_rem)
/* TX Ack */ /* TX Ack */
event_tx_ack(&conn, tx); event_tx_ack(&conn, tx);
event_done(&conn);
ut_rx_q_is_empty();
/* Release Ntf, so next cycle will generate NTF and complete procedure */
ull_cp_release_ntf(ntf);
event_prepare(&conn);
event_done(&conn); event_done(&conn);
ut_rx_pdu(LL_LENGTH_RSP, &ntf, &length_ntf); ut_rx_pdu(LL_LENGTH_RSP, &ntf, &length_ntf);

View file

@ -290,7 +290,7 @@ ZTEST(encryption_start, test_encryption_start_central_loc)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free()); "Free CTX buffers %d", llcp_ctx_buffers_free());
@ -392,6 +392,13 @@ ZTEST(encryption_start, test_encryption_start_central_loc_limited_memory)
/* Dummy remove, as above loop might queue up ctx */ /* Dummy remove, as above loop might queue up ctx */
llcp_tx_alloc_unpeek(ctx); llcp_tx_alloc_unpeek(ctx);
/* Steal all ntf buffers */
while (ll_pdu_rx_alloc_peek(1)) {
ntf = ll_pdu_rx_alloc();
/* Make sure we use a correct type or the release won't work */
ntf->hdr.type = NODE_RX_TYPE_DC_PDU;
}
/* Initiate an Encryption Start Procedure */ /* Initiate an Encryption Start Procedure */
err = ull_cp_encryption_start(&conn, rand, ediv, ltk); err = ull_cp_encryption_start(&conn, rand, ediv, ltk);
zassert_equal(err, BT_HCI_ERR_SUCCESS); zassert_equal(err, BT_HCI_ERR_SUCCESS);
@ -478,12 +485,32 @@ ZTEST(encryption_start, test_encryption_start_central_loc_limited_memory)
CHECK_RX_PE_STATE(conn, RESUMED, ENCRYPTED); /* Rx enc. */ CHECK_RX_PE_STATE(conn, RESUMED, ENCRYPTED); /* Rx enc. */
CHECK_TX_PE_STATE(conn, RESUMED, ENCRYPTED); /* Tx enc. */ CHECK_TX_PE_STATE(conn, RESUMED, ENCRYPTED); /* Tx enc. */
/* There should be no host notifications */
ut_rx_q_is_empty();
/* Release Ntf */
ull_cp_release_ntf(ntf);
/* Prepare */
event_prepare(&conn);
/* Check state */
CHECK_RX_PE_STATE(conn, RESUMED, ENCRYPTED); /* Rx enc. */
CHECK_TX_PE_STATE(conn, RESUMED, ENCRYPTED); /* Tx enc. */
/* Done */
event_done(&conn);
/* Check state */
CHECK_RX_PE_STATE(conn, RESUMED, ENCRYPTED); /* Rx enc. */
CHECK_TX_PE_STATE(conn, RESUMED, ENCRYPTED); /* Tx enc. */
/* There should be one host notification */ /* There should be one host notification */
ut_rx_pdu(LL_START_ENC_RSP, &ntf, NULL); ut_rx_pdu(LL_START_ENC_RSP, &ntf, NULL);
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/* Tx Encryption should be enabled */ /* Tx Encryption should be enabled */
zassert_equal(conn.lll.enc_tx, 1U); zassert_equal(conn.lll.enc_tx, 1U);
@ -594,7 +621,7 @@ ZTEST(encryption_start, test_encryption_start_central_loc_reject_ext)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free()); "Free CTX buffers %d", llcp_ctx_buffers_free());
@ -691,7 +718,7 @@ ZTEST(encryption_start, test_encryption_start_central_loc_reject)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free()); "Free CTX buffers %d", llcp_ctx_buffers_free());
@ -802,7 +829,7 @@ ZTEST(encryption_start, test_encryption_start_central_loc_no_ltk)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free()); "Free CTX buffers %d", llcp_ctx_buffers_free());
@ -908,7 +935,7 @@ ZTEST(encryption_start, test_encryption_start_central_loc_no_ltk_2)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free()); "Free CTX buffers %d", llcp_ctx_buffers_free());
@ -1170,7 +1197,7 @@ ZTEST(encryption_start, test_encryption_start_periph_rem)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/* LTK request reply */ /* LTK request reply */
ull_cp_ltk_req_reply(&conn, ltk); ull_cp_ltk_req_reply(&conn, ltk);
@ -1352,6 +1379,13 @@ ZTEST(encryption_start, test_encryption_start_periph_rem_limited_memory)
/* Dummy remove, as above loop might queue up ctx */ /* Dummy remove, as above loop might queue up ctx */
llcp_tx_alloc_unpeek(ctx); llcp_tx_alloc_unpeek(ctx);
/* Steal all ntf buffers */
while (ll_pdu_rx_alloc_peek(1)) {
ntf = ll_pdu_rx_alloc();
/* Make sure we use a correct type or the release won't work */
ntf->hdr.type = NODE_RX_TYPE_DC_PDU;
}
/* Check state */ /* Check state */
CHECK_RX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Rx unenc. */ CHECK_RX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Rx unenc. */
CHECK_TX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Tx unenc. */ CHECK_TX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Tx unenc. */
@ -1390,12 +1424,29 @@ ZTEST(encryption_start, test_encryption_start_periph_rem_limited_memory)
CHECK_RX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Rx paused & unenc. */ CHECK_RX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Rx paused & unenc. */
CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */
/* There should be one host notification */ /* Done */
ut_rx_pdu(LL_ENC_REQ, &ntf, &enc_req); event_done(&conn);
/* Check state */
CHECK_RX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Rx paused & unenc. */
CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */
/* There should not be a host notification */
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release ntf */ /* Release ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/* Prepare */
event_prepare(&conn);
/* Check state */
CHECK_RX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Rx paused & unenc. */
CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */
/* There should be one host notification */
ut_rx_pdu(LL_ENC_REQ, &ntf, &enc_req);
ut_rx_q_is_empty();
/* Done */ /* Done */
event_done(&conn); event_done(&conn);
@ -1472,13 +1523,19 @@ ZTEST(encryption_start, test_encryption_start_periph_rem_limited_memory)
CHECK_RX_PE_STATE(conn, PAUSED, ENCRYPTED); /* Rx paused & enc. */ CHECK_RX_PE_STATE(conn, PAUSED, ENCRYPTED); /* Rx paused & enc. */
CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */
/* There should be one host notification */ /* There should not be a host notification */
ut_rx_pdu(LL_START_ENC_RSP, &ntf, NULL);
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release ntf */
ull_cp_release_ntf(ntf);
/* Prepare */ /* Prepare */
event_prepare(&conn); event_prepare(&conn);
/* There should be one host notification */
ut_rx_pdu(LL_START_ENC_RSP, &ntf, NULL);
ut_rx_q_is_empty();
/* Tx Queue should not have a LL Control PDU */ /* Tx Queue should not have a LL Control PDU */
lt_rx_q_is_empty(&conn); lt_rx_q_is_empty(&conn);
@ -1630,7 +1687,7 @@ ZTEST(encryption_start, test_encryption_start_periph_rem_no_ltk)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/* LTK request reply */ /* LTK request reply */
ull_cp_ltk_req_neq_reply(&conn); ull_cp_ltk_req_neq_reply(&conn);
@ -1770,7 +1827,7 @@ ZTEST(encryption_start, test_encryption_start_periph_rem_mic)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/* Prepare */ /* Prepare */
event_prepare(&conn); event_prepare(&conn);
@ -1955,7 +2012,7 @@ ZTEST(encryption_pause, test_encryption_pause_central_loc)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/* Tx Encryption should be enabled */ /* Tx Encryption should be enabled */
zassert_equal(conn.lll.enc_tx, 1U); zassert_equal(conn.lll.enc_tx, 1U);
@ -2072,7 +2129,7 @@ ZTEST(encryption_pause, test_encryption_pause_periph_rem)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/* LTK request reply */ /* LTK request reply */
ull_cp_ltk_req_reply(&conn, ltk); ull_cp_ltk_req_reply(&conn, ltk);

View file

@ -129,7 +129,7 @@ ZTEST(fex_central, test_feat_exchange_central_loc)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
ull_cp_release_tx(&conn, tx); ull_cp_release_tx(&conn, tx);
release_ntf(ntf); ull_cp_release_ntf(ntf);
} }
/* Test that host enabled feature makes it into feature exchange */ /* Test that host enabled feature makes it into feature exchange */
@ -159,7 +159,7 @@ ZTEST(fex_central, test_feat_exchange_central_loc)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
ull_cp_release_tx(&conn, tx); ull_cp_release_tx(&conn, tx);
release_ntf(ntf); ull_cp_release_ntf(ntf);
/* Remove host feature bit again */ /* Remove host feature bit again */
ll_set_host_feature(BT_LE_FEAT_BIT_ISO_CHANNELS, 0); ll_set_host_feature(BT_LE_FEAT_BIT_ISO_CHANNELS, 0);
@ -432,7 +432,7 @@ ZTEST(fex_central, test_feat_exchange_central_rem_2)
lt_rx_q_is_empty(&conn); lt_rx_q_is_empty(&conn);
ull_cp_release_tx(&conn, tx); ull_cp_release_tx(&conn, tx);
release_ntf(ntf); ull_cp_release_ntf(ntf);
} }
zassert_equal(conn.lll.event_counter, CENTRAL_NR_OF_EVENTS * (feat_to_test), zassert_equal(conn.lll.event_counter, CENTRAL_NR_OF_EVENTS * (feat_to_test),
@ -460,6 +460,13 @@ ZTEST(fex_periph, test_peripheral_feat_exchange_periph_loc)
/* Connect */ /* Connect */
ull_cp_state_set(&conn, ULL_CP_CONNECTED); ull_cp_state_set(&conn, ULL_CP_CONNECTED);
/* Steal all ntf buffers, so as to check that the wait_ntf mechanism works */
while (ll_pdu_rx_alloc_peek(1)) {
ntf = ll_pdu_rx_alloc();
/* Make sure we use a correct type or the release won't work */
ntf->hdr.type = NODE_RX_TYPE_DC_PDU;
}
/* Initiate a Feature Exchange Procedure */ /* Initiate a Feature Exchange Procedure */
err = ull_cp_feature_exchange(&conn); err = ull_cp_feature_exchange(&conn);
zassert_equal(err, BT_HCI_ERR_SUCCESS); zassert_equal(err, BT_HCI_ERR_SUCCESS);
@ -474,11 +481,19 @@ ZTEST(fex_periph, test_peripheral_feat_exchange_periph_loc)
event_done(&conn); event_done(&conn);
/* There should be one host notification */
ut_rx_pdu(LL_FEATURE_RSP, &ntf, &remote_feature_rsp);
ut_rx_q_is_empty(); ut_rx_q_is_empty();
zassert_equal(conn.lll.event_counter, 1, "Wrong event-count %d\n", /* Release Ntf, so next cycle will generate NTF and complete procedure */
ull_cp_release_ntf(ntf);
event_prepare(&conn);
event_done(&conn);
/* There should be one host notification */
ut_rx_pdu(LL_FEATURE_RSP, &ntf, &remote_feature_rsp);
ut_rx_q_is_empty();
zassert_equal(conn.lll.event_counter, 2, "Wrong event-count %d\n",
conn.lll.event_counter); conn.lll.event_counter);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free()); "Free CTX buffers %d", llcp_ctx_buffers_free());
@ -504,7 +519,15 @@ ZTEST(fex_periph, test_feat_exchange_periph_loc_unknown_rsp)
ull_cp_state_set(&conn, ULL_CP_CONNECTED); ull_cp_state_set(&conn, ULL_CP_CONNECTED);
/* Steal all ntf buffers, so as to check that the wait_ntf mechanism works */
while (ll_pdu_rx_alloc_peek(1)) {
ntf = ll_pdu_rx_alloc();
/* Make sure we use a correct type or the release won't work */
ntf->hdr.type = NODE_RX_TYPE_DC_PDU;
}
/* Initiate a Feature Exchange Procedure */ /* Initiate a Feature Exchange Procedure */
event_prepare(&conn); event_prepare(&conn);
err = ull_cp_feature_exchange(&conn); err = ull_cp_feature_exchange(&conn);
zassert_equal(err, BT_HCI_ERR_SUCCESS); zassert_equal(err, BT_HCI_ERR_SUCCESS);
@ -522,9 +545,17 @@ ZTEST(fex_periph, test_feat_exchange_periph_loc_unknown_rsp)
event_done(&conn); event_done(&conn);
ut_rx_q_is_empty();
/* Release Ntf, so next cycle will generate NTF and complete procedure */
ull_cp_release_ntf(ntf);
event_prepare(&conn);
event_done(&conn);
ut_rx_pdu(LL_UNKNOWN_RSP, &ntf, &unknown_rsp); ut_rx_pdu(LL_UNKNOWN_RSP, &ntf, &unknown_rsp);
ut_rx_q_is_empty(); ut_rx_q_is_empty();
zassert_equal(conn.lll.event_counter, 2, "Wrong event-count %d\n", zassert_equal(conn.lll.event_counter, 3, "Wrong event-count %d\n",
conn.lll.event_counter); conn.lll.event_counter);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free()); "Free CTX buffers %d", llcp_ctx_buffers_free());

View file

@ -136,7 +136,7 @@ ZTEST(hci_fex, test_hci_feat_exchange_central_loc)
"Wrong event count %d\n", conn_from_pool->lll.event_counter); "Wrong event count %d\n", conn_from_pool->lll.event_counter);
ull_cp_release_tx(conn_from_pool, tx); ull_cp_release_tx(conn_from_pool, tx);
release_ntf(ntf); ull_cp_release_ntf(ntf);
ll_conn_release(conn_from_pool); ll_conn_release(conn_from_pool);
} }

View file

@ -120,7 +120,7 @@ ZTEST(hci_fex, test_hci_feature_exchange)
zassert_equal(conn_from_pool->lll.event_counter, 1, "Wrong event count %d\n", zassert_equal(conn_from_pool->lll.event_counter, 1, "Wrong event count %d\n",
conn_from_pool->lll.event_counter); conn_from_pool->lll.event_counter);
ull_cp_release_tx(conn_from_pool, tx); ull_cp_release_tx(conn_from_pool, tx);
release_ntf(ntf); ull_cp_release_ntf(ntf);
ll_conn_release(conn_from_pool); ll_conn_release(conn_from_pool);
} }
@ -186,7 +186,7 @@ ZTEST(hci_version, test_hci_version_ind)
zassert_equal(conn_from_pool->lll.event_counter, 1, "Wrong event count %d\n", zassert_equal(conn_from_pool->lll.event_counter, 1, "Wrong event count %d\n",
conn_from_pool->lll.event_counter); conn_from_pool->lll.event_counter);
ull_cp_release_tx(conn_from_pool, tx); ull_cp_release_tx(conn_from_pool, tx);
release_ntf(ntf); ull_cp_release_ntf(ntf);
ll_conn_release(conn_from_pool); ll_conn_release(conn_from_pool);
} }

View file

@ -37,7 +37,6 @@
#include "ull_iso_types.h" #include "ull_iso_types.h"
#include "ull_conn_iso_types.h" #include "ull_conn_iso_types.h"
#include "ull_internal.h"
#include "ull_conn_types.h" #include "ull_conn_types.h"
#include "ull_llcp.h" #include "ull_llcp.h"
#include "ull_conn_internal.h" #include "ull_conn_internal.h"
@ -121,7 +120,7 @@ ZTEST(phy_central, test_phy_update_central_loc)
struct pdu_data_llctrl_phy_req req = { .rx_phys = PHY_2M, .tx_phys = PHY_2M }; struct pdu_data_llctrl_phy_req req = { .rx_phys = PHY_2M, .tx_phys = PHY_2M };
struct pdu_data_llctrl_phy_req rsp = { .rx_phys = PHY_1M | PHY_2M, struct pdu_data_llctrl_phy_req rsp = { .rx_phys = PHY_1M | PHY_2M,
.tx_phys = PHY_1M | PHY_2M }; .tx_phys = PHY_1M | PHY_2M };
struct pdu_data_llctrl_phy_upd_ind ind = { .instant = 8, struct pdu_data_llctrl_phy_upd_ind ind = { .instant = 7,
.c_to_p_phy = PHY_2M, .c_to_p_phy = PHY_2M,
.p_to_c_phy = PHY_2M }; .p_to_c_phy = PHY_2M };
struct pdu_data_llctrl_length_rsp length_ntf = { struct pdu_data_llctrl_length_rsp length_ntf = {
@ -145,13 +144,6 @@ ZTEST(phy_central, test_phy_update_central_loc)
err = ull_cp_phy_update(&conn, PHY_2M, PREFER_S8_CODING, PHY_2M, HOST_INITIATED); err = ull_cp_phy_update(&conn, PHY_2M, PREFER_S8_CODING, PHY_2M, HOST_INITIATED);
zassert_equal(err, BT_HCI_ERR_SUCCESS); zassert_equal(err, BT_HCI_ERR_SUCCESS);
/* Steal all ntf buffers, to trigger TX stall on non avail of NTF buffer for DLE */
while (ll_pdu_rx_alloc_peek(1)) {
ntf = ll_pdu_rx_alloc();
/* Make sure we use a correct type or the release won't work */
ntf->hdr.type = NODE_RX_TYPE_DC_PDU;
}
/* Prepare */ /* Prepare */
event_prepare(&conn); event_prepare(&conn);
@ -177,18 +169,6 @@ ZTEST(phy_central, test_phy_update_central_loc)
/* Prepare */ /* Prepare */
event_prepare(&conn); event_prepare(&conn);
/* No TX yet as unable to pre-allocate NTF buffer for DLE */
lt_rx_q_is_empty(&conn);
/* Done */
event_done(&conn);
/* Release RX node to now allow pre-alloc for DLE NTF */
release_ntf(ntf);
/* Prepare */
event_prepare(&conn);
/* Tx Queue should have one LL Control PDU */ /* Tx Queue should have one LL Control PDU */
lt_rx(LL_PHY_UPDATE_IND, &conn, &tx, &ind); lt_rx(LL_PHY_UPDATE_IND, &conn, &tx, &ind);
lt_rx_q_is_empty(&conn); lt_rx_q_is_empty(&conn);
@ -237,15 +217,11 @@ ZTEST(phy_central, test_phy_update_central_loc)
/* There should be two host notifications, one pu and one dle */ /* There should be two host notifications, one pu and one dle */
ut_rx_node(NODE_PHY_UPDATE, &ntf, &pu); ut_rx_node(NODE_PHY_UPDATE, &ntf, &pu);
/* Release Ntf */
release_ntf(ntf);
ut_rx_pdu(LL_LENGTH_RSP, &ntf, &length_ntf); ut_rx_pdu(LL_LENGTH_RSP, &ntf, &length_ntf);
/* Release Ntf */
release_ntf(ntf);
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */
ull_cp_release_ntf(ntf);
CHECK_CURRENT_PHY_STATE(conn, PHY_2M, PREFER_S8_CODING, PHY_2M); CHECK_CURRENT_PHY_STATE(conn, PHY_2M, PREFER_S8_CODING, PHY_2M);
CHECK_PREF_PHY_STATE(conn, PHY_2M, PHY_2M); CHECK_PREF_PHY_STATE(conn, PHY_2M, PHY_2M);
@ -342,18 +318,12 @@ ZTEST(phy_central, test_phy_update_central_loc_unsupp_feat)
/* Release Tx */ /* Release Tx */
ull_cp_release_tx(&conn, tx); ull_cp_release_tx(&conn, tx);
/* Prepare */
event_prepare(&conn);
/* Done */
event_done(&conn);
/* There should be one host notification */ /* There should be one host notification */
ut_rx_node(NODE_PHY_UPDATE, &ntf, &pu); ut_rx_node(NODE_PHY_UPDATE, &ntf, &pu);
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free()); "Free CTX buffers %d", llcp_ctx_buffers_free());
@ -365,7 +335,7 @@ ZTEST(phy_central, test_phy_update_central_rem)
struct node_rx_pdu *ntf; struct node_rx_pdu *ntf;
struct pdu_data *pdu; struct pdu_data *pdu;
struct pdu_data_llctrl_phy_req req = { .rx_phys = PHY_1M, .tx_phys = PHY_2M }; struct pdu_data_llctrl_phy_req req = { .rx_phys = PHY_1M, .tx_phys = PHY_2M };
struct pdu_data_llctrl_phy_upd_ind ind = { .instant = 8, struct pdu_data_llctrl_phy_upd_ind ind = { .instant = 7,
.c_to_p_phy = 0, .c_to_p_phy = 0,
.p_to_c_phy = PHY_2M }; .p_to_c_phy = PHY_2M };
uint16_t instant; uint16_t instant;
@ -378,13 +348,6 @@ ZTEST(phy_central, test_phy_update_central_rem)
/* Connect */ /* Connect */
ull_cp_state_set(&conn, ULL_CP_CONNECTED); ull_cp_state_set(&conn, ULL_CP_CONNECTED);
/* Steal all ntf buffers, to trigger TX stall on non avail of NTF buffer for DLE */
while (ll_pdu_rx_alloc_peek(1)) {
ntf = ll_pdu_rx_alloc();
/* Make sure we use a correct type or the release won't work */
ntf->hdr.type = NODE_RX_TYPE_DC_PDU;
}
/* Prepare */ /* Prepare */
event_prepare(&conn); event_prepare(&conn);
@ -397,18 +360,6 @@ ZTEST(phy_central, test_phy_update_central_rem)
/* Done */ /* Done */
event_done(&conn); event_done(&conn);
/* Prepare */
event_prepare(&conn);
/* No TX yet as unable to pre-allocate NTF buffer for DLE */
lt_rx_q_is_empty(&conn);
/* Done */
event_done(&conn);
/* Release RX node to now allow pre-alloc for DLE NTF */
release_ntf(ntf);
/* Check that data tx was paused */ /* Check that data tx was paused */
zassert_equal(conn.tx_q.pause_data, 1U, "Data tx is not paused"); zassert_equal(conn.tx_q.pause_data, 1U, "Data tx is not paused");
@ -464,7 +415,7 @@ ZTEST(phy_central, test_phy_update_central_rem)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
CHECK_CURRENT_PHY_STATE(conn, PHY_1M, PREFER_S8_CODING, PHY_2M); CHECK_CURRENT_PHY_STATE(conn, PHY_1M, PREFER_S8_CODING, PHY_2M);
CHECK_PREF_PHY_STATE(conn, PHY_1M | PHY_2M | PHY_CODED, PHY_1M | PHY_2M | PHY_CODED); CHECK_PREF_PHY_STATE(conn, PHY_1M | PHY_2M | PHY_CODED, PHY_1M | PHY_2M | PHY_CODED);
@ -553,7 +504,7 @@ ZTEST(phy_periph, test_phy_update_periph_loc)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
CHECK_CURRENT_PHY_STATE(conn, PHY_2M, PREFER_S8_CODING, PHY_2M); CHECK_CURRENT_PHY_STATE(conn, PHY_2M, PREFER_S8_CODING, PHY_2M);
CHECK_PREF_PHY_STATE(conn, PHY_2M, PHY_2M); CHECK_PREF_PHY_STATE(conn, PHY_2M, PHY_2M);
@ -651,7 +602,7 @@ ZTEST(phy_periph, test_phy_update_periph_rem)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
CHECK_CURRENT_PHY_STATE(conn, PHY_2M, PREFER_S8_CODING, PHY_1M); CHECK_CURRENT_PHY_STATE(conn, PHY_2M, PREFER_S8_CODING, PHY_1M);
CHECK_PREF_PHY_STATE(conn, PHY_1M | PHY_2M | PHY_CODED, PHY_1M | PHY_2M | PHY_CODED); CHECK_PREF_PHY_STATE(conn, PHY_1M | PHY_2M | PHY_CODED, PHY_1M | PHY_2M | PHY_CODED);
@ -700,18 +651,12 @@ ZTEST(phy_periph, test_phy_update_periph_loc_unsupp_feat)
/* Release Tx */ /* Release Tx */
ull_cp_release_tx(&conn, tx); ull_cp_release_tx(&conn, tx);
/* Prepare */
event_prepare(&conn);
/* Done */
event_done(&conn);
/* There should be one host notification */ /* There should be one host notification */
ut_rx_node(NODE_PHY_UPDATE, &ntf, &pu); ut_rx_node(NODE_PHY_UPDATE, &ntf, &pu);
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free()); "Free CTX buffers %d", llcp_ctx_buffers_free());
@ -936,7 +881,7 @@ ZTEST(phy_central, test_phy_update_central_loc_collision)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free()); "Free CTX buffers %d", llcp_ctx_buffers_free());
@ -1062,7 +1007,7 @@ ZTEST(phy_central, test_phy_update_central_rem_collision)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/* Prepare */ /* Prepare */
event_prepare(&conn); event_prepare(&conn);
@ -1113,7 +1058,7 @@ ZTEST(phy_central, test_phy_update_central_rem_collision)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free()); "Free CTX buffers %d", llcp_ctx_buffers_free());
@ -1183,19 +1128,13 @@ ZTEST(phy_periph, test_phy_update_periph_loc_collision)
/* Done */ /* Done */
event_done(&conn); event_done(&conn);
/* Prepare */
event_prepare(&conn);
/* Done */
event_done(&conn);
/* There should be one host notification */ /* There should be one host notification */
pu.status = BT_HCI_ERR_LL_PROC_COLLISION; pu.status = BT_HCI_ERR_LL_PROC_COLLISION;
ut_rx_node(NODE_PHY_UPDATE, &ntf, &pu); ut_rx_node(NODE_PHY_UPDATE, &ntf, &pu);
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
/* Prepare */ /* Prepare */
event_prepare(&conn); event_prepare(&conn);
@ -1243,7 +1182,7 @@ ZTEST(phy_periph, test_phy_update_periph_loc_collision)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free()); "Free CTX buffers %d", llcp_ctx_buffers_free());
@ -1326,7 +1265,7 @@ ZTEST(phy_central, test_phy_update_central_loc_no_act_change)
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
CHECK_CURRENT_PHY_STATE(conn, PHY_1M, PREFER_S8_CODING, PHY_1M); CHECK_CURRENT_PHY_STATE(conn, PHY_1M, PREFER_S8_CODING, PHY_1M);
CHECK_PREF_PHY_STATE(conn, PHY_1M, PHY_1M); CHECK_PREF_PHY_STATE(conn, PHY_1M, PHY_1M);
@ -1449,18 +1388,12 @@ ZTEST(phy_periph, test_phy_update_periph_loc_no_actual_change)
/* Done */ /* Done */
event_done(&conn); event_done(&conn);
/* Prepare */
event_prepare(&conn);
/* Done */
event_done(&conn);
/* There should be one notification due to Host initiated PHY UPD */ /* There should be one notification due to Host initiated PHY UPD */
ut_rx_node(NODE_PHY_UPDATE, &ntf, &pu); ut_rx_node(NODE_PHY_UPDATE, &ntf, &pu);
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Release Ntf */ /* Release Ntf */
release_ntf(ntf); ull_cp_release_ntf(ntf);
CHECK_CURRENT_PHY_STATE(conn, PHY_1M, PREFER_S8_CODING, PHY_1M); CHECK_CURRENT_PHY_STATE(conn, PHY_1M, PREFER_S8_CODING, PHY_1M);
CHECK_PREF_PHY_STATE(conn, PHY_1M, PHY_1M); CHECK_PREF_PHY_STATE(conn, PHY_1M, PHY_1M);
@ -1526,12 +1459,6 @@ ZTEST(phy_periph, test_phy_update_periph_rem_no_actual_change)
/* There should be no host notification */ /* There should be no host notification */
ut_rx_q_is_empty(); ut_rx_q_is_empty();
/* Prepare */
event_prepare(&conn);
/* Done */
event_done(&conn);
CHECK_CURRENT_PHY_STATE(conn, PHY_1M, PREFER_S8_CODING, PHY_1M); CHECK_CURRENT_PHY_STATE(conn, PHY_1M, PREFER_S8_CODING, PHY_1M);
CHECK_PREF_PHY_STATE(conn, PHY_1M | PHY_2M | PHY_CODED, PHY_1M | PHY_2M | PHY_CODED); CHECK_PREF_PHY_STATE(conn, PHY_1M | PHY_2M | PHY_CODED, PHY_1M | PHY_2M | PHY_CODED);

View file

@ -137,7 +137,6 @@ void ll_rx_mem_release(void **node_rx)
case NODE_RX_TYPE_ENC_REFRESH: case NODE_RX_TYPE_ENC_REFRESH:
case NODE_RX_TYPE_PHY_UPDATE: case NODE_RX_TYPE_PHY_UPDATE:
case NODE_RX_TYPE_CIS_REQUEST: case NODE_RX_TYPE_CIS_REQUEST:
case NODE_RX_TYPE_CIS_ESTABLISHED:
ll_rx_link_inc_quota(1); ll_rx_link_inc_quota(1);
mem_release(rx_free, &mem_pdu_rx.free); mem_release(rx_free, &mem_pdu_rx.free);
@ -180,10 +179,7 @@ void ll_rx_release(void *node_rx)
void ll_rx_put(memq_link_t *link, void *rx) void ll_rx_put(memq_link_t *link, void *rx)
{ {
if (((struct node_rx_hdr *)rx)->type != NODE_RX_TYPE_RELEASE) { sys_slist_append(&ut_rx_q, (sys_snode_t *)rx);
/* Only put/sched if node was not marked for release */
sys_slist_append(&ut_rx_q, (sys_snode_t *)rx);
}
} }
void ll_rx_sched(void) void ll_rx_sched(void)