Skip to content

Commit 2ccde10

Browse files
iulia-tanasescugregkh
authored andcommitted
Bluetooth: ISO: Add support for connecting multiple BISes
[ Upstream commit a0bfde1 ] It is required for some configurations to have multiple BISes as part of the same BIG. Similar to the flow implemented for unicast, DEFER_SETUP will also be used to bind multiple BISes for the same BIG, before starting Periodic Advertising and creating the BIG. The user will have to open a new socket for each BIS. By setting the BT_DEFER_SETUP socket option and calling connect, a new connection will be added for the BIG and advertising handle set by the socket QoS parameters. Since all BISes will be bound for the same BIG and advertising handle, the socket QoS options and base parameters should match for all connections. By calling connect on a socket that does not have the BT_DEFER_SETUP option set, periodic advertising will be started and the BIG will be created, with a BIS for each previously bound connection. Since a BIG cannot be reconfigured with additional BISes after creation, no more connections can be bound for the BIG after the start periodic advertising and create BIG commands have been queued. The bis_cleanup function has also been updated, so that the advertising set and the BIG will not be terminated unless there are no more bound or connected BISes. The HCI_CONN_BIG_CREATED connection flag has been added to indicate that the BIG has been successfully created. This flag is checked at bis_cleanup, so that the BIG is only terminated if the HCI_LE_Create_BIG_Complete has been received. This implementation has been tested on hardware, using the "isotest" tool with an additional command line option, to specify the number of BISes to create as part of the desired BIG: tools/isotest -i hci0 -s 00:00:00:00:00:00 -N 2 -G 1 -T 1 The btmon log shows that a BIG containing 2 BISes has been created: < HCI Command: LE Create Broadcast Isochronous Group (0x08|0x0068) plen 31 Handle: 0x01 Advertising Handle: 0x01 Number of BIS: 2 SDU Interval: 10000 us (0x002710) Maximum SDU size: 40 Maximum Latency: 10 ms (0x000a) RTN: 0x02 PHY: LE 2M (0x02) Packing: Sequential (0x00) Framing: Unframed (0x00) Encryption: 0x00 Broadcast Code: 00000000000000000000000000000000 > HCI Event: Command Status (0x0f) plen 4 LE Create Broadcast Isochronous Group (0x08|0x0068) ncmd 1 Status: Success (0x00) > HCI Event: LE Meta Event (0x3e) plen 23 LE Broadcast Isochronous Group Complete (0x1b) Status: Success (0x00) Handle: 0x01 BIG Synchronization Delay: 1974 us (0x0007b6) Transport Latency: 1974 us (0x0007b6) PHY: LE 2M (0x02) NSE: 3 BN: 1 PTO: 1 IRC: 3 Maximum PDU: 40 ISO Interval: 10.00 msec (0x0008) Connection Handle #0: 10 Connection Handle #1: 11 < HCI Command: LE Setup Isochronous Data Path (0x08|0x006e) plen 13 Handle: 10 Data Path Direction: Input (Host to Controller) (0x00) Data Path: HCI (0x00) Coding Format: Transparent (0x03) Company Codec ID: Ericsson Technology Licensing (0) Vendor Codec ID: 0 Controller Delay: 0 us (0x000000) Codec Configuration Length: 0 Codec Configuration: > HCI Event: Command Complete (0x0e) plen 6 LE Setup Isochronous Data Path (0x08|0x006e) ncmd 1 Status: Success (0x00) Handle: 10 < HCI Command: LE Setup Isochronous Data Path (0x08|0x006e) plen 13 Handle: 11 Data Path Direction: Input (Host to Controller) (0x00) Data Path: HCI (0x00) Coding Format: Transparent (0x03) Company Codec ID: Ericsson Technology Licensing (0) Vendor Codec ID: 0 Controller Delay: 0 us (0x000000) Codec Configuration Length: 0 Codec Configuration: > HCI Event: Command Complete (0x0e) plen 6 LE Setup Isochronous Data Path (0x08|0x006e) ncmd 1 Status: Success (0x00) Handle: 11 < ISO Data TX: Handle 10 flags 0x02 dlen 44 < ISO Data TX: Handle 11 flags 0x02 dlen 44 > HCI Event: Number of Completed Packets (0x13) plen 5 Num handles: 1 Handle: 10 Count: 1 > HCI Event: Number of Completed Packets (0x13) plen 5 Num handles: 1 Handle: 11 Count: 1 Signed-off-by: Iulia Tanasescu <[email protected]> Signed-off-by: Luiz Augusto von Dentz <[email protected]> Stable-dep-of: 7f74563 ("Bluetooth: ISO: do not emit new LE Create CIS if previous is pending") Signed-off-by: Sasha Levin <[email protected]>
1 parent c0dbceb commit 2ccde10

File tree

4 files changed

+189
-73
lines changed

4 files changed

+189
-73
lines changed

include/net/bluetooth/hci_core.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -974,6 +974,7 @@ enum {
974974
HCI_CONN_SCANNING,
975975
HCI_CONN_AUTH_FAILURE,
976976
HCI_CONN_PER_ADV,
977+
HCI_CONN_BIG_CREATED,
977978
};
978979

979980
static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
@@ -1115,6 +1116,32 @@ static inline struct hci_conn *hci_conn_hash_lookup_bis(struct hci_dev *hdev,
11151116
return NULL;
11161117
}
11171118

1119+
static inline struct hci_conn *
1120+
hci_conn_hash_lookup_per_adv_bis(struct hci_dev *hdev,
1121+
bdaddr_t *ba,
1122+
__u8 big, __u8 bis)
1123+
{
1124+
struct hci_conn_hash *h = &hdev->conn_hash;
1125+
struct hci_conn *c;
1126+
1127+
rcu_read_lock();
1128+
1129+
list_for_each_entry_rcu(c, &h->list, list) {
1130+
if (bacmp(&c->dst, ba) || c->type != ISO_LINK ||
1131+
!test_bit(HCI_CONN_PER_ADV, &c->flags))
1132+
continue;
1133+
1134+
if (c->iso_qos.bcast.big == big &&
1135+
c->iso_qos.bcast.bis == bis) {
1136+
rcu_read_unlock();
1137+
return c;
1138+
}
1139+
}
1140+
rcu_read_unlock();
1141+
1142+
return NULL;
1143+
}
1144+
11181145
static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev,
11191146
__u16 handle)
11201147
{
@@ -1351,6 +1378,9 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
13511378
__u16 setting, struct bt_codec *codec);
13521379
struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst,
13531380
__u8 dst_type, struct bt_iso_qos *qos);
1381+
struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst,
1382+
struct bt_iso_qos *qos,
1383+
__u8 base_len, __u8 *base);
13541384
struct hci_conn *hci_connect_cis(struct hci_dev *hdev, bdaddr_t *dst,
13551385
__u8 dst_type, struct bt_iso_qos *qos);
13561386
struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst,

net/bluetooth/hci_conn.c

Lines changed: 106 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,7 @@ struct iso_list_data {
792792
};
793793
int count;
794794
struct iso_cig_params pdu;
795+
bool big_term;
795796
};
796797

797798
static void bis_list(struct hci_conn *conn, void *data)
@@ -828,11 +829,8 @@ static int terminate_big_sync(struct hci_dev *hdev, void *data)
828829

829830
hci_remove_ext_adv_instance_sync(hdev, d->bis, NULL);
830831

831-
/* Check if ISO connection is a BIS and terminate BIG if there are
832-
* no other connections using it.
833-
*/
834-
hci_conn_hash_list_state(hdev, find_bis, ISO_LINK, BT_CONNECTED, d);
835-
if (d->count)
832+
/* Only terminate BIG if it has been created */
833+
if (!d->big_term)
836834
return 0;
837835

838836
return hci_le_terminate_big_sync(hdev, d->big,
@@ -844,19 +842,21 @@ static void terminate_big_destroy(struct hci_dev *hdev, void *data, int err)
844842
kfree(data);
845843
}
846844

847-
static int hci_le_terminate_big(struct hci_dev *hdev, u8 big, u8 bis)
845+
static int hci_le_terminate_big(struct hci_dev *hdev, struct hci_conn *conn)
848846
{
849847
struct iso_list_data *d;
850848
int ret;
851849

852-
bt_dev_dbg(hdev, "big 0x%2.2x bis 0x%2.2x", big, bis);
850+
bt_dev_dbg(hdev, "big 0x%2.2x bis 0x%2.2x", conn->iso_qos.bcast.big,
851+
conn->iso_qos.bcast.bis);
853852

854853
d = kzalloc(sizeof(*d), GFP_KERNEL);
855854
if (!d)
856855
return -ENOMEM;
857856

858-
d->big = big;
859-
d->bis = bis;
857+
d->big = conn->iso_qos.bcast.big;
858+
d->bis = conn->iso_qos.bcast.bis;
859+
d->big_term = test_and_clear_bit(HCI_CONN_BIG_CREATED, &conn->flags);
860860

861861
ret = hci_cmd_sync_queue(hdev, terminate_big_sync, d,
862862
terminate_big_destroy);
@@ -916,15 +916,24 @@ static int hci_le_big_terminate(struct hci_dev *hdev, u8 big, u16 sync_handle)
916916
static void bis_cleanup(struct hci_conn *conn)
917917
{
918918
struct hci_dev *hdev = conn->hdev;
919+
struct hci_conn *bis;
919920

920921
bt_dev_dbg(hdev, "conn %p", conn);
921922

922923
if (conn->role == HCI_ROLE_MASTER) {
923924
if (!test_and_clear_bit(HCI_CONN_PER_ADV, &conn->flags))
924925
return;
925926

926-
hci_le_terminate_big(hdev, conn->iso_qos.bcast.big,
927-
conn->iso_qos.bcast.bis);
927+
/* Check if ISO connection is a BIS and terminate advertising
928+
* set and BIG if there are no other connections using it.
929+
*/
930+
bis = hci_conn_hash_lookup_bis(hdev, BDADDR_ANY,
931+
conn->iso_qos.bcast.big,
932+
conn->iso_qos.bcast.bis);
933+
if (bis)
934+
return;
935+
936+
hci_le_terminate_big(hdev, conn);
928937
} else {
929938
hci_le_big_terminate(hdev, conn->iso_qos.bcast.big,
930939
conn->sync_handle);
@@ -1495,10 +1504,10 @@ static int qos_set_bis(struct hci_dev *hdev, struct bt_iso_qos *qos)
14951504

14961505
/* This function requires the caller holds hdev->lock */
14971506
static struct hci_conn *hci_add_bis(struct hci_dev *hdev, bdaddr_t *dst,
1498-
struct bt_iso_qos *qos)
1507+
struct bt_iso_qos *qos, __u8 base_len,
1508+
__u8 *base)
14991509
{
15001510
struct hci_conn *conn;
1501-
struct iso_list_data data;
15021511
int err;
15031512

15041513
/* Let's make sure that le is enabled.*/
@@ -1516,24 +1525,27 @@ static struct hci_conn *hci_add_bis(struct hci_dev *hdev, bdaddr_t *dst,
15161525
if (err)
15171526
return ERR_PTR(err);
15181527

1519-
data.big = qos->bcast.big;
1520-
data.bis = qos->bcast.bis;
1521-
data.count = 0;
1522-
1523-
/* Check if there is already a matching BIG/BIS */
1524-
hci_conn_hash_list_state(hdev, bis_list, ISO_LINK, BT_BOUND, &data);
1525-
if (data.count)
1528+
/* Check if the LE Create BIG command has already been sent */
1529+
conn = hci_conn_hash_lookup_per_adv_bis(hdev, dst, qos->bcast.big,
1530+
qos->bcast.big);
1531+
if (conn)
15261532
return ERR_PTR(-EADDRINUSE);
15271533

1528-
conn = hci_conn_hash_lookup_bis(hdev, dst, qos->bcast.big, qos->bcast.bis);
1529-
if (conn)
1534+
/* Check BIS settings against other bound BISes, since all
1535+
* BISes in a BIG must have the same value for all parameters
1536+
*/
1537+
conn = hci_conn_hash_lookup_bis(hdev, dst, qos->bcast.big,
1538+
qos->bcast.bis);
1539+
1540+
if (conn && (memcmp(qos, &conn->iso_qos, sizeof(*qos)) ||
1541+
base_len != conn->le_per_adv_data_len ||
1542+
memcmp(conn->le_per_adv_data, base, base_len)))
15301543
return ERR_PTR(-EADDRINUSE);
15311544

15321545
conn = hci_conn_add(hdev, ISO_LINK, dst, HCI_ROLE_MASTER);
15331546
if (!conn)
15341547
return ERR_PTR(-ENOMEM);
15351548

1536-
set_bit(HCI_CONN_PER_ADV, &conn->flags);
15371549
conn->state = BT_CONNECT;
15381550

15391551
hci_conn_hold(conn);
@@ -1747,12 +1759,21 @@ static int hci_le_create_big(struct hci_conn *conn, struct bt_iso_qos *qos)
17471759
{
17481760
struct hci_dev *hdev = conn->hdev;
17491761
struct hci_cp_le_create_big cp;
1762+
struct iso_list_data data;
17501763

17511764
memset(&cp, 0, sizeof(cp));
17521765

1766+
data.big = qos->bcast.big;
1767+
data.bis = qos->bcast.bis;
1768+
data.count = 0;
1769+
1770+
/* Create a BIS for each bound connection */
1771+
hci_conn_hash_list_state(hdev, bis_list, ISO_LINK,
1772+
BT_BOUND, &data);
1773+
17531774
cp.handle = qos->bcast.big;
17541775
cp.adv_handle = qos->bcast.bis;
1755-
cp.num_bis = 0x01;
1776+
cp.num_bis = data.count;
17561777
hci_cpu_to_le24(qos->bcast.out.interval, cp.bis.sdu_interval);
17571778
cp.bis.sdu = cpu_to_le16(qos->bcast.out.sdu);
17581779
cp.bis.latency = cpu_to_le16(qos->bcast.out.latency);
@@ -2051,16 +2072,6 @@ static void hci_iso_qos_setup(struct hci_dev *hdev, struct hci_conn *conn,
20512072
qos->latency = conn->le_conn_latency;
20522073
}
20532074

2054-
static void hci_bind_bis(struct hci_conn *conn,
2055-
struct bt_iso_qos *qos)
2056-
{
2057-
/* Update LINK PHYs according to QoS preference */
2058-
conn->le_tx_phy = qos->bcast.out.phy;
2059-
conn->le_tx_phy = qos->bcast.out.phy;
2060-
conn->iso_qos = *qos;
2061-
conn->state = BT_BOUND;
2062-
}
2063-
20642075
static int create_big_sync(struct hci_dev *hdev, void *data)
20652076
{
20662077
struct hci_conn *conn = data;
@@ -2183,27 +2194,80 @@ static void create_big_complete(struct hci_dev *hdev, void *data, int err)
21832194
}
21842195
}
21852196

2186-
struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst,
2187-
__u8 dst_type, struct bt_iso_qos *qos,
2188-
__u8 base_len, __u8 *base)
2197+
struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst,
2198+
struct bt_iso_qos *qos,
2199+
__u8 base_len, __u8 *base)
21892200
{
21902201
struct hci_conn *conn;
2191-
int err;
2202+
__u8 eir[HCI_MAX_PER_AD_LENGTH];
2203+
2204+
if (base_len && base)
2205+
base_len = eir_append_service_data(eir, 0, 0x1851,
2206+
base, base_len);
21922207

21932208
/* We need hci_conn object using the BDADDR_ANY as dst */
2194-
conn = hci_add_bis(hdev, dst, qos);
2209+
conn = hci_add_bis(hdev, dst, qos, base_len, eir);
21952210
if (IS_ERR(conn))
21962211
return conn;
21972212

2198-
hci_bind_bis(conn, qos);
2213+
/* Update LINK PHYs according to QoS preference */
2214+
conn->le_tx_phy = qos->bcast.out.phy;
2215+
conn->le_tx_phy = qos->bcast.out.phy;
21992216

22002217
/* Add Basic Announcement into Peridic Adv Data if BASE is set */
22012218
if (base_len && base) {
2202-
base_len = eir_append_service_data(conn->le_per_adv_data, 0,
2203-
0x1851, base, base_len);
2219+
memcpy(conn->le_per_adv_data, eir, sizeof(eir));
22042220
conn->le_per_adv_data_len = base_len;
22052221
}
22062222

2223+
hci_iso_qos_setup(hdev, conn, &qos->bcast.out,
2224+
conn->le_tx_phy ? conn->le_tx_phy :
2225+
hdev->le_tx_def_phys);
2226+
2227+
conn->iso_qos = *qos;
2228+
conn->state = BT_BOUND;
2229+
2230+
return conn;
2231+
}
2232+
2233+
static void bis_mark_per_adv(struct hci_conn *conn, void *data)
2234+
{
2235+
struct iso_list_data *d = data;
2236+
2237+
/* Skip if not broadcast/ANY address */
2238+
if (bacmp(&conn->dst, BDADDR_ANY))
2239+
return;
2240+
2241+
if (d->big != conn->iso_qos.bcast.big ||
2242+
d->bis == BT_ISO_QOS_BIS_UNSET ||
2243+
d->bis != conn->iso_qos.bcast.bis)
2244+
return;
2245+
2246+
set_bit(HCI_CONN_PER_ADV, &conn->flags);
2247+
}
2248+
2249+
struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst,
2250+
__u8 dst_type, struct bt_iso_qos *qos,
2251+
__u8 base_len, __u8 *base)
2252+
{
2253+
struct hci_conn *conn;
2254+
int err;
2255+
struct iso_list_data data;
2256+
2257+
conn = hci_bind_bis(hdev, dst, qos, base_len, base);
2258+
if (IS_ERR(conn))
2259+
return conn;
2260+
2261+
data.big = qos->bcast.big;
2262+
data.bis = qos->bcast.bis;
2263+
2264+
/* Set HCI_CONN_PER_ADV for all bound connections, to mark that
2265+
* the start periodic advertising and create BIG commands have
2266+
* been queued
2267+
*/
2268+
hci_conn_hash_list_state(hdev, bis_mark_per_adv, ISO_LINK,
2269+
BT_BOUND, &data);
2270+
22072271
/* Queue start periodic advertising and create BIG */
22082272
err = hci_cmd_sync_queue(hdev, create_big_sync, conn,
22092273
create_big_complete);
@@ -2212,10 +2276,6 @@ struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst,
22122276
return ERR_PTR(err);
22132277
}
22142278

2215-
hci_iso_qos_setup(hdev, conn, &qos->bcast.out,
2216-
conn->le_tx_phy ? conn->le_tx_phy :
2217-
hdev->le_tx_def_phys);
2218-
22192279
return conn;
22202280
}
22212281

