Bluetooth: Allow use of ScanData with BT_LE_ADV_OPT_USE_NAME

This enables the user to provide a ScanData, as long as it contain
names, and set BT_LE_ADV_OPT_USE_NAME.

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
Luiz Augusto von Dentz 2018-07-16 11:45:20 +03:00 committed by Johan Hedberg
commit 18df11646f

View file

@ -4698,11 +4698,16 @@ int bt_enable(bt_ready_cb_t cb)
return 0;
}
static int set_ad(u16_t hci_op, const struct bt_data *ad, size_t ad_len)
struct bt_ad {
const struct bt_data *data;
size_t len;
};
static int set_ad(u16_t hci_op, const struct bt_ad *ad, size_t ad_len)
{
struct bt_hci_cp_le_set_adv_data *set_data;
struct net_buf *buf;
int i;
int c, i;
buf = bt_hci_cmd_create(hci_op, sizeof(*set_data));
if (!buf) {
@ -4713,19 +4718,23 @@ static int set_ad(u16_t hci_op, const struct bt_data *ad, size_t ad_len)
memset(set_data, 0, sizeof(*set_data));
for (i = 0; i < ad_len; i++) {
/* Check if ad fit in the remaining buffer */
if (set_data->len + ad[i].data_len + 2 > 31) {
net_buf_unref(buf);
return -EINVAL;
for (c = 0; c < ad_len; c++) {
const struct bt_data *data = ad[c].data;
for (i = 0; i < ad[c].len; i++) {
/* Check if ad fit in the remaining buffer */
if (set_data->len + data[i].data_len + 2 > 31) {
net_buf_unref(buf);
return -EINVAL;
}
set_data->data[set_data->len++] = data[i].data_len + 1;
set_data->data[set_data->len++] = data[i].type;
memcpy(&set_data->data[set_data->len], data[i].data,
data[i].data_len);
set_data->len += data[i].data_len;
}
set_data->data[set_data->len++] = ad[i].data_len + 1;
set_data->data[set_data->len++] = ad[i].type;
memcpy(&set_data->data[set_data->len], ad[i].data,
ad[i].data_len);
set_data->len += ad[i].data_len;
}
return bt_hci_cmd_send_sync(hci_op, buf, NULL);
@ -4756,10 +4765,11 @@ int bt_set_name(const char *name)
/* Update advertising name if in use */
if (atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING_NAME)) {
struct bt_data sd[] = { BT_DATA(BT_DATA_NAME_COMPLETE, name,
struct bt_data data[] = { BT_DATA(BT_DATA_NAME_COMPLETE, name,
strlen(name)) };
struct bt_ad sd = { data, ARRAY_SIZE(data) };
set_ad(BT_HCI_OP_LE_SET_SCAN_RSP_DATA, sd, ARRAY_SIZE(sd));
set_ad(BT_HCI_OP_LE_SET_SCAN_RSP_DATA, &sd, 1);
/* Make sure the new name is set */
if (atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING)) {
@ -4843,6 +4853,7 @@ int bt_le_adv_start(const struct bt_le_adv_param *param,
{
struct bt_hci_cp_le_set_adv_param set_param;
struct net_buf *buf;
struct bt_ad d[2] = {};
int err;
if (!valid_adv_param(param)) {
@ -4853,37 +4864,51 @@ int bt_le_adv_start(const struct bt_le_adv_param *param,
return -EALREADY;
}
err = set_ad(BT_HCI_OP_LE_SET_ADV_DATA, ad, ad_len);
d[0].data = ad;
d[0].len = ad_len;
err = set_ad(BT_HCI_OP_LE_SET_ADV_DATA, d, 1);
if (err) {
return err;
}
d[0].data = sd;
d[0].len = sd_len;
if (param->options & BT_LE_ADV_OPT_USE_NAME) {
const char *name;
/* Cannot use name if sd is set */
if (sd) {
return -EINVAL;
int i;
/* Cannot use name if name is already set */
for (i = 0; i < sd_len; i++) {
if (sd[i].type == BT_DATA_NAME_COMPLETE ||
sd[i].type == BT_DATA_NAME_SHORTENED) {
return -EINVAL;
}
}
}
name = bt_get_name();
sd = (&(struct bt_data)BT_DATA(BT_DATA_NAME_COMPLETE, name,
strlen(name)));
sd_len = 1;
d[1].data = (&(struct bt_data)BT_DATA(BT_DATA_NAME_COMPLETE,
name, strlen(name)));
d[1].len = 1;
}
/*
* We need to set SCAN_RSP when enabling advertising type that allows
* for Scan Requests.
*
* If sd was not provided but we enable connectable undirected
* If any data was not provided but we enable connectable undirected
* advertising sd needs to be cleared from values set by previous calls.
* Clearing sd is done by calling set_ad() with NULL data and zero len.
* So following condition check is unusual but correct.
*/
if (sd || (param->options & BT_LE_ADV_OPT_CONNECTABLE)) {
err = set_ad(BT_HCI_OP_LE_SET_SCAN_RSP_DATA, sd, sd_len);
if (d[0].data || d[1].data ||
(param->options & BT_LE_ADV_OPT_CONNECTABLE)) {
err = set_ad(BT_HCI_OP_LE_SET_SCAN_RSP_DATA, d, 2);
if (err) {
return err;
}