diff options
Diffstat (limited to 'net/bluetooth/iso.c')
-rw-r--r-- | net/bluetooth/iso.c | 47 |
1 files changed, 33 insertions, 14 deletions
diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c index 16da946f5881..07b80e97aead 100644 --- a/net/bluetooth/iso.c +++ b/net/bluetooth/iso.c @@ -14,6 +14,7 @@ #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; @@ -47,6 +48,7 @@ static void iso_sock_kill(struct sock *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 { @@ -77,6 +79,7 @@ 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_sync_handle(struct sock *sk, void *data); static void iso_sock_disconn(struct sock *sk); /* ---- ISO timers ---- */ @@ -502,7 +505,7 @@ drop: } /* -------- Socket interface ---------- */ -static struct sock *__iso_get_sock_listen_by_addr(bdaddr_t *ba) +static struct sock *__iso_get_sock_listen_by_addr(bdaddr_t *src, bdaddr_t *dst) { struct sock *sk; @@ -510,7 +513,10 @@ static struct sock *__iso_get_sock_listen_by_addr(bdaddr_t *ba) if (sk->sk_state != BT_LISTEN) continue; - if (!bacmp(&iso_pi(sk)->src, ba)) + if (bacmp(&iso_pi(sk)->dst, dst)) + continue; + + if (!bacmp(&iso_pi(sk)->src, src)) return sk; } @@ -786,8 +792,7 @@ static int iso_sock_bind_bc(struct socket *sock, struct sockaddr *addr, BT_DBG("sk %p bc_sid %u bc_num_bis %u", sk, sa->iso_bc->bc_sid, sa->iso_bc->bc_num_bis); - if (addr_len > sizeof(*sa) + sizeof(*sa->iso_bc) || - sa->iso_bc->bc_num_bis < 0x01 || sa->iso_bc->bc_num_bis > 0x1f) + if (addr_len > sizeof(*sa) + sizeof(*sa->iso_bc)) return -EINVAL; bacpy(&iso_pi(sk)->dst, &sa->iso_bc->bc_bdaddr); @@ -952,7 +957,7 @@ static int iso_listen_cis(struct sock *sk) write_lock(&iso_sk_list.lock); - if (__iso_get_sock_listen_by_addr(&iso_pi(sk)->src)) + if (__iso_get_sock_listen_by_addr(&iso_pi(sk)->src, &iso_pi(sk)->dst)) err = -EADDRINUSE; write_unlock(&iso_sk_list.lock); @@ -1199,7 +1204,6 @@ static int iso_sock_recvmsg(struct socket *sock, struct msghdr *msg, test_bit(HCI_CONN_PA_SYNC, &pi->conn->hcon->flags)) { iso_conn_big_sync(sk); sk->sk_state = BT_LISTEN; - set_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags); } else { iso_conn_defer_accept(pi->conn->hcon); sk->sk_state = BT_CONFIG; @@ -1458,6 +1462,8 @@ static int iso_sock_getsockopt(struct socket *sock, int level, int optname, len = min_t(unsigned int, len, base_len); if (copy_to_user(optval, base, len)) err = -EFAULT; + if (put_user(len, optlen)) + err = -EFAULT; break; @@ -1576,6 +1582,7 @@ static void iso_conn_ready(struct iso_conn *conn) struct sock *sk = conn->sk; struct hci_ev_le_big_sync_estabilished *ev = NULL; struct hci_ev_le_pa_sync_established *ev2 = NULL; + struct hci_evt_le_big_info_adv_report *ev3 = NULL; struct hci_conn *hcon; BT_DBG("conn %p", conn); @@ -1600,14 +1607,20 @@ static void iso_conn_ready(struct iso_conn *conn) parent = iso_get_sock_listen(&hcon->src, &hcon->dst, iso_match_big, ev); - } else if (test_bit(HCI_CONN_PA_SYNC, &hcon->flags) || - test_bit(HCI_CONN_PA_SYNC_FAILED, &hcon->flags)) { + } else if (test_bit(HCI_CONN_PA_SYNC_FAILED, &hcon->flags)) { ev2 = hci_recv_event_data(hcon->hdev, HCI_EV_LE_PA_SYNC_ESTABLISHED); if (ev2) parent = iso_get_sock_listen(&hcon->src, &hcon->dst, iso_match_sid, ev2); + } else if (test_bit(HCI_CONN_PA_SYNC, &hcon->flags)) { + ev3 = hci_recv_event_data(hcon->hdev, + HCI_EVT_LE_BIG_INFO_ADV_REPORT); + if (ev3) + parent = iso_get_sock_listen(&hcon->src, + &hcon->dst, + iso_match_sync_handle, ev3); } if (!parent) @@ -1647,11 +1660,13 @@ static void iso_conn_ready(struct iso_conn *conn) hcon->sync_handle = iso_pi(parent)->sync_handle; } - if (ev2 && !ev2->status) { - iso_pi(sk)->sync_handle = iso_pi(parent)->sync_handle; + if (ev3) { iso_pi(sk)->qos = iso_pi(parent)->qos; + iso_pi(sk)->qos.bcast.encryption = ev3->encryption; + hcon->iso_qos = iso_pi(sk)->qos; iso_pi(sk)->bc_num_bis = iso_pi(parent)->bc_num_bis; memcpy(iso_pi(sk)->bc_bis, iso_pi(parent)->bc_bis, ISO_MAX_NUM_BIS); + set_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags); } bacpy(&iso_pi(sk)->dst, &hcon->dst); @@ -1771,12 +1786,16 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags) ev3 = hci_recv_event_data(hdev, HCI_EV_LE_PER_ADV_REPORT); if (ev3) { + size_t base_len = ev3->length; + u8 *base; + sk = iso_get_sock_listen(&hdev->bdaddr, bdaddr, iso_match_sync_handle_pa_report, ev3); - - if (sk) { - memcpy(iso_pi(sk)->base, ev3->data, ev3->length); - iso_pi(sk)->base_len = ev3->length; + base = eir_get_service_data(ev3->data, ev3->length, + EIR_BAA_SERVICE_UUID, &base_len); + if (base && sk && base_len <= sizeof(iso_pi(sk)->base)) { + memcpy(iso_pi(sk)->base, base, base_len); + iso_pi(sk)->base_len = base_len; } } else { sk = iso_get_sock_listen(&hdev->bdaddr, BDADDR_ANY, NULL, NULL); |