Skip to content

Commit f777d88

Browse files
iulia-tanasescuVudentz
authored andcommitted
Bluetooth: ISO: Notify user space about failed bis connections
Some use cases require the user to be informed if BIG synchronization fails. This commit makes it so that even if the BIG sync established event arrives with error status, a new hconn is added for each BIS, and the iso layer is notified about the failed connections. Unsuccesful bis connections will be marked using the HCI_CONN_BIG_SYNC_FAILED flag. From the iso layer, the POLLERR event is triggered on the newly allocated bis sockets, before adding them to the accept list of the parent socket. From user space, a new fd for each failed bis connection will be obtained by calling accept. The user should check for the POLLERR event on the new socket, to determine if the connection was successful or not. The HCI_CONN_BIG_SYNC flag has been added to mark whether the BIG sync has been successfully established. This flag is checked at bis cleanup, so the HCI LE BIG Terminate Sync command is only issued if needed. The BT_SK_BIG_SYNC flag indicates if BIG create sync has been called for a listening socket, to avoid issuing the command everytime a BIGInfo advertising report is received. Signed-off-by: Iulia Tanasescu <[email protected]> Signed-off-by: Luiz Augusto von Dentz <[email protected]>
1 parent e160a8f commit f777d88

File tree

5 files changed

+93
-38
lines changed

5 files changed

+93
-38
lines changed

include/net/bluetooth/hci_core.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -976,6 +976,8 @@ enum {
976976
HCI_CONN_PER_ADV,
977977
HCI_CONN_BIG_CREATED,
978978
HCI_CONN_CREATE_CIS,
979+
HCI_CONN_BIG_SYNC,
980+
HCI_CONN_BIG_SYNC_FAILED,
979981
};
980982

981983
static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
@@ -1286,6 +1288,29 @@ static inline struct hci_conn *hci_conn_hash_lookup_big(struct hci_dev *hdev,
12861288
return NULL;
12871289
}
12881290

1291+
static inline struct hci_conn *hci_conn_hash_lookup_big_any_dst(struct hci_dev *hdev,
1292+
__u8 handle)
1293+
{
1294+
struct hci_conn_hash *h = &hdev->conn_hash;
1295+
struct hci_conn *c;
1296+
1297+
rcu_read_lock();
1298+
1299+
list_for_each_entry_rcu(c, &h->list, list) {
1300+
if (c->type != ISO_LINK)
1301+
continue;
1302+
1303+
if (handle == c->iso_qos.bcast.big) {
1304+
rcu_read_unlock();
1305+
return c;
1306+
}
1307+
}
1308+
1309+
rcu_read_unlock();
1310+
1311+
return NULL;
1312+
}
1313+
12891314
static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
12901315
__u8 type, __u16 state)
12911316
{

net/bluetooth/hci_conn.c

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,7 @@ struct iso_list_data {
735735
int count;
736736
struct iso_cig_params pdu;
737737
bool big_term;
738+
bool big_sync_term;
738739
};
739740

740741
static void bis_list(struct hci_conn *conn, void *data)
@@ -752,17 +753,6 @@ static void bis_list(struct hci_conn *conn, void *data)
752753
d->count++;
753754
}
754755

755-
static void find_bis(struct hci_conn *conn, void *data)
756-
{
757-
struct iso_list_data *d = data;
758-
759-
/* Ignore unicast */
760-
if (bacmp(&conn->dst, BDADDR_ANY))
761-
return;
762-
763-
d->count++;
764-
}
765-
766756
static int terminate_big_sync(struct hci_dev *hdev, void *data)
767757
{
768758
struct iso_list_data *d = data;
@@ -815,31 +805,26 @@ static int big_terminate_sync(struct hci_dev *hdev, void *data)
815805
bt_dev_dbg(hdev, "big 0x%2.2x sync_handle 0x%4.4x", d->big,
816806
d->sync_handle);
817807

818-
/* Check if ISO connection is a BIS and terminate BIG if there are
819-
* no other connections using it.
820-
*/
821-
hci_conn_hash_list_state(hdev, find_bis, ISO_LINK, BT_CONNECTED, d);
822-
if (d->count)
823-
return 0;
824-
825-
hci_le_big_terminate_sync(hdev, d->big);
808+
if (d->big_sync_term)
809+
hci_le_big_terminate_sync(hdev, d->big);
826810

827811
return hci_le_pa_terminate_sync(hdev, d->sync_handle);
828812
}
829813

