summaryrefslogtreecommitdiff
path: root/net/bluetooth/hci_conn.c
diff options
context:
space:
mode:
authorIulia Tanasescu <iulia.tanasescu@nxp.com>2023-11-13 17:38:00 +0200
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>2023-12-22 12:53:29 -0500
commitfa224d0c094a458e9ebf5ea9b1c696136b7af427 (patch)
treec2d4599b441bc4b11b9e774ed75a8fef173a70ed /net/bluetooth/hci_conn.c
parent80837140c1f2c05d566b49181785bced3ab6140e (diff)
Bluetooth: ISO: Reassociate a socket with an active BIS
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 <iulia.tanasescu@nxp.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Diffstat (limited to 'net/bluetooth/hci_conn.c')
-rw-r--r--net/bluetooth/hci_conn.c32
1 files changed, 30 insertions, 2 deletions
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 2cee330188ce..a09071059214 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -1086,8 +1086,9 @@ static void hci_conn_cleanup_child(struct hci_conn *conn, u8 reason)
hci_conn_failed(conn, reason);
break;
case ISO_LINK:
- if (conn->state != BT_CONNECTED &&
- !test_bit(HCI_CONN_CREATE_CIS, &conn->flags))
+ if ((conn->state != BT_CONNECTED &&
+ !test_bit(HCI_CONN_CREATE_CIS, &conn->flags)) ||
+ test_bit(HCI_CONN_BIG_CREATED, &conn->flags))
hci_conn_failed(conn, reason);
break;
}
@@ -2228,7 +2229,17 @@ struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst,
__u8 base_len, __u8 *base)
{
struct hci_conn *conn;
+ struct hci_conn *parent;
__u8 eir[HCI_MAX_PER_AD_LENGTH];
+ struct hci_link *link;
+
+ /* Look for any BIS that is open for rebinding */
+ conn = hci_conn_hash_lookup_big_state(hdev, qos->bcast.big, BT_OPEN);
+ if (conn) {
+ memcpy(qos, &conn->iso_qos, sizeof(*qos));
+ conn->state = BT_CONNECTED;
+ return conn;
+ }
if (base_len && base)
base_len = eir_append_service_data(eir, 0, 0x1851,
@@ -2256,6 +2267,20 @@ struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst,
conn->iso_qos = *qos;
conn->state = BT_BOUND;
+ /* Link BISes together */
+ parent = hci_conn_hash_lookup_big(hdev,
+ conn->iso_qos.bcast.big);
+ if (parent && parent != conn) {
+ link = hci_conn_link(parent, conn);
+ if (!link) {
+ hci_conn_drop(conn);
+ return ERR_PTR(-ENOLINK);
+ }
+
+ /* Link takes the refcount */
+ hci_conn_drop(conn);
+ }
+
return conn;
}
@@ -2287,6 +2312,9 @@ struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst,
if (IS_ERR(conn))
return conn;
+ if (conn->state == BT_CONNECTED)
+ return conn;
+
data.big = qos->bcast.big;
data.bis = qos->bcast.bis;