@@ -91,6 +91,7 @@ struct le_ext_adv {
struct btdev *dev;
uint8_t handle;
uint8_t enable;
+ uint32_t interval;
uint8_t type; /* evt_properties */
uint8_t own_addr_type; /* own_addr_type */
uint8_t direct_addr_type; /* peer_addr_type */
@@ -102,7 +103,8 @@ struct le_ext_adv {
uint8_t adv_data_len;
uint8_t scan_data[252];
uint8_t scan_data_len;
- unsigned int id;
+ unsigned int broadcast_id;
+ unsigned int timeout_id;
};
struct le_per_adv {
@@ -575,8 +577,10 @@ static void le_ext_adv_free(void *data)
/* Remove to queue */
queue_remove(ext_adv->dev->le_ext_adv, ext_adv);
- if (ext_adv->id)
- timeout_remove(ext_adv->id);
+ if (ext_adv->broadcast_id)
+ timeout_remove(ext_adv->broadcast_id);
+ if (ext_adv->timeout_id)
+ timeout_remove(ext_adv->timeout_id);
free(ext_adv);
}
@@ -4759,9 +4763,13 @@ static void ext_adv_disable(void *data, void *user_data)
if (handle && ext_adv->handle != handle)
return;
- if (ext_adv->id) {
- timeout_remove(ext_adv->id);
- ext_adv->id = 0;
+ if (ext_adv->broadcast_id) {
+ timeout_remove(ext_adv->broadcast_id);
+ ext_adv->broadcast_id = 0;
+ }
+ if (ext_adv->timeout_id) {
+ timeout_remove(ext_adv->timeout_id);
+ ext_adv->timeout_id = 0;
}
ext_adv->enable = 0x00;
@@ -4782,6 +4790,8 @@ static struct le_ext_adv *le_ext_adv_new(struct btdev *btdev, uint8_t handle)
ext_adv = new0(struct le_ext_adv, 1);
ext_adv->dev = btdev;
ext_adv->handle = handle;
+ /* Default value for min/max advertising interval shall be 1.28s. */
+ ext_adv->interval = 1280;
/* Add to queue */
if (!queue_push_tail(btdev->le_ext_adv, ext_adv)) {
@@ -4862,6 +4872,23 @@ static int cmd_set_ext_adv_params(struct btdev *dev, const void *data,
}
ext_adv->type = le16_to_cpu(cmd->evt_properties);
+
+ /* In case of direct advertising (type == 0x01) the advertising
+ * intervals shall be ignored and high duty cycle shall be used.
+ */
+ if (ext_adv->type == 0x01)
+ ext_adv->interval = 10;
+ else {
+ unsigned int min_interval = get_le24(cmd->min_interval);
+ if (min_interval < 0x0020 || min_interval > 0x4000) {
+ rsp.status = BT_HCI_ERR_UNSUPPORTED_FEATURE;
+ cmd_complete(dev, BT_HCI_CMD_LE_SET_EXT_ADV_PARAMS,
+ &rsp, sizeof(rsp));
+ return 0;
+ }
+ ext_adv->interval = min_interval * 0.625;
+ }
+
ext_adv->own_addr_type = cmd->own_addr_type;
ext_adv->direct_addr_type = cmd->peer_addr_type;
memcpy(ext_adv->direct_addr, cmd->peer_addr, 6);
@@ -4978,9 +5005,10 @@ static void send_ext_adv(struct btdev *btdev, const struct btdev *remote,
1 + 24 + meta_event.lear.data_len);
}
-static void le_set_ext_adv_enable_complete(struct btdev *btdev,
- struct le_ext_adv *ext_adv)
+static bool ext_adv_broadcast(void *user_data)
{
+ struct le_ext_adv *ext_adv = user_data;
+ struct btdev *btdev = ext_adv->dev;
uint16_t report_type;
int i;
@@ -5016,7 +5044,10 @@ static void le_set_ext_adv_enable_complete(struct btdev *btdev,
report_type, true);
}
}
+
+ return true;
}
+
static void adv_set_terminate(struct btdev *dev, uint8_t status, uint8_t handle,
uint16_t conn_handle, uint8_t num_evts)
{
@@ -5035,7 +5066,7 @@ static bool ext_adv_timeout(void *user_data)
{
struct le_ext_adv *adv = user_data;
- adv->id = 0;
+ adv->timeout_id = 0;
adv_set_terminate(adv->dev, BT_HCI_ERR_ADV_TIMEOUT, adv->handle,
0x0000, 0x00);
le_ext_adv_free(adv);
@@ -5120,32 +5151,28 @@ static int cmd_set_ext_adv_enable(struct btdev *dev, const void *data,
if (!cmd->enable)
ext_adv_disable(ext_adv, NULL);
- else if (eas->duration)
- ext_adv->id = timeout_add(eas->duration * 10,
- ext_adv_timeout,
+ else {
+ /* Send the first advertising report right away and
+ * start the timer for continuous advertising.
+ */
+ ext_adv_broadcast(ext_adv);
+ ext_adv->broadcast_id = timeout_add(ext_adv->interval,
+ ext_adv_broadcast,
ext_adv, NULL);
+ if (eas->duration) {
+ unsigned int duration_ms = eas->duration * 10;
+ ext_adv->timeout_id = timeout_add(duration_ms,
+ ext_adv_timeout,
+ ext_adv, NULL);
+ }
+ }
+
}
exit_complete:
cmd_complete(dev, BT_HCI_CMD_LE_SET_EXT_ADV_ENABLE, &status,
sizeof(status));
- if (status == BT_HCI_ERR_SUCCESS && cmd->enable) {
- /* Go through each sets and send adv event to peer device */
- for (i = 0; i < cmd->num_of_sets; i++) {
- const struct bt_hci_cmd_ext_adv_set *eas;
- struct le_ext_adv *ext_adv;
-
- eas = data + sizeof(*cmd) + (sizeof(*eas) * i);
-
- ext_adv = queue_find(dev->le_ext_adv,
- match_ext_adv_handle,
- UINT_TO_PTR(eas->handle));
- if (ext_adv)
- le_set_ext_adv_enable_complete(dev, ext_adv);
- }
- }
-
return 0;
}
@@ -5495,43 +5522,6 @@ done:
return 0;
}
-static void scan_ext_adv(struct btdev *dev, struct btdev *remote)
-{
- const struct queue_entry *entry;
-
- for (entry = queue_get_entries(remote->le_ext_adv); entry;
- entry = entry->next) {
- struct le_ext_adv *ext_adv = entry->data;
- uint16_t report_type;
-
- if (!ext_adv->enable)
- continue;
-
- if (!ext_adv_match_addr(dev, ext_adv))
- continue;
-
- report_type = get_ext_adv_type(ext_adv->type);
- send_ext_adv(dev, remote, ext_adv, report_type, false);
-
- if (dev->le_scan_type != 0x01)
- continue;
-
- /* if scannable bit is set the send scan response */
- if (ext_adv->type & 0x02) {
- if (ext_adv->type == 0x13)
- report_type = 0x1b;
- else if (ext_adv->type == 0x12)
- report_type = 0x1a;
- else if (!(ext_adv->type & 0x10))
- report_type &= 0x08;
- else
- continue;
-
- send_ext_adv(dev, remote, ext_adv, report_type, true);
- }
- }
-}
-
static void scan_pa(struct btdev *dev, struct btdev *remote)
{
struct le_per_adv *per_adv = queue_find(dev->le_per_adv,
@@ -5560,7 +5550,6 @@ static int cmd_set_ext_scan_enable_complete(struct btdev *dev, const void *data,
if (!btdev_list[i] || btdev_list[i] == dev)
continue;
- scan_ext_adv(dev, btdev_list[i]);
scan_pa(dev, btdev_list[i]);
}