830-
static int hci_le_big_terminate(struct hci_dev *hdev, u8 big, u16 sync_handle)
814+
static int hci_le_big_terminate(struct hci_dev *hdev, u8 big, struct hci_conn *conn)
831815
{
832816
struct iso_list_data *d;
833817
int ret;
834818

835-
bt_dev_dbg(hdev, "big 0x%2.2x sync_handle 0x%4.4x", big, sync_handle);
819+
bt_dev_dbg(hdev, "big 0x%2.2x sync_handle 0x%4.4x", big, conn->sync_handle);
836820

837821
d = kzalloc(sizeof(*d), GFP_KERNEL);
838822
if (!d)
839823
return -ENOMEM;
840824

841825
d->big = big;
842-
d->sync_handle = sync_handle;
826+
d->sync_handle = conn->sync_handle;
827+
d->big_sync_term = test_and_clear_bit(HCI_CONN_BIG_SYNC, &conn->flags);
843828

844829
ret = hci_cmd_sync_queue(hdev, big_terminate_sync, d,
845830
terminate_big_destroy);
@@ -875,8 +860,14 @@ static void bis_cleanup(struct hci_conn *conn)
875860

876861
hci_le_terminate_big(hdev, conn);
877862
} else {
863+
bis = hci_conn_hash_lookup_big_any_dst(hdev,
864+
conn->iso_qos.bcast.big);
865+
866+
if (bis)
867+
return;
868+
878869
hci_le_big_terminate(hdev, conn->iso_qos.bcast.big,
879-
conn->sync_handle);
870+
conn);
880871
}
881872
}
882873

net/bluetooth/hci_event.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7039,9 +7039,6 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
70397039
flex_array_size(ev, bis, ev->num_bis)))
70407040
return;
70417041

7042-
if (ev->status)
7043-
return;
7044-
70457042
hci_dev_lock(hdev);
70467043

70477044
for (i = 0; i < ev->num_bis; i++) {
@@ -7065,9 +7062,25 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
70657062
bis->iso_qos.bcast.in.latency = le16_to_cpu(ev->interval) * 125 / 100;
70667063
bis->iso_qos.bcast.in.sdu = le16_to_cpu(ev->max_pdu);
70677064

7068-
hci_iso_setup_path(bis);
7065+
if (!ev->status) {
7066+
set_bit(HCI_CONN_BIG_SYNC, &bis->flags);
7067+
hci_iso_setup_path(bis);
7068+
}
70697069
}
70707070

7071+
/* In case BIG sync failed, notify each failed connection to
7072+
* the user after all hci connections have been added
7073+
*/
7074+
if (ev->status)
7075+
for (i = 0; i < ev->num_bis; i++) {
7076+
u16 handle = le16_to_cpu(ev->bis[i]);
7077+
7078+
bis = hci_conn_hash_lookup_handle(hdev, handle);
7079+
7080+
set_bit(HCI_CONN_BIG_SYNC_FAILED, &bis->flags);
7081+
hci_connect_cfm(bis, ev->status);
7082+
}
7083+
70717084
hci_dev_unlock(hdev);
70727085
}
70737086

