* [PATCH BlueZ v2 01/13] monitor: Use PAST to refer to Periodic Advertising Sync Transfer
@ 2025-10-09 21:29 Luiz Augusto von Dentz
2025-10-09 21:29 ` [PATCH BlueZ v2 02/13] emulator: Add initial support for PAST Luiz Augusto von Dentz
` (12 more replies)
0 siblings, 13 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2025-10-09 21:29 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This simplify the command and event names and their structs to just
use PAST in place of other terminology currently in use.
---
monitor/bt.h | 39 +++++++++++++++++++++++++++------------
monitor/packet.c | 41 +++++++++++++++++++++++------------------
2 files changed, 50 insertions(+), 30 deletions(-)
diff --git a/monitor/bt.h b/monitor/bt.h
index 0e80ad2a2d6f..ca91f7fefc84 100644
--- a/monitor/bt.h
+++ b/monitor/bt.h
@@ -2630,22 +2630,32 @@ struct bt_hci_cmd_set_pa_rec_enable {
uint8_t enable;
} __attribute__ ((packed));
-#define BT_HCI_CMD_PERIODIC_SYNC_TRANS 0x205a
-struct bt_hci_cmd_periodic_sync_trans {
+#define BT_HCI_CMD_LE_PAST 0x205a
+struct bt_hci_cmd_le_past {
uint16_t handle;
uint16_t service_data;
uint16_t sync_handle;
} __attribute__ ((packed));
-#define BT_HCI_CMD_PA_SET_INFO_TRANS 0x205b
-struct bt_hci_cmd_pa_set_info_trans {
+struct bt_hci_rsp_le_past {
+ uint8_t status;
uint16_t handle;
- uint16_t service_data;
- uint8_t adv_handle;
} __attribute__ ((packed));
-#define BT_HCI_CMD_PA_SYNC_TRANS_PARAMS 0x205c
-struct bt_hci_cmd_pa_sync_trans_params {
+#define BT_HCI_CMD_LE_PAST_SET_INFO 0x205b
+struct bt_hci_cmd_le_past_set_info {
+ uint16_t handle;
+ uint16_t service_data;
+ uint8_t adv_handle;
+} __attribute__ ((packed));
+
+struct bt_hci_rsp_le_past_set_info {
+ uint8_t status;
+ uint16_t handle;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_LE_PAST_PARAMS 0x205c
+struct bt_hci_cmd_le_past_params {
uint16_t handle;
uint8_t mode;
uint16_t skip;
@@ -2653,8 +2663,13 @@ struct bt_hci_cmd_pa_sync_trans_params {
uint8_t cte_type;
} __attribute__ ((packed));
-#define BT_HCI_CMD_DEFAULT_PA_SYNC_TRANS_PARAMS 0x205d
-struct bt_hci_cmd_default_pa_sync_trans_params {
+struct bt_hci_rsp_le_past_params {
+ uint8_t status;
+ uint16_t handle;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_DEFAULT_PAST_PARAMS 0x205d
+struct bt_hci_cmd_le_default_past_params {
uint8_t mode;
uint16_t skip;
uint16_t sync_timeout;
@@ -3865,8 +3880,8 @@ struct bt_hci_evt_le_cte_request_failed {
uint16_t handle;
} __attribute__ ((packed));
-#define BT_HCI_EVT_LE_PA_SYNC_TRANS_REC 0x18
-struct bt_hci_evt_le_pa_sync_trans_rec {
+#define BT_HCI_EVT_LE_PAST_RECEIVED 0x18
+struct bt_hci_evt_le_past_recv {
uint8_t status;
uint16_t handle;
uint16_t service_data;
diff --git a/monitor/packet.c b/monitor/packet.c
index 2b30e881a201..f7db1cbb88c6 100644
--- a/monitor/packet.c
+++ b/monitor/packet.c
@@ -3192,7 +3192,7 @@ static const struct bitfield_data events_le_table[] = {
{ 20, "LE Connectionless IQ Report" },
{ 21, "LE Connection IQ Report" },
{ 22, "LE CTE Request Failed" },
- { 23, "LE Periodic Advertising Sync Transfer Rvc"},
+ { 23, "LE PAST Received" },
{ 24, "LE CIS Established" },
{ 25, "LE CIS Request" },
{ 26, "LE Create BIG Complete" },
@@ -8596,18 +8596,18 @@ static void le_pa_rec_enable(uint16_t index, const void *data, uint8_t size)
print_enable("Reporting", cmd->enable);
}
-static void le_pa_sync_trans(uint16_t index, const void *data, uint8_t size)
+static void le_past(uint16_t index, const void *data, uint8_t size)
{
- const struct bt_hci_cmd_periodic_sync_trans *cmd = data;
+ const struct bt_hci_cmd_le_past *cmd = data;
print_field("Connection handle: %d", cmd->handle);
print_field("Service data: 0x%4.4x", cmd->service_data);
print_field("Sync handle: %d", cmd->sync_handle);
}
-static void le_pa_set_info_trans(uint16_t index, const void *data, uint8_t size)
+static void le_past_set_info(uint16_t index, const void *data, uint8_t size)
{
- const struct bt_hci_cmd_pa_set_info_trans *cmd = data;
+ const struct bt_hci_cmd_le_past_set_info *cmd = data;
print_field("Connection handle: %d", cmd->handle);
print_field("Service data: 0x%4.4x", cmd->service_data);
@@ -8628,6 +8628,10 @@ static void print_sync_mode(uint8_t mode)
case 0x02:
str = "Enabled with report events enabled";
break;
+ case 0x03:
+ str = "Enabled with report events enabled with duplicate "
+ "filtering";
+ break;
default:
str = "RFU";
break;
@@ -8636,10 +8640,10 @@ static void print_sync_mode(uint8_t mode)
print_field("Mode: %s (0x%2.2x)", str, mode);
}
-static void le_pa_sync_trans_params(uint16_t index, const void *data,
+static void le_past_params(uint16_t index, const void *data,
uint8_t size)
{
- const struct bt_hci_cmd_pa_sync_trans_params *cmd = data;
+ const struct bt_hci_cmd_le_past_params *cmd = data;
print_field("Connection handle: %d", cmd->handle);
print_sync_mode(cmd->mode);
@@ -8650,10 +8654,10 @@ static void le_pa_sync_trans_params(uint16_t index, const void *data,
print_create_sync_cte_type(cmd->cte_type);
}
-static void le_set_default_pa_sync_trans_params(uint16_t index,
+static void le_set_default_past_params(uint16_t index,
const void *data, uint8_t size)
{
- const struct bt_hci_cmd_default_pa_sync_trans_params *cmd = data;
+ const struct bt_hci_cmd_le_default_past_params *cmd = data;
print_sync_mode(cmd->mode);
print_field("Skip: 0x%2.2x", cmd->skip);
@@ -10492,17 +10496,17 @@ static const struct opcode_data opcode_table[] = {
le_pa_rec_enable, 3, true,
status_rsp, 1, true },
{ 0x205a, 326, "LE Periodic Advertising Sync Transfer",
- le_pa_sync_trans, 6, true,
+ le_past, 6, true,
status_handle_rsp, 3, true },
{ 0x205b, 327, "LE Periodic Advertising Set Info Transfer",
- le_pa_set_info_trans, 5, true,
+ le_past_set_info, 5, true,
status_handle_rsp, 3, true },
{ 0x205c, 328, "LE Periodic Advertising Sync Transfer Parameters",
- le_pa_sync_trans_params, 8, true,
+ le_past_params, 8, true,
status_handle_rsp, 3, true},
{ 0x205d, 329, "LE Set Default Periodic Advertisng Sync Transfer "
"Parameters",
- le_set_default_pa_sync_trans_params,
+ le_set_default_past_params,
6, true, status_rsp, 1, true},
{ BT_HCI_CMD_LE_READ_BUFFER_SIZE_V2,
BT_HCI_BIT_LE_READ_BUFFER_SIZE_V2,
@@ -12383,10 +12387,10 @@ static void le_cte_request_failed_evt(struct timeval *tv, uint16_t index,
print_field("Connection handle: %d", evt->handle);
}
-static void le_pa_sync_trans_rec_evt(struct timeval *tv, uint16_t index,
+static void le_past_received_evt(struct timeval *tv, uint16_t index,
const void *data, uint8_t size)
{
- const struct bt_hci_evt_le_pa_sync_trans_rec *evt = data;
+ const struct bt_hci_evt_le_past_recv *evt = data;
print_status(evt->status);
print_field("Handle: %d", evt->handle);
@@ -13283,9 +13287,10 @@ static const struct subevent_data le_meta_event_table[] = {
le_chan_select_alg_evt, 3, true},
{ 0x17, "LE CTE Request Failed",
le_cte_request_failed_evt, 3, true},
- { 0x18, "LE Periodic Advertising Sync Transfer Received",
- le_pa_sync_trans_rec_evt, 19,
- true},
+ { BT_HCI_EVT_LE_PAST_RECEIVED,
+ "LE Periodic Advertising Sync Transfer Received",
+ le_past_received_evt, 19,
+ true},
{ BT_HCI_EVT_LE_CIS_ESTABLISHED,
"LE Connected Isochronous Stream Established",
le_cis_established_evt,
--
2.51.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH BlueZ v2 02/13] emulator: Add initial support for PAST
2025-10-09 21:29 [PATCH BlueZ v2 01/13] monitor: Use PAST to refer to Periodic Advertising Sync Transfer Luiz Augusto von Dentz
@ 2025-10-09 21:29 ` Luiz Augusto von Dentz
2025-10-09 21:29 ` [PATCH BlueZ v2 03/13] iso-tester: Add tests for PAST procedures Luiz Augusto von Dentz
` (11 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2025-10-09 21:29 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
client/scripts/broadcast-sink.bt | 2 +-
emulator/btdev.c | 333 +++++++++++++++++++++++++++++--
emulator/bthost.c | 43 ++++
emulator/bthost.h | 3 +-
4 files changed, 358 insertions(+), 23 deletions(-)
diff --git a/client/scripts/broadcast-sink.bt b/client/scripts/broadcast-sink.bt
index b912231b248f..b26dc44ac237 100644
--- a/client/scripts/broadcast-sink.bt
+++ b/client/scripts/broadcast-sink.bt
@@ -4,4 +4,4 @@ y
a
3
4
-scan on
\ No newline at end of file
+scan on
diff --git a/emulator/btdev.c b/emulator/btdev.c
index 1a0f9ef2de58..8c72a24290c6 100644
--- a/emulator/btdev.c
+++ b/emulator/btdev.c
@@ -52,9 +52,10 @@
#define has_bredr(btdev) (!((btdev)->features[4] & 0x20))
#define has_le(btdev) (!!((btdev)->features[4] & 0x40))
-#define ACL_HANDLE 42
-#define ISO_HANDLE 257
-#define SCO_HANDLE 257
+#define ACL_HANDLE BIT(0)
+#define SCO_HANDLE BIT(8)
+#define CIS_HANDLE SCO_HANDLE
+#define BIS_HANDLE BIT(9)
#define SYNC_HANDLE 1
#define INV_HANDLE 0xffff
@@ -72,8 +73,10 @@ struct hook {
struct btdev_conn {
uint16_t handle;
uint8_t type;
+ uint8_t past_mode;
struct btdev *dev;
struct btdev_conn *link;
+ struct queue *links;
void *data;
};
@@ -386,7 +389,7 @@ static inline struct btdev *find_btdev_by_bdaddr_type(const uint8_t *bdaddr,
if (!dev)
continue;
- if (bdaddr_type == 0x01)
+ if (bdaddr_type == 0x01 || bdaddr_type == 0x03)
cmp = memcmp(dev->random_addr, bdaddr, 6);
else
cmp = memcmp(dev->bdaddr, bdaddr, 6);
@@ -395,7 +398,7 @@ static inline struct btdev *find_btdev_by_bdaddr_type(const uint8_t *bdaddr,
return dev;
/* Check for instance own Random addresses */
- if (bdaddr_type == 0x01) {
+ if (bdaddr_type == 0x01 || bdaddr_type == 0x03) {
adv = queue_find(dev->le_ext_adv, match_adv_addr,
bdaddr);
if (adv)
@@ -566,10 +569,15 @@ static void conn_remove(void *data)
if (conn->link) {
struct btdev_conn *link = conn->link;
- conn_unlink(conn, conn->link);
- conn_remove(link);
+ if (link->link == conn) {
+ conn_unlink(conn, conn->link);
+ conn_remove(link);
+ } else
+ queue_remove(link->links, conn);
}
+ queue_destroy(conn->links, conn_remove);
+
queue_remove(conn->dev->conns, conn);
free(conn->data);
@@ -1225,7 +1233,7 @@ static struct btdev_conn *find_bis_index(const struct btdev *remote,
conn = entry->data;
/* Skip if not a broadcast */
- if (conn->type != HCI_ISODATA_PKT || conn->link)
+ if (conn->type != HCI_ISODATA_PKT && conn->handle < BIS_HANDLE)
continue;
if (!index)
@@ -1247,11 +1255,22 @@ static struct btdev_conn *conn_link_bis(struct btdev *dev, struct btdev *remote,
if (!bis)
return NULL;
- conn = conn_add_bis(dev, ISO_HANDLE, bis->data);
+ conn = conn_add_bis(dev, BIS_HANDLE, bis->data);
if (!conn)
return NULL;
- bis->link = conn;
+ if (!bis->link) {
+ bis->link = conn;
+ } else {
+ if (!bis->links)
+ bis->links = queue_new();
+
+ if (!queue_push_tail(bis->links, conn)) {
+ conn_remove(conn);
+ return NULL;
+ }
+ }
+
conn->link = bis;
util_debug(dev->debug_callback, dev->debug_data,
@@ -5466,6 +5485,9 @@ static void le_pa_sync_estabilished(struct btdev *dev, struct btdev *remote,
struct le_ext_adv *ext_adv;
uint16_t sync_handle = SYNC_HANDLE;
+ if (!remote)
+ return;
+
per_adv = queue_find(dev->le_per_adv, match_dev, remote);
if (!per_adv)
return;
@@ -6025,6 +6047,258 @@ static void set_le_50_commands(struct btdev *btdev)
btdev->cmds = cmd_le_5_0;
}
+static void le_past_received_event(struct btdev_conn *acl,
+ struct bt_hci_evt_le_past_recv *ev,
+ struct le_per_adv *pa)
+{
+ struct btdev *remote;
+
+ le_meta_event(acl->dev, BT_HCI_EVT_LE_PAST_RECEIVED, ev, sizeof(*ev));
+
+ if (ev->status != BT_HCI_ERR_SUCCESS)
+ return;
+
+ remote = find_btdev_by_bdaddr_type(pa->addr, pa->addr_type);
+ if (!remote)
+ return;
+
+ switch (acl->past_mode) {
+ case 0x01:
+ /* HCI_LE_Periodic_Advertising_Report events will be
+ * disabled.
+ */
+ break;
+ case 0x02:
+ /* HCI_LE_Periodic_Advertising_Report events will be enabled
+ * with duplicate filtering disabled.
+ */
+ case 0x03:
+ /* HCI_LE_Periodic_Advertising_Report events will be enabled
+ * with duplicate filtering enabled.
+ */
+ send_pa(acl->dev, remote, 0, pa->sync_handle);
+ break;
+ }
+}
+
+static void le_past_received(struct btdev_conn *acl, struct le_per_adv *pa)
+{
+ struct btdev *dev = acl->dev;
+ struct bt_hci_evt_le_past_recv ev;
+ struct le_per_adv *cp;
+ uint16_t sync_handle = SYNC_HANDLE;
+
+ /* 0x00:
+ * No attempt is made to synchronize to the periodic advertising and no
+ * HCI_LE_Periodic_Advertising_Sync_Transfer_Received event is sent to
+ * the Host.
+ */
+ if (!acl->past_mode)
+ return;
+
+ memset(&ev, 0, sizeof(ev));
+ ev.status = BT_HCI_ERR_SUCCESS;
+
+ /* Create a copy of the PA sync */
+ cp = le_per_adv_new(dev, pa->addr_type, pa->addr, pa->sid);
+ if (!cp) {
+ ev.status = BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
+ goto done;
+ }
+
+ /* Find the next available sync handle */
+ while (queue_find(dev->le_per_adv, match_sync_handle,
+ UINT_TO_PTR(sync_handle)))
+ sync_handle++;
+
+ cp->sync_handle = sync_handle;
+
+ ev.handle = cpu_to_le16(acl->handle);
+ ev.sync_handle = cpu_to_le16(cp->sync_handle);
+ ev.sid = cpu_to_le16(cp->sid);
+ ev.addr_type = cp->addr_type;
+ memcpy(ev.addr, cp->addr, sizeof(ev.addr));
+ ev.phy = 0x01;
+ ev.interval = acl->dev->le_pa_min_interval;
+ ev.clock_accuracy = 0x07;
+
+done:
+ le_past_received_event(acl, &ev, pa);
+}
+
+static int cmd_past(struct btdev *dev, const void *data, uint8_t len)
+{
+ const struct bt_hci_cmd_le_past *cmd = data;
+ struct bt_hci_rsp_le_past rsp;
+ struct le_per_adv *pa;
+ struct btdev_conn *acl = NULL;
+
+ memset(&rsp, 0, sizeof(rsp));
+
+ rsp.status = BT_HCI_ERR_SUCCESS;
+ rsp.handle = cmd->handle;
+
+ pa = queue_find(dev->le_per_adv, match_sync_handle,
+ UINT_TO_PTR(le16_to_cpu(cmd->sync_handle)));
+ if (!pa) {
+ /* If the periodic advertising train corresponding to the
+ * Sync_Handle parameter does not exist, the Controller shall
+ * return the error code Unknown Advertising Identifier (0x42).
+ */
+ rsp.status = BT_HCI_ERR_UNKNOWN_ADVERTISING_ID;
+ goto done;
+ }
+
+ acl = queue_find(dev->conns, match_handle,
+ UINT_TO_PTR(le16_to_cpu(cmd->handle)));
+ if (!acl) {
+ /* If the Connection_Handle parameter does not identify a
+ * current connection, the Controller shall return the error
+ * code Unknown Connection Identifier (0x02).
+ */
+ rsp.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
+ goto done;
+ }
+
+done:
+ cmd_complete(dev, BT_HCI_CMD_LE_PAST, &rsp, sizeof(rsp));
+
+ if (rsp.status == BT_HCI_ERR_SUCCESS)
+ le_past_received(acl->link, pa);
+
+ return 0;
+}
+
+static void le_past_info_received(struct btdev_conn *acl, struct le_ext_adv *ea)
+{
+ struct btdev *dev = acl->dev;
+ struct bt_hci_evt_le_past_recv ev;
+ struct le_per_adv *pa;
+ uint16_t sync_handle = SYNC_HANDLE;
+
+ /* 0x00:
+ * No attempt is made to synchronize to the periodic advertising and no
+ * HCI_LE_Periodic_Advertising_Sync_Transfer_Received event is sent to
+ * the Host.
+ */
+ if (!acl->past_mode)
+ return;
+
+ memset(&ev, 0, sizeof(ev));
+ ev.status = BT_HCI_ERR_SUCCESS;
+
+ /* Create a copy using EA parameters */
+ pa = le_per_adv_new(dev, ea->own_addr_type,
+ ea->own_addr_type ? ea->random_addr :
+ acl->link->dev->bdaddr, ea->sid);
+ if (!pa) {
+ ev.status = BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
+ goto done;
+ }
+
+ /* Find the next available sync handle */
+ while (queue_find(dev->le_per_adv, match_sync_handle,
+ UINT_TO_PTR(sync_handle)))
+ sync_handle++;
+
+ pa->sync_handle = sync_handle;
+
+ ev.handle = cpu_to_le16(acl->handle);
+ ev.sync_handle = cpu_to_le16(pa->sync_handle);
+ ev.sid = cpu_to_le16(pa->sid);
+ ev.addr_type = pa->addr_type;
+ memcpy(ev.addr, pa->addr, sizeof(ev.addr));
+ ev.phy = 0x01;
+ ev.interval = acl->dev->le_pa_min_interval;
+ ev.clock_accuracy = 0x07;
+
+done:
+ le_past_received_event(acl, &ev, pa);
+}
+
+static int cmd_past_set_info(struct btdev *dev, const void *data, uint8_t len)
+{
+ const struct bt_hci_cmd_le_past_set_info *cmd = data;
+ struct bt_hci_rsp_le_past_set_info rsp;
+ struct le_ext_adv *ea;
+ struct btdev_conn *acl = NULL;
+
+ memset(&rsp, 0, sizeof(rsp));
+
+ rsp.status = BT_HCI_ERR_SUCCESS;
+ rsp.handle = cmd->handle;
+
+ ea = queue_find(dev->le_ext_adv, match_ext_adv_handle,
+ UINT_TO_PTR(cmd->adv_handle));
+ if (!ea) {
+ /* If the advertising set corresponding to the
+ * Advertising_Handle parameter does not exist, the Controller
+ * shall return the error code Unknown Advertising Identifier
+ * (0x42).
+ */
+ rsp.status = BT_HCI_ERR_UNKNOWN_ADVERTISING_ID;
+ goto done;
+ }
+
+ if (!dev->le_pa_enable) {
+ /* If periodic advertising is not currently in progress for the
+ * advertising set, the Controller shall return the error code
+ * Command Disallowed (0x0C).
+ */
+ rsp.status = BT_HCI_ERR_COMMAND_DISALLOWED;
+ goto done;
+ }
+
+ acl = queue_find(dev->conns, match_handle,
+ UINT_TO_PTR(le16_to_cpu(cmd->handle)));
+ if (!acl) {
+ /* If the Connection_Handle parameter does not identify a
+ * current connection, the Controller shall return the error
+ * code Unknown Connection Identifier (0x02).
+ */
+ rsp.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
+ goto done;
+ }
+
+done:
+ cmd_complete(dev, BT_HCI_CMD_LE_PAST_SET_INFO, &rsp, sizeof(rsp));
+
+ if (rsp.status == BT_HCI_ERR_SUCCESS)
+ le_past_info_received(acl->link, ea);
+
+ return 0;
+}
+
+static int cmd_past_params(struct btdev *dev, const void *data, uint8_t len)
+{
+ const struct bt_hci_cmd_le_past_params *cmd = data;
+ struct bt_hci_rsp_le_past_set_info rsp;
+ struct btdev_conn *acl = NULL;
+
+ memset(&rsp, 0, sizeof(rsp));
+
+ rsp.status = BT_HCI_ERR_SUCCESS;
+ rsp.handle = cmd->handle;
+
+ acl = queue_find(dev->conns, match_handle,
+ UINT_TO_PTR(le16_to_cpu(cmd->handle)));
+ if (!acl) {
+ /* If the Connection_Handle parameter does not identify a
+ * current connection, the Controller shall return the error
+ * code Unknown Connection Identifier (0x02).
+ */
+ rsp.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
+ goto done;
+ }
+
+ acl->past_mode = cmd->mode;
+
+done:
+ cmd_complete(dev, BT_HCI_CMD_LE_PAST_PARAMS, &rsp, sizeof(rsp));
+
+ return 0;
+}
+
static int cmd_read_size_v2(struct btdev *dev, const void *data,
uint8_t len)
{
@@ -6062,19 +6336,19 @@ static int find_cig(struct btdev *dev, uint8_t cig_id)
static uint16_t make_cis_handle(uint8_t cig_idx, uint8_t cis_idx)
{
/* Put CIG+CIS idxs to handle so don't need to track separately */
- return ISO_HANDLE + cig_idx*CIS_SIZE + cis_idx;
+ return CIS_HANDLE + cig_idx*CIS_SIZE + cis_idx;
}
static int parse_cis_handle(uint16_t handle, int *cis_idx)
{
int cig_idx;
- if (handle < ISO_HANDLE || handle >= ISO_HANDLE + CIS_SIZE*CIG_SIZE)
+ if (handle < CIS_HANDLE || handle >= CIS_HANDLE + CIS_SIZE*CIG_SIZE)
return -1;
- cig_idx = (handle - ISO_HANDLE) / CIS_SIZE;
+ cig_idx = (handle - CIS_HANDLE) / CIS_SIZE;
if (cis_idx)
- *cis_idx = (handle - ISO_HANDLE) % CIS_SIZE;
+ *cis_idx = (handle - CIS_HANDLE) % CIS_SIZE;
return cig_idx;
}
@@ -6514,7 +6788,7 @@ static int cmd_create_big_complete(struct btdev *dev, const void *data,
for (i = 0; i < cmd->num_bis; i++) {
struct btdev_conn *conn;
- conn = conn_add_bis(dev, ISO_HANDLE + i, bis);
+ conn = conn_add_bis(dev, BIS_HANDLE + i, bis);
if (!conn) {
queue_remove(dev->le_big, big);
le_big_free(big);
@@ -6691,17 +6965,28 @@ static int cmd_big_create_sync_complete(struct btdev *dev, const void *data,
struct bt_hci_bis *bis;
int i;
uint16_t sync_handle = le16_to_cpu(cmd->sync_handle);
- struct le_per_adv *per_adv = queue_find(dev->le_per_adv,
- match_sync_handle, UINT_TO_PTR(sync_handle));
+ struct le_per_adv *per_adv;
struct le_big *big;
- if (!per_adv)
+ memset(&pdu.ev, 0, sizeof(pdu.ev));
+
+ per_adv = queue_find(dev->le_per_adv, match_sync_handle,
+ UINT_TO_PTR(sync_handle));
+ if (!per_adv) {
+ pdu.ev.status = BT_HCI_ERR_UNKNOWN_ADVERTISING_ID;
+ le_meta_event(dev, BT_HCI_EVT_LE_BIG_SYNC_ESTABILISHED, &pdu,
+ sizeof(pdu.ev));
return 0;
+ }
remote = find_btdev_by_bdaddr_type(per_adv->addr,
per_adv->addr_type);
- if (!remote)
+ if (!remote) {
+ pdu.ev.status = BT_HCI_ERR_UNKNOWN_ADVERTISING_ID;
+ le_meta_event(dev, BT_HCI_EVT_LE_BIG_SYNC_ESTABILISHED, &pdu,
+ sizeof(pdu.ev));
return 0;
+ }
big = le_big_new(dev, cmd->handle);
if (!big) {
@@ -6711,8 +6996,6 @@ static int cmd_big_create_sync_complete(struct btdev *dev, const void *data,
return 0;
}
- memset(&pdu.ev, 0, sizeof(pdu.ev));
-
for (i = 0; i < cmd->num_bis; i++) {
conn = conn_link_bis(dev, remote, i);
if (!conn)
@@ -6992,6 +7275,9 @@ static int cmd_config_data_path(struct btdev *dev, const void *data,
}
#define CMD_LE_52 \
+ CMD(BT_HCI_CMD_LE_PAST, cmd_past, NULL), \
+ CMD(BT_HCI_CMD_LE_PAST_SET_INFO, cmd_past_set_info, NULL), \
+ CMD(BT_HCI_CMD_LE_PAST_PARAMS, cmd_past_params, NULL), \
CMD(BT_HCI_CMD_LE_READ_BUFFER_SIZE_V2, cmd_read_size_v2, NULL), \
CMD(BT_HCI_CMD_LE_READ_ISO_TX_SYNC, cmd_read_iso_tx_sync, NULL), \
CMD(BT_HCI_CMD_LE_SET_EVENT_MASK, cmd_le_set_event_mask, NULL), \
@@ -7036,6 +7322,9 @@ static const struct btdev_cmd cmd_le_5_2[] = {
static void set_le_52_commands(struct btdev *btdev)
{
+ btdev->commands[40] |= BIT(6); /* LE PAST */
+ btdev->commands[40] |= BIT(7); /* LE PA Set Info Transfer */
+ btdev->commands[41] |= BIT(1); /* LE PAST Parameters */
btdev->commands[41] |= 0x20; /* LE Read Buffer Size v2 */
btdev->commands[41] |= 0x40; /* LE Read ISO TX Sync */
btdev->commands[41] |= 0x80; /* LE Set CIG Parameters */
@@ -7317,6 +7606,8 @@ static void set_bredrle_features(struct btdev *btdev)
if (btdev->type >= BTDEV_TYPE_BREDRLE52) {
btdev->le_features[1] |= 0x20; /* LE PER ADV */
+ btdev->le_features[3] |= BIT(0); /* LE PAST Sender */
+ btdev->le_features[3] |= BIT(1); /* LE PAST Receiver */
btdev->le_features[3] |= 0x10; /* LE CIS Central */
btdev->le_features[3] |= 0x20; /* LE CIS Peripheral */
btdev->le_features[3] |= 0x40; /* LE ISO Broadcaster */
diff --git a/emulator/bthost.c b/emulator/bthost.c
index c85f751cc7a8..8a6d397fe346 100644
--- a/emulator/bthost.c
+++ b/emulator/bthost.c
@@ -1834,6 +1834,24 @@ static void evt_le_big_sync_established(struct bthost *bthost,
}
}
+static void evt_le_big_info_adv_report(struct bthost *bthost,
+ const void *data, uint8_t size)
+{
+ const struct bt_hci_evt_le_big_info_adv_report *ev = data;
+ struct {
+ struct bt_hci_cmd_le_big_create_sync cp;
+ struct bt_hci_bis_sync index[1];
+ } cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.cp.handle = 0x01;
+ cmd.cp.sync_handle = ev->sync_handle;
+ cmd.cp.encryption = ev->encryption;
+ cmd.cp.num_bis = 1;
+
+ send_command(bthost, BT_HCI_CMD_LE_BIG_CREATE_SYNC, &cmd, sizeof(cmd));
+}
+
static void evt_le_meta_event(struct bthost *bthost, const void *data,
uint8_t len)
{
@@ -1876,6 +1894,9 @@ static void evt_le_meta_event(struct bthost *bthost, const void *data,
case BT_HCI_EVT_LE_BIG_SYNC_ESTABILISHED:
evt_le_big_sync_established(bthost, evt_data, len - 1);
break;
+ case BT_HCI_EVT_LE_BIG_INFO_ADV_REPORT:
+ evt_le_big_info_adv_report(bthost, evt_data, len - 1);
+ break;
default:
bthost_debug(bthost, "Unsupported LE Meta event 0x%2.2x",
*event);
@@ -3624,6 +3645,28 @@ void bthost_set_pa_enable(struct bthost *bthost, uint8_t enable)
send_command(bthost, BT_HCI_CMD_LE_SET_PA_ENABLE, &cp, sizeof(cp));
}
+void bthost_set_past_mode(struct bthost *bthost, uint16_t handle, uint8_t mode)
+{
+ struct bt_hci_cmd_le_past_params cp;
+
+ memset(&cp, 0, sizeof(cp));
+ cp.handle = cpu_to_le16(handle);
+ cp.mode = mode;
+
+ send_command(bthost, BT_HCI_CMD_LE_PAST_PARAMS, &cp, sizeof(cp));
+}
+
+void bthost_past_set_info(struct bthost *bthost, uint16_t handle)
+{
+ struct bt_hci_cmd_le_past_set_info cp;
+
+ memset(&cp, 0, sizeof(cp));
+ cp.handle = cpu_to_le16(handle);
+ cp.adv_handle = 0x01;
+
+ send_command(bthost, BT_HCI_CMD_LE_PAST_SET_INFO, &cp, sizeof(cp));
+}
+
void bthost_create_big(struct bthost *bthost, uint8_t num_bis,
uint8_t enc, const uint8_t *bcode)
{
diff --git a/emulator/bthost.h b/emulator/bthost.h
index 743615838c25..3e828a198c1a 100644
--- a/emulator/bthost.h
+++ b/emulator/bthost.h
@@ -119,8 +119,10 @@ void bthost_set_ext_adv_enable(struct bthost *bthost, uint8_t enable);
void bthost_set_pa_params(struct bthost *bthost);
void bthost_set_pa_data(struct bthost *bthost, const uint8_t *data,
uint8_t len);
+void bthost_set_past_mode(struct bthost *bthost, uint16_t handle, uint8_t mode);
void bthost_set_base(struct bthost *bthost, const uint8_t *data, uint8_t len);
void bthost_set_pa_enable(struct bthost *bthost, uint8_t enable);
+void bthost_past_set_info(struct bthost *bthost, uint16_t handle);
void bthost_create_big(struct bthost *bthost, uint8_t num_bis, uint8_t enc,
const uint8_t *bcode);
bool bthost_search_ext_adv_addr(struct bthost *bthost, const uint8_t *addr);
@@ -130,7 +132,6 @@ void bthost_set_cig_params(struct bthost *bthost, uint8_t cig_id,
void bthost_create_cis(struct bthost *bthost, uint16_t cis_handle,
uint16_t acl_handle);
-
void bthost_set_scan_params(struct bthost *bthost, uint8_t scan_type,
uint8_t addr_type, uint8_t filter_policy);
void bthost_set_scan_enable(struct bthost *bthost, uint8_t enable);
--
2.51.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH BlueZ v2 03/13] iso-tester: Add tests for PAST procedures
2025-10-09 21:29 [PATCH BlueZ v2 01/13] monitor: Use PAST to refer to Periodic Advertising Sync Transfer Luiz Augusto von Dentz
2025-10-09 21:29 ` [PATCH BlueZ v2 02/13] emulator: Add initial support for PAST Luiz Augusto von Dentz
@ 2025-10-09 21:29 ` Luiz Augusto von Dentz
2025-10-09 21:29 ` [PATCH BlueZ v2 04/13] monitor: Add support for PAST MGMT settings and flags Luiz Augusto von Dentz
` (10 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2025-10-09 21:29 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This introduces the following tests that test PAST procedures both as
a sender, either for colocated broadcast source or a third peer, and as
receiver:
ISO Broadcaster PAST Info - Success
ISO Broadcaster PAST Info RPA - Success
ISO Broadcaster PAST Sender - Success
ISO Broadcaster PAST Receiver - Success
---
tools/iso-tester.c | 292 +++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 279 insertions(+), 13 deletions(-)
diff --git a/tools/iso-tester.c b/tools/iso-tester.c
index 0eeab4fd7108..4bf1a287bc68 100644
--- a/tools/iso-tester.c
+++ b/tools/iso-tester.c
@@ -488,6 +488,8 @@ struct iso_client_data {
const struct iovec *recv;
bool server;
bool bcast;
+ bool past;
+ bool rpa;
bool defer;
bool disconnect;
bool ts;
@@ -1381,6 +1383,28 @@ static const struct iso_client_data bcast_16_2_1_send = {
.base_len = sizeof(base_lc3_16_2_1),
};
+static const struct iso_client_data past_16_2_1_send = {
+ .qos = QOS_OUT_16_2_1,
+ .expect_err = 0,
+ .send = &send_16_2_1,
+ .bcast = true,
+ .past = true,
+ .rpa = true,
+ .base = base_lc3_16_2_1,
+ .base_len = sizeof(base_lc3_16_2_1),
+};
+
+static const struct iso_client_data past_16_2_1 = {
+ .qos = QOS_OUT_16_2_1,
+ .expect_err = 0,
+ .recv = &send_16_2_1,
+ .bcast = true,
+ .past = true,
+ .big = true,
+ .base = base_lc3_16_2_1,
+ .base_len = sizeof(base_lc3_16_2_1),
+};
+
static const struct iso_client_data bcast_enc_16_2_1_send = {
.qos = QOS_OUT_ENC_16_2_1,
.expect_err = 0,
@@ -1446,6 +1470,16 @@ static const struct iso_client_data bcast_16_2_1_recv = {
.big = true,
};
+static const struct iso_client_data past_16_2_1_recv = {
+ .qos = QOS_IN_16_2_1,
+ .expect_err = 0,
+ .recv = &send_16_2_1,
+ .bcast = true,
+ .past = true,
+ .server = true,
+ .big = true,
+};
+
static const struct iso_client_data bcast_16_2_1_recv2 = {
.qos = QOS_IN_16_2_1,
.expect_err = 0,
@@ -1594,6 +1628,7 @@ static void client_connectable_complete(uint16_t opcode, uint8_t status,
{
struct test_data *data = user_data;
static uint8_t client_num;
+ const struct iso_client_data *isodata = data->test_data;
if (opcode != BT_HCI_CMD_LE_SET_EXT_ADV_ENABLE)
return;
@@ -1606,7 +1641,8 @@ static void client_connectable_complete(uint16_t opcode, uint8_t status,
if (status)
tester_setup_failed();
else if (data->client_num == client_num) {
- tester_setup_complete();
+ if (!isodata || !isodata->past)
+ tester_setup_complete();
client_num = 0;
}
}
@@ -1641,6 +1677,8 @@ static void iso_new_conn(uint16_t handle, void *user_data)
{
struct test_data *data = user_data;
struct bthost *host;
+ const struct iso_client_data *isodata = data->test_data;
+ static uint8_t client_num;
tester_print("New client connection with handle 0x%04x", handle);
@@ -1649,6 +1687,14 @@ static void iso_new_conn(uint16_t handle, void *user_data)
host = hciemu_client_get_host(data->hciemu);
bthost_add_iso_hook(host, data->handle, bthost_recv_data, data,
bthost_iso_disconnected);
+
+ if (!isodata->past || data->client_num == 1)
+ return;
+
+ client_num++;
+
+ if (client_num == data->client_num)
+ tester_test_passed();
}
static uint8_t iso_accept_conn(uint16_t handle, void *user_data)
@@ -1664,10 +1710,73 @@ static uint8_t iso_accept_conn(uint16_t handle, void *user_data)
static void acl_new_conn(uint16_t handle, void *user_data)
{
struct test_data *data = user_data;
+ const struct iso_client_data *isodata = data->test_data;
tester_print("New ACL connection with handle 0x%04x", handle);
data->acl_handle = handle;
+
+ if (!isodata->past)
+ return;
+
+ tester_setup_complete();
+
+ if (!isodata->server) {
+ struct bthost *host;
+
+ host = hciemu_client_get_host(data->hciemu);
+ bthost_set_past_mode(host, data->acl_handle, 0x03);
+ }
+}
+
+static void setup_connect_recv(struct test_data *data, struct bthost *host)
+{
+ const uint8_t *bdaddr;
+
+ bdaddr = hciemu_get_central_bdaddr(data->hciemu);
+ bthost_set_connect_cb(host, acl_new_conn, data);
+ bthost_hci_connect(host, bdaddr, BDADDR_LE_PUBLIC);
+}
+
+static void setup_past_complete(uint8_t status, uint16_t length,
+ const void *param, void *user_data)
+{
+ struct test_data *data = tester_get_data();
+ struct bthost *host = user_data;
+
+ if (status != MGMT_STATUS_SUCCESS) {
+ tester_setup_failed();
+ return;
+ }
+
+ tester_print("Set device flags status 0x%02x", status);
+
+ setup_connect_recv(data, host);
+}
+
+static void setup_past_recv(struct test_data *data, struct bthost *host)
+{
+ struct mgmt_cp_add_device add;
+ struct mgmt_cp_set_device_flags set;
+
+ memset(&add, 0, sizeof(add));
+ bacpy(&add.addr.bdaddr,
+ (bdaddr_t *)hciemu_get_client_bdaddr(data->hciemu));
+ add.addr.type = BDADDR_LE_PUBLIC;
+ add.action = 0x01; /* Allow incoming connection */
+
+ mgmt_send(data->mgmt, MGMT_OP_ADD_DEVICE, data->mgmt_index,
+ sizeof(add), &add, NULL, NULL, NULL);
+
+ memset(&set, 0, sizeof(set));
+ bacpy(&set.addr.bdaddr,
+ (bdaddr_t *)hciemu_get_client_bdaddr(data->hciemu));
+ set.addr.type = BDADDR_LE_PUBLIC;
+ set.current_flags = BIT(3);
+
+ mgmt_send(data->mgmt, MGMT_OP_SET_DEVICE_FLAGS, data->mgmt_index,
+ sizeof(set), &set, setup_past_complete, host,
+ NULL);
}
static void setup_powered_callback(uint8_t status, uint16_t length,
@@ -1716,18 +1825,17 @@ static void setup_powered_callback(uint8_t status, uint16_t length,
bthost_set_base(host, isodata->base,
isodata->base_len);
- if (isodata->big)
+ if (isodata->big && (!isodata->past ||
+ i + 1 == data->client_num))
bthost_create_big(host, 1,
isodata->qos.bcast.encryption,
isodata->qos.bcast.bcode);
- } else if (!isodata->send && isodata->recv) {
- const uint8_t *bdaddr;
+ if (isodata->past)
+ setup_past_recv(data, host);
- bdaddr = hciemu_get_central_bdaddr(data->hciemu);
- bthost_set_connect_cb(host, acl_new_conn, data);
- bthost_hci_connect(host, bdaddr, BDADDR_LE_PUBLIC);
- }
+ } else if (!isodata->send && isodata->recv)
+ setup_connect_recv(data, host);
}
}
@@ -1739,7 +1847,7 @@ static void setup_powered(const void *test_data)
tester_print("Powering on controller");
- if (!isodata || !isodata->bcast)
+ if (!isodata || !isodata->bcast || isodata->past)
mgmt_send(data->mgmt, MGMT_OP_SET_CONNECTABLE, data->mgmt_index,
sizeof(param), param,
NULL, NULL, NULL);
@@ -1750,7 +1858,16 @@ static void setup_powered(const void *test_data)
mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
sizeof(param), param, NULL, NULL, NULL);
- if (isodata && isodata->server && !isodata->bcast)
+ if (isodata && isodata->rpa) {
+ const uint8_t params[] = { 0x01,
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
+
+ mgmt_send(data->mgmt, MGMT_OP_SET_PRIVACY, data->mgmt_index,
+ sizeof(params), params, NULL, NULL, NULL);
+ }
+
+ if (isodata && ((isodata->server && !isodata->bcast) || isodata->past))
mgmt_send(data->mgmt, MGMT_OP_SET_ADVERTISING,
data->mgmt_index, sizeof(param), param, NULL,
NULL, NULL);
@@ -1905,6 +2022,7 @@ static int create_iso_sock(struct test_data *data)
addr->iso_bc->bc_sid = isodata->sid;
err = bind(sk, (struct sockaddr *) addr, sizeof(*addr) +
sizeof(*addr->iso_bc));
+ free(addr);
} else {
addr = malloc(sizeof(*addr));
memset(addr, 0, sizeof(*addr));
@@ -1912,6 +2030,7 @@ static int create_iso_sock(struct test_data *data)
bacpy(&addr->iso_bdaddr, (void *) master_bdaddr);
addr->iso_bdaddr_type = BDADDR_LE_PUBLIC;
err = bind(sk, (struct sockaddr *) addr, sizeof(*addr));
+ free(addr);
}
if (err < 0) {
@@ -2520,6 +2639,9 @@ static gboolean iso_pollout(GIOChannel *io, GIOCondition cond,
const struct iso_client_data *isodata = data->test_data;
unsigned int count;
+ if (isodata->past && !data->handle)
+ return TRUE;
+
data->io_id[0] = 0;
tester_print("POLLOUT event received");
@@ -2533,6 +2655,8 @@ static gboolean iso_pollout(GIOChannel *io, GIOCondition cond,
iso_send_data(data, io);
if (isodata->bcast) {
+ if (isodata->past)
+ return FALSE;
tester_test_passed();
return FALSE;
}
@@ -2588,6 +2712,84 @@ static void trigger_force_suspend(void *user_data)
hook_set_event_mask, data);
}
+static int iso_rebind_bcast_dst(struct test_data *data, int sk)
+{
+ struct hciemu_client *client;
+ const uint8_t *dst;
+ struct sockaddr_iso *addr = NULL;
+ int err;
+
+ client = hciemu_get_client(data->hciemu, 0);
+
+ /* Bind to local address */
+ addr = malloc(sizeof(*addr) + sizeof(*addr->iso_bc));
+ memset(addr, 0, sizeof(*addr) + sizeof(*addr->iso_bc));
+ addr->iso_family = AF_BLUETOOTH;
+
+ /* Bind to destination address in case of broadcast */
+ dst = hciemu_client_bdaddr(client);
+ if (!dst) {
+ tester_warn("No destination bdaddr");
+ free(addr);
+ return -ENODEV;
+ }
+
+ bacpy(&addr->iso_bc->bc_bdaddr, (void *) dst);
+ addr->iso_bc->bc_bdaddr_type = BDADDR_LE_PUBLIC;
+
+ err = bind(sk, (struct sockaddr *) addr, sizeof(*addr) +
+ sizeof(*addr->iso_bc));
+ if (err)
+ tester_warn("bind: %s (%d)", strerror(errno), errno);
+ else
+ tester_print("PAST in progress...");
+
+ free(addr);
+
+ return err;
+}
+
+static bool check_rpa(struct test_data *data, int sk)
+{
+ const struct iso_client_data *isodata = data->test_data;
+ struct sockaddr_iso addr;
+ socklen_t olen;
+ const uint8_t *src;
+
+ if (!isodata->rpa)
+ return true;
+
+ src = hciemu_get_central_bdaddr(data->hciemu);
+ if (!src) {
+ tester_warn("No source bdaddr");
+ return false;
+ }
+
+ olen = sizeof(addr);
+
+ memset(&addr, 0, olen);
+ if (getsockname(sk, (void *)&addr, &olen) < 0) {
+ tester_warn("getsockname: %s (%d)", strerror(errno), errno);
+ return false;
+ }
+
+ /* Compare socket source address (RPA) with central address, if they
+ * match it means the RPA has not been set.
+ */
+ if (!bacmp(&addr.iso_bdaddr, (bdaddr_t *)src)) {
+ char a1[18], a2[18];
+
+ ba2str(&addr.iso_bdaddr, a1);
+ ba2str((bdaddr_t *)src, a2);
+
+ tester_warn("rpa %s == %s id", a1, a2);
+ return false;
+
+ }
+
+ return true;
+}
+
static gboolean iso_connect(GIOChannel *io, GIOCondition cond,
gpointer user_data)
{
@@ -2616,8 +2818,11 @@ static gboolean iso_connect(GIOChannel *io, GIOCondition cond,
if (!isodata->bcast) {
ret = check_ucast_qos(&qos, &isodata->qos,
isodata->mconn ? &isodata->qos_2 : NULL);
- } else if (!isodata->server)
+ } else if (!isodata->server) {
ret = check_bcast_qos(&qos, &isodata->qos);
+ if (ret && isodata->past)
+ ret = iso_rebind_bcast_dst(data, sk) == 0;
+ }
if (!ret) {
tester_warn("Unexpected QoS parameter");
@@ -2692,8 +2897,15 @@ static gboolean iso_connect(GIOChannel *io, GIOCondition cond,
if (err < 0)
tester_warn("Connect failed: %s (%d)", strerror(-err), -err);
- else
+ else {
+ if (!check_rpa(data, sk)) {
+ data->step = 0;
+ tester_test_failed();
+ return FALSE;
+ }
+
tester_print("Successfully connected");
+ }
if (err != isodata->expect_err) {
tester_warn("Expect error: %s (%d) != %s (%d)",
@@ -3025,6 +3237,17 @@ fail:
return err;
}
+static gboolean test_listen_past(gpointer user_data)
+{
+ struct test_data *data = tester_get_data();
+ struct bthost *host;
+
+ host = hciemu_client_get_host(data->hciemu);
+ bthost_past_set_info(host, data->acl_handle);
+
+ return FALSE;
+}
+
static void setup_listen_many(struct test_data *data, uint8_t n, uint8_t *num,
GIOFunc *func)
{
@@ -3070,7 +3293,18 @@ static void setup_listen_many(struct test_data *data, uint8_t n, uint8_t *num,
host = hciemu_client_host(client);
bthost_set_cig_params(host, 0x01, 0x01, &isodata->qos);
- bthost_create_cis(host, 257, data->acl_handle);
+ bthost_create_cis(host, 256, data->acl_handle);
+ } else if (isodata->past) {
+ if (!data->acl_handle) {
+ tester_print("ACL handle not set");
+ tester_test_failed();
+ return;
+ }
+
+ /* Wait for listen to take effect before initiating PAST
+ * procedure.
+ */
+ data->io_id[i] = g_timeout_add(250, test_listen_past, data);
}
}
@@ -3518,6 +3752,18 @@ static void test_bcast(const void *test_data)
setup_connect(data, 0, iso_connect_cb);
}
+static void test_past(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ uint8_t num[1] = { 1 };
+ GIOFunc funcs[1] = { iso_accept2_cb };
+
+ if (data->client_num > 1)
+ setup_listen_many(data, 1, num, funcs);
+ else
+ setup_connect(data, 0, iso_connect_cb);
+}
+
static void test_bcast_reconnect(const void *test_data)
{
struct test_data *data = tester_get_data();
@@ -3593,6 +3839,13 @@ static void test_bcast_recv2_defer(const void *test_data)
setup_listen_many(data, 2, num, funcs);
}
+static void test_past_recv(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+
+ setup_listen(data, 0, iso_accept_cb);
+}
+
static void test_connect2_suspend(const void *test_data)
{
test_connect2(test_data);
@@ -3980,6 +4233,15 @@ int main(int argc, char *argv[])
test_iso("ISO Broadcaster - Success", &bcast_16_2_1_send, setup_powered,
test_bcast);
+ test_iso("ISO Broadcaster PAST Info - Success", &past_16_2_1_send,
+ setup_powered,
+ test_past);
+ test_iso("ISO Broadcaster PAST Info RPA - Success", &past_16_2_1_send,
+ setup_powered,
+ test_past);
+ test_iso2("ISO Broadcaster PAST Sender - Success", &past_16_2_1,
+ setup_powered,
+ test_past);
test_iso("ISO Broadcaster Encrypted - Success", &bcast_enc_16_2_1_send,
setup_powered,
test_bcast);
@@ -4003,6 +4265,10 @@ int main(int argc, char *argv[])
test_iso("ISO Broadcaster Receiver - Success", &bcast_16_2_1_recv,
setup_powered,
test_bcast_recv);
+ test_iso("ISO Broadcaster PAST Receiver - Success",
+ &past_16_2_1_recv,
+ setup_powered,
+ test_past_recv);
test_iso("ISO Broadcaster Receiver SID auto - Success",
&bcast_16_2_1_recv_sid,
setup_powered,
--
2.51.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH BlueZ v2 04/13] monitor: Add support for PAST MGMT settings and flags
2025-10-09 21:29 [PATCH BlueZ v2 01/13] monitor: Use PAST to refer to Periodic Advertising Sync Transfer Luiz Augusto von Dentz
2025-10-09 21:29 ` [PATCH BlueZ v2 02/13] emulator: Add initial support for PAST Luiz Augusto von Dentz
2025-10-09 21:29 ` [PATCH BlueZ v2 03/13] iso-tester: Add tests for PAST procedures Luiz Augusto von Dentz
@ 2025-10-09 21:29 ` Luiz Augusto von Dentz
2025-10-09 21:29 ` [PATCH BlueZ v2 05/13] MGMT: Add PAST Settings and Flags Luiz Augusto von Dentz
` (9 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2025-10-09 21:29 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This adds parising support for PAST MGMT settings and device flags.
---
monitor/packet.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/monitor/packet.c b/monitor/packet.c
index f7db1cbb88c6..dd808deaa79f 100644
--- a/monitor/packet.c
+++ b/monitor/packet.c
@@ -14424,6 +14424,8 @@ static const struct bitfield_data mgmt_settings_table[] = {
{ 20, "ISO Broadcaster" },
{ 21, "Sync Receiver" },
{ 22, "LL Privacy" },
+ { 23, "PAST Sender" },
+ { 24, "PAST Receiver" },
{}
};
@@ -15852,6 +15854,7 @@ static const struct bitfield_data mgmt_added_device_flags_table[] = {
{ 0, "Remote Wakeup" },
{ 1, "Device Privacy Mode" },
{ 2, "Address Resolution" },
+ { 3, "PAST" },
{ }
};
--
2.51.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH BlueZ v2 05/13] MGMT: Add PAST Settings and Flags
2025-10-09 21:29 [PATCH BlueZ v2 01/13] monitor: Use PAST to refer to Periodic Advertising Sync Transfer Luiz Augusto von Dentz
` (2 preceding siblings ...)
2025-10-09 21:29 ` [PATCH BlueZ v2 04/13] monitor: Add support for PAST MGMT settings and flags Luiz Augusto von Dentz
@ 2025-10-09 21:29 ` Luiz Augusto von Dentz
2025-10-09 21:29 ` [PATCH BlueZ v2 06/13] device: Add initial support for setting DEVICE_FLAG_PAST Luiz Augusto von Dentz
` (8 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2025-10-09 21:29 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This adds PAST Settings and Flags definitions and documentation.
---
doc/mgmt.rst | 3 +++
lib/bluetooth/mgmt.h | 3 +++
2 files changed, 6 insertions(+)
diff --git a/doc/mgmt.rst b/doc/mgmt.rst
index 5ffc766bddc4..3fca69ed0b6e 100644
--- a/doc/mgmt.rst
+++ b/doc/mgmt.rst
@@ -319,6 +319,8 @@ following available bits:
20, Isochronous Broadcaster
21, Synchronized Receiver
22, LL Privacy
+ 23, PAST Sender
+ 24, PAST Receiver
This command generates a Command Complete event on success or a Command Status
event on failure.
@@ -3581,6 +3583,7 @@ available bits:
0, Remote Wakeup enabled
1, Device Privacy Mode enabled
2, Address Resolution enabled
+ 3, PAST enabled
This command generates a Command Complete event on success or a Command Status
event on failure.
diff --git a/lib/bluetooth/mgmt.h b/lib/bluetooth/mgmt.h
index 2b45010d1b0b..1ad52529f0c7 100644
--- a/lib/bluetooth/mgmt.h
+++ b/lib/bluetooth/mgmt.h
@@ -105,6 +105,8 @@ struct mgmt_rp_read_index_list {
#define MGMT_SETTING_ISO_BROADCASTER BIT(20)
#define MGMT_SETTING_ISO_SYNC_RECEIVER BIT(21)
#define MGMT_SETTING_LL_PRIVACY BIT(22)
+#define MGMT_SETTING_PAST_SENDER BIT(23)
+#define MGMT_SETTING_PAST_RECEIVER BIT(24)
#define MGMT_OP_READ_INFO 0x0004
struct mgmt_rp_read_info {
@@ -680,6 +682,7 @@ struct mgmt_rp_get_device_flags {
#define DEVICE_FLAG_REMOTE_WAKEUP BIT(0)
#define DEVICE_FLAG_DEVICE_PRIVACY BIT(1)
#define DEVICE_FLAG_ADDRESS_RESOLUTION BIT(2)
+#define DEVICE_FLAG_PAST BIT(3)
#define MGMT_OP_SET_DEVICE_FLAGS 0x0050
#define MGMT_SET_DEVICE_FLAGS_SIZE 11
--
2.51.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH BlueZ v2 06/13] device: Add initial support for setting DEVICE_FLAG_PAST
2025-10-09 21:29 [PATCH BlueZ v2 01/13] monitor: Use PAST to refer to Periodic Advertising Sync Transfer Luiz Augusto von Dentz
` (3 preceding siblings ...)
2025-10-09 21:29 ` [PATCH BlueZ v2 05/13] MGMT: Add PAST Settings and Flags Luiz Augusto von Dentz
@ 2025-10-09 21:29 ` Luiz Augusto von Dentz
2025-10-09 21:29 ` [PATCH BlueZ v2 07/13] bass: Add " Luiz Augusto von Dentz
` (7 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2025-10-09 21:29 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This introduces device_set_past_support which can be used by drivers
to indicate that DEVICE_FLAG_PAST shall be changed.
---
src/adapter.c | 31 +++++++++++++++++++++++--------
src/adapter.h | 2 +-
src/device.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
src/device.h | 3 +++
4 files changed, 74 insertions(+), 9 deletions(-)
diff --git a/src/adapter.c b/src/adapter.c
index 1ee2f3a08164..4452034630f8 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -5640,6 +5640,8 @@ static void add_device_complete(uint8_t status, uint16_t length,
struct btd_adapter *adapter = user_data;
struct btd_device *dev;
char addr[18];
+ uint32_t flags;
+
if (length < sizeof(*rp)) {
btd_error(adapter->dev_id,
@@ -5669,8 +5671,7 @@ static void add_device_complete(uint8_t status, uint16_t length,
DBG("%s (%u) added to kernel connect list", addr, rp->addr.type);
if (btd_opts.device_privacy) {
- uint32_t flags = btd_device_get_current_flags(dev);
-
+ flags = btd_device_get_current_flags(dev);
/* Set Device Privacy Mode if it has not set the flag yet. */
if (!(flags & DEVICE_FLAG_DEVICE_PRIVACY)) {
/* Include the pending flags, or they may get
@@ -5682,8 +5683,18 @@ static void add_device_complete(uint8_t status, uint16_t length,
DEVICE_FLAG_DEVICE_PRIVACY,
set_device_privacy_complete,
dev);
+ return;
}
}
+
+ /* Check if any flag was marked as pending before ADD_DEVICE
+ * complete then set it now
+ */
+ flags = btd_device_get_pending_flags(dev);
+ if (flags)
+ adapter_set_device_flags(adapter, dev, flags,
+ set_device_privacy_complete,
+ dev);
}
void adapter_auto_connect_add(struct btd_adapter *adapter,
@@ -5725,7 +5736,7 @@ void adapter_auto_connect_add(struct btd_adapter *adapter,
adapter->connect_list = g_slist_append(adapter->connect_list, device);
}
-void adapter_set_device_flags(struct btd_adapter *adapter,
+int adapter_set_device_flags(struct btd_adapter *adapter,
struct btd_device *device, uint32_t flags,
mgmt_request_func_t func, void *user_data)
{
@@ -5737,14 +5748,15 @@ void adapter_set_device_flags(struct btd_adapter *adapter,
uint8_t bdaddr_type;
bool ll_privacy = btd_adapter_has_settings(adapter,
MGMT_SETTING_LL_PRIVACY);
+ unsigned int id;
if (!btd_has_kernel_features(KERNEL_CONN_CONTROL) ||
- (supported | flags) != supported)
- return;
+ (supported && (supported | flags) != supported))
+ return -EINVAL;
/* Check if changing flags are pending */
if ((current ^ flags) == (flags & pending))
- return;
+ return -EINPROGRESS;
/* Set Device Privacy Mode if it has not set the flag yet. */
if (btd_opts.device_privacy && !(flags & DEVICE_FLAG_DEVICE_PRIVACY))
@@ -5764,9 +5776,12 @@ void adapter_set_device_flags(struct btd_adapter *adapter,
cp.addr.type = bdaddr_type;
cp.current_flags = cpu_to_le32(flags);
- if (mgmt_send(adapter->mgmt, MGMT_OP_SET_DEVICE_FLAGS, adapter->dev_id,
- sizeof(cp), &cp, func, user_data, NULL))
+ id = mgmt_send(adapter->mgmt, MGMT_OP_SET_DEVICE_FLAGS, adapter->dev_id,
+ sizeof(cp), &cp, func, user_data, NULL);
+ if (id != 0)
btd_device_set_pending_flags(device, flags);
+
+ return id == 0 ? -EBUSY : 0;
}
static void device_flags_changed_callback(uint16_t index, uint16_t length,
diff --git a/src/adapter.h b/src/adapter.h
index ad81a10b1bb1..dd0c90d9cb3a 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -237,7 +237,7 @@ void adapter_connect_list_remove(struct btd_adapter *adapter,
typedef void (*adapter_set_device_flags_func_t)(uint8_t status, uint16_t length,
const void *param,
void *user_data);
-void adapter_set_device_flags(struct btd_adapter *adapter,
+int adapter_set_device_flags(struct btd_adapter *adapter,
struct btd_device *device, uint32_t flags,
adapter_set_device_flags_func_t func,
void *user_data);
diff --git a/src/device.c b/src/device.c
index 8d74ae0ea0ff..3e907858b9d3 100644
--- a/src/device.c
+++ b/src/device.c
@@ -1733,6 +1733,53 @@ void device_set_wake_allowed(struct btd_device *device, bool wake_allowed,
set_wake_allowed_complete, device);
}
+static void set_past_complete(uint8_t status, uint16_t length,
+ const void *param, void *user_data)
+{
+ const struct mgmt_rp_set_device_flags *rp = param;
+ struct btd_device *dev = user_data;
+
+ if (status != MGMT_STATUS_SUCCESS) {
+ error("Set device flags return status: %s",
+ mgmt_errstr(status));
+ return;
+ }
+
+ if (length < sizeof(*rp)) {
+ error("Too small Set Device Flags complete event: %d", length);
+ return;
+ }
+
+ btd_device_flags_changed(dev, dev->supported_flags, dev->pending_flags);
+}
+
+void device_set_past_support(struct btd_device *device, bool value)
+{
+ uint32_t flags;
+ int err;
+
+ if (btd_device_flags_enabled(device, DEVICE_FLAG_PAST) == value)
+ return;
+
+ DBG("value %s", value ? "true" : "false");
+
+ flags = device->current_flags;
+
+ /* Include the pending flags, or they may get overwritten. */
+ flags |= device->pending_flags;
+
+ if (value)
+ flags |= DEVICE_FLAG_PAST;
+ else
+ flags &= ~DEVICE_FLAG_PAST;
+
+ err = adapter_set_device_flags(device->adapter, device, flags,
+ set_past_complete, device);
+
+ if (err)
+ error("Failed to set past support: %s", strerror(-err));
+}
+
static gboolean
dev_property_get_wake_allowed(const GDBusPropertyTable *property,
DBusMessageIter *iter, void *data)
diff --git a/src/device.h b/src/device.h
index 9ff9cdfefc28..6ed8affa0d4a 100644
--- a/src/device.h
+++ b/src/device.h
@@ -158,6 +158,9 @@ void device_set_wake_support(struct btd_device *device, bool wake_support);
void device_set_wake_override(struct btd_device *device, bool wake_override);
void device_set_wake_allowed(struct btd_device *device, bool wake_allowed,
guint32 id);
+
+void device_set_past_support(struct btd_device *device, bool value);
+
void device_set_refresh_discovery(struct btd_device *dev, bool refresh);
typedef void (*disconnect_watch) (struct btd_device *device, gboolean removal,
--
2.51.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH BlueZ v2 07/13] bass: Add support for setting DEVICE_FLAG_PAST
2025-10-09 21:29 [PATCH BlueZ v2 01/13] monitor: Use PAST to refer to Periodic Advertising Sync Transfer Luiz Augusto von Dentz
` (4 preceding siblings ...)
2025-10-09 21:29 ` [PATCH BlueZ v2 06/13] device: Add initial support for setting DEVICE_FLAG_PAST Luiz Augusto von Dentz
@ 2025-10-09 21:29 ` Luiz Augusto von Dentz
2025-10-09 21:29 ` [PATCH BlueZ v2 08/13] iso.rst: Add documentation for PAST/rebind Luiz Augusto von Dentz
` (6 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2025-10-09 21:29 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This attempts to check if setting DEVICE_FLAG_PAST is possible based on
the MGMT settings.
---
profiles/audio/bass.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/profiles/audio/bass.c b/profiles/audio/bass.c
index d42740ca4afb..537c9206a71c 100644
--- a/profiles/audio/bass.c
+++ b/profiles/audio/bass.c
@@ -30,6 +30,7 @@
#include "bluetooth/bluetooth.h"
#include "bluetooth/uuid.h"
#include "bluetooth/iso.h"
+#include "bluetooth/mgmt.h"
#include "src/dbus-common.h"
#include "src/shared/util.h"
@@ -1253,8 +1254,17 @@ static void bass_data_add(struct bass_data *data)
queue_push_tail(sessions, data);
- if (data->service)
+ if (data->service) {
+ struct btd_adapter *adapter = device_get_adapter(data->device);
+ bool initiator = btd_service_is_initiator(data->service);
+
btd_service_set_user_data(data->service, data);
+ if ((!initiator && btd_adapter_has_settings(adapter,
+ MGMT_SETTING_PAST_RECEIVER)) || (initiator &&
+ btd_adapter_has_settings(adapter,
+ MGMT_SETTING_PAST_SENDER)))
+ device_set_past_support(data->device, true);
+ }
}
static bool match_data(const void *data, const void *match_data)
--
2.51.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH BlueZ v2 08/13] iso.rst: Add documentation for PAST/rebind
2025-10-09 21:29 [PATCH BlueZ v2 01/13] monitor: Use PAST to refer to Periodic Advertising Sync Transfer Luiz Augusto von Dentz
` (5 preceding siblings ...)
2025-10-09 21:29 ` [PATCH BlueZ v2 07/13] bass: Add " Luiz Augusto von Dentz
@ 2025-10-09 21:29 ` Luiz Augusto von Dentz
2025-10-09 21:29 ` [PATCH BlueZ v2 09/13] shared/bap: Add callback broadcast instances Luiz Augusto von Dentz
` (5 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2025-10-09 21:29 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This documents how to use PAST procedures by doing bind on already
connected socket.
---
doc/iso.rst | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/doc/iso.rst b/doc/iso.rst
index 2ad9c73e4eb8..4d315132f911 100644
--- a/doc/iso.rst
+++ b/doc/iso.rst
@@ -125,6 +125,26 @@ Broadcast Sink (Receiver) example:
/* Bind to Broadcaster address */
bind(iso_socket, (struct sockaddr *)addr, addr_len);
+Broadcast Source (Broadcaster) or Broadcast Sink (Receiver) Periodic
+Advertising Sync Transfer (PAST):
+
+.. code-block::
+
+ struct sockaddr_iso *addr;
+ size_t addr_len;
+
+ addr_len = sizeof(*addr) + sizeof(*addr->iso_bc);
+
+ memset(addr, 0, addr_len);
+ addr->iso_family = AF_BLUETOOTH;
+
+ /* Set destination address to PAST destination address */
+ bacpy(&addr->iso_bc->bc_bdaddr, (void *) bdaddr);
+ addr->iso_bc->bc_bdaddr_type = bdaddr_type;
+
+ /* Rebind already connected socket to PAST address */
+ bind(iso_socket, (struct sockaddr *)addr, addr_len);
+
SOCKET OPTIONS (SOL_BLUETOOTH)
==============================
--
2.51.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH BlueZ v2 09/13] shared/bap: Add callback broadcast instances
2025-10-09 21:29 [PATCH BlueZ v2 01/13] monitor: Use PAST to refer to Periodic Advertising Sync Transfer Luiz Augusto von Dentz
` (6 preceding siblings ...)
2025-10-09 21:29 ` [PATCH BlueZ v2 08/13] iso.rst: Add documentation for PAST/rebind Luiz Augusto von Dentz
@ 2025-10-09 21:29 ` Luiz Augusto von Dentz
2025-10-09 21:29 ` [PATCH BlueZ v2 10/13] MediaAssistant: Add Device option to Push Luiz Augusto von Dentz
` (4 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2025-10-09 21:29 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This makes bt_bap_register have a dedicated callback for broadcast
instances and also fixes bt_bap_stream_io_get_qos to handle broadcast
streams.
---
profiles/audio/bap.c | 2 +-
profiles/audio/bass.c | 2 +-
src/shared/bap.c | 59 ++++++++++++++++++++++++++++++++++++++++---
src/shared/bap.h | 4 +--
unit/test-bap.c | 2 +-
5 files changed, 60 insertions(+), 9 deletions(-)
diff --git a/profiles/audio/bap.c b/profiles/audio/bap.c
index 2994881ccc1d..b2711359952b 100644
--- a/profiles/audio/bap.c
+++ b/profiles/audio/bap.c
@@ -3897,7 +3897,7 @@ static int bap_init(void)
if (err)
return err;
- bap_id = bt_bap_register(bap_attached, bap_detached, NULL);
+ bap_id = bt_bap_register(bap_attached, NULL, bap_detached, NULL);
return 0;
}
diff --git a/profiles/audio/bass.c b/profiles/audio/bass.c
index 537c9206a71c..ee1257702638 100644
--- a/profiles/audio/bass.c
+++ b/profiles/audio/bass.c
@@ -1815,7 +1815,7 @@ static int bass_init(void)
return err;
bass_id = bt_bass_register(bass_attached, bass_detached, NULL);
- bap_id = bt_bap_register(bap_attached, bap_detached, NULL);
+ bap_id = bt_bap_register(bap_attached, NULL, bap_detached, NULL);
return 0;
}
diff --git a/src/shared/bap.c b/src/shared/bap.c
index 9b7395223c67..2b99b23488fa 100644
--- a/src/shared/bap.c
+++ b/src/shared/bap.c
@@ -98,6 +98,7 @@ struct bt_bap_bcode_cb {
struct bt_bap_cb {
unsigned int id;
bt_bap_func_t attached;
+ bt_bap_func_t bc_attached;
bt_bap_func_t detached;
void *user_data;
};
@@ -4524,13 +4525,13 @@ static void bap_free(void *data)
free(bap);
}
-unsigned int bt_bap_register(bt_bap_func_t attached, bt_bap_func_t detached,
- void *user_data)
+unsigned int bt_bap_register(bt_bap_func_t attached, bt_bap_func_t bc_attached,
+ bt_bap_func_t detached, void *user_data)
{
struct bt_bap_cb *cb;
static unsigned int id;
- if (!attached && !detached)
+ if (!attached && !bc_attached && !detached)
return 0;
if (!bap_cbs)
@@ -4539,6 +4540,7 @@ unsigned int bt_bap_register(bt_bap_func_t attached, bt_bap_func_t detached,
cb = new0(struct bt_bap_cb, 1);
cb->id = ++id ? id : ++id;
cb->attached = attached;
+ cb->bc_attached = bc_attached;
cb->detached = detached;
cb->user_data = user_data;
@@ -5643,6 +5645,17 @@ clone:
return true;
}
+static void bap_bc_attached(void *data, void *user_data)
+{
+ struct bt_bap_cb *cb = data;
+ struct bt_bap *bap = user_data;
+
+ if (!cb->bc_attached)
+ return;
+
+ cb->bc_attached(bap, cb->user_data);
+}
+
bool bt_bap_attach_broadcast(struct bt_bap *bap)
{
struct bt_bap_endpoint *ep;
@@ -5655,6 +5668,8 @@ bool bt_bap_attach_broadcast(struct bt_bap *bap)
queue_push_tail(sessions, bap);
+ queue_foreach(bap_cbs, bap_bc_attached, bap);
+
ep = bap_get_endpoint_bcast(bap->remote_eps, bap->ldb,
BT_BAP_BCAST_SOURCE);
if (ep)
@@ -6769,6 +6784,36 @@ static void bap_stream_get_out_qos(void *data, void *user_data)
*qos = &stream->qos;
}
+static void bap_stream_bcast_get_out_qos(void *data, void *user_data)
+{
+ struct bt_bap_stream *stream = data;
+ struct bt_bap_qos **qos = user_data;
+
+ if (!stream)
+ return;
+
+ if (!qos || *qos || stream->ep->dir != BT_BAP_BCAST_SINK ||
+ !stream->qos.bcast.io_qos.sdu)
+ return;
+
+ *qos = &stream->qos;
+}
+
+static void bap_stream_bcast_get_in_qos(void *data, void *user_data)
+{
+ struct bt_bap_stream *stream = data;
+ struct bt_bap_qos **qos = user_data;
+
+ if (!stream)
+ return;
+
+ if (!qos || *qos || stream->ep->dir != BT_BAP_BCAST_SOURCE ||
+ !stream->qos.bcast.io_qos.sdu)
+ return;
+
+ *qos = &stream->qos;
+}
+
bool bt_bap_stream_io_get_qos(struct bt_bap_stream *stream,
struct bt_bap_qos **in,
struct bt_bap_qos **out)
@@ -6785,13 +6830,19 @@ bool bt_bap_stream_io_get_qos(struct bt_bap_stream *stream,
bap_stream_get_out_qos(stream, out);
queue_foreach(stream->links, bap_stream_get_in_qos, in);
break;
+ case BT_BAP_BCAST_SOURCE:
+ bap_stream_bcast_get_in_qos(stream, in);
+ break;
+ case BT_BAP_BCAST_SINK:
+ bap_stream_bcast_get_out_qos(stream, out);
+ break;
default:
return false;
}
DBG(stream->bap, "in %p out %p", in ? *in : NULL, out ? *out : NULL);
- return in && out;
+ return (in && *in) || (out && *out);
}
static void bap_stream_get_dir(void *data, void *user_data)
diff --git a/src/shared/bap.h b/src/shared/bap.h
index fba8b6b17884..bf166d439935 100644
--- a/src/shared/bap.h
+++ b/src/shared/bap.h
@@ -116,8 +116,8 @@ uint8_t bt_bap_stream_get_type(struct bt_bap_stream *stream);
struct bt_bap_stream *bt_bap_pac_get_stream(struct bt_bap_pac *pac);
/* Session related function */
-unsigned int bt_bap_register(bt_bap_func_t added, bt_bap_func_t removed,
- void *user_data);
+unsigned int bt_bap_register(bt_bap_func_t attached, bt_bap_func_t bc_attached,
+ bt_bap_func_t detached, void *user_data);
bool bt_bap_unregister(unsigned int id);
struct bt_bap *bt_bap_new(struct gatt_db *ldb, struct gatt_db *rdb);
diff --git a/unit/test-bap.c b/unit/test-bap.c
index c15afe52dbbc..d07652f6ca44 100644
--- a/unit/test-bap.c
+++ b/unit/test-bap.c
@@ -1184,7 +1184,7 @@ static void test_server(const void *user_data)
tester_io_set_complete_func(test_complete_cb);
- data->id = bt_bap_register(bap_attached, NULL, data);
+ data->id = bt_bap_register(bap_attached, NULL, NULL, data);
g_assert(data->id);
tester_io_send();
--
2.51.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH BlueZ v2 10/13] MediaAssistant: Add Device option to Push
2025-10-09 21:29 [PATCH BlueZ v2 01/13] monitor: Use PAST to refer to Periodic Advertising Sync Transfer Luiz Augusto von Dentz
` (7 preceding siblings ...)
2025-10-09 21:29 ` [PATCH BlueZ v2 09/13] shared/bap: Add callback broadcast instances Luiz Augusto von Dentz
@ 2025-10-09 21:29 ` Luiz Augusto von Dentz
2025-10-09 21:29 ` [PATCH BlueZ v2 11/13] bass: Implement Device option for Push Luiz Augusto von Dentz
` (3 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2025-10-09 21:29 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This enables MediaAssistant.Push to work with local broadcast sources.
---
doc/org.bluez.MediaAssistant.rst | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/doc/org.bluez.MediaAssistant.rst b/doc/org.bluez.MediaAssistant.rst
index 64e689f8621d..8650d8abb379 100644
--- a/doc/org.bluez.MediaAssistant.rst
+++ b/doc/org.bluez.MediaAssistant.rst
@@ -40,6 +40,11 @@ Values:
See QoS property.
+ :object Device [ISO only, State=local only]:
+
+ Push to a specific device. Device must be connected and with
+ an active BASS session.
+
Properties
----------
@@ -52,6 +57,7 @@ Indicates the state of the assistant object. Possible values are:
:"pending": assistant object was pushed (stream information was sent to the peer)
:"requesting": remote device requires Broadcast_Code
:"active": remote device started receiving stream
+:"local": assistant object was created for a local stream
array{byte} Metadata [readwrite, ISO Only, experimental]
````````````````````````````````````````````````````````
@@ -59,7 +65,7 @@ array{byte} Metadata [readwrite, ISO Only, experimental]
Indicates stream Metadata.
dict QoS [readwrite, ISO only, experimental]
-`````````````````````````````````````````````````````
+````````````````````````````````````````````
Indicates stream QoS capabilities.
--
2.51.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH BlueZ v2 11/13] bass: Implement Device option for Push
2025-10-09 21:29 [PATCH BlueZ v2 01/13] monitor: Use PAST to refer to Periodic Advertising Sync Transfer Luiz Augusto von Dentz
` (8 preceding siblings ...)
2025-10-09 21:29 ` [PATCH BlueZ v2 10/13] MediaAssistant: Add Device option to Push Luiz Augusto von Dentz
@ 2025-10-09 21:29 ` Luiz Augusto von Dentz
2025-10-09 21:29 ` [PATCH BlueZ v2 12/13] client/assistant: Handle assistant.push to own broadcasts Luiz Augusto von Dentz
` (2 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2025-10-09 21:29 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This implements support for MediaAssistant.Push with local broadcast
sources.
---
profiles/audio/bap.c | 1 +
profiles/audio/bass.c | 656 ++++++++++++++++++++++++++++++------------
src/shared/bass.c | 7 +-
src/shared/bass.h | 4 +-
4 files changed, 478 insertions(+), 190 deletions(-)
diff --git a/profiles/audio/bap.c b/profiles/audio/bap.c
index b2711359952b..0de620d05fd6 100644
--- a/profiles/audio/bap.c
+++ b/profiles/audio/bap.c
@@ -3821,6 +3821,7 @@ static int bap_adapter_probe(struct btd_profile *p, struct btd_adapter *adapter)
return -EINVAL;
}
+ bt_bap_set_user_data(data->bap, adapter);
bap_data_add(data);
if (!bt_bap_attach_broadcast(data->bap)) {
diff --git a/profiles/audio/bass.c b/profiles/audio/bass.c
index ee1257702638..70ef6f932ec7 100644
--- a/profiles/audio/bass.c
+++ b/profiles/audio/bass.c
@@ -43,6 +43,7 @@
#include "src/shared/bass.h"
#include "src/shared/bap.h"
#include "src/shared/ad.h"
+#include "src/shared/io.h"
#include "btio/btio.h"
#include "src/plugin.h"
@@ -69,6 +70,9 @@ enum assistant_state {
ASSISTANT_STATE_ACTIVE, /* Remote device started receiving
* stream
*/
+ ASSISTANT_STATE_LOCAL, /* Assistant object was created for
+ * local stream
+ */
};
static const char *const str_state[] = {
@@ -76,18 +80,23 @@ static const char *const str_state[] = {
"ASSISTANT_STATE_PENDING",
"ASSISTANT_STATE_REQUESTING",
"ASSISTANT_STATE_ACTIVE",
+ "ASSISTANT_STATE_LOCAL",
};
struct bass_data {
+ struct btd_adapter *adapter;
struct btd_device *device;
struct btd_service *service;
struct bt_bass *bass;
+ struct bt_bap_stream *stream;
unsigned int src_id;
unsigned int cp_id;
unsigned int bis_id;
+ unsigned int state_id;
};
struct bass_assistant {
+ struct btd_adapter *adapter; /* Broadcast source device */
struct btd_device *device; /* Broadcast source device */
struct bass_data *data; /* BASS session with peer device */
uint8_t sgrp;
@@ -140,7 +149,8 @@ static struct queue *delegators;
static const char *state2str(enum assistant_state state);
-static struct bass_data *bass_data_new(struct btd_device *device);
+static struct bass_data *bass_data_new(struct btd_adapter *adapter,
+ struct btd_device *device);
static void bass_data_add(struct bass_data *data);
static void bass_data_remove(struct bass_data *data);
@@ -654,7 +664,7 @@ static void bap_attached(struct bt_bap *bap, void *user_data)
adapter = device_get_adapter(device);
/* Create BASS session with the Broadcast Source */
- data = bass_data_new(device);
+ data = bass_data_new(adapter, device);
data->bis_id = bt_bap_bis_cb_register(bap, bis_probe,
bis_remove, device, NULL);
@@ -696,108 +706,13 @@ static void bap_attached(struct bt_bap *bap, void *user_data)
btd_service_set_user_data(service, dg);
}
-static void setup_free(void *data)
-{
- struct bass_setup *setup = data;
-
- DBG("setup %p", setup);
-
- util_iov_free(setup->qos.bcast.bcode, 1);
- util_iov_free(setup->meta, 1);
- util_iov_free(setup->config, 1);
- free(setup->path);
-
- /* Clear bis index from the bis sync bitmask, if it
- * has been previously set.
- */
- bt_bass_clear_bis_sync(setup->dg->src, setup->bis);
-}
-
-static bool match_device(const void *data, const void *match_data)
-{
- const struct bass_data *bdata = data;
- const struct btd_device *device = match_data;
-
- return bdata->device == device;
-}
-
-static void bap_detached(struct bt_bap *bap, void *user_data)
-{
- struct btd_service *service;
- struct btd_profile *p;
- struct btd_device *device;
- struct bass_delegator *dg;
- struct bass_data *data;
-
- DBG("%p", bap);
-
- service = bt_bap_get_user_data(bap);
- if (!service)
- return;
-
- p = btd_service_get_profile(service);
- if (!p)
- return;
-
- /* Only handle sessions with Broadcast Sources */
- if (!g_str_equal(p->remote_uuid, BCAAS_UUID_STR))
- return;
-
- device = btd_service_get_device(service);
-
- /* Remove BASS session with the Broadcast Source device */
- data = queue_find(sessions, match_device, device);
- if (data) {
- bt_bap_bis_cb_unregister(bap, data->bis_id);
- bass_data_remove(data);
- }
-
- dg = queue_remove_if(delegators, delegator_match_device, device);
- if (!dg)
- return;
-
- DBG("%p", dg);
-
- if (dg->io_id)
- g_source_remove(dg->io_id);
-
- if (dg->io) {
- g_io_channel_shutdown(dg->io, TRUE, NULL);
- g_io_channel_unref(dg->io);
- }
-
- queue_destroy(dg->setups, setup_free);
-
- /* Update Broadcast Receive State characteristic value and notify
- * peers.
- */
- if (bt_bass_set_pa_sync(dg->src, BT_BASS_NOT_SYNCHRONIZED_TO_PA))
- DBG("Failed to update Broadcast Receive State characteristic");
-
- /* Unregister BAP stream state changed callback. */
- bt_bap_state_unregister(dg->bap, dg->state_id);
-
- bt_bap_bcode_cb_unregister(dg->bap, dg->bcode_id);
-
- if (dg->timeout)
- g_source_remove(dg->timeout);
-
- queue_destroy(dg->bcode_reqs, free);
-
- free(dg->bcode);
-
- free(dg);
-
- btd_service_set_user_data(service, NULL);
-}
-
static void assistant_set_state(struct bass_assistant *assistant,
enum assistant_state state)
{
enum assistant_state old_state = assistant->state;
const char *str;
- if (old_state == state)
+ if (old_state == state || old_state == ASSISTANT_STATE_LOCAL)
return;
assistant->state = state;
@@ -864,11 +779,21 @@ static int assistant_parse_qos(struct bass_assistant *assistant,
return 0;
}
+static bool match_device(const void *data, const void *match_data)
+{
+ const struct bass_data *bdata = data;
+ const struct btd_device *device = match_data;
+
+ return bdata->device == device;
+}
+
static int assistant_parse_props(struct bass_assistant *assistant,
DBusMessageIter *props)
{
DBusMessageIter value, entry, array;
- const char *key;
+ const char *key, *path;
+ struct btd_device *device;
+ struct bass_data *data;
while (dbus_message_iter_get_arg_type(props) == DBUS_TYPE_DICT_ENTRY) {
dbus_message_iter_recurse(props, &entry);
@@ -901,6 +826,44 @@ static int assistant_parse_props(struct bass_assistant *assistant,
goto fail;
DBG("Parsed QoS");
+ } else if (!strcasecmp(key, "Device")) {
+ if (assistant->state != ASSISTANT_STATE_LOCAL) {
+ error("Device property is for local assistant "
+ "only");
+ goto fail;
+ }
+
+ if (dbus_message_iter_get_arg_type(&value) !=
+ DBUS_TYPE_OBJECT_PATH)
+ goto fail;
+
+ dbus_message_iter_get_basic(&value, &path);
+
+ device = btd_adapter_find_device_by_path(
+ assistant->adapter,
+ path);
+ if (!device) {
+ error("Unable to find device %s", path);
+ goto fail;
+ }
+
+ data = queue_find(sessions, match_device, device);
+ if (!data) {
+ error("Unable to find data for device %s",
+ path);
+ goto fail;
+ }
+
+ if (!data->bass) {
+ error("Unable to find bass for device %s",
+ path);
+ goto fail;
+ }
+
+ if (assistant->data->bass)
+ bt_bass_unref(assistant->data->bass);
+
+ assistant->data->bass = bt_bass_ref(data->bass);
}
dbus_message_iter_next(props);
@@ -914,6 +877,63 @@ fail:
return -EINVAL;
}
+static bool match_data(const void *data, const void *match_data)
+{
+ const struct bass_data *bdata = data;
+ const struct bt_bass *bass = match_data;
+
+ return bdata->bass == bass;
+}
+
+static void assistant_past(struct bass_assistant *assistant)
+{
+ struct io *io = bt_bap_stream_get_io(assistant->data->stream);
+ struct btd_device *device = assistant->device;
+ int sk;
+ struct sockaddr_iso *addr;
+ int err;
+
+ DBG("");
+
+ if (!io) {
+ error("stream io not set");
+ return;
+ }
+
+ sk = io_get_fd(io);
+ if (sk < 0)
+ return;
+
+ if (!device) {
+ struct bt_bass *bass = assistant->data->bass;
+ struct bass_data *data;
+
+ data = queue_find(sessions, match_data, bass);
+ if (!data) {
+ error("Unable to find data for bass %p", bass);
+ return;
+ }
+
+ device = data->device;
+ if (!device) {
+ error("Unable to find device for bass %p", bass);
+ return;
+ }
+ }
+
+ addr = malloc(sizeof(*addr) + sizeof(*addr->iso_bc));
+ memset(addr, 0, sizeof(*addr) + sizeof(*addr->iso_bc));
+ addr->iso_family = AF_BLUETOOTH;
+
+ bacpy(&addr->iso_bc->bc_bdaddr, (void *) device_get_address(device));
+ addr->iso_bc->bc_bdaddr_type = device_get_le_address_type(device);
+
+ err = bind(sk, (struct sockaddr *) addr, sizeof(*addr) +
+ sizeof(*addr->iso_bc));
+ if (err)
+ error("bind: %s", strerror(errno));
+}
+
static DBusMessage *push(DBusConnection *conn, DBusMessage *msg,
void *user_data)
{
@@ -925,6 +945,7 @@ static DBusMessage *push(DBusConnection *conn, DBusMessage *msg,
uint8_t meta_len = 0;
int err;
DBusMessageIter props, dict;
+ struct io *io;
DBG("");
@@ -944,17 +965,63 @@ static DBusMessage *push(DBusConnection *conn, DBusMessage *msg,
hdr.op = BT_BASS_ADD_SRC;
- if (device_get_le_address_type(assistant->device) == BDADDR_LE_PUBLIC)
- params.addr_type = BT_BASS_ADDR_PUBLIC;
- else
- params.addr_type = BT_BASS_ADDR_RANDOM;
+ if (assistant->device) {
+ if (device_get_le_address_type(assistant->device) ==
+ BDADDR_LE_PUBLIC)
+ params.addr_type = BT_BASS_ADDR_PUBLIC;
+ else
+ params.addr_type = BT_BASS_ADDR_RANDOM;
- bacpy(¶ms.addr, device_get_address(assistant->device));
- params.sid = assistant->sid;
- put_le24(assistant->bid, params.bid);
- params.pa_sync = PA_SYNC_NO_PAST;
- params.pa_interval = PA_INTERVAL_UNKNOWN;
- params.num_subgroups = assistant->sgrp + 1;
+ bacpy(¶ms.addr, device_get_address(assistant->device));
+ params.sid = assistant->sid;
+ put_le24(assistant->bid, params.bid);
+ params.pa_sync = PA_SYNC_NO_PAST;
+ params.pa_interval = PA_INTERVAL_UNKNOWN;
+ params.num_subgroups = assistant->sgrp + 1;
+ } else {
+ io = bt_bap_stream_get_io(assistant->data->stream);
+ if (io) {
+ int fd = io_get_fd(io);
+ struct sockaddr_iso addr;
+ socklen_t olen = sizeof(addr);
+
+ if (getsockname(fd, (struct sockaddr *) &addr,
+ &olen) < 0) {
+ error("getsockname: %s", strerror(errno));
+ return btd_error_invalid_args(msg);
+ }
+
+ if (addr.iso_bdaddr_type == BDADDR_LE_PUBLIC)
+ params.addr_type = BT_BASS_ADDR_PUBLIC;
+ else
+ params.addr_type = BT_BASS_ADDR_RANDOM;
+
+ bacpy(¶ms.addr, &addr.iso_bdaddr);
+ } else {
+ if (btd_adapter_get_address_type(assistant->adapter) ==
+ BDADDR_LE_PUBLIC)
+ params.addr_type = BT_BASS_ADDR_PUBLIC;
+ else
+ params.addr_type = BT_BASS_ADDR_RANDOM;
+
+ bacpy(¶ms.addr,
+ btd_adapter_get_address(assistant->adapter));
+ }
+
+ params.sid = assistant->sid;
+ /* TODO: Add a way to recover BID */
+ put_le24(assistant->bid, params.bid);
+
+ if (assistant->data->stream &&
+ btd_adapter_has_settings(assistant->adapter,
+ MGMT_SETTING_PAST_SENDER))
+ params.pa_sync = PA_SYNC_PAST;
+ else
+ params.pa_sync = PA_SYNC_NO_SYNC;
+
+ params.pa_interval = PA_INTERVAL_UNKNOWN;
+ params.num_subgroups = assistant->sgrp + 1;
+ }
util_iov_append(&iov, ¶ms, sizeof(params));
@@ -1009,6 +1076,8 @@ static const char *state2str(enum assistant_state state)
return "requesting";
case ASSISTANT_STATE_ACTIVE:
return "active";
+ case ASSISTANT_STATE_LOCAL:
+ return "local";
}
return NULL;
@@ -1108,7 +1177,8 @@ static void src_ad_search_bid(void *data, void *user_data)
util_iov_pull_le24(&iov, &assistant->bid);
}
-static struct bass_assistant *assistant_new(struct btd_adapter *adapter,
+static struct bass_assistant *
+assistant_new(struct btd_adapter *adapter,
struct btd_device *device, struct bass_data *data,
uint8_t sgrp, uint8_t sid, uint8_t bis, struct bt_bap_qos *qos,
struct iovec *meta, struct iovec *caps)
@@ -1122,6 +1192,7 @@ static struct bass_assistant *assistant_new(struct btd_adapter *adapter,
DBG("assistant %p", assistant);
+ assistant->adapter = adapter;
assistant->device = device;
assistant->data = data;
assistant->sgrp = sgrp;
@@ -1135,14 +1206,21 @@ static struct bass_assistant *assistant_new(struct btd_adapter *adapter,
assistant->meta = util_iov_dup(meta, 1);
assistant->caps = util_iov_dup(caps, 1);
- btd_device_foreach_service_data(assistant->device, src_ad_search_bid,
+ if (device) {
+ btd_device_foreach_service_data(device, src_ad_search_bid,
assistant);
- ba2str(device_get_address(device), src_addr);
+ ba2str(device_get_address(device), src_addr);
- assistant->path = g_strdup_printf("%s/src_%s/sid%d/bis%d",
- device_get_path(data->device), src_addr,
- sid, bis);
+ assistant->path = g_strdup_printf("%s/src_%s/sid%d/bis%d",
+ device_get_path(data->device),
+ src_addr, sid, bis);
+ } else {
+ assistant->path = g_strdup_printf("%s/sid%d/bis%d",
+ adapter_get_path(data->adapter),
+ sid, bis);
+ assistant->state = ASSISTANT_STATE_LOCAL;
+ }
g_strdelimit(assistant->path, ":", '_');
@@ -1154,6 +1232,194 @@ static struct bass_assistant *assistant_new(struct btd_adapter *adapter,
return assistant;
}
+static void bis_src_handler(uint8_t sid, uint8_t bis, uint8_t sgrp,
+ struct iovec *caps, struct iovec *meta,
+ struct bt_bap_qos *qos, void *user_data)
+{
+ struct bass_data *data = user_data;
+ struct bass_assistant *assistant;
+ char addr[18];
+
+ ba2str(btd_adapter_get_address(data->adapter), addr);
+
+ DBG("%s data %p BIS %d", addr, data, bis);
+
+ assistant = assistant_new(data->adapter, NULL, data, sgrp, sid, bis,
+ qos, meta, caps);
+ if (!g_dbus_register_interface(btd_get_dbus_connection(),
+ assistant->path,
+ MEDIA_ASSISTANT_INTERFACE,
+ assistant_methods, NULL,
+ assistant_properties,
+ assistant,
+ assistant_free))
+ DBG("Could not register path %s", assistant->path);
+}
+
+static bool assistant_match_data(const void *data, const void *match_data)
+{
+ const struct bass_assistant *assistant = data;
+ const struct bass_data *bdata = match_data;
+
+ return (assistant->data == bdata);
+}
+
+static void unregister_assistant(void *data)
+{
+ struct bass_assistant *assistant = data;
+
+ DBG("%p", assistant);
+
+ g_dbus_unregister_interface(btd_get_dbus_connection(),
+ assistant->path, MEDIA_ASSISTANT_INTERFACE);
+}
+
+static void bap_state_src_changed(struct bt_bap_stream *stream,
+ uint8_t old_state, uint8_t new_state,
+ void *user_data)
+{
+ struct bass_data *data = user_data;
+ struct assistant *assistant;
+ struct bt_bap_qos *qos = NULL;
+ struct iovec *base;
+
+ DBG("stream %p: %s(%u) -> %s(%u)", stream,
+ bt_bap_stream_statestr(old_state), old_state,
+ bt_bap_stream_statestr(new_state), new_state);
+
+ switch (new_state) {
+ case BT_BAP_STREAM_STATE_IDLE:
+ /* Unregister assistant object if one exists */
+ assistant = queue_remove_if(assistants, assistant_match_data,
+ data);
+ if (assistant)
+ unregister_assistant(assistant);
+ data->stream = NULL;
+ break;
+ case BT_BAP_STREAM_STATE_STREAMING:
+ base = bt_bap_stream_get_base(stream);
+ if (!base) {
+ error("Unable to read BASE of stream %p", stream);
+ break;
+ }
+
+ if (!bt_bap_stream_io_get_qos(stream, NULL, &qos)) {
+ error("Unable to read QoS of stream %p", stream);
+ break;
+ }
+
+ bt_bap_parse_base(0x00, base, qos, bass_debug, bis_src_handler,
+ data);
+ data->stream = stream;
+ break;
+ }
+}
+
+static void bap_bc_attached(struct bt_bap *bap, void *user_data)
+{
+ struct btd_adapter *adapter;
+ struct bass_data *data;
+
+ DBG("%p", bap);
+
+ adapter = bt_bap_get_user_data(bap);
+ if (!adapter)
+ return;
+
+ /* Create BASS session with the local Broadcast Source */
+ data = bass_data_new(adapter, NULL);
+ data->state_id = bt_bap_state_register(bap, bap_state_src_changed,
+ NULL, data, NULL);
+}
+
+static void setup_free(void *data)
+{
+ struct bass_setup *setup = data;
+
+ DBG("setup %p", setup);
+
+ util_iov_free(setup->qos.bcast.bcode, 1);
+ util_iov_free(setup->meta, 1);
+ util_iov_free(setup->config, 1);
+ free(setup->path);
+
+ /* Clear bis index from the bis sync bitmask, if it
+ * has been previously set.
+ */
+ bt_bass_clear_bis_sync(setup->dg->src, setup->bis);
+}
+
+static void bap_detached(struct bt_bap *bap, void *user_data)
+{
+ struct btd_service *service;
+ struct btd_profile *p;
+ struct btd_device *device;
+ struct bass_delegator *dg;
+ struct bass_data *data;
+
+ DBG("%p", bap);
+
+ service = bt_bap_get_user_data(bap);
+ if (!service)
+ return;
+
+ p = btd_service_get_profile(service);
+ if (!p)
+ return;
+
+ /* Only handle sessions with Broadcast Sources */
+ if (!g_str_equal(p->remote_uuid, BCAAS_UUID_STR))
+ return;
+
+ device = btd_service_get_device(service);
+
+ /* Remove BASS session with the Broadcast Source device */
+ data = queue_find(sessions, match_device, device);
+ if (data) {
+ bt_bap_bis_cb_unregister(bap, data->bis_id);
+ bt_bap_state_unregister(bap, data->state_id);
+ bass_data_remove(data);
+ }
+
+ dg = queue_remove_if(delegators, delegator_match_device, device);
+ if (!dg)
+ return;
+
+ DBG("%p", dg);
+
+ if (dg->io_id)
+ g_source_remove(dg->io_id);
+
+ if (dg->io) {
+ g_io_channel_shutdown(dg->io, TRUE, NULL);
+ g_io_channel_unref(dg->io);
+ }
+
+ queue_destroy(dg->setups, setup_free);
+
+ /* Update Broadcast Receive State characteristic value and notify
+ * peers.
+ */
+ if (bt_bass_set_pa_sync(dg->src, BT_BASS_NOT_SYNCHRONIZED_TO_PA))
+ DBG("Failed to update Broadcast Receive State characteristic");
+
+ /* Unregister BAP stream state changed callback. */
+ bt_bap_state_unregister(dg->bap, dg->state_id);
+
+ bt_bap_bcode_cb_unregister(dg->bap, dg->bcode_id);
+
+ if (dg->timeout)
+ g_source_remove(dg->timeout);
+
+ queue_destroy(dg->bcode_reqs, free);
+
+ free(dg->bcode);
+
+ free(dg);
+
+ btd_service_set_user_data(service, NULL);
+}
+
static void bis_probe(uint8_t sid, uint8_t bis, uint8_t sgrp,
struct iovec *caps, struct iovec *meta,
struct bt_bap_qos *qos, void *user_data)
@@ -1210,16 +1476,6 @@ static bool assistant_match_device(const void *data, const void *match_data)
return (assistant->device == device);
}
-static void unregister_assistant(void *data)
-{
- struct bass_assistant *assistant = data;
-
- DBG("%p", assistant);
-
- g_dbus_unregister_interface(btd_get_dbus_connection(),
- assistant->path, MEDIA_ASSISTANT_INTERFACE);
-}
-
static void bis_remove(struct bt_bap *bap, void *user_data)
{
struct btd_device *device = user_data;
@@ -1228,11 +1484,13 @@ static void bis_remove(struct bt_bap *bap, void *user_data)
device, unregister_assistant);
}
-static struct bass_data *bass_data_new(struct btd_device *device)
+static struct bass_data *bass_data_new(struct btd_adapter *adapter,
+ struct btd_device *device)
{
struct bass_data *data;
data = new0(struct bass_data, 1);
+ data->adapter = adapter;
data->device = device;
return data;
@@ -1240,6 +1498,8 @@ static struct bass_data *bass_data_new(struct btd_device *device)
static void bass_data_add(struct bass_data *data)
{
+ bool initiator = false;
+
DBG("data %p", data);
if (queue_find(sessions, NULL, data)) {
@@ -1254,33 +1514,14 @@ static void bass_data_add(struct bass_data *data)
queue_push_tail(sessions, data);
- if (data->service) {
- struct btd_adapter *adapter = device_get_adapter(data->device);
- bool initiator = btd_service_is_initiator(data->service);
-
+ if (data->service)
btd_service_set_user_data(data->service, data);
- if ((!initiator && btd_adapter_has_settings(adapter,
+
+ if ((!initiator && btd_adapter_has_settings(data->adapter,
MGMT_SETTING_PAST_RECEIVER)) || (initiator &&
- btd_adapter_has_settings(adapter,
+ btd_adapter_has_settings(data->adapter,
MGMT_SETTING_PAST_SENDER)))
- device_set_past_support(data->device, true);
- }
-}
-
-static bool match_data(const void *data, const void *match_data)
-{
- const struct bass_data *bdata = data;
- const struct bt_bass *bass = match_data;
-
- return bdata->bass == bass;
-}
-
-static bool assistant_match_data(const void *data, const void *match_data)
-{
- const struct bass_assistant *assistant = data;
- const struct bass_data *bdata = match_data;
-
- return (assistant->data == bdata);
+ device_set_past_support(data->device, true);
}
static void bass_data_free(struct bass_data *data)
@@ -1337,42 +1578,19 @@ static void bass_detached(struct bt_bass *bass, void *user_data)
bass_data_remove(data);
}
-static int handle_add_src_req(struct bt_bcast_src *bcast_src,
- struct bt_bass_add_src_params *params,
- struct bass_data *data)
+static struct bass_delegator *
+bass_delegator_new(struct btd_device *device, struct bt_bcast_src *src,
+ uint8_t sid)
{
- struct btd_adapter *adapter = device_get_adapter(data->device);
- struct btd_device *device;
struct bass_delegator *dg;
- /* Create device for Broadcast Source using the parameters
- * provided by Broadcast Assistant.
- */
- device = btd_adapter_get_device(adapter, ¶ms->addr,
- params->addr_type);
- if (!device) {
- DBG("Unable to get device");
- return -EINVAL;
- }
-
- DBG("device %p", device);
-
- /* Probe Broadcast Source, if it has not already been
- * autonomously probed inside BAP.
- */
- if (!btd_device_get_service(device, BCAAS_UUID_STR))
- goto probe;
-
- return 0;
-
-probe:
dg = new0(struct bass_delegator, 1);
if (!dg)
- return -ENOMEM;
+ return NULL;
dg->device = device;
- dg->src = bcast_src;
- dg->sid = params->sid;
+ dg->src = src;
+ dg->sid = sid;
dg->bcode_reqs = queue_new();
dg->setups = queue_new();
@@ -1388,6 +1606,59 @@ probe:
*/
btd_device_add_uuid(device, BCAAS_UUID_STR);
+ return dg;
+}
+
+static int handle_add_src_req(struct bt_bcast_src *bcast_src,
+ struct bt_bass_add_src_params *params,
+ struct bass_data *data)
+{
+ struct btd_adapter *adapter = device_get_adapter(data->device);
+ struct btd_device *device;
+ struct bass_delegator *dg;
+
+ /* Detect if PAST can be used then it can be used as destination since
+ * PAST Receiver uses the ACL connection itself.
+ */
+ if (params->pa_sync == PA_SYNC_PAST) {
+ /* Check if MGMT_SETTING_PAST_RECEIVER is supported then set
+ * DEVICE_FLAG_PAST since the device is requesting PAST to be
+ * used.
+ */
+ if (btd_adapter_has_settings(data->adapter,
+ MGMT_SETTING_PAST_RECEIVER)) {
+ device_set_past_support(data->device, true);
+ bt_bass_set_pa_sync(bcast_src, BT_BASS_SYNC_INFO_RE);
+ device = data->device;
+ goto done;
+ }
+
+ bt_bass_set_pa_sync(bcast_src, BT_BASS_NO_PAST);
+ }
+
+ /* Create device for Broadcast Source using the parameters
+ * provided by Broadcast Assistant.
+ */
+ device = btd_adapter_get_device(adapter, ¶ms->addr,
+ params->addr_type);
+
+ if (!device) {
+ DBG("Unable to get device");
+ return -EINVAL;
+ }
+
+done:
+ DBG("device %p", device);
+
+ /* Probe Broadcast Source, if it has not already been
+ * autonomously probed inside BAP.
+ */
+ if (!btd_device_get_service(device, BCAAS_UUID_STR)) {
+ dg = bass_delegator_new(device, bcast_src, params->sid);
+ if (!dg)
+ return -ENOMEM;
+ }
+
return 0;
}
@@ -1570,7 +1841,7 @@ static void bass_attached(struct bt_bass *bass, void *user_data)
return;
}
- data = bass_data_new(device);
+ data = bass_data_new(device_get_adapter(device), device);
data->bass = bass;
data->cp_id = bt_bass_cp_handler_register(data->bass,
@@ -1612,8 +1883,8 @@ static void bass_handle_bcode_req(struct bass_assistant *assistant, int id)
free(iov.iov_base);
}
-static void bass_src_changed(uint8_t id, uint32_t bid, uint8_t enc,
- uint32_t bis_sync, void *user_data)
+static void bass_src_changed(uint8_t id, uint32_t bid, uint8_t state,
+ uint8_t enc, uint32_t bis_sync, void *user_data)
{
const struct queue_entry *entry;
@@ -1622,15 +1893,27 @@ static void bass_src_changed(uint8_t id, uint32_t bid, uint8_t enc,
struct bass_assistant *assistant = entry->data;
uint32_t bis = 1 << (assistant->bis - 1);
- if (assistant->bid != bid)
+ if (bid && assistant->bid != bid)
/* Only handle assistant objects
* that match the source
*/
continue;
+ /* If BID is not set it may happen to be local stream so ignore
+ * non-local assistants.
+ */
+ if (!bid && assistant->state != ASSISTANT_STATE_LOCAL)
+ continue;
+
+ if (state == BT_BASS_SYNC_INFO_RE) {
+ assistant_past(assistant);
+ return;
+ }
+
switch (enc) {
case BT_BASS_BIG_ENC_STATE_BCODE_REQ:
- if (assistant->state != ASSISTANT_STATE_PENDING)
+ if (assistant->state != ASSISTANT_STATE_PENDING &&
+ assistant->state != ASSISTANT_STATE_LOCAL)
/* Only handle assistant objects that
* have been pushed by the user
*/
@@ -1686,7 +1969,7 @@ static int bass_probe(struct btd_service *service)
return -EINVAL;
}
- data = bass_data_new(device);
+ data = bass_data_new(adapter, device);
data->service = service;
data->bass = bt_bass_new(btd_gatt_database_get_db(database),
@@ -1815,7 +2098,8 @@ static int bass_init(void)
return err;
bass_id = bt_bass_register(bass_attached, bass_detached, NULL);
- bap_id = bt_bap_register(bap_attached, NULL, bap_detached, NULL);
+ bap_id = bt_bap_register(bap_attached, bap_bc_attached, bap_detached,
+ NULL);
return 0;
}
diff --git a/src/shared/bass.c b/src/shared/bass.c
index 36bb9ea66523..19cc9531d617 100644
--- a/src/shared/bass.c
+++ b/src/shared/bass.c
@@ -1319,8 +1319,9 @@ static void notify_src_changed(void *data, void *user_data)
}
if (changed->cb)
- changed->cb(bcast_src->id, bcast_src->bid, bcast_src->enc,
- bis_sync, changed->data);
+ changed->cb(bcast_src->id, bcast_src->bid,
+ bcast_src->sync_state, bcast_src->enc,
+ bis_sync, changed->data);
}
static void bcast_recv_state_notify(struct bt_bass *bass, uint16_t value_handle,
@@ -1681,7 +1682,7 @@ static struct bt_bass_db *bass_get_db(struct gatt_db *db,
return bass_db_new(db, adapter_bdaddr);
}
-static struct bt_bass *bt_bass_ref(struct bt_bass *bass)
+struct bt_bass *bt_bass_ref(struct bt_bass *bass)
{
if (!bass)
return NULL;
diff --git a/src/shared/bass.h b/src/shared/bass.h
index f39ed7dad41d..a7b7741db3b7 100644
--- a/src/shared/bass.h
+++ b/src/shared/bass.h
@@ -97,7 +97,8 @@ typedef void (*bt_bass_func_t)(struct bt_bass *bass, void *user_data);
typedef void (*bt_bass_destroy_func_t)(void *user_data);
typedef void (*bt_bass_debug_func_t)(const char *str, void *user_data);
typedef void (*bt_bass_src_func_t)(uint8_t id, uint32_t bid, uint8_t enc,
- uint32_t bis_sync, void *user_data);
+ uint8_t state, uint32_t bis_sync,
+ void *user_data);
typedef int (*bt_bass_cp_handler_func_t)(struct bt_bcast_src *bcast_src,
uint8_t op, void *params, void *user_data);
@@ -112,6 +113,7 @@ bool bt_bass_set_debug(struct bt_bass *bass, bt_bass_debug_func_t func,
struct bt_bass *bt_bass_new(struct gatt_db *ldb, struct gatt_db *rdb,
const bdaddr_t *adapter_bdaddr);
bool bt_bass_set_user_data(struct bt_bass *bass, void *user_data);
+struct bt_bass *bt_bass_ref(struct bt_bass *bass);
void bt_bass_unref(struct bt_bass *bass);
bool bt_bass_attach(struct bt_bass *bass, struct bt_gatt_client *client);
bool bt_bass_set_att(struct bt_bass *bass, struct bt_att *att);
--
2.51.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH BlueZ v2 12/13] client/assistant: Handle assistant.push to own broadcasts
2025-10-09 21:29 [PATCH BlueZ v2 01/13] monitor: Use PAST to refer to Periodic Advertising Sync Transfer Luiz Augusto von Dentz
` (9 preceding siblings ...)
2025-10-09 21:29 ` [PATCH BlueZ v2 11/13] bass: Implement Device option for Push Luiz Augusto von Dentz
@ 2025-10-09 21:29 ` Luiz Augusto von Dentz
2025-10-09 21:29 ` [PATCH BlueZ v2 13/13] client/assistant: Detect if object already contains a valid BCode Luiz Augusto von Dentz
2025-10-09 22:51 ` [BlueZ,v2,01/13] monitor: Use PAST to refer to Periodic Advertising Sync Transfer bluez.test.bot
12 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2025-10-09 21:29 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
client/assistant.c | 114 ++++++++++++++++++++++++++++++++++-----------
client/mgmt.c | 5 +-
2 files changed, 92 insertions(+), 27 deletions(-)
diff --git a/client/assistant.c b/client/assistant.c
index 3551aaad8a16..1ff8001d7216 100644
--- a/client/assistant.c
+++ b/client/assistant.c
@@ -47,6 +47,8 @@
struct assistant_config {
GDBusProxy *proxy; /* DBus object reference */
+ char *state; /* Assistant state */
+ char *device; /* Device address */
struct iovec *meta; /* Stream metadata LTVs */
struct bt_iso_qos qos; /* Stream QoS parameters */
};
@@ -223,6 +225,10 @@ static void push_setup(DBusMessageIter *iter, void *user_data)
DBUS_TYPE_BYTE, &cfg->meta->iov_base,
cfg->meta->iov_len);
+ if (cfg->device)
+ g_dbus_dict_append_entry(&dict, "Device", DBUS_TYPE_OBJECT_PATH,
+ &cfg->device);
+
if (cfg->qos.bcast.encryption)
append_qos(&dict, cfg);
@@ -285,11 +291,43 @@ fail:
return bt_shell_noninteractive_quit(EXIT_FAILURE);
}
+static bool assistant_get_qos(struct assistant_config *cfg)
+{
+ DBusMessageIter iter, dict, entry, value;
+ const char *key;
+
+ /* Get QoS property to check if the stream is encrypted */
+ if (!g_dbus_proxy_get_property(cfg->proxy, "QoS", &iter))
+ return false;
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+ return false;
+
+ dbus_message_iter_recurse(&iter, &dict);
+
+ if (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_DICT_ENTRY)
+ return false;
+
+ dbus_message_iter_recurse(&dict, &entry);
+ dbus_message_iter_get_basic(&entry, &key);
+
+ if (strcasecmp(key, "Encryption") != 0)
+ return false;
+
+ dbus_message_iter_next(&entry);
+ dbus_message_iter_recurse(&entry, &value);
+
+ if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_BYTE)
+ return false;
+
+ dbus_message_iter_get_basic(&value, &cfg->qos.bcast.encryption);
+
+ return true;
+}
+
static void assistant_set_metadata_cfg(const char *input, void *user_data)
{
struct assistant_config *cfg = user_data;
- DBusMessageIter iter, dict, entry, value;
- const char *key;
if (!strcasecmp(input, "a") || !strcasecmp(input, "auto"))
goto done;
@@ -305,32 +343,9 @@ static void assistant_set_metadata_cfg(const char *input, void *user_data)
}
done:
- /* Get QoS property to check if the stream is encrypted */
- if (!g_dbus_proxy_get_property(cfg->proxy, "QoS", &iter))
+ if (!assistant_get_qos(cfg))
goto fail;
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
- goto fail;
-
- dbus_message_iter_recurse(&iter, &dict);
-
- if (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_DICT_ENTRY)
- goto fail;
-
- dbus_message_iter_recurse(&dict, &entry);
- dbus_message_iter_get_basic(&entry, &key);
-
- if (strcasecmp(key, "Encryption") != 0)
- goto fail;
-
- dbus_message_iter_next(&entry);
- dbus_message_iter_recurse(&entry, &value);
-
- if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_BYTE)
- goto fail;
-
- dbus_message_iter_get_basic(&value, &cfg->qos.bcast.encryption);
-
if (cfg->qos.bcast.encryption)
/* Prompt user to enter the Broadcast Code to decrypt
* the stream
@@ -355,9 +370,45 @@ fail:
return bt_shell_noninteractive_quit(EXIT_FAILURE);
}
+static void assistant_set_device_cfg(const char *input, void *user_data)
+{
+ struct assistant_config *cfg = user_data;
+
+ cfg->device = strdup(input);
+
+ if (!assistant_get_qos(cfg))
+ goto fail;
+
+ if (cfg->qos.bcast.encryption) {
+ /* Prompt user to enter the Broadcast Code to decrypt
+ * the stream
+ */
+ bt_shell_prompt_input("Assistant",
+ "Enter Broadcast Code (auto/value):",
+ assistant_set_bcode_cfg, cfg);
+ } else {
+ if (!g_dbus_proxy_method_call(cfg->proxy, "Push",
+ push_setup, push_reply,
+ cfg, NULL)) {
+ bt_shell_printf("Failed to push assistant\n");
+ goto fail;
+ }
+ }
+
+ return;
+
+fail:
+ free(cfg->device);
+ free(cfg->meta);
+ g_free(cfg);
+
+ return bt_shell_noninteractive_quit(EXIT_FAILURE);
+}
+
static void cmd_push_assistant(int argc, char *argv[])
{
struct assistant_config *cfg;
+ DBusMessageIter iter;
cfg = new0(struct assistant_config, 1);
if (!cfg)
@@ -371,6 +422,17 @@ static void cmd_push_assistant(int argc, char *argv[])
goto fail;
}
+ if (g_dbus_proxy_get_property(cfg->proxy, "State", &iter)) {
+ dbus_message_iter_get_basic(&iter, &cfg->state);
+
+ if (!strcmp(cfg->state, "local")) {
+ /* Prompt user to enter metadata */
+ bt_shell_prompt_input("Assistant",
+ "Enter Device (path):",
+ assistant_set_device_cfg, cfg);
+ return;
+ }
+ }
/* Prompt user to enter metadata */
bt_shell_prompt_input("Assistant",
"Enter Metadata (auto/value):",
diff --git a/client/mgmt.c b/client/mgmt.c
index 255155e41873..968efdbca5b0 100644
--- a/client/mgmt.c
+++ b/client/mgmt.c
@@ -369,7 +369,10 @@ static const char *settings_str[] = {
"cis-central",
"cis-peripheral",
"iso-broadcaster",
- "sync-receiver"
+ "sync-receiver",
+ "ll-privacy",
+ "past-sender",
+ "past-receiver"
};
static const char *settings2str(uint32_t settings)
--
2.51.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH BlueZ v2 13/13] client/assistant: Detect if object already contains a valid BCode
2025-10-09 21:29 [PATCH BlueZ v2 01/13] monitor: Use PAST to refer to Periodic Advertising Sync Transfer Luiz Augusto von Dentz
` (10 preceding siblings ...)
2025-10-09 21:29 ` [PATCH BlueZ v2 12/13] client/assistant: Handle assistant.push to own broadcasts Luiz Augusto von Dentz
@ 2025-10-09 21:29 ` Luiz Augusto von Dentz
2025-10-09 22:51 ` [BlueZ,v2,01/13] monitor: Use PAST to refer to Periodic Advertising Sync Transfer bluez.test.bot
12 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2025-10-09 21:29 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
If assistant object already contains a valid (non-zero) BCode
(e.g state=local) use it instead of always request the user to
re-enter.
---
client/assistant.c | 55 ++++++++++++++++++++++++++++++++++------------
1 file changed, 41 insertions(+), 14 deletions(-)
diff --git a/client/assistant.c b/client/assistant.c
index 1ff8001d7216..ed0c8cdd6c7a 100644
--- a/client/assistant.c
+++ b/client/assistant.c
@@ -293,7 +293,7 @@ fail:
static bool assistant_get_qos(struct assistant_config *cfg)
{
- DBusMessageIter iter, dict, entry, value;
+ DBusMessageIter iter, dict;
const char *key;
/* Get QoS property to check if the stream is encrypted */
@@ -305,22 +305,45 @@ static bool assistant_get_qos(struct assistant_config *cfg)
dbus_message_iter_recurse(&iter, &dict);
- if (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_DICT_ENTRY)
- return false;
+ while (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry, value;
+ int var;
- dbus_message_iter_recurse(&dict, &entry);
- dbus_message_iter_get_basic(&entry, &key);
+ dbus_message_iter_recurse(&dict, &entry);
+ dbus_message_iter_get_basic(&entry, &key);
- if (strcasecmp(key, "Encryption") != 0)
- return false;
+ dbus_message_iter_next(&entry);
+ dbus_message_iter_recurse(&entry, &value);
- dbus_message_iter_next(&entry);
- dbus_message_iter_recurse(&entry, &value);
+ var = dbus_message_iter_get_arg_type(&value);
- if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_BYTE)
- return false;
+ if (!strcasecmp(key, "Encryption")) {
+ if (var != DBUS_TYPE_BYTE)
+ return false;
- dbus_message_iter_get_basic(&value, &cfg->qos.bcast.encryption);
+ dbus_message_iter_get_basic(&value,
+ &cfg->qos.bcast.encryption);
+ } else if (!strcasecmp(key, "BCode")) {
+ DBusMessageIter array;
+ struct iovec iov = {0};
+
+ if (var != DBUS_TYPE_ARRAY)
+ return false;
+
+ dbus_message_iter_recurse(&value, &array);
+ dbus_message_iter_get_fixed_array(&array,
+ &iov.iov_base,
+ (int *)&iov.iov_len);
+
+ if (iov.iov_len != 16) {
+ bt_shell_printf("Invalid size for BCode: "
+ "%zu != 16\n", iov.iov_len);
+ return false;
+ }
+
+ memcpy(cfg->qos.bcast.bcode, iov.iov_base, iov.iov_len);
+ }
+ }
return true;
}
@@ -328,6 +351,7 @@ static bool assistant_get_qos(struct assistant_config *cfg)
static void assistant_set_metadata_cfg(const char *input, void *user_data)
{
struct assistant_config *cfg = user_data;
+ uint8_t no_bcode[16] = {};
if (!strcasecmp(input, "a") || !strcasecmp(input, "auto"))
goto done;
@@ -346,7 +370,8 @@ done:
if (!assistant_get_qos(cfg))
goto fail;
- if (cfg->qos.bcast.encryption)
+ if (cfg->qos.bcast.encryption &&
+ !memcmp(cfg->qos.bcast.bcode, no_bcode, 16))
/* Prompt user to enter the Broadcast Code to decrypt
* the stream
*/
@@ -373,13 +398,15 @@ fail:
static void assistant_set_device_cfg(const char *input, void *user_data)
{
struct assistant_config *cfg = user_data;
+ uint8_t no_bcode[16] = {};
cfg->device = strdup(input);
if (!assistant_get_qos(cfg))
goto fail;
- if (cfg->qos.bcast.encryption) {
+ if (cfg->qos.bcast.encryption &&
+ !memcmp(cfg->qos.bcast.bcode, no_bcode, 16)) {
/* Prompt user to enter the Broadcast Code to decrypt
* the stream
*/
--
2.51.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* RE: [BlueZ,v2,01/13] monitor: Use PAST to refer to Periodic Advertising Sync Transfer
2025-10-09 21:29 [PATCH BlueZ v2 01/13] monitor: Use PAST to refer to Periodic Advertising Sync Transfer Luiz Augusto von Dentz
` (11 preceding siblings ...)
2025-10-09 21:29 ` [PATCH BlueZ v2 13/13] client/assistant: Detect if object already contains a valid BCode Luiz Augusto von Dentz
@ 2025-10-09 22:51 ` bluez.test.bot
12 siblings, 0 replies; 14+ messages in thread
From: bluez.test.bot @ 2025-10-09 22:51 UTC (permalink / raw)
To: linux-bluetooth, luiz.dentz
[-- Attachment #1: Type: text/plain, Size: 2912 bytes --]
This is automated email and please do not reply to this email!
Dear submitter,
Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1009899
---Test result---
Test Summary:
CheckPatch PENDING 0.32 seconds
GitLint PENDING 0.41 seconds
BuildEll PASS 20.43 seconds
BluezMake PASS 2855.29 seconds
MakeCheck PASS 20.08 seconds
MakeDistcheck PASS 182.11 seconds
CheckValgrind PASS 233.33 seconds
CheckSmatch WARNING 306.53 seconds
bluezmakeextell PASS 126.92 seconds
IncrementalBuild PENDING 0.26 seconds
ScanBuild PASS 914.40 seconds
Details
##############################
Test: CheckPatch - PENDING
Desc: Run checkpatch.pl script
Output:
##############################
Test: GitLint - PENDING
Desc: Run gitlint
Output:
##############################
Test: CheckSmatch - WARNING
Desc: Run smatch tool with source
Output:
monitor/packet.c: note: in included file:monitor/display.h:82:26: warning: Variable length array is used.monitor/packet.c:1931:26: warning: Variable length array is used.monitor/packet.c: note: in included file:monitor/bt.h:3837:52: warning: array of flexible structuresmonitor/bt.h:3825:40: warning: array of flexible structuresemulator/btdev.c:459:29: warning: Variable length array is used.emulator/bthost.c:678:28: warning: Variable length array is used.emulator/bthost.c:679:32: warning: Variable length array is used.emulator/bthost.c:896:28: warning: Variable length array is used.emulator/bthost.c:930:28: warning: Variable length array is used.emulator/bthost.c:931:32: warning: Variable length array is used.monitor/packet.c: note: in included file:monitor/display.h:82:26: warning: Variable length array is used.monitor/packet.c:1931:26: warning: Variable length array is used.monitor/packet.c: note: in included file:monitor/bt.h:3837:52: warning: array of flexible structuresmonitor/bt.h:3825:40: warning: array of flexible structuressrc/shared/bap.c:318:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structuressrc/shared/bap.c:318:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structuressrc/shared/bap.c:318:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structures
##############################
Test: IncrementalBuild - PENDING
Desc: Incremental build with the patches in the series
Output:
---
Regards,
Linux Bluetooth
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2025-10-09 22:51 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-09 21:29 [PATCH BlueZ v2 01/13] monitor: Use PAST to refer to Periodic Advertising Sync Transfer Luiz Augusto von Dentz
2025-10-09 21:29 ` [PATCH BlueZ v2 02/13] emulator: Add initial support for PAST Luiz Augusto von Dentz
2025-10-09 21:29 ` [PATCH BlueZ v2 03/13] iso-tester: Add tests for PAST procedures Luiz Augusto von Dentz
2025-10-09 21:29 ` [PATCH BlueZ v2 04/13] monitor: Add support for PAST MGMT settings and flags Luiz Augusto von Dentz
2025-10-09 21:29 ` [PATCH BlueZ v2 05/13] MGMT: Add PAST Settings and Flags Luiz Augusto von Dentz
2025-10-09 21:29 ` [PATCH BlueZ v2 06/13] device: Add initial support for setting DEVICE_FLAG_PAST Luiz Augusto von Dentz
2025-10-09 21:29 ` [PATCH BlueZ v2 07/13] bass: Add " Luiz Augusto von Dentz
2025-10-09 21:29 ` [PATCH BlueZ v2 08/13] iso.rst: Add documentation for PAST/rebind Luiz Augusto von Dentz
2025-10-09 21:29 ` [PATCH BlueZ v2 09/13] shared/bap: Add callback broadcast instances Luiz Augusto von Dentz
2025-10-09 21:29 ` [PATCH BlueZ v2 10/13] MediaAssistant: Add Device option to Push Luiz Augusto von Dentz
2025-10-09 21:29 ` [PATCH BlueZ v2 11/13] bass: Implement Device option for Push Luiz Augusto von Dentz
2025-10-09 21:29 ` [PATCH BlueZ v2 12/13] client/assistant: Handle assistant.push to own broadcasts Luiz Augusto von Dentz
2025-10-09 21:29 ` [PATCH BlueZ v2 13/13] client/assistant: Detect if object already contains a valid BCode Luiz Augusto von Dentz
2025-10-09 22:51 ` [BlueZ,v2,01/13] monitor: Use PAST to refer to Periodic Advertising Sync Transfer bluez.test.bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox