Bluetooth: hci_sync: Fix broadcast/PA when using an existing instance
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Thu, 5 Jun 2025 15:15:16 +0000 (11:15 -0400)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Wed, 11 Jun 2025 20:27:29 +0000 (16:27 -0400)
When using and existing adv_info instance for broadcast source it
needs to be updated to periodic first before it can be reused, also in
case the existing instance already have data hci_set_adv_instance_data
cannot be used directly since it would overwrite the existing data so
this reappend the original data after the Broadcast ID, if one was
generated.

Example:

bluetoothctl># Add PBP to EA so it can be later referenced as the BIS ID
bluetoothctl> advertise.service 0x1856 0x00 0x00
bluetoothctl> advertise on
...
< HCI Command: LE Set Extended Advertising Data (0x08|0x0037) plen 13
        Handle: 0x01
        Operation: Complete extended advertising data (0x03)
        Fragment preference: Minimize fragmentation (0x01)
        Data length: 0x09
        Service Data: Public Broadcast Announcement (0x1856)
          Data[2]: 0000
        Flags: 0x06
          LE General Discoverable Mode
          BR/EDR Not Supported
...
bluetoothctl># Attempt to acquire Broadcast Source transport
bluetoothctl>transport.acquire /org/bluez/hci0/pac_bcast0/fd0
...
< HCI Command: LE Set Extended Advertising Data (0x08|0x0037) plen 255
        Handle: 0x01
        Operation: Complete extended advertising data (0x03)
        Fragment preference: Minimize fragmentation (0x01)
        Data length: 0x0e
        Service Data: Broadcast Audio Announcement (0x1852)
        Broadcast ID: 11371620 (0xad8464)
        Service Data: Public Broadcast Announcement (0x1856)
          Data[2]: 0000
        Flags: 0x06
          LE General Discoverable Mode
          BR/EDR Not Supported

Link: https://github.com/bluez/bluez/issues/1117
Fixes: eca0ae4aea66 ("Bluetooth: Add initial implementation of BIS connections")
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
net/bluetooth/hci_sync.c

index 62d1ff951ebe6058cca17f5b620980f366ae087a..8ba1c3aa7801a4d93c180f8dc1dcafb80d415891 100644 (file)
@@ -1559,7 +1559,8 @@ static int hci_enable_per_advertising_sync(struct hci_dev *hdev, u8 instance)
 static int hci_adv_bcast_annoucement(struct hci_dev *hdev, struct adv_info *adv)
 {
        u8 bid[3];
-       u8 ad[4 + 3];
+       u8 ad[HCI_MAX_EXT_AD_LENGTH];
+       u8 len;
 
        /* Skip if NULL adv as instance 0x00 is used for general purpose
         * advertising so it cannot used for the likes of Broadcast Announcement
@@ -1585,8 +1586,10 @@ static int hci_adv_bcast_annoucement(struct hci_dev *hdev, struct adv_info *adv)
 
        /* Generate Broadcast ID */
        get_random_bytes(bid, sizeof(bid));
-       eir_append_service_data(ad, 0, 0x1852, bid, sizeof(bid));
-       hci_set_adv_instance_data(hdev, adv->instance, sizeof(ad), ad, 0, NULL);
+       len = eir_append_service_data(ad, 0, 0x1852, bid, sizeof(bid));
+       memcpy(ad + len, adv->adv_data, adv->adv_data_len);
+       hci_set_adv_instance_data(hdev, adv->instance, len + adv->adv_data_len,
+                                 ad, 0, NULL);
 
        return hci_update_adv_data_sync(hdev, adv->instance);
 }
@@ -1603,8 +1606,15 @@ int hci_start_per_adv_sync(struct hci_dev *hdev, u8 instance, u8 data_len,
 
        if (instance) {
                adv = hci_find_adv_instance(hdev, instance);
-               /* Create an instance if that could not be found */
-               if (!adv) {
+               if (adv) {
+                       /* Turn it into periodic advertising */
+                       adv->periodic = true;
+                       adv->per_adv_data_len = data_len;
+                       if (data)
+                               memcpy(adv->per_adv_data, data, data_len);
+                       adv->flags = flags;
+               } else if (!adv) {
+                       /* Create an instance if that could not be found */
                        adv = hci_add_per_instance(hdev, instance, flags,
                                                   data_len, data,
                                                   sync_interval,