net/bluetooth/hci_sync.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5395,6 +5395,14 @@ int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason)
53955395
return err;
53965396
case BT_CONNECT2:
53975397
return hci_reject_conn_sync(hdev, conn, reason);
5398+
case BT_OPEN:
5399+
/* Cleanup bises that failed to be established */
5400+
if (test_and_clear_bit(HCI_CONN_BIG_SYNC_FAILED, &conn->flags)) {
5401+
hci_dev_lock(hdev);
5402+
hci_conn_failed(conn, reason);
5403+
hci_dev_unlock(hdev);
5404+
}
5405+
break;
53985406
default:
53995407
conn->state = BT_CLOSED;
54005408
break;

net/bluetooth/iso.c

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ static void iso_sock_kill(struct sock *sk);
4848
#define EIR_SERVICE_DATA_LENGTH 4
4949
#define BASE_MAX_LENGTH (HCI_MAX_PER_AD_LENGTH - EIR_SERVICE_DATA_LENGTH)
5050

51+
/* iso_pinfo flags values */
52+
enum {
53+
BT_SK_BIG_SYNC,
54+
};
55+
5156
struct iso_pinfo {
5257
struct bt_sock bt;
5358
bdaddr_t src;
@@ -58,7 +63,7 @@ struct iso_pinfo {
5863
__u8 bc_num_bis;
5964
__u8 bc_bis[ISO_MAX_NUM_BIS];
6065
__u16 sync_handle;
61-
__u32 flags;
66+
unsigned long flags;
6267
struct bt_iso_qos qos;
6368
bool qos_user_set;
6469
__u8 base_len;
@@ -1555,6 +1560,12 @@ static void iso_conn_ready(struct iso_conn *conn)
15551560
hci_conn_hold(hcon);
15561561
iso_chan_add(conn, sk, parent);
15571562

1563+
if (ev && ((struct hci_evt_le_big_sync_estabilished *)ev)->status) {
1564+
/* Trigger error signal on child socket */
1565+
sk->sk_err = ECONNREFUSED;
1566+
sk->sk_error_report(sk);
1567+
}
1568+
15581569
if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags))
15591570
sk->sk_state = BT_CONNECT2;
15601571
else
@@ -1623,15 +1634,17 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
16231634
if (ev2->num_bis < iso_pi(sk)->bc_num_bis)
16241635
iso_pi(sk)->bc_num_bis = ev2->num_bis;
16251636

1626-
err = hci_le_big_create_sync(hdev,
1627-
&iso_pi(sk)->qos,
1628-
iso_pi(sk)->sync_handle,
1629-
iso_pi(sk)->bc_num_bis,
1630-
iso_pi(sk)->bc_bis);
1631-
if (err) {
1632-
bt_dev_err(hdev, "hci_le_big_create_sync: %d",
1633-
err);
1634-
sk = NULL;
1637+
if (!test_and_set_bit(BT_SK_BIG_SYNC, &iso_pi(sk)->flags)) {
1638+
err = hci_le_big_create_sync(hdev,
1639+
&iso_pi(sk)->qos,
1640+
iso_pi(sk)->sync_handle,
1641+
iso_pi(sk)->bc_num_bis,
1642+
iso_pi(sk)->bc_bis);
1643+
if (err) {
1644+
bt_dev_err(hdev, "hci_le_big_create_sync: %d",
1645+
err);
1646+
sk = NULL;
1647+
}
16351648
}
16361649
}
16371650
} else {
@@ -1674,7 +1687,12 @@ static void iso_connect_cfm(struct hci_conn *hcon, __u8 status)
16741687

16751688
BT_DBG("hcon %p bdaddr %pMR status %d", hcon, &hcon->dst, status);
16761689

1677-
if (!status) {
1690+
/* Similar to the success case, if HCI_CONN_BIG_SYNC_FAILED is set,
1691+
* queue the failed bis connection into the accept queue of the
1692+
* listening socket and wake up userspace, to inform the user about
1693+
* the BIG sync failed event.
1694+
*/
1695+
if (!status || test_bit(HCI_CONN_BIG_SYNC_FAILED, &hcon->flags)) {
16781696
struct iso_conn *conn;
16791697

16801698
conn = iso_conn_add(hcon);

0 commit comments

Comments
 (0)