summaryrefslogtreecommitdiff
path: root/emulator
diff options
context:
space:
mode:
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>2022-03-04 17:22:19 -0800
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>2022-03-07 17:18:36 -0800
commitea501af91caed2d1687fe39ff94762ffb1ddf889 (patch)
tree6f0d59cd4eb5016846bdef316d61c2a79fc64455 /emulator
parentb5ab5eee3aea5a22dfbc738a3f6edf9d022c3fe9 (diff)
downloadbluez-ea501af91caed2d1687fe39ff94762ffb1ddf889.tar.gz
btdev: Implement BT_HCI_CMD_LE_PERIODIC_ADV_CREATE_SYNC
This adds implementation of BT_HCI_CMD_LE_PERIODIC_ADV_CREATE_SYNC generating BT_HCI_EVT_LE_PER_SYNC_ESTABLISHED and BT_HCI_EVT_LE_PER_ADV_REPORT.
Diffstat (limited to 'emulator')
-rw-r--r--emulator/btdev.c99
1 files changed, 96 insertions, 3 deletions
diff --git a/emulator/btdev.c b/emulator/btdev.c
index 9189e8082..34469d986 100644
--- a/emulator/btdev.c
+++ b/emulator/btdev.c
@@ -47,6 +47,7 @@
#define ACL_HANDLE 42
#define ISO_HANDLE 257
#define SCO_HANDLE 257
+#define SYC_HANDLE 1
struct hook {
btdev_hook_func handler;
@@ -195,6 +196,7 @@ struct btdev {
uint16_t le_periodic_max_interval;
uint8_t le_periodic_data_len;
uint8_t le_periodic_data[31];
+ uint16_t le_periodic_sync_handle;
uint8_t le_ltk[16];
struct {
struct bt_hci_cmd_le_set_cig_params params;
@@ -5294,8 +5296,99 @@ static int cmd_ext_create_conn_complete(struct btdev *dev, const void *data,
static int cmd_per_adv_create_sync(struct btdev *dev, const void *data,
uint8_t len)
{
- /* TODO */
- return -ENOTSUP;
+ uint8_t status = BT_HCI_ERR_SUCCESS;
+
+ if (dev->le_periodic_sync_handle)
+ status = BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
+ else
+ dev->le_periodic_sync_handle = SYC_HANDLE;
+
+ cmd_status(dev, status, BT_HCI_CMD_LE_PERIODIC_ADV_CREATE_SYNC);
+
+ return 0;
+}
+
+static void send_per_adv(struct btdev *dev, const struct btdev *remote,
+ uint8_t offset)
+{
+ struct __packed {
+ struct bt_hci_le_per_adv_report ev;
+ uint8_t data[31];
+ } pdu;
+
+ memset(&pdu.ev, 0, sizeof(pdu.ev));
+ pdu.ev.handle = cpu_to_le16(dev->le_periodic_sync_handle);
+ pdu.ev.tx_power = 127;
+ pdu.ev.rssi = 127;
+ pdu.ev.cte_type = 0x0ff;
+
+ if ((size_t) remote->le_periodic_data_len - offset > sizeof(pdu.data)) {
+ pdu.ev.data_status = 0x01;
+ pdu.ev.data_len = sizeof(pdu.data);
+ } else {
+ pdu.ev.data_status = 0x00;
+ pdu.ev.data_len = remote->le_periodic_data_len - offset;
+ }
+
+ memcpy(pdu.data, remote->le_periodic_data + offset, pdu.ev.data_len);
+
+ le_meta_event(dev, BT_HCI_EVT_LE_PER_ADV_REPORT, &pdu,
+ sizeof(pdu.ev) + pdu.ev.data_len);
+
+ if (pdu.ev.data_status == 0x01) {
+ offset += pdu.ev.data_len;
+ send_per_adv(dev, remote, offset);
+ }
+}
+
+static void le_per_adv_sync_estabilished(struct btdev *dev,
+ const struct bt_hci_cmd_le_periodic_adv_create_sync *cmd,
+ struct btdev *remote, uint8_t status)
+{
+ struct bt_hci_evt_le_per_sync_established ev;
+
+ memset(&ev, 0, sizeof(ev));
+ ev.status = status;
+
+ if (status) {
+ le_meta_event(dev, BT_HCI_EVT_LE_PER_SYNC_ESTABLISHED, &ev,
+ sizeof(ev));
+ return;
+ }
+
+ ev.handle = cpu_to_le16(dev->le_periodic_sync_handle);
+ ev.addr_type = cmd->addr_type;
+ memcpy(ev.addr, cmd->addr, sizeof(ev.addr));
+ ev.phy = 0x01;
+ ev.interval = remote->le_periodic_min_interval;
+ ev.clock_accuracy = 0x07;
+
+ le_meta_event(dev, BT_HCI_EVT_LE_PER_SYNC_ESTABLISHED, &ev, sizeof(ev));
+ send_per_adv(dev, remote, 0);
+}
+
+static int cmd_per_adv_create_sync_complete(struct btdev *dev, const void *data,
+ uint8_t len)
+{
+ const struct bt_hci_cmd_le_periodic_adv_create_sync *cmd = data;
+ struct btdev *remote;
+
+ /* This command may be issued whether or not scanning is enabled and
+ * scanning may be enabled and disabled (see the LE Set Extended Scan
+ * Enable command) while this command is pending. However,
+ * synchronization can only occur when scanning is enabled. While
+ * scanning is disabled, no attempt to synchronize will take place.
+ */
+ if (!dev->scan_enable)
+ return 0;
+
+ remote = find_btdev_by_bdaddr_type(cmd->addr, cmd->addr_type);
+ if (!remote || !remote->le_periodic_adv_enable)
+ return 0;
+
+ le_per_adv_sync_estabilished(dev, cmd, remote, BT_HCI_ERR_SUCCESS);
+
+ return 0;
}
static int cmd_per_adv_create_sync_cancel(struct btdev *dev, const void *data,
@@ -5420,7 +5513,7 @@ done:
CMD(BT_HCI_CMD_LE_EXT_CREATE_CONN, cmd_ext_create_conn, \
cmd_ext_create_conn_complete), \
CMD(BT_HCI_CMD_LE_PERIODIC_ADV_CREATE_SYNC, cmd_per_adv_create_sync, \
- NULL), \
+ cmd_per_adv_create_sync_complete), \
CMD(BT_HCI_CMD_LE_PERIODIC_ADV_CREATE_SYNC_CANCEL, \
cmd_per_adv_create_sync_cancel, NULL), \
CMD(BT_HCI_CMD_LE_PERIODIC_ADV_TERM_SYNC, cmd_per_adv_term_sync, \