diff --git a/subsys/bluetooth/controller/ll_sw/ull.c b/subsys/bluetooth/controller/ll_sw/ull.c index 48bd68277db..817cf388b59 100644 --- a/subsys/bluetooth/controller/ll_sw/ull.c +++ b/subsys/bluetooth/controller/ll_sw/ull.c @@ -72,6 +72,7 @@ #include "lll_conn_iso.h" #include "ull_conn_iso_types.h" #include "ull_central_iso_internal.h" +#include "ull_llcp.h" #include "ull_conn_iso_internal.h" #include "ull_peripheral_iso_internal.h" @@ -2781,6 +2782,25 @@ static inline int rx_demux_rx(memq_link_t *link, struct node_rx_hdr *rx) #endif /* CONFIG_BT_CTLR_ADV_EXT */ #endif /* CONFIG_BT_OBSERVER */ +#if !defined(CONFIG_BT_LL_SW_LLCP_LEGACY) && \ + defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) + case NODE_RX_TYPE_CIS_ESTABLISHED: + { + struct ll_conn *conn; + + (void)memq_dequeue(memq_ull_rx.tail, &memq_ull_rx.head, NULL); + + conn = ll_conn_get(rx->handle); + if (ull_cp_cc_awaiting_established(conn)) { + ull_cp_cc_established(conn, BT_HCI_ERR_SUCCESS); + } + + rx->type = NODE_RX_TYPE_RELEASE; + ll_rx_put_sched(link, rx); + } + break; +#endif /* !CONFIG_BT_LL_SW_LLCP_LEGACY && CONFIG_BT_CTLR_PERIPHERAL_ISO */ + #if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) || defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) || \ defined(CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT) case NODE_RX_TYPE_SYNC_IQ_SAMPLE_REPORT: diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c b/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c index e4f24cabd2f..310c35a6bd6 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c @@ -36,6 +36,7 @@ #include "ull_conn_iso_internal.h" #include "ull_peripheral_iso_internal.h" #include "ull_internal.h" +#include "ull_llcp.h" #include "lll/lll_vendor.h" #include "ll.h" @@ -258,8 +259,6 @@ uint8_t ll_conn_iso_accept_timeout_set(uint16_t timeout) void ull_conn_iso_cis_established(struct ll_conn_iso_stream *cis) { -#if defined(CONFIG_BT_LL_SW_LLCP_LEGACY) - struct node_rx_conn_iso_estab *est; struct node_rx_pdu *node_rx; node_rx = ull_pdu_rx_alloc(); @@ -268,8 +267,12 @@ void ull_conn_iso_cis_established(struct ll_conn_iso_stream *cis) return; } - /* TODO: Send CIS_ESTABLISHED with status != 0 in error scenarios */ node_rx->hdr.type = NODE_RX_TYPE_CIS_ESTABLISHED; + +#if defined(CONFIG_BT_LL_SW_LLCP_LEGACY) + struct node_rx_conn_iso_estab *est; + + /* TODO: Send CIS_ESTABLISHED with status != 0 in error scenarios */ node_rx->hdr.handle = 0xFFFF; node_rx->hdr.rx_ftr.param = cis; @@ -277,6 +280,11 @@ void ull_conn_iso_cis_established(struct ll_conn_iso_stream *cis) est->status = 0; est->cis_handle = cis->lll.handle; + ll_rx_put_sched(node_rx->hdr.link, node_rx); +#else + /* Send node to ULL RX demuxer for triggering LLCP state machine */ + node_rx->hdr.handle = cis->lll.acl_handle; + ll_rx_put_sched(node_rx->hdr.link, node_rx); #endif /* defined(CONFIG_BT_LL_SW_LLCP_LEGACY) */ @@ -332,7 +340,11 @@ void ull_conn_iso_done(struct node_rx_event_done *done) } if (--cis->event_expire == 0) { - /* Stop CIS and defer cleanup to after teardown. */ + /* Stop CIS and defer cleanup to after teardown. This will + * only generate a terminate event to the host if CIS has + * been established. If CIS was not established, the + * teardown will send CIS_ESTABLISHED with failure. + */ ull_conn_iso_cis_stop(cis, NULL, cis->established ? BT_HCI_ERR_CONN_TIMEOUT : @@ -835,6 +847,7 @@ static void cis_disabled_cb(void *param) struct ll_conn_iso_group *cig; struct ll_conn_iso_stream *cis; uint32_t ticker_status; + struct ll_conn *conn; uint16_t handle_iter; uint8_t is_last_cis; uint8_t cis_idx; @@ -850,7 +863,6 @@ static void cis_disabled_cb(void *param) if (cis->lll.flushed) { ll_iso_stream_released_cb_t cis_released_cb; - struct ll_conn *conn; conn = ll_conn_get(cis->lll.acl_handle); cis_released_cb = cis->released_cb; @@ -883,16 +895,25 @@ static void cis_disabled_cb(void *param) struct node_rx_pdu *node_terminate; uint32_t ret; - /* Create and enqueue termination node. This shall prevent - * further enqueuing of TX nodes for terminating CIS. - */ - node_terminate = ull_pdu_rx_alloc(); - LL_ASSERT(node_terminate); - node_terminate->hdr.handle = cis->lll.handle; - node_terminate->hdr.type = NODE_RX_TYPE_TERMINATE; - *((uint8_t *)node_terminate->pdu) = cis->terminate_reason; + if (cis->established) { + /* Create and enqueue termination node. This shall prevent + * further enqueuing of TX nodes for terminating CIS. + */ + node_terminate = ull_pdu_rx_alloc(); + LL_ASSERT(node_terminate); + node_terminate->hdr.handle = cis->lll.handle; + node_terminate->hdr.type = NODE_RX_TYPE_TERMINATE; + *((uint8_t *)node_terminate->pdu) = cis->terminate_reason; - ll_rx_put_sched(node_terminate->hdr.link, node_terminate); + ll_rx_put_sched(node_terminate->hdr.link, node_terminate); + } else { + conn = ll_conn_get(cis->lll.acl_handle); + + /* CIS was not established - complete the procedure with error */ + if (ull_cp_cc_awaiting_established(conn)) { + ull_cp_cc_established(conn, cis->terminate_reason); + } + } if (cig->lll.resume_cis == cis->lll.handle) { /* Resume pending for terminating CIS - stop ticker */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp.c b/subsys/bluetooth/controller/ll_sw/ull_llcp.c index 8d57c1698d7..33f79af9ef5 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp.c @@ -1230,6 +1230,7 @@ void ull_cp_cte_req_set_disable(struct ll_conn *conn) conn->llcp.cte_req.req_interval = 0U; } #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ + #if defined(CONFIG_BT_PERIPHERAL) && defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) bool ull_cp_cc_awaiting_reply(struct ll_conn *conn) { @@ -1276,7 +1277,50 @@ void ull_cp_cc_reject(struct ll_conn *conn, uint8_t error_code) llcp_rp_cc_reject(conn, ctx); } } -#endif /* defined(CONFIG_BT_PERIPHERAL) && defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) */ +#endif /* CONFIG_BT_PERIPHERAL && CONFIG_BT_CTLR_PERIPHERAL_ISO */ + +#if defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) || defined(CONFIG_BT_CTLR_CENTRAL_ISO) +bool ull_cp_cc_awaiting_established(struct ll_conn *conn) +{ + struct proc_ctx *ctx; + +#if defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) + ctx = llcp_rr_peek(conn); + if (ctx && ctx->proc == PROC_CIS_CREATE) { + return llcp_rp_cc_awaiting_established(ctx); + } +#endif /* CONFIG_BT_CTLR_PERIPHERAL_ISO */ + +#if defined(CONFIG_BT_CTLR_CENTRAL_ISO) + ctx = llcp_lr_peek(conn); + if (ctx && ctx->proc == PROC_CIS_CREATE) { + return llcp_lp_cc_awaiting_established(ctx); + } +#endif /* CONFIG_BT_CTLR_CENTRAL_ISO */ + return false; +} + +void ull_cp_cc_established(struct ll_conn *conn, uint8_t error_code) +{ + struct proc_ctx *ctx; + +#if defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) + ctx = llcp_rr_peek(conn); + if (ctx && ctx->proc == PROC_CIS_CREATE) { + ctx->data.cis_create.error = error_code; + llcp_rp_cc_established(conn, ctx); + } +#endif /* CONFIG_BT_CTLR_PERIPHERAL_ISO */ + +#if defined(CONFIG_BT_CTLR_CENTRAL_ISO) + ctx = llcp_lr_peek(conn); + if (ctx && ctx->proc == PROC_CIS_CREATE) { + ctx->data.cis_create.error = error_code; + llcp_lp_cc_established(conn, ctx); + } +#endif /* CONFIG_BT_CTLR_CENTRAL_ISO */ +} +#endif /* CONFIG_BT_CTLR_PERIPHERAL_ISO || CONFIG_BT_CTLR_CENTRAL_ISO */ #if defined(CONFIG_BT_CENTRAL) && defined(CONFIG_BT_CTLR_CENTRAL_ISO) bool ull_lp_cc_is_active(struct ll_conn *conn) diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp.h b/subsys/bluetooth/controller/ll_sw/ull_llcp.h index 27f84616138..a264e0297f3 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp.h +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp.h @@ -191,6 +191,11 @@ uint8_t ull_cp_cis_create(struct ll_conn *conn, struct ll_conn_iso_stream *cis); */ bool ull_cp_cc_awaiting_reply(struct ll_conn *conn); +/** + * @brief Is ongoing create cis procedure expecting an established event? + */ +bool ull_cp_cc_awaiting_established(struct ll_conn *conn); + /** * @brief Get handle of ongoing create cis procedure. * @return 0xFFFF if none @@ -203,7 +208,7 @@ uint16_t ull_cp_cc_ongoing_handle(struct ll_conn *conn); void ull_cp_cc_accept(struct ll_conn *conn); /** - * @brief Rejset the remote device’s request to create cis. + * @brief Reject the remote device’s request to create cis. */ void ull_cp_cc_reject(struct ll_conn *conn, uint8_t error_code); diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_cc.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_cc.c index fa46947d7c3..dc05a8649b9 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_cc.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_cc.c @@ -127,6 +127,9 @@ enum { /* Reject response received */ RP_CC_EVT_REJECT, + /* Established */ + RP_CC_EVT_CIS_ESTABLISHED, + /* Unknown response received */ RP_CC_EVT_UNKNOWN, }; @@ -433,7 +436,6 @@ static void rp_cc_state_wait_ntf_cis_create(struct ll_conn *conn, struct proc_ct } } - static void rp_cc_state_wait_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { @@ -535,6 +537,10 @@ static void rp_cc_state_wait_cis_established(struct ll_conn *conn, struct proc_c rp_cc_complete(conn, ctx, evt, param); } break; + case RP_CC_EVT_CIS_ESTABLISHED: + /* CIS was established, so let's go ahead and complete procedure */ + rp_cc_complete(conn, ctx, evt, param); + break; default: /* Ignore other evts */ break; @@ -623,6 +629,11 @@ bool llcp_rp_cc_awaiting_reply(struct proc_ctx *ctx) return (ctx->state == RP_CC_STATE_WAIT_REPLY); } +bool llcp_rp_cc_awaiting_established(struct proc_ctx *ctx) +{ + return (ctx->state == RP_CC_STATE_WAIT_CIS_ESTABLISHED); +} + void llcp_rp_cc_accept(struct ll_conn *conn, struct proc_ctx *ctx) { rp_cc_execute_fsm(conn, ctx, RP_CC_EVT_CIS_REQ_ACCEPT, NULL); @@ -642,6 +653,11 @@ bool llcp_rp_cc_awaiting_instant(struct proc_ctx *ctx) { return (ctx->state == RP_CC_STATE_WAIT_INSTANT); } + +void llcp_rp_cc_established(struct ll_conn *conn, struct proc_ctx *ctx) +{ + rp_cc_execute_fsm(conn, ctx, RP_CC_EVT_CIS_ESTABLISHED, NULL); +} #endif /* CONFIG_BT_PERIPHERAL */ #if defined(CONFIG_BT_CTLR_CENTRAL_ISO) @@ -669,6 +685,9 @@ enum { /* Reject response received */ LP_CC_EVT_REJECT, + /* CIS established */ + LP_CC_EVT_ESTABLISHED, + /* Unknown response received */ LP_CC_EVT_UNKNOWN, }; @@ -898,6 +917,10 @@ static void lp_cc_st_wait_established(struct ll_conn *conn, struct proc_ctx *ctx lp_cc_complete(conn, ctx, evt, param); } break; + case LP_CC_EVT_ESTABLISHED: + /* CIS was established, so let's go ahead and complete procedure */ + lp_cc_complete(conn, ctx, evt, param); + break; default: /* Ignore other evts */ break; @@ -956,4 +979,14 @@ bool llcp_lp_cc_is_active(struct proc_ctx *ctx) { return ctx->state != LP_CC_STATE_IDLE; } + +bool llcp_lp_cc_awaiting_established(struct proc_ctx *ctx) +{ + return (ctx->state == LP_CC_STATE_WAIT_ESTABLISHED); +} + +void llcp_lp_cc_established(struct ll_conn *conn, struct proc_ctx *ctx) +{ + lp_cc_execute_fsm(conn, ctx, LP_CC_EVT_ESTABLISHED, NULL); +} #endif /* CONFIG_BT_CTLR_CENTRAL_ISO */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h b/subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h index dfe2460c2d6..489eb6b569b 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h @@ -711,14 +711,18 @@ void llcp_lp_cc_init_proc(struct proc_ctx *ctx); void llcp_lp_cc_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pdu *rx); void llcp_lp_cc_run(struct ll_conn *conn, struct proc_ctx *ctx, void *param); bool llcp_lp_cc_is_active(struct proc_ctx *ctx); +bool llcp_lp_cc_awaiting_established(struct proc_ctx *ctx); +void llcp_lp_cc_established(struct ll_conn *conn, struct proc_ctx *ctx); void llcp_rp_cc_init_proc(struct proc_ctx *ctx); void llcp_rp_cc_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pdu *rx); void llcp_rp_cc_run(struct ll_conn *conn, struct proc_ctx *ctx, void *param); bool llcp_rp_cc_awaiting_reply(struct proc_ctx *ctx); +bool llcp_rp_cc_awaiting_established(struct proc_ctx *ctx); void llcp_rp_cc_accept(struct ll_conn *conn, struct proc_ctx *ctx); void llcp_rp_cc_reject(struct ll_conn *conn, struct proc_ctx *ctx); bool llcp_rp_cc_awaiting_instant(struct proc_ctx *ctx); +void llcp_rp_cc_established(struct ll_conn *conn, struct proc_ctx *ctx); void llcp_pdu_decode_cis_req(struct proc_ctx *ctx, struct pdu_data *pdu); void llcp_pdu_encode_cis_rsp(struct proc_ctx *ctx, struct pdu_data *pdu);