Skip to content

Commit 109eb53

Browse files
committed
Bluetooth: ISO: Fix issue with BIS tx_complete
BIS termination as broadcaster is handled different than ACL and CIS, and in rare chances the tx_complete for BIS may not have been completed in the system workqueue before iso_new was called for the same bt_conn struct (e.g. via bt_iso_cig_create), which would perform k_work_init(&conn->tx_complete_work, tx_complete_work); but where conn->tx_complete_work still existed in the system workqueue, which would cause the list of pending items on the system workqueue to be removed as the `next` pointer would be NULL. This also adds an assert in bt_conn_new to prevent this issue from appearing again. Signed-off-by: Emil Gydesen <[email protected]>
1 parent 31ef45e commit 109eb53

File tree

4 files changed

+19
-2
lines changed

4 files changed

+19
-2
lines changed

subsys/bluetooth/host/conn.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,8 @@ struct bt_conn *bt_conn_new(struct bt_conn *conns, size_t size)
372372
k_work_init_delayable(&conn->deferred_work, deferred_work);
373373
#endif /* CONFIG_BT_CONN */
374374
#if defined(CONFIG_BT_CONN_TX)
375+
__ASSERT(!k_work_is_pending(&conn->tx_complete_work),
376+
"tx_complete_work is pending, performing k_work_init will break the workqueue");
375377
k_work_init(&conn->tx_complete_work, tx_complete_work);
376378
#endif /* CONFIG_BT_CONN_TX */
377379

subsys/bluetooth/host/iso.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,15 @@ static void bt_iso_chan_disconnected(struct bt_iso_chan *chan, uint8_t reason)
511511
}
512512
#endif /* CONFIG_BT_ISO_CENTRAL */
513513
}
514+
} else if (IS_ENABLED(CONFIG_BT_ISO_BROADCASTER) &&
515+
conn_type == BT_ISO_CHAN_TYPE_BROADCASTER) {
516+
/* BIS do not get a HCI Disconnected event and will not handle cleanup of pending TX
517+
* complete in the same way as ACL and CIS do. Call bt_conn_tx_notify directly here
518+
* to flush the chan->iso->tx_complete for each disconnected BIS
519+
*/
520+
bt_conn_tx_notify(chan->iso, true);
521+
} else {
522+
/* No special handling for BT_ISO_CHAN_TYPE_SYNC_RECEIVER */
514523
}
515524
}
516525

tests/bluetooth/host/conn/mocks/kernel.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
/*
2-
* Copyright (c) 2024 Nordic Semiconductor ASA
2+
* Copyright (c) 2024-2025 Nordic Semiconductor ASA
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
66

7+
#include <stdbool.h>
8+
9+
#include <zephyr/fff.h>
710
#include <zephyr/kernel.h>
811

912
#include "kernel.h"
@@ -22,6 +25,7 @@ DEFINE_FAKE_VALUE_FUNC(int, k_work_submit, struct k_work *);
2225
DEFINE_FAKE_VALUE_FUNC(int, k_work_submit_to_queue, struct k_work_q *, struct k_work *);
2326
DEFINE_FAKE_VALUE_FUNC(int, k_work_reschedule, struct k_work_delayable *, k_timeout_t);
2427
DEFINE_FAKE_VALUE_FUNC(int, k_work_schedule, struct k_work_delayable *, k_timeout_t);
28+
DEFINE_FAKE_VALUE_FUNC(int, k_work_busy_get, const struct k_work *);
2529
DEFINE_FAKE_VOID_FUNC(k_queue_init, struct k_queue *);
2630
DEFINE_FAKE_VOID_FUNC(k_queue_append, struct k_queue *, void *);
2731
DEFINE_FAKE_VALUE_FUNC(int, k_queue_is_empty, struct k_queue *);

tests/bluetooth/host/conn/mocks/kernel.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
/*
2-
* Copyright (c) 2024 Nordic Semiconductor ASA
2+
* Copyright (c) 2024-2025 Nordic Semiconductor ASA
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
6+
#include <stdbool.h>
67

78
#include <zephyr/kernel.h>
89
#include <zephyr/fff.h>
@@ -41,6 +42,7 @@ DECLARE_FAKE_VOID_FUNC(k_sem_give, struct k_sem *);
4142
DECLARE_FAKE_VALUE_FUNC(k_tid_t, k_sched_current_thread_query);
4243
DECLARE_FAKE_VOID_FUNC(k_work_init, struct k_work *, k_work_handler_t);
4344
DECLARE_FAKE_VOID_FUNC(k_work_init_delayable, struct k_work_delayable *, k_work_handler_t);
45+
DECLARE_FAKE_VALUE_FUNC(int, k_work_busy_get, const struct k_work *);
4446
DECLARE_FAKE_VALUE_FUNC(int, k_work_cancel_delayable, struct k_work_delayable *);
4547
DECLARE_FAKE_VALUE_FUNC(bool, k_work_flush, struct k_work *, struct k_work_sync *);
4648
DECLARE_FAKE_VALUE_FUNC(int, k_work_submit, struct k_work *);

0 commit comments

Comments
 (0)