Skip to content

Commit 11dc486

Browse files
iulia-tanasescugregkh
authored andcommitted
Bluetooth: ISO: Reassociate a socket with an active BIS
[ Upstream commit fa224d0 ] For ISO Broadcast, all BISes from a BIG have the same lifespan - they cannot be created or terminated independently from each other. This links together all BIS hcons that are part of the same BIG, so all hcons are kept alive as long as the BIG is active. If multiple BIS sockets are opened for a BIG handle, and only part of them are closed at some point, the associated hcons will be marked as open. If new sockets will later be opened for the same BIG, they will be reassociated with the open BIS hcons. All BIS hcons will be cleaned up and the BIG will be terminated when the last BIS socket is closed from userspace. Signed-off-by: Iulia Tanasescu <[email protected]> Signed-off-by: Luiz Augusto von Dentz <[email protected]> Stable-dep-of: 581dd2d ("Bluetooth: hci_event: Fix using rcu_read_(un)lock while iterating") Signed-off-by: Sasha Levin <[email protected]>
1 parent 81c4b95 commit 11dc486

File tree

3 files changed

+131
-4
lines changed

3 files changed

+131
-4
lines changed

include/net/bluetooth/hci_core.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,6 +1294,30 @@ static inline struct hci_conn *hci_conn_hash_lookup_big_any_dst(struct hci_dev *
12941294
return NULL;
12951295
}
12961296

1297+
static inline struct hci_conn *
1298+
hci_conn_hash_lookup_big_state(struct hci_dev *hdev, __u8 handle, __u16 state)
1299+
{
1300+
struct hci_conn_hash *h = &hdev->conn_hash;
1301+
struct hci_conn *c;
1302+
1303+
rcu_read_lock();
1304+
1305+
list_for_each_entry_rcu(c, &h->list, list) {
1306+
if (bacmp(&c->dst, BDADDR_ANY) || c->type != ISO_LINK ||
1307+
c->state != state)
1308+
continue;
1309+
1310+
if (handle == c->iso_qos.bcast.big) {
1311+
rcu_read_unlock();
1312+
return c;
1313+
}
1314+
}
1315+
1316+
rcu_read_unlock();
1317+
1318+
return NULL;
1319+
}
1320+
12971321
static inline struct hci_conn *
12981322
hci_conn_hash_lookup_pa_sync_big_handle(struct hci_dev *hdev, __u8 big)
12991323
{

net/bluetooth/hci_conn.c

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,8 +1054,9 @@ static void hci_conn_cleanup_child(struct hci_conn *conn, u8 reason)
10541054
hci_conn_failed(conn, reason);
10551055
break;
10561056
case ISO_LINK:
1057-
if (conn->state != BT_CONNECTED &&
1058-
!test_bit(HCI_CONN_CREATE_CIS, &conn->flags))
1057+
if ((conn->state != BT_CONNECTED &&
1058+
!test_bit(HCI_CONN_CREATE_CIS, &conn->flags)) ||
1059+
test_bit(HCI_CONN_BIG_CREATED, &conn->flags))
10591060
hci_conn_failed(conn, reason);
10601061
break;
10611062
}
@@ -2134,7 +2135,17 @@ struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst,
21342135
__u8 base_len, __u8 *base)
21352136
{
21362137
struct hci_conn *conn;
2138+
struct hci_conn *parent;
21372139
__u8 eir[HCI_MAX_PER_AD_LENGTH];
2140+
struct hci_link *link;
2141+
2142+
/* Look for any BIS that is open for rebinding */
2143+
conn = hci_conn_hash_lookup_big_state(hdev, qos->bcast.big, BT_OPEN);
2144+
if (conn) {
2145+
memcpy(qos, &conn->iso_qos, sizeof(*qos));
2146+
conn->state = BT_CONNECTED;
2147+
return conn;
2148+
}
21382149

21392150
if (base_len && base)
21402151
base_len = eir_append_service_data(eir, 0, 0x1851,
@@ -2162,6 +2173,20 @@ struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst,
21622173
conn->iso_qos = *qos;
21632174
conn->state = BT_BOUND;
21642175

2176+
/* Link BISes together */
2177+
parent = hci_conn_hash_lookup_big(hdev,
2178+
conn->iso_qos.bcast.big);
2179+
if (parent && parent != conn) {
2180+
link = hci_conn_link(parent, conn);
2181+
if (!link) {
2182+
hci_conn_drop(conn);
2183+
return ERR_PTR(-ENOLINK);
2184+
}
2185+
2186+
/* Link takes the refcount */
2187+
hci_conn_drop(conn);
2188+
}
2189+
21652190
return conn;
21662191
}
21672192

@@ -2193,6 +2218,9 @@ struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst,
21932218
if (IS_ERR(conn))
21942219
return conn;
21952220

2221+
if (conn->state == BT_CONNECTED)
2222+
return conn;
2223+
21962224
data.big = qos->bcast.big;
21972225
data.bis = qos->bcast.bis;
21982226

net/bluetooth/iso.c

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -612,19 +612,68 @@ static struct sock *iso_get_sock_listen(bdaddr_t *src, bdaddr_t *dst,
612612
continue;
613613

614614
/* Exact match. */
615-
if (!bacmp(&iso_pi(sk)->src, src))
615+
if (!bacmp(&iso_pi(sk)->src, src)) {
616+
sock_hold(sk);
616617
break;
618+
}
617619

618620
/* Closest match */
619-
if (!bacmp(&iso_pi(sk)->src, BDADDR_ANY))
621+
if (!bacmp(&iso_pi(sk)->src, BDADDR_ANY)) {
622+
if (sk1)
623+
sock_put(sk1);
624+
620625
sk1 = sk;
626+
sock_hold(sk1);
627+
}
621628
}
622629

630+
if (sk && sk1)
631+
sock_put(sk1);
632+
623633
read_unlock(&iso_sk_list.lock);
624634

625635
return sk ? sk : sk1;
626636
}
627637

