Bluetooth: controller: Send disconnect complete when CIS is terminated
Previously the host would handle disconnecting associated CISes and invoking callbacks when a host ACL conn was disconnected. This responsibility has now been moved to the controller, which needs to send a NODE_RX_TYPE_TERMINATE with the CIS handle for proper disconnection in the host. This is in accordance with the spec. As disconnect reason, the CIS uses the ACL reason, which is passed to the host along with the handle. Signed-off-by: Morten Priess <mtpr@oticon.com>
This commit is contained in:
parent
57ca5298b3
commit
cd470da214
6 changed files with 44 additions and 16 deletions
|
@ -1403,18 +1403,20 @@ void ll_rx_mem_release(void **node_rx)
|
||||||
#if defined(CONFIG_BT_CONN)
|
#if defined(CONFIG_BT_CONN)
|
||||||
case NODE_RX_TYPE_TERMINATE:
|
case NODE_RX_TYPE_TERMINATE:
|
||||||
{
|
{
|
||||||
struct ll_conn *conn;
|
if (IS_ACL_HANDLE(rx_free->handle)) {
|
||||||
memq_link_t *link;
|
struct ll_conn *conn;
|
||||||
|
memq_link_t *link;
|
||||||
|
|
||||||
conn = ll_conn_get(rx_free->handle);
|
conn = ll_conn_get(rx_free->handle);
|
||||||
|
|
||||||
LL_ASSERT(!conn->lll.link_tx_free);
|
LL_ASSERT(!conn->lll.link_tx_free);
|
||||||
link = memq_deinit(&conn->lll.memq_tx.head,
|
link = memq_deinit(&conn->lll.memq_tx.head,
|
||||||
&conn->lll.memq_tx.tail);
|
&conn->lll.memq_tx.tail);
|
||||||
LL_ASSERT(link);
|
LL_ASSERT(link);
|
||||||
conn->lll.link_tx_free = link;
|
conn->lll.link_tx_free = link;
|
||||||
|
|
||||||
ll_conn_release(conn);
|
ll_conn_release(conn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif /* CONFIG_BT_CONN */
|
#endif /* CONFIG_BT_CONN */
|
||||||
|
|
|
@ -1961,8 +1961,15 @@ static void conn_cleanup_iso_cis_released_cb(struct ll_conn *conn)
|
||||||
|
|
||||||
cis = ll_conn_iso_stream_get_by_acl(conn, NULL);
|
cis = ll_conn_iso_stream_get_by_acl(conn, NULL);
|
||||||
if (cis) {
|
if (cis) {
|
||||||
|
struct node_rx_pdu *rx;
|
||||||
|
uint8_t reason;
|
||||||
|
|
||||||
/* More associated CISes - stop next */
|
/* More associated CISes - stop next */
|
||||||
ull_conn_iso_cis_stop(cis, conn_cleanup_iso_cis_released_cb);
|
rx = (void *)&conn->llcp_terminate.node_rx;
|
||||||
|
reason = *(uint8_t *)rx->pdu;
|
||||||
|
|
||||||
|
ull_conn_iso_cis_stop(cis, conn_cleanup_iso_cis_released_cb,
|
||||||
|
reason);
|
||||||
} else {
|
} else {
|
||||||
/* No more CISes associated with conn - finalize */
|
/* No more CISes associated with conn - finalize */
|
||||||
conn_cleanup_finalize(conn);
|
conn_cleanup_finalize(conn);
|
||||||
|
@ -2038,7 +2045,8 @@ static void conn_cleanup(struct ll_conn *conn, uint8_t reason)
|
||||||
cis = ll_conn_iso_stream_get_by_acl(conn, NULL);
|
cis = ll_conn_iso_stream_get_by_acl(conn, NULL);
|
||||||
if (cis) {
|
if (cis) {
|
||||||
/* Stop CIS and defer cleanup to after teardown. */
|
/* Stop CIS and defer cleanup to after teardown. */
|
||||||
ull_conn_iso_cis_stop(cis, conn_cleanup_iso_cis_released_cb);
|
ull_conn_iso_cis_stop(cis, conn_cleanup_iso_cis_released_cb,
|
||||||
|
reason);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_BT_CTLR_PERIPHERAL_ISO || CONFIG_BT_CTLR_CENTRAL_ISO */
|
#endif /* CONFIG_BT_CTLR_PERIPHERAL_ISO || CONFIG_BT_CTLR_CENTRAL_ISO */
|
||||||
|
|
|
@ -274,9 +274,11 @@ void ull_conn_iso_done(struct node_rx_event_done *done)
|
||||||
* @param cis Pointer to connected ISO stream to stop
|
* @param cis Pointer to connected ISO stream to stop
|
||||||
* @param cis_relased_cb Callback to invoke when the CIS has been released.
|
* @param cis_relased_cb Callback to invoke when the CIS has been released.
|
||||||
* NULL to ignore.
|
* NULL to ignore.
|
||||||
|
* @param reason Termination reason
|
||||||
*/
|
*/
|
||||||
void ull_conn_iso_cis_stop(struct ll_conn_iso_stream *cis,
|
void ull_conn_iso_cis_stop(struct ll_conn_iso_stream *cis,
|
||||||
ll_iso_stream_released_cb_t cis_released_cb)
|
ll_iso_stream_released_cb_t cis_released_cb,
|
||||||
|
uint8_t reason)
|
||||||
{
|
{
|
||||||
struct ll_conn_iso_group *cig;
|
struct ll_conn_iso_group *cig;
|
||||||
struct ull_hdr *hdr;
|
struct ull_hdr *hdr;
|
||||||
|
@ -287,6 +289,7 @@ void ull_conn_iso_cis_stop(struct ll_conn_iso_stream *cis,
|
||||||
}
|
}
|
||||||
cis->teardown = 1;
|
cis->teardown = 1;
|
||||||
cis->released_cb = cis_released_cb;
|
cis->released_cb = cis_released_cb;
|
||||||
|
cis->terminate_reason = reason;
|
||||||
|
|
||||||
/* Check ref count to determine if any pending LLL events in pipeline */
|
/* Check ref count to determine if any pending LLL events in pipeline */
|
||||||
cig = cis->group;
|
cig = cis->group;
|
||||||
|
@ -486,12 +489,23 @@ static void cis_disabled_cb(void *param)
|
||||||
LL_ASSERT(cis);
|
LL_ASSERT(cis);
|
||||||
|
|
||||||
if (cis->teardown) {
|
if (cis->teardown) {
|
||||||
struct ll_conn *conn;
|
|
||||||
ll_iso_stream_released_cb_t cis_released_cb;
|
ll_iso_stream_released_cb_t cis_released_cb;
|
||||||
|
struct node_rx_pdu *node_terminate;
|
||||||
|
struct ll_conn *conn;
|
||||||
|
|
||||||
conn = ll_conn_get(cis->lll.acl_handle);
|
conn = ll_conn_get(cis->lll.acl_handle);
|
||||||
cis_released_cb = cis->released_cb;
|
cis_released_cb = cis->released_cb;
|
||||||
|
|
||||||
|
/* Create and enqueue termination node */
|
||||||
|
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(node_terminate->hdr.link, node_terminate);
|
||||||
|
ll_rx_sched();
|
||||||
|
|
||||||
ll_conn_iso_stream_release(cis);
|
ll_conn_iso_stream_release(cis);
|
||||||
cig->lll.num_cis--;
|
cig->lll.num_cis--;
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,8 @@ struct ll_conn_iso_stream *ll_conn_iso_stream_get_by_group(struct ll_conn_iso_gr
|
||||||
void ull_conn_iso_done(struct node_rx_event_done *done);
|
void ull_conn_iso_done(struct node_rx_event_done *done);
|
||||||
void ull_conn_iso_cis_established(struct ll_conn_iso_stream *cis);
|
void ull_conn_iso_cis_established(struct ll_conn_iso_stream *cis);
|
||||||
void ull_conn_iso_cis_stop(struct ll_conn_iso_stream *cis,
|
void ull_conn_iso_cis_stop(struct ll_conn_iso_stream *cis,
|
||||||
ll_iso_stream_released_cb_t cis_released_cb);
|
ll_iso_stream_released_cb_t cis_released_cb,
|
||||||
|
uint8_t reason);
|
||||||
|
|
||||||
void ull_conn_iso_resume_ticker_start(struct lll_event *resume_event,
|
void ull_conn_iso_resume_ticker_start(struct lll_event *resume_event,
|
||||||
uint16_t cis_handle,
|
uint16_t cis_handle,
|
||||||
|
|
|
@ -8,9 +8,9 @@ struct ll_conn;
|
||||||
|
|
||||||
typedef void (*ll_iso_stream_released_cb_t)(struct ll_conn *conn);
|
typedef void (*ll_iso_stream_released_cb_t)(struct ll_conn *conn);
|
||||||
|
|
||||||
#define LL_CIS_HANDLE_BASE CONFIG_BT_MAX_CONN
|
#define LL_CIS_HANDLE_BASE CONFIG_BT_MAX_CONN
|
||||||
|
|
||||||
#define LL_CIS_IDX_FROM_HANDLE(_handle) \
|
#define LL_CIS_IDX_FROM_HANDLE(_handle) \
|
||||||
((_handle) - LL_CIS_HANDLE_BASE)
|
((_handle) - LL_CIS_HANDLE_BASE)
|
||||||
|
|
||||||
struct ll_conn_iso_stream {
|
struct ll_conn_iso_stream {
|
||||||
|
@ -18,6 +18,7 @@ struct ll_conn_iso_stream {
|
||||||
struct lll_conn_iso_stream lll;
|
struct lll_conn_iso_stream lll;
|
||||||
uint32_t sync_delay;
|
uint32_t sync_delay;
|
||||||
uint8_t cis_id;
|
uint8_t cis_id;
|
||||||
|
uint8_t terminate_reason;
|
||||||
struct ll_iso_datapath *datapath_in;
|
struct ll_iso_datapath *datapath_in;
|
||||||
struct ll_iso_datapath *datapath_out;
|
struct ll_iso_datapath *datapath_out;
|
||||||
uint32_t offset; /* Offset of CIS from ACL event in us */
|
uint32_t offset; /* Offset of CIS from ACL event in us */
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define IS_ACL_HANDLE(_handle) ((_handle) < CONFIG_BT_MAX_CONN)
|
||||||
|
|
||||||
enum llcp {
|
enum llcp {
|
||||||
LLCP_NONE,
|
LLCP_NONE,
|
||||||
LLCP_CONN_UPD,
|
LLCP_CONN_UPD,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue