// SPDX-License-Identifier: GPL-2.0/* * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2022 Intel Corporation * Copyright 2023-2024 NXP */ #include <linux/module.h>#include <linux/debugfs.h>#include <linux/seq_file.h>#include <linux/sched/signal.h>#include <linux/uio.h> #include <net/bluetooth/bluetooth.h>#include <net/bluetooth/hci_core.h>#include <net/bluetooth/iso.h>#include "eir.h" static const struct proto_ops iso_sock_ops; static struct bt_sock_list iso_sk_list = { .lock = __RW_LOCK_UNLOCKED(iso_sk_list.lock)}; /* ---- ISO connections ---- */enum { ISO_CONN_DROPPED, __ISO_CONN_NUM_FLAGS}; struct iso_conn { struct hci_conn *hcon; DECLARE_BITMAP(flags, __ISO_CONN_NUM_FLAGS); /* @lock: spinlock protecting changes to iso_conn fields */ spinlock_t lock; struct sock *sk; struct sk_buff *rx_skb; __u32 rx_len; __u16 tx_sn; struct kref ref;}; #define iso_conn_lock(c) spin_lock(&(c)->lock)#define iso_conn_unlock(c) spin_unlock(&(c)->lock) static void iso_sock_close(struct sock *sk);static void iso_sock_kill(struct sock *sk); /* ----- ISO socket info ----- */#define iso_pi(sk) ((struct iso_pinfo *)sk) #define EIR_SERVICE_DATA_LENGTH 4#define BASE_MAX_LENGTH (HCI_MAX_PER_AD_LENGTH - EIR_SERVICE_DATA_LENGTH)#define EIR_BAA_SERVICE_UUID 0x1851 /* iso_pinfo flags values */enum { BT_SK_BIG_SYNC, BT_SK_PA_SYNC, BT_SK_KILLED,}; struct iso_pinfo { struct bt_sock bt; bdaddr_t src; __u8 src_type; bdaddr_t dst; __u8 dst_type; __u8 bc_sid; __u8 bc_num_bis; __u8 bc_bis[ISO_MAX_NUM_BIS]; __u16 sync_handle; unsigned long flags; struct bt_iso_qos qos; bool qos_user_set; __u8 base_len; __u8 base[BASE_MAX_LENGTH]; struct iso_conn *conn; struct delayed_work timeout_work;}; static struct bt_iso_qos default_qos; static bool check_ucast_qos(struct bt_iso_qos *qos);static bool check_bcast_qos(struct bt_iso_qos *qos);static bool iso_match_sid(struct sock *sk, void *data);static bool iso_match_sid_past(struct sock *sk, void *data);static bool iso_match_sync_handle(struct sock *sk, void *data);static bool iso_match_sync_handle_pa_report(struct sock *sk, void *data);static void iso_sock_disconn(struct sock *sk); typedef bool (*iso_sock_match_t)(struct sock *sk, void *data); static struct sock *iso_get_sock(struct hci_dev *hdev, bdaddr_t *src, bdaddr_t *dst, enum bt_sock_state state, iso_sock_match_t match, void *data); /* ---- ISO timers ---- */#define ISO_CONN_TIMEOUT secs_to_jiffies(20)#define ISO_DISCONN_TIMEOUT secs_to_jiffies(2) static void iso_conn_free(struct kref *ref){ struct iso_conn *conn = container_of(ref, struct iso_conn, ref); BT_DBG("conn %p", conn); if (conn->hcon) { spin_lock(&conn->hcon->proto_lock); /* Check we are not racing with iso_conn_add */ if (conn->hcon->iso_data == conn) { conn->hcon->iso_data = NULL; if (!test_and_set_bit(ISO_CONN_DROPPED, conn->flags)) hci_conn_drop(conn->hcon); } spin_unlock(&conn->hcon->proto_lock); } kfree_skb(conn->rx_skb); kfree(conn);} static void iso_conn_put(struct iso_conn *conn){ if (!conn) return; BT_DBG("conn %p refcnt %d", conn, kref_read(&conn->ref)); /* The following race vs. iso_conn_del() is possible: * * 1. conn->hcon != NULL here * 2. kref_put puts the last reference * 3. concurrent iso_conn_del() gets iso_conn_hold_unless_zero() -> NULL * and returns immediately, so conn->hcon is not cleared * 4. iso_conn_free() dereferences conn->hcon * * To avoid UAF in step 4, take RCU before decrementing the refcount. */ rcu_read_lock(); kref_put(&conn->ref, iso_conn_free); rcu_read_unlock();} static struct iso_conn *iso_conn_hold_unless_zero(struct iso_conn *conn){ if (!conn) return NULL; BT_DBG("conn %p refcnt %u", conn, kref_read(&conn->ref)); if (!kref_get_unless_zero(&conn->ref)) return NULL; return conn;} static struct iso_conn *iso_conn_hold(struct iso_conn *conn){ BT_DBG("conn %p refcnt %u", conn, kref_read(&conn->ref)); kref_get(&conn->ref); return conn;} static struct sock *iso_sock_hold(struct iso_conn *conn){ if (!conn || !bt_sock_linked(&iso_sk_list, conn->sk)) return NULL; sock_hold(conn->sk); return conn->sk;} static void iso_sock_timeout(struct work_struct *work){ struct iso_pinfo *pi = container_of(work, struct iso_pinfo, timeout_work.work); struct sock *sk = &pi->bt.sk; BT_DBG("sock %p state %d", sk, sk->sk_state); lock_sock(sk); if (!sock_flag(sk, SOCK_ZAPPED)) { sk->sk_err = ETIMEDOUT; sk->sk_state_change(sk); } release_sock(sk);} static void iso_sock_set_timer(struct sock *sk, long timeout){ lockdep_assert(lockdep_sock_is_held(sk)); cancel_delayed_work(&iso_pi(sk)->timeout_work); if (!iso_pi(sk)->conn) return; BT_DBG("sock %p state %d timeout %ld", sk, sk->sk_state, timeout); schedule_delayed_work(&iso_pi(sk)->timeout_work, timeout);} static void iso_sock_clear_timer(struct sock *sk){ BT_DBG("sock %p state %d", sk, sk->sk_state); cancel_delayed_work(&iso_pi(sk)->timeout_work);} static void iso_sock_disable_timer(struct sock *sk){ lockdep_assert(!lockdep_sock_is_held(sk)); BT_DBG("sock %p state %d", sk, sk->sk_state); disable_delayed_work_sync(&iso_pi(sk)->timeout_work);} /* ---- ISO connections ---- */static struct iso_conn *iso_conn_add(struct hci_conn *hcon) __must_hold(&hcon->hdev->lock){ struct iso_conn *conn; spin_lock(&hcon->proto_lock); conn = iso_conn_hold_unless_zero(hcon->iso_data); if (conn) { if (!conn->hcon) { iso_conn_lock(conn); conn->hcon = hcon; iso_conn_unlock(conn); } spin_unlock(&hcon->proto_lock); return conn; } conn = kzalloc_obj(*conn, GFP_ATOMIC); if (!conn) { spin_unlock(&hcon->proto_lock); return NULL; } kref_init(&conn->ref); spin_lock_init(&conn->lock); hcon->iso_data = conn; conn->hcon = hcon; conn->tx_sn = 0; spin_unlock(&hcon->proto_lock); BT_DBG("hcon %p conn %p", hcon, conn); return conn;} /* Delete channel. Must be called on the locked socket. */static void iso_chan_del(struct sock *sk, int err){ struct iso_conn *conn; struct sock *parent; conn = iso_pi(sk)->conn; iso_pi(sk)->conn = NULL; BT_DBG("sk %p, conn %p, err %d", sk, conn, err); if (conn) { iso_conn_lock(conn); conn->sk = NULL; iso_conn_unlock(conn); iso_conn_put(conn); } sk->sk_state = BT_CLOSED; sk->sk_err = err; parent = bt_sk(sk)->parent; if (parent) { bt_accept_unlink(sk); parent->sk_data_ready(parent); } else { sk->sk_state_change(sk); } sock_set_flag(sk, SOCK_ZAPPED);} static void iso_conn_del(struct hci_conn *hcon, int err) __must_hold(&hcon->hdev->lock){ struct iso_conn *conn; struct sock *sk; spin_lock(&hcon->proto_lock); conn = iso_conn_hold_unless_zero(hcon->iso_data); spin_unlock(&hcon->proto_lock); if (!conn) return; BT_DBG("hcon %p conn %p, err %d", hcon, conn, err); /* Kill socket */ iso_conn_lock(conn); sk = iso_sock_hold(conn); iso_conn_unlock(conn); if (!sk) goto done; iso_sock_disable_timer(sk); lock_sock(sk); iso_chan_del(sk, err); release_sock(sk); iso_sock_kill(sk); sock_put(sk); done: /* No sk access to conn->hcon any more (lock_sock + hdev->lock) */ spin_lock(&hcon->proto_lock); iso_conn_lock(conn); conn->hcon = NULL; hcon->iso_data = NULL; iso_conn_unlock(conn); spin_unlock(&hcon->proto_lock); iso_conn_put(conn);} static int __iso_chan_add(struct iso_conn *conn, struct sock *sk, struct sock *parent){ BT_DBG("conn %p", conn); if (iso_pi(sk)->conn == conn && conn->sk == sk) return 0; if (conn->sk) { BT_ERR("conn->sk already set"); return -EBUSY; } if (!conn->hcon) { BT_ERR("conn->hcon missing"); return -EIO; } iso_pi(sk)->conn = iso_conn_hold(conn); conn->sk = sk; clear_bit(ISO_CONN_DROPPED, conn->flags); if (parent) bt_accept_enqueue(parent, sk, true); return 0;} static int iso_chan_add(struct iso_conn *conn, struct sock *sk, struct sock *parent){ int err; iso_conn_lock(conn); err = __iso_chan_add(conn, sk, parent); iso_conn_unlock(conn); return err;} static inline u8 le_addr_type(u8 bdaddr_type){ if (bdaddr_type == BDADDR_LE_PUBLIC) return ADDR_LE_DEV_PUBLIC; else return ADDR_LE_DEV_RANDOM;} static int iso_connect_bis(struct sock *sk){ struct iso_conn *conn; struct hci_conn *hcon; struct hci_dev *hdev; bdaddr_t src, dst; u8 src_type, bc_sid; int err; lock_sock(sk); bacpy(&src, &iso_pi(sk)->src); bacpy(&dst, &iso_pi(sk)->dst); src_type = iso_pi(sk)->src_type; bc_sid = iso_pi(sk)->bc_sid; release_sock(sk); BT_DBG("%pMR (SID 0x%2.2x)", &src, bc_sid); hdev = hci_get_route(&dst, &src, src_type); if (!hdev) return -EHOSTUNREACH; hci_dev_lock(hdev); lock_sock(sk); if (!bis_capable(hdev)) { err = -EOPNOTSUPP; goto unlock; } /* 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; err = -EINVAL; goto unlock; } /* Fail if out PHYs are marked as disabled */ if (!iso_pi(sk)->qos.bcast.out.phys) { err = -EINVAL; goto unlock; } /* Just bind if DEFER_SETUP has been set */ if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) { hcon = hci_bind_bis(hdev, &iso_pi(sk)->dst, iso_pi(sk)->bc_sid, &iso_pi(sk)->qos, iso_pi(sk)->base_len, iso_pi(sk)->base, READ_ONCE(sk->sk_sndtimeo)); if (IS_ERR(hcon)) { err = PTR_ERR(hcon); goto unlock; } } else { hcon = hci_connect_bis(hdev, &iso_pi(sk)->dst, le_addr_type(iso_pi(sk)->dst_type), iso_pi(sk)->bc_sid, &iso_pi(sk)->qos, iso_pi(sk)->base_len, iso_pi(sk)->base, READ_ONCE(sk->sk_sndtimeo)); if (IS_ERR(hcon)) { err = PTR_ERR(hcon); goto unlock; } /* Update SID if it was not set */ if (iso_pi(sk)->bc_sid == HCI_SID_INVALID) iso_pi(sk)->bc_sid = hcon->sid; } lockdep_assert_held(&hcon->hdev->lock); conn = iso_conn_add(hcon); if (!conn) { hci_conn_drop(hcon); err = -ENOMEM; goto unlock; } err = iso_chan_add(conn, sk, NULL); iso_conn_put(conn); if (err) goto unlock; /* Update source addr of the socket */ bacpy(&iso_pi(sk)->src, &hcon->src); if (hcon->state == BT_CONNECTED) { iso_sock_clear_timer(sk); sk->sk_state = BT_CONNECTED; } else if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) { iso_sock_clear_timer(sk); sk->sk_state = BT_CONNECT; } else { sk->sk_state = BT_CONNECT; iso_sock_set_timer(sk, READ_ONCE(sk->sk_sndtimeo)); } unlock: release_sock(sk); hci_dev_unlock(hdev); hci_dev_put(hdev); return err;} static int iso_connect_cis(struct sock *sk){ struct iso_conn *conn; struct hci_conn *hcon; struct hci_dev *hdev; bdaddr_t src, dst; u8 src_type; int err; Lines 1–500 of 2934. Load more
// SPDX-License-Identifier: GPL-2.0 /* * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2022 Intel Corporation * Copyright 2023-2024 NXP */ #include <linux/module.h> #include <linux/debugfs.h> #include <linux/seq_file.h> #include <linux/sched/signal.h> #include <linux/uio.h> #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> #include <net/bluetooth/iso.h> #include "eir.h" static const struct proto_ops iso_sock_ops; static struct bt_sock_list iso_sk_list = { .lock = __RW_LOCK_UNLOCKED(iso_sk_list.lock) }; /* ---- ISO connections ---- */ enum { ISO_CONN_DROPPED, __ISO_CONN_NUM_FLAGS }; struct iso_conn { struct hci_conn *hcon; DECLARE_BITMAP(flags, __ISO_CONN_NUM_FLAGS); /* @lock: spinlock protecting changes to iso_conn fields */ spinlock_t lock; struct sock *sk; struct sk_buff *rx_skb; __u32 rx_len; __u16 tx_sn; struct kref ref; }; #define iso_conn_lock(c) spin_lock(&(c)->lock) #define iso_conn_unlock(c) spin_unlock(&(c)->lock) static void iso_sock_close(struct sock *sk); static void iso_sock_kill(struct sock *sk); /* ----- ISO socket info ----- */ #define iso_pi(sk) ((struct iso_pinfo *)sk) #define EIR_SERVICE_DATA_LENGTH 4 #define BASE_MAX_LENGTH (HCI_MAX_PER_AD_LENGTH - EIR_SERVICE_DATA_LENGTH) #define EIR_BAA_SERVICE_UUID 0x1851 /* iso_pinfo flags values */ enum { BT_SK_BIG_SYNC, BT_SK_PA_SYNC, BT_SK_KILLED, }; struct iso_pinfo { struct bt_sock bt; bdaddr_t src; __u8 src_type; bdaddr_t dst; __u8 dst_type; __u8 bc_sid; __u8 bc_num_bis; __u8 bc_bis[ISO_MAX_NUM_BIS]; __u16 sync_handle; unsigned long flags; struct bt_iso_qos qos; bool qos_user_set; __u8 base_len; __u8 base[BASE_MAX_LENGTH]; struct iso_conn *conn; struct delayed_work timeout_work; }; static struct bt_iso_qos default_qos; static bool check_ucast_qos(struct bt_iso_qos *qos); static bool check_bcast_qos(struct bt_iso_qos *qos); static bool iso_match_sid(struct sock *sk, void *data); static bool iso_match_sid_past(struct sock *sk, void *data); static bool iso_match_sync_handle(struct sock *sk, void *data); static bool iso_match_sync_handle_pa_report(struct sock *sk, void *data); static void iso_sock_disconn(struct sock *sk); typedef bool (*iso_sock_match_t)(struct sock *sk, void *data); static struct sock *iso_get_sock(struct hci_dev *hdev, bdaddr_t *src, bdaddr_t *dst, enum bt_sock_state state, iso_sock_match_t match, void *data); /* ---- ISO timers ---- */ #define ISO_CONN_TIMEOUT secs_to_jiffies(20) #define ISO_DISCONN_TIMEOUT secs_to_jiffies(2) static void iso_conn_free(struct kref *ref) { struct iso_conn *conn = container_of(ref, struct iso_conn, ref); BT_DBG("conn %p", conn); if (conn->hcon) { spin_lock(&conn->hcon->proto_lock); /* Check we are not racing with iso_conn_add */ if (conn->hcon->iso_data == conn) { conn->hcon->iso_data = NULL; if (!test_and_set_bit(ISO_CONN_DROPPED, conn->flags)) hci_conn_drop(conn->hcon); } spin_unlock(&conn->hcon->proto_lock); } kfree_skb(conn->rx_skb); kfree(conn); } static void iso_conn_put(struct iso_conn *conn) { if (!conn) return; BT_DBG("conn %p refcnt %d", conn, kref_read(&conn->ref)); /* The following race vs. iso_conn_del() is possible: * * 1. conn->hcon != NULL here * 2. kref_put puts the last reference * 3. concurrent iso_conn_del() gets iso_conn_hold_unless_zero() -> NULL * and returns immediately, so conn->hcon is not cleared * 4. iso_conn_free() dereferences conn->hcon * * To avoid UAF in step 4, take RCU before decrementing the refcount. */ rcu_read_lock(); kref_put(&conn->ref, iso_conn_free); rcu_read_unlock(); } static struct iso_conn *iso_conn_hold_unless_zero(struct iso_conn *conn) { if (!conn) return NULL; BT_DBG("conn %p refcnt %u", conn, kref_read(&conn->ref)); if (!kref_get_unless_zero(&conn->ref)) return NULL; return conn; } static struct iso_conn *iso_conn_hold(struct iso_conn *conn) { BT_DBG("conn %p refcnt %u", conn, kref_read(&conn->ref)); kref_get(&conn->ref); return conn; } static struct sock *iso_sock_hold(struct iso_conn *conn) { if (!conn || !bt_sock_linked(&iso_sk_list, conn->sk)) return NULL; sock_hold(conn->sk); return conn->sk; } static void iso_sock_timeout(struct work_struct *work) { struct iso_pinfo *pi = container_of(work, struct iso_pinfo, timeout_work.work); struct sock *sk = &pi->bt.sk; BT_DBG("sock %p state %d", sk, sk->sk_state); lock_sock(sk); if (!sock_flag(sk, SOCK_ZAPPED)) { sk->sk_err = ETIMEDOUT; sk->sk_state_change(sk); } release_sock(sk); } static void iso_sock_set_timer(struct sock *sk, long timeout) { lockdep_assert(lockdep_sock_is_held(sk)); cancel_delayed_work(&iso_pi(sk)->timeout_work); if (!iso_pi(sk)->conn) return; BT_DBG("sock %p state %d timeout %ld", sk, sk->sk_state, timeout); schedule_delayed_work(&iso_pi(sk)->timeout_work, timeout); } static void iso_sock_clear_timer(struct sock *sk) { BT_DBG("sock %p state %d", sk, sk->sk_state); cancel_delayed_work(&iso_pi(sk)->timeout_work); } static void iso_sock_disable_timer(struct sock *sk) { lockdep_assert(!lockdep_sock_is_held(sk)); BT_DBG("sock %p state %d", sk, sk->sk_state); disable_delayed_work_sync(&iso_pi(sk)->timeout_work); } /* ---- ISO connections ---- */ static struct iso_conn *iso_conn_add(struct hci_conn *hcon) __must_hold(&hcon->hdev->lock) { struct iso_conn *conn; spin_lock(&hcon->proto_lock); conn = iso_conn_hold_unless_zero(hcon->iso_data); if (conn) { if (!conn->hcon) { iso_conn_lock(conn); conn->hcon = hcon; iso_conn_unlock(conn); } spin_unlock(&hcon->proto_lock); return conn; } conn = kzalloc_obj(*conn, GFP_ATOMIC); if (!conn) { spin_unlock(&hcon->proto_lock); return NULL; } kref_init(&conn->ref); spin_lock_init(&conn->lock); hcon->iso_data = conn; conn->hcon = hcon; conn->tx_sn = 0; spin_unlock(&hcon->proto_lock); BT_DBG("hcon %p conn %p", hcon, conn); return conn; } /* Delete channel. Must be called on the locked socket. */ static void iso_chan_del(struct sock *sk, int err) { struct iso_conn *conn; struct sock *parent; conn = iso_pi(sk)->conn; iso_pi(sk)->conn = NULL; BT_DBG("sk %p, conn %p, err %d", sk, conn, err); if (conn) { iso_conn_lock(conn); conn->sk = NULL; iso_conn_unlock(conn); iso_conn_put(conn); } sk->sk_state = BT_CLOSED; sk->sk_err = err; parent = bt_sk(sk)->parent; if (parent) { bt_accept_unlink(sk); parent->sk_data_ready(parent); } else { sk->sk_state_change(sk); } sock_set_flag(sk, SOCK_ZAPPED); } static void iso_conn_del(struct hci_conn *hcon, int err) __must_hold(&hcon->hdev->lock) { struct iso_conn *conn; struct sock *sk; spin_lock(&hcon->proto_lock); conn = iso_conn_hold_unless_zero(hcon->iso_data); spin_unlock(&hcon->proto_lock); if (!conn) return; BT_DBG("hcon %p conn %p, err %d", hcon, conn, err); /* Kill socket */ iso_conn_lock(conn); sk = iso_sock_hold(conn); iso_conn_unlock(conn); if (!sk) goto done; iso_sock_disable_timer(sk); lock_sock(sk); iso_chan_del(sk, err); release_sock(sk); iso_sock_kill(sk); sock_put(sk); done: /* No sk access to conn->hcon any more (lock_sock + hdev->lock) */ spin_lock(&hcon->proto_lock); iso_conn_lock(conn); conn->hcon = NULL; hcon->iso_data = NULL; iso_conn_unlock(conn); spin_unlock(&hcon->proto_lock); iso_conn_put(conn); } static int __iso_chan_add(struct iso_conn *conn, struct sock *sk, struct sock *parent) { BT_DBG("conn %p", conn); if (iso_pi(sk)->conn == conn && conn->sk == sk) return 0; if (conn->sk) { BT_ERR("conn->sk already set"); return -EBUSY; } if (!conn->hcon) { BT_ERR("conn->hcon missing"); return -EIO; } iso_pi(sk)->conn = iso_conn_hold(conn); conn->sk = sk; clear_bit(ISO_CONN_DROPPED, conn->flags); if (parent) bt_accept_enqueue(parent, sk, true); return 0; } static int iso_chan_add(struct iso_conn *conn, struct sock *sk, struct sock *parent) { int err; iso_conn_lock(conn); err = __iso_chan_add(conn, sk, parent); iso_conn_unlock(conn); return err; } static inline u8 le_addr_type(u8 bdaddr_type) { if (bdaddr_type == BDADDR_LE_PUBLIC) return ADDR_LE_DEV_PUBLIC; else return ADDR_LE_DEV_RANDOM; } static int iso_connect_bis(struct sock *sk) { struct iso_conn *conn; struct hci_conn *hcon; struct hci_dev *hdev; bdaddr_t src, dst; u8 src_type, bc_sid; int err; lock_sock(sk); bacpy(&src, &iso_pi(sk)->src); bacpy(&dst, &iso_pi(sk)->dst); src_type = iso_pi(sk)->src_type; bc_sid = iso_pi(sk)->bc_sid; release_sock(sk); BT_DBG("%pMR (SID 0x%2.2x)", &src, bc_sid); hdev = hci_get_route(&dst, &src, src_type); if (!hdev) return -EHOSTUNREACH; hci_dev_lock(hdev); lock_sock(sk); if (!bis_capable(hdev)) { err = -EOPNOTSUPP; goto unlock; } /* 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; err = -EINVAL; goto unlock; } /* Fail if out PHYs are marked as disabled */ if (!iso_pi(sk)->qos.bcast.out.phys) { err = -EINVAL; goto unlock; } /* Just bind if DEFER_SETUP has been set */ if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) { hcon = hci_bind_bis(hdev, &iso_pi(sk)->dst, iso_pi(sk)->bc_sid, &iso_pi(sk)->qos, iso_pi(sk)->base_len, iso_pi(sk)->base, READ_ONCE(sk->sk_sndtimeo)); if (IS_ERR(hcon)) { err = PTR_ERR(hcon); goto unlock; } } else { hcon = hci_connect_bis(hdev, &iso_pi(sk)->dst, le_addr_type(iso_pi(sk)->dst_type), iso_pi(sk)->bc_sid, &iso_pi(sk)->qos, iso_pi(sk)->base_len, iso_pi(sk)->base, READ_ONCE(sk->sk_sndtimeo)); if (IS_ERR(hcon)) { err = PTR_ERR(hcon); goto unlock; } /* Update SID if it was not set */ if (iso_pi(sk)->bc_sid == HCI_SID_INVALID) iso_pi(sk)->bc_sid = hcon->sid; } lockdep_assert_held(&hcon->hdev->lock); conn = iso_conn_add(hcon); if (!conn) { hci_conn_drop(hcon); err = -ENOMEM; goto unlock; } err = iso_chan_add(conn, sk, NULL); iso_conn_put(conn); if (err) goto unlock; /* Update source addr of the socket */ bacpy(&iso_pi(sk)->src, &hcon->src); if (hcon->state == BT_CONNECTED) { iso_sock_clear_timer(sk); sk->sk_state = BT_CONNECTED; } else if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) { iso_sock_clear_timer(sk); sk->sk_state = BT_CONNECT; } else { sk->sk_state = BT_CONNECT; iso_sock_set_timer(sk, READ_ONCE(sk->sk_sndtimeo)); } unlock: release_sock(sk); hci_dev_unlock(hdev); hci_dev_put(hdev); return err; } static int iso_connect_cis(struct sock *sk) { struct iso_conn *conn; struct hci_conn *hcon; struct hci_dev *hdev; bdaddr_t src, dst; u8 src_type; int err;