Bluetooth: ISO: Add hcon for listening bis sk
authorIulia Tanasescu <iulia.tanasescu@nxp.com>
Fri, 23 Feb 2024 13:14:41 +0000 (15:14 +0200)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Wed, 6 Mar 2024 22:26:18 +0000 (17:26 -0500)
This creates a hcon instance at bis listen, before the PA sync
procedure is started.

Signed-off-by: Iulia Tanasescu <iulia.tanasescu@nxp.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
include/net/bluetooth/hci_core.h
net/bluetooth/hci_conn.c
net/bluetooth/iso.c

index 317d495..199a9f8 100644 (file)
@@ -1,7 +1,7 @@
 /*
    BlueZ - Bluetooth protocol stack for Linux
    Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved.
-   Copyright 2023 NXP
+   Copyright 2023-2024 NXP
 
    Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
 
@@ -1528,8 +1528,8 @@ struct hci_conn *hci_connect_cis(struct hci_dev *hdev, bdaddr_t *dst,
 struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst,
                                 __u8 dst_type, struct bt_iso_qos *qos,
                                 __u8 data_len, __u8 *data);
-int hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst, __u8 dst_type,
-                      __u8 sid, struct bt_iso_qos *qos);
+struct hci_conn *hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst,
+                      __u8 dst_type, __u8 sid, struct bt_iso_qos *qos);
 int hci_le_big_create_sync(struct hci_dev *hdev, struct hci_conn *hcon,
                           struct bt_iso_qos *qos,
                           __u16 sync_handle, __u8 num_bis, __u8 bis[]);
index 21e0b40..54d4189 100644 (file)
@@ -1,7 +1,7 @@
 /*
    BlueZ - Bluetooth protocol stack for Linux
    Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved.
-   Copyright 2023 NXP
+   Copyright 2023-2024 NXP
 
    Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
 
@@ -2057,18 +2057,31 @@ static int create_pa_sync(struct hci_dev *hdev, void *data)
        return hci_update_passive_scan_sync(hdev);
 }
 
-int hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst, __u8 dst_type,
-                      __u8 sid, struct bt_iso_qos *qos)
+struct hci_conn *hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst,
+                                   __u8 dst_type, __u8 sid,
+                                   struct bt_iso_qos *qos)
 {
        struct hci_cp_le_pa_create_sync *cp;
+       struct hci_conn *conn;
+       int err;
 
        if (hci_dev_test_and_set_flag(hdev, HCI_PA_SYNC))
-               return -EBUSY;
+               return ERR_PTR(-EBUSY);
+
+       conn = hci_conn_add_unset(hdev, ISO_LINK, dst, HCI_ROLE_SLAVE);
+       if (!conn)
+               return ERR_PTR(-ENOMEM);
+
+       conn->iso_qos = *qos;
+       conn->state = BT_LISTEN;
+
+       hci_conn_hold(conn);
 
        cp = kzalloc(sizeof(*cp), GFP_KERNEL);
        if (!cp) {
                hci_dev_clear_flag(hdev, HCI_PA_SYNC);
-               return -ENOMEM;
+               hci_conn_drop(conn);
+               return ERR_PTR(-ENOMEM);
        }
 
        cp->options = qos->bcast.options;
@@ -2080,7 +2093,14 @@ int hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst, __u8 dst_type,
        cp->sync_cte_type = qos->bcast.sync_cte_type;
 
        /* Queue start pa_create_sync and scan */
-       return hci_cmd_sync_queue(hdev, create_pa_sync, cp, create_pa_complete);
+       err = hci_cmd_sync_queue(hdev, create_pa_sync, cp, create_pa_complete);
+       if (err < 0) {
+               hci_conn_drop(conn);
+               kfree(cp);
+               return ERR_PTR(err);
+       }
+
+       return conn;
 }
 
 int hci_le_big_create_sync(struct hci_dev *hdev, struct hci_conn *hcon,
index 04f6572..d9ee69f 100644 (file)
@@ -3,7 +3,7 @@
  * BlueZ - Bluetooth protocol stack for Linux
  *
  * Copyright (C) 2022 Intel Corporation
- * Copyright 2023 NXP
+ * Copyright 2023-2024 NXP
  */
 
 #include <linux/module.h>
@@ -690,11 +690,8 @@ static void iso_sock_cleanup_listen(struct sock *parent)
                iso_sock_kill(sk);
        }
 
-       /* If listening socket stands for a PA sync connection,
-        * properly disconnect the hcon and socket.
-        */
-       if (iso_pi(parent)->conn && iso_pi(parent)->conn->hcon &&
-           test_bit(HCI_CONN_PA_SYNC, &iso_pi(parent)->conn->hcon->flags)) {
+       /* If listening socket has a hcon, properly disconnect it */
+       if (iso_pi(parent)->conn && iso_pi(parent)->conn->hcon) {
                iso_sock_disconn(parent);
                return;
        }
@@ -1076,6 +1073,8 @@ static int iso_listen_bis(struct sock *sk)
 {
        struct hci_dev *hdev;
        int err = 0;
+       struct iso_conn *conn;
+       struct hci_conn *hcon;
 
        BT_DBG("%pMR -> %pMR (SID 0x%2.2x)", &iso_pi(sk)->src,
               &iso_pi(sk)->dst, iso_pi(sk)->bc_sid);
@@ -1096,18 +1095,40 @@ static int iso_listen_bis(struct sock *sk)
        if (!hdev)
                return -EHOSTUNREACH;
 
+       hci_dev_lock(hdev);
+
        /* Fail if user set invalid QoS */
        if (iso_pi(sk)->qos_user_set && !check_bcast_qos(&iso_pi(sk)->qos)) {
                iso_pi(sk)->qos = default_qos;
-               return -EINVAL;
+               err = -EINVAL;
+               goto unlock;
        }
 
-       err = hci_pa_create_sync(hdev, &iso_pi(sk)->dst,
-                                le_addr_type(iso_pi(sk)->dst_type),
-                                iso_pi(sk)->bc_sid, &iso_pi(sk)->qos);
+       hcon = hci_pa_create_sync(hdev, &iso_pi(sk)->dst,
+                                 le_addr_type(iso_pi(sk)->dst_type),
+                                 iso_pi(sk)->bc_sid, &iso_pi(sk)->qos);
+       if (IS_ERR(hcon)) {
+               err = PTR_ERR(hcon);
+               goto unlock;
+       }
+
+       conn = iso_conn_add(hcon);
+       if (!conn) {
+               hci_conn_drop(hcon);
+               err = -ENOMEM;
+               goto unlock;
+       }
+
+       err = iso_chan_add(conn, sk, NULL);
+       if (err) {
+               hci_conn_drop(hcon);
+               goto unlock;
+       }
 
        hci_dev_put(hdev);
 
+unlock:
+       hci_dev_unlock(hdev);
        return err;
 }