638+
static struct sock *iso_get_sock_big(struct sock *match_sk, bdaddr_t *src,
639+
bdaddr_t *dst, uint8_t big)
640+
{
641+
struct sock *sk = NULL;
642+
643+
read_lock(&iso_sk_list.lock);
644+
645+
sk_for_each(sk, &iso_sk_list.head) {
646+
if (match_sk == sk)
647+
continue;
648+
649+
/* Look for sockets that have already been
650+
* connected to the BIG
651+
*/
652+
if (sk->sk_state != BT_CONNECTED &&
653+
sk->sk_state != BT_CONNECT)
654+
continue;
655+
656+
/* Match Broadcast destination */
657+
if (bacmp(&iso_pi(sk)->dst, dst))
658+
continue;
659+
660+
/* Match BIG handle */
661+
if (iso_pi(sk)->qos.bcast.big != big)
662+
continue;
663+
664+
/* Match source address */
665+
if (bacmp(&iso_pi(sk)->src, src))
666+
continue;
667+
668+
sock_hold(sk);
669+
break;
670+
}
671+
672+
read_unlock(&iso_sk_list.lock);
673+
674+
return sk;
675+
}
676+
628677
static void iso_sock_destruct(struct sock *sk)
629678
{
630679
BT_DBG("sk %p", sk);
@@ -677,6 +726,28 @@ static void iso_sock_kill(struct sock *sk)
677726

678727
static void iso_sock_disconn(struct sock *sk)
679728
{
729+
struct sock *bis_sk;
730+
struct hci_conn *hcon = iso_pi(sk)->conn->hcon;
731+
732+
if (test_bit(HCI_CONN_BIG_CREATED, &hcon->flags)) {
733+
bis_sk = iso_get_sock_big(sk, &iso_pi(sk)->src,
734+
&iso_pi(sk)->dst,
735+
iso_pi(sk)->qos.bcast.big);
736+
737+
/* If there are any other connected sockets for the
738+
* same BIG, just delete the sk and leave the bis
739+
* hcon active, in case later rebinding is needed.
740+
*/
741+
if (bis_sk) {
742+
hcon->state = BT_OPEN;
743+
iso_pi(sk)->conn->hcon = NULL;
744+
iso_sock_clear_timer(sk);
745+
iso_chan_del(sk, bt_to_errno(hcon->abort_reason));
746+
sock_put(bis_sk);
747+
return;
748+
}
749+
}
750+
680751
sk->sk_state = BT_DISCONN;
681752
iso_sock_set_timer(sk, ISO_DISCONN_TIMEOUT);
682753
iso_conn_lock(iso_pi(sk)->conn);
@@ -1724,6 +1795,7 @@ static void iso_conn_ready(struct iso_conn *conn)
17241795
parent->sk_data_ready(parent);
17251796

17261797
release_sock(parent);
1798+
sock_put(parent);
17271799
}
17281800
}
17291801

@@ -1819,6 +1891,7 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
18191891
if (err) {
18201892
bt_dev_err(hdev, "hci_le_big_create_sync: %d",
18211893
err);
1894+
sock_put(sk);
18221895
sk = NULL;
18231896
}
18241897
}
@@ -1847,6 +1920,8 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
18471920
if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags))
18481921
*flags |= HCI_PROTO_DEFER;
18491922

1923+
sock_put(sk);
1924+
18501925
return lm;
18511926
}
18521927

0 commit comments

Comments
 (0)