Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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 <iulia.tanasescu@nxp.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

authored by

Iulia Tanasescu and committed by
Luiz Augusto von Dentz
f777d882 e160a8f4

+93 -38
+25
include/net/bluetooth/hci_core.h
··· 976 976 HCI_CONN_PER_ADV, 977 977 HCI_CONN_BIG_CREATED, 978 978 HCI_CONN_CREATE_CIS, 979 + HCI_CONN_BIG_SYNC, 980 + HCI_CONN_BIG_SYNC_FAILED, 979 981 }; 980 982 981 983 static inline bool hci_conn_ssp_enabled(struct hci_conn *conn) ··· 1275 1273 1276 1274 list_for_each_entry_rcu(c, &h->list, list) { 1277 1275 if (bacmp(&c->dst, BDADDR_ANY) || c->type != ISO_LINK) 1276 + continue; 1277 + 1278 + if (handle == c->iso_qos.bcast.big) { 1279 + rcu_read_unlock(); 1280 + return c; 1281 + } 1282 + } 1283 + 1284 + rcu_read_unlock(); 1285 + 1286 + return NULL; 1287 + } 1288 + 1289 + static inline struct hci_conn *hci_conn_hash_lookup_big_any_dst(struct hci_dev *hdev, 1290 + __u8 handle) 1291 + { 1292 + struct hci_conn_hash *h = &hdev->conn_hash; 1293 + struct hci_conn *c; 1294 + 1295 + rcu_read_lock(); 1296 + 1297 + list_for_each_entry_rcu(c, &h->list, list) { 1298 + if (c->type != ISO_LINK) 1278 1299 continue; 1279 1300 1280 1301 if (handle == c->iso_qos.bcast.big) {
+14 -23
net/bluetooth/hci_conn.c
··· 735 735 int count; 736 736 struct iso_cig_params pdu; 737 737 bool big_term; 738 + bool big_sync_term; 738 739 }; 739 740 740 741 static void bis_list(struct hci_conn *conn, void *data) ··· 748 747 749 748 if (d->big != conn->iso_qos.bcast.big || d->bis == BT_ISO_QOS_BIS_UNSET || 750 749 d->bis != conn->iso_qos.bcast.bis) 751 - return; 752 - 753 - d->count++; 754 - } 755 - 756 - static void find_bis(struct hci_conn *conn, void *data) 757 - { 758 - struct iso_list_data *d = data; 759 - 760 - /* Ignore unicast */ 761 - if (bacmp(&conn->dst, BDADDR_ANY)) 762 750 return; 763 751 764 752 d->count++; ··· 805 815 bt_dev_dbg(hdev, "big 0x%2.2x sync_handle 0x%4.4x", d->big, 806 816 d->sync_handle); 807 817 808 - /* Check if ISO connection is a BIS and terminate BIG if there are 809 - * no other connections using it. 810 - */ 811 - hci_conn_hash_list_state(hdev, find_bis, ISO_LINK, BT_CONNECTED, d); 812 - if (d->count) 813 - return 0; 814 - 815 - hci_le_big_terminate_sync(hdev, d->big); 818 + if (d->big_sync_term) 819 + hci_le_big_terminate_sync(hdev, d->big); 816 820 817 821 return hci_le_pa_terminate_sync(hdev, d->sync_handle); 818 822 } 819 823 820 - static int hci_le_big_terminate(struct hci_dev *hdev, u8 big, u16 sync_handle) 824 + static int hci_le_big_terminate(struct hci_dev *hdev, u8 big, struct hci_conn *conn) 821 825 { 822 826 struct iso_list_data *d; 823 827 int ret; 824 828 825 - bt_dev_dbg(hdev, "big 0x%2.2x sync_handle 0x%4.4x", big, sync_handle); 829 + bt_dev_dbg(hdev, "big 0x%2.2x sync_handle 0x%4.4x", big, conn->sync_handle); 826 830 827 831 d = kzalloc(sizeof(*d), GFP_KERNEL); 828 832 if (!d) 829 833 return -ENOMEM; 830 834 831 835 d->big = big; 832 - d->sync_handle = sync_handle; 836 + d->sync_handle = conn->sync_handle; 837 + d->big_sync_term = test_and_clear_bit(HCI_CONN_BIG_SYNC, &conn->flags); 833 838 834 839 ret = hci_cmd_sync_queue(hdev, big_terminate_sync, d, 835 840 terminate_big_destroy); ··· 860 875 861 876 hci_le_terminate_big(hdev, conn); 862 877 } else { 878 + bis = hci_conn_hash_lookup_big_any_dst(hdev, 879 + conn->iso_qos.bcast.big); 880 + 881 + if (bis) 882 + return; 883 + 863 884 hci_le_big_terminate(hdev, conn->iso_qos.bcast.big, 864 - conn->sync_handle); 885 + conn); 865 886 } 866 887 } 867 888
+17 -4
net/bluetooth/hci_event.c
··· 7039 7039 flex_array_size(ev, bis, ev->num_bis))) 7040 7040 return; 7041 7041 7042 - if (ev->status) 7043 - return; 7044 - 7045 7042 hci_dev_lock(hdev); 7046 7043 7047 7044 for (i = 0; i < ev->num_bis; i++) { ··· 7062 7065 bis->iso_qos.bcast.in.latency = le16_to_cpu(ev->interval) * 125 / 100; 7063 7066 bis->iso_qos.bcast.in.sdu = le16_to_cpu(ev->max_pdu); 7064 7067 7065 - hci_iso_setup_path(bis); 7068 + if (!ev->status) { 7069 + set_bit(HCI_CONN_BIG_SYNC, &bis->flags); 7070 + hci_iso_setup_path(bis); 7071 + } 7066 7072 } 7073 + 7074 + /* In case BIG sync failed, notify each failed connection to 7075 + * the user after all hci connections have been added 7076 + */ 7077 + if (ev->status) 7078 + for (i = 0; i < ev->num_bis; i++) { 7079 + u16 handle = le16_to_cpu(ev->bis[i]); 7080 + 7081 + bis = hci_conn_hash_lookup_handle(hdev, handle); 7082 + 7083 + set_bit(HCI_CONN_BIG_SYNC_FAILED, &bis->flags); 7084 + hci_connect_cfm(bis, ev->status); 7085 + } 7067 7086 7068 7087 hci_dev_unlock(hdev); 7069 7088 }
+8
net/bluetooth/hci_sync.c
··· 5395 5395 return err; 5396 5396 case BT_CONNECT2: 5397 5397 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; 5398 5406 default: 5399 5407 conn->state = BT_CLOSED; 5400 5408 break;
+29 -11
net/bluetooth/iso.c
··· 48 48 #define EIR_SERVICE_DATA_LENGTH 4 49 49 #define BASE_MAX_LENGTH (HCI_MAX_PER_AD_LENGTH - EIR_SERVICE_DATA_LENGTH) 50 50 51 + /* iso_pinfo flags values */ 52 + enum { 53 + BT_SK_BIG_SYNC, 54 + }; 55 + 51 56 struct iso_pinfo { 52 57 struct bt_sock bt; 53 58 bdaddr_t src; ··· 63 58 __u8 bc_num_bis; 64 59 __u8 bc_bis[ISO_MAX_NUM_BIS]; 65 60 __u16 sync_handle; 66 - __u32 flags; 61 + unsigned long flags; 67 62 struct bt_iso_qos qos; 68 63 bool qos_user_set; 69 64 __u8 base_len; ··· 1560 1555 hci_conn_hold(hcon); 1561 1556 iso_chan_add(conn, sk, parent); 1562 1557 1558 + if (ev && ((struct hci_evt_le_big_sync_estabilished *)ev)->status) { 1559 + /* Trigger error signal on child socket */ 1560 + sk->sk_err = ECONNREFUSED; 1561 + sk->sk_error_report(sk); 1562 + } 1563 + 1563 1564 if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags)) 1564 1565 sk->sk_state = BT_CONNECT2; 1565 1566 else ··· 1634 1623 if (ev2->num_bis < iso_pi(sk)->bc_num_bis) 1635 1624 iso_pi(sk)->bc_num_bis = ev2->num_bis; 1636 1625 1637 - err = hci_le_big_create_sync(hdev, 1638 - &iso_pi(sk)->qos, 1639 - iso_pi(sk)->sync_handle, 1640 - iso_pi(sk)->bc_num_bis, 1641 - iso_pi(sk)->bc_bis); 1642 - if (err) { 1643 - bt_dev_err(hdev, "hci_le_big_create_sync: %d", 1644 - err); 1645 - sk = NULL; 1626 + if (!test_and_set_bit(BT_SK_BIG_SYNC, &iso_pi(sk)->flags)) { 1627 + err = hci_le_big_create_sync(hdev, 1628 + &iso_pi(sk)->qos, 1629 + iso_pi(sk)->sync_handle, 1630 + iso_pi(sk)->bc_num_bis, 1631 + iso_pi(sk)->bc_bis); 1632 + if (err) { 1633 + bt_dev_err(hdev, "hci_le_big_create_sync: %d", 1634 + err); 1635 + sk = NULL; 1636 + } 1646 1637 } 1647 1638 } 1648 1639 } else { ··· 1687 1674 1688 1675 BT_DBG("hcon %p bdaddr %pMR status %d", hcon, &hcon->dst, status); 1689 1676 1690 - if (!status) { 1677 + /* Similar to the success case, if HCI_CONN_BIG_SYNC_FAILED is set, 1678 + * queue the failed bis connection into the accept queue of the 1679 + * listening socket and wake up userspace, to inform the user about 1680 + * the BIG sync failed event. 1681 + */ 1682 + if (!status || test_bit(HCI_CONN_BIG_SYNC_FAILED, &hcon->flags)) { 1691 1683 struct iso_conn *conn; 1692 1684 1693 1685 conn = iso_conn_add(hcon);