Skip to content

Commit

Permalink
Bluetooth: ISO: Pass BIG encryption info through QoS
Browse files Browse the repository at this point in the history
This enables a broadcast sink to be informed if the PA
it has synced with is associated with an encrypted BIG,
by retrieving the socket QoS and checking the encryption
field.

After PA sync has been successfully established and the
first BIGInfo advertising report is received, a new hcon
is added and notified to the ISO layer. The ISO layer
sets the encryption field of the socket and hcon QoS
according to the encryption parameter of the BIGInfo
advertising report event.

After that, the userspace is woken up, and the QoS of the
new PA sync socket can be read, to inspect the encryption
field and follow up accordingly.

Signed-off-by: Iulia Tanasescu <iulia.tanasescu@nxp.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
  • Loading branch information
Iulia Tanasescu authored and Luiz Augusto von Dentz committed Oct 23, 2023
1 parent a254b90 commit 1d11d70
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 20 deletions.
3 changes: 3 additions & 0 deletions include/net/bluetooth/hci.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright (C) 2000-2001 Qualcomm Incorporated
Copyright 2023 NXP
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
Expand Down Expand Up @@ -673,6 +674,8 @@ enum {
#define HCI_TX_POWER_INVALID 127
#define HCI_RSSI_INVALID 127

#define HCI_SYNC_HANDLE_INVALID 0xffff

#define HCI_ROLE_MASTER 0x00
#define HCI_ROLE_SLAVE 0x01

Expand Down
25 changes: 24 additions & 1 deletion include/net/bluetooth/hci_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -1314,7 +1314,7 @@ static inline struct hci_conn *hci_conn_hash_lookup_big_any_dst(struct hci_dev *
}

static inline struct hci_conn *
hci_conn_hash_lookup_pa_sync(struct hci_dev *hdev, __u8 big)
hci_conn_hash_lookup_pa_sync_big_handle(struct hci_dev *hdev, __u8 big)
{
struct hci_conn_hash *h = &hdev->conn_hash;
struct hci_conn *c;
Expand All @@ -1336,6 +1336,29 @@ hci_conn_hash_lookup_pa_sync(struct hci_dev *hdev, __u8 big)
return NULL;
}

static inline struct hci_conn *
hci_conn_hash_lookup_pa_sync_handle(struct hci_dev *hdev, __u16 sync_handle)
{
struct hci_conn_hash *h = &hdev->conn_hash;
struct hci_conn *c;

rcu_read_lock();

list_for_each_entry_rcu(c, &h->list, list) {
if (c->type != ISO_LINK ||
!test_bit(HCI_CONN_PA_SYNC, &c->flags))
continue;

if (c->sync_handle == sync_handle) {
rcu_read_unlock();
return c;
}
}
rcu_read_unlock();

return NULL;
}

static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
__u8 type, __u16 state)
{
Expand Down
1 change: 1 addition & 0 deletions net/bluetooth/hci_conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
conn->rssi = HCI_RSSI_INVALID;
conn->tx_power = HCI_TX_POWER_INVALID;
conn->max_tx_power = HCI_TX_POWER_INVALID;
conn->sync_handle = HCI_SYNC_HANDLE_INVALID;

set_bit(HCI_CONN_POWER_SAVE, &conn->flags);
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
Expand Down
54 changes: 40 additions & 14 deletions net/bluetooth/hci_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -6603,7 +6603,7 @@ static void hci_le_pa_sync_estabilished_evt(struct hci_dev *hdev, void *data,
struct hci_ev_le_pa_sync_established *ev = data;
int mask = hdev->link_mode;
__u8 flags = 0;
struct hci_conn *bis;
struct hci_conn *pa_sync;

bt_dev_dbg(hdev, "status 0x%2.2x", ev->status);

Expand All @@ -6620,20 +6620,19 @@ static void hci_le_pa_sync_estabilished_evt(struct hci_dev *hdev, void *data,
if (!(flags & HCI_PROTO_DEFER))
goto unlock;

/* Add connection to indicate the PA sync event */
bis = hci_conn_add(hdev, ISO_LINK, BDADDR_ANY,
HCI_ROLE_SLAVE);
if (ev->status) {
/* Add connection to indicate the failed PA sync event */
pa_sync = hci_conn_add(hdev, ISO_LINK, BDADDR_ANY,
HCI_ROLE_SLAVE);

if (!bis)
goto unlock;
if (!pa_sync)
goto unlock;

if (ev->status)
set_bit(HCI_CONN_PA_SYNC_FAILED, &bis->flags);
else
set_bit(HCI_CONN_PA_SYNC, &bis->flags);
set_bit(HCI_CONN_PA_SYNC_FAILED, &pa_sync->flags);

/* Notify connection to iso layer */
hci_connect_cfm(bis, ev->status);
/* Notify iso layer */
hci_connect_cfm(pa_sync, ev->status);
}

unlock:
hci_dev_unlock(hdev);
Expand Down Expand Up @@ -7125,7 +7124,7 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
hci_dev_lock(hdev);

if (!ev->status) {
pa_sync = hci_conn_hash_lookup_pa_sync(hdev, ev->handle);
pa_sync = hci_conn_hash_lookup_pa_sync_big_handle(hdev, ev->handle);
if (pa_sync)
/* Also mark the BIG sync established event on the
* associated PA sync hcon
Expand Down Expand Up @@ -7186,15 +7185,42 @@ static void hci_le_big_info_adv_report_evt(struct hci_dev *hdev, void *data,
struct hci_evt_le_big_info_adv_report *ev = data;
int mask = hdev->link_mode;
__u8 flags = 0;
struct hci_conn *pa_sync;

bt_dev_dbg(hdev, "sync_handle 0x%4.4x", le16_to_cpu(ev->sync_handle));

hci_dev_lock(hdev);

mask |= hci_proto_connect_ind(hdev, BDADDR_ANY, ISO_LINK, &flags);
if (!(mask & HCI_LM_ACCEPT))
if (!(mask & HCI_LM_ACCEPT)) {
hci_le_pa_term_sync(hdev, ev->sync_handle);
goto unlock;
}

if (!(flags & HCI_PROTO_DEFER))
goto unlock;

pa_sync = hci_conn_hash_lookup_pa_sync_handle
(hdev,
le16_to_cpu(ev->sync_handle));

if (pa_sync)
goto unlock;

/* Add connection to indicate the PA sync event */
pa_sync = hci_conn_add(hdev, ISO_LINK, BDADDR_ANY,
HCI_ROLE_SLAVE);

if (!pa_sync)
goto unlock;

pa_sync->sync_handle = le16_to_cpu(ev->sync_handle);
set_bit(HCI_CONN_PA_SYNC, &pa_sync->flags);

/* Notify iso layer */
hci_connect_cfm(pa_sync, 0x00);

unlock:
hci_dev_unlock(hdev);
}

Expand Down
19 changes: 14 additions & 5 deletions net/bluetooth/iso.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,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 ---- */
Expand Down Expand Up @@ -1202,7 +1203,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;
Expand Down Expand Up @@ -1579,6 +1579,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);
Expand All @@ -1603,14 +1604,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)
Expand Down Expand Up @@ -1650,11 +1657,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);
Expand Down

0 comments on commit 1d11d70

Please sign in to comment.