net/bluetooth/hci_event.c

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6936,6 +6936,7 @@ static void hci_le_create_big_complete_evt(struct hci_dev *hdev, void *data,
69366936
{
69376937
struct hci_evt_le_create_big_complete *ev = data;
69386938
struct hci_conn *conn;
6939+
__u8 bis_idx = 0;
69396940

69406941
BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);
69416942

@@ -6944,33 +6945,44 @@ static void hci_le_create_big_complete_evt(struct hci_dev *hdev, void *data,
69446945
return;
69456946

69466947
hci_dev_lock(hdev);
6948+
rcu_read_lock();
69476949

6948-
conn = hci_conn_hash_lookup_big(hdev, ev->handle);
6949-
if (!conn)
6950-
goto unlock;
6950+
/* Connect all BISes that are bound to the BIG */
6951+
list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) {
6952+
if (bacmp(&conn->dst, BDADDR_ANY) ||
6953+
conn->type != ISO_LINK ||
6954+
conn->iso_qos.bcast.big != ev->handle)
6955+
continue;
69516956

6952-
if (conn->type != ISO_LINK) {
6953-
bt_dev_err(hdev,
6954-
"Invalid connection link type handle 0x%2.2x",
6955-
ev->handle);
6956-
goto unlock;
6957-
}
6957+
conn->handle = __le16_to_cpu(ev->bis_handle[bis_idx++]);
69586958

6959-
if (ev->num_bis)
6960-
conn->handle = __le16_to_cpu(ev->bis_handle[0]);
6959+
if (!ev->status) {
6960+
conn->state = BT_CONNECTED;
6961+
set_bit(HCI_CONN_BIG_CREATED, &conn->flags);
6962+
rcu_read_unlock();
6963+
hci_debugfs_create_conn(conn);
6964+
hci_conn_add_sysfs(conn);
6965+
hci_iso_setup_path(conn);
6966+
rcu_read_lock();
6967+
continue;
6968+
}
69616969

6962-
if (!ev->status) {
6963-
conn->state = BT_CONNECTED;
6964-
hci_debugfs_create_conn(conn);
6965-
hci_conn_add_sysfs(conn);
6966-
hci_iso_setup_path(conn);
6967-
goto unlock;
6970+
hci_connect_cfm(conn, ev->status);
6971+
rcu_read_unlock();
6972+
hci_conn_del(conn);
6973+
rcu_read_lock();
69686974
}
69696975

6970-
hci_connect_cfm(conn, ev->status);
6971-
hci_conn_del(conn);
6976+
if (!ev->status && !bis_idx)
6977+
/* If no BISes have been connected for the BIG,
6978+
* terminate. This is in case all bound connections
6979+
* have been closed before the BIG creation
6980+
* has completed.
6981+
*/
6982+
hci_le_terminate_big_sync(hdev, ev->handle,
6983+
HCI_ERROR_LOCAL_HOST_TERM);
69726984

6973-
unlock:
6985+
rcu_read_unlock();
69746986
hci_dev_unlock(hdev);
69756987
}
69766988

0 commit comments

Comments
 (0)