Skip to content

Commit af0fc96

Browse files
Vudentznashif
authored andcommitted
Bluetooth: ISO: Fix cleanup connection
This fixes bt_iso_cleanup when there are still channels bound to the ACL connection. On top of it introduce bt_iso_chan_unbind which can be used to unbind channels and thus release the reference to the ACL connection if that has not been disconnected in which case the channels are unbind automatically. Signed-off-by: Luiz Augusto von Dentz <[email protected]>
1 parent 7ffbd55 commit af0fc96

File tree

2 files changed

+77
-30
lines changed

2 files changed

+77
-30
lines changed

include/bluetooth/iso.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,20 @@ int bt_iso_server_register(struct bt_iso_server *server);
305305
int bt_iso_chan_bind(struct bt_conn **conns, uint8_t num_conns,
306306
struct bt_iso_chan **chans);
307307

308+
/** @brief Unbind ISO channel
309+
*
310+
* Unbind ISO channel from ACL connection, channel must be in BT_ISO_BOUND
311+
* state.
312+
*
313+
* Note: Channels which the ACL connection has been disconnected are unbind
314+
* automatically.
315+
*
316+
* @param chan Channel object.
317+
*
318+
* @return 0 in case of success or negative value in case of error.
319+
*/
320+
int bt_iso_chan_unbind(struct bt_iso_chan *chan);
321+
308322
/** @brief Connect ISO channels
309323
*
310324
* Connect ISO channels, once the connection is completed each channel

subsys/bluetooth/host/iso.c

Lines changed: 63 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -257,26 +257,43 @@ void bt_iso_cleanup(struct bt_conn *conn)
257257
{
258258
int i;
259259

260-
if (conn->iso.acl) { /* CIS */
261-
bt_conn_unref(conn->iso.acl);
262-
conn->iso.acl = NULL;
263-
264-
/* Check if conn is last of CIG */
265-
for (i = 0; i < CONFIG_BT_ISO_MAX_CHAN; i++) {
266-
if (conn == &iso_conns[i]) {
267-
continue;
268-
}
260+
__ASSERT_NO_MSG(conn->type == BT_CONN_TYPE_ISO);
269261

270-
if (atomic_get(&iso_conns[i].ref) &&
271-
iso_conns[i].iso.cig_id == conn->iso.cig_id) {
272-
break;
273-
}
262+
BT_DBG("%p", conn);
263+
264+
/* Check if ISO connection is in fact a BIS */
265+
if (!conn->iso.acl) {
266+
goto done;
267+
}
268+
269+
/* If ACL is still connected there are channels to serve that means the
270+
* connection is still in use.
271+
*/
272+
if (conn->iso.acl->state == BT_CONN_CONNECTED &&
273+
!sys_slist_is_empty(&conn->channels)) {
274+
goto done;
275+
}
276+
277+
bt_conn_unref(conn->iso.acl);
278+
conn->iso.acl = NULL;
279+
280+
/* Check if conn is last of CIG */
281+
for (i = 0; i < CONFIG_BT_ISO_MAX_CHAN; i++) {
282+
if (conn == &iso_conns[i]) {
283+
continue;
274284
}
275285

276-
if (i == CONFIG_BT_ISO_MAX_CHAN) {
277-
hci_le_remove_cig(conn->iso.cig_id);
286+
if (atomic_get(&iso_conns[i].ref) &&
287+
iso_conns[i].iso.cig_id == conn->iso.cig_id) {
288+
break;
278289
}
279290
}
291+
292+
if (i == CONFIG_BT_ISO_MAX_CHAN) {
293+
hci_le_remove_cig(conn->iso.cig_id);
294+
}
295+
296+
done:
280297
bt_conn_unref(conn);
281298
}
282299

@@ -734,23 +751,25 @@ static void bt_iso_remove_data_path(struct bt_conn *conn)
734751
hci_le_remove_iso_data_path(conn, BT_HCI_DATAPATH_DIR_HOST_TO_CTLR);
735752
}
736753

737-
static void bt_iso_chan_del(struct bt_iso_chan *chan)
754+
static void bt_iso_chan_disconnected(struct bt_iso_chan *chan)
738755
{
739756
BT_DBG("%p", chan);
740757

741758
if (!chan->conn) {
742-
goto done;
759+
bt_iso_chan_set_state(chan, BT_ISO_DISCONNECTED);
760+
return;
761+
}
762+
763+
bt_iso_chan_set_state(chan, BT_ISO_BOUND);
764+
765+
/* Unbind if acting as slave */
766+
if (chan->conn->role == BT_HCI_ROLE_SLAVE) {
767+
bt_iso_chan_unbind(chan);
743768
}
744769

745770
if (chan->ops->disconnected) {
746771
chan->ops->disconnected(chan);
747772
}
748-
749-
bt_conn_unref(chan->conn);
750-
chan->conn = NULL;
751-
752-
done:
753-
bt_iso_chan_set_state(chan, BT_ISO_DISCONNECTED);
754773
}
755774

756775
void bt_iso_disconnected(struct bt_conn *conn)
@@ -768,7 +787,7 @@ void bt_iso_disconnected(struct bt_conn *conn)
768787
bt_iso_remove_data_path(conn);
769788

770789
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&conn->channels, chan, next, node) {
771-
bt_iso_chan_del(chan);
790+
bt_iso_chan_disconnected(chan);
772791
}
773792
}
774793

@@ -832,12 +851,8 @@ void bt_iso_chan_set_state_debug(struct bt_iso_chan *chan, uint8_t state,
832851
/* check transitions validness */
833852
switch (state) {
834853
case BT_ISO_DISCONNECTED:
835-
/* regardless of old state always allows this state */
836-
break;
837854
case BT_ISO_BOUND:
838-
if (chan->state != BT_ISO_DISCONNECTED) {
839-
BT_WARN("%s()%d: invalid transition", func, line);
840-
}
855+
/* regardless of old state always allows these states */
841856
break;
842857
case BT_ISO_CONNECT:
843858
if (chan->state != BT_ISO_BOUND) {
@@ -916,6 +931,24 @@ int bt_iso_chan_bind(struct bt_conn **conns, uint8_t num_conns,
916931
return 0;
917932
}
918933

934+
int bt_iso_chan_unbind(struct bt_iso_chan *chan)
935+
{
936+
__ASSERT_NO_MSG(chan);
937+
938+
if (!chan->conn || chan->state != BT_ISO_BOUND) {
939+
return -EINVAL;
940+
}
941+
942+
bt_iso_chan_remove(chan->conn, chan);
943+
944+
bt_conn_unref(chan->conn);
945+
chan->conn = NULL;
946+
947+
bt_iso_chan_set_state(chan, BT_ISO_DISCONNECTED);
948+
949+
return 0;
950+
}
951+
919952
int bt_iso_chan_connect(struct bt_iso_chan **chans, uint8_t num_chans)
920953
{
921954
struct bt_conn *conns[CONFIG_BT_ISO_MAX_CHAN];
@@ -954,7 +987,7 @@ int bt_iso_chan_disconnect(struct bt_iso_chan *chan)
954987

955988
if (chan->state == BT_ISO_BOUND) {
956989
bt_iso_chan_remove(chan->conn, chan);
957-
bt_iso_chan_del(chan);
990+
bt_iso_chan_disconnected(chan);
958991
return 0;
959992
}
960993

0 commit comments

Comments
 (0)