2015-04-04 15:43:51

by Florian Grandel

[permalink] [raw]
Subject: [PATCH] Bluetooth: hci_core/mgmt: Change adv inst to list.

As a preparatory step towards multi-instance advertising it is
necessary to introduce a data structure that supports storing
multiple advertising info data structures for a bluetooth device.

This is introduced by refactoring the existing adv_instance member
of the hci_dev struct into a linked list and making the necessary
changes in the code to support this list.

Signed-off-by: Florian Grandel <[email protected]>
---
include/net/bluetooth/hci_core.h | 21 ++-
net/bluetooth/hci_core.c | 118 +++++++++++++-
net/bluetooth/mgmt.c | 339 +++++++++++++++++++++------------------
3 files changed, 314 insertions(+), 164 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 93fd3e7..69a8f30 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -156,6 +156,8 @@ struct oob_data {
};

struct adv_info {
+ struct list_head list;
+ struct hci_dev *hdev;
struct delayed_work timeout_exp;
__u8 instance;
__u32 flags;
@@ -166,6 +168,8 @@ struct adv_info {
__u8 scan_rsp_data[HCI_MAX_AD_LENGTH];
};

+#define HCI_MAX_ADV_INSTANCES 1
+
#define HCI_MAX_SHORT_NAME_LENGTH 10

/* Default LE RPA expiry time, 15 minutes */
@@ -375,7 +379,8 @@ struct hci_dev {
__u8 scan_rsp_data[HCI_MAX_AD_LENGTH];
__u8 scan_rsp_data_len;

- struct adv_info adv_instance;
+ struct list_head adv_instances;
+ __u8 cur_adv_instance;

__u8 irk[16];
__u32 rpa_timeout;
@@ -563,11 +568,6 @@ static inline void hci_discovery_filter_clear(struct hci_dev *hdev)
hdev->discovery.scan_duration = 0;
}

-static inline void adv_info_init(struct hci_dev *hdev)
-{
- memset(&hdev->adv_instance, 0, sizeof(struct adv_info));
-}
-
bool hci_discovery_active(struct hci_dev *hdev);

void hci_discovery_set_state(struct hci_dev *hdev, int state);
@@ -1009,6 +1009,15 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 bdaddr_type);

+int hci_num_adv_instances(struct hci_dev *hdev);
+void hci_adv_instances_clear(struct hci_dev *hdev);
+struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance);
+int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
+ u16 adv_data_len, u8 *adv_data,
+ u16 scan_rsp_len, u8 *scan_rsp_data,
+ work_func_t timeout_work, u16 timeout);
+int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance);
+
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);

int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 46b114c..15ab2eb 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2613,6 +2613,120 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
return 0;
}

+struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance)
+{
+ struct adv_info *adv_instance;
+
+ list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
+ if (adv_instance->instance != instance)
+ continue;
+ return adv_instance;
+ }
+
+ return NULL;
+}
+
+/* This function requires the caller holds hdev->lock */
+int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance)
+{
+ struct adv_info *adv_instance;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (!adv_instance)
+ return -ENOENT;
+
+ BT_DBG("%s removing %dMR", hdev->name, instance);
+
+ if (adv_instance->timeout)
+ cancel_delayed_work(&adv_instance->timeout_exp);
+
+ list_del(&adv_instance->list);
+ kfree(adv_instance);
+
+ return 0;
+}
+
+/* This function requires the caller holds hdev->lock */
+void hci_adv_instances_clear(struct hci_dev *hdev)
+{
+ struct adv_info *adv_instance, *n;
+
+ list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
+ if (adv_instance->timeout)
+ cancel_delayed_work(&adv_instance->timeout_exp);
+
+ list_del(&adv_instance->list);
+ kfree(adv_instance);
+ }
+}
+
+int hci_num_adv_instances(struct hci_dev *hdev)
+{
+ struct adv_info *adv_instance;
+ int num = 0;
+
+ list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
+ num++;
+ }
+
+ return num;
+}
+
+/* This function requires the caller holds hdev->lock */
+int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
+ u16 adv_data_len, u8 *adv_data,
+ u16 scan_rsp_len, u8 *scan_rsp_data,
+ work_func_t timeout_work, u16 timeout)
+{
+ struct adv_info *adv_instance;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (adv_instance) {
+ if (adv_instance->timeout)
+ cancel_delayed_work(&adv_instance->timeout_exp);
+
+ memset(adv_instance->adv_data, 0,
+ sizeof(adv_instance->adv_data));
+ memset(adv_instance->scan_rsp_data, 0,
+ sizeof(adv_instance->scan_rsp_data));
+ } else {
+ if (hci_num_adv_instances(hdev) >= HCI_MAX_ADV_INSTANCES)
+ return -EOVERFLOW;
+
+ adv_instance = kmalloc(sizeof(*adv_instance), GFP_KERNEL);
+ if (!adv_instance)
+ return -ENOMEM;
+
+ memset(adv_instance, 0, sizeof(*adv_instance));
+ adv_instance->hdev = hdev;
+ INIT_DELAYED_WORK(&adv_instance->timeout_exp, timeout_work);
+ adv_instance->instance = instance;
+ list_add(&adv_instance->list, &hdev->adv_instances);
+ }
+
+ adv_instance->flags = flags;
+ adv_instance->adv_data_len = adv_data_len;
+ adv_instance->scan_rsp_len = scan_rsp_len;
+
+ if (adv_data_len)
+ memcpy(adv_instance->adv_data, adv_data, adv_data_len);
+
+ if (scan_rsp_len)
+ memcpy(adv_instance->scan_rsp_data,
+ scan_rsp_data, scan_rsp_len);
+
+ adv_instance->timeout = timeout;
+
+ if (timeout)
+ queue_delayed_work(hdev->workqueue,
+ &adv_instance->timeout_exp,
+ msecs_to_jiffies(timeout * 1000));
+
+ BT_DBG("%s for %dMR", hdev->name, instance);
+
+ return 0;
+}
+
struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *bdaddr_list,
bdaddr_t *bdaddr, u8 type)
{
@@ -3016,6 +3130,7 @@ struct hci_dev *hci_alloc_dev(void)
hdev->manufacturer = 0xffff; /* Default to internal use */
hdev->inq_tx_power = HCI_TX_POWER_INVALID;
hdev->adv_tx_power = HCI_TX_POWER_INVALID;
+ hdev->cur_adv_instance = 0x00;

hdev->sniff_max_interval = 800;
hdev->sniff_min_interval = 80;
@@ -3057,6 +3172,7 @@ struct hci_dev *hci_alloc_dev(void)
INIT_LIST_HEAD(&hdev->pend_le_conns);
INIT_LIST_HEAD(&hdev->pend_le_reports);
INIT_LIST_HEAD(&hdev->conn_hash.list);
+ INIT_LIST_HEAD(&hdev->adv_instances);

INIT_WORK(&hdev->rx_work, hci_rx_work);
INIT_WORK(&hdev->cmd_work, hci_cmd_work);
@@ -3079,7 +3195,6 @@ struct hci_dev *hci_alloc_dev(void)

hci_init_sysfs(hdev);
discovery_init(hdev);
- adv_info_init(hdev);

return hdev;
}
@@ -3253,6 +3368,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
hci_smp_ltks_clear(hdev);
hci_smp_irks_clear(hdev);
hci_remote_oob_data_clear(hdev);
+ hci_adv_instances_clear(hdev);
hci_bdaddr_list_clear(&hdev->le_white_list);
hci_conn_params_clear_all(hdev);
hci_discovery_filter_clear(hdev);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 845dfcc..5d3e9f0 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -858,31 +858,53 @@ static u8 create_default_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
return ad_len;
}

-static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
+static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 instance,
+ u8 *ptr)
{
- /* TODO: Set the appropriate entries based on advertising instance flags
- * here once flags other than 0 are supported.
+ struct adv_info *adv_instance;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (adv_instance) {
+ /* TODO: Set the appropriate entries based on advertising instance flags
+ * here once flags other than 0 are supported.
+ */
+ memcpy(ptr, adv_instance->scan_rsp_data,
+ adv_instance->scan_rsp_len);
+
+ return adv_instance->scan_rsp_len;
+ }
+
+ return 0;
+}
+
+static u8 get_current_adv_instance(struct hci_dev *hdev)
+{
+ /* The "Set Advertising" setting supersedes the "Add Advertising"
+ * setting. Here we set the advertising data based on which
+ * setting was set. When neither apply, default to the global settings,
+ * represented by instance "0".
*/
- memcpy(ptr, hdev->adv_instance.scan_rsp_data,
- hdev->adv_instance.scan_rsp_len);
+ if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
+ !hci_dev_test_flag(hdev, HCI_ADVERTISING))
+ return hdev->cur_adv_instance;

- return hdev->adv_instance.scan_rsp_len;
+ return 0x00;
}

-static void update_scan_rsp_data_for_instance(struct hci_request *req,
- u8 instance)
+static void update_scan_rsp_data(struct hci_request *req)
{
struct hci_dev *hdev = req->hdev;
struct hci_cp_le_set_scan_rsp_data cp;
- u8 len;
+ u8 instance, len;

if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
return;

memset(&cp, 0, sizeof(cp));

+ instance = get_current_adv_instance(hdev);
if (instance)
- len = create_instance_scan_rsp_data(hdev, cp.data);
+ len = create_instance_scan_rsp_data(hdev, instance, cp.data);
else
len = create_default_scan_rsp_data(hdev, cp.data);

@@ -898,25 +920,6 @@ static void update_scan_rsp_data_for_instance(struct hci_request *req,
hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
}

-static void update_scan_rsp_data(struct hci_request *req)
-{
- struct hci_dev *hdev = req->hdev;
- u8 instance;
-
- /* The "Set Advertising" setting supersedes the "Add Advertising"
- * setting. Here we set the scan response data based on which
- * setting was set. When neither apply, default to the global settings,
- * represented by instance "0".
- */
- if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
- !hci_dev_test_flag(hdev, HCI_ADVERTISING))
- instance = 0x01;
- else
- instance = 0x00;
-
- update_scan_rsp_data_for_instance(req, instance);
-}
-
static u8 get_adv_discov_flags(struct hci_dev *hdev)
{
struct mgmt_pending_cmd *cmd;
@@ -941,20 +944,6 @@ static u8 get_adv_discov_flags(struct hci_dev *hdev)
return 0;
}

-static u8 get_current_adv_instance(struct hci_dev *hdev)
-{
- /* The "Set Advertising" setting supersedes the "Add Advertising"
- * setting. Here we set the advertising data based on which
- * setting was set. When neither apply, default to the global settings,
- * represented by instance "0".
- */
- if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
- !hci_dev_test_flag(hdev, HCI_ADVERTISING))
- return 0x01;
-
- return 0x00;
-}
-
static bool get_connectable(struct hci_dev *hdev)
{
struct mgmt_pending_cmd *cmd;
@@ -975,40 +964,52 @@ static bool get_connectable(struct hci_dev *hdev)
static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance)
{
u32 flags;
+ struct adv_info *adv_instance;

- if (instance > 0x01)
- return 0;
+ if (instance == 0x00) {
+ /* Instance 0 always manages the "Tx Power" and "Flags" fields */
+ flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS;

- if (instance == 0x01)
- return hdev->adv_instance.flags;
+ /* For instance 0, the HCI_ADVERTISING_CONNECTABLE setting corresponds
+ * to the "connectable" instance flag.
+ */
+ if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
+ flags |= MGMT_ADV_FLAG_CONNECTABLE;

- /* Instance 0 always manages the "Tx Power" and "Flags" fields */
- flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS;
+ return flags;
+ }

- /* For instance 0, the HCI_ADVERTISING_CONNECTABLE setting corresponds
- * to the "connectable" instance flag.
- */
- if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
- flags |= MGMT_ADV_FLAG_CONNECTABLE;
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (adv_instance)
+ return adv_instance->flags;

- return flags;
+ return 0;
}

-static u8 get_adv_instance_scan_rsp_len(struct hci_dev *hdev, u8 instance)
+static u8 get_cur_adv_instance_scan_rsp_len(struct hci_dev *hdev)
{
- /* Ignore instance 0 and other unsupported instances */
- if (instance != 0x01)
+ u8 instance = get_current_adv_instance(hdev);
+ struct adv_info *adv_instance;
+
+ /* Ignore instance 0 */
+ if (instance == 0x00)
+ return 0;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (!adv_instance)
return 0;

/* TODO: Take into account the "appearance" and "local-name" flags here.
* These are currently being ignored as they are not supported.
*/
- return hdev->adv_instance.scan_rsp_len;
+ return adv_instance->scan_rsp_len;
}

-static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
+static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr)
{
+ struct adv_info *adv_instance;
u8 ad_len = 0, flags = 0;
+ u8 instance = get_current_adv_instance(hdev);
u32 instance_flags = get_adv_instance_flags(hdev, instance);

/* The Add Advertising command allows userspace to set both the general
@@ -1044,11 +1045,13 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
}

if (instance) {
- memcpy(ptr, hdev->adv_instance.adv_data,
- hdev->adv_instance.adv_data_len);
-
- ad_len += hdev->adv_instance.adv_data_len;
- ptr += hdev->adv_instance.adv_data_len;
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (adv_instance) {
+ memcpy(ptr, adv_instance->adv_data,
+ adv_instance->adv_data_len);
+ ad_len += adv_instance->adv_data_len;
+ ptr += adv_instance->adv_data_len;
+ }
}

/* Provide Tx Power only if we can provide a valid value for it */
@@ -1065,7 +1068,7 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
return ad_len;
}

-static void update_adv_data_for_instance(struct hci_request *req, u8 instance)
+static void update_adv_data(struct hci_request *req)
{
struct hci_dev *hdev = req->hdev;
struct hci_cp_le_set_adv_data cp;
@@ -1076,7 +1079,7 @@ static void update_adv_data_for_instance(struct hci_request *req, u8 instance)

memset(&cp, 0, sizeof(cp));

- len = create_instance_adv_data(hdev, instance, cp.data);
+ len = create_adv_data(hdev, cp.data);

/* There's nothing to do if the data hasn't changed */
if (hdev->adv_data_len == len &&
@@ -1091,14 +1094,6 @@ static void update_adv_data_for_instance(struct hci_request *req, u8 instance)
hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
}

-static void update_adv_data(struct hci_request *req)
-{
- struct hci_dev *hdev = req->hdev;
- u8 instance = get_current_adv_instance(hdev);
-
- update_adv_data_for_instance(req, instance);
-}
-
int mgmt_update_adv_data(struct hci_dev *hdev)
{
struct hci_request req;
@@ -1237,9 +1232,9 @@ static void enable_advertising(struct hci_request *req)
{
struct hci_dev *hdev = req->hdev;
struct hci_cp_le_set_adv_param cp;
+ u8 instance;
u8 own_addr_type, enable = 0x01;
bool connectable;
- u8 instance;
u32 flags;

if (hci_conn_num(hdev, LE_LINK) > 0)
@@ -1277,7 +1272,7 @@ static void enable_advertising(struct hci_request *req)

if (connectable)
cp.type = LE_ADV_IND;
- else if (get_adv_instance_scan_rsp_len(hdev, instance))
+ else if (get_cur_adv_instance_scan_rsp_len(hdev))
cp.type = LE_ADV_SCAN_IND;
else
cp.type = LE_ADV_NONCONN_IND;
@@ -1459,27 +1454,26 @@ static void advertising_removed(struct sock *sk, struct hci_dev *hdev,
mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
}

-static void clear_adv_instance(struct hci_dev *hdev)
+static void clear_adv_instance(struct sock *sk, struct hci_dev *hdev, u8 instance)
{
- struct hci_request req;
-
- if (!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
- return;
-
- if (hdev->adv_instance.timeout)
- cancel_delayed_work(&hdev->adv_instance.timeout_exp);
-
- memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
- advertising_removed(NULL, hdev, 1);
- hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
-
- if (!hdev_is_powered(hdev) ||
- hci_dev_test_flag(hdev, HCI_ADVERTISING))
- return;
+ struct adv_info *adv_instance, *n;
+ int err;

- hci_req_init(&req, hdev);
- disable_advertising(&req);
- hci_req_run(&req, NULL);
+ /* A value of 0 indicates that all instances should be cleared. */
+ if (instance == 0x00) {
+ list_for_each_entry_safe(adv_instance, n,
+ &hdev->adv_instances, list) {
+ err = hci_remove_adv_instance(hdev,
+ adv_instance->instance);
+ if (err == 0)
+ advertising_removed(sk, hdev,
+ adv_instance->instance);
+ }
+ } else {
+ err = hci_remove_adv_instance(hdev, instance);
+ if (err == 0)
+ advertising_removed(sk, hdev, instance);
+ }
}

static int clean_up_hci_state(struct hci_dev *hdev)
@@ -1497,8 +1491,7 @@ static int clean_up_hci_state(struct hci_dev *hdev)
hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
}

- if (hdev->adv_instance.timeout)
- clear_adv_instance(hdev);
+ clear_adv_instance(NULL, hdev, 0x00);

if (hci_dev_test_flag(hdev, HCI_LE_ADV))
disable_advertising(&req);
@@ -4669,6 +4662,7 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status,
{
struct cmd_lookup match = { NULL, hdev };
struct hci_request req;
+ struct adv_info *adv_instance;

hci_dev_lock(hdev);

@@ -4697,11 +4691,14 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status,
* set up earlier, then enable the advertising instance.
*/
if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
- !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
+ !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) ||
+ list_empty(&hdev->adv_instances))
goto unlock;

hci_req_init(&req, hdev);
-
+ adv_instance = list_first_entry(&hdev->adv_instances,
+ struct adv_info, list);
+ hdev->cur_adv_instance = adv_instance->instance;
update_adv_data(&req);
enable_advertising(&req);

@@ -4792,8 +4789,9 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,

if (val) {
/* Switch to instance "0" for the Set Advertising setting. */
- update_adv_data_for_instance(&req, 0);
- update_scan_rsp_data_for_instance(&req, 0);
+ hdev->cur_adv_instance = 0x00;
+ update_adv_data(&req);
+ update_scan_rsp_data(&req);
enable_advertising(&req);
} else {
disable_advertising(&req);
@@ -6631,8 +6629,10 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
{
struct mgmt_rp_read_adv_features *rp;
size_t rp_len;
- int err;
+ int err, i;
bool instance;
+ int num_adv_instances = 0;
+ struct adv_info *adv_instance;
u32 supported_flags;

BT_DBG("%s", hdev->name);
@@ -6650,7 +6650,8 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
*/
instance = hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE);
if (instance)
- rp_len++;
+ num_adv_instances = hci_num_adv_instances(hdev);
+ rp_len += num_adv_instances;

rp = kmalloc(rp_len, GFP_ATOMIC);
if (!rp) {
@@ -6663,16 +6664,15 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
rp->supported_flags = cpu_to_le32(supported_flags);
rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
- rp->max_instances = 1;
+ rp->max_instances = HCI_MAX_ADV_INSTANCES;
+ rp->num_instances = num_adv_instances;

- /* Currently only one instance is supported, so simply return the
- * current instance number.
- */
if (instance) {
- rp->num_instances = 1;
- rp->instance[0] = 1;
- } else {
- rp->num_instances = 0;
+ i = 0;
+ list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
+ rp->instance[i] = adv_instance->instance;
+ i++;
+ }
}

hci_dev_unlock(hdev);
@@ -6732,24 +6732,37 @@ static void add_advertising_complete(struct hci_dev *hdev, u8 status,
u16 opcode)
{
struct mgmt_pending_cmd *cmd;
+ struct mgmt_cp_add_advertising *cp = NULL;
struct mgmt_rp_add_advertising rp;
+ struct adv_info *adv_instance;

BT_DBG("status %d", status);

hci_dev_lock(hdev);

cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
+ if (cmd)
+ cp = cmd->param;

if (status) {
+ /* TODO: Start advertising another adv instance if any? */
hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
- memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
- advertising_removed(cmd ? cmd->sk : NULL, hdev, 1);
+
+ if (cmd) {
+ adv_instance = hci_find_adv_instance(hdev,
+ cp->instance);
+ if (adv_instance) {
+ hci_remove_adv_instance(hdev, cp->instance);
+ advertising_removed(cmd ? cmd->sk : NULL, hdev,
+ cp->instance);
+ }
+ }
}

if (!cmd)
goto unlock;

- rp.instance = 0x01;
+ rp.instance = cp->instance;

if (status)
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
@@ -6766,13 +6779,33 @@ unlock:

static void adv_timeout_expired(struct work_struct *work)
{
- struct hci_dev *hdev = container_of(work, struct hci_dev,
- adv_instance.timeout_exp.work);
+ struct adv_info *adv_instance;
+ struct hci_dev *hdev;
+ int err;
+ struct hci_request req;
+
+ adv_instance = container_of(work, struct adv_info, timeout_exp.work);
+ hdev = adv_instance->hdev;

- hdev->adv_instance.timeout = 0;
+ adv_instance->timeout = 0;

hci_dev_lock(hdev);
- clear_adv_instance(hdev);
+ err = hci_remove_adv_instance(hdev, adv_instance->instance);
+ if (err == 0)
+ advertising_removed(NULL, hdev, adv_instance->instance);
+
+ /* TODO: Schedule the next advertisement instance here if any. */
+ hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
+
+ if (!hdev_is_powered(hdev) ||
+ hci_dev_test_flag(hdev, HCI_ADVERTISING))
+ goto unlock;
+
+ hci_req_init(&req, hdev);
+ disable_advertising(&req);
+ hci_req_run(&req, NULL);
+
+unlock:
hci_dev_unlock(hdev);
}

@@ -6831,38 +6864,30 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}

- INIT_DELAYED_WORK(&hdev->adv_instance.timeout_exp, adv_timeout_expired);
-
- hdev->adv_instance.flags = flags;
- hdev->adv_instance.adv_data_len = cp->adv_data_len;
- hdev->adv_instance.scan_rsp_len = cp->scan_rsp_len;
-
- if (cp->adv_data_len)
- memcpy(hdev->adv_instance.adv_data, cp->data, cp->adv_data_len);
-
- if (cp->scan_rsp_len)
- memcpy(hdev->adv_instance.scan_rsp_data,
- cp->data + cp->adv_data_len, cp->scan_rsp_len);
-
- if (hdev->adv_instance.timeout)
- cancel_delayed_work(&hdev->adv_instance.timeout_exp);
-
- hdev->adv_instance.timeout = timeout;
+ err = hci_add_adv_instance(hdev, cp->instance, flags,
+ cp->adv_data_len, cp->data,
+ cp->scan_rsp_len,
+ cp->data + cp->adv_data_len,
+ adv_timeout_expired, timeout);
+ if (err < 0) {
+ err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
+ MGMT_STATUS_FAILED);
+ goto unlock;
+ }

- if (timeout)
- queue_delayed_work(hdev->workqueue,
- &hdev->adv_instance.timeout_exp,
- msecs_to_jiffies(timeout * 1000));
+ hdev->cur_adv_instance = cp->instance;

+ // TODO: Trigger an advertising added event even when instance
+ // advertising is already switched on?
if (!hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING_INSTANCE))
- advertising_added(sk, hdev, 1);
+ advertising_added(sk, hdev, cp->instance);

/* If the HCI_ADVERTISING flag is set or the device isn't powered then
* we have no HCI communication to make. Simply return.
*/
if (!hdev_is_powered(hdev) ||
hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
- rp.instance = 0x01;
+ rp.instance = cp->instance;
err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
goto unlock;
@@ -6933,12 +6958,11 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,

BT_DBG("%s", hdev->name);

- /* The current implementation only allows modifying instance no 1. A
- * value of 0 indicates that all instances should be cleared.
- */
- if (cp->instance > 1)
- return mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
- MGMT_STATUS_INVALID_PARAMS);
+ if (cp->instance != 0x00) {
+ if (!hci_find_adv_instance(hdev, cp->instance))
+ return mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
+ MGMT_STATUS_INVALID_PARAMS);
+ }

hci_dev_lock(hdev);

@@ -6956,21 +6980,22 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}

- if (hdev->adv_instance.timeout)
- cancel_delayed_work(&hdev->adv_instance.timeout_exp);
-
- memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
-
- advertising_removed(sk, hdev, 1);
+ clear_adv_instance(sk, hdev, cp->instance);

+ /* TODO: Only switch off advertising if the instance list is empty
+ * else switch to the next remaining adv instance. */
hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);

- /* If the HCI_ADVERTISING flag is set or the device isn't powered then
- * we have no HCI communication to make. Simply return.
+ /* If the HCI_ADVERTISING[_INSTANCE] flag is set or the device
+ * isn't powered then we have no HCI communication to make.
+ * Simply return.
+ */
+ /* TODO: Only switch off instance advertising when the flag has
+ * actually been unset (see TODO above).
*/
if (!hdev_is_powered(hdev) ||
hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
- rp.instance = 1;
+ rp.instance = cp->instance;
err = mgmt_cmd_complete(sk, hdev->id,
MGMT_OP_REMOVE_ADVERTISING,
MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
--
1.9.1



2015-04-30 15:46:44

by Florian Grandel

[permalink] [raw]
Subject: Re: [PATCH v3 2/2] Bluetooth: mgmt: Start using multi-adv inst list

Hi Arman,

to answer your remaining review questions...

>> @@ -1044,11 +1047,13 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
>> }
>>
>> if (instance) {
>
> Maybe we should do this check earlier and just return 0 if instance
> doesn't exist. This code worked before since the only valid instances
> were 0x00 and 0x01. Now you may need to do a look up earlier and
> return 0 if instance is non-zero and hci_find_adv_instance returns
> NULL.
>

Agreed. I'm checking for this condition early on now and return 0 when
the current instance identifier is invalid for some reason.

>> -static void clear_adv_instance(struct hci_dev *hdev)
>> +static void clear_adv_instance(struct sock *sk, struct hci_dev *hdev,
>> + u8 instance)
>> {
>> - struct hci_request req;
>> -
>> - if (!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
>> - return;
>> -
>> - if (hdev->adv_instance.timeout)
>> - cancel_delayed_work(&hdev->adv_instance.timeout_exp);
>> -
>> - memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
>> - advertising_removed(NULL, hdev, 1);
>> - hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
>> -
>> - if (!hdev_is_powered(hdev) ||
>> - hci_dev_test_flag(hdev, HCI_ADVERTISING))
>> - return;
>> + struct adv_info *adv_instance, *n;
>> + int err;
>>
>> - hci_req_init(&req, hdev);
>> - disable_advertising(&req);
>> - hci_req_run(&req, NULL);
>
> Why did you remove this logic? Advertising needs to be disabled if
> HCI_ADVERTISING_INSTANCE is set and HCI_ADVERTISING wasn't. Hence most
> of the logic above (within this function) is still needed.

This was a serious oversight on my side. My intention was to deduplicate
code in remove_advertising(). While this is probably a good idea, I just
didn't implement it correctly. For the moment being I removed the
refactoring. I'll propose an improved patch later on. Just not now - my
change set is large enough without that change. ;-)

>
>> + /* A value of 0 indicates that all instances should be cleared. */
>> + if (instance == 0x00) {
>> + list_for_each_entry_safe(adv_instance, n,
>> + &hdev->adv_instances, list) {
>
> Didn't you add a hci_adv_instances_clear for this purpose? Now you
> have nested loops for iterating through the list and doing the lookup.
> If you've added this loop just to send the removed event, then perhaps
> it makes more sense to make advertising_removed public (like
> mgmt_advertising_removed) and to call it from hci.c. Or, just do a
> loop first to send the removed events and then call
> hci_adv_instances_clear.

I implemented the latter proposal.

>> @@ -4697,11 +4694,14 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status,
>> * set up earlier, then enable the advertising instance.
>> */
>> if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
>> - !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
>> + !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) ||
>> + list_empty(&hdev->adv_instances))
>
> We should make sure that the HCI_ADVERTISING_INSTANCE setting is set
> as long as hdev->adv_instances is non-empty and it's not set if the
> list is empty.

I introduced a TODO for that as there are several other similar cases in
the code. The code currently still relies on HCI_MAX_ADV_INSTANCES being
exactly one and should work correctly in that case. All places in the
code that need tweaking for real multi-adv support are marked with TODOs
now.

>
>> @@ -6882,24 +6883,37 @@ static void add_advertising_complete(struct hci_dev *hdev, u8 status,
>> if (status) {
>> + /* TODO: Start advertising another adv instance if any? */
>> hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
>> - memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
>> - advertising_removed(cmd ? cmd->sk : NULL, hdev, 1);
>> +
>> + if (cmd) {
>
> If "cmd" is NULL for whatever reason, then we'll end up leaking the
> instance. Maybe there is a better way to propagate the pending
> instance ID?

I fixed that by introducing a "pending" flag in the adv_info struct.
This also catches other cases, e.g. when no new instance has been
introduced.


>> @@ -6981,38 +7015,31 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
>> goto unlock;
>> }
>>
>> + /* TODO: Trigger an advertising added event even when instance
>> + * advertising is already switched on?
>> + */
>
> With a single instance, what this prevents is sending an "added" event
> for an instance that was previously added. So the TODO doesn't make
> sense in that context but the new code needs to correctly abide by
> that logic. What you actually need to pay attention to is to not send
> any HCI commands to update advertising data every time you add a new
> instance. So maybe add a TODO for that.

I obviously didn't understand the purpose of this code. I refactored the
code to make it work in the way you propose at least for one instance
and introduced a TODO for the real multi-adv case.

> The patch is still a bit too large
> for linux-bluetooth standards and it's a bit difficult to get through,
> so if you can break it down into smaller logical pieces it will be
> easier for the others to review it.

I now split up the code in much more manageable pieces. This comes at
the cost, though, that e2e-tests (mgmt-tester) won't run any more if you
take away parts of the change set. I asked the question on the list,
whether that was ok, but this was probably overlooked. I assume, though,
that such a thing is valid as otherwise there would be no means to
introduce such a strongly coherent patch in multiple pieces. I'm making
sure though (git rebase -i --exec make) that the build will not break
for any of the pieces.

Thanks again for your great in-depth review!

Florian

2015-04-30 15:33:20

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v4 17/17] Bluetooth: hci_core: Remove obsolete adv_instance

Now that the obsolete adv_instance is no longer being referenced
anywhere in the code it can be removed without breaking the build.

Signed-off-by: Florian Grandel <[email protected]>
---
include/net/bluetooth/hci_core.h | 6 ------
net/bluetooth/hci_core.c | 1 -
2 files changed, 7 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 36cc941..f8cf00f 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -378,7 +378,6 @@ struct hci_dev {
__u8 scan_rsp_data[HCI_MAX_AD_LENGTH];
__u8 scan_rsp_data_len;

- struct adv_info adv_instance;
struct list_head adv_instances;
unsigned int adv_instance_cnt;
__u8 cur_adv_instance;
@@ -569,11 +568,6 @@ static inline void hci_discovery_filter_clear(struct hci_dev *hdev)
hdev->discovery.scan_duration = 0;
}

-static inline void adv_info_init(struct hci_dev *hdev)
-{
- memset(&hdev->adv_instance, 0, sizeof(struct adv_info));
-}
-
bool hci_discovery_active(struct hci_dev *hdev);

void hci_discovery_set_state(struct hci_dev *hdev, int state);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index de00e21..95bd4ab 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3190,7 +3190,6 @@ struct hci_dev *hci_alloc_dev(void)

hci_init_sysfs(hdev);
discovery_init(hdev);
- adv_info_init(hdev);

return hdev;
}
--
1.9.1


2015-04-30 15:33:19

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v4 16/17] Bluetooth: multi adv for remove_advertising()

The remove_advertising() and remove_advertising_complete() functions
had a hard coded instance identifier. This is being fixed by referencing
the instance identifier from the management API call instead.

remove_advertising() would not allow for instance identifiers other than
0x01. We now allow for arbitrary and/or multiple instance identifiers
while maintaining the previous semantics that an instance identifier of
0x00 signals that all advertising instances should be removed.

The code is made more readable by factoring advertising instance
management and initialization into the low-level
hci_remove_adv_instance() and hci_adv_instances_clear() functions.

This change still relies on the fact that we only allow for a single
advertising instance as it should only switch off advertising when there
are no more active advertising instances. It should advertise the next
active advertising instance instead in case there are remaining
advertising instances. A corresponding TODO has been inserted into the
code.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 42 +++++++++++++++++++++++++++---------------
1 file changed, 27 insertions(+), 15 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 0a42900..f9d7ee3 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -7084,6 +7084,7 @@ static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
u16 opcode)
{
struct mgmt_pending_cmd *cmd;
+ struct mgmt_cp_remove_advertising *cp;
struct mgmt_rp_remove_advertising rp;

BT_DBG("status %d", status);
@@ -7098,7 +7099,8 @@ static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
if (!cmd)
goto unlock;

- rp.instance = 1;
+ cp = cmd->param;
+ rp.instance = cp->instance;

mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
&rp, sizeof(rp));
@@ -7113,21 +7115,23 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
{
struct mgmt_cp_remove_advertising *cp = data;
struct mgmt_rp_remove_advertising rp;
+ struct adv_info *adv_instance;
int err;
struct mgmt_pending_cmd *cmd;
struct hci_request req;

BT_DBG("%s", hdev->name);

- /* The current implementation only allows modifying instance no 1. A
- * value of 0 indicates that all instances should be cleared.
- */
- if (cp->instance > 1)
- return mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
- MGMT_STATUS_INVALID_PARAMS);
-
hci_dev_lock(hdev);

+ if (cp->instance != 0x00 &&
+ !hci_find_adv_instance(hdev, cp->instance)) {
+ err = mgmt_cmd_status(sk, hdev->id,
+ MGMT_OP_REMOVE_ADVERTISING,
+ MGMT_STATUS_INVALID_PARAMS);
+ goto unlock;
+ }
+
if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
pending_find(MGMT_OP_SET_LE, hdev)) {
@@ -7142,13 +7146,21 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}

- if (hdev->adv_instance.timeout)
- cancel_delayed_work(&hdev->adv_instance.timeout_exp);
-
- memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
-
- advertising_removed(sk, hdev, 1);
+ /* A value of 0 indicates that all instances should be cleared. */
+ if (cp->instance == 0x00) {
+ list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
+ advertising_removed(sk, hdev, adv_instance->instance);
+ }
+ hci_adv_instances_clear(hdev);
+ } else {
+ err = hci_remove_adv_instance(hdev, cp->instance);
+ if (!err)
+ advertising_removed(sk, hdev, cp->instance);
+ }

+ /* TODO: Only switch off advertising if the instance list is empty
+ * else switch to the next remaining adv instance.
+ */
hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);

/* If the HCI_ADVERTISING flag is set or the device isn't powered then
@@ -7156,7 +7168,7 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
*/
if (!hdev_is_powered(hdev) ||
hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
- rp.instance = 1;
+ rp.instance = cp->instance;
err = mgmt_cmd_complete(sk, hdev->id,
MGMT_OP_REMOVE_ADVERTISING,
MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
--
1.9.1


2015-04-30 15:33:18

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v4 15/17] Bluetooth: mgmt: multi adv for clear_adv_instances()

The clean_adv_instance() function could not clean up multiple
advertising instances previously. It is being changed to provide both, a
means to clean up a single instance and cleaning up all instances at
once.

An additional instance parameter is being introduced to achieve this.
Passing in 0x00 to this parameter signifies that all instances should be
cleaned up. This semantics has been chosen similarly to the semantics of
the instance parameter in the remove_advertising() function.

This change still relies on the fact that we only allow a single
advertising instance. When we allow for more than one instance then
advertising should only be disabled when the last instance was cleaned
up, in all other cases the next active advertising instance should be
advertised instead. A corresponding TODO has been inserted into the
code.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 29 ++++++++++++++++++++---------
1 file changed, 20 insertions(+), 9 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 52f3e62..0a42900 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1463,18 +1463,30 @@ static void advertising_removed(struct sock *sk, struct hci_dev *hdev,
mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
}

-static void clear_adv_instance(struct hci_dev *hdev)
+static void clear_adv_instance(struct hci_dev *hdev, u8 instance)
{
+ struct adv_info *adv_instance;
+ int err;
struct hci_request req;

+ /* A value of 0 indicates that all instances should be cleared. */
+ if (instance == 0x00) {
+ list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
+ advertising_removed(NULL, hdev, adv_instance->instance);
+ }
+ hci_adv_instances_clear(hdev);
+ } else {
+ err = hci_remove_adv_instance(hdev, instance);
+ if (!err)
+ advertising_removed(NULL, hdev, instance);
+ }
+
if (!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
return;

- if (hdev->adv_instance.timeout)
- cancel_delayed_work(&hdev->adv_instance.timeout_exp);
-
- memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
- advertising_removed(NULL, hdev, 1);
+ /* TODO: Only switch off advertising if the instance list is empty
+ * else switch to the next remaining adv instance.
+ */
hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);

if (!hdev_is_powered(hdev) ||
@@ -1501,8 +1513,7 @@ static int clean_up_hci_state(struct hci_dev *hdev)
hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
}

- if (hdev->adv_instance.timeout)
- clear_adv_instance(hdev);
+ clear_adv_instance(hdev, 0x00);

if (hci_dev_test_flag(hdev, HCI_LE_ADV))
disable_advertising(&req);
@@ -6951,7 +6962,7 @@ static void adv_timeout_expired(struct work_struct *work)

adv_instance->timeout = 0;
hci_dev_lock(hdev);
- clear_adv_instance(hdev);
+ clear_adv_instance(hdev, adv_instance->instance);
hci_dev_unlock(hdev);
}

--
1.9.1


2015-04-30 15:33:17

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v4 14/17] Bluetooth: mgmt: multi adv for add_advertising()

The add_advertising() function had a hard coded instance identifier.
This is being fixed by adding an arbitrary advertising instance to the
dynamic advertising instance list and updating the current instance
identifier accordingly.

The code is made more readable by factoring advertising instance
management and initialization into a low-level hci_add_adv_instance()
function.

We also make sure that event notifications are correctly dealt with in
the case of multiple advertising instances.

This change still relies on the fact that we only allow for a single
advertising instance as it does not yet provide a means to advertise
several instances in a round-robin fashion. This must be added as soon
as more than one instance will be allowed. A corresponding TODO has been
inserted into the code.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 72 ++++++++++++++++++++++++++++++----------------------
1 file changed, 41 insertions(+), 31 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 92560ae..52f3e62 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -6897,7 +6897,9 @@ static void add_advertising_complete(struct hci_dev *hdev, u8 status,
u16 opcode)
{
struct mgmt_pending_cmd *cmd;
+ struct mgmt_cp_add_advertising *cp;
struct mgmt_rp_add_advertising rp;
+ struct adv_info *adv_instance, *n;

BT_DBG("status %d", status);

@@ -6906,15 +6908,27 @@ static void add_advertising_complete(struct hci_dev *hdev, u8 status,
cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);

if (status) {
+ /* TODO: Start advertising another adv instance if any. */
hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
- memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
- advertising_removed(cmd ? cmd->sk : NULL, hdev, 1);
+ }
+
+ list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
+ if (!adv_instance->pending)
+ continue;
+
+ if (status) {
+ hci_remove_adv_instance(hdev, adv_instance->instance);
+ advertising_removed(cmd ? cmd->sk : NULL, hdev, adv_instance->instance);
+ } else {
+ adv_instance->pending = false;
+ }
}

if (!cmd)
goto unlock;

- rp.instance = 0x01;
+ cp = cmd->param;
+ rp.instance = cp->instance;

if (status)
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
@@ -6950,6 +6964,7 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
u32 supported_flags;
u8 status;
u16 timeout;
+ unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
int err;
struct mgmt_pending_cmd *cmd;
struct hci_request req;
@@ -6964,11 +6979,11 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
flags = __le32_to_cpu(cp->flags);
timeout = __le16_to_cpu(cp->timeout);

- /* The current implementation only supports adding one instance and only
- * a subset of the specified flags.
+ /* The current implementation only supports a subset of the specified
+ * flags.
*/
supported_flags = get_supported_adv_flags(hdev);
- if (cp->instance != 0x01 || (flags & ~supported_flags))
+ if (flags & ~supported_flags)
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
MGMT_STATUS_INVALID_PARAMS);

@@ -6996,38 +7011,33 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}

- INIT_DELAYED_WORK(&hdev->adv_instance.timeout_exp, adv_timeout_expired);
-
- hdev->adv_instance.flags = flags;
- hdev->adv_instance.adv_data_len = cp->adv_data_len;
- hdev->adv_instance.scan_rsp_len = cp->scan_rsp_len;
-
- if (cp->adv_data_len)
- memcpy(hdev->adv_instance.adv_data, cp->data, cp->adv_data_len);
-
- if (cp->scan_rsp_len)
- memcpy(hdev->adv_instance.scan_rsp_data,
- cp->data + cp->adv_data_len, cp->scan_rsp_len);
-
- if (hdev->adv_instance.timeout)
- cancel_delayed_work(&hdev->adv_instance.timeout_exp);
+ err = hci_add_adv_instance(hdev, cp->instance, flags,
+ cp->adv_data_len, cp->data,
+ cp->scan_rsp_len,
+ cp->data + cp->adv_data_len,
+ adv_timeout_expired, timeout);
+ if (err < 0) {
+ err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
+ MGMT_STATUS_FAILED);
+ goto unlock;
+ }

- hdev->adv_instance.timeout = timeout;
+ hdev->cur_adv_instance = cp->instance;

- if (timeout)
- queue_delayed_work(hdev->workqueue,
- &hdev->adv_instance.timeout_exp,
- msecs_to_jiffies(timeout * 1000));
+ hci_dev_set_flag(hdev, HCI_ADVERTISING_INSTANCE);

- if (!hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING_INSTANCE))
- advertising_added(sk, hdev, 1);
+ /* Only trigger an advertising added event if a new instance was
+ * actually added.
+ */
+ if (hdev->adv_instance_cnt > prev_instance_cnt)
+ advertising_added(sk, hdev, cp->instance);

- /* If the HCI_ADVERTISING flag is set or the device isn't powered then
+ /* If we are already advertising or the device isn't powered then
* we have no HCI communication to make. Simply return.
*/
if (!hdev_is_powered(hdev) ||
- hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
- rp.instance = 0x01;
+ hci_dev_test_flag(hdev, HCI_LE_ADV)) {
+ rp.instance = cp->instance;
err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
goto unlock;
--
1.9.1


2015-04-30 15:33:16

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v4 13/17] Bluetooth: mgmt: multi adv for set_advertising_complete()

The set_advertising_complete() method relied on the now obsolete
hci_dev->adv_instance structure. We replace this reference by an
equivalent access to the newly introduced dynamic advertising instance
list.

This solution still relies on the fact that we only allow a single
advertising instance for now. It needs to be further refactored once we
allow more than one advertising instance. A corresponding TODO has been
inserted in the code to make this clear.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 04d1c5a..92560ae 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -4673,6 +4673,7 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status,
{
struct cmd_lookup match = { NULL, hdev };
struct hci_request req;
+ struct adv_info *adv_instance;

hci_dev_lock(hdev);

@@ -4698,14 +4699,26 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status,
sock_put(match.sk);

/* If "Set Advertising" was just disabled and instance advertising was
- * set up earlier, then enable the advertising instance.
+ * set up earlier, then re-enable multi-instance advertising.
*/
if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
- !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
+ !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) ||
+ &hdev->adv_instance_cnt == 0)
goto unlock;

- hci_req_init(&req, hdev);
+ /* We advertise multiple instances in a round robin fashion starting
+ * with the first instance in the list.
+ */
+ /* TODO: Make sure the other instances are actually being advertised
+ * once we set HCI_MAX_ADV_INSTANCES > 1.
+ */
+ adv_instance = list_first_entry(&hdev->adv_instances, struct adv_info,
+ list);
+ if (!adv_instance)
+ goto unlock;

+ hci_req_init(&req, hdev);
+ hdev->cur_adv_instance = adv_instance->instance;
update_adv_data(&req);
enable_advertising(&req);

--
1.9.1


2015-04-30 15:33:15

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v4 12/17] Bluetooth: mgmt: refactor update_*_data()

The update_*_data_for_instance() methods are no longer being referenced
anywhere in the code. To reduce complexity and improve readability,
these methods are being joined with their corresponding update_*_data()
counterparts.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 27 ++++++---------------------
1 file changed, 6 insertions(+), 21 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 7e53eb4..04d1c5a 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -890,18 +890,18 @@ static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 instance,
return adv_instance->scan_rsp_len;
}

-static void update_scan_rsp_data_for_instance(struct hci_request *req,
- u8 instance)
+static void update_scan_rsp_data(struct hci_request *req)
{
struct hci_dev *hdev = req->hdev;
struct hci_cp_le_set_scan_rsp_data cp;
- u8 len;
+ u8 instance, len;

if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
return;

memset(&cp, 0, sizeof(cp));

+ instance = get_current_adv_instance(hdev);
if (instance)
len = create_instance_scan_rsp_data(hdev, instance, cp.data);
else
@@ -919,14 +919,6 @@ static void update_scan_rsp_data_for_instance(struct hci_request *req,
hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
}

-static void update_scan_rsp_data(struct hci_request *req)
-{
- struct hci_dev *hdev = req->hdev;
- u8 instance = get_current_adv_instance(hdev);
-
- update_scan_rsp_data_for_instance(req, instance);
-}
-
static u8 get_adv_discov_flags(struct hci_dev *hdev)
{
struct mgmt_pending_cmd *cmd;
@@ -1084,17 +1076,18 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
return ad_len;
}

-static void update_adv_data_for_instance(struct hci_request *req, u8 instance)
+static void update_adv_data(struct hci_request *req)
{
struct hci_dev *hdev = req->hdev;
struct hci_cp_le_set_adv_data cp;
- u8 len;
+ u8 instance, len;

if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
return;

memset(&cp, 0, sizeof(cp));

+ instance = get_current_adv_instance(hdev);
len = create_instance_adv_data(hdev, instance, cp.data);

/* There's nothing to do if the data hasn't changed */
@@ -1110,14 +1103,6 @@ static void update_adv_data_for_instance(struct hci_request *req, u8 instance)
hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
}

-static void update_adv_data(struct hci_request *req)
-{
- struct hci_dev *hdev = req->hdev;
- u8 instance = get_current_adv_instance(hdev);
-
- update_adv_data_for_instance(req, instance);
-}
-
int mgmt_update_adv_data(struct hci_dev *hdev)
{
struct hci_request req;
--
1.9.1


2015-04-30 15:33:14

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v4 11/17] Bluetooth: mgmt: multi adv for create_instance_adv_data()

The create_instance_adv_data() function could not deal with
multiple advertising instances previously. This is being fixed by
retrieving advertising instances from the newly introduced dynamic
advertising instance list.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 23 ++++++++++++++++-------
1 file changed, 16 insertions(+), 7 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index ef48b24..7e53eb4 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1018,8 +1018,18 @@ static u8 get_cur_adv_instance_scan_rsp_len(struct hci_dev *hdev)

static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
{
+ struct adv_info *adv_instance = NULL;
u8 ad_len = 0, flags = 0;
- u32 instance_flags = get_adv_instance_flags(hdev, instance);
+ u32 instance_flags;
+
+ /* Return 0 when the current instance identifier is invalid. */
+ if (instance) {
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (!adv_instance)
+ return 0;
+ }
+
+ instance_flags = get_adv_instance_flags(hdev, instance);

/* The Add Advertising command allows userspace to set both the general
* and limited discoverable flags.
@@ -1053,12 +1063,11 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
}
}

- if (instance) {
- memcpy(ptr, hdev->adv_instance.adv_data,
- hdev->adv_instance.adv_data_len);
-
- ad_len += hdev->adv_instance.adv_data_len;
- ptr += hdev->adv_instance.adv_data_len;
+ if (adv_instance) {
+ memcpy(ptr, adv_instance->adv_data,
+ adv_instance->adv_data_len);
+ ad_len += adv_instance->adv_data_len;
+ ptr += adv_instance->adv_data_len;
}

/* Provide Tx Power only if we can provide a valid value for it */
--
1.9.1


2015-04-30 15:33:13

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v4 10/17] Bluetooth: mgmt: multi adv for create_instance_scan_rsp_data()

The create_instance_scan_rsp_data() function could not deal with
multiple advertising instances previously. This is being fixed by adding
an additional instance parameter.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 8519789..ef48b24 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -872,15 +872,22 @@ static u8 create_default_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
return ad_len;
}

-static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
+static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 instance,
+ u8 *ptr)
{
+ struct adv_info *adv_instance;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (!adv_instance)
+ return 0;
+
/* TODO: Set the appropriate entries based on advertising instance flags
* here once flags other than 0 are supported.
*/
- memcpy(ptr, hdev->adv_instance.scan_rsp_data,
- hdev->adv_instance.scan_rsp_len);
+ memcpy(ptr, adv_instance->scan_rsp_data,
+ adv_instance->scan_rsp_len);

- return hdev->adv_instance.scan_rsp_len;
+ return adv_instance->scan_rsp_len;
}

static void update_scan_rsp_data_for_instance(struct hci_request *req,
@@ -896,7 +903,7 @@ static void update_scan_rsp_data_for_instance(struct hci_request *req,
memset(&cp, 0, sizeof(cp));

if (instance)
- len = create_instance_scan_rsp_data(hdev, cp.data);
+ len = create_instance_scan_rsp_data(hdev, instance, cp.data);
else
len = create_default_scan_rsp_data(hdev, cp.data);

--
1.9.1


2015-04-30 15:33:12

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v4 09/17] Bluetooth: mgmt: use current adv instance in set_advertising()

The set_advertising() method needs to update the newly introduced
cur_adv_instance member of the hci device. This also allows us to remove
the last remaining references to the ..._for_instance... versions of
the adv data and scan response update functions.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index f65472d..8519789 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -4795,8 +4795,9 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,

if (val) {
/* Switch to instance "0" for the Set Advertising setting. */
- update_adv_data_for_instance(&req, 0);
- update_scan_rsp_data_for_instance(&req, 0);
+ hdev->cur_adv_instance = 0x00;
+ update_adv_data(&req);
+ update_scan_rsp_data(&req);
enable_advertising(&req);
} else {
disable_advertising(&req);
--
1.9.1


2015-04-30 15:33:11

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v4 08/17] Bluetooth: mgmt: multi adv for enable_advertising()

Previously enable_advertising() would rely on
get_adv_instance_scan_rsp_len() which checked for a hard coded instance
identifier. This is being changed to check for the current advertising
instance's scan response length instead. The function is renamed
accordingly.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index acc7efd..f65472d 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -990,16 +990,23 @@ static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance)
return adv_instance->flags;
}

-static u8 get_adv_instance_scan_rsp_len(struct hci_dev *hdev, u8 instance)
+static u8 get_cur_adv_instance_scan_rsp_len(struct hci_dev *hdev)
{
- /* Ignore instance 0 and other unsupported instances */
- if (instance != 0x01)
+ u8 instance = get_current_adv_instance(hdev);
+ struct adv_info *adv_instance;
+
+ /* Ignore instance 0 */
+ if (instance == 0x00)
+ return 0;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (!adv_instance)
return 0;

/* TODO: Take into account the "appearance" and "local-name" flags here.
* These are currently being ignored as they are not supported.
*/
- return hdev->adv_instance.scan_rsp_len;
+ return adv_instance->scan_rsp_len;
}

static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
@@ -1273,7 +1280,7 @@ static void enable_advertising(struct hci_request *req)

if (connectable)
cp.type = LE_ADV_IND;
- else if (get_adv_instance_scan_rsp_len(hdev, instance))
+ else if (get_cur_adv_instance_scan_rsp_len(hdev))
cp.type = LE_ADV_SCAN_IND;
else
cp.type = LE_ADV_NONCONN_IND;
--
1.9.1


2015-04-30 15:33:10

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v4 07/17] Bluetooth: mgmt: improve get_adv_instance_flags() readability

Switch if and else conditions to replace a negative statement by a
positive one which makes the condition more readable.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 30 ++++++++++++++++--------------
1 file changed, 16 insertions(+), 14 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 14414e7..acc7efd 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -966,26 +966,28 @@ static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance)
u32 flags;
struct adv_info *adv_instance;

- if (instance != 0x00) {
- adv_instance = hci_find_adv_instance(hdev, instance);
+ if (instance == 0x00) {
+ /* Instance 0 always manages the "Tx Power" and "Flags"
+ * fields
+ */
+ flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS;

- /* Return 0 when we got an invalid instance identifier. */
- if (!adv_instance)
- return 0;
+ /* For instance 0, the HCI_ADVERTISING_CONNECTABLE setting
+ * corresponds to the "connectable" instance flag.
+ */
+ if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
+ flags |= MGMT_ADV_FLAG_CONNECTABLE;

- return adv_instance->flags;
+ return flags;
}

- /* Instance 0 always manages the "Tx Power" and "Flags" fields */
- flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS;
+ adv_instance = hci_find_adv_instance(hdev, instance);

- /* For instance 0, the HCI_ADVERTISING_CONNECTABLE setting corresponds
- * to the "connectable" instance flag.
- */
- if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
- flags |= MGMT_ADV_FLAG_CONNECTABLE;
+ /* Return 0 when we got an invalid instance identifier. */
+ if (!adv_instance)
+ return 0;

- return flags;
+ return adv_instance->flags;
}

static u8 get_adv_instance_scan_rsp_len(struct hci_dev *hdev, u8 instance)
--
1.9.1


2015-04-30 15:33:09

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v4 06/17] Bluetooth: mgmt: multi adv for get_adv_instance_flags()

The get_adv_instance_flags() would not work with instance identifiers
other than 0x01. This is being fixed so that arbitrary instance
identifiers can be dealt with while still correctly dealing with the
special case of the 0x00 identifier.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index a6b5813..14414e7 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -964,12 +964,17 @@ static bool get_connectable(struct hci_dev *hdev)
static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance)
{
u32 flags;
+ struct adv_info *adv_instance;

- if (instance > 0x01)
- return 0;
+ if (instance != 0x00) {
+ adv_instance = hci_find_adv_instance(hdev, instance);

- if (instance == 0x01)
- return hdev->adv_instance.flags;
+ /* Return 0 when we got an invalid instance identifier. */
+ if (!adv_instance)
+ return 0;
+
+ return adv_instance->flags;
+ }

/* Instance 0 always manages the "Tx Power" and "Flags" fields */
flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS;
--
1.9.1


2015-04-30 15:33:08

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v4 05/17] Bluetooth: mgmt: multi adv for get_current_adv_instance()

Replaces the hard coded instance identifier in
get_current_adv_instance() with the actual current instance identifier
so that this method is prepared to work with more than one advertising
instance.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 55ab2a3..a6b5813 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -841,7 +841,7 @@ static u8 get_current_adv_instance(struct hci_dev *hdev)
*/
if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
!hci_dev_test_flag(hdev, HCI_ADVERTISING))
- return 0x01;
+ return hdev->cur_adv_instance;

return 0x00;
}
--
1.9.1


2015-04-30 15:33:07

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v4 04/17] Bluetooth: mgmt: multi adv for read_adv_features()

The read_adv_features() method had a single instance identifier hard
coded. Refer to the advertising instance list instead to return a
dynamically generated list of instance identifiers.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 21 +++++++++------------
1 file changed, 9 insertions(+), 12 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 9dc4905..55ab2a3 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -6770,8 +6770,9 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
{
struct mgmt_rp_read_adv_features *rp;
size_t rp_len;
- int err;
+ int err, i;
bool instance;
+ struct adv_info *adv_instance;
u32 supported_flags;

BT_DBG("%s", hdev->name);
@@ -6784,12 +6785,9 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,

rp_len = sizeof(*rp);

- /* Currently only one instance is supported, so just add 1 to the
- * response length.
- */
instance = hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE);
if (instance)
- rp_len++;
+ rp_len += hdev->adv_instance_cnt;

rp = kmalloc(rp_len, GFP_ATOMIC);
if (!rp) {
@@ -6803,15 +6801,14 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
rp->max_instances = HCI_MAX_ADV_INSTANCES;
+ rp->num_instances = hdev->adv_instance_cnt;

- /* Currently only one instance is supported, so simply return the
- * current instance number.
- */
if (instance) {
- rp->num_instances = 1;
- rp->instance[0] = 1;
- } else {
- rp->num_instances = 0;
+ i = 0;
+ list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
+ rp->instance[i] = adv_instance->instance;
+ i++;
+ }
}

hci_dev_unlock(hdev);
--
1.9.1


2015-04-30 15:33:05

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v4 02/17] Bluetooth: hci_core: Introduce multi-adv inst list

The current hci dev structure only supports a single advertising
instance. To support multi-instance advertising it is necessary to
introduce a linked list of advertising instances so that multiple
advertising instances can be dynamically added and/or removed.

In a first step, the existing adv_instance member of the hci_dev
struct is supplemented by a linked list of advertising instances.
This patch introduces the list and supporting list management
infrastructure. The list is not being used yet.

Signed-off-by: Florian Grandel <[email protected]>
---
include/net/bluetooth/hci_core.h | 16 ++++++
net/bluetooth/hci_core.c | 112 +++++++++++++++++++++++++++++++++++++++
net/bluetooth/mgmt.c | 10 ++--
3 files changed, 133 insertions(+), 5 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index a056c2b..36cc941 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -156,6 +156,9 @@ struct oob_data {
};

struct adv_info {
+ struct list_head list;
+ struct hci_dev *hdev;
+ bool pending;
struct delayed_work timeout_exp;
__u8 instance;
__u32 flags;
@@ -166,6 +169,8 @@ struct adv_info {
__u8 scan_rsp_data[HCI_MAX_AD_LENGTH];
};

+#define HCI_MAX_ADV_INSTANCES 1
+
#define HCI_MAX_SHORT_NAME_LENGTH 10

/* Default LE RPA expiry time, 15 minutes */
@@ -374,6 +379,9 @@ struct hci_dev {
__u8 scan_rsp_data_len;

struct adv_info adv_instance;
+ struct list_head adv_instances;
+ unsigned int adv_instance_cnt;
+ __u8 cur_adv_instance;

__u8 irk[16];
__u32 rpa_timeout;
@@ -1007,6 +1015,14 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 bdaddr_type);

+void hci_adv_instances_clear(struct hci_dev *hdev);
+struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance);
+int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
+ u16 adv_data_len, u8 *adv_data,
+ u16 scan_rsp_len, u8 *scan_rsp_data,
+ work_func_t timeout_work, u16 timeout);
+int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance);
+
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);

int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 476709b..de00e21 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2613,6 +2613,114 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
return 0;
}

+/* This function requires the caller holds hdev->lock */
+struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance)
+{
+ struct adv_info *adv_instance;
+
+ list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
+ if (adv_instance->instance == instance)
+ return adv_instance;
+ }
+
+ return NULL;
+}
+
+/* This function requires the caller holds hdev->lock */
+int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance)
+{
+ struct adv_info *adv_instance;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (!adv_instance)
+ return -ENOENT;
+
+ BT_DBG("%s removing %dMR", hdev->name, instance);
+
+ if (adv_instance->timeout)
+ cancel_delayed_work(&adv_instance->timeout_exp);
+
+ list_del(&adv_instance->list);
+ kfree(adv_instance);
+
+ hdev->adv_instance_cnt--;
+
+ return 0;
+}
+
+/* This function requires the caller holds hdev->lock */
+void hci_adv_instances_clear(struct hci_dev *hdev)
+{
+ struct adv_info *adv_instance, *n;
+
+ list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
+ if (adv_instance->timeout)
+ cancel_delayed_work(&adv_instance->timeout_exp);
+
+ list_del(&adv_instance->list);
+ kfree(adv_instance);
+ }
+
+ hdev->adv_instance_cnt = 0;
+}
+
+/* This function requires the caller holds hdev->lock */
+int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
+ u16 adv_data_len, u8 *adv_data,
+ u16 scan_rsp_len, u8 *scan_rsp_data,
+ work_func_t timeout_work, u16 timeout)
+{
+ struct adv_info *adv_instance;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (adv_instance) {
+ if (adv_instance->timeout)
+ cancel_delayed_work(&adv_instance->timeout_exp);
+
+ memset(adv_instance->adv_data, 0,
+ sizeof(adv_instance->adv_data));
+ memset(adv_instance->scan_rsp_data, 0,
+ sizeof(adv_instance->scan_rsp_data));
+ } else {
+ if (hdev->adv_instance_cnt >= HCI_MAX_ADV_INSTANCES)
+ return -EOVERFLOW;
+
+ adv_instance = kmalloc(sizeof(*adv_instance), GFP_KERNEL);
+ if (!adv_instance)
+ return -ENOMEM;
+
+ memset(adv_instance, 0, sizeof(*adv_instance));
+ adv_instance->hdev = hdev;
+ adv_instance->pending = true;
+ INIT_DELAYED_WORK(&adv_instance->timeout_exp, timeout_work);
+ adv_instance->instance = instance;
+ list_add(&adv_instance->list, &hdev->adv_instances);
+ hdev->adv_instance_cnt++;
+ }
+
+ adv_instance->flags = flags;
+ adv_instance->adv_data_len = adv_data_len;
+ adv_instance->scan_rsp_len = scan_rsp_len;
+
+ if (adv_data_len)
+ memcpy(adv_instance->adv_data, adv_data, adv_data_len);
+
+ if (scan_rsp_len)
+ memcpy(adv_instance->scan_rsp_data,
+ scan_rsp_data, scan_rsp_len);
+
+ adv_instance->timeout = timeout;
+
+ if (timeout)
+ queue_delayed_work(hdev->workqueue,
+ &adv_instance->timeout_exp,
+ msecs_to_jiffies(timeout * 1000));
+
+ BT_DBG("%s for %dMR", hdev->name, instance);
+
+ return 0;
+}
+
struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *bdaddr_list,
bdaddr_t *bdaddr, u8 type)
{
@@ -3016,6 +3124,8 @@ struct hci_dev *hci_alloc_dev(void)
hdev->manufacturer = 0xffff; /* Default to internal use */
hdev->inq_tx_power = HCI_TX_POWER_INVALID;
hdev->adv_tx_power = HCI_TX_POWER_INVALID;
+ hdev->adv_instance_cnt = 0;
+ hdev->cur_adv_instance = 0x00;

hdev->sniff_max_interval = 800;
hdev->sniff_min_interval = 80;
@@ -3057,6 +3167,7 @@ struct hci_dev *hci_alloc_dev(void)
INIT_LIST_HEAD(&hdev->pend_le_conns);
INIT_LIST_HEAD(&hdev->pend_le_reports);
INIT_LIST_HEAD(&hdev->conn_hash.list);
+ INIT_LIST_HEAD(&hdev->adv_instances);

INIT_WORK(&hdev->rx_work, hci_rx_work);
INIT_WORK(&hdev->cmd_work, hci_cmd_work);
@@ -3250,6 +3361,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
hci_smp_ltks_clear(hdev);
hci_smp_irks_clear(hdev);
hci_remote_oob_data_clear(hdev);
+ hci_adv_instances_clear(hdev);
hci_bdaddr_list_clear(&hdev->le_white_list);
hci_conn_params_clear_all(hdev);
hci_discovery_filter_clear(hdev);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 7fd87e7..ce25b6d 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -6813,7 +6813,7 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
rp->supported_flags = cpu_to_le32(supported_flags);
rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
- rp->max_instances = 1;
+ rp->max_instances = HCI_MAX_ADV_INSTANCES;

/* Currently only one instance is supported, so simply return the
* current instance number.
@@ -6916,11 +6916,11 @@ unlock:

static void adv_timeout_expired(struct work_struct *work)
{
- struct hci_dev *hdev = container_of(work, struct hci_dev,
- adv_instance.timeout_exp.work);
-
- hdev->adv_instance.timeout = 0;
+ struct adv_info *adv_instance = container_of(work, struct adv_info,
+ timeout_exp.work);
+ struct hci_dev *hdev = adv_instance->hdev;

+ adv_instance->timeout = 0;
hci_dev_lock(hdev);
clear_adv_instance(hdev);
hci_dev_unlock(hdev);
--
1.9.1


2015-04-30 15:33:06

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v4 03/17] Bluetooth: mgmt: dry update_scan_rsp_data()

update_scan_rsp_data() duplicates code from get_current_adv_instance().
This is being fixed by letting the former make use of the latter.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 41 +++++++++++++++--------------------------
1 file changed, 15 insertions(+), 26 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index ce25b6d..9dc4905 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -832,6 +832,20 @@ static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
}

+static u8 get_current_adv_instance(struct hci_dev *hdev)
+{
+ /* The "Set Advertising" setting supersedes the "Add Advertising"
+ * setting. Here we set the advertising data based on which
+ * setting was set. When neither apply, default to the global settings,
+ * represented by instance "0".
+ */
+ if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
+ !hci_dev_test_flag(hdev, HCI_ADVERTISING))
+ return 0x01;
+
+ return 0x00;
+}
+
static u8 create_default_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
{
u8 ad_len = 0;
@@ -901,18 +915,7 @@ static void update_scan_rsp_data_for_instance(struct hci_request *req,
static void update_scan_rsp_data(struct hci_request *req)
{
struct hci_dev *hdev = req->hdev;
- u8 instance;
-
- /* The "Set Advertising" setting supersedes the "Add Advertising"
- * setting. Here we set the scan response data based on which
- * setting was set. When neither apply, default to the global settings,
- * represented by instance "0".
- */
- if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
- !hci_dev_test_flag(hdev, HCI_ADVERTISING))
- instance = 0x01;
- else
- instance = 0x00;
+ u8 instance = get_current_adv_instance(hdev);

update_scan_rsp_data_for_instance(req, instance);
}
@@ -941,20 +944,6 @@ static u8 get_adv_discov_flags(struct hci_dev *hdev)
return 0;
}

-static u8 get_current_adv_instance(struct hci_dev *hdev)
-{
- /* The "Set Advertising" setting supersedes the "Add Advertising"
- * setting. Here we set the advertising data based on which
- * setting was set. When neither apply, default to the global settings,
- * represented by instance "0".
- */
- if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
- !hci_dev_test_flag(hdev, HCI_ADVERTISING))
- return 0x01;
-
- return 0x00;
-}
-
static bool get_connectable(struct hci_dev *hdev)
{
struct mgmt_pending_cmd *cmd;
--
1.9.1


2015-04-30 15:33:04

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v4 01/17] tools/mgmt_tester: expect 0 rp when removing all adv inst

The kernel would previously return a hard coded instance value of 0x01
even when removing multiple advertising instances. This was ok as long
as we only had a single advertising instance but no longer makes sense
now that we allow for multiple advertising instances.

We therefore expect the mgmt API to return zero when multiple instances
have been removed. This corresponds to the semantics of the mgmt API
call made in the first place.

The corresponding test is updated to reflect that logic.
---
tools/mgmt-tester.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index c0f58ce..4c62a6b 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -4465,8 +4465,8 @@ static const struct generic_data remove_advertising_success_2 = {
.send_param = remove_advertising_param_2,
.send_len = sizeof(remove_advertising_param_2),
.expect_status = MGMT_STATUS_SUCCESS,
- .expect_param = remove_advertising_param_1,
- .expect_len = sizeof(remove_advertising_param_1),
+ .expect_param = remove_advertising_param_2,
+ .expect_len = sizeof(remove_advertising_param_2),
.expect_alt_ev = MGMT_EV_ADVERTISING_REMOVED,
.expect_alt_ev_param = advertising_instance_param,
.expect_alt_ev_len = sizeof(advertising_instance_param),
--
1.9.1


2015-04-30 15:33:03

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v4 00/17] BlueZ/Bluetooth: Multi-advertising infrastructure

This is a patch set introducing the infrastructure for multi-advertising
capability to the HCI core and mgmt API.

v1 -> v2:
- add missing braces in read_adv_features()

v2 -> v3:
- split change-set into several patches
- replace err == 0 by !err
- fix coding style problems

v3 -> v4:
publicly visible change:
- when calling remove_advertising with an instance value of zero (i.e.
remove all instances), the command response also returns an instance
value of zero now as it doesn't make sense to return a single instance
id when removing several instances

refactoring and fixes (due to Arman's review):
- splitting the change set into a much larger number of patches to
facilitate review
- use HCI_MAX_ADV_INSTANCES in the same patch that introduces it
- use adv_info->hdev in the same patch that introduces it
- make the logic of hci_find_adv_instance() more readable
- make sure that hci_find_adv_instance() is called while hci_dev is
locked
- replace hci_num_adv_instances() by an instance counter in hci_dev
- add inline comment in get_adv_instance_flags() explaining its return
value in the error case
- generate zero-length adv data if the current instance identifier is
invalid
- revert erroneous changes to the logic in clear_adv_instance()
- use hci_adv_instances_clear() in clear_adv_instance() when removing
all advertising instances also removing a reduntant error check
- inserting TODO messages to make sure that advertising will not be
switched off prematurely once we allow more than one advertising
instance
- inserting TODO messages to make sure that multiple advertising
instances will be advertised in a round-robin fashion once we allow
for more than one advertising instance
- identify peding advertising instances (just added but not yet
confirmed in add_advertising_complete) by a boolean flag in the
adv_info struct so that we can identify and remove them even when
the pending add_advertising command cannot be retrieved for some
reason - makes sure that we do not lead advertising instances in this
case
- only send HCI commands to update advertising data when a new instance
has actually been added



Userland:

Florian Grandel (1):
tools/mgmt_tester: expect 0 rp when removing all adv inst

tools/mgmt-tester.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)



Kernel:

Florian Grandel (16):
Bluetooth: hci_core: Introduce multi-adv inst list
Bluetooth: mgmt: dry update_scan_rsp_data()
Bluetooth: mgmt: multi adv for read_adv_features()
Bluetooth: mgmt: multi adv for get_current_adv_instance()
Bluetooth: mgmt: multi adv for get_adv_instance_flags()
Bluetooth: mgmt: improve get_adv_instance_flags() readability
Bluetooth: mgmt: multi adv for enable_advertising()
Bluetooth: mgmt: use current adv instance in set_advertising()
Bluetooth: mgmt: multi adv for create_instance_scan_rsp_data()
Bluetooth: mgmt: multi adv for create_instance_adv_data()
Bluetooth: mgmt: refactor update_*_data()
Bluetooth: mgmt: multi adv for set_advertising_complete()
Bluetooth: mgmt: multi adv for add_advertising()
Bluetooth: mgmt: multi adv for clear_adv_instances()
Bluetooth: multi adv for remove_advertising()
Bluetooth: hci_core: Remove obsolete adv_instance

include/net/bluetooth/hci_core.h | 22 ++-
net/bluetooth/hci_core.c | 113 ++++++++++++-
net/bluetooth/mgmt.c | 352 ++++++++++++++++++++++-----------------
3 files changed, 328 insertions(+), 159 deletions(-)

--
1.9.1


2015-04-29 12:20:55

by Florian Grandel

[permalink] [raw]
Subject: Re: [PATCH v3 1/2] Bluetooth: hci_core: Introduce multi-adv inst list

Hi Arman,

answers to your questions below:

>> @@ -374,6 +377,8 @@ struct hci_dev {
>> __u8 scan_rsp_data_len;
>>
>> struct adv_info adv_instance;
>
> Is this still needed?

I leave this variable in the first patch and remove it in the second to
get smaller patches without breaking the build. Is this ok?

>> diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
>> index 476709b..1859e67 100644
>> --- a/net/bluetooth/hci_core.c
>> +++ b/net/bluetooth/hci_core.c
>> @@ -2613,6 +2613,119 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
>> return 0;
>> }
>>
>> +struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance)
>> +{
>
> Doesn't this require a lock as well?

Good catch, I actually found an instance where I called this method
before locking hdev. Fixed.

>> + struct adv_info *adv_instance;
>> +
>> + list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
>> + if (adv_instance->instance != instance)
>> + continue;
>> + return adv_instance;
Florian

2015-04-24 11:43:54

by Florian Grandel

[permalink] [raw]
Subject: Re: [PATCH v3 2/2] Bluetooth: mgmt: Start using multi-adv inst list

Hi Arman,

just wanted to send you a big personal "thank you" that you took all
that time to review my code so thoroughly. I'll have time over the
week-end to build in your recommendations which sound reasonable to me
throughout.

On 04/24/2015 03:33 AM, Arman Uguray wrote:
> Hi Florian,
>
>> On Thu, Apr 9, 2015 at 7:30 PM, Florian Grandel <[email protected]> wrote:
>> To prepare the mgmt api for multiple advertising instances it must be
>> refactored to use the new advertising instance linked list:
>> - refactor all prior references to the adv_instance member of the
>> hci_dev struct to use the new dynamic list,
>> - remove the then unused adv_instance member,
>> - replace hard coded instance ids by references to the current
>> instance id saved in the hci_dev struct
>>
>> Signed-off-by: Florian Grandel <[email protected]>
>> ---
>> include/net/bluetooth/hci_core.h | 7 +-
>> net/bluetooth/hci_core.c | 2 +-
>> net/bluetooth/mgmt.c | 349 +++++++++++++++++++++------------------
>> 3 files changed, 191 insertions(+), 167 deletions(-)
>>
>> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
>> index 98678eb..8c19f38 100644
>> --- a/include/net/bluetooth/hci_core.h
>> +++ b/include/net/bluetooth/hci_core.h
>> @@ -157,6 +157,7 @@ struct oob_data {
>>
>> struct adv_info {
>> struct list_head list;
>> + struct hci_dev *hdev;
>> struct delayed_work timeout_exp;
>> __u8 instance;
>> __u32 flags;
>> @@ -376,7 +377,6 @@ struct hci_dev {
>> __u8 scan_rsp_data[HCI_MAX_AD_LENGTH];
>> __u8 scan_rsp_data_len;
>>
>> - struct adv_info adv_instance;
>> struct list_head adv_instances;
>> __u8 cur_adv_instance;
>>
>> @@ -566,11 +566,6 @@ static inline void hci_discovery_filter_clear(struct hci_dev *hdev)
>> hdev->discovery.scan_duration = 0;
>> }
>>
>> -static inline void adv_info_init(struct hci_dev *hdev)
>> -{
>> - memset(&hdev->adv_instance, 0, sizeof(struct adv_info));
>> -}
>> -
>> bool hci_discovery_active(struct hci_dev *hdev);
>>
>> void hci_discovery_set_state(struct hci_dev *hdev, int state);
>> diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
>> index 1859e67..8ac53cf 100644
>> --- a/net/bluetooth/hci_core.c
>> +++ b/net/bluetooth/hci_core.c
>> @@ -2698,6 +2698,7 @@ int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
>> return -ENOMEM;
>>
>> memset(adv_instance, 0, sizeof(*adv_instance));
>> + adv_instance->hdev = hdev;
>
> Include this fix in your previous patch (1/2) rather than here.
>
>> INIT_DELAYED_WORK(&adv_instance->timeout_exp, timeout_work);
>> adv_instance->instance = instance;
>> list_add(&adv_instance->list, &hdev->adv_instances);
>> @@ -3194,7 +3195,6 @@ struct hci_dev *hci_alloc_dev(void)
>>
>> hci_init_sysfs(hdev);
>> discovery_init(hdev);
>> - adv_info_init(hdev);
>>
>> return hdev;
>> }
>> diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
>> index 7fd87e7..199e312 100644
>> --- a/net/bluetooth/mgmt.c
>> +++ b/net/bluetooth/mgmt.c
>> @@ -858,31 +858,53 @@ static u8 create_default_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
>> return ad_len;
>> }
>>
>> -static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
>> +static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 instance,
>> + u8 *ptr)
>> {
>> - /* TODO: Set the appropriate entries based on advertising instance flags
>> - * here once flags other than 0 are supported.
>> + struct adv_info *adv_instance;
>> +
>> + adv_instance = hci_find_adv_instance(hdev, instance);
>> + if (adv_instance) {
>> + /* TODO: Set the appropriate entries based on advertising
>> + * instance flags here once flags other than 0 are supported.
>> + */
>> + memcpy(ptr, adv_instance->scan_rsp_data,
>> + adv_instance->scan_rsp_len);
>> +
>> + return adv_instance->scan_rsp_len;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static u8 get_current_adv_instance(struct hci_dev *hdev)
>> +{
>> + /* The "Set Advertising" setting supersedes the "Add Advertising"
>> + * setting. Here we set the advertising data based on which
>> + * setting was set. When neither apply, default to the global settings,
>> + * represented by instance "0".
>> */
>> - memcpy(ptr, hdev->adv_instance.scan_rsp_data,
>> - hdev->adv_instance.scan_rsp_len);
>> + if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
>> + !hci_dev_test_flag(hdev, HCI_ADVERTISING))
>> + return hdev->cur_adv_instance;
>>
>> - return hdev->adv_instance.scan_rsp_len;
>> + return 0x00;
>> }
>>
>> -static void update_scan_rsp_data_for_instance(struct hci_request *req,
>> - u8 instance)
>> +static void update_scan_rsp_data(struct hci_request *req)
>> {
>> struct hci_dev *hdev = req->hdev;
>> struct hci_cp_le_set_scan_rsp_data cp;
>> - u8 len;
>> + u8 instance, len;
>>
>> if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
>> return;
>>
>> memset(&cp, 0, sizeof(cp));
>>
>> + instance = get_current_adv_instance(hdev);
>> if (instance)
>> - len = create_instance_scan_rsp_data(hdev, cp.data);
>> + len = create_instance_scan_rsp_data(hdev, instance, cp.data);
>> else
>> len = create_default_scan_rsp_data(hdev, cp.data);
>>
>> @@ -898,25 +920,6 @@ static void update_scan_rsp_data_for_instance(struct hci_request *req,
>> hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
>> }
>>
>> -static void update_scan_rsp_data(struct hci_request *req)
>> -{
>> - struct hci_dev *hdev = req->hdev;
>> - u8 instance;
>> -
>> - /* The "Set Advertising" setting supersedes the "Add Advertising"
>> - * setting. Here we set the scan response data based on which
>> - * setting was set. When neither apply, default to the global settings,
>> - * represented by instance "0".
>> - */
>> - if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
>> - !hci_dev_test_flag(hdev, HCI_ADVERTISING))
>> - instance = 0x01;
>> - else
>> - instance = 0x00;
>> -
>> - update_scan_rsp_data_for_instance(req, instance);
>> -}
>> -
>> static u8 get_adv_discov_flags(struct hci_dev *hdev)
>> {
>> struct mgmt_pending_cmd *cmd;
>> @@ -941,20 +944,6 @@ static u8 get_adv_discov_flags(struct hci_dev *hdev)
>> return 0;
>> }
>>
>> -static u8 get_current_adv_instance(struct hci_dev *hdev)
>> -{
>> - /* The "Set Advertising" setting supersedes the "Add Advertising"
>> - * setting. Here we set the advertising data based on which
>> - * setting was set. When neither apply, default to the global settings,
>> - * represented by instance "0".
>> - */
>> - if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
>> - !hci_dev_test_flag(hdev, HCI_ADVERTISING))
>> - return 0x01;
>> -
>> - return 0x00;
>> -}
>> -
>> static bool get_connectable(struct hci_dev *hdev)
>> {
>> struct mgmt_pending_cmd *cmd;
>> @@ -975,40 +964,54 @@ static bool get_connectable(struct hci_dev *hdev)
>> static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance)
>> {
>> u32 flags;
>> + struct adv_info *adv_instance;
>>
>> - if (instance > 0x01)
>> - return 0;
>> + if (instance == 0x00) {
>> + /* Instance 0 always manages the "Tx Power" and "Flags"
>> + * fields.
>> + */
>> + flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS;
>>
>> - if (instance == 0x01)
>> - return hdev->adv_instance.flags;
>> + /* For instance 0, the HCI_ADVERTISING_CONNECTABLE setting
>> + * corresponds to the "connectable" instance flag.
>> + */
>> + if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
>> + flags |= MGMT_ADV_FLAG_CONNECTABLE;
>>
>> - /* Instance 0 always manages the "Tx Power" and "Flags" fields */
>> - flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS;
>> + return flags;
>> + }
>>
>> - /* For instance 0, the HCI_ADVERTISING_CONNECTABLE setting corresponds
>> - * to the "connectable" instance flag.
>> - */
>> - if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
>> - flags |= MGMT_ADV_FLAG_CONNECTABLE;
>> + adv_instance = hci_find_adv_instance(hdev, instance);
>> + if (adv_instance)
>> + return adv_instance->flags;
>>
>> - return flags;
>
> Add a comment right here saying that "instance" is invalid so we're returning 0.
>
>> + return 0;
>> }
>>
>> -static u8 get_adv_instance_scan_rsp_len(struct hci_dev *hdev, u8 instance)
>> +static u8 get_cur_adv_instance_scan_rsp_len(struct hci_dev *hdev)
>> {
>> - /* Ignore instance 0 and other unsupported instances */
>> - if (instance != 0x01)
>> + u8 instance = get_current_adv_instance(hdev);
>> + struct adv_info *adv_instance;
>> +
>> + /* Ignore instance 0 */
>> + if (instance == 0x00)
>> + return 0;
>> +
>> + adv_instance = hci_find_adv_instance(hdev, instance);
>> + if (!adv_instance)
>> return 0;
>>
>> /* TODO: Take into account the "appearance" and "local-name" flags here.
>> * These are currently being ignored as they are not supported.
>> */
>> - return hdev->adv_instance.scan_rsp_len;
>> + return adv_instance->scan_rsp_len;
>> }
>>
>> -static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
>> +static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr)
>> {
>> + struct adv_info *adv_instance;
>> u8 ad_len = 0, flags = 0;
>> + u8 instance = get_current_adv_instance(hdev);
>> u32 instance_flags = get_adv_instance_flags(hdev, instance);
>>
>> /* The Add Advertising command allows userspace to set both the general
>> @@ -1044,11 +1047,13 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
>> }
>>
>> if (instance) {
>
> Maybe we should do this check earlier and just return 0 if instance
> doesn't exist. This code worked before since the only valid instances
> were 0x00 and 0x01. Now you may need to do a look up earlier and
> return 0 if instance is non-zero and hci_find_adv_instance returns
> NULL.
>
>> - memcpy(ptr, hdev->adv_instance.adv_data,
>> - hdev->adv_instance.adv_data_len);
>> -
>> - ad_len += hdev->adv_instance.adv_data_len;
>> - ptr += hdev->adv_instance.adv_data_len;
>> + adv_instance = hci_find_adv_instance(hdev, instance);
>> + if (adv_instance) {
>> + memcpy(ptr, adv_instance->adv_data,
>> + adv_instance->adv_data_len);
>> + ad_len += adv_instance->adv_data_len;
>> + ptr += adv_instance->adv_data_len;
>> + }
>> }
>>
>> /* Provide Tx Power only if we can provide a valid value for it */
>> @@ -1065,7 +1070,7 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
>> return ad_len;
>> }
>>
>> -static void update_adv_data_for_instance(struct hci_request *req, u8 instance)
>> +static void update_adv_data(struct hci_request *req)
>> {
>> struct hci_dev *hdev = req->hdev;
>> struct hci_cp_le_set_adv_data cp;
>> @@ -1076,7 +1081,7 @@ static void update_adv_data_for_instance(struct hci_request *req, u8 instance)
>>
>> memset(&cp, 0, sizeof(cp));
>>
>> - len = create_instance_adv_data(hdev, instance, cp.data);
>> + len = create_adv_data(hdev, cp.data);
>>
>> /* There's nothing to do if the data hasn't changed */
>> if (hdev->adv_data_len == len &&
>> @@ -1091,14 +1096,6 @@ static void update_adv_data_for_instance(struct hci_request *req, u8 instance)
>> hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
>> }
>>
>> -static void update_adv_data(struct hci_request *req)
>> -{
>> - struct hci_dev *hdev = req->hdev;
>> - u8 instance = get_current_adv_instance(hdev);
>> -
>> - update_adv_data_for_instance(req, instance);
>> -}
>> -
>> int mgmt_update_adv_data(struct hci_dev *hdev)
>> {
>> struct hci_request req;
>> @@ -1277,7 +1274,7 @@ static void enable_advertising(struct hci_request *req)
>>
>> if (connectable)
>> cp.type = LE_ADV_IND;
>> - else if (get_adv_instance_scan_rsp_len(hdev, instance))
>> + else if (get_cur_adv_instance_scan_rsp_len(hdev))
>> cp.type = LE_ADV_SCAN_IND;
>> else
>> cp.type = LE_ADV_NONCONN_IND;
>> @@ -1459,27 +1456,27 @@ static void advertising_removed(struct sock *sk, struct hci_dev *hdev,
>> mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
>> }
>>
>> -static void clear_adv_instance(struct hci_dev *hdev)
>> +static void clear_adv_instance(struct sock *sk, struct hci_dev *hdev,
>> + u8 instance)
>> {
>> - struct hci_request req;
>> -
>> - if (!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
>> - return;
>> -
>> - if (hdev->adv_instance.timeout)
>> - cancel_delayed_work(&hdev->adv_instance.timeout_exp);
>> -
>> - memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
>> - advertising_removed(NULL, hdev, 1);
>> - hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
>> -
>> - if (!hdev_is_powered(hdev) ||
>> - hci_dev_test_flag(hdev, HCI_ADVERTISING))
>> - return;
>> + struct adv_info *adv_instance, *n;
>> + int err;
>>
>> - hci_req_init(&req, hdev);
>> - disable_advertising(&req);
>> - hci_req_run(&req, NULL);
>
> Why did you remove this logic? Advertising needs to be disabled if
> HCI_ADVERTISING_INSTANCE is set and HCI_ADVERTISING wasn't. Hence most
> of the logic above (within this function) is still needed.
>
>> + /* A value of 0 indicates that all instances should be cleared. */
>> + if (instance == 0x00) {
>> + list_for_each_entry_safe(adv_instance, n,
>> + &hdev->adv_instances, list) {
>
> Didn't you add a hci_adv_instances_clear for this purpose? Now you
> have nested loops for iterating through the list and doing the lookup.
> If you've added this loop just to send the removed event, then perhaps
> it makes more sense to make advertising_removed public (like
> mgmt_advertising_removed) and to call it from hci.c. Or, just do a
> loop first to send the removed events and then call
> hci_adv_instances_clear.
>
>> + err = hci_remove_adv_instance(hdev,
>> + adv_instance->instance);
>> + if (!err)
>
> This error check isn't really necessary since you're looping through
> valid instances.
>
>> + advertising_removed(sk, hdev,
>> + adv_instance->instance);
>> + }
>> + } else {
>> + err = hci_remove_adv_instance(hdev, instance);
>> + if (!err)
>> + advertising_removed(sk, hdev, instance);
>> + }
>> }
>>
>> static int clean_up_hci_state(struct hci_dev *hdev)
>> @@ -1497,8 +1494,7 @@ static int clean_up_hci_state(struct hci_dev *hdev)
>> hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
>> }
>>
>> - if (hdev->adv_instance.timeout)
>> - clear_adv_instance(hdev);
>> + clear_adv_instance(NULL, hdev, 0x00);
>>
>> if (hci_dev_test_flag(hdev, HCI_LE_ADV))
>> disable_advertising(&req);
>> @@ -4669,6 +4665,7 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status,
>> {
>> struct cmd_lookup match = { NULL, hdev };
>> struct hci_request req;
>> + struct adv_info *adv_instance;
>>
>> hci_dev_lock(hdev);
>>
>> @@ -4697,11 +4694,14 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status,
>> * set up earlier, then enable the advertising instance.
>> */
>> if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
>> - !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
>> + !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) ||
>> + list_empty(&hdev->adv_instances))
>
> We should make sure that the HCI_ADVERTISING_INSTANCE setting is set
> as long as hdev->adv_instances is non-empty and it's not set if the
> list is empty.
>
>> goto unlock;
>>
>> hci_req_init(&req, hdev);
>> -
>> + adv_instance = list_first_entry(&hdev->adv_instances,
>> + struct adv_info, list);
>> + hdev->cur_adv_instance = adv_instance->instance;
>
> Add a comment here explaining why we're picking the first instance.
> Why does this make sense and will this need to be updated in the
> future? Add a TODO if necessary.
>
>> update_adv_data(&req);
>> enable_advertising(&req);
>>
>> @@ -4792,8 +4792,9 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
>>
>> if (val) {
>> /* Switch to instance "0" for the Set Advertising setting. */
>> - update_adv_data_for_instance(&req, 0);
>> - update_scan_rsp_data_for_instance(&req, 0);
>> + hdev->cur_adv_instance = 0x00;
>> + update_adv_data(&req);
>> + update_scan_rsp_data(&req);
>> enable_advertising(&req);
>> } else {
>> disable_advertising(&req);
>> @@ -6781,8 +6782,10 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
>> {
>> struct mgmt_rp_read_adv_features *rp;
>> size_t rp_len;
>> - int err;
>> + int err, i;
>> bool instance;
>> + int num_adv_instances = 0;
>> + struct adv_info *adv_instance;
>> u32 supported_flags;
>>
>> BT_DBG("%s", hdev->name);
>> @@ -6795,12 +6798,11 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
>>
>> rp_len = sizeof(*rp);
>>
>> - /* Currently only one instance is supported, so just add 1 to the
>> - * response length.
>> - */
>> instance = hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE);
>> - if (instance)
>> - rp_len++;
>> + if (instance) {
>> + num_adv_instances = hci_num_adv_instances(hdev);
>> + rp_len += num_adv_instances;
>> + }
>>
>> rp = kmalloc(rp_len, GFP_ATOMIC);
>> if (!rp) {
>> @@ -6813,16 +6815,15 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
>> rp->supported_flags = cpu_to_le32(supported_flags);
>> rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
>> rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
>> - rp->max_instances = 1;
>> + rp->max_instances = HCI_MAX_ADV_INSTANCES;
>
> Saw that you've done this here, so ignore my comment about this in
> your previous patch.
>
>> + rp->num_instances = num_adv_instances;
>>
>> - /* Currently only one instance is supported, so simply return the
>> - * current instance number.
>> - */
>> if (instance) {
>> - rp->num_instances = 1;
>> - rp->instance[0] = 1;
>> - } else {
>> - rp->num_instances = 0;
>> + i = 0;
>> + list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
>> + rp->instance[i] = adv_instance->instance;
>> + i++;
>> + }
>> }
>>
>> hci_dev_unlock(hdev);
>> @@ -6882,24 +6883,37 @@ static void add_advertising_complete(struct hci_dev *hdev, u8 status,
>> u16 opcode)
>> {
>> struct mgmt_pending_cmd *cmd;
>> + struct mgmt_cp_add_advertising *cp = NULL;
>> struct mgmt_rp_add_advertising rp;
>> + struct adv_info *adv_instance;
>>
>> BT_DBG("status %d", status);
>>
>> hci_dev_lock(hdev);
>>
>> cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
>> + if (cmd)
>> + cp = cmd->param;
>
> This makes the code complicated. Just check if (!cmd) and goto unlock,
> so you won't need all the nested checks.
>>
>> if (status) {
>> + /* TODO: Start advertising another adv instance if any? */
>> hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
>> - memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
>> - advertising_removed(cmd ? cmd->sk : NULL, hdev, 1);
>> +
>> + if (cmd) {
>
> If "cmd" is NULL for whatever reason, then we'll end up leaking the
> instance. Maybe there is a better way to propagate the pending
> instance ID?
>
>> + adv_instance = hci_find_adv_instance(hdev,
>> + cp->instance);
>> + if (adv_instance) {
>> + hci_remove_adv_instance(hdev, cp->instance);
>> + advertising_removed(cmd ? cmd->sk : NULL, hdev,
>> + cp->instance);
>> + }
>> + }
>> }
>>
>> if (!cmd)
>> goto unlock;
>>
>> - rp.instance = 0x01;
>> + rp.instance = cp->instance;
>>
>> if (status)
>> mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
>> @@ -6916,13 +6930,33 @@ unlock:
>>
>> static void adv_timeout_expired(struct work_struct *work)
>> {
>> - struct hci_dev *hdev = container_of(work, struct hci_dev,
>> - adv_instance.timeout_exp.work);
>> + struct adv_info *adv_instance;
>> + struct hci_dev *hdev;
>> + int err;
>> + struct hci_request req;
>>
>> - hdev->adv_instance.timeout = 0;
>> + adv_instance = container_of(work, struct adv_info, timeout_exp.work);
>> + hdev = adv_instance->hdev;
>> +
>> + adv_instance->timeout = 0;
>>
>> hci_dev_lock(hdev);
>> - clear_adv_instance(hdev);
>> + err = hci_remove_adv_instance(hdev, adv_instance->instance);
>> + if (!err)
>> + advertising_removed(NULL, hdev, adv_instance->instance);
>> +
>> + /* TODO: Schedule the next advertisement instance here if any. */
>> + hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
>> +
>> + if (!hdev_is_powered(hdev) ||
>> + hci_dev_test_flag(hdev, HCI_ADVERTISING))
>> + goto unlock;
>> +
>> + hci_req_init(&req, hdev);
>> + disable_advertising(&req);
>> + hci_req_run(&req, NULL);
>
> clr_adv_instance did/does exactly the code above, why are you
> duplicating it here again?
>
>> +
>> +unlock:
>> hci_dev_unlock(hdev);
>> }
>>
>> @@ -6981,38 +7015,31 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
>> goto unlock;
>> }
>>
>> - INIT_DELAYED_WORK(&hdev->adv_instance.timeout_exp, adv_timeout_expired);
>> -
>> - hdev->adv_instance.flags = flags;
>> - hdev->adv_instance.adv_data_len = cp->adv_data_len;
>> - hdev->adv_instance.scan_rsp_len = cp->scan_rsp_len;
>> -
>> - if (cp->adv_data_len)
>> - memcpy(hdev->adv_instance.adv_data, cp->data, cp->adv_data_len);
>> -
>> - if (cp->scan_rsp_len)
>> - memcpy(hdev->adv_instance.scan_rsp_data,
>> - cp->data + cp->adv_data_len, cp->scan_rsp_len);
>> -
>> - if (hdev->adv_instance.timeout)
>> - cancel_delayed_work(&hdev->adv_instance.timeout_exp);
>> -
>> - hdev->adv_instance.timeout = timeout;
>> + err = hci_add_adv_instance(hdev, cp->instance, flags,
>> + cp->adv_data_len, cp->data,
>> + cp->scan_rsp_len,
>> + cp->data + cp->adv_data_len,
>> + adv_timeout_expired, timeout);
>> + if (err < 0) {
>> + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
>> + MGMT_STATUS_FAILED);
>> + goto unlock;
>> + }
>>
>> - if (timeout)
>> - queue_delayed_work(hdev->workqueue,
>> - &hdev->adv_instance.timeout_exp,
>> - msecs_to_jiffies(timeout * 1000));
>> + hdev->cur_adv_instance = cp->instance;
>>
>> + /* TODO: Trigger an advertising added event even when instance
>> + * advertising is already switched on?
>> + */
>
> With a single instance, what this prevents is sending an "added" event
> for an instance that was previously added. So the TODO doesn't make
> sense in that context but the new code needs to correctly abide by
> that logic. What you actually need to pay attention to is to not send
> any HCI commands to update advertising data every time you add a new
> instance. So maybe add a TODO for that.
>
>> if (!hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING_INSTANCE))
>> - advertising_added(sk, hdev, 1);
>> + advertising_added(sk, hdev, cp->instance);
>>
>> /* If the HCI_ADVERTISING flag is set or the device isn't powered then
>> * we have no HCI communication to make. Simply return.
>> */
>> if (!hdev_is_powered(hdev) ||
>> hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
>> - rp.instance = 0x01;
>> + rp.instance = cp->instance;
>> err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
>> MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
>> goto unlock;
>> @@ -7083,12 +7110,12 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
>>
>> BT_DBG("%s", hdev->name);
>>
>> - /* The current implementation only allows modifying instance no 1. A
>> - * value of 0 indicates that all instances should be cleared.
>> - */
>> - if (cp->instance > 1)
>> - return mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
>> - MGMT_STATUS_INVALID_PARAMS);
>> + if (cp->instance != 0x00) {
>> + if (!hci_find_adv_instance(hdev, cp->instance))
>
> if (cp->instance != 0x00 && !hci_find_adv_instance(hdev, cp->instance))
>
>> + return mgmt_cmd_status(sk, hdev->id,
>> + MGMT_OP_REMOVE_ADVERTISING,
>> + MGMT_STATUS_INVALID_PARAMS);
>> + }
>>
>> hci_dev_lock(hdev);
>>
>> @@ -7106,21 +7133,23 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
>> goto unlock;
>> }
>>
>> - if (hdev->adv_instance.timeout)
>> - cancel_delayed_work(&hdev->adv_instance.timeout_exp);
>> -
>> - memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
>> -
>> - advertising_removed(sk, hdev, 1);
>> + clear_adv_instance(sk, hdev, cp->instance);
>>
>> + /* TODO: Only switch off advertising if the instance list is empty
>> + * else switch to the next remaining adv instance.
>> + */
>> hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
>>
>> - /* If the HCI_ADVERTISING flag is set or the device isn't powered then
>> - * we have no HCI communication to make. Simply return.
>> + /* If the HCI_ADVERTISING[_INSTANCE] flag is set or the device
>> + * isn't powered then we have no HCI communication to make.
>> + * Simply return.
>> + */
>> + /* TODO: Only switch off instance advertising when the flag has
>> + * actually been unset (see TODO above).
>> */
>> if (!hdev_is_powered(hdev) ||
>> hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
>> - rp.instance = 1;
>> + rp.instance = cp->instance;
>> err = mgmt_cmd_complete(sk, hdev->id,
>> MGMT_OP_REMOVE_ADVERTISING,
>> MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
>> --
>> 1.9.1
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
>> the body of a message to [email protected]
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
>
> I think, aside from a few issues, this is going in the right
> direction, so thanks for the patch. The patch is still a bit too large
> for linux-bluetooth standards and it's a bit difficult to get through,
> so if you can break it down into smaller logical pieces it will be
> easier for the others to review it.

That's a question that I still don't have a good response for: I'm
thinking all the time how this patch could be split up to make it easier
for the others to review. I already asked this question on the list but
understandably got no response as one would have to look through the
patch (as you did) to propose something.

It seems to me that the changes are so strongly dependent on each other
that it is very hard to split up the patch without breaking either the
build or the functionality.

Even now I'm already making a compromise by building up parallel
structures in the first patch which are then removed in the second. You
commented on it as you found it strange, too. Seems unavoidable to me,
though.

Do you have any idea, now that you looked at the code?

> I'm not an official maintainer on
> the kernel side so either Johan or Marcel will need to sign off on
> your patches.
>
> Thanks,
> Arman
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>

Florian

2015-04-24 01:33:39

by Arman Uguray

[permalink] [raw]
Subject: Re: [PATCH v3 2/2] Bluetooth: mgmt: Start using multi-adv inst list

Hi Florian,

> On Thu, Apr 9, 2015 at 7:30 PM, Florian Grandel <[email protected]> wrote:
> To prepare the mgmt api for multiple advertising instances it must be
> refactored to use the new advertising instance linked list:
> - refactor all prior references to the adv_instance member of the
> hci_dev struct to use the new dynamic list,
> - remove the then unused adv_instance member,
> - replace hard coded instance ids by references to the current
> instance id saved in the hci_dev struct
>
> Signed-off-by: Florian Grandel <[email protected]>
> ---
> include/net/bluetooth/hci_core.h | 7 +-
> net/bluetooth/hci_core.c | 2 +-
> net/bluetooth/mgmt.c | 349 +++++++++++++++++++++------------------
> 3 files changed, 191 insertions(+), 167 deletions(-)
>
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index 98678eb..8c19f38 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -157,6 +157,7 @@ struct oob_data {
>
> struct adv_info {
> struct list_head list;
> + struct hci_dev *hdev;
> struct delayed_work timeout_exp;
> __u8 instance;
> __u32 flags;
> @@ -376,7 +377,6 @@ struct hci_dev {
> __u8 scan_rsp_data[HCI_MAX_AD_LENGTH];
> __u8 scan_rsp_data_len;
>
> - struct adv_info adv_instance;
> struct list_head adv_instances;
> __u8 cur_adv_instance;
>
> @@ -566,11 +566,6 @@ static inline void hci_discovery_filter_clear(struct hci_dev *hdev)
> hdev->discovery.scan_duration = 0;
> }
>
> -static inline void adv_info_init(struct hci_dev *hdev)
> -{
> - memset(&hdev->adv_instance, 0, sizeof(struct adv_info));
> -}
> -
> bool hci_discovery_active(struct hci_dev *hdev);
>
> void hci_discovery_set_state(struct hci_dev *hdev, int state);
> diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
> index 1859e67..8ac53cf 100644
> --- a/net/bluetooth/hci_core.c
> +++ b/net/bluetooth/hci_core.c
> @@ -2698,6 +2698,7 @@ int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
> return -ENOMEM;
>
> memset(adv_instance, 0, sizeof(*adv_instance));
> + adv_instance->hdev = hdev;

Include this fix in your previous patch (1/2) rather than here.

> INIT_DELAYED_WORK(&adv_instance->timeout_exp, timeout_work);
> adv_instance->instance = instance;
> list_add(&adv_instance->list, &hdev->adv_instances);
> @@ -3194,7 +3195,6 @@ struct hci_dev *hci_alloc_dev(void)
>
> hci_init_sysfs(hdev);
> discovery_init(hdev);
> - adv_info_init(hdev);
>
> return hdev;
> }
> diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
> index 7fd87e7..199e312 100644
> --- a/net/bluetooth/mgmt.c
> +++ b/net/bluetooth/mgmt.c
> @@ -858,31 +858,53 @@ static u8 create_default_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
> return ad_len;
> }
>
> -static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
> +static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 instance,
> + u8 *ptr)
> {
> - /* TODO: Set the appropriate entries based on advertising instance flags
> - * here once flags other than 0 are supported.
> + struct adv_info *adv_instance;
> +
> + adv_instance = hci_find_adv_instance(hdev, instance);
> + if (adv_instance) {
> + /* TODO: Set the appropriate entries based on advertising
> + * instance flags here once flags other than 0 are supported.
> + */
> + memcpy(ptr, adv_instance->scan_rsp_data,
> + adv_instance->scan_rsp_len);
> +
> + return adv_instance->scan_rsp_len;
> + }
> +
> + return 0;
> +}
> +
> +static u8 get_current_adv_instance(struct hci_dev *hdev)
> +{
> + /* The "Set Advertising" setting supersedes the "Add Advertising"
> + * setting. Here we set the advertising data based on which
> + * setting was set. When neither apply, default to the global settings,
> + * represented by instance "0".
> */
> - memcpy(ptr, hdev->adv_instance.scan_rsp_data,
> - hdev->adv_instance.scan_rsp_len);
> + if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
> + !hci_dev_test_flag(hdev, HCI_ADVERTISING))
> + return hdev->cur_adv_instance;
>
> - return hdev->adv_instance.scan_rsp_len;
> + return 0x00;
> }
>
> -static void update_scan_rsp_data_for_instance(struct hci_request *req,
> - u8 instance)
> +static void update_scan_rsp_data(struct hci_request *req)
> {
> struct hci_dev *hdev = req->hdev;
> struct hci_cp_le_set_scan_rsp_data cp;
> - u8 len;
> + u8 instance, len;
>
> if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
> return;
>
> memset(&cp, 0, sizeof(cp));
>
> + instance = get_current_adv_instance(hdev);
> if (instance)
> - len = create_instance_scan_rsp_data(hdev, cp.data);
> + len = create_instance_scan_rsp_data(hdev, instance, cp.data);
> else
> len = create_default_scan_rsp_data(hdev, cp.data);
>
> @@ -898,25 +920,6 @@ static void update_scan_rsp_data_for_instance(struct hci_request *req,
> hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
> }
>
> -static void update_scan_rsp_data(struct hci_request *req)
> -{
> - struct hci_dev *hdev = req->hdev;
> - u8 instance;
> -
> - /* The "Set Advertising" setting supersedes the "Add Advertising"
> - * setting. Here we set the scan response data based on which
> - * setting was set. When neither apply, default to the global settings,
> - * represented by instance "0".
> - */
> - if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
> - !hci_dev_test_flag(hdev, HCI_ADVERTISING))
> - instance = 0x01;
> - else
> - instance = 0x00;
> -
> - update_scan_rsp_data_for_instance(req, instance);
> -}
> -
> static u8 get_adv_discov_flags(struct hci_dev *hdev)
> {
> struct mgmt_pending_cmd *cmd;
> @@ -941,20 +944,6 @@ static u8 get_adv_discov_flags(struct hci_dev *hdev)
> return 0;
> }
>
> -static u8 get_current_adv_instance(struct hci_dev *hdev)
> -{
> - /* The "Set Advertising" setting supersedes the "Add Advertising"
> - * setting. Here we set the advertising data based on which
> - * setting was set. When neither apply, default to the global settings,
> - * represented by instance "0".
> - */
> - if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
> - !hci_dev_test_flag(hdev, HCI_ADVERTISING))
> - return 0x01;
> -
> - return 0x00;
> -}
> -
> static bool get_connectable(struct hci_dev *hdev)
> {
> struct mgmt_pending_cmd *cmd;
> @@ -975,40 +964,54 @@ static bool get_connectable(struct hci_dev *hdev)
> static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance)
> {
> u32 flags;
> + struct adv_info *adv_instance;
>
> - if (instance > 0x01)
> - return 0;
> + if (instance == 0x00) {
> + /* Instance 0 always manages the "Tx Power" and "Flags"
> + * fields.
> + */
> + flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS;
>
> - if (instance == 0x01)
> - return hdev->adv_instance.flags;
> + /* For instance 0, the HCI_ADVERTISING_CONNECTABLE setting
> + * corresponds to the "connectable" instance flag.
> + */
> + if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
> + flags |= MGMT_ADV_FLAG_CONNECTABLE;
>
> - /* Instance 0 always manages the "Tx Power" and "Flags" fields */
> - flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS;
> + return flags;
> + }
>
> - /* For instance 0, the HCI_ADVERTISING_CONNECTABLE setting corresponds
> - * to the "connectable" instance flag.
> - */
> - if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
> - flags |= MGMT_ADV_FLAG_CONNECTABLE;
> + adv_instance = hci_find_adv_instance(hdev, instance);
> + if (adv_instance)
> + return adv_instance->flags;
>
> - return flags;

Add a comment right here saying that "instance" is invalid so we're returning 0.

> + return 0;
> }
>
> -static u8 get_adv_instance_scan_rsp_len(struct hci_dev *hdev, u8 instance)
> +static u8 get_cur_adv_instance_scan_rsp_len(struct hci_dev *hdev)
> {
> - /* Ignore instance 0 and other unsupported instances */
> - if (instance != 0x01)
> + u8 instance = get_current_adv_instance(hdev);
> + struct adv_info *adv_instance;
> +
> + /* Ignore instance 0 */
> + if (instance == 0x00)
> + return 0;
> +
> + adv_instance = hci_find_adv_instance(hdev, instance);
> + if (!adv_instance)
> return 0;
>
> /* TODO: Take into account the "appearance" and "local-name" flags here.
> * These are currently being ignored as they are not supported.
> */
> - return hdev->adv_instance.scan_rsp_len;
> + return adv_instance->scan_rsp_len;
> }
>
> -static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
> +static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr)
> {
> + struct adv_info *adv_instance;
> u8 ad_len = 0, flags = 0;
> + u8 instance = get_current_adv_instance(hdev);
> u32 instance_flags = get_adv_instance_flags(hdev, instance);
>
> /* The Add Advertising command allows userspace to set both the general
> @@ -1044,11 +1047,13 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
> }
>
> if (instance) {

Maybe we should do this check earlier and just return 0 if instance
doesn't exist. This code worked before since the only valid instances
were 0x00 and 0x01. Now you may need to do a look up earlier and
return 0 if instance is non-zero and hci_find_adv_instance returns
NULL.

> - memcpy(ptr, hdev->adv_instance.adv_data,
> - hdev->adv_instance.adv_data_len);
> -
> - ad_len += hdev->adv_instance.adv_data_len;
> - ptr += hdev->adv_instance.adv_data_len;
> + adv_instance = hci_find_adv_instance(hdev, instance);
> + if (adv_instance) {
> + memcpy(ptr, adv_instance->adv_data,
> + adv_instance->adv_data_len);
> + ad_len += adv_instance->adv_data_len;
> + ptr += adv_instance->adv_data_len;
> + }
> }
>
> /* Provide Tx Power only if we can provide a valid value for it */
> @@ -1065,7 +1070,7 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
> return ad_len;
> }
>
> -static void update_adv_data_for_instance(struct hci_request *req, u8 instance)
> +static void update_adv_data(struct hci_request *req)
> {
> struct hci_dev *hdev = req->hdev;
> struct hci_cp_le_set_adv_data cp;
> @@ -1076,7 +1081,7 @@ static void update_adv_data_for_instance(struct hci_request *req, u8 instance)
>
> memset(&cp, 0, sizeof(cp));
>
> - len = create_instance_adv_data(hdev, instance, cp.data);
> + len = create_adv_data(hdev, cp.data);
>
> /* There's nothing to do if the data hasn't changed */
> if (hdev->adv_data_len == len &&
> @@ -1091,14 +1096,6 @@ static void update_adv_data_for_instance(struct hci_request *req, u8 instance)
> hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
> }
>
> -static void update_adv_data(struct hci_request *req)
> -{
> - struct hci_dev *hdev = req->hdev;
> - u8 instance = get_current_adv_instance(hdev);
> -
> - update_adv_data_for_instance(req, instance);
> -}
> -
> int mgmt_update_adv_data(struct hci_dev *hdev)
> {
> struct hci_request req;
> @@ -1277,7 +1274,7 @@ static void enable_advertising(struct hci_request *req)
>
> if (connectable)
> cp.type = LE_ADV_IND;
> - else if (get_adv_instance_scan_rsp_len(hdev, instance))
> + else if (get_cur_adv_instance_scan_rsp_len(hdev))
> cp.type = LE_ADV_SCAN_IND;
> else
> cp.type = LE_ADV_NONCONN_IND;
> @@ -1459,27 +1456,27 @@ static void advertising_removed(struct sock *sk, struct hci_dev *hdev,
> mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
> }
>
> -static void clear_adv_instance(struct hci_dev *hdev)
> +static void clear_adv_instance(struct sock *sk, struct hci_dev *hdev,
> + u8 instance)
> {
> - struct hci_request req;
> -
> - if (!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
> - return;
> -
> - if (hdev->adv_instance.timeout)
> - cancel_delayed_work(&hdev->adv_instance.timeout_exp);
> -
> - memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
> - advertising_removed(NULL, hdev, 1);
> - hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
> -
> - if (!hdev_is_powered(hdev) ||
> - hci_dev_test_flag(hdev, HCI_ADVERTISING))
> - return;
> + struct adv_info *adv_instance, *n;
> + int err;
>
> - hci_req_init(&req, hdev);
> - disable_advertising(&req);
> - hci_req_run(&req, NULL);

Why did you remove this logic? Advertising needs to be disabled if
HCI_ADVERTISING_INSTANCE is set and HCI_ADVERTISING wasn't. Hence most
of the logic above (within this function) is still needed.

> + /* A value of 0 indicates that all instances should be cleared. */
> + if (instance == 0x00) {
> + list_for_each_entry_safe(adv_instance, n,
> + &hdev->adv_instances, list) {

Didn't you add a hci_adv_instances_clear for this purpose? Now you
have nested loops for iterating through the list and doing the lookup.
If you've added this loop just to send the removed event, then perhaps
it makes more sense to make advertising_removed public (like
mgmt_advertising_removed) and to call it from hci.c. Or, just do a
loop first to send the removed events and then call
hci_adv_instances_clear.

> + err = hci_remove_adv_instance(hdev,
> + adv_instance->instance);
> + if (!err)

This error check isn't really necessary since you're looping through
valid instances.

> + advertising_removed(sk, hdev,
> + adv_instance->instance);
> + }
> + } else {
> + err = hci_remove_adv_instance(hdev, instance);
> + if (!err)
> + advertising_removed(sk, hdev, instance);
> + }
> }
>
> static int clean_up_hci_state(struct hci_dev *hdev)
> @@ -1497,8 +1494,7 @@ static int clean_up_hci_state(struct hci_dev *hdev)
> hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
> }
>
> - if (hdev->adv_instance.timeout)
> - clear_adv_instance(hdev);
> + clear_adv_instance(NULL, hdev, 0x00);
>
> if (hci_dev_test_flag(hdev, HCI_LE_ADV))
> disable_advertising(&req);
> @@ -4669,6 +4665,7 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status,
> {
> struct cmd_lookup match = { NULL, hdev };
> struct hci_request req;
> + struct adv_info *adv_instance;
>
> hci_dev_lock(hdev);
>
> @@ -4697,11 +4694,14 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status,
> * set up earlier, then enable the advertising instance.
> */
> if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
> - !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
> + !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) ||
> + list_empty(&hdev->adv_instances))

We should make sure that the HCI_ADVERTISING_INSTANCE setting is set
as long as hdev->adv_instances is non-empty and it's not set if the
list is empty.

> goto unlock;
>
> hci_req_init(&req, hdev);
> -
> + adv_instance = list_first_entry(&hdev->adv_instances,
> + struct adv_info, list);
> + hdev->cur_adv_instance = adv_instance->instance;

Add a comment here explaining why we're picking the first instance.
Why does this make sense and will this need to be updated in the
future? Add a TODO if necessary.

> update_adv_data(&req);
> enable_advertising(&req);
>
> @@ -4792,8 +4792,9 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
>
> if (val) {
> /* Switch to instance "0" for the Set Advertising setting. */
> - update_adv_data_for_instance(&req, 0);
> - update_scan_rsp_data_for_instance(&req, 0);
> + hdev->cur_adv_instance = 0x00;
> + update_adv_data(&req);
> + update_scan_rsp_data(&req);
> enable_advertising(&req);
> } else {
> disable_advertising(&req);
> @@ -6781,8 +6782,10 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
> {
> struct mgmt_rp_read_adv_features *rp;
> size_t rp_len;
> - int err;
> + int err, i;
> bool instance;
> + int num_adv_instances = 0;
> + struct adv_info *adv_instance;
> u32 supported_flags;
>
> BT_DBG("%s", hdev->name);
> @@ -6795,12 +6798,11 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
>
> rp_len = sizeof(*rp);
>
> - /* Currently only one instance is supported, so just add 1 to the
> - * response length.
> - */
> instance = hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE);
> - if (instance)
> - rp_len++;
> + if (instance) {
> + num_adv_instances = hci_num_adv_instances(hdev);
> + rp_len += num_adv_instances;
> + }
>
> rp = kmalloc(rp_len, GFP_ATOMIC);
> if (!rp) {
> @@ -6813,16 +6815,15 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
> rp->supported_flags = cpu_to_le32(supported_flags);
> rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
> rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
> - rp->max_instances = 1;
> + rp->max_instances = HCI_MAX_ADV_INSTANCES;

Saw that you've done this here, so ignore my comment about this in
your previous patch.

> + rp->num_instances = num_adv_instances;
>
> - /* Currently only one instance is supported, so simply return the
> - * current instance number.
> - */
> if (instance) {
> - rp->num_instances = 1;
> - rp->instance[0] = 1;
> - } else {
> - rp->num_instances = 0;
> + i = 0;
> + list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
> + rp->instance[i] = adv_instance->instance;
> + i++;
> + }
> }
>
> hci_dev_unlock(hdev);
> @@ -6882,24 +6883,37 @@ static void add_advertising_complete(struct hci_dev *hdev, u8 status,
> u16 opcode)
> {
> struct mgmt_pending_cmd *cmd;
> + struct mgmt_cp_add_advertising *cp = NULL;
> struct mgmt_rp_add_advertising rp;
> + struct adv_info *adv_instance;
>
> BT_DBG("status %d", status);
>
> hci_dev_lock(hdev);
>
> cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
> + if (cmd)
> + cp = cmd->param;

This makes the code complicated. Just check if (!cmd) and goto unlock,
so you won't need all the nested checks.
>
> if (status) {
> + /* TODO: Start advertising another adv instance if any? */
> hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
> - memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
> - advertising_removed(cmd ? cmd->sk : NULL, hdev, 1);
> +
> + if (cmd) {

If "cmd" is NULL for whatever reason, then we'll end up leaking the
instance. Maybe there is a better way to propagate the pending
instance ID?

> + adv_instance = hci_find_adv_instance(hdev,
> + cp->instance);
> + if (adv_instance) {
> + hci_remove_adv_instance(hdev, cp->instance);
> + advertising_removed(cmd ? cmd->sk : NULL, hdev,
> + cp->instance);
> + }
> + }
> }
>
> if (!cmd)
> goto unlock;
>
> - rp.instance = 0x01;
> + rp.instance = cp->instance;
>
> if (status)
> mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
> @@ -6916,13 +6930,33 @@ unlock:
>
> static void adv_timeout_expired(struct work_struct *work)
> {
> - struct hci_dev *hdev = container_of(work, struct hci_dev,
> - adv_instance.timeout_exp.work);
> + struct adv_info *adv_instance;
> + struct hci_dev *hdev;
> + int err;
> + struct hci_request req;
>
> - hdev->adv_instance.timeout = 0;
> + adv_instance = container_of(work, struct adv_info, timeout_exp.work);
> + hdev = adv_instance->hdev;
> +
> + adv_instance->timeout = 0;
>
> hci_dev_lock(hdev);
> - clear_adv_instance(hdev);
> + err = hci_remove_adv_instance(hdev, adv_instance->instance);
> + if (!err)
> + advertising_removed(NULL, hdev, adv_instance->instance);
> +
> + /* TODO: Schedule the next advertisement instance here if any. */
> + hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
> +
> + if (!hdev_is_powered(hdev) ||
> + hci_dev_test_flag(hdev, HCI_ADVERTISING))
> + goto unlock;
> +
> + hci_req_init(&req, hdev);
> + disable_advertising(&req);
> + hci_req_run(&req, NULL);

clr_adv_instance did/does exactly the code above, why are you
duplicating it here again?

> +
> +unlock:
> hci_dev_unlock(hdev);
> }
>
> @@ -6981,38 +7015,31 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
> goto unlock;
> }
>
> - INIT_DELAYED_WORK(&hdev->adv_instance.timeout_exp, adv_timeout_expired);
> -
> - hdev->adv_instance.flags = flags;
> - hdev->adv_instance.adv_data_len = cp->adv_data_len;
> - hdev->adv_instance.scan_rsp_len = cp->scan_rsp_len;
> -
> - if (cp->adv_data_len)
> - memcpy(hdev->adv_instance.adv_data, cp->data, cp->adv_data_len);
> -
> - if (cp->scan_rsp_len)
> - memcpy(hdev->adv_instance.scan_rsp_data,
> - cp->data + cp->adv_data_len, cp->scan_rsp_len);
> -
> - if (hdev->adv_instance.timeout)
> - cancel_delayed_work(&hdev->adv_instance.timeout_exp);
> -
> - hdev->adv_instance.timeout = timeout;
> + err = hci_add_adv_instance(hdev, cp->instance, flags,
> + cp->adv_data_len, cp->data,
> + cp->scan_rsp_len,
> + cp->data + cp->adv_data_len,
> + adv_timeout_expired, timeout);
> + if (err < 0) {
> + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
> + MGMT_STATUS_FAILED);
> + goto unlock;
> + }
>
> - if (timeout)
> - queue_delayed_work(hdev->workqueue,
> - &hdev->adv_instance.timeout_exp,
> - msecs_to_jiffies(timeout * 1000));
> + hdev->cur_adv_instance = cp->instance;
>
> + /* TODO: Trigger an advertising added event even when instance
> + * advertising is already switched on?
> + */

With a single instance, what this prevents is sending an "added" event
for an instance that was previously added. So the TODO doesn't make
sense in that context but the new code needs to correctly abide by
that logic. What you actually need to pay attention to is to not send
any HCI commands to update advertising data every time you add a new
instance. So maybe add a TODO for that.

> if (!hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING_INSTANCE))
> - advertising_added(sk, hdev, 1);
> + advertising_added(sk, hdev, cp->instance);
>
> /* If the HCI_ADVERTISING flag is set or the device isn't powered then
> * we have no HCI communication to make. Simply return.
> */
> if (!hdev_is_powered(hdev) ||
> hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
> - rp.instance = 0x01;
> + rp.instance = cp->instance;
> err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
> MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
> goto unlock;
> @@ -7083,12 +7110,12 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
>
> BT_DBG("%s", hdev->name);
>
> - /* The current implementation only allows modifying instance no 1. A
> - * value of 0 indicates that all instances should be cleared.
> - */
> - if (cp->instance > 1)
> - return mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
> - MGMT_STATUS_INVALID_PARAMS);
> + if (cp->instance != 0x00) {
> + if (!hci_find_adv_instance(hdev, cp->instance))

if (cp->instance != 0x00 && !hci_find_adv_instance(hdev, cp->instance))

> + return mgmt_cmd_status(sk, hdev->id,
> + MGMT_OP_REMOVE_ADVERTISING,
> + MGMT_STATUS_INVALID_PARAMS);
> + }
>
> hci_dev_lock(hdev);
>
> @@ -7106,21 +7133,23 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
> goto unlock;
> }
>
> - if (hdev->adv_instance.timeout)
> - cancel_delayed_work(&hdev->adv_instance.timeout_exp);
> -
> - memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
> -
> - advertising_removed(sk, hdev, 1);
> + clear_adv_instance(sk, hdev, cp->instance);
>
> + /* TODO: Only switch off advertising if the instance list is empty
> + * else switch to the next remaining adv instance.
> + */
> hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
>
> - /* If the HCI_ADVERTISING flag is set or the device isn't powered then
> - * we have no HCI communication to make. Simply return.
> + /* If the HCI_ADVERTISING[_INSTANCE] flag is set or the device
> + * isn't powered then we have no HCI communication to make.
> + * Simply return.
> + */
> + /* TODO: Only switch off instance advertising when the flag has
> + * actually been unset (see TODO above).
> */
> if (!hdev_is_powered(hdev) ||
> hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
> - rp.instance = 1;
> + rp.instance = cp->instance;
> err = mgmt_cmd_complete(sk, hdev->id,
> MGMT_OP_REMOVE_ADVERTISING,
> MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
> --
> 1.9.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html


I think, aside from a few issues, this is going in the right
direction, so thanks for the patch. The patch is still a bit too large
for linux-bluetooth standards and it's a bit difficult to get through,
so if you can break it down into smaller logical pieces it will be
easier for the others to review it. I'm not an official maintainer on
the kernel side so either Johan or Marcel will need to sign off on
your patches.

Thanks,
Arman

2015-04-24 00:37:32

by Arman Uguray

[permalink] [raw]
Subject: Re: [PATCH v3 1/2] Bluetooth: hci_core: Introduce multi-adv inst list

Hi Florian,

Sorry for my delayed response, please see my comments inline below.

> On Thu, Apr 9, 2015 at 7:30 PM, Florian Grandel <[email protected]> wrote:
> The current hci dev structure only supports a single advertising
> instance. To support multi-instance advertising it is necessary to
> introduce a linked list of advertising instances so that multiple
> advertising instances can be dynamically added and/or removed.
>
> In a first step, the existing adv_instance member of the hci_dev
> struct is supplemented by a linked list of advertising instances.
> This patch introduces the list and supporting list management
> infrastructure. The list is not being used yet.
>
> Signed-off-by: Florian Grandel <[email protected]>
> ---
> include/net/bluetooth/hci_core.h | 14 +++++
> net/bluetooth/hci_core.c | 116 +++++++++++++++++++++++++++++++++++++++
> 2 files changed, 130 insertions(+)
>
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index a056c2b..98678eb 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -156,6 +156,7 @@ struct oob_data {
> };
>
> struct adv_info {
> + struct list_head list;
> struct delayed_work timeout_exp;
> __u8 instance;
> __u32 flags;
> @@ -166,6 +167,8 @@ struct adv_info {
> __u8 scan_rsp_data[HCI_MAX_AD_LENGTH];
> };
>
> +#define HCI_MAX_ADV_INSTANCES 1
> +

Now that you've added this constant, this is what you should use to
populate "rp->max_instances" in
net/bluetooth/mgmt.c:read_adv_features.

> #define HCI_MAX_SHORT_NAME_LENGTH 10
>
> /* Default LE RPA expiry time, 15 minutes */
> @@ -374,6 +377,8 @@ struct hci_dev {
> __u8 scan_rsp_data_len;
>
> struct adv_info adv_instance;

Is this still needed?

> + struct list_head adv_instances;
> + __u8 cur_adv_instance;
>
> __u8 irk[16];
> __u32 rpa_timeout;
> @@ -1007,6 +1012,15 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
> int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
> u8 bdaddr_type);
>
> +int hci_num_adv_instances(struct hci_dev *hdev);
> +void hci_adv_instances_clear(struct hci_dev *hdev);
> +struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance);
> +int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
> + u16 adv_data_len, u8 *adv_data,
> + u16 scan_rsp_len, u8 *scan_rsp_data,
> + work_func_t timeout_work, u16 timeout);
> +int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance);
> +
> void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
>
> int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb);
> diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
> index 476709b..1859e67 100644
> --- a/net/bluetooth/hci_core.c
> +++ b/net/bluetooth/hci_core.c
> @@ -2613,6 +2613,119 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
> return 0;
> }
>
> +struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance)
> +{

Doesn't this require a lock as well?

> + struct adv_info *adv_instance;
> +
> + list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
> + if (adv_instance->instance != instance)
> + continue;
> + return adv_instance;

Simpler to just do:

if (adv_instance->instance == instance)
return adv_instance;

> + }
> +
> + return NULL;
> +}
> +
> +/* This function requires the caller holds hdev->lock */
> +int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance)
> +{
> + struct adv_info *adv_instance;
> +
> + adv_instance = hci_find_adv_instance(hdev, instance);
> + if (!adv_instance)
> + return -ENOENT;
> +
> + BT_DBG("%s removing %dMR", hdev->name, instance);
> +
> + if (adv_instance->timeout)
> + cancel_delayed_work(&adv_instance->timeout_exp);
> +
> + list_del(&adv_instance->list);
> + kfree(adv_instance);
> +
> + return 0;
> +}
> +
> +/* This function requires the caller holds hdev->lock */
> +void hci_adv_instances_clear(struct hci_dev *hdev)
> +{
> + struct adv_info *adv_instance, *n;
> +
> + list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
> + if (adv_instance->timeout)
> + cancel_delayed_work(&adv_instance->timeout_exp);
> +
> + list_del(&adv_instance->list);
> + kfree(adv_instance);
> + }
> +}
> +
> +int hci_num_adv_instances(struct hci_dev *hdev)
> +{
> + struct adv_info *adv_instance;
> + int num = 0;
> +
> + list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
> + num++;
> + }

I'm not particularly opinionated on this but it would be more
efficient to keep a count in hci_dev, though that's up to Johan.

> +
> + return num;
> +}
> +
> +/* This function requires the caller holds hdev->lock */
> +int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
> + u16 adv_data_len, u8 *adv_data,
> + u16 scan_rsp_len, u8 *scan_rsp_data,
> + work_func_t timeout_work, u16 timeout)
> +{
> + struct adv_info *adv_instance;
> +
> + adv_instance = hci_find_adv_instance(hdev, instance);
> + if (adv_instance) {
> + if (adv_instance->timeout)
> + cancel_delayed_work(&adv_instance->timeout_exp);
> +
> + memset(adv_instance->adv_data, 0,
> + sizeof(adv_instance->adv_data));
> + memset(adv_instance->scan_rsp_data, 0,
> + sizeof(adv_instance->scan_rsp_data));
> + } else {
> + if (hci_num_adv_instances(hdev) >= HCI_MAX_ADV_INSTANCES)
> + return -EOVERFLOW;
> +
> + adv_instance = kmalloc(sizeof(*adv_instance), GFP_KERNEL);
> + if (!adv_instance)
> + return -ENOMEM;
> +
> + memset(adv_instance, 0, sizeof(*adv_instance));
> + INIT_DELAYED_WORK(&adv_instance->timeout_exp, timeout_work);
> + adv_instance->instance = instance;
> + list_add(&adv_instance->list, &hdev->adv_instances);
> + }
> +
> + adv_instance->flags = flags;
> + adv_instance->adv_data_len = adv_data_len;
> + adv_instance->scan_rsp_len = scan_rsp_len;
> +
> + if (adv_data_len)
> + memcpy(adv_instance->adv_data, adv_data, adv_data_len);
> +
> + if (scan_rsp_len)
> + memcpy(adv_instance->scan_rsp_data,
> + scan_rsp_data, scan_rsp_len);
> +
> + adv_instance->timeout = timeout;
> +
> + if (timeout)
> + queue_delayed_work(hdev->workqueue,
> + &adv_instance->timeout_exp,
> + msecs_to_jiffies(timeout * 1000));
> +
> + BT_DBG("%s for %dMR", hdev->name, instance);
> +
> + return 0;
> +}
> +
> struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *bdaddr_list,
> bdaddr_t *bdaddr, u8 type)
> {
> @@ -3016,6 +3129,7 @@ struct hci_dev *hci_alloc_dev(void)
> hdev->manufacturer = 0xffff; /* Default to internal use */
> hdev->inq_tx_power = HCI_TX_POWER_INVALID;
> hdev->adv_tx_power = HCI_TX_POWER_INVALID;
> + hdev->cur_adv_instance = 0x00;
>
> hdev->sniff_max_interval = 800;
> hdev->sniff_min_interval = 80;
> @@ -3057,6 +3171,7 @@ struct hci_dev *hci_alloc_dev(void)
> INIT_LIST_HEAD(&hdev->pend_le_conns);
> INIT_LIST_HEAD(&hdev->pend_le_reports);
> INIT_LIST_HEAD(&hdev->conn_hash.list);
> + INIT_LIST_HEAD(&hdev->adv_instances);
>
> INIT_WORK(&hdev->rx_work, hci_rx_work);
> INIT_WORK(&hdev->cmd_work, hci_cmd_work);
> @@ -3250,6 +3365,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
> hci_smp_ltks_clear(hdev);
> hci_smp_irks_clear(hdev);
> hci_remote_oob_data_clear(hdev);
> + hci_adv_instances_clear(hdev);
> hci_bdaddr_list_clear(&hdev->le_white_list);
> hci_conn_params_clear_all(hdev);
> hci_discovery_filter_clear(hdev);
> --
> 1.9.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html

Thanks,
Arman

2015-04-21 01:52:35

by jerico.dev

[permalink] [raw]
Subject: Re: [PATCH v3 0/2] Bluetooth: Multi-Advertising Infrastructure

Hi everyone,

I'd be glad if someone found the time to review this patch set.

I made the changes proposed by Johan in his review. So not sure whether
this is good to be applied now or whether further changes are needed.

I'm holding back with more multi-advertisement change sets until I'm
sure that we have a good basis...

Thanks!!

Florian

On 04/10/2015 04:30 AM, Florian Grandel wrote:
> A patch set introducing the infrastructure for multi-advertising
> capability to the HCI core and mgmt API.
>
> v1 -> v2:
> - add missing braces in read_adv_features()
>
> v2 -> v3:
> - split change-set into several patches
> - replace err == 0 by !err
> - fix coding style problems
>
> Florian Grandel (2):
> Bluetooth: hci_core: Introduce multi-adv inst list
> Bluetooth: mgmt: Start using multi-adv inst list
>
> include/net/bluetooth/hci_core.h | 21 ++-
> net/bluetooth/hci_core.c | 118 ++++++++++++-
> net/bluetooth/mgmt.c | 349 +++++++++++++++++++++------------------
> 3 files changed, 321 insertions(+), 167 deletions(-)
>

2015-04-10 02:30:41

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v3 2/2] Bluetooth: mgmt: Start using multi-adv inst list

To prepare the mgmt api for multiple advertising instances it must be
refactored to use the new advertising instance linked list:
- refactor all prior references to the adv_instance member of the
hci_dev struct to use the new dynamic list,
- remove the then unused adv_instance member,
- replace hard coded instance ids by references to the current
instance id saved in the hci_dev struct

Signed-off-by: Florian Grandel <[email protected]>
---
include/net/bluetooth/hci_core.h | 7 +-
net/bluetooth/hci_core.c | 2 +-
net/bluetooth/mgmt.c | 349 +++++++++++++++++++++------------------
3 files changed, 191 insertions(+), 167 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 98678eb..8c19f38 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -157,6 +157,7 @@ struct oob_data {

struct adv_info {
struct list_head list;
+ struct hci_dev *hdev;
struct delayed_work timeout_exp;
__u8 instance;
__u32 flags;
@@ -376,7 +377,6 @@ struct hci_dev {
__u8 scan_rsp_data[HCI_MAX_AD_LENGTH];
__u8 scan_rsp_data_len;

- struct adv_info adv_instance;
struct list_head adv_instances;
__u8 cur_adv_instance;

@@ -566,11 +566,6 @@ static inline void hci_discovery_filter_clear(struct hci_dev *hdev)
hdev->discovery.scan_duration = 0;
}

-static inline void adv_info_init(struct hci_dev *hdev)
-{
- memset(&hdev->adv_instance, 0, sizeof(struct adv_info));
-}
-
bool hci_discovery_active(struct hci_dev *hdev);

void hci_discovery_set_state(struct hci_dev *hdev, int state);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 1859e67..8ac53cf 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2698,6 +2698,7 @@ int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
return -ENOMEM;

memset(adv_instance, 0, sizeof(*adv_instance));
+ adv_instance->hdev = hdev;
INIT_DELAYED_WORK(&adv_instance->timeout_exp, timeout_work);
adv_instance->instance = instance;
list_add(&adv_instance->list, &hdev->adv_instances);
@@ -3194,7 +3195,6 @@ struct hci_dev *hci_alloc_dev(void)

hci_init_sysfs(hdev);
discovery_init(hdev);
- adv_info_init(hdev);

return hdev;
}
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 7fd87e7..199e312 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -858,31 +858,53 @@ static u8 create_default_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
return ad_len;
}

-static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
+static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 instance,
+ u8 *ptr)
{
- /* TODO: Set the appropriate entries based on advertising instance flags
- * here once flags other than 0 are supported.
+ struct adv_info *adv_instance;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (adv_instance) {
+ /* TODO: Set the appropriate entries based on advertising
+ * instance flags here once flags other than 0 are supported.
+ */
+ memcpy(ptr, adv_instance->scan_rsp_data,
+ adv_instance->scan_rsp_len);
+
+ return adv_instance->scan_rsp_len;
+ }
+
+ return 0;
+}
+
+static u8 get_current_adv_instance(struct hci_dev *hdev)
+{
+ /* The "Set Advertising" setting supersedes the "Add Advertising"
+ * setting. Here we set the advertising data based on which
+ * setting was set. When neither apply, default to the global settings,
+ * represented by instance "0".
*/
- memcpy(ptr, hdev->adv_instance.scan_rsp_data,
- hdev->adv_instance.scan_rsp_len);
+ if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
+ !hci_dev_test_flag(hdev, HCI_ADVERTISING))
+ return hdev->cur_adv_instance;

- return hdev->adv_instance.scan_rsp_len;
+ return 0x00;
}

-static void update_scan_rsp_data_for_instance(struct hci_request *req,
- u8 instance)
+static void update_scan_rsp_data(struct hci_request *req)
{
struct hci_dev *hdev = req->hdev;
struct hci_cp_le_set_scan_rsp_data cp;
- u8 len;
+ u8 instance, len;

if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
return;

memset(&cp, 0, sizeof(cp));

+ instance = get_current_adv_instance(hdev);
if (instance)
- len = create_instance_scan_rsp_data(hdev, cp.data);
+ len = create_instance_scan_rsp_data(hdev, instance, cp.data);
else
len = create_default_scan_rsp_data(hdev, cp.data);

@@ -898,25 +920,6 @@ static void update_scan_rsp_data_for_instance(struct hci_request *req,
hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
}

-static void update_scan_rsp_data(struct hci_request *req)
-{
- struct hci_dev *hdev = req->hdev;
- u8 instance;
-
- /* The "Set Advertising" setting supersedes the "Add Advertising"
- * setting. Here we set the scan response data based on which
- * setting was set. When neither apply, default to the global settings,
- * represented by instance "0".
- */
- if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
- !hci_dev_test_flag(hdev, HCI_ADVERTISING))
- instance = 0x01;
- else
- instance = 0x00;
-
- update_scan_rsp_data_for_instance(req, instance);
-}
-
static u8 get_adv_discov_flags(struct hci_dev *hdev)
{
struct mgmt_pending_cmd *cmd;
@@ -941,20 +944,6 @@ static u8 get_adv_discov_flags(struct hci_dev *hdev)
return 0;
}

-static u8 get_current_adv_instance(struct hci_dev *hdev)
-{
- /* The "Set Advertising" setting supersedes the "Add Advertising"
- * setting. Here we set the advertising data based on which
- * setting was set. When neither apply, default to the global settings,
- * represented by instance "0".
- */
- if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
- !hci_dev_test_flag(hdev, HCI_ADVERTISING))
- return 0x01;
-
- return 0x00;
-}
-
static bool get_connectable(struct hci_dev *hdev)
{
struct mgmt_pending_cmd *cmd;
@@ -975,40 +964,54 @@ static bool get_connectable(struct hci_dev *hdev)
static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance)
{
u32 flags;
+ struct adv_info *adv_instance;

- if (instance > 0x01)
- return 0;
+ if (instance == 0x00) {
+ /* Instance 0 always manages the "Tx Power" and "Flags"
+ * fields.
+ */
+ flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS;

- if (instance == 0x01)
- return hdev->adv_instance.flags;
+ /* For instance 0, the HCI_ADVERTISING_CONNECTABLE setting
+ * corresponds to the "connectable" instance flag.
+ */
+ if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
+ flags |= MGMT_ADV_FLAG_CONNECTABLE;

- /* Instance 0 always manages the "Tx Power" and "Flags" fields */
- flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS;
+ return flags;
+ }

- /* For instance 0, the HCI_ADVERTISING_CONNECTABLE setting corresponds
- * to the "connectable" instance flag.
- */
- if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
- flags |= MGMT_ADV_FLAG_CONNECTABLE;
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (adv_instance)
+ return adv_instance->flags;

- return flags;
+ return 0;
}

-static u8 get_adv_instance_scan_rsp_len(struct hci_dev *hdev, u8 instance)
+static u8 get_cur_adv_instance_scan_rsp_len(struct hci_dev *hdev)
{
- /* Ignore instance 0 and other unsupported instances */
- if (instance != 0x01)
+ u8 instance = get_current_adv_instance(hdev);
+ struct adv_info *adv_instance;
+
+ /* Ignore instance 0 */
+ if (instance == 0x00)
+ return 0;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (!adv_instance)
return 0;

/* TODO: Take into account the "appearance" and "local-name" flags here.
* These are currently being ignored as they are not supported.
*/
- return hdev->adv_instance.scan_rsp_len;
+ return adv_instance->scan_rsp_len;
}

-static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
+static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr)
{
+ struct adv_info *adv_instance;
u8 ad_len = 0, flags = 0;
+ u8 instance = get_current_adv_instance(hdev);
u32 instance_flags = get_adv_instance_flags(hdev, instance);

/* The Add Advertising command allows userspace to set both the general
@@ -1044,11 +1047,13 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
}

if (instance) {
- memcpy(ptr, hdev->adv_instance.adv_data,
- hdev->adv_instance.adv_data_len);
-
- ad_len += hdev->adv_instance.adv_data_len;
- ptr += hdev->adv_instance.adv_data_len;
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (adv_instance) {
+ memcpy(ptr, adv_instance->adv_data,
+ adv_instance->adv_data_len);
+ ad_len += adv_instance->adv_data_len;
+ ptr += adv_instance->adv_data_len;
+ }
}

/* Provide Tx Power only if we can provide a valid value for it */
@@ -1065,7 +1070,7 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
return ad_len;
}

-static void update_adv_data_for_instance(struct hci_request *req, u8 instance)
+static void update_adv_data(struct hci_request *req)
{
struct hci_dev *hdev = req->hdev;
struct hci_cp_le_set_adv_data cp;
@@ -1076,7 +1081,7 @@ static void update_adv_data_for_instance(struct hci_request *req, u8 instance)

memset(&cp, 0, sizeof(cp));

- len = create_instance_adv_data(hdev, instance, cp.data);
+ len = create_adv_data(hdev, cp.data);

/* There's nothing to do if the data hasn't changed */
if (hdev->adv_data_len == len &&
@@ -1091,14 +1096,6 @@ static void update_adv_data_for_instance(struct hci_request *req, u8 instance)
hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
}

-static void update_adv_data(struct hci_request *req)
-{
- struct hci_dev *hdev = req->hdev;
- u8 instance = get_current_adv_instance(hdev);
-
- update_adv_data_for_instance(req, instance);
-}
-
int mgmt_update_adv_data(struct hci_dev *hdev)
{
struct hci_request req;
@@ -1277,7 +1274,7 @@ static void enable_advertising(struct hci_request *req)

if (connectable)
cp.type = LE_ADV_IND;
- else if (get_adv_instance_scan_rsp_len(hdev, instance))
+ else if (get_cur_adv_instance_scan_rsp_len(hdev))
cp.type = LE_ADV_SCAN_IND;
else
cp.type = LE_ADV_NONCONN_IND;
@@ -1459,27 +1456,27 @@ static void advertising_removed(struct sock *sk, struct hci_dev *hdev,
mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
}

-static void clear_adv_instance(struct hci_dev *hdev)
+static void clear_adv_instance(struct sock *sk, struct hci_dev *hdev,
+ u8 instance)
{
- struct hci_request req;
-
- if (!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
- return;
-
- if (hdev->adv_instance.timeout)
- cancel_delayed_work(&hdev->adv_instance.timeout_exp);
-
- memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
- advertising_removed(NULL, hdev, 1);
- hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
-
- if (!hdev_is_powered(hdev) ||
- hci_dev_test_flag(hdev, HCI_ADVERTISING))
- return;
+ struct adv_info *adv_instance, *n;
+ int err;

- hci_req_init(&req, hdev);
- disable_advertising(&req);
- hci_req_run(&req, NULL);
+ /* A value of 0 indicates that all instances should be cleared. */
+ if (instance == 0x00) {
+ list_for_each_entry_safe(adv_instance, n,
+ &hdev->adv_instances, list) {
+ err = hci_remove_adv_instance(hdev,
+ adv_instance->instance);
+ if (!err)
+ advertising_removed(sk, hdev,
+ adv_instance->instance);
+ }
+ } else {
+ err = hci_remove_adv_instance(hdev, instance);
+ if (!err)
+ advertising_removed(sk, hdev, instance);
+ }
}

static int clean_up_hci_state(struct hci_dev *hdev)
@@ -1497,8 +1494,7 @@ static int clean_up_hci_state(struct hci_dev *hdev)
hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
}

- if (hdev->adv_instance.timeout)
- clear_adv_instance(hdev);
+ clear_adv_instance(NULL, hdev, 0x00);

if (hci_dev_test_flag(hdev, HCI_LE_ADV))
disable_advertising(&req);
@@ -4669,6 +4665,7 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status,
{
struct cmd_lookup match = { NULL, hdev };
struct hci_request req;
+ struct adv_info *adv_instance;

hci_dev_lock(hdev);

@@ -4697,11 +4694,14 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status,
* set up earlier, then enable the advertising instance.
*/
if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
- !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
+ !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) ||
+ list_empty(&hdev->adv_instances))
goto unlock;

hci_req_init(&req, hdev);
-
+ adv_instance = list_first_entry(&hdev->adv_instances,
+ struct adv_info, list);
+ hdev->cur_adv_instance = adv_instance->instance;
update_adv_data(&req);
enable_advertising(&req);

@@ -4792,8 +4792,9 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,

if (val) {
/* Switch to instance "0" for the Set Advertising setting. */
- update_adv_data_for_instance(&req, 0);
- update_scan_rsp_data_for_instance(&req, 0);
+ hdev->cur_adv_instance = 0x00;
+ update_adv_data(&req);
+ update_scan_rsp_data(&req);
enable_advertising(&req);
} else {
disable_advertising(&req);
@@ -6781,8 +6782,10 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
{
struct mgmt_rp_read_adv_features *rp;
size_t rp_len;
- int err;
+ int err, i;
bool instance;
+ int num_adv_instances = 0;
+ struct adv_info *adv_instance;
u32 supported_flags;

BT_DBG("%s", hdev->name);
@@ -6795,12 +6798,11 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,

rp_len = sizeof(*rp);

- /* Currently only one instance is supported, so just add 1 to the
- * response length.
- */
instance = hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE);
- if (instance)
- rp_len++;
+ if (instance) {
+ num_adv_instances = hci_num_adv_instances(hdev);
+ rp_len += num_adv_instances;
+ }

rp = kmalloc(rp_len, GFP_ATOMIC);
if (!rp) {
@@ -6813,16 +6815,15 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
rp->supported_flags = cpu_to_le32(supported_flags);
rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
- rp->max_instances = 1;
+ rp->max_instances = HCI_MAX_ADV_INSTANCES;
+ rp->num_instances = num_adv_instances;

- /* Currently only one instance is supported, so simply return the
- * current instance number.
- */
if (instance) {
- rp->num_instances = 1;
- rp->instance[0] = 1;
- } else {
- rp->num_instances = 0;
+ i = 0;
+ list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
+ rp->instance[i] = adv_instance->instance;
+ i++;
+ }
}

hci_dev_unlock(hdev);
@@ -6882,24 +6883,37 @@ static void add_advertising_complete(struct hci_dev *hdev, u8 status,
u16 opcode)
{
struct mgmt_pending_cmd *cmd;
+ struct mgmt_cp_add_advertising *cp = NULL;
struct mgmt_rp_add_advertising rp;
+ struct adv_info *adv_instance;

BT_DBG("status %d", status);

hci_dev_lock(hdev);

cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
+ if (cmd)
+ cp = cmd->param;

if (status) {
+ /* TODO: Start advertising another adv instance if any? */
hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
- memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
- advertising_removed(cmd ? cmd->sk : NULL, hdev, 1);
+
+ if (cmd) {
+ adv_instance = hci_find_adv_instance(hdev,
+ cp->instance);
+ if (adv_instance) {
+ hci_remove_adv_instance(hdev, cp->instance);
+ advertising_removed(cmd ? cmd->sk : NULL, hdev,
+ cp->instance);
+ }
+ }
}

if (!cmd)
goto unlock;

- rp.instance = 0x01;
+ rp.instance = cp->instance;

if (status)
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
@@ -6916,13 +6930,33 @@ unlock:

static void adv_timeout_expired(struct work_struct *work)
{
- struct hci_dev *hdev = container_of(work, struct hci_dev,
- adv_instance.timeout_exp.work);
+ struct adv_info *adv_instance;
+ struct hci_dev *hdev;
+ int err;
+ struct hci_request req;

- hdev->adv_instance.timeout = 0;
+ adv_instance = container_of(work, struct adv_info, timeout_exp.work);
+ hdev = adv_instance->hdev;
+
+ adv_instance->timeout = 0;

hci_dev_lock(hdev);
- clear_adv_instance(hdev);
+ err = hci_remove_adv_instance(hdev, adv_instance->instance);
+ if (!err)
+ advertising_removed(NULL, hdev, adv_instance->instance);
+
+ /* TODO: Schedule the next advertisement instance here if any. */
+ hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
+
+ if (!hdev_is_powered(hdev) ||
+ hci_dev_test_flag(hdev, HCI_ADVERTISING))
+ goto unlock;
+
+ hci_req_init(&req, hdev);
+ disable_advertising(&req);
+ hci_req_run(&req, NULL);
+
+unlock:
hci_dev_unlock(hdev);
}

@@ -6981,38 +7015,31 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}

- INIT_DELAYED_WORK(&hdev->adv_instance.timeout_exp, adv_timeout_expired);
-
- hdev->adv_instance.flags = flags;
- hdev->adv_instance.adv_data_len = cp->adv_data_len;
- hdev->adv_instance.scan_rsp_len = cp->scan_rsp_len;
-
- if (cp->adv_data_len)
- memcpy(hdev->adv_instance.adv_data, cp->data, cp->adv_data_len);
-
- if (cp->scan_rsp_len)
- memcpy(hdev->adv_instance.scan_rsp_data,
- cp->data + cp->adv_data_len, cp->scan_rsp_len);
-
- if (hdev->adv_instance.timeout)
- cancel_delayed_work(&hdev->adv_instance.timeout_exp);
-
- hdev->adv_instance.timeout = timeout;
+ err = hci_add_adv_instance(hdev, cp->instance, flags,
+ cp->adv_data_len, cp->data,
+ cp->scan_rsp_len,
+ cp->data + cp->adv_data_len,
+ adv_timeout_expired, timeout);
+ if (err < 0) {
+ err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
+ MGMT_STATUS_FAILED);
+ goto unlock;
+ }

- if (timeout)
- queue_delayed_work(hdev->workqueue,
- &hdev->adv_instance.timeout_exp,
- msecs_to_jiffies(timeout * 1000));
+ hdev->cur_adv_instance = cp->instance;

+ /* TODO: Trigger an advertising added event even when instance
+ * advertising is already switched on?
+ */
if (!hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING_INSTANCE))
- advertising_added(sk, hdev, 1);
+ advertising_added(sk, hdev, cp->instance);

/* If the HCI_ADVERTISING flag is set or the device isn't powered then
* we have no HCI communication to make. Simply return.
*/
if (!hdev_is_powered(hdev) ||
hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
- rp.instance = 0x01;
+ rp.instance = cp->instance;
err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
goto unlock;
@@ -7083,12 +7110,12 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,

BT_DBG("%s", hdev->name);

- /* The current implementation only allows modifying instance no 1. A
- * value of 0 indicates that all instances should be cleared.
- */
- if (cp->instance > 1)
- return mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
- MGMT_STATUS_INVALID_PARAMS);
+ if (cp->instance != 0x00) {
+ if (!hci_find_adv_instance(hdev, cp->instance))
+ return mgmt_cmd_status(sk, hdev->id,
+ MGMT_OP_REMOVE_ADVERTISING,
+ MGMT_STATUS_INVALID_PARAMS);
+ }

hci_dev_lock(hdev);

@@ -7106,21 +7133,23 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}

- if (hdev->adv_instance.timeout)
- cancel_delayed_work(&hdev->adv_instance.timeout_exp);
-
- memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
-
- advertising_removed(sk, hdev, 1);
+ clear_adv_instance(sk, hdev, cp->instance);

+ /* TODO: Only switch off advertising if the instance list is empty
+ * else switch to the next remaining adv instance.
+ */
hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);

- /* If the HCI_ADVERTISING flag is set or the device isn't powered then
- * we have no HCI communication to make. Simply return.
+ /* If the HCI_ADVERTISING[_INSTANCE] flag is set or the device
+ * isn't powered then we have no HCI communication to make.
+ * Simply return.
+ */
+ /* TODO: Only switch off instance advertising when the flag has
+ * actually been unset (see TODO above).
*/
if (!hdev_is_powered(hdev) ||
hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
- rp.instance = 1;
+ rp.instance = cp->instance;
err = mgmt_cmd_complete(sk, hdev->id,
MGMT_OP_REMOVE_ADVERTISING,
MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
--
1.9.1


2015-04-10 02:30:40

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v3 1/2] Bluetooth: hci_core: Introduce multi-adv inst list

The current hci dev structure only supports a single advertising
instance. To support multi-instance advertising it is necessary to
introduce a linked list of advertising instances so that multiple
advertising instances can be dynamically added and/or removed.

In a first step, the existing adv_instance member of the hci_dev
struct is supplemented by a linked list of advertising instances.
This patch introduces the list and supporting list management
infrastructure. The list is not being used yet.

Signed-off-by: Florian Grandel <[email protected]>
---
include/net/bluetooth/hci_core.h | 14 +++++
net/bluetooth/hci_core.c | 116 +++++++++++++++++++++++++++++++++++++++
2 files changed, 130 insertions(+)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index a056c2b..98678eb 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -156,6 +156,7 @@ struct oob_data {
};

struct adv_info {
+ struct list_head list;
struct delayed_work timeout_exp;
__u8 instance;
__u32 flags;
@@ -166,6 +167,8 @@ struct adv_info {
__u8 scan_rsp_data[HCI_MAX_AD_LENGTH];
};

+#define HCI_MAX_ADV_INSTANCES 1
+
#define HCI_MAX_SHORT_NAME_LENGTH 10

/* Default LE RPA expiry time, 15 minutes */
@@ -374,6 +377,8 @@ struct hci_dev {
__u8 scan_rsp_data_len;

struct adv_info adv_instance;
+ struct list_head adv_instances;
+ __u8 cur_adv_instance;

__u8 irk[16];
__u32 rpa_timeout;
@@ -1007,6 +1012,15 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 bdaddr_type);

+int hci_num_adv_instances(struct hci_dev *hdev);
+void hci_adv_instances_clear(struct hci_dev *hdev);
+struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance);
+int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
+ u16 adv_data_len, u8 *adv_data,
+ u16 scan_rsp_len, u8 *scan_rsp_data,
+ work_func_t timeout_work, u16 timeout);
+int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance);
+
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);

int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 476709b..1859e67 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2613,6 +2613,119 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
return 0;
}

+struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance)
+{
+ struct adv_info *adv_instance;
+
+ list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
+ if (adv_instance->instance != instance)
+ continue;
+ return adv_instance;
+ }
+
+ return NULL;
+}
+
+/* This function requires the caller holds hdev->lock */
+int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance)
+{
+ struct adv_info *adv_instance;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (!adv_instance)
+ return -ENOENT;
+
+ BT_DBG("%s removing %dMR", hdev->name, instance);
+
+ if (adv_instance->timeout)
+ cancel_delayed_work(&adv_instance->timeout_exp);
+
+ list_del(&adv_instance->list);
+ kfree(adv_instance);
+
+ return 0;
+}
+
+/* This function requires the caller holds hdev->lock */
+void hci_adv_instances_clear(struct hci_dev *hdev)
+{
+ struct adv_info *adv_instance, *n;
+
+ list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
+ if (adv_instance->timeout)
+ cancel_delayed_work(&adv_instance->timeout_exp);
+
+ list_del(&adv_instance->list);
+ kfree(adv_instance);
+ }
+}
+
+int hci_num_adv_instances(struct hci_dev *hdev)
+{
+ struct adv_info *adv_instance;
+ int num = 0;
+
+ list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
+ num++;
+ }
+
+ return num;
+}
+
+/* This function requires the caller holds hdev->lock */
+int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
+ u16 adv_data_len, u8 *adv_data,
+ u16 scan_rsp_len, u8 *scan_rsp_data,
+ work_func_t timeout_work, u16 timeout)
+{
+ struct adv_info *adv_instance;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (adv_instance) {
+ if (adv_instance->timeout)
+ cancel_delayed_work(&adv_instance->timeout_exp);
+
+ memset(adv_instance->adv_data, 0,
+ sizeof(adv_instance->adv_data));
+ memset(adv_instance->scan_rsp_data, 0,
+ sizeof(adv_instance->scan_rsp_data));
+ } else {
+ if (hci_num_adv_instances(hdev) >= HCI_MAX_ADV_INSTANCES)
+ return -EOVERFLOW;
+
+ adv_instance = kmalloc(sizeof(*adv_instance), GFP_KERNEL);
+ if (!adv_instance)
+ return -ENOMEM;
+
+ memset(adv_instance, 0, sizeof(*adv_instance));
+ INIT_DELAYED_WORK(&adv_instance->timeout_exp, timeout_work);
+ adv_instance->instance = instance;
+ list_add(&adv_instance->list, &hdev->adv_instances);
+ }
+
+ adv_instance->flags = flags;
+ adv_instance->adv_data_len = adv_data_len;
+ adv_instance->scan_rsp_len = scan_rsp_len;
+
+ if (adv_data_len)
+ memcpy(adv_instance->adv_data, adv_data, adv_data_len);
+
+ if (scan_rsp_len)
+ memcpy(adv_instance->scan_rsp_data,
+ scan_rsp_data, scan_rsp_len);
+
+ adv_instance->timeout = timeout;
+
+ if (timeout)
+ queue_delayed_work(hdev->workqueue,
+ &adv_instance->timeout_exp,
+ msecs_to_jiffies(timeout * 1000));
+
+ BT_DBG("%s for %dMR", hdev->name, instance);
+
+ return 0;
+}
+
struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *bdaddr_list,
bdaddr_t *bdaddr, u8 type)
{
@@ -3016,6 +3129,7 @@ struct hci_dev *hci_alloc_dev(void)
hdev->manufacturer = 0xffff; /* Default to internal use */
hdev->inq_tx_power = HCI_TX_POWER_INVALID;
hdev->adv_tx_power = HCI_TX_POWER_INVALID;
+ hdev->cur_adv_instance = 0x00;

hdev->sniff_max_interval = 800;
hdev->sniff_min_interval = 80;
@@ -3057,6 +3171,7 @@ struct hci_dev *hci_alloc_dev(void)
INIT_LIST_HEAD(&hdev->pend_le_conns);
INIT_LIST_HEAD(&hdev->pend_le_reports);
INIT_LIST_HEAD(&hdev->conn_hash.list);
+ INIT_LIST_HEAD(&hdev->adv_instances);

INIT_WORK(&hdev->rx_work, hci_rx_work);
INIT_WORK(&hdev->cmd_work, hci_cmd_work);
@@ -3250,6 +3365,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
hci_smp_ltks_clear(hdev);
hci_smp_irks_clear(hdev);
hci_remote_oob_data_clear(hdev);
+ hci_adv_instances_clear(hdev);
hci_bdaddr_list_clear(&hdev->le_white_list);
hci_conn_params_clear_all(hdev);
hci_discovery_filter_clear(hdev);
--
1.9.1


2015-04-10 02:30:39

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v3 0/2] Bluetooth: Multi-Advertising Infrastructure

A patch set introducing the infrastructure for multi-advertising
capability to the HCI core and mgmt API.

v1 -> v2:
- add missing braces in read_adv_features()

v2 -> v3:
- split change-set into several patches
- replace err == 0 by !err
- fix coding style problems

Florian Grandel (2):
Bluetooth: hci_core: Introduce multi-adv inst list
Bluetooth: mgmt: Start using multi-adv inst list

include/net/bluetooth/hci_core.h | 21 ++-
net/bluetooth/hci_core.c | 118 ++++++++++++-
net/bluetooth/mgmt.c | 349 +++++++++++++++++++++------------------
3 files changed, 321 insertions(+), 167 deletions(-)

--
1.9.1


2015-04-09 10:28:08

by Florian Grandel

[permalink] [raw]
Subject: Re: [PATCH v2] Bluetooth: hci_core/mgmt: Change adv inst to list.

Hi Johan,

thank you very much for your review.

On 04/09/2015 11:49 AM, Johan Hedberg wrote:
> Hi Florian,
>
> On Sun, Apr 05, 2015, Florian Grandel wrote:
>> As a preparatory step towards multi-instance advertising it is
>> necessary to introduce a data structure that supports storing
>> multiple advertising info data structures for a bluetooth device.
>>
>> This is introduced by refactoring the existing adv_instance member
>> of the hci_dev struct into a linked list and making the necessary
>> changes in the code to support this list.
>>
>> Signed-off-by: Florian Grandel <[email protected]>
>> ---
>>
>> v1 -> v2: add missing braces in read_adv_features()
>>
>> include/net/bluetooth/hci_core.h | 21 ++-
>> net/bluetooth/hci_core.c | 118 ++++++++++++-
>> net/bluetooth/mgmt.c | 345 +++++++++++++++++++++------------------
>> 3 files changed, 316 insertions(+), 168 deletions(-)
>
> It'd be really good if you could try to split this patch up a bit. It
> really is going over the limits of individual patch sizes that we're
> comfortable with. See if you can split this up logically into at least
> two, preferably more (3-4) patches while still keeping something that
> compiles during each step.

I fully agree. I admit that I thought hard about how to split this up
before posting the patch but couldn't come up with a solution I felt
comfortable with: :-(

1) I could leave the old data-structure temporarily in place and
introduce the new one in parallel which would allow me to introduce the
list management stuff in hci_core separately without breaking the build
or any e2e tests. Removing parts of such a patch set would leave the
code in an intermediate state, though, that wouldn't be acceptable as
such. And I'd still have to introduce the bulk of the complexity in
mgmt.* as a single patch to not break e2e tests.

2) If breaking functionality temporarily between commits is not an
issue, then I could think of a much finer grained approach. I could
provide e.g. one patch per mgmt API method or even one patch per method.
Removing parts of such a patch set would still compile but leave the
code in a buggy state that would not pass e2e tests.

Does any of these ideas sound like an acceptable solution to you? Or do
you maybe have a better alternative?

>> + if (err == 0)
>> + advertising_removed(sk, hdev,
>> + adv_instance->instance);
>> + }
>> + } else {
>> + err = hci_remove_adv_instance(hdev, instance);
>> + if (err == 0)
>> + advertising_removed(sk, hdev, instance);
>
> I think if (!err) is the more consistent convension.

Sure, will be fixed throughout.

>> + err = hci_add_adv_instance(hdev, cp->instance, flags,
>> + cp->adv_data_len, cp->data,
>> + cp->scan_rsp_len,
>> + cp->data + cp->adv_data_len,
>> + adv_timeout_expired, timeout);
>
> The split lines don't look like they're correctly lined up. They should
> start from one column after the opening '(' on the first line.
>
>> + // TODO: Trigger an advertising added event even when instance
>> + // advertising is already switched on?
>
> Please stick to /* ... */ for comments.

Of course. My oversight.

Florian

2015-04-09 09:49:13

by Johan Hedberg

[permalink] [raw]
Subject: Re: [PATCH v2] Bluetooth: hci_core/mgmt: Change adv inst to list.

Hi Florian,

On Sun, Apr 05, 2015, Florian Grandel wrote:
> As a preparatory step towards multi-instance advertising it is
> necessary to introduce a data structure that supports storing
> multiple advertising info data structures for a bluetooth device.
>
> This is introduced by refactoring the existing adv_instance member
> of the hci_dev struct into a linked list and making the necessary
> changes in the code to support this list.
>
> Signed-off-by: Florian Grandel <[email protected]>
> ---
>
> v1 -> v2: add missing braces in read_adv_features()
>
> include/net/bluetooth/hci_core.h | 21 ++-
> net/bluetooth/hci_core.c | 118 ++++++++++++-
> net/bluetooth/mgmt.c | 345 +++++++++++++++++++++------------------
> 3 files changed, 316 insertions(+), 168 deletions(-)

It'd be really good if you could try to split this patch up a bit. It
really is going over the limits of individual patch sizes that we're
comfortable with. See if you can split this up logically into at least
two, preferably more (3-4) patches while still keeping something that
compiles during each step.

> + if (err == 0)
> + advertising_removed(sk, hdev,
> + adv_instance->instance);
> + }
> + } else {
> + err = hci_remove_adv_instance(hdev, instance);
> + if (err == 0)
> + advertising_removed(sk, hdev, instance);

I think if (!err) is the more consistent convension.

> + err = hci_add_adv_instance(hdev, cp->instance, flags,
> + cp->adv_data_len, cp->data,
> + cp->scan_rsp_len,
> + cp->data + cp->adv_data_len,
> + adv_timeout_expired, timeout);

The split lines don't look like they're correctly lined up. They should
start from one column after the opening '(' on the first line.

> + // TODO: Trigger an advertising added event even when instance
> + // advertising is already switched on?

Please stick to /* ... */ for comments.

Johan

2015-04-05 18:21:20

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v2] Bluetooth: hci_core/mgmt: Change adv inst to list.

As a preparatory step towards multi-instance advertising it is
necessary to introduce a data structure that supports storing
multiple advertising info data structures for a bluetooth device.

This is introduced by refactoring the existing adv_instance member
of the hci_dev struct into a linked list and making the necessary
changes in the code to support this list.

Signed-off-by: Florian Grandel <[email protected]>
---

v1 -> v2: add missing braces in read_adv_features()

include/net/bluetooth/hci_core.h | 21 ++-
net/bluetooth/hci_core.c | 118 ++++++++++++-
net/bluetooth/mgmt.c | 345 +++++++++++++++++++++------------------
3 files changed, 316 insertions(+), 168 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 93fd3e7..69a8f30 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -156,6 +156,8 @@ struct oob_data {
};

struct adv_info {
+ struct list_head list;
+ struct hci_dev *hdev;
struct delayed_work timeout_exp;
__u8 instance;
__u32 flags;
@@ -166,6 +168,8 @@ struct adv_info {
__u8 scan_rsp_data[HCI_MAX_AD_LENGTH];
};

+#define HCI_MAX_ADV_INSTANCES 1
+
#define HCI_MAX_SHORT_NAME_LENGTH 10

/* Default LE RPA expiry time, 15 minutes */
@@ -375,7 +379,8 @@ struct hci_dev {
__u8 scan_rsp_data[HCI_MAX_AD_LENGTH];
__u8 scan_rsp_data_len;

- struct adv_info adv_instance;
+ struct list_head adv_instances;
+ __u8 cur_adv_instance;

__u8 irk[16];
__u32 rpa_timeout;
@@ -563,11 +568,6 @@ static inline void hci_discovery_filter_clear(struct hci_dev *hdev)
hdev->discovery.scan_duration = 0;
}

-static inline void adv_info_init(struct hci_dev *hdev)
-{
- memset(&hdev->adv_instance, 0, sizeof(struct adv_info));
-}
-
bool hci_discovery_active(struct hci_dev *hdev);

void hci_discovery_set_state(struct hci_dev *hdev, int state);
@@ -1009,6 +1009,15 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 bdaddr_type);

+int hci_num_adv_instances(struct hci_dev *hdev);
+void hci_adv_instances_clear(struct hci_dev *hdev);
+struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance);
+int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
+ u16 adv_data_len, u8 *adv_data,
+ u16 scan_rsp_len, u8 *scan_rsp_data,
+ work_func_t timeout_work, u16 timeout);
+int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance);
+
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);

int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 46b114c..15ab2eb 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2613,6 +2613,120 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
return 0;
}

+struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance)
+{
+ struct adv_info *adv_instance;
+
+ list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
+ if (adv_instance->instance != instance)
+ continue;
+ return adv_instance;
+ }
+
+ return NULL;
+}
+
+/* This function requires the caller holds hdev->lock */
+int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance)
+{
+ struct adv_info *adv_instance;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (!adv_instance)
+ return -ENOENT;
+
+ BT_DBG("%s removing %dMR", hdev->name, instance);
+
+ if (adv_instance->timeout)
+ cancel_delayed_work(&adv_instance->timeout_exp);
+
+ list_del(&adv_instance->list);
+ kfree(adv_instance);
+
+ return 0;
+}
+
+/* This function requires the caller holds hdev->lock */
+void hci_adv_instances_clear(struct hci_dev *hdev)
+{
+ struct adv_info *adv_instance, *n;
+
+ list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
+ if (adv_instance->timeout)
+ cancel_delayed_work(&adv_instance->timeout_exp);
+
+ list_del(&adv_instance->list);
+ kfree(adv_instance);
+ }
+}
+
+int hci_num_adv_instances(struct hci_dev *hdev)
+{
+ struct adv_info *adv_instance;
+ int num = 0;
+
+ list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
+ num++;
+ }
+
+ return num;
+}
+
+/* This function requires the caller holds hdev->lock */
+int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
+ u16 adv_data_len, u8 *adv_data,
+ u16 scan_rsp_len, u8 *scan_rsp_data,
+ work_func_t timeout_work, u16 timeout)
+{
+ struct adv_info *adv_instance;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (adv_instance) {
+ if (adv_instance->timeout)
+ cancel_delayed_work(&adv_instance->timeout_exp);
+
+ memset(adv_instance->adv_data, 0,
+ sizeof(adv_instance->adv_data));
+ memset(adv_instance->scan_rsp_data, 0,
+ sizeof(adv_instance->scan_rsp_data));
+ } else {
+ if (hci_num_adv_instances(hdev) >= HCI_MAX_ADV_INSTANCES)
+ return -EOVERFLOW;
+
+ adv_instance = kmalloc(sizeof(*adv_instance), GFP_KERNEL);
+ if (!adv_instance)
+ return -ENOMEM;
+
+ memset(adv_instance, 0, sizeof(*adv_instance));
+ adv_instance->hdev = hdev;
+ INIT_DELAYED_WORK(&adv_instance->timeout_exp, timeout_work);
+ adv_instance->instance = instance;
+ list_add(&adv_instance->list, &hdev->adv_instances);
+ }
+
+ adv_instance->flags = flags;
+ adv_instance->adv_data_len = adv_data_len;
+ adv_instance->scan_rsp_len = scan_rsp_len;
+
+ if (adv_data_len)
+ memcpy(adv_instance->adv_data, adv_data, adv_data_len);
+
+ if (scan_rsp_len)
+ memcpy(adv_instance->scan_rsp_data,
+ scan_rsp_data, scan_rsp_len);
+
+ adv_instance->timeout = timeout;
+
+ if (timeout)
+ queue_delayed_work(hdev->workqueue,
+ &adv_instance->timeout_exp,
+ msecs_to_jiffies(timeout * 1000));
+
+ BT_DBG("%s for %dMR", hdev->name, instance);
+
+ return 0;
+}
+
struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *bdaddr_list,
bdaddr_t *bdaddr, u8 type)
{
@@ -3016,6 +3130,7 @@ struct hci_dev *hci_alloc_dev(void)
hdev->manufacturer = 0xffff; /* Default to internal use */
hdev->inq_tx_power = HCI_TX_POWER_INVALID;
hdev->adv_tx_power = HCI_TX_POWER_INVALID;
+ hdev->cur_adv_instance = 0x00;

hdev->sniff_max_interval = 800;
hdev->sniff_min_interval = 80;
@@ -3057,6 +3172,7 @@ struct hci_dev *hci_alloc_dev(void)
INIT_LIST_HEAD(&hdev->pend_le_conns);
INIT_LIST_HEAD(&hdev->pend_le_reports);
INIT_LIST_HEAD(&hdev->conn_hash.list);
+ INIT_LIST_HEAD(&hdev->adv_instances);

INIT_WORK(&hdev->rx_work, hci_rx_work);
INIT_WORK(&hdev->cmd_work, hci_cmd_work);
@@ -3079,7 +3195,6 @@ struct hci_dev *hci_alloc_dev(void)

hci_init_sysfs(hdev);
discovery_init(hdev);
- adv_info_init(hdev);

return hdev;
}
@@ -3253,6 +3368,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
hci_smp_ltks_clear(hdev);
hci_smp_irks_clear(hdev);
hci_remote_oob_data_clear(hdev);
+ hci_adv_instances_clear(hdev);
hci_bdaddr_list_clear(&hdev->le_white_list);
hci_conn_params_clear_all(hdev);
hci_discovery_filter_clear(hdev);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 845dfcc..6c11141 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -858,31 +858,53 @@ static u8 create_default_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
return ad_len;
}

-static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
+static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 instance,
+ u8 *ptr)
{
- /* TODO: Set the appropriate entries based on advertising instance flags
- * here once flags other than 0 are supported.
+ struct adv_info *adv_instance;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (adv_instance) {
+ /* TODO: Set the appropriate entries based on advertising instance flags
+ * here once flags other than 0 are supported.
+ */
+ memcpy(ptr, adv_instance->scan_rsp_data,
+ adv_instance->scan_rsp_len);
+
+ return adv_instance->scan_rsp_len;
+ }
+
+ return 0;
+}
+
+static u8 get_current_adv_instance(struct hci_dev *hdev)
+{
+ /* The "Set Advertising" setting supersedes the "Add Advertising"
+ * setting. Here we set the advertising data based on which
+ * setting was set. When neither apply, default to the global settings,
+ * represented by instance "0".
*/
- memcpy(ptr, hdev->adv_instance.scan_rsp_data,
- hdev->adv_instance.scan_rsp_len);
+ if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
+ !hci_dev_test_flag(hdev, HCI_ADVERTISING))
+ return hdev->cur_adv_instance;

- return hdev->adv_instance.scan_rsp_len;
+ return 0x00;
}

-static void update_scan_rsp_data_for_instance(struct hci_request *req,
- u8 instance)
+static void update_scan_rsp_data(struct hci_request *req)
{
struct hci_dev *hdev = req->hdev;
struct hci_cp_le_set_scan_rsp_data cp;
- u8 len;
+ u8 instance, len;

if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
return;

memset(&cp, 0, sizeof(cp));

+ instance = get_current_adv_instance(hdev);
if (instance)
- len = create_instance_scan_rsp_data(hdev, cp.data);
+ len = create_instance_scan_rsp_data(hdev, instance, cp.data);
else
len = create_default_scan_rsp_data(hdev, cp.data);

@@ -898,25 +920,6 @@ static void update_scan_rsp_data_for_instance(struct hci_request *req,
hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
}

-static void update_scan_rsp_data(struct hci_request *req)
-{
- struct hci_dev *hdev = req->hdev;
- u8 instance;
-
- /* The "Set Advertising" setting supersedes the "Add Advertising"
- * setting. Here we set the scan response data based on which
- * setting was set. When neither apply, default to the global settings,
- * represented by instance "0".
- */
- if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
- !hci_dev_test_flag(hdev, HCI_ADVERTISING))
- instance = 0x01;
- else
- instance = 0x00;
-
- update_scan_rsp_data_for_instance(req, instance);
-}
-
static u8 get_adv_discov_flags(struct hci_dev *hdev)
{
struct mgmt_pending_cmd *cmd;
@@ -941,20 +944,6 @@ static u8 get_adv_discov_flags(struct hci_dev *hdev)
return 0;
}

-static u8 get_current_adv_instance(struct hci_dev *hdev)
-{
- /* The "Set Advertising" setting supersedes the "Add Advertising"
- * setting. Here we set the advertising data based on which
- * setting was set. When neither apply, default to the global settings,
- * represented by instance "0".
- */
- if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
- !hci_dev_test_flag(hdev, HCI_ADVERTISING))
- return 0x01;
-
- return 0x00;
-}
-
static bool get_connectable(struct hci_dev *hdev)
{
struct mgmt_pending_cmd *cmd;
@@ -975,40 +964,52 @@ static bool get_connectable(struct hci_dev *hdev)
static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance)
{
u32 flags;
+ struct adv_info *adv_instance;

- if (instance > 0x01)
- return 0;
+ if (instance == 0x00) {
+ /* Instance 0 always manages the "Tx Power" and "Flags" fields */
+ flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS;

- if (instance == 0x01)
- return hdev->adv_instance.flags;
+ /* For instance 0, the HCI_ADVERTISING_CONNECTABLE setting corresponds
+ * to the "connectable" instance flag.
+ */
+ if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
+ flags |= MGMT_ADV_FLAG_CONNECTABLE;

- /* Instance 0 always manages the "Tx Power" and "Flags" fields */
- flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS;
+ return flags;
+ }

- /* For instance 0, the HCI_ADVERTISING_CONNECTABLE setting corresponds
- * to the "connectable" instance flag.
- */
- if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
- flags |= MGMT_ADV_FLAG_CONNECTABLE;
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (adv_instance)
+ return adv_instance->flags;

- return flags;
+ return 0;
}

-static u8 get_adv_instance_scan_rsp_len(struct hci_dev *hdev, u8 instance)
+static u8 get_cur_adv_instance_scan_rsp_len(struct hci_dev *hdev)
{
- /* Ignore instance 0 and other unsupported instances */
- if (instance != 0x01)
+ u8 instance = get_current_adv_instance(hdev);
+ struct adv_info *adv_instance;
+
+ /* Ignore instance 0 */
+ if (instance == 0x00)
+ return 0;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (!adv_instance)
return 0;

/* TODO: Take into account the "appearance" and "local-name" flags here.
* These are currently being ignored as they are not supported.
*/
- return hdev->adv_instance.scan_rsp_len;
+ return adv_instance->scan_rsp_len;
}

-static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
+static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr)
{
+ struct adv_info *adv_instance;
u8 ad_len = 0, flags = 0;
+ u8 instance = get_current_adv_instance(hdev);
u32 instance_flags = get_adv_instance_flags(hdev, instance);

/* The Add Advertising command allows userspace to set both the general
@@ -1044,11 +1045,13 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
}

if (instance) {
- memcpy(ptr, hdev->adv_instance.adv_data,
- hdev->adv_instance.adv_data_len);
-
- ad_len += hdev->adv_instance.adv_data_len;
- ptr += hdev->adv_instance.adv_data_len;
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (adv_instance) {
+ memcpy(ptr, adv_instance->adv_data,
+ adv_instance->adv_data_len);
+ ad_len += adv_instance->adv_data_len;
+ ptr += adv_instance->adv_data_len;
+ }
}

/* Provide Tx Power only if we can provide a valid value for it */
@@ -1065,7 +1068,7 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
return ad_len;
}

-static void update_adv_data_for_instance(struct hci_request *req, u8 instance)
+static void update_adv_data(struct hci_request *req)
{
struct hci_dev *hdev = req->hdev;
struct hci_cp_le_set_adv_data cp;
@@ -1076,7 +1079,7 @@ static void update_adv_data_for_instance(struct hci_request *req, u8 instance)

memset(&cp, 0, sizeof(cp));

- len = create_instance_adv_data(hdev, instance, cp.data);
+ len = create_adv_data(hdev, cp.data);

/* There's nothing to do if the data hasn't changed */
if (hdev->adv_data_len == len &&
@@ -1091,14 +1094,6 @@ static void update_adv_data_for_instance(struct hci_request *req, u8 instance)
hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
}

-static void update_adv_data(struct hci_request *req)
-{
- struct hci_dev *hdev = req->hdev;
- u8 instance = get_current_adv_instance(hdev);
-
- update_adv_data_for_instance(req, instance);
-}
-
int mgmt_update_adv_data(struct hci_dev *hdev)
{
struct hci_request req;
@@ -1237,9 +1232,9 @@ static void enable_advertising(struct hci_request *req)
{
struct hci_dev *hdev = req->hdev;
struct hci_cp_le_set_adv_param cp;
+ u8 instance;
u8 own_addr_type, enable = 0x01;
bool connectable;
- u8 instance;
u32 flags;

if (hci_conn_num(hdev, LE_LINK) > 0)
@@ -1277,7 +1272,7 @@ static void enable_advertising(struct hci_request *req)

if (connectable)
cp.type = LE_ADV_IND;
- else if (get_adv_instance_scan_rsp_len(hdev, instance))
+ else if (get_cur_adv_instance_scan_rsp_len(hdev))
cp.type = LE_ADV_SCAN_IND;
else
cp.type = LE_ADV_NONCONN_IND;
@@ -1459,27 +1454,26 @@ static void advertising_removed(struct sock *sk, struct hci_dev *hdev,
mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
}

-static void clear_adv_instance(struct hci_dev *hdev)
+static void clear_adv_instance(struct sock *sk, struct hci_dev *hdev, u8 instance)
{
- struct hci_request req;
-
- if (!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
- return;
-
- if (hdev->adv_instance.timeout)
- cancel_delayed_work(&hdev->adv_instance.timeout_exp);
-
- memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
- advertising_removed(NULL, hdev, 1);
- hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
-
- if (!hdev_is_powered(hdev) ||
- hci_dev_test_flag(hdev, HCI_ADVERTISING))
- return;
+ struct adv_info *adv_instance, *n;
+ int err;

- hci_req_init(&req, hdev);
- disable_advertising(&req);
- hci_req_run(&req, NULL);
+ /* A value of 0 indicates that all instances should be cleared. */
+ if (instance == 0x00) {
+ list_for_each_entry_safe(adv_instance, n,
+ &hdev->adv_instances, list) {
+ err = hci_remove_adv_instance(hdev,
+ adv_instance->instance);
+ if (err == 0)
+ advertising_removed(sk, hdev,
+ adv_instance->instance);
+ }
+ } else {
+ err = hci_remove_adv_instance(hdev, instance);
+ if (err == 0)
+ advertising_removed(sk, hdev, instance);
+ }
}

static int clean_up_hci_state(struct hci_dev *hdev)
@@ -1497,8 +1491,7 @@ static int clean_up_hci_state(struct hci_dev *hdev)
hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
}

- if (hdev->adv_instance.timeout)
- clear_adv_instance(hdev);
+ clear_adv_instance(NULL, hdev, 0x00);

if (hci_dev_test_flag(hdev, HCI_LE_ADV))
disable_advertising(&req);
@@ -4669,6 +4662,7 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status,
{
struct cmd_lookup match = { NULL, hdev };
struct hci_request req;
+ struct adv_info *adv_instance;

hci_dev_lock(hdev);

@@ -4697,11 +4691,14 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status,
* set up earlier, then enable the advertising instance.
*/
if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
- !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
+ !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) ||
+ list_empty(&hdev->adv_instances))
goto unlock;

hci_req_init(&req, hdev);
-
+ adv_instance = list_first_entry(&hdev->adv_instances,
+ struct adv_info, list);
+ hdev->cur_adv_instance = adv_instance->instance;
update_adv_data(&req);
enable_advertising(&req);

@@ -4792,8 +4789,9 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,

if (val) {
/* Switch to instance "0" for the Set Advertising setting. */
- update_adv_data_for_instance(&req, 0);
- update_scan_rsp_data_for_instance(&req, 0);
+ hdev->cur_adv_instance = 0x00;
+ update_adv_data(&req);
+ update_scan_rsp_data(&req);
enable_advertising(&req);
} else {
disable_advertising(&req);
@@ -6631,8 +6629,10 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
{
struct mgmt_rp_read_adv_features *rp;
size_t rp_len;
- int err;
+ int err, i;
bool instance;
+ int num_adv_instances = 0;
+ struct adv_info *adv_instance;
u32 supported_flags;

BT_DBG("%s", hdev->name);
@@ -6645,12 +6645,11 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,

rp_len = sizeof(*rp);

- /* Currently only one instance is supported, so just add 1 to the
- * response length.
- */
instance = hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE);
- if (instance)
- rp_len++;
+ if (instance) {
+ num_adv_instances = hci_num_adv_instances(hdev);
+ rp_len += num_adv_instances;
+ }

rp = kmalloc(rp_len, GFP_ATOMIC);
if (!rp) {
@@ -6663,16 +6662,15 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
rp->supported_flags = cpu_to_le32(supported_flags);
rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
- rp->max_instances = 1;
+ rp->max_instances = HCI_MAX_ADV_INSTANCES;
+ rp->num_instances = num_adv_instances;

- /* Currently only one instance is supported, so simply return the
- * current instance number.
- */
if (instance) {
- rp->num_instances = 1;
- rp->instance[0] = 1;
- } else {
- rp->num_instances = 0;
+ i = 0;
+ list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
+ rp->instance[i] = adv_instance->instance;
+ i++;
+ }
}

hci_dev_unlock(hdev);
@@ -6732,24 +6730,37 @@ static void add_advertising_complete(struct hci_dev *hdev, u8 status,
u16 opcode)
{
struct mgmt_pending_cmd *cmd;
+ struct mgmt_cp_add_advertising *cp = NULL;
struct mgmt_rp_add_advertising rp;
+ struct adv_info *adv_instance;

BT_DBG("status %d", status);

hci_dev_lock(hdev);

cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
+ if (cmd)
+ cp = cmd->param;

if (status) {
+ /* TODO: Start advertising another adv instance if any? */
hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
- memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
- advertising_removed(cmd ? cmd->sk : NULL, hdev, 1);
+
+ if (cmd) {
+ adv_instance = hci_find_adv_instance(hdev,
+ cp->instance);
+ if (adv_instance) {
+ hci_remove_adv_instance(hdev, cp->instance);
+ advertising_removed(cmd ? cmd->sk : NULL, hdev,
+ cp->instance);
+ }
+ }
}

if (!cmd)
goto unlock;

- rp.instance = 0x01;
+ rp.instance = cp->instance;

if (status)
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
@@ -6766,13 +6777,33 @@ unlock:

static void adv_timeout_expired(struct work_struct *work)
{
- struct hci_dev *hdev = container_of(work, struct hci_dev,
- adv_instance.timeout_exp.work);
+ struct adv_info *adv_instance;
+ struct hci_dev *hdev;
+ int err;
+ struct hci_request req;
+
+ adv_instance = container_of(work, struct adv_info, timeout_exp.work);
+ hdev = adv_instance->hdev;

- hdev->adv_instance.timeout = 0;
+ adv_instance->timeout = 0;

hci_dev_lock(hdev);
- clear_adv_instance(hdev);
+ err = hci_remove_adv_instance(hdev, adv_instance->instance);
+ if (err == 0)
+ advertising_removed(NULL, hdev, adv_instance->instance);
+
+ /* TODO: Schedule the next advertisement instance here if any. */
+ hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
+
+ if (!hdev_is_powered(hdev) ||
+ hci_dev_test_flag(hdev, HCI_ADVERTISING))
+ goto unlock;
+
+ hci_req_init(&req, hdev);
+ disable_advertising(&req);
+ hci_req_run(&req, NULL);
+
+unlock:
hci_dev_unlock(hdev);
}

@@ -6831,38 +6862,30 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}

- INIT_DELAYED_WORK(&hdev->adv_instance.timeout_exp, adv_timeout_expired);
-
- hdev->adv_instance.flags = flags;
- hdev->adv_instance.adv_data_len = cp->adv_data_len;
- hdev->adv_instance.scan_rsp_len = cp->scan_rsp_len;
-
- if (cp->adv_data_len)
- memcpy(hdev->adv_instance.adv_data, cp->data, cp->adv_data_len);
-
- if (cp->scan_rsp_len)
- memcpy(hdev->adv_instance.scan_rsp_data,
- cp->data + cp->adv_data_len, cp->scan_rsp_len);
-
- if (hdev->adv_instance.timeout)
- cancel_delayed_work(&hdev->adv_instance.timeout_exp);
-
- hdev->adv_instance.timeout = timeout;
+ err = hci_add_adv_instance(hdev, cp->instance, flags,
+ cp->adv_data_len, cp->data,
+ cp->scan_rsp_len,
+ cp->data + cp->adv_data_len,
+ adv_timeout_expired, timeout);
+ if (err < 0) {
+ err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
+ MGMT_STATUS_FAILED);
+ goto unlock;
+ }

- if (timeout)
- queue_delayed_work(hdev->workqueue,
- &hdev->adv_instance.timeout_exp,
- msecs_to_jiffies(timeout * 1000));
+ hdev->cur_adv_instance = cp->instance;

+ // TODO: Trigger an advertising added event even when instance
+ // advertising is already switched on?
if (!hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING_INSTANCE))
- advertising_added(sk, hdev, 1);
+ advertising_added(sk, hdev, cp->instance);

/* If the HCI_ADVERTISING flag is set or the device isn't powered then
* we have no HCI communication to make. Simply return.
*/
if (!hdev_is_powered(hdev) ||
hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
- rp.instance = 0x01;
+ rp.instance = cp->instance;
err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
goto unlock;
@@ -6933,12 +6956,11 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,

BT_DBG("%s", hdev->name);

- /* The current implementation only allows modifying instance no 1. A
- * value of 0 indicates that all instances should be cleared.
- */
- if (cp->instance > 1)
- return mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
- MGMT_STATUS_INVALID_PARAMS);
+ if (cp->instance != 0x00) {
+ if (!hci_find_adv_instance(hdev, cp->instance))
+ return mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
+ MGMT_STATUS_INVALID_PARAMS);
+ }

hci_dev_lock(hdev);

@@ -6956,21 +6978,22 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}

- if (hdev->adv_instance.timeout)
- cancel_delayed_work(&hdev->adv_instance.timeout_exp);
-
- memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
-
- advertising_removed(sk, hdev, 1);
+ clear_adv_instance(sk, hdev, cp->instance);

+ /* TODO: Only switch off advertising if the instance list is empty
+ * else switch to the next remaining adv instance. */
hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);

- /* If the HCI_ADVERTISING flag is set or the device isn't powered then
- * we have no HCI communication to make. Simply return.
+ /* If the HCI_ADVERTISING[_INSTANCE] flag is set or the device
+ * isn't powered then we have no HCI communication to make.
+ * Simply return.
+ */
+ /* TODO: Only switch off instance advertising when the flag has
+ * actually been unset (see TODO above).
*/
if (!hdev_is_powered(hdev) ||
hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
- rp.instance = 1;
+ rp.instance = cp->instance;
err = mgmt_cmd_complete(sk, hdev->id,
MGMT_OP_REMOVE_ADVERTISING,
MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
--
1.9.1


2015-05-31 01:20:40

by Johan Hedberg

[permalink] [raw]
Subject: Re: [PATCH v6 00/16] Bluetooth: Multi-advertising infrastructure

Hi Florian,

On Wed, May 27, 2015, Florian Grandel wrote:
> >Are multiple instances suppose to work with this patch set?
>
> No. There are a few remaining TODOs (documented in the code) for actual
> multi-advertising. I mention these in the commit messages where applicable.
>
> The idea was to do the more complex changes in a functionally neutral
> refactoring first as a safe starting point for functional changes (see my
> conv. with Arman on the list).
>
> Of course I'm prepared to resolve those remaining TODOs in a second patch
> set. I just think it is a good idea if I go full cycle once to avoid those
> beginner's errors during the next iteration.
>
> If you think that there are no more fundamental flaws in that first patch
> set then I can start with the second one now. What do you think?

I was also under the impression that this set implemented the full
multi-advertising feature (rather than being refactoring in preparation
for it). I think a kernel release should contain the whole thing or
nothing at all, which makes me now a bit doubtful of whether this can
make it to 4.2.

How soon can you send the follow-up set? It will essentially validate
the work of your first set, so it'd be good to see and test it as soon
as possible.

Johan

2015-05-27 21:04:33

by Florian Grandel

[permalink] [raw]
Subject: Re: [PATCH v6 00/16] Bluetooth: Multi-advertising infrastructure

Hi Marcel,

On 05/27/2015 09:23 PM, Marcel Holtmann wrote:
> Hi Florian,
>
>> patch set introducing the infrastructure for multi-advertising
>> capability to the HCI core and mgmt API.
>>
>> v1 -> v2:
>> - add missing braces in read_adv_features()
>>
>> v2 -> v3 (changes due to Johan's review):
>> - split change-set into several patches
>> - replace err == 0 by !err
>> - fix coding style problems
>>
>> v3 -> v4 (changes due to Arman's review):
>> - bug fix: when calling remove_advertising with an instance value of
>> zero (i.e. remove all instances), the command response also returns
>> an instance value of zero now as it doesn't make sense to return a
>> single instance id when removing several instances
>> - splitting the change set into a much larger number of patches to
>> facilitate review
>> - use HCI_MAX_ADV_INSTANCES in the same patch that introduces it
>> - use adv_info->hdev in the same patch that introduces it
>> - make the logic of hci_find_adv_instance() more readable
>> - make sure that hci_find_adv_instance() is called while hci_dev is
>> locked
>> - replace hci_num_adv_instances() by an instance counter in hci_dev
>> - add inline comment in get_adv_instance_flags() explaining its return
>> value in the error case
>> - generate zero-length adv data if the current instance identifier is
>> invalid
>> - revert erroneous changes to the logic in clear_adv_instance()
>> - use hci_adv_instances_clear() in clear_adv_instance() when removing
>> all advertising instances also removing a redundant error check
>> - inserting TODO messages to make sure that advertising will not be
>> switched off prematurely once we allow more than one advertising
>> instance
>> - inserting TODO messages to make sure that multiple advertising
>> instances will be advertised in a round-robin fashion once we allow
>> for more than one advertising instance
>> - identify peding advertising instances (just added but not yet
>> confirmed in add_advertising_complete) by a boolean flag in the
>> adv_info struct so that we can identify and remove them even when the
>> pending add_advertising command cannot be retrieved for some reason -
>> makes sure that we do not leak advertising instances in this case
>> - only send HCI commands to update advertising data when a new instance
>> has actually been added
>>
>> v4 -> v5 (changes due to Marcel's review):
>> - split into separate change sets for kernel and userspace
>> - do not trust the adv instance list length when compiling the adv
>> features struct
>> - introduce adv_info->pending in the same patch it's used for the first
>> time
>>
>> v5 -> v6 (changes due to Marcel's review):
>> - fix the add adv override bug
>> - fix "Using plain integer as NULL pointer" warning in
>> set_advertising_complete()
>> - reword the "remove adv instance" commit comment to make it clear that
>> an existing bug is being fixed
>
> so the max adv instances variable is still 1 after applying this patch set. So fundamentally nothing has changed. However when I set this to any other value, the feature does not really work. Doing a simple thing and adding multiple instances with a default duration value only keeps the last one active forever. It just never rotates. Also when I have two or more instances and remove instance 1, then advertising gets disabled and trying to remove the other instances return an error.
>
> Are multiple instances suppose to work with this patch set?

No. There are a few remaining TODOs (documented in the code) for actual
multi-advertising. I mention these in the commit messages where applicable.

The idea was to do the more complex changes in a functionally neutral
refactoring first as a safe starting point for functional changes (see
my conv. with Arman on the list).

Of course I'm prepared to resolve those remaining TODOs in a second
patch set. I just think it is a good idea if I go full cycle once to
avoid those beginner's errors during the next iteration.

If you think that there are no more fundamental flaws in that first
patch set then I can start with the second one now. What do you think?

Florian

2015-05-27 19:23:14

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH v6 00/16] Bluetooth: Multi-advertising infrastructure

Hi Florian,

> patch set introducing the infrastructure for multi-advertising
> capability to the HCI core and mgmt API.
>
> v1 -> v2:
> - add missing braces in read_adv_features()
>
> v2 -> v3 (changes due to Johan's review):
> - split change-set into several patches
> - replace err == 0 by !err
> - fix coding style problems
>
> v3 -> v4 (changes due to Arman's review):
> - bug fix: when calling remove_advertising with an instance value of
> zero (i.e. remove all instances), the command response also returns
> an instance value of zero now as it doesn't make sense to return a
> single instance id when removing several instances
> - splitting the change set into a much larger number of patches to
> facilitate review
> - use HCI_MAX_ADV_INSTANCES in the same patch that introduces it
> - use adv_info->hdev in the same patch that introduces it
> - make the logic of hci_find_adv_instance() more readable
> - make sure that hci_find_adv_instance() is called while hci_dev is
> locked
> - replace hci_num_adv_instances() by an instance counter in hci_dev
> - add inline comment in get_adv_instance_flags() explaining its return
> value in the error case
> - generate zero-length adv data if the current instance identifier is
> invalid
> - revert erroneous changes to the logic in clear_adv_instance()
> - use hci_adv_instances_clear() in clear_adv_instance() when removing
> all advertising instances also removing a redundant error check
> - inserting TODO messages to make sure that advertising will not be
> switched off prematurely once we allow more than one advertising
> instance
> - inserting TODO messages to make sure that multiple advertising
> instances will be advertised in a round-robin fashion once we allow
> for more than one advertising instance
> - identify peding advertising instances (just added but not yet
> confirmed in add_advertising_complete) by a boolean flag in the
> adv_info struct so that we can identify and remove them even when the
> pending add_advertising command cannot be retrieved for some reason -
> makes sure that we do not leak advertising instances in this case
> - only send HCI commands to update advertising data when a new instance
> has actually been added
>
> v4 -> v5 (changes due to Marcel's review):
> - split into separate change sets for kernel and userspace
> - do not trust the adv instance list length when compiling the adv
> features struct
> - introduce adv_info->pending in the same patch it's used for the first
> time
>
> v5 -> v6 (changes due to Marcel's review):
> - fix the add adv override bug
> - fix "Using plain integer as NULL pointer" warning in
> set_advertising_complete()
> - reword the "remove adv instance" commit comment to make it clear that
> an existing bug is being fixed

so the max adv instances variable is still 1 after applying this patch set. So fundamentally nothing has changed. However when I set this to any other value, the feature does not really work. Doing a simple thing and adding multiple instances with a default duration value only keeps the last one active forever. It just never rotates. Also when I have two or more instances and remove instance 1, then advertising gets disabled and trying to remove the other instances return an error.

Are multiple instances suppose to work with this patch set?

Regards

Marcel


2015-05-26 01:22:09

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v7 4/4] tools/mgmt-tester: add an additional add adv test

This test covers a use case that had not been tested before: When an
advertising instance has already been added and is then added again with
different advertising data, the new advertising data should be
advertised.
---
doc/test-coverage.txt | 4 ++--
tools/mgmt-tester.c | 16 ++++++++++++++++
2 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/doc/test-coverage.txt b/doc/test-coverage.txt
index 26e5855..89d9991 100644
--- a/doc/test-coverage.txt
+++ b/doc/test-coverage.txt
@@ -39,7 +39,7 @@ Automated end-to-end testing

Application Count Description
-------------------------------------------
-mgmt-tester 296 Kernel management interface testing
+mgmt-tester 297 Kernel management interface testing
l2cap-tester 27 Kernel L2CAP implementation testing
rfcomm-tester 9 Kernel RFCOMM implementation testing
bnep-tester 1 Kernel BNEP implementation testing
@@ -49,7 +49,7 @@ gap-tester 1 Daemon D-Bus API testing
hci-tester 14 Controller hardware testing
userchan-tester 3 Kernel HCI User Channel testting
-----
- 365
+ 368


Android end-to-end testing
diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 474d258..675c35c 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -4510,6 +4510,18 @@ static const struct generic_data add_advertising_timeout_power_off = {
.expect_alt_ev_len = sizeof(advertising_instance_param),
};

+static const struct generic_data add_advertising_success_18 = {
+ .send_opcode = MGMT_OP_ADD_ADVERTISING,
+ .send_param = add_advertising_param_1,
+ .send_len = sizeof(add_advertising_param_1),
+ .expect_param = advertising_instance_param,
+ .expect_len = sizeof(advertising_instance_param),
+ .expect_status = MGMT_STATUS_SUCCESS,
+ .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
+ .expect_hci_param = set_adv_data_1,
+ .expect_hci_len = sizeof(set_adv_data_1),
+};
+
static const uint8_t remove_advertising_param_1[] = {
0x01,
};
@@ -6641,6 +6653,10 @@ int main(int argc, char *argv[])
&add_advertising_success_17,
setup_add_advertising_connectable,
test_command_generic);
+ test_bredrle("Add Advertising - Success 19 (Add Adv override)",
+ &add_advertising_success_18,
+ setup_add_advertising,
+ test_command_generic);

test_bredrle("Remove Advertising - Invalid Params 1",
&remove_advertising_fail_1,
--
1.9.1


2015-05-26 01:22:08

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v7 3/4] tools/mgmt-tester: rename add adv tests

The add advertisement tests were named a bit inconsistently and the test
intent was not always clear from the naming of the test. This has been
improved by introducing a somewhat more consistent naming scheme and
adding additional hints wrt the test intent.
---
tools/mgmt-tester.c | 38 +++++++++++++++++++-------------------
1 file changed, 19 insertions(+), 19 deletions(-)

diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 62bea80..474d258 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -6577,67 +6577,67 @@ int main(int argc, char *argv[])
test_le("Add Advertising - Invalid Params 10 (ScRsp too long)",
&add_advertising_fail_11,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Timeout Not Powered",
+ test_bredrle("Add Advertising - Rejected (Timeout, Not Powered)",
&add_advertising_fail_12,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Timeout Power off",
+ test_bredrle("Add Advertising - Success 1 (Timeout, Power off)",
&add_advertising_timeout_power_off,
setup_add_advertising_timeout,
test_command_generic);
- test_bredrle("Add Advertising - Success 1",
+ test_bredrle("Add Advertising - Success 2 (Powered, Added, Adv Data)",
&add_advertising_success_1,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 2",
+ test_bredrle("Add Advertising - Success 3 (Not Powered, Adv Data)",
&add_advertising_success_2,
setup_add_advertising_not_powered,
test_command_generic);
- test_bredrle("Add Advertising - Success 3",
+ test_bredrle("Add Advertising - Success 4 (Not Powered, Adv Enable)",
&add_advertising_success_3,
setup_add_advertising_not_powered,
test_command_generic);
- test_bredrle("Add Advertising - Set Advertising on override 1",
+ test_bredrle("Add Advertising - Success 5 (Set Adv on override)",
&add_advertising_success_4,
setup_add_advertising,
test_command_generic);
- test_bredrle("Add Advertising - Set Advertising off override 2",
+ test_bredrle("Add Advertising - Success 6 (Set Adv off override)",
&add_advertising_success_5,
setup_set_and_add_advertising,
test_command_generic);
- test_bredrle("Add Advertising - Success 4",
+ test_bredrle("Add Advertising - Success 7 (Scan Rsp Data, Adv ok)",
&add_advertising_success_6,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 5",
+ test_bredrle("Add Advertising - Success 8 (Scan Rsp Data, Scan ok) ",
&add_advertising_success_7,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 6 - Flag 0",
+ test_bredrle("Add Advertising - Success 9 (Connectable Flag)",
&add_advertising_success_8,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 7 - Flag 1",
+ test_bredrle("Add Advertising - Success 10 (General Discov Flag)",
&add_advertising_success_9,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 8 - Flag 2",
+ test_bredrle("Add Advertising - Success 11 (Limited Discov Flag)",
&add_advertising_success_10,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 8 - Flag 3",
+ test_bredrle("Add Advertising - Success 12 (Managed Flags)",
&add_advertising_success_11,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 9 - Flag 4",
+ test_bredrle("Add Advertising - Success 13 (TX Power Flag)",
&add_advertising_success_12,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 10 - ADV_SCAN_IND",
+ test_bredrle("Add Advertising - Success 14 (ADV_SCAN_IND)",
&add_advertising_success_13,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 11 - ADV_NONCONN_IND",
+ test_bredrle("Add Advertising - Success 15 (ADV_NONCONN_IND)",
&add_advertising_success_14,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 12 - ADV_IND",
+ test_bredrle("Add Advertising - Success 16 (ADV_IND)",
&add_advertising_success_15,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 13 - connectable -> on",
+ test_bredrle("Add Advertising - Success 17 (Connectable -> on)",
&add_advertising_success_16,
setup_add_advertising,
test_command_generic);
- test_bredrle("Add Advertising - Success 14 - connectable -> off",
+ test_bredrle("Add Advertising - Success 18 (Connectable -> off)",
&add_advertising_success_17,
setup_add_advertising_connectable,
test_command_generic);
--
1.9.1


2015-05-26 01:22:07

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v7 2/4] tools/mgmt-tester: comment add adv test setup

The add advertising test setup data was just a number of arrays with
undocumented hex data. This sometimes made it difficult to understand
the test intent.

Comments have been added to the add advertising mgmt and hci parameter
data arrays to make them more readable and better document the test
intent.
---
tools/mgmt-tester.c | 215 ++++++++++++++++++++++++++++++++++++----------------
1 file changed, 150 insertions(+), 65 deletions(-)

diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 2c5fc1b..62bea80 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -3886,54 +3886,92 @@ static const struct generic_data read_adv_features_success_2 = {
.expect_status = MGMT_STATUS_SUCCESS,
};

+/* simple add advertising command */
static const uint8_t add_advertising_param_1[] = {
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
-};
-
+ 0x01, /* adv instance */
+ 0x00, 0x00, 0x00, 0x00, /* flags: none */
+ 0x00, 0x00, /* duration */
+ 0x00, 0x00, /* timeout: none */
+ 0x09, /* adv data len */
+ 0x00, /* scan rsp len */
+ /* adv data: */
+ 0x03, /* AD len */
+ 0x02, /* AD type: some 16 bit service class UUIDs */
+ 0x0d, 0x18, /* heart rate monitor */
+ 0x04, /* AD len */
+ 0xff, /* AD type: manufacturer specific data */
+ 0x01, 0x02, 0x03, /* custom advertising data */
+};
+
+/* add advertising with scan response data */
static const uint8_t add_advertising_param_2[] = {
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x0a,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
- 0x03, 0x19, 0x40, 0x03,
- 0x05, 0x03, 0x0d, 0x18, 0x0f, 0x18,
-};
-
+ /* instance, flags, duration, timeout, adv data len: same as before */
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
+ 0x0a, /* scan rsp len */
+ /* adv data: same as before */
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+ /* scan rsp data: */
+ 0x03, /* AD len */
+ 0x19, /* AD type: external appearance */
+ 0x40, 0x03, /* some custom appearance */
+ 0x05, /* AD len */
+ 0x03, /* AD type: all 16 bit service class UUIDs */
+ 0x0d, 0x18, /* heart rate monitor */
+ 0x0f, 0x18, /* battery service */
+};
+
+/* add advertising with timeout */
static const uint8_t add_advertising_param_3[] = {
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
+ /* instance, flags, duration: same as before */
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x05, 0x00, /* timeout: 5 seconds */
+ /* adv data: same as before */
+ 0x09, 0x00, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
};

+/* add advertising with connectable flag */
static const uint8_t add_advertising_param_4[] = {
- 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
+ 0x01, /* adv instance */
+ 0x01, 0x00, 0x00, 0x00, /* flags: connectable*/
+ /* duration, timeout, adv/scan data: same as before */
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
};

+/* add advertising with general discoverable flag */
static const uint8_t add_advertising_param_5[] = {
- 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
+ 0x01, /* adv instance */
+ 0x02, 0x00, 0x00, 0x00, /* flags: general discoverable*/
+ /* duration, timeout, adv/scan data: same as before */
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
};

+/* add advertising with limited discoverable flag */
static const uint8_t add_advertising_param_6[] = {
- 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
+ 0x01, /* adv instance */
+ 0x04, 0x00, 0x00, 0x00, /* flags: limited discoverable */
+ /* duration, timeout, adv/scan data: same as before */
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
};

+/* add advertising with managed flags */
static const uint8_t add_advertising_param_7[] = {
- 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
+ 0x01, /* adv instance */
+ 0x08, 0x00, 0x00, 0x00, /* flags: managed flags */
+ /* duration, timeout, adv/scan data: same as before */
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
};

+/* add advertising with tx power flag */
static const uint8_t add_advertising_param_8[] = {
- 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
+ 0x01, /* adv instance */
+ 0x10, 0x00, 0x00, 0x00, /* flags: tx power */
+ /* duration, timeout, adv/scan data: same as before */
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
};

static const uint8_t advertising_instance_param[] = {
@@ -3941,59 +3979,106 @@ static const uint8_t advertising_instance_param[] = {
};

static const uint8_t set_adv_data_1[] = {
- 0x09, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+ /* adv data len */
+ 0x09,
+ /* advertise heart rate monitor and manufacturer specific data */
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00,
};

static const uint8_t set_adv_data_2[] = {
- 0x06, 0x05, 0x08, 0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x00,
+ 0x06, /* adv data len */
+ 0x05, /* AD len */
+ 0x08, /* AD type: shortened local name */
+ 0x74, 0x65, 0x73, 0x74, /* "test" */
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
};

static const uint8_t set_adv_data_3[] = {
- 0x03, 0x02, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, /* adv data len */
+ 0x02, /* AD len */
+ 0x0a, /* AD type: tx power */
+ 0x00, /* tx power */
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};

static const uint8_t set_adv_data_4[] = {
- 0x0c, 0x02, 0x01, 0x02, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff,
- 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, /* adv data len */
+ 0x02, /* AD len */
+ 0x01, /* AD type: flags */
+ 0x02, /* general discoverable */
+ 0x03, /* AD len */
+ 0x02, /* AD type: some 16bit service class UUIDs */
+ 0x0d, 0x18, /* heart rate monitor */
+ 0x04, /* AD len */
+ 0xff, /* AD type: manufacturer specific data */
+ 0x01, 0x02, 0x03, /* custom advertising data */
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};

static const uint8_t set_adv_data_5[] = {
- 0x0c, 0x02, 0x01, 0x01, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff,
- 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, /* adv data len */
+ 0x02, /* AD len */
+ 0x01, /* AD type: flags */
+ 0x01, /* limited discoverable */
+ /* rest: same as before */
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};

static const uint8_t set_adv_data_6[] = {
- 0x0c, 0x02, 0x01, 0x02, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff,
- 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, /* adv data len */
+ 0x02, /* AD len */
+ 0x01, /* AD type: flags */
+ 0x02, /* general discoverable */
+ /* rest: same as before */
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};

static const uint8_t set_adv_data_7[] = {
- 0x0c, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
- 0x02, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, /* adv data len */
+ 0x03, /* AD len */
+ 0x02, /* AD type: some 16bit service class UUIDs */
+ 0x0d, 0x18, /* heart rate monitor */
+ 0x04, /* AD len */
+ 0xff, /* AD type: manufacturer specific data */
+ 0x01, 0x02, 0x03, /* custom advertising data */
+ 0x02, /* AD len */
+ 0x0a, /* AD type: tx power */
+ 0x00, /* tx power */
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};

static const uint8_t set_scan_rsp_1[] = {
- 0x0a, 0x03, 0x19, 0x40, 0x03, 0x05, 0x03, 0x0d, 0x18, 0x0f,
- 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0a, /* scan rsp data len */
+ 0x03, /* AD len */
+ 0x19, /* AD type: external appearance */
+ 0x40, 0x03, /* some custom appearance */
+ 0x05, /* AD len */
+ 0x03, /* AD type: all 16 bit service class UUIDs */
+ 0x0d, 0x18, 0x0f, 0x18, /* heart rate monitor, battery service */
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00,
};

static const uint8_t add_advertising_invalid_param_1[] = {
@@ -4914,9 +4999,9 @@ static void setup_add_advertising_not_powered(const void *test_data)

cp->instance = 1;
cp->adv_data_len = 6;
- cp->data[0] = 0x05;
- cp->data[1] = 0x08;
- cp->data[2] = 't';
+ cp->data[0] = 0x05; /* AD len */
+ cp->data[1] = 0x08; /* AD type: shortened local name */
+ cp->data[2] = 't'; /* adv data ... */
cp->data[3] = 'e';
cp->data[4] = 's';
cp->data[5] = 't';
@@ -4945,9 +5030,9 @@ static void setup_add_advertising(const void *test_data)

cp->instance = 1;
cp->adv_data_len = 6;
- cp->data[0] = 0x05;
- cp->data[1] = 0x08;
- cp->data[2] = 't';
+ cp->data[0] = 0x05; /* AD len */
+ cp->data[1] = 0x08; /* AD type: shortened local name */
+ cp->data[2] = 't'; /* adv data ... */
cp->data[3] = 'e';
cp->data[4] = 's';
cp->data[5] = 't';
@@ -4980,9 +5065,9 @@ static void setup_add_advertising_connectable(const void *test_data)

cp->instance = 1;
cp->adv_data_len = 6;
- cp->data[0] = 0x05;
- cp->data[1] = 0x08;
- cp->data[2] = 't';
+ cp->data[0] = 0x05; /* AD len */
+ cp->data[1] = 0x08; /* AD type: shortened local name */
+ cp->data[2] = 't'; /* adv data ... */
cp->data[3] = 'e';
cp->data[4] = 's';
cp->data[5] = 't';
@@ -5020,9 +5105,9 @@ static void setup_add_advertising_timeout(const void *test_data)
cp->instance = 1;
cp->timeout = 5;
cp->adv_data_len = 6;
- cp->data[0] = 0x05;
- cp->data[1] = 0x08;
- cp->data[2] = 't';
+ cp->data[0] = 0x05; /* AD len */
+ cp->data[1] = 0x08; /* AD type: shortened local name */
+ cp->data[2] = 't'; /* adv data ... */
cp->data[3] = 'e';
cp->data[4] = 's';
cp->data[5] = 't';
@@ -5055,9 +5140,9 @@ static void setup_set_and_add_advertising(const void *test_data)

cp->instance = 1;
cp->adv_data_len = 6;
- cp->data[0] = 0x05;
- cp->data[1] = 0x08;
- cp->data[2] = 't';
+ cp->data[0] = 0x05; /* AD len */
+ cp->data[1] = 0x08; /* AD type: shortened local name */
+ cp->data[2] = 't'; /* adv data ... */
cp->data[3] = 'e';
cp->data[4] = 's';
cp->data[5] = 't';
--
1.9.1


2015-05-26 01:22:06

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v7 1/4] tools/mgmt_tester: expect 0 rp when removing all adv inst

The kernel would previously return a hard coded instance value of 0x01
even when removing multiple advertising instances. The correct behavior,
though, would be to return zero when multiple instances have been
removed. This corresponds to the semantics of the mgmt API call made in
the first place.

A fix for this problem has been introduced in the kernel. Now the
corresponding test is updated to reflect that logic.
---
tools/mgmt-tester.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 3ecddab..2c5fc1b 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -4460,8 +4460,8 @@ static const struct generic_data remove_advertising_success_2 = {
.send_param = remove_advertising_param_2,
.send_len = sizeof(remove_advertising_param_2),
.expect_status = MGMT_STATUS_SUCCESS,
- .expect_param = remove_advertising_param_1,
- .expect_len = sizeof(remove_advertising_param_1),
+ .expect_param = remove_advertising_param_2,
+ .expect_len = sizeof(remove_advertising_param_2),
.expect_alt_ev = MGMT_EV_ADVERTISING_REMOVED,
.expect_alt_ev_param = advertising_instance_param,
.expect_alt_ev_len = sizeof(advertising_instance_param),
--
1.9.1


2015-05-26 01:22:05

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v7 0/4] tools/mgmt-tester: multi-advertising additions

patch set accompanying the introduction of a multi-advertising
infrastructure in the kernel

v1 ... v4:
- fix tests to test for correct behavior when removing all adv instances
by passing in the 0x00 instance identifier

v4 -> v5:
- factored userland code changes into a separate change set for easier
review

v5 -> v6:
- documented add advertising test setup
- renamed add advertising tests to make them more readable
- added test to reproduce a bug found by Marcel (executing add-adv twice
for the same instance should override the adv data)

v6 -> v7
- correctly split mangled patches

Florian Grandel (4):
tools/mgmt_tester: expect 0 rp when removing all adv inst
tools/mgmt-tester: comment add adv test setup
tools/mgmt-tester: rename add adv tests
tools/mgmt-tester: add an additional add adv test

doc/test-coverage.txt | 4 +-
tools/mgmt-tester.c | 273 ++++++++++++++++++++++++++++++++++----------------
2 files changed, 189 insertions(+), 88 deletions(-)

--
1.9.1


2015-05-26 00:35:55

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v6 4/4] tools/mgmt-tester: add an additional add adv test

This test covers a use case that had not been tested before: When an
advertising instance has already been added and is then added again with
different advertising data, the new advertising data should be
advertised.
---
doc/test-coverage.txt | 4 ++--
tools/mgmt-tester.c | 20 ++++++++++++++++++--
2 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/doc/test-coverage.txt b/doc/test-coverage.txt
index 26e5855..89d9991 100644
--- a/doc/test-coverage.txt
+++ b/doc/test-coverage.txt
@@ -39,7 +39,7 @@ Automated end-to-end testing

Application Count Description
-------------------------------------------
-mgmt-tester 296 Kernel management interface testing
+mgmt-tester 297 Kernel management interface testing
l2cap-tester 27 Kernel L2CAP implementation testing
rfcomm-tester 9 Kernel RFCOMM implementation testing
bnep-tester 1 Kernel BNEP implementation testing
@@ -49,7 +49,7 @@ gap-tester 1 Daemon D-Bus API testing
hci-tester 14 Controller hardware testing
userchan-tester 3 Kernel HCI User Channel testting
-----
- 365
+ 368


Android end-to-end testing
diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 72ed224..675c35c 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -4510,6 +4510,18 @@ static const struct generic_data add_advertising_timeout_power_off = {
.expect_alt_ev_len = sizeof(advertising_instance_param),
};

+static const struct generic_data add_advertising_success_18 = {
+ .send_opcode = MGMT_OP_ADD_ADVERTISING,
+ .send_param = add_advertising_param_1,
+ .send_len = sizeof(add_advertising_param_1),
+ .expect_param = advertising_instance_param,
+ .expect_len = sizeof(advertising_instance_param),
+ .expect_status = MGMT_STATUS_SUCCESS,
+ .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
+ .expect_hci_param = set_adv_data_1,
+ .expect_hci_len = sizeof(set_adv_data_1),
+};
+
static const uint8_t remove_advertising_param_1[] = {
0x01,
};
@@ -6633,14 +6645,18 @@ int main(int argc, char *argv[])
test_bredrle("Add Advertising - Success 16 (ADV_IND)",
&add_advertising_success_15,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 17 (connectable -> on)",
+ test_bredrle("Add Advertising - Success 17 (Connectable -> on)",
&add_advertising_success_16,
setup_add_advertising,
test_command_generic);
- test_bredrle("Add Advertising - Success 18 (connectable -> off)",
+ test_bredrle("Add Advertising - Success 18 (Connectable -> off)",
&add_advertising_success_17,
setup_add_advertising_connectable,
test_command_generic);
+ test_bredrle("Add Advertising - Success 19 (Add Adv override)",
+ &add_advertising_success_18,
+ setup_add_advertising,
+ test_command_generic);

test_bredrle("Remove Advertising - Invalid Params 1",
&remove_advertising_fail_1,
--
1.9.1


2015-05-26 00:35:54

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v6 3/4] tools/mgmt-tester: rename add adv tests

The add advertisement tests were named a bit inconsistently and the test
intent was not always clear from the naming of the test. This has been
improved by introducing a somewhat more consistent naming scheme and
adding additional hints wrt the test intent.
---
tools/mgmt-tester.c | 38 +++++++++++++++++++-------------------
1 file changed, 19 insertions(+), 19 deletions(-)

diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 62bea80..72ed224 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -6577,67 +6577,67 @@ int main(int argc, char *argv[])
test_le("Add Advertising - Invalid Params 10 (ScRsp too long)",
&add_advertising_fail_11,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Timeout Not Powered",
+ test_bredrle("Add Advertising - Rejected (Timeout, Not Powered)",
&add_advertising_fail_12,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Timeout Power off",
+ test_bredrle("Add Advertising - Success 1 (Timeout, Power off)",
&add_advertising_timeout_power_off,
setup_add_advertising_timeout,
test_command_generic);
- test_bredrle("Add Advertising - Success 1",
+ test_bredrle("Add Advertising - Success 2 (Powered, Added, Adv Data)",
&add_advertising_success_1,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 2",
+ test_bredrle("Add Advertising - Success 3 (Not Powered, Adv Data)",
&add_advertising_success_2,
setup_add_advertising_not_powered,
test_command_generic);
- test_bredrle("Add Advertising - Success 3",
+ test_bredrle("Add Advertising - Success 4 (Not Powered, Adv Enable)",
&add_advertising_success_3,
setup_add_advertising_not_powered,
test_command_generic);
- test_bredrle("Add Advertising - Set Advertising on override 1",
+ test_bredrle("Add Advertising - Success 5 (Set Adv on override)",
&add_advertising_success_4,
setup_add_advertising,
test_command_generic);
- test_bredrle("Add Advertising - Set Advertising off override 2",
+ test_bredrle("Add Advertising - Success 6 (Set Adv off override)",
&add_advertising_success_5,
setup_set_and_add_advertising,
test_command_generic);
- test_bredrle("Add Advertising - Success 4",
+ test_bredrle("Add Advertising - Success 7 (Scan Rsp Data, Adv ok)",
&add_advertising_success_6,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 5",
+ test_bredrle("Add Advertising - Success 8 (Scan Rsp Data, Scan ok) ",
&add_advertising_success_7,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 6 - Flag 0",
+ test_bredrle("Add Advertising - Success 9 (Connectable Flag)",
&add_advertising_success_8,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 7 - Flag 1",
+ test_bredrle("Add Advertising - Success 10 (General Discov Flag)",
&add_advertising_success_9,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 8 - Flag 2",
+ test_bredrle("Add Advertising - Success 11 (Limited Discov Flag)",
&add_advertising_success_10,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 8 - Flag 3",
+ test_bredrle("Add Advertising - Success 12 (Managed Flags)",
&add_advertising_success_11,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 9 - Flag 4",
+ test_bredrle("Add Advertising - Success 13 (TX Power Flag)",
&add_advertising_success_12,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 10 - ADV_SCAN_IND",
+ test_bredrle("Add Advertising - Success 14 (ADV_SCAN_IND)",
&add_advertising_success_13,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 11 - ADV_NONCONN_IND",
+ test_bredrle("Add Advertising - Success 15 (ADV_NONCONN_IND)",
&add_advertising_success_14,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 12 - ADV_IND",
+ test_bredrle("Add Advertising - Success 16 (ADV_IND)",
&add_advertising_success_15,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 13 - connectable -> on",
+ test_bredrle("Add Advertising - Success 17 (connectable -> on)",
&add_advertising_success_16,
setup_add_advertising,
test_command_generic);
- test_bredrle("Add Advertising - Success 14 - connectable -> off",
+ test_bredrle("Add Advertising - Success 18 (connectable -> off)",
&add_advertising_success_17,
setup_add_advertising_connectable,
test_command_generic);
--
1.9.1


2015-05-26 00:35:53

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v6 2/4] tools/mgmt-tester: comment add adv test setup

The add advertising test setup data was just a number of arrays with
undocumented hex data. This sometimes made it difficult to understand
the test intent.

Comments have been added to the add advertising mgmt and hci parameter
data arrays to make them more readable and better document the test
intent.
---
tools/mgmt-tester.c | 215 ++++++++++++++++++++++++++++++++++++----------------
1 file changed, 150 insertions(+), 65 deletions(-)

diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 2c5fc1b..62bea80 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -3886,54 +3886,92 @@ static const struct generic_data read_adv_features_success_2 = {
.expect_status = MGMT_STATUS_SUCCESS,
};

+/* simple add advertising command */
static const uint8_t add_advertising_param_1[] = {
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
-};
-
+ 0x01, /* adv instance */
+ 0x00, 0x00, 0x00, 0x00, /* flags: none */
+ 0x00, 0x00, /* duration */
+ 0x00, 0x00, /* timeout: none */
+ 0x09, /* adv data len */
+ 0x00, /* scan rsp len */
+ /* adv data: */
+ 0x03, /* AD len */
+ 0x02, /* AD type: some 16 bit service class UUIDs */
+ 0x0d, 0x18, /* heart rate monitor */
+ 0x04, /* AD len */
+ 0xff, /* AD type: manufacturer specific data */
+ 0x01, 0x02, 0x03, /* custom advertising data */
+};
+
+/* add advertising with scan response data */
static const uint8_t add_advertising_param_2[] = {
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x0a,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
- 0x03, 0x19, 0x40, 0x03,
- 0x05, 0x03, 0x0d, 0x18, 0x0f, 0x18,
-};
-
+ /* instance, flags, duration, timeout, adv data len: same as before */
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
+ 0x0a, /* scan rsp len */
+ /* adv data: same as before */
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+ /* scan rsp data: */
+ 0x03, /* AD len */
+ 0x19, /* AD type: external appearance */
+ 0x40, 0x03, /* some custom appearance */
+ 0x05, /* AD len */
+ 0x03, /* AD type: all 16 bit service class UUIDs */
+ 0x0d, 0x18, /* heart rate monitor */
+ 0x0f, 0x18, /* battery service */
+};
+
+/* add advertising with timeout */
static const uint8_t add_advertising_param_3[] = {
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
+ /* instance, flags, duration: same as before */
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x05, 0x00, /* timeout: 5 seconds */
+ /* adv data: same as before */
+ 0x09, 0x00, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
};

+/* add advertising with connectable flag */
static const uint8_t add_advertising_param_4[] = {
- 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
+ 0x01, /* adv instance */
+ 0x01, 0x00, 0x00, 0x00, /* flags: connectable*/
+ /* duration, timeout, adv/scan data: same as before */
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
};

+/* add advertising with general discoverable flag */
static const uint8_t add_advertising_param_5[] = {
- 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
+ 0x01, /* adv instance */
+ 0x02, 0x00, 0x00, 0x00, /* flags: general discoverable*/
+ /* duration, timeout, adv/scan data: same as before */
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
};

+/* add advertising with limited discoverable flag */
static const uint8_t add_advertising_param_6[] = {
- 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
+ 0x01, /* adv instance */
+ 0x04, 0x00, 0x00, 0x00, /* flags: limited discoverable */
+ /* duration, timeout, adv/scan data: same as before */
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
};

+/* add advertising with managed flags */
static const uint8_t add_advertising_param_7[] = {
- 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
+ 0x01, /* adv instance */
+ 0x08, 0x00, 0x00, 0x00, /* flags: managed flags */
+ /* duration, timeout, adv/scan data: same as before */
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
};

+/* add advertising with tx power flag */
static const uint8_t add_advertising_param_8[] = {
- 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
+ 0x01, /* adv instance */
+ 0x10, 0x00, 0x00, 0x00, /* flags: tx power */
+ /* duration, timeout, adv/scan data: same as before */
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
};

static const uint8_t advertising_instance_param[] = {
@@ -3941,59 +3979,106 @@ static const uint8_t advertising_instance_param[] = {
};

static const uint8_t set_adv_data_1[] = {
- 0x09, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+ /* adv data len */
+ 0x09,
+ /* advertise heart rate monitor and manufacturer specific data */
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00,
};

static const uint8_t set_adv_data_2[] = {
- 0x06, 0x05, 0x08, 0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x00,
+ 0x06, /* adv data len */
+ 0x05, /* AD len */
+ 0x08, /* AD type: shortened local name */
+ 0x74, 0x65, 0x73, 0x74, /* "test" */
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
};

static const uint8_t set_adv_data_3[] = {
- 0x03, 0x02, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, /* adv data len */
+ 0x02, /* AD len */
+ 0x0a, /* AD type: tx power */
+ 0x00, /* tx power */
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};

static const uint8_t set_adv_data_4[] = {
- 0x0c, 0x02, 0x01, 0x02, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff,
- 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, /* adv data len */
+ 0x02, /* AD len */
+ 0x01, /* AD type: flags */
+ 0x02, /* general discoverable */
+ 0x03, /* AD len */
+ 0x02, /* AD type: some 16bit service class UUIDs */
+ 0x0d, 0x18, /* heart rate monitor */
+ 0x04, /* AD len */
+ 0xff, /* AD type: manufacturer specific data */
+ 0x01, 0x02, 0x03, /* custom advertising data */
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};

static const uint8_t set_adv_data_5[] = {
- 0x0c, 0x02, 0x01, 0x01, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff,
- 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, /* adv data len */
+ 0x02, /* AD len */
+ 0x01, /* AD type: flags */
+ 0x01, /* limited discoverable */
+ /* rest: same as before */
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};

static const uint8_t set_adv_data_6[] = {
- 0x0c, 0x02, 0x01, 0x02, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff,
- 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, /* adv data len */
+ 0x02, /* AD len */
+ 0x01, /* AD type: flags */
+ 0x02, /* general discoverable */
+ /* rest: same as before */
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};

static const uint8_t set_adv_data_7[] = {
- 0x0c, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
- 0x02, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, /* adv data len */
+ 0x03, /* AD len */
+ 0x02, /* AD type: some 16bit service class UUIDs */
+ 0x0d, 0x18, /* heart rate monitor */
+ 0x04, /* AD len */
+ 0xff, /* AD type: manufacturer specific data */
+ 0x01, 0x02, 0x03, /* custom advertising data */
+ 0x02, /* AD len */
+ 0x0a, /* AD type: tx power */
+ 0x00, /* tx power */
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};

static const uint8_t set_scan_rsp_1[] = {
- 0x0a, 0x03, 0x19, 0x40, 0x03, 0x05, 0x03, 0x0d, 0x18, 0x0f,
- 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0a, /* scan rsp data len */
+ 0x03, /* AD len */
+ 0x19, /* AD type: external appearance */
+ 0x40, 0x03, /* some custom appearance */
+ 0x05, /* AD len */
+ 0x03, /* AD type: all 16 bit service class UUIDs */
+ 0x0d, 0x18, 0x0f, 0x18, /* heart rate monitor, battery service */
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00,
};

static const uint8_t add_advertising_invalid_param_1[] = {
@@ -4914,9 +4999,9 @@ static void setup_add_advertising_not_powered(const void *test_data)

cp->instance = 1;
cp->adv_data_len = 6;
- cp->data[0] = 0x05;
- cp->data[1] = 0x08;
- cp->data[2] = 't';
+ cp->data[0] = 0x05; /* AD len */
+ cp->data[1] = 0x08; /* AD type: shortened local name */
+ cp->data[2] = 't'; /* adv data ... */
cp->data[3] = 'e';
cp->data[4] = 's';
cp->data[5] = 't';
@@ -4945,9 +5030,9 @@ static void setup_add_advertising(const void *test_data)

cp->instance = 1;
cp->adv_data_len = 6;
- cp->data[0] = 0x05;
- cp->data[1] = 0x08;
- cp->data[2] = 't';
+ cp->data[0] = 0x05; /* AD len */
+ cp->data[1] = 0x08; /* AD type: shortened local name */
+ cp->data[2] = 't'; /* adv data ... */
cp->data[3] = 'e';
cp->data[4] = 's';
cp->data[5] = 't';
@@ -4980,9 +5065,9 @@ static void setup_add_advertising_connectable(const void *test_data)

cp->instance = 1;
cp->adv_data_len = 6;
- cp->data[0] = 0x05;
- cp->data[1] = 0x08;
- cp->data[2] = 't';
+ cp->data[0] = 0x05; /* AD len */
+ cp->data[1] = 0x08; /* AD type: shortened local name */
+ cp->data[2] = 't'; /* adv data ... */
cp->data[3] = 'e';
cp->data[4] = 's';
cp->data[5] = 't';
@@ -5020,9 +5105,9 @@ static void setup_add_advertising_timeout(const void *test_data)
cp->instance = 1;
cp->timeout = 5;
cp->adv_data_len = 6;
- cp->data[0] = 0x05;
- cp->data[1] = 0x08;
- cp->data[2] = 't';
+ cp->data[0] = 0x05; /* AD len */
+ cp->data[1] = 0x08; /* AD type: shortened local name */
+ cp->data[2] = 't'; /* adv data ... */
cp->data[3] = 'e';
cp->data[4] = 's';
cp->data[5] = 't';
@@ -5055,9 +5140,9 @@ static void setup_set_and_add_advertising(const void *test_data)

cp->instance = 1;
cp->adv_data_len = 6;
- cp->data[0] = 0x05;
- cp->data[1] = 0x08;
- cp->data[2] = 't';
+ cp->data[0] = 0x05; /* AD len */
+ cp->data[1] = 0x08; /* AD type: shortened local name */
+ cp->data[2] = 't'; /* adv data ... */
cp->data[3] = 'e';
cp->data[4] = 's';
cp->data[5] = 't';
--
1.9.1


2015-05-26 00:35:52

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v6 1/4] tools/mgmt_tester: expect 0 rp when removing all adv inst

The kernel would previously return a hard coded instance value of 0x01
even when removing multiple advertising instances. The correct behavior,
though, would be to return zero when multiple instances have been
removed. This corresponds to the semantics of the mgmt API call made in
the first place.

A fix for this problem has been introduced in the kernel. Now the
corresponding test is updated to reflect that logic.
---
tools/mgmt-tester.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 3ecddab..2c5fc1b 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -4460,8 +4460,8 @@ static const struct generic_data remove_advertising_success_2 = {
.send_param = remove_advertising_param_2,
.send_len = sizeof(remove_advertising_param_2),
.expect_status = MGMT_STATUS_SUCCESS,
- .expect_param = remove_advertising_param_1,
- .expect_len = sizeof(remove_advertising_param_1),
+ .expect_param = remove_advertising_param_2,
+ .expect_len = sizeof(remove_advertising_param_2),
.expect_alt_ev = MGMT_EV_ADVERTISING_REMOVED,
.expect_alt_ev_param = advertising_instance_param,
.expect_alt_ev_len = sizeof(advertising_instance_param),
--
1.9.1


2015-05-26 00:35:51

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v6 0/4] tools/mgmt-tester: multi-advertising additions

patch set accompanying the introduction of a multi-advertising
infrastructure in the kernel

v1 ... v4:
- fix tests to test for correct behavior when removing all adv instances
by passing in the 0x00 instance identifier

v4 -> v5:
- factored userland code changes into a separate change set for easier
review

v5 -> v6:
- documented add advertising test setup
- renamed add advertising tests to make them more readable
- added test to reproduce a bug found by Marcel (executing add-adv twice
for the same instance should override the adv data)

Florian Grandel (4):
tools/mgmt_tester: expect 0 rp when removing all adv inst
tools/mgmt-tester: comment add adv test setup
tools/mgmt-tester: rename add adv tests
tools/mgmt-tester: add an additional add adv test

doc/test-coverage.txt | 4 +-
tools/mgmt-tester.c | 273 ++++++++++++++++++++++++++++++++++----------------
2 files changed, 189 insertions(+), 88 deletions(-)

--
1.9.1


2015-05-26 00:34:23

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v6 16/16] Bluetooth: hci_core: remove obsolete adv_instance

Now that the obsolete adv_instance is no longer being referenced
anywhere in the code it can be removed without breaking the build.

Signed-off-by: Florian Grandel <[email protected]>
---
include/net/bluetooth/hci_core.h | 6 ------
net/bluetooth/hci_core.c | 1 -
2 files changed, 7 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 36cc941..f8cf00f 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -378,7 +378,6 @@ struct hci_dev {
__u8 scan_rsp_data[HCI_MAX_AD_LENGTH];
__u8 scan_rsp_data_len;

- struct adv_info adv_instance;
struct list_head adv_instances;
unsigned int adv_instance_cnt;
__u8 cur_adv_instance;
@@ -569,11 +568,6 @@ static inline void hci_discovery_filter_clear(struct hci_dev *hdev)
hdev->discovery.scan_duration = 0;
}

-static inline void adv_info_init(struct hci_dev *hdev)
-{
- memset(&hdev->adv_instance, 0, sizeof(struct adv_info));
-}
-
bool hci_discovery_active(struct hci_dev *hdev);

void hci_discovery_set_state(struct hci_dev *hdev, int state);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 01fc98e..8ed8184 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3186,7 +3186,6 @@ struct hci_dev *hci_alloc_dev(void)

hci_init_sysfs(hdev);
discovery_init(hdev);
- adv_info_init(hdev);

return hdev;
}
--
1.9.1


2015-05-26 00:34:22

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v6 15/16] Bluetooth: mgmt: multi adv for remove_advertising()

The remove_advertising() and remove_advertising_complete() functions
had instance identifiers hard coded. Notably, when passing in 0x00 as
an instance identifier to signal that all instances should be removed
then the mgmt API would return a hard coded 0x01 rather than returning
the expected value 0x00. This bug is being fixed by always referencing
the instance identifier from the management API call instead.

remove_advertising() is refactored to use the new dynamic advertising
instance list.

The code is made more readable by factoring advertising instance
management and initialization into the low-level
hci_remove_adv_instance() and hci_adv_instances_clear() functions.

This change still relies on the fact that we only allow for a single
advertising instance as it should only switch off advertising when there
are no more active advertising instances. It should advertise the next
active advertising instance instead in case there are remaining
advertising instances. A corresponding TODO has been inserted into the
code.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 42 +++++++++++++++++++++++++++---------------
1 file changed, 27 insertions(+), 15 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 6fd0ab9..c662778 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -7089,6 +7089,7 @@ static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
u16 opcode)
{
struct mgmt_pending_cmd *cmd;
+ struct mgmt_cp_remove_advertising *cp;
struct mgmt_rp_remove_advertising rp;

BT_DBG("status %d", status);
@@ -7103,7 +7104,8 @@ static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
if (!cmd)
goto unlock;

- rp.instance = 1;
+ cp = cmd->param;
+ rp.instance = cp->instance;

mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
&rp, sizeof(rp));
@@ -7118,21 +7120,23 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
{
struct mgmt_cp_remove_advertising *cp = data;
struct mgmt_rp_remove_advertising rp;
+ struct adv_info *adv_instance;
int err;
struct mgmt_pending_cmd *cmd;
struct hci_request req;

BT_DBG("%s", hdev->name);

- /* The current implementation only allows modifying instance no 1. A
- * value of 0 indicates that all instances should be cleared.
- */
- if (cp->instance > 1)
- return mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
- MGMT_STATUS_INVALID_PARAMS);
-
hci_dev_lock(hdev);

+ if (cp->instance != 0x00 &&
+ !hci_find_adv_instance(hdev, cp->instance)) {
+ err = mgmt_cmd_status(sk, hdev->id,
+ MGMT_OP_REMOVE_ADVERTISING,
+ MGMT_STATUS_INVALID_PARAMS);
+ goto unlock;
+ }
+
if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
pending_find(MGMT_OP_SET_LE, hdev)) {
@@ -7147,13 +7151,21 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}

- if (hdev->adv_instance.timeout)
- cancel_delayed_work(&hdev->adv_instance.timeout_exp);
-
- memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
-
- advertising_removed(sk, hdev, 1);
+ /* A value of 0 indicates that all instances should be cleared. */
+ if (cp->instance == 0x00) {
+ list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
+ advertising_removed(sk, hdev, adv_instance->instance);
+ }
+ hci_adv_instances_clear(hdev);
+ } else {
+ err = hci_remove_adv_instance(hdev, cp->instance);
+ if (!err)
+ advertising_removed(sk, hdev, cp->instance);
+ }

+ /* TODO: Only switch off advertising if the instance list is empty
+ * else switch to the next remaining adv instance.
+ */
hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);

/* If the HCI_ADVERTISING flag is set or the device isn't powered then
@@ -7161,7 +7173,7 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
*/
if (!hdev_is_powered(hdev) ||
hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
- rp.instance = 1;
+ rp.instance = cp->instance;
err = mgmt_cmd_complete(sk, hdev->id,
MGMT_OP_REMOVE_ADVERTISING,
MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
--
1.9.1


2015-05-26 00:34:21

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v6 14/16] Bluetooth: mgmt: multi adv for clear_adv_instances()

The clean_adv_instance() function could not clean up multiple
advertising instances previously. It is being changed to provide both, a
means to clean up a single instance and cleaning up all instances at
once.

An additional instance parameter is being introduced to achieve this.
Passing in 0x00 to this parameter signifies that all instances should be
cleaned up. This semantics has been chosen similarly to the semantics of
the instance parameter in the remove_advertising() function.

This change still relies on the fact that we only allow a single
advertising instance. When we allow for more than one instance then
advertising should only be disabled when the last instance was cleaned
up, in all other cases the next active advertising instance should be
advertised instead. A corresponding TODO has been inserted into the
code.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 29 ++++++++++++++++++++---------
1 file changed, 20 insertions(+), 9 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 29d871a..6fd0ab9 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1463,18 +1463,30 @@ static void advertising_removed(struct sock *sk, struct hci_dev *hdev,
mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
}

-static void clear_adv_instance(struct hci_dev *hdev)
+static void clear_adv_instance(struct hci_dev *hdev, u8 instance)
{
+ struct adv_info *adv_instance;
+ int err;
struct hci_request req;

+ /* A value of 0 indicates that all instances should be cleared. */
+ if (instance == 0x00) {
+ list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
+ advertising_removed(NULL, hdev, adv_instance->instance);
+ }
+ hci_adv_instances_clear(hdev);
+ } else {
+ err = hci_remove_adv_instance(hdev, instance);
+ if (!err)
+ advertising_removed(NULL, hdev, instance);
+ }
+
if (!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
return;

- if (hdev->adv_instance.timeout)
- cancel_delayed_work(&hdev->adv_instance.timeout_exp);
-
- memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
- advertising_removed(NULL, hdev, 1);
+ /* TODO: Only switch off advertising if the instance list is empty
+ * else switch to the next remaining adv instance.
+ */
hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);

if (!hdev_is_powered(hdev) ||
@@ -1501,8 +1513,7 @@ static int clean_up_hci_state(struct hci_dev *hdev)
hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
}

- if (hdev->adv_instance.timeout)
- clear_adv_instance(hdev);
+ clear_adv_instance(hdev, 0x00);

if (hci_dev_test_flag(hdev, HCI_LE_ADV))
disable_advertising(&req);
@@ -6956,7 +6967,7 @@ static void adv_timeout_expired(struct work_struct *work)

adv_instance->timeout = 0;
hci_dev_lock(hdev);
- clear_adv_instance(hdev);
+ clear_adv_instance(hdev, adv_instance->instance);
hci_dev_unlock(hdev);
}

--
1.9.1


2015-05-26 00:34:20

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v6 13/16] Bluetooth: mgmt: multi adv for add_advertising()

The add_advertising() function had a hard coded instance identifier.
This is being fixed by adding an arbitrary advertising instance to the
dynamic advertising instance list and updating the current instance
identifier accordingly.

The code is made more readable by factoring advertising instance
management and initialization into a low-level hci_add_adv_instance()
function.

We also make sure that event notifications are correctly dealt with in
the case of multiple advertising instances.

This change still relies on the fact that we only allow for a single
advertising instance as it does not yet provide a means to advertise
several instances in a round-robin fashion. This must be added as soon
as more than one instance will be allowed. A corresponding TODO has been
inserted into the code.

Signed-off-by: Florian Grandel <[email protected]>
---
include/net/bluetooth/hci_core.h | 1 +
net/bluetooth/hci_core.c | 1 +
net/bluetooth/mgmt.c | 68 +++++++++++++++++++++++-----------------
3 files changed, 41 insertions(+), 29 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index d92d324..36cc941 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -158,6 +158,7 @@ struct oob_data {
struct adv_info {
struct list_head list;
struct hci_dev *hdev;
+ bool pending;
struct delayed_work timeout_exp;
__u8 instance;
__u32 flags;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 1ec557f..01fc98e 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2687,6 +2687,7 @@ int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,

memset(adv_instance, 0, sizeof(*adv_instance));
adv_instance->hdev = hdev;
+ adv_instance->pending = true;
INIT_DELAYED_WORK(&adv_instance->timeout_exp, timeout_work);
adv_instance->instance = instance;
list_add(&adv_instance->list, &hdev->adv_instances);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 40f4299..29d871a 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -6902,7 +6902,9 @@ static void add_advertising_complete(struct hci_dev *hdev, u8 status,
u16 opcode)
{
struct mgmt_pending_cmd *cmd;
+ struct mgmt_cp_add_advertising *cp;
struct mgmt_rp_add_advertising rp;
+ struct adv_info *adv_instance, *n;

BT_DBG("status %d", status);

@@ -6911,15 +6913,27 @@ static void add_advertising_complete(struct hci_dev *hdev, u8 status,
cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);

if (status) {
+ /* TODO: Start advertising another adv instance if any. */
hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
- memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
- advertising_removed(cmd ? cmd->sk : NULL, hdev, 1);
+ }
+
+ list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
+ if (!adv_instance->pending)
+ continue;
+
+ if (status) {
+ hci_remove_adv_instance(hdev, adv_instance->instance);
+ advertising_removed(cmd ? cmd->sk : NULL, hdev, adv_instance->instance);
+ } else {
+ adv_instance->pending = false;
+ }
}

if (!cmd)
goto unlock;

- rp.instance = 0x01;
+ cp = cmd->param;
+ rp.instance = cp->instance;

if (status)
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
@@ -6955,6 +6969,7 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
u32 supported_flags;
u8 status;
u16 timeout;
+ unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
int err;
struct mgmt_pending_cmd *cmd;
struct hci_request req;
@@ -6969,11 +6984,11 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
flags = __le32_to_cpu(cp->flags);
timeout = __le16_to_cpu(cp->timeout);

- /* The current implementation only supports adding one instance and only
- * a subset of the specified flags.
+ /* The current implementation only supports a subset of the specified
+ * flags.
*/
supported_flags = get_supported_adv_flags(hdev);
- if (cp->instance != 0x01 || (flags & ~supported_flags))
+ if (flags & ~supported_flags)
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
MGMT_STATUS_INVALID_PARAMS);

@@ -7001,38 +7016,33 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}

- INIT_DELAYED_WORK(&hdev->adv_instance.timeout_exp, adv_timeout_expired);
-
- hdev->adv_instance.flags = flags;
- hdev->adv_instance.adv_data_len = cp->adv_data_len;
- hdev->adv_instance.scan_rsp_len = cp->scan_rsp_len;
-
- if (cp->adv_data_len)
- memcpy(hdev->adv_instance.adv_data, cp->data, cp->adv_data_len);
-
- if (cp->scan_rsp_len)
- memcpy(hdev->adv_instance.scan_rsp_data,
- cp->data + cp->adv_data_len, cp->scan_rsp_len);
-
- if (hdev->adv_instance.timeout)
- cancel_delayed_work(&hdev->adv_instance.timeout_exp);
+ err = hci_add_adv_instance(hdev, cp->instance, flags,
+ cp->adv_data_len, cp->data,
+ cp->scan_rsp_len,
+ cp->data + cp->adv_data_len,
+ adv_timeout_expired, timeout);
+ if (err < 0) {
+ err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
+ MGMT_STATUS_FAILED);
+ goto unlock;
+ }

- hdev->adv_instance.timeout = timeout;
+ hdev->cur_adv_instance = cp->instance;

- if (timeout)
- queue_delayed_work(hdev->workqueue,
- &hdev->adv_instance.timeout_exp,
- msecs_to_jiffies(timeout * 1000));
+ hci_dev_set_flag(hdev, HCI_ADVERTISING_INSTANCE);

- if (!hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING_INSTANCE))
- advertising_added(sk, hdev, 1);
+ /* Only trigger an advertising added event if a new instance was
+ * actually added.
+ */
+ if (hdev->adv_instance_cnt > prev_instance_cnt)
+ advertising_added(sk, hdev, cp->instance);

/* If the HCI_ADVERTISING flag is set or the device isn't powered then
* we have no HCI communication to make. Simply return.
*/
if (!hdev_is_powered(hdev) ||
hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
- rp.instance = 0x01;
+ rp.instance = cp->instance;
err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
goto unlock;
--
1.9.1


2015-05-26 00:34:19

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v6 12/16] Bluetooth: mgmt: multi adv for set_advertising_complete()

The set_advertising_complete() method relied on the now obsolete
hci_dev->adv_instance structure. We replace this reference by an
equivalent access to the newly introduced dynamic advertising instance
list.

This solution still relies on the fact that we only allow a single
advertising instance for now. It needs to be further refactored once we
allow more than one advertising instance. A corresponding TODO has been
inserted in the code to make this clear.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 3d09cb9..40f4299 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -4673,6 +4673,7 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status,
{
struct cmd_lookup match = { NULL, hdev };
struct hci_request req;
+ struct adv_info *adv_instance;

hci_dev_lock(hdev);

@@ -4698,14 +4699,26 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status,
sock_put(match.sk);

/* If "Set Advertising" was just disabled and instance advertising was
- * set up earlier, then enable the advertising instance.
+ * set up earlier, then re-enable multi-instance advertising.
*/
if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
- !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
+ !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) ||
+ hdev->adv_instance_cnt == 0)
goto unlock;

- hci_req_init(&req, hdev);
+ /* We advertise multiple instances in a round robin fashion starting
+ * with the first instance in the list.
+ */
+ /* TODO: Make sure the other instances are actually being advertised
+ * once we set HCI_MAX_ADV_INSTANCES > 1.
+ */
+ adv_instance = list_first_entry(&hdev->adv_instances, struct adv_info,
+ list);
+ if (!adv_instance)
+ goto unlock;

+ hci_req_init(&req, hdev);
+ hdev->cur_adv_instance = adv_instance->instance;
update_adv_data(&req);
enable_advertising(&req);

--
1.9.1


2015-05-26 00:34:18

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v6 11/16] Bluetooth: mgmt: refactor update_*_data()

The update_*_data_for_instance() methods are no longer being referenced
anywhere in the code. To reduce complexity and improve readability,
these methods are being joined with their corresponding update_*_data()
counterparts.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 27 ++++++---------------------
1 file changed, 6 insertions(+), 21 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index e999bbb..3d09cb9 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -890,18 +890,18 @@ static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 instance,
return adv_instance->scan_rsp_len;
}

-static void update_scan_rsp_data_for_instance(struct hci_request *req,
- u8 instance)
+static void update_scan_rsp_data(struct hci_request *req)
{
struct hci_dev *hdev = req->hdev;
struct hci_cp_le_set_scan_rsp_data cp;
- u8 len;
+ u8 instance, len;

if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
return;

memset(&cp, 0, sizeof(cp));

+ instance = get_current_adv_instance(hdev);
if (instance)
len = create_instance_scan_rsp_data(hdev, instance, cp.data);
else
@@ -919,14 +919,6 @@ static void update_scan_rsp_data_for_instance(struct hci_request *req,
hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
}

-static void update_scan_rsp_data(struct hci_request *req)
-{
- struct hci_dev *hdev = req->hdev;
- u8 instance = get_current_adv_instance(hdev);
-
- update_scan_rsp_data_for_instance(req, instance);
-}
-
static u8 get_adv_discov_flags(struct hci_dev *hdev)
{
struct mgmt_pending_cmd *cmd;
@@ -1084,17 +1076,18 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
return ad_len;
}

-static void update_adv_data_for_instance(struct hci_request *req, u8 instance)
+static void update_adv_data(struct hci_request *req)
{
struct hci_dev *hdev = req->hdev;
struct hci_cp_le_set_adv_data cp;
- u8 len;
+ u8 instance, len;

if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
return;

memset(&cp, 0, sizeof(cp));

+ instance = get_current_adv_instance(hdev);
len = create_instance_adv_data(hdev, instance, cp.data);

/* There's nothing to do if the data hasn't changed */
@@ -1110,14 +1103,6 @@ static void update_adv_data_for_instance(struct hci_request *req, u8 instance)
hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
}

-static void update_adv_data(struct hci_request *req)
-{
- struct hci_dev *hdev = req->hdev;
- u8 instance = get_current_adv_instance(hdev);
-
- update_adv_data_for_instance(req, instance);
-}
-
int mgmt_update_adv_data(struct hci_dev *hdev)
{
struct hci_request req;
--
1.9.1


2015-05-26 00:34:17

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v6 10/16] Bluetooth: mgmt: multi adv for create_instance_adv_data()

The create_instance_adv_data() function could not deal with
multiple advertising instances previously. This is being fixed by
retrieving advertising instances from the newly introduced dynamic
advertising instance list.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 23 ++++++++++++++++-------
1 file changed, 16 insertions(+), 7 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 8913739..e999bbb 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1018,8 +1018,18 @@ static u8 get_cur_adv_instance_scan_rsp_len(struct hci_dev *hdev)

static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
{
+ struct adv_info *adv_instance = NULL;
u8 ad_len = 0, flags = 0;
- u32 instance_flags = get_adv_instance_flags(hdev, instance);
+ u32 instance_flags;
+
+ /* Return 0 when the current instance identifier is invalid. */
+ if (instance) {
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (!adv_instance)
+ return 0;
+ }
+
+ instance_flags = get_adv_instance_flags(hdev, instance);

/* The Add Advertising command allows userspace to set both the general
* and limited discoverable flags.
@@ -1053,12 +1063,11 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
}
}

- if (instance) {
- memcpy(ptr, hdev->adv_instance.adv_data,
- hdev->adv_instance.adv_data_len);
-
- ad_len += hdev->adv_instance.adv_data_len;
- ptr += hdev->adv_instance.adv_data_len;
+ if (adv_instance) {
+ memcpy(ptr, adv_instance->adv_data,
+ adv_instance->adv_data_len);
+ ad_len += adv_instance->adv_data_len;
+ ptr += adv_instance->adv_data_len;
}

/* Provide Tx Power only if we can provide a valid value for it */
--
1.9.1


2015-05-26 00:34:16

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v6 09/16] Bluetooth: mgmt: multi adv for create_instance_scan_rsp_data()

The create_instance_scan_rsp_data() function could not deal with
multiple advertising instances previously. This is being fixed by adding
an additional instance parameter.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 65c1e51..8913739 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -872,15 +872,22 @@ static u8 create_default_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
return ad_len;
}

-static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
+static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 instance,
+ u8 *ptr)
{
+ struct adv_info *adv_instance;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (!adv_instance)
+ return 0;
+
/* TODO: Set the appropriate entries based on advertising instance flags
* here once flags other than 0 are supported.
*/
- memcpy(ptr, hdev->adv_instance.scan_rsp_data,
- hdev->adv_instance.scan_rsp_len);
+ memcpy(ptr, adv_instance->scan_rsp_data,
+ adv_instance->scan_rsp_len);

- return hdev->adv_instance.scan_rsp_len;
+ return adv_instance->scan_rsp_len;
}

static void update_scan_rsp_data_for_instance(struct hci_request *req,
@@ -896,7 +903,7 @@ static void update_scan_rsp_data_for_instance(struct hci_request *req,
memset(&cp, 0, sizeof(cp));

if (instance)
- len = create_instance_scan_rsp_data(hdev, cp.data);
+ len = create_instance_scan_rsp_data(hdev, instance, cp.data);
else
len = create_default_scan_rsp_data(hdev, cp.data);

--
1.9.1


2015-05-26 00:34:15

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v6 08/16] Bluetooth: mgmt: use current adv instance in set_advertising()

The set_advertising() method needs to update the newly introduced
cur_adv_instance member of the hci device. This also allows us to remove
the last remaining references to the ..._for_instance... versions of
the adv data and scan response update functions.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 94b49ed..65c1e51 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -4795,8 +4795,9 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,

if (val) {
/* Switch to instance "0" for the Set Advertising setting. */
- update_adv_data_for_instance(&req, 0);
- update_scan_rsp_data_for_instance(&req, 0);
+ hdev->cur_adv_instance = 0x00;
+ update_adv_data(&req);
+ update_scan_rsp_data(&req);
enable_advertising(&req);
} else {
disable_advertising(&req);
--
1.9.1


2015-05-26 00:34:14

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v6 07/16] Bluetooth: mgmt: multi adv for enable_advertising()

Previously enable_advertising() would rely on
get_adv_instance_scan_rsp_len() which checked for a hard coded instance
identifier. This is being changed to check for the current advertising
instance's scan response length instead. The function is renamed
accordingly.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 80dd5db..94b49ed 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -990,16 +990,23 @@ static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance)
return adv_instance->flags;
}

-static u8 get_adv_instance_scan_rsp_len(struct hci_dev *hdev, u8 instance)
+static u8 get_cur_adv_instance_scan_rsp_len(struct hci_dev *hdev)
{
- /* Ignore instance 0 and other unsupported instances */
- if (instance != 0x01)
+ u8 instance = get_current_adv_instance(hdev);
+ struct adv_info *adv_instance;
+
+ /* Ignore instance 0 */
+ if (instance == 0x00)
+ return 0;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (!adv_instance)
return 0;

/* TODO: Take into account the "appearance" and "local-name" flags here.
* These are currently being ignored as they are not supported.
*/
- return hdev->adv_instance.scan_rsp_len;
+ return adv_instance->scan_rsp_len;
}

static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
@@ -1273,7 +1280,7 @@ static void enable_advertising(struct hci_request *req)

if (connectable)
cp.type = LE_ADV_IND;
- else if (get_adv_instance_scan_rsp_len(hdev, instance))
+ else if (get_cur_adv_instance_scan_rsp_len(hdev))
cp.type = LE_ADV_SCAN_IND;
else
cp.type = LE_ADV_NONCONN_IND;
--
1.9.1


2015-05-26 00:34:13

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v6 06/16] Bluetooth: mgmt: improve get_adv_instance_flags() readability

Switch if and else conditions to replace a negative statement by a
positive one which makes the condition more readable.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 30 ++++++++++++++++--------------
1 file changed, 16 insertions(+), 14 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 5a531fd5..80dd5db 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -966,26 +966,28 @@ static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance)
u32 flags;
struct adv_info *adv_instance;

- if (instance != 0x00) {
- adv_instance = hci_find_adv_instance(hdev, instance);
+ if (instance == 0x00) {
+ /* Instance 0 always manages the "Tx Power" and "Flags"
+ * fields
+ */
+ flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS;

- /* Return 0 when we got an invalid instance identifier. */
- if (!adv_instance)
- return 0;
+ /* For instance 0, the HCI_ADVERTISING_CONNECTABLE setting
+ * corresponds to the "connectable" instance flag.
+ */
+ if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
+ flags |= MGMT_ADV_FLAG_CONNECTABLE;

- return adv_instance->flags;
+ return flags;
}

- /* Instance 0 always manages the "Tx Power" and "Flags" fields */
- flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS;
+ adv_instance = hci_find_adv_instance(hdev, instance);

- /* For instance 0, the HCI_ADVERTISING_CONNECTABLE setting corresponds
- * to the "connectable" instance flag.
- */
- if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
- flags |= MGMT_ADV_FLAG_CONNECTABLE;
+ /* Return 0 when we got an invalid instance identifier. */
+ if (!adv_instance)
+ return 0;

- return flags;
+ return adv_instance->flags;
}

static u8 get_adv_instance_scan_rsp_len(struct hci_dev *hdev, u8 instance)
--
1.9.1


2015-05-26 00:34:12

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v6 05/16] Bluetooth: mgmt: multi adv for get_adv_instance_flags()

The get_adv_instance_flags() would not work with instance identifiers
other than 0x01. This is being fixed so that arbitrary instance
identifiers can be dealt with while still correctly dealing with the
special case of the 0x00 identifier.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index c28bb2d..5a531fd5 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -964,12 +964,17 @@ static bool get_connectable(struct hci_dev *hdev)
static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance)
{
u32 flags;
+ struct adv_info *adv_instance;

- if (instance > 0x01)
- return 0;
+ if (instance != 0x00) {
+ adv_instance = hci_find_adv_instance(hdev, instance);

- if (instance == 0x01)
- return hdev->adv_instance.flags;
+ /* Return 0 when we got an invalid instance identifier. */
+ if (!adv_instance)
+ return 0;
+
+ return adv_instance->flags;
+ }

/* Instance 0 always manages the "Tx Power" and "Flags" fields */
flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS;
--
1.9.1


2015-05-26 00:34:11

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v6 04/16] Bluetooth: mgmt: multi adv for get_current_adv_instance()

Replaces the hard coded instance identifier in
get_current_adv_instance() with the actual current instance identifier
so that this method is prepared to work with more than one advertising
instance.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 9f5ac26..c28bb2d 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -841,7 +841,7 @@ static u8 get_current_adv_instance(struct hci_dev *hdev)
*/
if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
!hci_dev_test_flag(hdev, HCI_ADVERTISING))
- return 0x01;
+ return hdev->cur_adv_instance;

return 0x00;
}
--
1.9.1


2015-05-26 00:34:10

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v6 03/16] Bluetooth: mgmt: multi adv for read_adv_features()

The read_adv_features() method had a single instance identifier hard
coded. Refer to the advertising instance list instead to return a
dynamically generated list of instance identifiers.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 22 ++++++++++++----------
1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 9dc4905..9f5ac26 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -6770,8 +6770,9 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
{
struct mgmt_rp_read_adv_features *rp;
size_t rp_len;
- int err;
+ int err, i;
bool instance;
+ struct adv_info *adv_instance;
u32 supported_flags;

BT_DBG("%s", hdev->name);
@@ -6784,12 +6785,9 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,

rp_len = sizeof(*rp);

- /* Currently only one instance is supported, so just add 1 to the
- * response length.
- */
instance = hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE);
if (instance)
- rp_len++;
+ rp_len += hdev->adv_instance_cnt;

rp = kmalloc(rp_len, GFP_ATOMIC);
if (!rp) {
@@ -6804,12 +6802,16 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
rp->max_instances = HCI_MAX_ADV_INSTANCES;

- /* Currently only one instance is supported, so simply return the
- * current instance number.
- */
if (instance) {
- rp->num_instances = 1;
- rp->instance[0] = 1;
+ i = 0;
+ list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
+ if (i >= hdev->adv_instance_cnt)
+ break;
+
+ rp->instance[i] = adv_instance->instance;
+ i++;
+ }
+ rp->num_instances = hdev->adv_instance_cnt;
} else {
rp->num_instances = 0;
}
--
1.9.1


2015-05-26 00:34:09

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v6 02/16] Bluetooth: mgmt: dry update_scan_rsp_data()

update_scan_rsp_data() duplicates code from get_current_adv_instance().
This is being fixed by letting the former make use of the latter.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 41 +++++++++++++++--------------------------
1 file changed, 15 insertions(+), 26 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index ce25b6d..9dc4905 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -832,6 +832,20 @@ static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
}

+static u8 get_current_adv_instance(struct hci_dev *hdev)
+{
+ /* The "Set Advertising" setting supersedes the "Add Advertising"
+ * setting. Here we set the advertising data based on which
+ * setting was set. When neither apply, default to the global settings,
+ * represented by instance "0".
+ */
+ if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
+ !hci_dev_test_flag(hdev, HCI_ADVERTISING))
+ return 0x01;
+
+ return 0x00;
+}
+
static u8 create_default_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
{
u8 ad_len = 0;
@@ -901,18 +915,7 @@ static void update_scan_rsp_data_for_instance(struct hci_request *req,
static void update_scan_rsp_data(struct hci_request *req)
{
struct hci_dev *hdev = req->hdev;
- u8 instance;
-
- /* The "Set Advertising" setting supersedes the "Add Advertising"
- * setting. Here we set the scan response data based on which
- * setting was set. When neither apply, default to the global settings,
- * represented by instance "0".
- */
- if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
- !hci_dev_test_flag(hdev, HCI_ADVERTISING))
- instance = 0x01;
- else
- instance = 0x00;
+ u8 instance = get_current_adv_instance(hdev);

update_scan_rsp_data_for_instance(req, instance);
}
@@ -941,20 +944,6 @@ static u8 get_adv_discov_flags(struct hci_dev *hdev)
return 0;
}

-static u8 get_current_adv_instance(struct hci_dev *hdev)
-{
- /* The "Set Advertising" setting supersedes the "Add Advertising"
- * setting. Here we set the advertising data based on which
- * setting was set. When neither apply, default to the global settings,
- * represented by instance "0".
- */
- if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
- !hci_dev_test_flag(hdev, HCI_ADVERTISING))
- return 0x01;
-
- return 0x00;
-}
-
static bool get_connectable(struct hci_dev *hdev)
{
struct mgmt_pending_cmd *cmd;
--
1.9.1


2015-05-26 00:34:08

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v6 01/16] Bluetooth: hci_core: Introduce multi-adv inst list

The current hci dev structure only supports a single advertising
instance. To support multi-instance advertising it is necessary to
introduce a linked list of advertising instances so that multiple
advertising instances can be dynamically added and/or removed.

In a first step, the existing adv_instance member of the hci_dev
struct is supplemented by a linked list of advertising instances.
This patch introduces the list and supporting list management
infrastructure. The list is not being used yet.

Signed-off-by: Florian Grandel <[email protected]>
---
include/net/bluetooth/hci_core.h | 15 ++++++
net/bluetooth/hci_core.c | 111 +++++++++++++++++++++++++++++++++++++++
net/bluetooth/mgmt.c | 10 ++--
3 files changed, 131 insertions(+), 5 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index a056c2b..d92d324 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -156,6 +156,8 @@ struct oob_data {
};

struct adv_info {
+ struct list_head list;
+ struct hci_dev *hdev;
struct delayed_work timeout_exp;
__u8 instance;
__u32 flags;
@@ -166,6 +168,8 @@ struct adv_info {
__u8 scan_rsp_data[HCI_MAX_AD_LENGTH];
};

+#define HCI_MAX_ADV_INSTANCES 1
+
#define HCI_MAX_SHORT_NAME_LENGTH 10

/* Default LE RPA expiry time, 15 minutes */
@@ -374,6 +378,9 @@ struct hci_dev {
__u8 scan_rsp_data_len;

struct adv_info adv_instance;
+ struct list_head adv_instances;
+ unsigned int adv_instance_cnt;
+ __u8 cur_adv_instance;

__u8 irk[16];
__u32 rpa_timeout;
@@ -1007,6 +1014,14 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 bdaddr_type);

+void hci_adv_instances_clear(struct hci_dev *hdev);
+struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance);
+int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
+ u16 adv_data_len, u8 *adv_data,
+ u16 scan_rsp_len, u8 *scan_rsp_data,
+ work_func_t timeout_work, u16 timeout);
+int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance);
+
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);

int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index db11b9d..1ec557f 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2609,6 +2609,113 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
return 0;
}

+/* This function requires the caller holds hdev->lock */
+struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance)
+{
+ struct adv_info *adv_instance;
+
+ list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
+ if (adv_instance->instance == instance)
+ return adv_instance;
+ }
+
+ return NULL;
+}
+
+/* This function requires the caller holds hdev->lock */
+int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance)
+{
+ struct adv_info *adv_instance;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (!adv_instance)
+ return -ENOENT;
+
+ BT_DBG("%s removing %dMR", hdev->name, instance);
+
+ if (adv_instance->timeout)
+ cancel_delayed_work(&adv_instance->timeout_exp);
+
+ list_del(&adv_instance->list);
+ kfree(adv_instance);
+
+ hdev->adv_instance_cnt--;
+
+ return 0;
+}
+
+/* This function requires the caller holds hdev->lock */
+void hci_adv_instances_clear(struct hci_dev *hdev)
+{
+ struct adv_info *adv_instance, *n;
+
+ list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
+ if (adv_instance->timeout)
+ cancel_delayed_work(&adv_instance->timeout_exp);
+
+ list_del(&adv_instance->list);
+ kfree(adv_instance);
+ }
+
+ hdev->adv_instance_cnt = 0;
+}
+
+/* This function requires the caller holds hdev->lock */
+int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
+ u16 adv_data_len, u8 *adv_data,
+ u16 scan_rsp_len, u8 *scan_rsp_data,
+ work_func_t timeout_work, u16 timeout)
+{
+ struct adv_info *adv_instance;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (adv_instance) {
+ if (adv_instance->timeout)
+ cancel_delayed_work(&adv_instance->timeout_exp);
+
+ memset(adv_instance->adv_data, 0,
+ sizeof(adv_instance->adv_data));
+ memset(adv_instance->scan_rsp_data, 0,
+ sizeof(adv_instance->scan_rsp_data));
+ } else {
+ if (hdev->adv_instance_cnt >= HCI_MAX_ADV_INSTANCES)
+ return -EOVERFLOW;
+
+ adv_instance = kmalloc(sizeof(*adv_instance), GFP_KERNEL);
+ if (!adv_instance)
+ return -ENOMEM;
+
+ memset(adv_instance, 0, sizeof(*adv_instance));
+ adv_instance->hdev = hdev;
+ INIT_DELAYED_WORK(&adv_instance->timeout_exp, timeout_work);
+ adv_instance->instance = instance;
+ list_add(&adv_instance->list, &hdev->adv_instances);
+ hdev->adv_instance_cnt++;
+ }
+
+ adv_instance->flags = flags;
+ adv_instance->adv_data_len = adv_data_len;
+ adv_instance->scan_rsp_len = scan_rsp_len;
+
+ if (adv_data_len)
+ memcpy(adv_instance->adv_data, adv_data, adv_data_len);
+
+ if (scan_rsp_len)
+ memcpy(adv_instance->scan_rsp_data,
+ scan_rsp_data, scan_rsp_len);
+
+ adv_instance->timeout = timeout;
+
+ if (timeout)
+ queue_delayed_work(hdev->workqueue,
+ &adv_instance->timeout_exp,
+ msecs_to_jiffies(timeout * 1000));
+
+ BT_DBG("%s for %dMR", hdev->name, instance);
+
+ return 0;
+}
+
struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *bdaddr_list,
bdaddr_t *bdaddr, u8 type)
{
@@ -3012,6 +3119,8 @@ struct hci_dev *hci_alloc_dev(void)
hdev->manufacturer = 0xffff; /* Default to internal use */
hdev->inq_tx_power = HCI_TX_POWER_INVALID;
hdev->adv_tx_power = HCI_TX_POWER_INVALID;
+ hdev->adv_instance_cnt = 0;
+ hdev->cur_adv_instance = 0x00;

hdev->sniff_max_interval = 800;
hdev->sniff_min_interval = 80;
@@ -3053,6 +3162,7 @@ struct hci_dev *hci_alloc_dev(void)
INIT_LIST_HEAD(&hdev->pend_le_conns);
INIT_LIST_HEAD(&hdev->pend_le_reports);
INIT_LIST_HEAD(&hdev->conn_hash.list);
+ INIT_LIST_HEAD(&hdev->adv_instances);

INIT_WORK(&hdev->rx_work, hci_rx_work);
INIT_WORK(&hdev->cmd_work, hci_cmd_work);
@@ -3246,6 +3356,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
hci_smp_ltks_clear(hdev);
hci_smp_irks_clear(hdev);
hci_remote_oob_data_clear(hdev);
+ hci_adv_instances_clear(hdev);
hci_bdaddr_list_clear(&hdev->le_white_list);
hci_conn_params_clear_all(hdev);
hci_discovery_filter_clear(hdev);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 7fd87e7..ce25b6d 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -6813,7 +6813,7 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
rp->supported_flags = cpu_to_le32(supported_flags);
rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
- rp->max_instances = 1;
+ rp->max_instances = HCI_MAX_ADV_INSTANCES;

/* Currently only one instance is supported, so simply return the
* current instance number.
@@ -6916,11 +6916,11 @@ unlock:

static void adv_timeout_expired(struct work_struct *work)
{
- struct hci_dev *hdev = container_of(work, struct hci_dev,
- adv_instance.timeout_exp.work);
-
- hdev->adv_instance.timeout = 0;
+ struct adv_info *adv_instance = container_of(work, struct adv_info,
+ timeout_exp.work);
+ struct hci_dev *hdev = adv_instance->hdev;

+ adv_instance->timeout = 0;
hci_dev_lock(hdev);
clear_adv_instance(hdev);
hci_dev_unlock(hdev);
--
1.9.1


2015-05-26 00:34:07

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v6 00/16] Bluetooth: Multi-advertising infrastructure

patch set introducing the infrastructure for multi-advertising
capability to the HCI core and mgmt API.

v1 -> v2:
- add missing braces in read_adv_features()

v2 -> v3 (changes due to Johan's review):
- split change-set into several patches
- replace err == 0 by !err
- fix coding style problems

v3 -> v4 (changes due to Arman's review):
- bug fix: when calling remove_advertising with an instance value of
zero (i.e. remove all instances), the command response also returns
an instance value of zero now as it doesn't make sense to return a
single instance id when removing several instances
- splitting the change set into a much larger number of patches to
facilitate review
- use HCI_MAX_ADV_INSTANCES in the same patch that introduces it
- use adv_info->hdev in the same patch that introduces it
- make the logic of hci_find_adv_instance() more readable
- make sure that hci_find_adv_instance() is called while hci_dev is
locked
- replace hci_num_adv_instances() by an instance counter in hci_dev
- add inline comment in get_adv_instance_flags() explaining its return
value in the error case
- generate zero-length adv data if the current instance identifier is
invalid
- revert erroneous changes to the logic in clear_adv_instance()
- use hci_adv_instances_clear() in clear_adv_instance() when removing
all advertising instances also removing a redundant error check
- inserting TODO messages to make sure that advertising will not be
switched off prematurely once we allow more than one advertising
instance
- inserting TODO messages to make sure that multiple advertising
instances will be advertised in a round-robin fashion once we allow
for more than one advertising instance
- identify peding advertising instances (just added but not yet
confirmed in add_advertising_complete) by a boolean flag in the
adv_info struct so that we can identify and remove them even when the
pending add_advertising command cannot be retrieved for some reason -
makes sure that we do not leak advertising instances in this case
- only send HCI commands to update advertising data when a new instance
has actually been added

v4 -> v5 (changes due to Marcel's review):
- split into separate change sets for kernel and userspace
- do not trust the adv instance list length when compiling the adv
features struct
- introduce adv_info->pending in the same patch it's used for the first
time

v5 -> v6 (changes due to Marcel's review):
- fix the add adv override bug
- fix "Using plain integer as NULL pointer" warning in
set_advertising_complete()
- reword the "remove adv instance" commit comment to make it clear that
an existing bug is being fixed


Florian Grandel (16):
Bluetooth: hci_core: Introduce multi-adv inst list
Bluetooth: mgmt: dry update_scan_rsp_data()
Bluetooth: mgmt: multi adv for read_adv_features()
Bluetooth: mgmt: multi adv for get_current_adv_instance()
Bluetooth: mgmt: multi adv for get_adv_instance_flags()
Bluetooth: mgmt: improve get_adv_instance_flags() readability
Bluetooth: mgmt: multi adv for enable_advertising()
Bluetooth: mgmt: use current adv instance in set_advertising()
Bluetooth: mgmt: multi adv for create_instance_scan_rsp_data()
Bluetooth: mgmt: multi adv for create_instance_adv_data()
Bluetooth: mgmt: refactor update_*_data()
Bluetooth: mgmt: multi adv for set_advertising_complete()
Bluetooth: mgmt: multi adv for add_advertising()
Bluetooth: mgmt: multi adv for clear_adv_instances()
Bluetooth: mgmt: multi adv for remove_advertising()
Bluetooth: hci_core: remove obsolete adv_instance

include/net/bluetooth/hci_core.h | 22 ++-
net/bluetooth/hci_core.c | 113 ++++++++++++-
net/bluetooth/mgmt.c | 349 ++++++++++++++++++++++-----------------
3 files changed, 329 insertions(+), 155 deletions(-)

--
1.9.1


2015-05-25 08:03:02

by Florian Grandel

[permalink] [raw]
Subject: Re: [PATCH v5 12/16] Bluetooth: mgmt: multi adv for set_advertising_complete()

Hi Marcel,

On 05/25/2015 02:25 AM, Marcel Holtmann wrote:
> Hi Florian,
>
>> The set_advertising_complete() method relied on the now obsolete
>> hci_dev->adv_instance structure. We replace this reference by an
>> equivalent access to the newly introduced dynamic advertising instance
>> list.
>>
>> This solution still relies on the fact that we only allow a single
>> advertising instance for now. It needs to be further refactored once we
>> allow more than one advertising instance. A corresponding TODO has been
>> inserted in the code to make this clear.
>>
>> Signed-off-by: Florian Grandel <[email protected]>
>> ---
>> net/bluetooth/mgmt.c | 19 ++++++++++++++++---
>> 1 file changed, 16 insertions(+), 3 deletions(-)
>>
>> diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
>> index 3d09cb9..1bdf005 100644
>> --- a/net/bluetooth/mgmt.c
>> +++ b/net/bluetooth/mgmt.c
>> @@ -4673,6 +4673,7 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status,
>> {
>> struct cmd_lookup match = { NULL, hdev };
>> struct hci_request req;
>> + struct adv_info *adv_instance;
>>
>> hci_dev_lock(hdev);
>>
>> @@ -4698,14 +4699,26 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status,
>> sock_put(match.sk);
>>
>> /* If "Set Advertising" was just disabled and instance advertising was
>> - * set up earlier, then enable the advertising instance.
>> + * set up earlier, then re-enable multi-instance advertising.
>> */
>> if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
>> - !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
>> + !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) ||
>> + &hdev->adv_instance_cnt == 0)
>
> this gives me an error on make C=2 net/bluetooth/
>
> CHECK net/bluetooth/mgmt.c
> net/bluetooth/mgmt.c:4717:40: warning: Using plain integer as NULL pointer

Oups! Beginner's error. I just did git rebase -i -exec make. I'll use
the C=2 option from now on for all my contributions. Thanks for pointing
me to it.

Florian

2015-05-25 07:51:22

by Florian Grandel

[permalink] [raw]
Subject: Re: [PATCH v5 00/16] Bluetooth: Multi-advertising infrastructure

Hi Marcel,

On 05/25/2015 02:52 AM, Marcel Holtmann wrote:
> Hi Florian,
>
>> patch set introducing the infrastructure for multi-advertising
>> capability to the HCI core and mgmt API.
>
> the patch set is actually breaking functionality. If you want to overwrite the advertising data of an existing instance, then you can just do that by issuing another management command.
>
> add-adv -u 180d 1
> add-adv -u 180f 1
>
> This will first enable advertising with the heart rate UUID and then with the battery service UUID. With your patch set, this basic feature does not work anymore.

I'm going to check this, write a test against this case and make sure
the problem is being fixed.

It's true that I relied on the test suite to already contain tests for
all basic features. That's why I did my regression testing there.

> I think first we need a lot more mgmt-tester commands that actually test this functionality.

Sure. I can introduce missing tests for prior features that are not yet
being tested. You can see that I already added a test case earlier that
was obviously missing (already accepted).

Therefore an important question to you: Which other cases should be
tested? It's hard for me to find that out without your help.

> Regards
>
> Marcel

Thanks!

Florian

2015-05-25 07:53:20

by Florian Grandel

[permalink] [raw]
Subject: Re: [BlueZ v5] tools/mgmt_tester: expect 0 rp when removing all adv inst

Hi Marcel,

On 05/25/2015 02:52 AM, Marcel Holtmann wrote:
> Hi Florian,
>
>> The kernel would previously return a hard coded instance value of 0x01
>> even when removing multiple advertising instances. This was ok as long
>> as we only had a single advertising instance but no longer makes sense
>> now that we allow for multiple advertising instances.
>>
>> We therefore expect the mgmt API to return zero when multiple instances
>> have been removed. This corresponds to the semantics of the mgmt API
>> call made in the first place.
>>
>> The corresponding test is updated to reflect that logic.
>
> this sounds like a bug that exists already today. It should make no difference is you support only once instance or multiple. If you remove all of them (aka clear them), the return value should be 0.

Not sure whether this implies any action for me? Should I single out the
bug fix into a separate patch set?

Regards,

Florian

2015-05-25 00:52:57

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH v5 00/16] Bluetooth: Multi-advertising infrastructure

Hi Florian,

> patch set introducing the infrastructure for multi-advertising
> capability to the HCI core and mgmt API.

the patch set is actually breaking functionality. If you want to overwrite the advertising data of an existing instance, then you can just do that by issuing another management command.

add-adv -u 180d 1
add-adv -u 180f 1

This will first enable advertising with the heart rate UUID and then with the battery service UUID. With your patch set, this basic feature does not work anymore.

I think first we need a lot more mgmt-tester commands that actually test this functionality.

Regards

Marcel


2015-05-25 00:52:21

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [BlueZ v5] tools/mgmt_tester: expect 0 rp when removing all adv inst

Hi Florian,

> The kernel would previously return a hard coded instance value of 0x01
> even when removing multiple advertising instances. This was ok as long
> as we only had a single advertising instance but no longer makes sense
> now that we allow for multiple advertising instances.
>
> We therefore expect the mgmt API to return zero when multiple instances
> have been removed. This corresponds to the semantics of the mgmt API
> call made in the first place.
>
> The corresponding test is updated to reflect that logic.

this sounds like a bug that exists already today. It should make no difference is you support only once instance or multiple. If you remove all of them (aka clear them), the return value should be 0.

Regards

Marcel


2015-05-25 00:25:42

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH v5 12/16] Bluetooth: mgmt: multi adv for set_advertising_complete()

Hi Florian,

> The set_advertising_complete() method relied on the now obsolete
> hci_dev->adv_instance structure. We replace this reference by an
> equivalent access to the newly introduced dynamic advertising instance
> list.
>
> This solution still relies on the fact that we only allow a single
> advertising instance for now. It needs to be further refactored once we
> allow more than one advertising instance. A corresponding TODO has been
> inserted in the code to make this clear.
>
> Signed-off-by: Florian Grandel <[email protected]>
> ---
> net/bluetooth/mgmt.c | 19 ++++++++++++++++---
> 1 file changed, 16 insertions(+), 3 deletions(-)
>
> diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
> index 3d09cb9..1bdf005 100644
> --- a/net/bluetooth/mgmt.c
> +++ b/net/bluetooth/mgmt.c
> @@ -4673,6 +4673,7 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status,
> {
> struct cmd_lookup match = { NULL, hdev };
> struct hci_request req;
> + struct adv_info *adv_instance;
>
> hci_dev_lock(hdev);
>
> @@ -4698,14 +4699,26 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status,
> sock_put(match.sk);
>
> /* If "Set Advertising" was just disabled and instance advertising was
> - * set up earlier, then enable the advertising instance.
> + * set up earlier, then re-enable multi-instance advertising.
> */
> if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
> - !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
> + !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) ||
> + &hdev->adv_instance_cnt == 0)

this gives me an error on make C=2 net/bluetooth/

CHECK net/bluetooth/mgmt.c
net/bluetooth/mgmt.c:4717:40: warning: Using plain integer as NULL pointer

Regards

Marcel


2015-05-24 22:41:57

by Florian Grandel

[permalink] [raw]
Subject: Re: [PATCH v4 04/17] Bluetooth: mgmt: multi adv for read_adv_features()

On 05/23/2015 11:25 PM, Marcel Holtmann wrote:
> Hi Florian,
>
>> The read_adv_features() method had a single instance identifier hard
>> coded. Refer to the advertising instance list instead to return a
>> dynamically generated list of instance identifiers.
>>
>> Signed-off-by: Florian Grandel <[email protected]>
>> ---
>> net/bluetooth/mgmt.c | 21 +++++++++------------
>> 1 file changed, 9 insertions(+), 12 deletions(-)
>>
>> diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
>> index 9dc4905..55ab2a3 100644
>> --- a/net/bluetooth/mgmt.c
>> +++ b/net/bluetooth/mgmt.c
>> @@ -6770,8 +6770,9 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
>> {
>> struct mgmt_rp_read_adv_features *rp;
>> size_t rp_len;
>> - int err;
>> + int err, i;
>> bool instance;
>> + struct adv_info *adv_instance;
>> u32 supported_flags;
>>
>> BT_DBG("%s", hdev->name);
>> @@ -6784,12 +6785,9 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
>>
>> rp_len = sizeof(*rp);
>>
>> - /* Currently only one instance is supported, so just add 1 to the
>> - * response length.
>> - */
>> instance = hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE);
>> if (instance)
>> - rp_len++;
>> + rp_len += hdev->adv_instance_cnt;
>>
>> rp = kmalloc(rp_len, GFP_ATOMIC);
>> if (!rp) {
>> @@ -6803,15 +6801,14 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
>> rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
>> rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
>> rp->max_instances = HCI_MAX_ADV_INSTANCES;
>> + rp->num_instances = hdev->adv_instance_cnt;
>>
>> - /* Currently only one instance is supported, so simply return the
>> - * current instance number.
>> - */
>> if (instance) {
>> - rp->num_instances = 1;
>> - rp->instance[0] = 1;
>> - } else {
>> - rp->num_instances = 0;
>> + i = 0;
>> + list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
>> + rp->instance[i] = adv_instance->instance;
>> + i++;
>> + }
>
> I would really prefer that we leave this logic in place. When !instance, then keep returning rp->num_instances = 0 and in the other case set it to hdev->adv_instance_cnt. I would also prefer that the list is really limited by adv_instance_cnt and not blindly trusted that the list size is the same.

Done... see the latest patch set (v5).

>
> Regards
>
> Marcel
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>

Florian

2015-05-24 22:40:09

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v5] tools/mgmt_tester: expect 0 rp when removing all adv inst

The kernel would previously return a hard coded instance value of 0x01
even when removing multiple advertising instances. This was ok as long
as we only had a single advertising instance but no longer makes sense
now that we allow for multiple advertising instances.

We therefore expect the mgmt API to return zero when multiple instances
have been removed. This corresponds to the semantics of the mgmt API
call made in the first place.

The corresponding test is updated to reflect that logic.
---
tools/mgmt-tester.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 3ecddab..2c5fc1b 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -4460,8 +4460,8 @@ static const struct generic_data remove_advertising_success_2 = {
.send_param = remove_advertising_param_2,
.send_len = sizeof(remove_advertising_param_2),
.expect_status = MGMT_STATUS_SUCCESS,
- .expect_param = remove_advertising_param_1,
- .expect_len = sizeof(remove_advertising_param_1),
+ .expect_param = remove_advertising_param_2,
+ .expect_len = sizeof(remove_advertising_param_2),
.expect_alt_ev = MGMT_EV_ADVERTISING_REMOVED,
.expect_alt_ev_param = advertising_instance_param,
.expect_alt_ev_len = sizeof(advertising_instance_param),
--
1.9.1


2015-05-24 22:39:14

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v5 16/16] Bluetooth: hci_core: remove obsolete adv_instance

Now that the obsolete adv_instance is no longer being referenced
anywhere in the code it can be removed without breaking the build.

Signed-off-by: Florian Grandel <[email protected]>
---
include/net/bluetooth/hci_core.h | 6 ------
net/bluetooth/hci_core.c | 1 -
2 files changed, 7 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 36cc941..f8cf00f 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -378,7 +378,6 @@ struct hci_dev {
__u8 scan_rsp_data[HCI_MAX_AD_LENGTH];
__u8 scan_rsp_data_len;

- struct adv_info adv_instance;
struct list_head adv_instances;
unsigned int adv_instance_cnt;
__u8 cur_adv_instance;
@@ -569,11 +568,6 @@ static inline void hci_discovery_filter_clear(struct hci_dev *hdev)
hdev->discovery.scan_duration = 0;
}

-static inline void adv_info_init(struct hci_dev *hdev)
-{
- memset(&hdev->adv_instance, 0, sizeof(struct adv_info));
-}
-
bool hci_discovery_active(struct hci_dev *hdev);

void hci_discovery_set_state(struct hci_dev *hdev, int state);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 01fc98e..8ed8184 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3186,7 +3186,6 @@ struct hci_dev *hci_alloc_dev(void)

hci_init_sysfs(hdev);
discovery_init(hdev);
- adv_info_init(hdev);

return hdev;
}
--
1.9.1


2015-05-24 22:39:13

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v5 15/16] Bluetooth: mgmt: multi adv for remove_advertising()

The remove_advertising() and remove_advertising_complete() functions
had a hard coded instance identifier. This is being fixed by referencing
the instance identifier from the management API call instead.

remove_advertising() would not allow for instance identifiers other than
0x01. We now allow for arbitrary and/or multiple instance identifiers
while maintaining the previous semantics that an instance identifier of
0x00 signals that all advertising instances should be removed.

The code is made more readable by factoring advertising instance
management and initialization into the low-level
hci_remove_adv_instance() and hci_adv_instances_clear() functions.

This change still relies on the fact that we only allow for a single
advertising instance as it should only switch off advertising when there
are no more active advertising instances. It should advertise the next
active advertising instance instead in case there are remaining
advertising instances. A corresponding TODO has been inserted into the
code.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 42 +++++++++++++++++++++++++++---------------
1 file changed, 27 insertions(+), 15 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 39e6b772..6a54eb5 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -7089,6 +7089,7 @@ static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
u16 opcode)
{
struct mgmt_pending_cmd *cmd;
+ struct mgmt_cp_remove_advertising *cp;
struct mgmt_rp_remove_advertising rp;

BT_DBG("status %d", status);
@@ -7103,7 +7104,8 @@ static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
if (!cmd)
goto unlock;

- rp.instance = 1;
+ cp = cmd->param;
+ rp.instance = cp->instance;

mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
&rp, sizeof(rp));
@@ -7118,21 +7120,23 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
{
struct mgmt_cp_remove_advertising *cp = data;
struct mgmt_rp_remove_advertising rp;
+ struct adv_info *adv_instance;
int err;
struct mgmt_pending_cmd *cmd;
struct hci_request req;

BT_DBG("%s", hdev->name);

- /* The current implementation only allows modifying instance no 1. A
- * value of 0 indicates that all instances should be cleared.
- */
- if (cp->instance > 1)
- return mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
- MGMT_STATUS_INVALID_PARAMS);
-
hci_dev_lock(hdev);

+ if (cp->instance != 0x00 &&
+ !hci_find_adv_instance(hdev, cp->instance)) {
+ err = mgmt_cmd_status(sk, hdev->id,
+ MGMT_OP_REMOVE_ADVERTISING,
+ MGMT_STATUS_INVALID_PARAMS);
+ goto unlock;
+ }
+
if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
pending_find(MGMT_OP_SET_LE, hdev)) {
@@ -7147,13 +7151,21 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}

- if (hdev->adv_instance.timeout)
- cancel_delayed_work(&hdev->adv_instance.timeout_exp);
-
- memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
-
- advertising_removed(sk, hdev, 1);
+ /* A value of 0 indicates that all instances should be cleared. */
+ if (cp->instance == 0x00) {
+ list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
+ advertising_removed(sk, hdev, adv_instance->instance);
+ }
+ hci_adv_instances_clear(hdev);
+ } else {
+ err = hci_remove_adv_instance(hdev, cp->instance);
+ if (!err)
+ advertising_removed(sk, hdev, cp->instance);
+ }

+ /* TODO: Only switch off advertising if the instance list is empty
+ * else switch to the next remaining adv instance.
+ */
hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);

/* If the HCI_ADVERTISING flag is set or the device isn't powered then
@@ -7161,7 +7173,7 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
*/
if (!hdev_is_powered(hdev) ||
hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
- rp.instance = 1;
+ rp.instance = cp->instance;
err = mgmt_cmd_complete(sk, hdev->id,
MGMT_OP_REMOVE_ADVERTISING,
MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
--
1.9.1


2015-05-24 22:39:12

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v5 14/16] Bluetooth: mgmt: multi adv for clear_adv_instances()

The clean_adv_instance() function could not clean up multiple
advertising instances previously. It is being changed to provide both, a
means to clean up a single instance and cleaning up all instances at
once.

An additional instance parameter is being introduced to achieve this.
Passing in 0x00 to this parameter signifies that all instances should be
cleaned up. This semantics has been chosen similarly to the semantics of
the instance parameter in the remove_advertising() function.

This change still relies on the fact that we only allow a single
advertising instance. When we allow for more than one instance then
advertising should only be disabled when the last instance was cleaned
up, in all other cases the next active advertising instance should be
advertised instead. A corresponding TODO has been inserted into the
code.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 29 ++++++++++++++++++++---------
1 file changed, 20 insertions(+), 9 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 6eba4d8..39e6b772 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1463,18 +1463,30 @@ static void advertising_removed(struct sock *sk, struct hci_dev *hdev,
mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
}

-static void clear_adv_instance(struct hci_dev *hdev)
+static void clear_adv_instance(struct hci_dev *hdev, u8 instance)
{
+ struct adv_info *adv_instance;
+ int err;
struct hci_request req;

+ /* A value of 0 indicates that all instances should be cleared. */
+ if (instance == 0x00) {
+ list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
+ advertising_removed(NULL, hdev, adv_instance->instance);
+ }
+ hci_adv_instances_clear(hdev);
+ } else {
+ err = hci_remove_adv_instance(hdev, instance);
+ if (!err)
+ advertising_removed(NULL, hdev, instance);
+ }
+
if (!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
return;

- if (hdev->adv_instance.timeout)
- cancel_delayed_work(&hdev->adv_instance.timeout_exp);
-
- memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
- advertising_removed(NULL, hdev, 1);
+ /* TODO: Only switch off advertising if the instance list is empty
+ * else switch to the next remaining adv instance.
+ */
hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);

if (!hdev_is_powered(hdev) ||
@@ -1501,8 +1513,7 @@ static int clean_up_hci_state(struct hci_dev *hdev)
hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
}

- if (hdev->adv_instance.timeout)
- clear_adv_instance(hdev);
+ clear_adv_instance(hdev, 0x00);

if (hci_dev_test_flag(hdev, HCI_LE_ADV))
disable_advertising(&req);
@@ -6956,7 +6967,7 @@ static void adv_timeout_expired(struct work_struct *work)

adv_instance->timeout = 0;
hci_dev_lock(hdev);
- clear_adv_instance(hdev);
+ clear_adv_instance(hdev, adv_instance->instance);
hci_dev_unlock(hdev);
}

--
1.9.1


2015-05-24 22:39:11

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v5 13/16] Bluetooth: mgmt: multi adv for add_advertising()

The add_advertising() function had a hard coded instance identifier.
This is being fixed by adding an arbitrary advertising instance to the
dynamic advertising instance list and updating the current instance
identifier accordingly.

The code is made more readable by factoring advertising instance
management and initialization into a low-level hci_add_adv_instance()
function.

We also make sure that event notifications are correctly dealt with in
the case of multiple advertising instances.

This change still relies on the fact that we only allow for a single
advertising instance as it does not yet provide a means to advertise
several instances in a round-robin fashion. This must be added as soon
as more than one instance will be allowed. A corresponding TODO has been
inserted into the code.

Signed-off-by: Florian Grandel <[email protected]>
---
include/net/bluetooth/hci_core.h | 1 +
net/bluetooth/hci_core.c | 1 +
net/bluetooth/mgmt.c | 72 +++++++++++++++++++++++-----------------
3 files changed, 43 insertions(+), 31 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index d92d324..36cc941 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -158,6 +158,7 @@ struct oob_data {
struct adv_info {
struct list_head list;
struct hci_dev *hdev;
+ bool pending;
struct delayed_work timeout_exp;
__u8 instance;
__u32 flags;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 1ec557f..01fc98e 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2687,6 +2687,7 @@ int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,

memset(adv_instance, 0, sizeof(*adv_instance));
adv_instance->hdev = hdev;
+ adv_instance->pending = true;
INIT_DELAYED_WORK(&adv_instance->timeout_exp, timeout_work);
adv_instance->instance = instance;
list_add(&adv_instance->list, &hdev->adv_instances);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 1bdf005..6eba4d8 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -6902,7 +6902,9 @@ static void add_advertising_complete(struct hci_dev *hdev, u8 status,
u16 opcode)
{
struct mgmt_pending_cmd *cmd;
+ struct mgmt_cp_add_advertising *cp;
struct mgmt_rp_add_advertising rp;
+ struct adv_info *adv_instance, *n;

BT_DBG("status %d", status);

@@ -6911,15 +6913,27 @@ static void add_advertising_complete(struct hci_dev *hdev, u8 status,
cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);

if (status) {
+ /* TODO: Start advertising another adv instance if any. */
hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
- memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
- advertising_removed(cmd ? cmd->sk : NULL, hdev, 1);
+ }
+
+ list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
+ if (!adv_instance->pending)
+ continue;
+
+ if (status) {
+ hci_remove_adv_instance(hdev, adv_instance->instance);
+ advertising_removed(cmd ? cmd->sk : NULL, hdev, adv_instance->instance);
+ } else {
+ adv_instance->pending = false;
+ }
}

if (!cmd)
goto unlock;

- rp.instance = 0x01;
+ cp = cmd->param;
+ rp.instance = cp->instance;

if (status)
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
@@ -6955,6 +6969,7 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
u32 supported_flags;
u8 status;
u16 timeout;
+ unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
int err;
struct mgmt_pending_cmd *cmd;
struct hci_request req;
@@ -6969,11 +6984,11 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
flags = __le32_to_cpu(cp->flags);
timeout = __le16_to_cpu(cp->timeout);

- /* The current implementation only supports adding one instance and only
- * a subset of the specified flags.
+ /* The current implementation only supports a subset of the specified
+ * flags.
*/
supported_flags = get_supported_adv_flags(hdev);
- if (cp->instance != 0x01 || (flags & ~supported_flags))
+ if (flags & ~supported_flags)
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
MGMT_STATUS_INVALID_PARAMS);

@@ -7001,38 +7016,33 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}

- INIT_DELAYED_WORK(&hdev->adv_instance.timeout_exp, adv_timeout_expired);
-
- hdev->adv_instance.flags = flags;
- hdev->adv_instance.adv_data_len = cp->adv_data_len;
- hdev->adv_instance.scan_rsp_len = cp->scan_rsp_len;
-
- if (cp->adv_data_len)
- memcpy(hdev->adv_instance.adv_data, cp->data, cp->adv_data_len);
-
- if (cp->scan_rsp_len)
- memcpy(hdev->adv_instance.scan_rsp_data,
- cp->data + cp->adv_data_len, cp->scan_rsp_len);
-
- if (hdev->adv_instance.timeout)
- cancel_delayed_work(&hdev->adv_instance.timeout_exp);
+ err = hci_add_adv_instance(hdev, cp->instance, flags,
+ cp->adv_data_len, cp->data,
+ cp->scan_rsp_len,
+ cp->data + cp->adv_data_len,
+ adv_timeout_expired, timeout);
+ if (err < 0) {
+ err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
+ MGMT_STATUS_FAILED);
+ goto unlock;
+ }

- hdev->adv_instance.timeout = timeout;
+ hdev->cur_adv_instance = cp->instance;

- if (timeout)
- queue_delayed_work(hdev->workqueue,
- &hdev->adv_instance.timeout_exp,
- msecs_to_jiffies(timeout * 1000));
+ hci_dev_set_flag(hdev, HCI_ADVERTISING_INSTANCE);

- if (!hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING_INSTANCE))
- advertising_added(sk, hdev, 1);
+ /* Only trigger an advertising added event if a new instance was
+ * actually added.
+ */
+ if (hdev->adv_instance_cnt > prev_instance_cnt)
+ advertising_added(sk, hdev, cp->instance);

- /* If the HCI_ADVERTISING flag is set or the device isn't powered then
+ /* If we are already advertising or the device isn't powered then
* we have no HCI communication to make. Simply return.
*/
if (!hdev_is_powered(hdev) ||
- hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
- rp.instance = 0x01;
+ hci_dev_test_flag(hdev, HCI_LE_ADV)) {
+ rp.instance = cp->instance;
err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
goto unlock;
--
1.9.1


2015-05-24 22:39:10

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v5 12/16] Bluetooth: mgmt: multi adv for set_advertising_complete()

The set_advertising_complete() method relied on the now obsolete
hci_dev->adv_instance structure. We replace this reference by an
equivalent access to the newly introduced dynamic advertising instance
list.

This solution still relies on the fact that we only allow a single
advertising instance for now. It needs to be further refactored once we
allow more than one advertising instance. A corresponding TODO has been
inserted in the code to make this clear.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 3d09cb9..1bdf005 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -4673,6 +4673,7 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status,
{
struct cmd_lookup match = { NULL, hdev };
struct hci_request req;
+ struct adv_info *adv_instance;

hci_dev_lock(hdev);

@@ -4698,14 +4699,26 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status,
sock_put(match.sk);

/* If "Set Advertising" was just disabled and instance advertising was
- * set up earlier, then enable the advertising instance.
+ * set up earlier, then re-enable multi-instance advertising.
*/
if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
- !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
+ !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) ||
+ &hdev->adv_instance_cnt == 0)
goto unlock;

- hci_req_init(&req, hdev);
+ /* We advertise multiple instances in a round robin fashion starting
+ * with the first instance in the list.
+ */
+ /* TODO: Make sure the other instances are actually being advertised
+ * once we set HCI_MAX_ADV_INSTANCES > 1.
+ */
+ adv_instance = list_first_entry(&hdev->adv_instances, struct adv_info,
+ list);
+ if (!adv_instance)
+ goto unlock;

+ hci_req_init(&req, hdev);
+ hdev->cur_adv_instance = adv_instance->instance;
update_adv_data(&req);
enable_advertising(&req);

--
1.9.1


2015-05-24 22:39:09

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v5 11/16] Bluetooth: mgmt: refactor update_*_data()

The update_*_data_for_instance() methods are no longer being referenced
anywhere in the code. To reduce complexity and improve readability,
these methods are being joined with their corresponding update_*_data()
counterparts.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 27 ++++++---------------------
1 file changed, 6 insertions(+), 21 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index e999bbb..3d09cb9 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -890,18 +890,18 @@ static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 instance,
return adv_instance->scan_rsp_len;
}

-static void update_scan_rsp_data_for_instance(struct hci_request *req,
- u8 instance)
+static void update_scan_rsp_data(struct hci_request *req)
{
struct hci_dev *hdev = req->hdev;
struct hci_cp_le_set_scan_rsp_data cp;
- u8 len;
+ u8 instance, len;

if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
return;

memset(&cp, 0, sizeof(cp));

+ instance = get_current_adv_instance(hdev);
if (instance)
len = create_instance_scan_rsp_data(hdev, instance, cp.data);
else
@@ -919,14 +919,6 @@ static void update_scan_rsp_data_for_instance(struct hci_request *req,
hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
}

-static void update_scan_rsp_data(struct hci_request *req)
-{
- struct hci_dev *hdev = req->hdev;
- u8 instance = get_current_adv_instance(hdev);
-
- update_scan_rsp_data_for_instance(req, instance);
-}
-
static u8 get_adv_discov_flags(struct hci_dev *hdev)
{
struct mgmt_pending_cmd *cmd;
@@ -1084,17 +1076,18 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
return ad_len;
}

-static void update_adv_data_for_instance(struct hci_request *req, u8 instance)
+static void update_adv_data(struct hci_request *req)
{
struct hci_dev *hdev = req->hdev;
struct hci_cp_le_set_adv_data cp;
- u8 len;
+ u8 instance, len;

if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
return;

memset(&cp, 0, sizeof(cp));

+ instance = get_current_adv_instance(hdev);
len = create_instance_adv_data(hdev, instance, cp.data);

/* There's nothing to do if the data hasn't changed */
@@ -1110,14 +1103,6 @@ static void update_adv_data_for_instance(struct hci_request *req, u8 instance)
hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
}

-static void update_adv_data(struct hci_request *req)
-{
- struct hci_dev *hdev = req->hdev;
- u8 instance = get_current_adv_instance(hdev);
-
- update_adv_data_for_instance(req, instance);
-}
-
int mgmt_update_adv_data(struct hci_dev *hdev)
{
struct hci_request req;
--
1.9.1


2015-05-24 22:39:08

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v5 10/16] Bluetooth: mgmt: multi adv for create_instance_adv_data()

The create_instance_adv_data() function could not deal with
multiple advertising instances previously. This is being fixed by
retrieving advertising instances from the newly introduced dynamic
advertising instance list.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 23 ++++++++++++++++-------
1 file changed, 16 insertions(+), 7 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 8913739..e999bbb 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1018,8 +1018,18 @@ static u8 get_cur_adv_instance_scan_rsp_len(struct hci_dev *hdev)

static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
{
+ struct adv_info *adv_instance = NULL;
u8 ad_len = 0, flags = 0;
- u32 instance_flags = get_adv_instance_flags(hdev, instance);
+ u32 instance_flags;
+
+ /* Return 0 when the current instance identifier is invalid. */
+ if (instance) {
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (!adv_instance)
+ return 0;
+ }
+
+ instance_flags = get_adv_instance_flags(hdev, instance);

/* The Add Advertising command allows userspace to set both the general
* and limited discoverable flags.
@@ -1053,12 +1063,11 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
}
}

- if (instance) {
- memcpy(ptr, hdev->adv_instance.adv_data,
- hdev->adv_instance.adv_data_len);
-
- ad_len += hdev->adv_instance.adv_data_len;
- ptr += hdev->adv_instance.adv_data_len;
+ if (adv_instance) {
+ memcpy(ptr, adv_instance->adv_data,
+ adv_instance->adv_data_len);
+ ad_len += adv_instance->adv_data_len;
+ ptr += adv_instance->adv_data_len;
}

/* Provide Tx Power only if we can provide a valid value for it */
--
1.9.1


2015-05-24 22:39:07

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v5 09/16] Bluetooth: mgmt: multi adv for create_instance_scan_rsp_data()

The create_instance_scan_rsp_data() function could not deal with
multiple advertising instances previously. This is being fixed by adding
an additional instance parameter.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 65c1e51..8913739 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -872,15 +872,22 @@ static u8 create_default_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
return ad_len;
}

-static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
+static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 instance,
+ u8 *ptr)
{
+ struct adv_info *adv_instance;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (!adv_instance)
+ return 0;
+
/* TODO: Set the appropriate entries based on advertising instance flags
* here once flags other than 0 are supported.
*/
- memcpy(ptr, hdev->adv_instance.scan_rsp_data,
- hdev->adv_instance.scan_rsp_len);
+ memcpy(ptr, adv_instance->scan_rsp_data,
+ adv_instance->scan_rsp_len);

- return hdev->adv_instance.scan_rsp_len;
+ return adv_instance->scan_rsp_len;
}

static void update_scan_rsp_data_for_instance(struct hci_request *req,
@@ -896,7 +903,7 @@ static void update_scan_rsp_data_for_instance(struct hci_request *req,
memset(&cp, 0, sizeof(cp));

if (instance)
- len = create_instance_scan_rsp_data(hdev, cp.data);
+ len = create_instance_scan_rsp_data(hdev, instance, cp.data);
else
len = create_default_scan_rsp_data(hdev, cp.data);

--
1.9.1


2015-05-24 22:39:06

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v5 08/16] Bluetooth: mgmt: use current adv instance in set_advertising()

The set_advertising() method needs to update the newly introduced
cur_adv_instance member of the hci device. This also allows us to remove
the last remaining references to the ..._for_instance... versions of
the adv data and scan response update functions.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 94b49ed..65c1e51 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -4795,8 +4795,9 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,

if (val) {
/* Switch to instance "0" for the Set Advertising setting. */
- update_adv_data_for_instance(&req, 0);
- update_scan_rsp_data_for_instance(&req, 0);
+ hdev->cur_adv_instance = 0x00;
+ update_adv_data(&req);
+ update_scan_rsp_data(&req);
enable_advertising(&req);
} else {
disable_advertising(&req);
--
1.9.1


2015-05-24 22:39:05

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v5 07/16] Bluetooth: mgmt: multi adv for enable_advertising()

Previously enable_advertising() would rely on
get_adv_instance_scan_rsp_len() which checked for a hard coded instance
identifier. This is being changed to check for the current advertising
instance's scan response length instead. The function is renamed
accordingly.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 80dd5db..94b49ed 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -990,16 +990,23 @@ static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance)
return adv_instance->flags;
}

-static u8 get_adv_instance_scan_rsp_len(struct hci_dev *hdev, u8 instance)
+static u8 get_cur_adv_instance_scan_rsp_len(struct hci_dev *hdev)
{
- /* Ignore instance 0 and other unsupported instances */
- if (instance != 0x01)
+ u8 instance = get_current_adv_instance(hdev);
+ struct adv_info *adv_instance;
+
+ /* Ignore instance 0 */
+ if (instance == 0x00)
+ return 0;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (!adv_instance)
return 0;

/* TODO: Take into account the "appearance" and "local-name" flags here.
* These are currently being ignored as they are not supported.
*/
- return hdev->adv_instance.scan_rsp_len;
+ return adv_instance->scan_rsp_len;
}

static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
@@ -1273,7 +1280,7 @@ static void enable_advertising(struct hci_request *req)

if (connectable)
cp.type = LE_ADV_IND;
- else if (get_adv_instance_scan_rsp_len(hdev, instance))
+ else if (get_cur_adv_instance_scan_rsp_len(hdev))
cp.type = LE_ADV_SCAN_IND;
else
cp.type = LE_ADV_NONCONN_IND;
--
1.9.1


2015-05-24 22:39:04

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v5 06/16] Bluetooth: mgmt: improve get_adv_instance_flags() readability

Switch if and else conditions to replace a negative statement by a
positive one which makes the condition more readable.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 30 ++++++++++++++++--------------
1 file changed, 16 insertions(+), 14 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 5a531fd5..80dd5db 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -966,26 +966,28 @@ static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance)
u32 flags;
struct adv_info *adv_instance;

- if (instance != 0x00) {
- adv_instance = hci_find_adv_instance(hdev, instance);
+ if (instance == 0x00) {
+ /* Instance 0 always manages the "Tx Power" and "Flags"
+ * fields
+ */
+ flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS;

- /* Return 0 when we got an invalid instance identifier. */
- if (!adv_instance)
- return 0;
+ /* For instance 0, the HCI_ADVERTISING_CONNECTABLE setting
+ * corresponds to the "connectable" instance flag.
+ */
+ if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
+ flags |= MGMT_ADV_FLAG_CONNECTABLE;

- return adv_instance->flags;
+ return flags;
}

- /* Instance 0 always manages the "Tx Power" and "Flags" fields */
- flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS;
+ adv_instance = hci_find_adv_instance(hdev, instance);

- /* For instance 0, the HCI_ADVERTISING_CONNECTABLE setting corresponds
- * to the "connectable" instance flag.
- */
- if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
- flags |= MGMT_ADV_FLAG_CONNECTABLE;
+ /* Return 0 when we got an invalid instance identifier. */
+ if (!adv_instance)
+ return 0;

- return flags;
+ return adv_instance->flags;
}

static u8 get_adv_instance_scan_rsp_len(struct hci_dev *hdev, u8 instance)
--
1.9.1


2015-05-24 22:39:03

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v5 05/16] Bluetooth: mgmt: multi adv for get_adv_instance_flags()

The get_adv_instance_flags() would not work with instance identifiers
other than 0x01. This is being fixed so that arbitrary instance
identifiers can be dealt with while still correctly dealing with the
special case of the 0x00 identifier.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index c28bb2d..5a531fd5 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -964,12 +964,17 @@ static bool get_connectable(struct hci_dev *hdev)
static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance)
{
u32 flags;
+ struct adv_info *adv_instance;

- if (instance > 0x01)
- return 0;
+ if (instance != 0x00) {
+ adv_instance = hci_find_adv_instance(hdev, instance);

- if (instance == 0x01)
- return hdev->adv_instance.flags;
+ /* Return 0 when we got an invalid instance identifier. */
+ if (!adv_instance)
+ return 0;
+
+ return adv_instance->flags;
+ }

/* Instance 0 always manages the "Tx Power" and "Flags" fields */
flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS;
--
1.9.1


2015-05-24 22:39:02

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v5 04/16] Bluetooth: mgmt: multi adv for get_current_adv_instance()

Replaces the hard coded instance identifier in
get_current_adv_instance() with the actual current instance identifier
so that this method is prepared to work with more than one advertising
instance.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 9f5ac26..c28bb2d 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -841,7 +841,7 @@ static u8 get_current_adv_instance(struct hci_dev *hdev)
*/
if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
!hci_dev_test_flag(hdev, HCI_ADVERTISING))
- return 0x01;
+ return hdev->cur_adv_instance;

return 0x00;
}
--
1.9.1


2015-05-24 22:38:59

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v5 01/16] Bluetooth: hci_core: Introduce multi-adv inst list

The current hci dev structure only supports a single advertising
instance. To support multi-instance advertising it is necessary to
introduce a linked list of advertising instances so that multiple
advertising instances can be dynamically added and/or removed.

In a first step, the existing adv_instance member of the hci_dev
struct is supplemented by a linked list of advertising instances.
This patch introduces the list and supporting list management
infrastructure. The list is not being used yet.

Signed-off-by: Florian Grandel <[email protected]>
---
include/net/bluetooth/hci_core.h | 15 ++++++
net/bluetooth/hci_core.c | 111 +++++++++++++++++++++++++++++++++++++++
net/bluetooth/mgmt.c | 10 ++--
3 files changed, 131 insertions(+), 5 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index a056c2b..d92d324 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -156,6 +156,8 @@ struct oob_data {
};

struct adv_info {
+ struct list_head list;
+ struct hci_dev *hdev;
struct delayed_work timeout_exp;
__u8 instance;
__u32 flags;
@@ -166,6 +168,8 @@ struct adv_info {
__u8 scan_rsp_data[HCI_MAX_AD_LENGTH];
};

+#define HCI_MAX_ADV_INSTANCES 1
+
#define HCI_MAX_SHORT_NAME_LENGTH 10

/* Default LE RPA expiry time, 15 minutes */
@@ -374,6 +378,9 @@ struct hci_dev {
__u8 scan_rsp_data_len;

struct adv_info adv_instance;
+ struct list_head adv_instances;
+ unsigned int adv_instance_cnt;
+ __u8 cur_adv_instance;

__u8 irk[16];
__u32 rpa_timeout;
@@ -1007,6 +1014,14 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 bdaddr_type);

+void hci_adv_instances_clear(struct hci_dev *hdev);
+struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance);
+int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
+ u16 adv_data_len, u8 *adv_data,
+ u16 scan_rsp_len, u8 *scan_rsp_data,
+ work_func_t timeout_work, u16 timeout);
+int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance);
+
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);

int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index db11b9d..1ec557f 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2609,6 +2609,113 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
return 0;
}

+/* This function requires the caller holds hdev->lock */
+struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance)
+{
+ struct adv_info *adv_instance;
+
+ list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
+ if (adv_instance->instance == instance)
+ return adv_instance;
+ }
+
+ return NULL;
+}
+
+/* This function requires the caller holds hdev->lock */
+int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance)
+{
+ struct adv_info *adv_instance;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (!adv_instance)
+ return -ENOENT;
+
+ BT_DBG("%s removing %dMR", hdev->name, instance);
+
+ if (adv_instance->timeout)
+ cancel_delayed_work(&adv_instance->timeout_exp);
+
+ list_del(&adv_instance->list);
+ kfree(adv_instance);
+
+ hdev->adv_instance_cnt--;
+
+ return 0;
+}
+
+/* This function requires the caller holds hdev->lock */
+void hci_adv_instances_clear(struct hci_dev *hdev)
+{
+ struct adv_info *adv_instance, *n;
+
+ list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
+ if (adv_instance->timeout)
+ cancel_delayed_work(&adv_instance->timeout_exp);
+
+ list_del(&adv_instance->list);
+ kfree(adv_instance);
+ }
+
+ hdev->adv_instance_cnt = 0;
+}
+
+/* This function requires the caller holds hdev->lock */
+int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
+ u16 adv_data_len, u8 *adv_data,
+ u16 scan_rsp_len, u8 *scan_rsp_data,
+ work_func_t timeout_work, u16 timeout)
+{
+ struct adv_info *adv_instance;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (adv_instance) {
+ if (adv_instance->timeout)
+ cancel_delayed_work(&adv_instance->timeout_exp);
+
+ memset(adv_instance->adv_data, 0,
+ sizeof(adv_instance->adv_data));
+ memset(adv_instance->scan_rsp_data, 0,
+ sizeof(adv_instance->scan_rsp_data));
+ } else {
+ if (hdev->adv_instance_cnt >= HCI_MAX_ADV_INSTANCES)
+ return -EOVERFLOW;
+
+ adv_instance = kmalloc(sizeof(*adv_instance), GFP_KERNEL);
+ if (!adv_instance)
+ return -ENOMEM;
+
+ memset(adv_instance, 0, sizeof(*adv_instance));
+ adv_instance->hdev = hdev;
+ INIT_DELAYED_WORK(&adv_instance->timeout_exp, timeout_work);
+ adv_instance->instance = instance;
+ list_add(&adv_instance->list, &hdev->adv_instances);
+ hdev->adv_instance_cnt++;
+ }
+
+ adv_instance->flags = flags;
+ adv_instance->adv_data_len = adv_data_len;
+ adv_instance->scan_rsp_len = scan_rsp_len;
+
+ if (adv_data_len)
+ memcpy(adv_instance->adv_data, adv_data, adv_data_len);
+
+ if (scan_rsp_len)
+ memcpy(adv_instance->scan_rsp_data,
+ scan_rsp_data, scan_rsp_len);
+
+ adv_instance->timeout = timeout;
+
+ if (timeout)
+ queue_delayed_work(hdev->workqueue,
+ &adv_instance->timeout_exp,
+ msecs_to_jiffies(timeout * 1000));
+
+ BT_DBG("%s for %dMR", hdev->name, instance);
+
+ return 0;
+}
+
struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *bdaddr_list,
bdaddr_t *bdaddr, u8 type)
{
@@ -3012,6 +3119,8 @@ struct hci_dev *hci_alloc_dev(void)
hdev->manufacturer = 0xffff; /* Default to internal use */
hdev->inq_tx_power = HCI_TX_POWER_INVALID;
hdev->adv_tx_power = HCI_TX_POWER_INVALID;
+ hdev->adv_instance_cnt = 0;
+ hdev->cur_adv_instance = 0x00;

hdev->sniff_max_interval = 800;
hdev->sniff_min_interval = 80;
@@ -3053,6 +3162,7 @@ struct hci_dev *hci_alloc_dev(void)
INIT_LIST_HEAD(&hdev->pend_le_conns);
INIT_LIST_HEAD(&hdev->pend_le_reports);
INIT_LIST_HEAD(&hdev->conn_hash.list);
+ INIT_LIST_HEAD(&hdev->adv_instances);

INIT_WORK(&hdev->rx_work, hci_rx_work);
INIT_WORK(&hdev->cmd_work, hci_cmd_work);
@@ -3246,6 +3356,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
hci_smp_ltks_clear(hdev);
hci_smp_irks_clear(hdev);
hci_remote_oob_data_clear(hdev);
+ hci_adv_instances_clear(hdev);
hci_bdaddr_list_clear(&hdev->le_white_list);
hci_conn_params_clear_all(hdev);
hci_discovery_filter_clear(hdev);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 7fd87e7..ce25b6d 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -6813,7 +6813,7 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
rp->supported_flags = cpu_to_le32(supported_flags);
rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
- rp->max_instances = 1;
+ rp->max_instances = HCI_MAX_ADV_INSTANCES;

/* Currently only one instance is supported, so simply return the
* current instance number.
@@ -6916,11 +6916,11 @@ unlock:

static void adv_timeout_expired(struct work_struct *work)
{
- struct hci_dev *hdev = container_of(work, struct hci_dev,
- adv_instance.timeout_exp.work);
-
- hdev->adv_instance.timeout = 0;
+ struct adv_info *adv_instance = container_of(work, struct adv_info,
+ timeout_exp.work);
+ struct hci_dev *hdev = adv_instance->hdev;

+ adv_instance->timeout = 0;
hci_dev_lock(hdev);
clear_adv_instance(hdev);
hci_dev_unlock(hdev);
--
1.9.1


2015-05-24 22:39:01

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v5 03/16] Bluetooth: mgmt: multi adv for read_adv_features()

The read_adv_features() method had a single instance identifier hard
coded. Refer to the advertising instance list instead to return a
dynamically generated list of instance identifiers.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 22 ++++++++++++----------
1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 9dc4905..9f5ac26 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -6770,8 +6770,9 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
{
struct mgmt_rp_read_adv_features *rp;
size_t rp_len;
- int err;
+ int err, i;
bool instance;
+ struct adv_info *adv_instance;
u32 supported_flags;

BT_DBG("%s", hdev->name);
@@ -6784,12 +6785,9 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,

rp_len = sizeof(*rp);

- /* Currently only one instance is supported, so just add 1 to the
- * response length.
- */
instance = hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE);
if (instance)
- rp_len++;
+ rp_len += hdev->adv_instance_cnt;

rp = kmalloc(rp_len, GFP_ATOMIC);
if (!rp) {
@@ -6804,12 +6802,16 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
rp->max_instances = HCI_MAX_ADV_INSTANCES;

- /* Currently only one instance is supported, so simply return the
- * current instance number.
- */
if (instance) {
- rp->num_instances = 1;
- rp->instance[0] = 1;
+ i = 0;
+ list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
+ if (i >= hdev->adv_instance_cnt)
+ break;
+
+ rp->instance[i] = adv_instance->instance;
+ i++;
+ }
+ rp->num_instances = hdev->adv_instance_cnt;
} else {
rp->num_instances = 0;
}
--
1.9.1


2015-05-24 22:39:00

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v5 02/16] Bluetooth: mgmt: dry update_scan_rsp_data()

update_scan_rsp_data() duplicates code from get_current_adv_instance().
This is being fixed by letting the former make use of the latter.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 41 +++++++++++++++--------------------------
1 file changed, 15 insertions(+), 26 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index ce25b6d..9dc4905 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -832,6 +832,20 @@ static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
}

+static u8 get_current_adv_instance(struct hci_dev *hdev)
+{
+ /* The "Set Advertising" setting supersedes the "Add Advertising"
+ * setting. Here we set the advertising data based on which
+ * setting was set. When neither apply, default to the global settings,
+ * represented by instance "0".
+ */
+ if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
+ !hci_dev_test_flag(hdev, HCI_ADVERTISING))
+ return 0x01;
+
+ return 0x00;
+}
+
static u8 create_default_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
{
u8 ad_len = 0;
@@ -901,18 +915,7 @@ static void update_scan_rsp_data_for_instance(struct hci_request *req,
static void update_scan_rsp_data(struct hci_request *req)
{
struct hci_dev *hdev = req->hdev;
- u8 instance;
-
- /* The "Set Advertising" setting supersedes the "Add Advertising"
- * setting. Here we set the scan response data based on which
- * setting was set. When neither apply, default to the global settings,
- * represented by instance "0".
- */
- if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
- !hci_dev_test_flag(hdev, HCI_ADVERTISING))
- instance = 0x01;
- else
- instance = 0x00;
+ u8 instance = get_current_adv_instance(hdev);

update_scan_rsp_data_for_instance(req, instance);
}
@@ -941,20 +944,6 @@ static u8 get_adv_discov_flags(struct hci_dev *hdev)
return 0;
}

-static u8 get_current_adv_instance(struct hci_dev *hdev)
-{
- /* The "Set Advertising" setting supersedes the "Add Advertising"
- * setting. Here we set the advertising data based on which
- * setting was set. When neither apply, default to the global settings,
- * represented by instance "0".
- */
- if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
- !hci_dev_test_flag(hdev, HCI_ADVERTISING))
- return 0x01;
-
- return 0x00;
-}
-
static bool get_connectable(struct hci_dev *hdev)
{
struct mgmt_pending_cmd *cmd;
--
1.9.1


2015-05-24 22:38:58

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v5 00/16] Bluetooth: Multi-advertising infrastructure

patch set introducing the infrastructure for multi-advertising
capability to the HCI core and mgmt API.

v1 -> v2:
- add missing braces in read_adv_features()

v2 -> v3:
- split change-set into several patches
- replace err == 0 by !err
- fix coding style problems

v3 -> v4:
publicly visible change:
- when calling remove_advertising with an instance value of zero (i.e.
remove all instances), the command response also returns an instance
value of zero now as it doesn't make sense to return a single instance
id when removing several instances

refactoring and fixes (due to Arman's review):
- splitting the change set into a much larger number of patches to
facilitate review
- use HCI_MAX_ADV_INSTANCES in the same patch that introduces it
- use adv_info->hdev in the same patch that introduces it
- make the logic of hci_find_adv_instance() more readable
- make sure that hci_find_adv_instance() is called while hci_dev is
locked
- replace hci_num_adv_instances() by an instance counter in hci_dev
- add inline comment in get_adv_instance_flags() explaining its return
value in the error case
- generate zero-length adv data if the current instance identifier is
invalid
- revert erroneous changes to the logic in clear_adv_instance()
- use hci_adv_instances_clear() in clear_adv_instance() when removing
all advertising instances also removing a reduntant error check
- inserting TODO messages to make sure that advertising will not be
switched off prematurely once we allow more than one advertising
instance
- inserting TODO messages to make sure that multiple advertising
instances will be advertised in a round-robin fashion once we allow
for more than one advertising instance
- identify peding advertising instances (just added but not yet
confirmed in add_advertising_complete) by a boolean flag in the
adv_info struct so that we can identify and remove them even when
the pending add_advertising command cannot be retrieved for some
reason - makes sure that we do not leak advertising instances in this
case
- only send HCI commands to update advertising data when a new instance
has actually been added

v4 -> v5 (fixes due to Marcel's review):
- split into separate change sets for kernel and userspace
- do not trust the adv instance list length when compiling the adv features
struct
- introduce adv_info->pending in the same patch it's used for the first time


Florian Grandel (16):
Bluetooth: hci_core: Introduce multi-adv inst list
Bluetooth: mgmt: dry update_scan_rsp_data()
Bluetooth: mgmt: multi adv for read_adv_features()
Bluetooth: mgmt: multi adv for get_current_adv_instance()
Bluetooth: mgmt: multi adv for get_adv_instance_flags()
Bluetooth: mgmt: improve get_adv_instance_flags() readability
Bluetooth: mgmt: multi adv for enable_advertising()
Bluetooth: mgmt: use current adv instance in set_advertising()
Bluetooth: mgmt: multi adv for create_instance_scan_rsp_data()
Bluetooth: mgmt: multi adv for create_instance_adv_data()
Bluetooth: mgmt: refactor update_*_data()
Bluetooth: mgmt: multi adv for set_advertising_complete()
Bluetooth: mgmt: multi adv for add_advertising()
Bluetooth: mgmt: multi adv for clear_adv_instances()
Bluetooth: mgmt: multi adv for remove_advertising()
Bluetooth: hci_core: remove obsolete adv_instance

include/net/bluetooth/hci_core.h | 22 ++-
net/bluetooth/hci_core.c | 113 ++++++++++++-
net/bluetooth/mgmt.c | 353 ++++++++++++++++++++++-----------------
3 files changed, 331 insertions(+), 157 deletions(-)

--
1.9.1


2015-05-24 21:50:06

by Florian Grandel

[permalink] [raw]
Subject: Re: [PATCH v4 02/17] Bluetooth: hci_core: Introduce multi-adv inst list

Hi Marcel,

thanks for reviewing my patches!

On 05/23/2015 11:25 PM, Marcel Holtmann wrote:
> Hi Florian,
>
>> The current hci dev structure only supports a single advertising
>> instance. To support multi-instance advertising it is necessary to
>> introduce a linked list of advertising instances so that multiple
>> advertising instances can be dynamically added and/or removed.
>>
>> In a first step, the existing adv_instance member of the hci_dev
>> struct is supplemented by a linked list of advertising instances.
>> This patch introduces the list and supporting list management
>> infrastructure. The list is not being used yet.
>>
>> Signed-off-by: Florian Grandel <[email protected]>
>> ---
>> include/net/bluetooth/hci_core.h | 16 ++++++
>> net/bluetooth/hci_core.c | 112 +++++++++++++++++++++++++++++++++++++++
>> net/bluetooth/mgmt.c | 10 ++--
>> 3 files changed, 133 insertions(+), 5 deletions(-)
>
> I dislike you intermixing userspace with kernel space patches. That makes it so hard to review. Keep them separate.

Ok, I'll provide two separate patch sets instead.

>> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
>> index a056c2b..36cc941 100644
>> --- a/include/net/bluetooth/hci_core.h
>> +++ b/include/net/bluetooth/hci_core.h
>> @@ -156,6 +156,9 @@ struct oob_data {
>> };
>>
>> struct adv_info {
>> + struct list_head list;
>> + struct hci_dev *hdev;
>
> Why is the a copy of hci_dev needed here?

We need this copy of hdev in adv_timeout_expired() - see further down in
this patch.

Arman and I had a discussion about this on the list - and this was the
solution we came up with. I'll forward you the thread so you don't have
to search through the archives.

>> + bool pending;
>
> What is this pending for. I do not see it being used in this patch.

It's required to make sure that we do not leak advertising instances
when they have just been created but for some reason the
add_advertising_complete() command encounters an error status. I'll move
the introduction of the variable to the patch where it's actually being
used to make it easier for you to review that part. In any case the
function to look at is add_advertising_complete().

>> struct delayed_work timeout_exp;
>> __u8 instance;
>> __u32 flags;
>> @@ -166,6 +169,8 @@ struct adv_info {
>> __u8 scan_rsp_data[HCI_MAX_AD_LENGTH];
>> };
>>
>> +#define HCI_MAX_ADV_INSTANCES 1
>> +
>> #define HCI_MAX_SHORT_NAME_LENGTH 10
>>
>> /* Default LE RPA expiry time, 15 minutes */
>> @@ -374,6 +379,9 @@ struct hci_dev {
>> __u8 scan_rsp_data_len;
>>
>> struct adv_info adv_instance;
>> + struct list_head adv_instances;
>> + unsigned int adv_instance_cnt;
>> + __u8 cur_adv_instance;
>>
>> __u8 irk[16];
>> __u32 rpa_timeout;
>> @@ -1007,6 +1015,14 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
>> int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
>> u8 bdaddr_type);
>>
>> +void hci_adv_instances_clear(struct hci_dev *hdev);
>> +struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance);
>> +int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
>> + u16 adv_data_len, u8 *adv_data,
>> + u16 scan_rsp_len, u8 *scan_rsp_data,
>> + work_func_t timeout_work, u16 timeout);
>> +int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance);
>> +
>> void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
>>
>> int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb);
>> diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
>> index 476709b..de00e21 100644
>> --- a/net/bluetooth/hci_core.c
>> +++ b/net/bluetooth/hci_core.c
>> @@ -2613,6 +2613,114 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
>> return 0;
>> }
>>
>> +/* This function requires the caller holds hdev->lock */
>> +struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance)
>> +{
>> + struct adv_info *adv_instance;
>> +
>> + list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
>> + if (adv_instance->instance == instance)
>> + return adv_instance;
>> + }
>> +
>> + return NULL;
>> +}
>> +
>> +/* This function requires the caller holds hdev->lock */
>> +int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance)
>> +{
>> + struct adv_info *adv_instance;
>> +
>> + adv_instance = hci_find_adv_instance(hdev, instance);
>> + if (!adv_instance)
>> + return -ENOENT;
>> +
>> + BT_DBG("%s removing %dMR", hdev->name, instance);
>> +
>> + if (adv_instance->timeout)
>> + cancel_delayed_work(&adv_instance->timeout_exp);
>> +
>> + list_del(&adv_instance->list);
>> + kfree(adv_instance);
>> +
>> + hdev->adv_instance_cnt--;
>> +
>> + return 0;
>> +}
>> +
>> +/* This function requires the caller holds hdev->lock */
>> +void hci_adv_instances_clear(struct hci_dev *hdev)
>> +{
>> + struct adv_info *adv_instance, *n;
>> +
>> + list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
>> + if (adv_instance->timeout)
>> + cancel_delayed_work(&adv_instance->timeout_exp);
>> +
>> + list_del(&adv_instance->list);
>> + kfree(adv_instance);
>> + }
>> +
>> + hdev->adv_instance_cnt = 0;
>> +}
>> +
>> +/* This function requires the caller holds hdev->lock */
>> +int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
>> + u16 adv_data_len, u8 *adv_data,
>> + u16 scan_rsp_len, u8 *scan_rsp_data,
>> + work_func_t timeout_work, u16 timeout)
>> +{
>> + struct adv_info *adv_instance;
>> +
>> + adv_instance = hci_find_adv_instance(hdev, instance);
>> + if (adv_instance) {
>> + if (adv_instance->timeout)
>> + cancel_delayed_work(&adv_instance->timeout_exp);
>> +
>> + memset(adv_instance->adv_data, 0,
>> + sizeof(adv_instance->adv_data));
>> + memset(adv_instance->scan_rsp_data, 0,
>> + sizeof(adv_instance->scan_rsp_data));
>> + } else {
>> + if (hdev->adv_instance_cnt >= HCI_MAX_ADV_INSTANCES)
>> + return -EOVERFLOW;
>> +
>> + adv_instance = kmalloc(sizeof(*adv_instance), GFP_KERNEL);
>> + if (!adv_instance)
>> + return -ENOMEM;
>> +
>> + memset(adv_instance, 0, sizeof(*adv_instance));
>> + adv_instance->hdev = hdev;
>> + adv_instance->pending = true;
>> + INIT_DELAYED_WORK(&adv_instance->timeout_exp, timeout_work);
>> + adv_instance->instance = instance;
>> + list_add(&adv_instance->list, &hdev->adv_instances);
>> + hdev->adv_instance_cnt++;
>> + }
>> +
>> + adv_instance->flags = flags;
>> + adv_instance->adv_data_len = adv_data_len;
>> + adv_instance->scan_rsp_len = scan_rsp_len;
>> +
>> + if (adv_data_len)
>> + memcpy(adv_instance->adv_data, adv_data, adv_data_len);
>> +
>> + if (scan_rsp_len)
>> + memcpy(adv_instance->scan_rsp_data,
>> + scan_rsp_data, scan_rsp_len);
>> +
>> + adv_instance->timeout = timeout;
>> +
>> + if (timeout)
>> + queue_delayed_work(hdev->workqueue,
>> + &adv_instance->timeout_exp,
>> + msecs_to_jiffies(timeout * 1000));
>> +
>> + BT_DBG("%s for %dMR", hdev->name, instance);
>> +
>> + return 0;
>> +}
>> +
>> struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *bdaddr_list,
>> bdaddr_t *bdaddr, u8 type)
>> {
>> @@ -3016,6 +3124,8 @@ struct hci_dev *hci_alloc_dev(void)
>> hdev->manufacturer = 0xffff; /* Default to internal use */
>> hdev->inq_tx_power = HCI_TX_POWER_INVALID;
>> hdev->adv_tx_power = HCI_TX_POWER_INVALID;
>> + hdev->adv_instance_cnt = 0;
>> + hdev->cur_adv_instance = 0x00;
>>
>> hdev->sniff_max_interval = 800;
>> hdev->sniff_min_interval = 80;
>> @@ -3057,6 +3167,7 @@ struct hci_dev *hci_alloc_dev(void)
>> INIT_LIST_HEAD(&hdev->pend_le_conns);
>> INIT_LIST_HEAD(&hdev->pend_le_reports);
>> INIT_LIST_HEAD(&hdev->conn_hash.list);
>> + INIT_LIST_HEAD(&hdev->adv_instances);
>>
>> INIT_WORK(&hdev->rx_work, hci_rx_work);
>> INIT_WORK(&hdev->cmd_work, hci_cmd_work);
>> @@ -3250,6 +3361,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
>> hci_smp_ltks_clear(hdev);
>> hci_smp_irks_clear(hdev);
>> hci_remote_oob_data_clear(hdev);
>> + hci_adv_instances_clear(hdev);
>> hci_bdaddr_list_clear(&hdev->le_white_list);
>> hci_conn_params_clear_all(hdev);
>> hci_discovery_filter_clear(hdev);
>> diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
>> index 7fd87e7..ce25b6d 100644
>> --- a/net/bluetooth/mgmt.c
>> +++ b/net/bluetooth/mgmt.c
>> @@ -6813,7 +6813,7 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
>> rp->supported_flags = cpu_to_le32(supported_flags);
>> rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
>> rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
>> - rp->max_instances = 1;
>> + rp->max_instances = HCI_MAX_ADV_INSTANCES;
>>
>> /* Currently only one instance is supported, so simply return the
>> * current instance number.
>> @@ -6916,11 +6916,11 @@ unlock:
>>
>> static void adv_timeout_expired(struct work_struct *work)
>> {
>> - struct hci_dev *hdev = container_of(work, struct hci_dev,
>> - adv_instance.timeout_exp.work);
>> -
>> - hdev->adv_instance.timeout = 0;
>> + struct adv_info *adv_instance = container_of(work, struct adv_info,
>> + timeout_exp.work);
>> + struct hci_dev *hdev = adv_instance->hdev;
>>
>> + adv_instance->timeout = 0;
>> hci_dev_lock(hdev);
>> clear_adv_instance(hdev);
>> hci_dev_unlock(hdev);
>
> Regards
>
> Marcel
>
>

Cheers!

Florian

2015-05-23 21:25:58

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH v4 04/17] Bluetooth: mgmt: multi adv for read_adv_features()

Hi Florian,

> The read_adv_features() method had a single instance identifier hard
> coded. Refer to the advertising instance list instead to return a
> dynamically generated list of instance identifiers.
>
> Signed-off-by: Florian Grandel <[email protected]>
> ---
> net/bluetooth/mgmt.c | 21 +++++++++------------
> 1 file changed, 9 insertions(+), 12 deletions(-)
>
> diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
> index 9dc4905..55ab2a3 100644
> --- a/net/bluetooth/mgmt.c
> +++ b/net/bluetooth/mgmt.c
> @@ -6770,8 +6770,9 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
> {
> struct mgmt_rp_read_adv_features *rp;
> size_t rp_len;
> - int err;
> + int err, i;
> bool instance;
> + struct adv_info *adv_instance;
> u32 supported_flags;
>
> BT_DBG("%s", hdev->name);
> @@ -6784,12 +6785,9 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
>
> rp_len = sizeof(*rp);
>
> - /* Currently only one instance is supported, so just add 1 to the
> - * response length.
> - */
> instance = hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE);
> if (instance)
> - rp_len++;
> + rp_len += hdev->adv_instance_cnt;
>
> rp = kmalloc(rp_len, GFP_ATOMIC);
> if (!rp) {
> @@ -6803,15 +6801,14 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
> rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
> rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
> rp->max_instances = HCI_MAX_ADV_INSTANCES;
> + rp->num_instances = hdev->adv_instance_cnt;
>
> - /* Currently only one instance is supported, so simply return the
> - * current instance number.
> - */
> if (instance) {
> - rp->num_instances = 1;
> - rp->instance[0] = 1;
> - } else {
> - rp->num_instances = 0;
> + i = 0;
> + list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
> + rp->instance[i] = adv_instance->instance;
> + i++;
> + }

I would really prefer that we leave this logic in place. When !instance, then keep returning rp->num_instances = 0 and in the other case set it to hdev->adv_instance_cnt. I would also prefer that the list is really limited by adv_instance_cnt and not blindly trusted that the list size is the same.

Regards

Marcel


2015-05-23 21:25:57

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH v4 02/17] Bluetooth: hci_core: Introduce multi-adv inst list

Hi Florian,

> The current hci dev structure only supports a single advertising
> instance. To support multi-instance advertising it is necessary to
> introduce a linked list of advertising instances so that multiple
> advertising instances can be dynamically added and/or removed.
>
> In a first step, the existing adv_instance member of the hci_dev
> struct is supplemented by a linked list of advertising instances.
> This patch introduces the list and supporting list management
> infrastructure. The list is not being used yet.
>
> Signed-off-by: Florian Grandel <[email protected]>
> ---
> include/net/bluetooth/hci_core.h | 16 ++++++
> net/bluetooth/hci_core.c | 112 +++++++++++++++++++++++++++++++++++++++
> net/bluetooth/mgmt.c | 10 ++--
> 3 files changed, 133 insertions(+), 5 deletions(-)

I dislike you intermixing userspace with kernel space patches. That makes it so hard to review. Keep them separate.

> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index a056c2b..36cc941 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -156,6 +156,9 @@ struct oob_data {
> };
>
> struct adv_info {
> + struct list_head list;
> + struct hci_dev *hdev;

Why is the a copy of hci_dev needed here?

> + bool pending;

What is this pending for. I do not see it being used in this patch.

> struct delayed_work timeout_exp;
> __u8 instance;
> __u32 flags;
> @@ -166,6 +169,8 @@ struct adv_info {
> __u8 scan_rsp_data[HCI_MAX_AD_LENGTH];
> };
>
> +#define HCI_MAX_ADV_INSTANCES 1
> +
> #define HCI_MAX_SHORT_NAME_LENGTH 10
>
> /* Default LE RPA expiry time, 15 minutes */
> @@ -374,6 +379,9 @@ struct hci_dev {
> __u8 scan_rsp_data_len;
>
> struct adv_info adv_instance;
> + struct list_head adv_instances;
> + unsigned int adv_instance_cnt;
> + __u8 cur_adv_instance;
>
> __u8 irk[16];
> __u32 rpa_timeout;
> @@ -1007,6 +1015,14 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
> int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
> u8 bdaddr_type);
>
> +void hci_adv_instances_clear(struct hci_dev *hdev);
> +struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance);
> +int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
> + u16 adv_data_len, u8 *adv_data,
> + u16 scan_rsp_len, u8 *scan_rsp_data,
> + work_func_t timeout_work, u16 timeout);
> +int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance);
> +
> void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
>
> int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb);
> diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
> index 476709b..de00e21 100644
> --- a/net/bluetooth/hci_core.c
> +++ b/net/bluetooth/hci_core.c
> @@ -2613,6 +2613,114 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
> return 0;
> }
>
> +/* This function requires the caller holds hdev->lock */
> +struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance)
> +{
> + struct adv_info *adv_instance;
> +
> + list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
> + if (adv_instance->instance == instance)
> + return adv_instance;
> + }
> +
> + return NULL;
> +}
> +
> +/* This function requires the caller holds hdev->lock */
> +int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance)
> +{
> + struct adv_info *adv_instance;
> +
> + adv_instance = hci_find_adv_instance(hdev, instance);
> + if (!adv_instance)
> + return -ENOENT;
> +
> + BT_DBG("%s removing %dMR", hdev->name, instance);
> +
> + if (adv_instance->timeout)
> + cancel_delayed_work(&adv_instance->timeout_exp);
> +
> + list_del(&adv_instance->list);
> + kfree(adv_instance);
> +
> + hdev->adv_instance_cnt--;
> +
> + return 0;
> +}
> +
> +/* This function requires the caller holds hdev->lock */
> +void hci_adv_instances_clear(struct hci_dev *hdev)
> +{
> + struct adv_info *adv_instance, *n;
> +
> + list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
> + if (adv_instance->timeout)
> + cancel_delayed_work(&adv_instance->timeout_exp);
> +
> + list_del(&adv_instance->list);
> + kfree(adv_instance);
> + }
> +
> + hdev->adv_instance_cnt = 0;
> +}
> +
> +/* This function requires the caller holds hdev->lock */
> +int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
> + u16 adv_data_len, u8 *adv_data,
> + u16 scan_rsp_len, u8 *scan_rsp_data,
> + work_func_t timeout_work, u16 timeout)
> +{
> + struct adv_info *adv_instance;
> +
> + adv_instance = hci_find_adv_instance(hdev, instance);
> + if (adv_instance) {
> + if (adv_instance->timeout)
> + cancel_delayed_work(&adv_instance->timeout_exp);
> +
> + memset(adv_instance->adv_data, 0,
> + sizeof(adv_instance->adv_data));
> + memset(adv_instance->scan_rsp_data, 0,
> + sizeof(adv_instance->scan_rsp_data));
> + } else {
> + if (hdev->adv_instance_cnt >= HCI_MAX_ADV_INSTANCES)
> + return -EOVERFLOW;
> +
> + adv_instance = kmalloc(sizeof(*adv_instance), GFP_KERNEL);
> + if (!adv_instance)
> + return -ENOMEM;
> +
> + memset(adv_instance, 0, sizeof(*adv_instance));
> + adv_instance->hdev = hdev;
> + adv_instance->pending = true;
> + INIT_DELAYED_WORK(&adv_instance->timeout_exp, timeout_work);
> + adv_instance->instance = instance;
> + list_add(&adv_instance->list, &hdev->adv_instances);
> + hdev->adv_instance_cnt++;
> + }
> +
> + adv_instance->flags = flags;
> + adv_instance->adv_data_len = adv_data_len;
> + adv_instance->scan_rsp_len = scan_rsp_len;
> +
> + if (adv_data_len)
> + memcpy(adv_instance->adv_data, adv_data, adv_data_len);
> +
> + if (scan_rsp_len)
> + memcpy(adv_instance->scan_rsp_data,
> + scan_rsp_data, scan_rsp_len);
> +
> + adv_instance->timeout = timeout;
> +
> + if (timeout)
> + queue_delayed_work(hdev->workqueue,
> + &adv_instance->timeout_exp,
> + msecs_to_jiffies(timeout * 1000));
> +
> + BT_DBG("%s for %dMR", hdev->name, instance);
> +
> + return 0;
> +}
> +
> struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *bdaddr_list,
> bdaddr_t *bdaddr, u8 type)
> {
> @@ -3016,6 +3124,8 @@ struct hci_dev *hci_alloc_dev(void)
> hdev->manufacturer = 0xffff; /* Default to internal use */
> hdev->inq_tx_power = HCI_TX_POWER_INVALID;
> hdev->adv_tx_power = HCI_TX_POWER_INVALID;
> + hdev->adv_instance_cnt = 0;
> + hdev->cur_adv_instance = 0x00;
>
> hdev->sniff_max_interval = 800;
> hdev->sniff_min_interval = 80;
> @@ -3057,6 +3167,7 @@ struct hci_dev *hci_alloc_dev(void)
> INIT_LIST_HEAD(&hdev->pend_le_conns);
> INIT_LIST_HEAD(&hdev->pend_le_reports);
> INIT_LIST_HEAD(&hdev->conn_hash.list);
> + INIT_LIST_HEAD(&hdev->adv_instances);
>
> INIT_WORK(&hdev->rx_work, hci_rx_work);
> INIT_WORK(&hdev->cmd_work, hci_cmd_work);
> @@ -3250,6 +3361,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
> hci_smp_ltks_clear(hdev);
> hci_smp_irks_clear(hdev);
> hci_remote_oob_data_clear(hdev);
> + hci_adv_instances_clear(hdev);
> hci_bdaddr_list_clear(&hdev->le_white_list);
> hci_conn_params_clear_all(hdev);
> hci_discovery_filter_clear(hdev);
> diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
> index 7fd87e7..ce25b6d 100644
> --- a/net/bluetooth/mgmt.c
> +++ b/net/bluetooth/mgmt.c
> @@ -6813,7 +6813,7 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
> rp->supported_flags = cpu_to_le32(supported_flags);
> rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
> rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
> - rp->max_instances = 1;
> + rp->max_instances = HCI_MAX_ADV_INSTANCES;
>
> /* Currently only one instance is supported, so simply return the
> * current instance number.
> @@ -6916,11 +6916,11 @@ unlock:
>
> static void adv_timeout_expired(struct work_struct *work)
> {
> - struct hci_dev *hdev = container_of(work, struct hci_dev,
> - adv_instance.timeout_exp.work);
> -
> - hdev->adv_instance.timeout = 0;
> + struct adv_info *adv_instance = container_of(work, struct adv_info,
> + timeout_exp.work);
> + struct hci_dev *hdev = adv_instance->hdev;
>
> + adv_instance->timeout = 0;
> hci_dev_lock(hdev);
> clear_adv_instance(hdev);
> hci_dev_unlock(hdev);

Regards

Marcel


2015-05-06 10:27:59

by jerico.dev

[permalink] [raw]
Subject: Re: [PATCH v4 00/17] BlueZ/Bluetooth: Multi-advertising infrastructure

Hi Marcel and Johan,

Arman was so kind to review my patch set and I implemented all his
proposals for change. Same for the comments Johan had made earlier.

Will you be able to review the patch series in its current form?

Of course I'll be available to make any further required changes.

Florian




On 04/30/2015 05:33 PM, Florian Grandel wrote:
> This is a patch set introducing the infrastructure for multi-advertising
> capability to the HCI core and mgmt API.
>
> v1 -> v2:
> - add missing braces in read_adv_features()
>
> v2 -> v3:
> - split change-set into several patches
> - replace err == 0 by !err
> - fix coding style problems
>
> v3 -> v4:
> publicly visible change:
> - when calling remove_advertising with an instance value of zero (i.e.
> remove all instances), the command response also returns an instance
> value of zero now as it doesn't make sense to return a single instance
> id when removing several instances
>
> refactoring and fixes (due to Arman's review):
> - splitting the change set into a much larger number of patches to
> facilitate review
> - use HCI_MAX_ADV_INSTANCES in the same patch that introduces it
> - use adv_info->hdev in the same patch that introduces it
> - make the logic of hci_find_adv_instance() more readable
> - make sure that hci_find_adv_instance() is called while hci_dev is
> locked
> - replace hci_num_adv_instances() by an instance counter in hci_dev
> - add inline comment in get_adv_instance_flags() explaining its return
> value in the error case
> - generate zero-length adv data if the current instance identifier is
> invalid
> - revert erroneous changes to the logic in clear_adv_instance()
> - use hci_adv_instances_clear() in clear_adv_instance() when removing
> all advertising instances also removing a reduntant error check
> - inserting TODO messages to make sure that advertising will not be
> switched off prematurely once we allow more than one advertising
> instance
> - inserting TODO messages to make sure that multiple advertising
> instances will be advertised in a round-robin fashion once we allow
> for more than one advertising instance
> - identify peding advertising instances (just added but not yet
> confirmed in add_advertising_complete) by a boolean flag in the
> adv_info struct so that we can identify and remove them even when
> the pending add_advertising command cannot be retrieved for some
> reason - makes sure that we do not lead advertising instances in this
> case
> - only send HCI commands to update advertising data when a new instance
> has actually been added
>
>
>
> Userland:
>
> Florian Grandel (1):
> tools/mgmt_tester: expect 0 rp when removing all adv inst
>
> tools/mgmt-tester.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
>
>
> Kernel:
>
> Florian Grandel (16):
> Bluetooth: hci_core: Introduce multi-adv inst list
> Bluetooth: mgmt: dry update_scan_rsp_data()
> Bluetooth: mgmt: multi adv for read_adv_features()
> Bluetooth: mgmt: multi adv for get_current_adv_instance()
> Bluetooth: mgmt: multi adv for get_adv_instance_flags()
> Bluetooth: mgmt: improve get_adv_instance_flags() readability
> Bluetooth: mgmt: multi adv for enable_advertising()
> Bluetooth: mgmt: use current adv instance in set_advertising()
> Bluetooth: mgmt: multi adv for create_instance_scan_rsp_data()
> Bluetooth: mgmt: multi adv for create_instance_adv_data()
> Bluetooth: mgmt: refactor update_*_data()
> Bluetooth: mgmt: multi adv for set_advertising_complete()
> Bluetooth: mgmt: multi adv for add_advertising()
> Bluetooth: mgmt: multi adv for clear_adv_instances()
> Bluetooth: multi adv for remove_advertising()
> Bluetooth: hci_core: Remove obsolete adv_instance
>
> include/net/bluetooth/hci_core.h | 22 ++-
> net/bluetooth/hci_core.c | 113 ++++++++++++-
> net/bluetooth/mgmt.c | 352 ++++++++++++++++++++++-----------------
> 3 files changed, 328 insertions(+), 159 deletions(-)
>

2015-06-18 16:58:47

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH v8 00/20] Multi-advertising

Hi Florian,

> patch set introducing the infrastructure for multi-advertising
> capability to the HCI core and mgmt API.
>
> v1 -> v2:
> - add missing braces in read_adv_features()
>
> v2 -> v3 (changes due to Johan's review):
> - split change-set into several patches
> - replace err == 0 by !err
> - fix coding style problems
>
> v3 -> v4 (changes due to Arman's review):
> - bug fix: when calling remove_advertising with an instance value of
> zero (i.e. remove all instances), the command response also returns
> an instance value of zero now as it doesn't make sense to return a
> single instance id when removing several instances
> - splitting the change set into a much larger number of patches to
> facilitate review
> - use HCI_MAX_ADV_INSTANCES in the same patch that introduces it
> - use adv_info->hdev in the same patch that introduces it
> - make the logic of hci_find_adv_instance() more readable
> - make sure that hci_find_adv_instance() is called while hci_dev is
> locked
> - replace hci_num_adv_instances() by an instance counter in hci_dev
> - add inline comment in get_adv_instance_flags() explaining its return
> value in the error case
> - generate zero-length adv data if the current instance identifier is
> invalid
> - revert erroneous changes to the logic in clear_adv_instance()
> - use hci_adv_instances_clear() in clear_adv_instance() when removing
> all advertising instances also removing a redundant error check
> - inserting TODO messages to make sure that advertising will not be
> switched off prematurely once we allow more than one advertising
> instance
> - inserting TODO messages to make sure that multiple advertising
> instances will be advertised in a round-robin fashion once we allow
> for more than one advertising instance
> - identify pending advertising instances (just added but not yet
> confirmed in add_advertising_complete) by a boolean flag in the
> adv_info struct so that we can identify and remove them even when the
> pending add_advertising command cannot be retrieved for some reason -
> makes sure that we do not leak advertising instances in this case
> - only send HCI commands to update advertising data when a new instance
> has actually been added
>
> v4 -> v5 (changes due to Marcel's review):
> - split into separate change sets for kernel and userspace
> - do not trust the adv instance list length when compiling the adv
> features struct
> - introduce adv_info->pending in the same patch it's used for the first
> time
>
> v5 -> v6 (changes due to Marcel's review):
> - fix the add adv override bug
> - fix "Using plain integer as NULL pointer" warning in
> set_advertising_complete()
> - reword the "remove adv instance" commit comment to make it clear that
> an existing bug is being fixed
>
> v6 -> v7:
> - so far the patch set only contained a functionally neutral refactoring
> to provide the basic infrastructure for multi-advertising. It has been
> decided, though, that the patch set should provide the whole package
> at once, including actual multi-advertising functionality. This has
> been implemented and tested in the latest version of the patch set.
>
> v7 -> v8 (changes due to Marcel's review):
> - switch to next instance when updating the currently advertised
> instance
> - keep instances without timeout during power cycles
>
> Florian Grandel (20):
> Bluetooth: hci_core/mgmt: Introduce multi-adv list
> Bluetooth: hci_core/mgmt: move adv timeout to hdev
> Bluetooth: mgmt: dry update_scan_rsp_data()
> Bluetooth: mgmt: rename update_*_data_for_instance()
> Bluetooth: mgmt: multi adv for read_adv_features()
> Bluetooth: mgmt: multi adv for get_current_adv_instance()
> Bluetooth: mgmt: multi adv for get_adv_instance_flags()
> Bluetooth: mgmt: improve get_adv_instance_flags() readability
> Bluetooth: mgmt: multi adv for enable_advertising()
> Bluetooth: mgmt: multi adv for create_instance_scan_rsp_data()
> Bluetooth: mgmt: multi adv for create_instance_adv_data()
> Bluetooth: mgmt: multi adv for set_advertising*()
> Bluetooth: mgmt: multi adv for clear_adv_instances()
> Bluetooth: mgmt/hci_core: multi-adv for add_advertising*()
> Bluetooth: mgmt: multi adv for remove_advertising*()
> Bluetooth: mgmt: program multi-adv on power on
> Bluetooth: mgmt: multi-adv for trigger_le_scan()
> Bluetooth: mgmt: multi-adv for mgmt_reenable_advertising()
> Bluetooth: hci_core: remove obsolete adv_instance
> Bluetooth: hci_core: increase max adv inst
>
> include/net/bluetooth/hci_core.h | 29 +-
> net/bluetooth/hci_core.c | 148 +++++++++-
> net/bluetooth/mgmt.c | 563 +++++++++++++++++++++++++++------------
> 3 files changed, 565 insertions(+), 175 deletions(-)

all 20 patches have been applied to bluetooth-next tree.

Regards

Marcel


2015-06-18 10:19:25

by Johan Hedberg

[permalink] [raw]
Subject: Re: [BlueZ v9 00/16] Multi-advertising

Hi Florian,

On Thu, Jun 18, 2015, Florian Grandel wrote:
> patch set accompanying the introduction of a multi-advertising
> infrastructure in the kernel
>
> v1 ... v4:
> - fix tests to test for correct behavior when removing all adv instances
> by passing in the 0x00 instance identifier
>
> v4 -> v5:
> - factored userland code changes into a separate change set for easier
> review
>
> v5 -> v6:
> - documented add advertising test setup
> - renamed add advertising tests to make them more readable
> - added test to reproduce a bug found by Marcel (executing add-adv twice
> for the same instance should override the adv data)
>
> v6 -> v7:
> - correctly split mangled patches
>
> v7 -> v8:
> - several additional test documentation improvements
> - documenting multi-adv implementation details in the mgmt api doc
> - made the debugging of cmd response messages easier
> - made the duration parameter accessible via btmgmt
> - provided test infrastructure for timed tests
> - fix duplicate code
> - fix a few typos
> - added test for advertising timeout
> - added test for le off
> - added multi-adv tests
>
> v8 -> v9 (due to Marcel's review):
> - improved and fixed changes to mgmt-api.txt
> - added a test that guarantees that instances without a timeout survive
> a power cycle
>
> Florian Grandel (16):
> doc/mgmt-api: multi-adv implementation details
> doc/mgmt-api: fix typos
> tools/btmgmt: make inst duration configurable
> tools/mgmt-tester: error message when unexp params
> tools/mgmt-tester: expect 0 rp when removing all adv inst
> tools/mgmt-tester: comment add adv test setup
> tools/mgmt-tester: rename add adv tests
> tools/mgmt-tester: increase max adv inst
> tools/mgmt-tester: keep instances on power cycle
> tools/mgmt-tester: test adv inst override
> tools/mgmt-tester: make test timeout configurable
> tools/mgmt-tester: allow for event-only tests
> tools/mgmt-tester: test advertising timeout
> tools/mgmt-tester: test le off
> tools/mgmt-tester: fix duplicate code
> tools/mgmt-tester: test multi-adv
>
> doc/mgmt-api.txt | 105 +++++--
> doc/test-coverage.txt | 4 +-
> tools/btmgmt.c | 28 +-
> tools/mgmt-tester.c | 838 +++++++++++++++++++++++++++++++++++---------------
> 4 files changed, 681 insertions(+), 294 deletions(-)

All patches in this set have been applied. Thanks!

Johan

2015-06-18 07:11:19

by Johan Hedberg

[permalink] [raw]
Subject: Re: [BlueZ v9 00/16] Multi-advertising

Hi Florian,

On Thu, Jun 18, 2015, Johan Hedberg wrote:
> I've been running mgmt-tester with your latest kernel and user space
> patch sets, and there are four tests either failing or not getting run:
>
> Read Advertising Features - Success 1 (No instance) Failed 0.019 seconds
> Read Advertising Features - Success 2 (One instance) Failed 0.025 seconds
> Multi Advertising - Success 1 (Instance Switch) Not Run
> Multi Advertising - Success 2 (Add Second Inst) Failed 0.030 seconds
>
> Are these passing for you?

False alarm. I had just failed to fully compile all of your kernel
patches. Now all the mgmt-tester tests pass for me. Sorry about the
confusion.

Johan

2015-06-18 05:55:52

by Johan Hedberg

[permalink] [raw]
Subject: Re: [BlueZ v9 00/16] Multi-advertising

Hi Florian,

On Thu, Jun 18, 2015, Florian Grandel wrote:
> Florian Grandel (16):
> doc/mgmt-api: multi-adv implementation details
> doc/mgmt-api: fix typos
> tools/btmgmt: make inst duration configurable
> tools/mgmt-tester: error message when unexp params
> tools/mgmt-tester: expect 0 rp when removing all adv inst
> tools/mgmt-tester: comment add adv test setup
> tools/mgmt-tester: rename add adv tests
> tools/mgmt-tester: increase max adv inst
> tools/mgmt-tester: keep instances on power cycle
> tools/mgmt-tester: test adv inst override
> tools/mgmt-tester: make test timeout configurable
> tools/mgmt-tester: allow for event-only tests
> tools/mgmt-tester: test advertising timeout
> tools/mgmt-tester: test le off
> tools/mgmt-tester: fix duplicate code
> tools/mgmt-tester: test multi-adv
>
> doc/mgmt-api.txt | 105 +++++--
> doc/test-coverage.txt | 4 +-
> tools/btmgmt.c | 28 +-
> tools/mgmt-tester.c | 838 +++++++++++++++++++++++++++++++++++---------------
> 4 files changed, 681 insertions(+), 294 deletions(-)

I've been running mgmt-tester with your latest kernel and user space
patch sets, and there are four tests either failing or not getting run:

Read Advertising Features - Success 1 (No instance) Failed 0.019 seconds
Read Advertising Features - Success 2 (One instance) Failed 0.025 seconds
Multi Advertising - Success 1 (Instance Switch) Not Run
Multi Advertising - Success 2 (Add Second Inst) Failed 0.030 seconds

Are these passing for you?

The detailed failures look like this:

Read Advertising Features - Success 1 (No instance) - run
Sending command 0x003d
Test condition added, total 1
Command 0x003d finished with status 0x00
Unexpected cmd response parameter value
Read Advertising Features - Success 1 (No instance) - test failed

Read Advertising Features - Success 2 (One instance) - run
Sending command 0x003d
Test condition added, total 1
Command 0x003d finished with status 0x00
Unexpected cmd response parameter value
Read Advertising Features - Success 2 (One instance) - test failed

Multi Advertising - Success 1 (Instance Switch) - setup
Adding two instances with timeout 1 and duration 1
Add Advertising setup complete (instance 1)
Multi Advertising - Success 1 (Instance Switch) - setup failed

Multi Advertising - Success 2 (Add Second Inst) - run
Registering Advertising Added notification
Test condition added, total 1
Registering HCI command callback
Test condition added, total 2
Sending command 0x003e
Test condition added, total 3
Command 0x003e finished with status 0x03
Multi Advertising - Success 2 (Add Second Inst) - test failed

Do these failures indicate a kernel bug or a test case having a bug or
otherwise needing updating (e.g. to match your latest changes)?

Johan

2015-06-18 01:17:46

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v9 16/16] tools/mgmt-tester: test multi-adv

This patch adds tests and required test infrastructure for multi
advertising tests.
---
doc/test-coverage.txt | 4 +-
tools/mgmt-tester.c | 215 +++++++++++++++++++++++++++++++++++++++++++-------
2 files changed, 190 insertions(+), 29 deletions(-)

diff --git a/doc/test-coverage.txt b/doc/test-coverage.txt
index 3e1c759..819ac50 100644
--- a/doc/test-coverage.txt
+++ b/doc/test-coverage.txt
@@ -39,7 +39,7 @@ Automated end-to-end testing

Application Count Description
-------------------------------------------
-mgmt-tester 300 Kernel management interface testing
+mgmt-tester 302 Kernel management interface testing
l2cap-tester 27 Kernel L2CAP implementation testing
rfcomm-tester 9 Kernel RFCOMM implementation testing
bnep-tester 1 Kernel BNEP implementation testing
@@ -49,7 +49,7 @@ gap-tester 1 Daemon D-Bus API testing
hci-tester 14 Controller hardware testing
userchan-tester 3 Kernel HCI User Channel testting
-----
- 371
+ 373


Android end-to-end testing
diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index e8333de..46b088c 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -3990,10 +3990,28 @@ static const uint8_t add_advertising_param_txpwr[] = {
0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
};

+/* add advertising command for a second instance */
+static const uint8_t add_advertising_param_test2[] = {
+ 0x02, /* adv instance */
+ 0x00, 0x00, 0x00, 0x00, /* flags: none */
+ 0x00, 0x00, /* duration: default */
+ 0x01, 0x00, /* timeout: 1 second */
+ 0x07, /* adv data len */
+ 0x00, /* scan rsp len */
+ /* adv data: */
+ 0x06, /* AD len */
+ 0x08, /* AD type: shortened local name */
+ 0x74, 0x65, 0x73, 0x74, 0x32, /* "test2" */
+};
+
static const uint8_t advertising_instance1_param[] = {
0x01,
};

+static const uint8_t advertising_instance2_param[] = {
+ 0x02,
+};
+
static const uint8_t set_adv_data_uuid[] = {
/* adv data len */
0x09,
@@ -4005,15 +4023,26 @@ static const uint8_t set_adv_data_uuid[] = {
0x00, 0x00,
};

-static const uint8_t set_adv_data_test[] = {
- 0x06, /* adv data len */
- 0x05, /* AD len */
- 0x08, /* AD type: shortened local name */
- 0x74, 0x65, 0x73, 0x74, /* "test" */
+static const uint8_t set_adv_data_test1[] = {
+ 0x07, /* adv data len */
+ 0x06, /* AD len */
+ 0x08, /* AD type: shortened local name */
+ 0x74, 0x65, 0x73, 0x74, 0x31, /* "test1" */
/* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+};
+
+static const uint8_t set_adv_data_test2[] = {
+ 0x07, /* adv data len */
+ 0x06, /* AD len */
+ 0x08, /* AD type: shortened local name */
+ 0x74, 0x65, 0x73, 0x74, 0x32, /* "test2" */
+ /* padding */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
};

static const uint8_t set_adv_data_txpwr[] = {
@@ -4277,8 +4306,8 @@ static const struct generic_data add_advertising_success_pwron_data = {
.expect_param = set_powered_adv_instance_settings_param,
.expect_len = sizeof(set_powered_adv_instance_settings_param),
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
- .expect_hci_param = set_adv_data_test,
- .expect_hci_len = sizeof(set_adv_data_test),
+ .expect_hci_param = set_adv_data_test1,
+ .expect_hci_len = sizeof(set_adv_data_test1),
};

static const struct generic_data add_advertising_success_pwron_enabled = {
@@ -4315,8 +4344,8 @@ static const struct generic_data add_advertising_success_5 = {
.expect_param = set_powered_adv_instance_settings_param,
.expect_len = sizeof(set_powered_adv_instance_settings_param),
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
- .expect_hci_param = set_adv_data_test,
- .expect_hci_len = sizeof(set_adv_data_test),
+ .expect_hci_param = set_adv_data_test1,
+ .expect_hci_len = sizeof(set_adv_data_test1),
};

static const struct generic_data add_advertising_success_6 = {
@@ -4595,6 +4624,31 @@ static const struct generic_data remove_advertising_success_2 = {
.expect_hci_len = sizeof(set_adv_off_param),
};

+static const struct generic_data multi_advertising_switch = {
+ .send_opcode = TESTER_NOOP_OPCODE,
+ .expect_alt_ev = MGMT_EV_ADVERTISING_REMOVED,
+ .expect_alt_ev_param = advertising_instance1_param,
+ .expect_alt_ev_len = sizeof(advertising_instance1_param),
+ .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
+ .expect_hci_param = set_adv_data_test2,
+ .expect_hci_len = sizeof(set_adv_data_test2),
+};
+
+static const struct generic_data multi_advertising_add_second = {
+ .send_opcode = MGMT_OP_ADD_ADVERTISING,
+ .send_param = add_advertising_param_test2,
+ .send_len = sizeof(add_advertising_param_test2),
+ .expect_param = advertising_instance2_param,
+ .expect_len = sizeof(advertising_instance2_param),
+ .expect_status = MGMT_STATUS_SUCCESS,
+ .expect_alt_ev = MGMT_EV_ADVERTISING_ADDED,
+ .expect_alt_ev_param = advertising_instance2_param,
+ .expect_alt_ev_len = sizeof(advertising_instance2_param),
+ .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
+ .expect_hci_param = set_adv_data_test2,
+ .expect_hci_len = sizeof(set_adv_data_test2),
+};
+
/* based on G-Tag ADV_DATA */
static const uint8_t adv_data_invalid_significant_len[] = { 0x02, 0x01, 0x06,
0x0d, 0xff, 0x80, 0x01, 0x02, 0x15, 0x12, 0x34, 0x80, 0x91,
@@ -5015,40 +5069,48 @@ static void setup_add_device(const void *test_data)
static void setup_add_advertising_callback(uint8_t status, uint16_t length,
const void *param, void *user_data)
{
+ struct mgmt_rp_add_advertising *rp =
+ (struct mgmt_rp_add_advertising *) param;
+
if (status != MGMT_STATUS_SUCCESS) {
tester_setup_failed();
return;
}

- tester_print("Add Advertising setup complete");
+ tester_print("Add Advertising setup complete (instance %d)",
+ rp->instance);

setup_bthost();
}

-static void setup_add_adv_param(struct mgmt_cp_add_advertising *cp)
+#define TESTER_ADD_ADV_DATA_LEN 7
+
+static void setup_add_adv_param(struct mgmt_cp_add_advertising *cp,
+ uint8_t instance)
{
memset(cp, 0, sizeof(*cp));
- cp->instance = 1;
- cp->adv_data_len = 6;
- cp->data[0] = 0x05; /* AD len */
+ cp->instance = instance;
+ cp->adv_data_len = TESTER_ADD_ADV_DATA_LEN;
+ cp->data[0] = TESTER_ADD_ADV_DATA_LEN - 1; /* AD len */
cp->data[1] = 0x08; /* AD type: shortened local name */
cp->data[2] = 't'; /* adv data ... */
cp->data[3] = 'e';
cp->data[4] = 's';
cp->data[5] = 't';
+ cp->data[6] = '0' + instance;
}

static void setup_add_advertising_not_powered(const void *test_data)
{
struct test_data *data = tester_get_data();
struct mgmt_cp_add_advertising *cp;
- unsigned char adv_param[sizeof(*cp) + 6];
+ unsigned char adv_param[sizeof(*cp) + TESTER_ADD_ADV_DATA_LEN];
unsigned char param[] = { 0x01 };

tester_print("Adding advertising instance while unpowered");

cp = (struct mgmt_cp_add_advertising *) adv_param;
- setup_add_adv_param(cp);
+ setup_add_adv_param(cp, 1);

mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
sizeof(param), &param,
@@ -5064,13 +5126,13 @@ static void setup_add_advertising(const void *test_data)
{
struct test_data *data = tester_get_data();
struct mgmt_cp_add_advertising *cp;
- unsigned char adv_param[sizeof(*cp) + 6];
+ unsigned char adv_param[sizeof(*cp) + TESTER_ADD_ADV_DATA_LEN];
unsigned char param[] = { 0x01 };

tester_print("Adding advertising instance while powered");

cp = (struct mgmt_cp_add_advertising *) adv_param;
- setup_add_adv_param(cp);
+ setup_add_adv_param(cp, 1);

mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
sizeof(param), &param,
@@ -5090,13 +5152,13 @@ static void setup_add_advertising_connectable(const void *test_data)
{
struct test_data *data = tester_get_data();
struct mgmt_cp_add_advertising *cp;
- unsigned char adv_param[sizeof(*cp) + 6];
+ unsigned char adv_param[sizeof(*cp) + TESTER_ADD_ADV_DATA_LEN];
unsigned char param[] = { 0x01 };

tester_print("Adding advertising instance while connectable");

cp = (struct mgmt_cp_add_advertising *) adv_param;
- setup_add_adv_param(cp);
+ setup_add_adv_param(cp, 1);

mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
sizeof(param), &param,
@@ -5120,13 +5182,13 @@ static void setup_add_advertising_timeout(const void *test_data)
{
struct test_data *data = tester_get_data();
struct mgmt_cp_add_advertising *cp;
- unsigned char adv_param[sizeof(*cp) + 6];
+ unsigned char adv_param[sizeof(*cp) + TESTER_ADD_ADV_DATA_LEN];
unsigned char param[] = { 0x01 };

tester_print("Adding advertising instance with timeout");

cp = (struct mgmt_cp_add_advertising *) adv_param;
- setup_add_adv_param(cp);
+ setup_add_adv_param(cp, 1);
cp->timeout = 1;

mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
@@ -5143,6 +5205,34 @@ static void setup_add_advertising_timeout(const void *test_data)
NULL, NULL);
}

+static void setup_add_advertising_duration(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ struct mgmt_cp_add_advertising *cp;
+ unsigned char adv_param[sizeof(*cp) + TESTER_ADD_ADV_DATA_LEN];
+ unsigned char param[] = { 0x01 };
+
+ tester_print("Adding instance with long timeout/short duration");
+
+ cp = (struct mgmt_cp_add_advertising *) adv_param;
+ setup_add_adv_param(cp, 1);
+ cp->duration = 1;
+ cp->timeout = 30;
+
+ mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
+ sizeof(param), &param,
+ NULL, NULL, NULL);
+
+ mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+ sizeof(param), &param,
+ NULL, NULL, NULL);
+
+ mgmt_send(data->mgmt, MGMT_OP_ADD_ADVERTISING, data->mgmt_index,
+ sizeof(adv_param), adv_param,
+ setup_add_advertising_callback,
+ NULL, NULL);
+}
+
static void setup_power_cycle_callback(uint8_t status, uint16_t length,
const void *param, void *user_data)
{
@@ -5165,13 +5255,13 @@ static void setup_add_advertising_power_cycle(const void *test_data)
{
struct test_data *data = tester_get_data();
struct mgmt_cp_add_advertising *cp;
- unsigned char adv_param[sizeof(*cp) + 6];
+ unsigned char adv_param[sizeof(*cp) + TESTER_ADD_ADV_DATA_LEN];
unsigned char param_on[] = { 0x01 };

tester_print("Adding instance without timeout and power cycle");

cp = (struct mgmt_cp_add_advertising *) adv_param;
- setup_add_adv_param(cp);
+ setup_add_adv_param(cp, 1);

mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
sizeof(param_on), &param_on,
@@ -5191,13 +5281,13 @@ static void setup_set_and_add_advertising(const void *test_data)
{
struct test_data *data = tester_get_data();
struct mgmt_cp_add_advertising *cp;
- unsigned char adv_param[sizeof(*cp) + 6];
+ unsigned char adv_param[sizeof(*cp) + TESTER_ADD_ADV_DATA_LEN];
unsigned char param[] = { 0x01 };

tester_print("Set and add advertising instance");

cp = (struct mgmt_cp_add_advertising *) adv_param;
- setup_add_adv_param(cp);
+ setup_add_adv_param(cp, 1);

mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
sizeof(param), &param,
@@ -5217,6 +5307,61 @@ static void setup_set_and_add_advertising(const void *test_data)
NULL, NULL);
}

+static void setup_multi_adv_second_instance(uint8_t status, uint16_t length,
+ const void *param, void *user_data) {
+ struct mgmt_rp_add_advertising *rp =
+ (struct mgmt_rp_add_advertising *) param;
+ struct test_data *data = tester_get_data();
+ struct mgmt_cp_add_advertising *cp;
+ unsigned char adv_param[sizeof(*cp) + TESTER_ADD_ADV_DATA_LEN];
+
+ if (status != MGMT_STATUS_SUCCESS) {
+ tester_setup_failed();
+ return;
+ }
+
+ tester_print("Add Advertising setup complete (instance %d)",
+ rp->instance);
+
+ cp = (struct mgmt_cp_add_advertising *) adv_param;
+ setup_add_adv_param(cp, 2);
+ cp->timeout = 1;
+ cp->duration = 1;
+
+ mgmt_send(data->mgmt, MGMT_OP_ADD_ADVERTISING, data->mgmt_index,
+ sizeof(adv_param), adv_param,
+ setup_add_advertising_callback,
+ NULL, NULL);
+}
+
+static void setup_multi_adv(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ struct mgmt_cp_add_advertising *cp;
+ unsigned char adv_param[sizeof(*cp) + TESTER_ADD_ADV_DATA_LEN];
+ unsigned char param[] = { 0x01 };
+
+ tester_print("Adding two instances with timeout 1 and duration 1");
+
+ cp = (struct mgmt_cp_add_advertising *) adv_param;
+ setup_add_adv_param(cp, 1);
+ cp->timeout = 1;
+ cp->duration = 1;
+
+ mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
+ sizeof(param), &param,
+ NULL, NULL, NULL);
+
+ mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+ sizeof(param), &param,
+ NULL, NULL, NULL);
+
+ mgmt_send(data->mgmt, MGMT_OP_ADD_ADVERTISING, data->mgmt_index,
+ sizeof(adv_param), adv_param,
+ setup_multi_adv_second_instance,
+ NULL, NULL);
+}
+
static void setup_complete(uint8_t status, uint16_t length,
const void *param, void *user_data)
{
@@ -6740,6 +6885,22 @@ int main(int argc, char *argv[])
setup_add_advertising,
test_command_generic);

+ /* When advertising two instances, the instances should be
+ * advertised in a round-robin fashion.
+ */
+ test_bredrle("Multi Advertising - Success 1 (Instance Switch)",
+ &multi_advertising_switch,
+ setup_multi_adv,
+ test_command_generic);
+ /* Adding a new instance when one is already being advertised
+ * will switch to the new instance after the first has reached
+ * its duration. A long timeout has been set to
+ */
+ test_bredrle_full("Multi Advertising - Success 2 (Add Second Inst)",
+ &multi_advertising_add_second,
+ setup_add_advertising_duration,
+ test_command_generic, 3);
+
test_bredrle("Read Local OOB Data - Not powered",
&read_local_oob_not_powered_test,
NULL, test_command_generic);
--
1.9.1


2015-06-18 01:17:45

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v9 15/16] tools/mgmt-tester: fix duplicate code

The definition of the test advertising instance was duplicated in
several places. This patch refactors the duplicate code into a
common subroutine.
---
tools/mgmt-tester.c | 79 +++++++++++++----------------------------------------
1 file changed, 19 insertions(+), 60 deletions(-)

diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 78091c4..e8333de 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -5025,18 +5025,9 @@ static void setup_add_advertising_callback(uint8_t status, uint16_t length,
setup_bthost();
}

-static void setup_add_advertising_not_powered(const void *test_data)
+static void setup_add_adv_param(struct mgmt_cp_add_advertising *cp)
{
- struct test_data *data = tester_get_data();
- struct mgmt_cp_add_advertising *cp;
- unsigned char adv_param[sizeof(*cp) + 6];
- unsigned char param[] = { 0x01 };
-
- tester_print("Adding advertising instance while unpowered");
-
- cp = (struct mgmt_cp_add_advertising *) adv_param;
memset(cp, 0, sizeof(*cp));
-
cp->instance = 1;
cp->adv_data_len = 6;
cp->data[0] = 0x05; /* AD len */
@@ -5045,6 +5036,19 @@ static void setup_add_advertising_not_powered(const void *test_data)
cp->data[3] = 'e';
cp->data[4] = 's';
cp->data[5] = 't';
+}
+
+static void setup_add_advertising_not_powered(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ struct mgmt_cp_add_advertising *cp;
+ unsigned char adv_param[sizeof(*cp) + 6];
+ unsigned char param[] = { 0x01 };
+
+ tester_print("Adding advertising instance while unpowered");
+
+ cp = (struct mgmt_cp_add_advertising *) adv_param;
+ setup_add_adv_param(cp);

mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
sizeof(param), &param,
@@ -5066,16 +5070,7 @@ static void setup_add_advertising(const void *test_data)
tester_print("Adding advertising instance while powered");

cp = (struct mgmt_cp_add_advertising *) adv_param;
- memset(cp, 0, sizeof(*cp));
-
- cp->instance = 1;
- cp->adv_data_len = 6;
- cp->data[0] = 0x05; /* AD len */
- cp->data[1] = 0x08; /* AD type: shortened local name */
- cp->data[2] = 't'; /* adv data ... */
- cp->data[3] = 'e';
- cp->data[4] = 's';
- cp->data[5] = 't';
+ setup_add_adv_param(cp);

mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
sizeof(param), &param,
@@ -5101,16 +5096,7 @@ static void setup_add_advertising_connectable(const void *test_data)
tester_print("Adding advertising instance while connectable");

cp = (struct mgmt_cp_add_advertising *) adv_param;
- memset(cp, 0, sizeof(*cp));
-
- cp->instance = 1;
- cp->adv_data_len = 6;
- cp->data[0] = 0x05; /* AD len */
- cp->data[1] = 0x08; /* AD type: shortened local name */
- cp->data[2] = 't'; /* adv data ... */
- cp->data[3] = 'e';
- cp->data[4] = 's';
- cp->data[5] = 't';
+ setup_add_adv_param(cp);

mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
sizeof(param), &param,
@@ -5140,17 +5126,8 @@ static void setup_add_advertising_timeout(const void *test_data)
tester_print("Adding advertising instance with timeout");

cp = (struct mgmt_cp_add_advertising *) adv_param;
- memset(cp, 0, sizeof(*cp));
-
- cp->instance = 1;
+ setup_add_adv_param(cp);
cp->timeout = 1;
- cp->adv_data_len = 6;
- cp->data[0] = 0x05; /* AD len */
- cp->data[1] = 0x08; /* AD type: shortened local name */
- cp->data[2] = 't'; /* adv data ... */
- cp->data[3] = 'e';
- cp->data[4] = 's';
- cp->data[5] = 't';

mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
sizeof(param), &param,
@@ -5194,16 +5171,7 @@ static void setup_add_advertising_power_cycle(const void *test_data)
tester_print("Adding instance without timeout and power cycle");

cp = (struct mgmt_cp_add_advertising *) adv_param;
- memset(cp, 0, sizeof(*cp));
-
- cp->instance = 1;
- cp->adv_data_len = 6;
- cp->data[0] = 0x05; /* AD len */
- cp->data[1] = 0x08; /* AD type: shortened local name */
- cp->data[2] = 't'; /* adv data ... */
- cp->data[3] = 'e';
- cp->data[4] = 's';
- cp->data[5] = 't';
+ setup_add_adv_param(cp);

mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
sizeof(param_on), &param_on,
@@ -5229,16 +5197,7 @@ static void setup_set_and_add_advertising(const void *test_data)
tester_print("Set and add advertising instance");

cp = (struct mgmt_cp_add_advertising *) adv_param;
- memset(cp, 0, sizeof(*cp));
-
- cp->instance = 1;
- cp->adv_data_len = 6;
- cp->data[0] = 0x05; /* AD len */
- cp->data[1] = 0x08; /* AD type: shortened local name */
- cp->data[2] = 't'; /* adv data ... */
- cp->data[3] = 'e';
- cp->data[4] = 's';
- cp->data[5] = 't';
+ setup_add_adv_param(cp);

mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
sizeof(param), &param,
--
1.9.1


2015-06-18 01:17:44

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v9 14/16] tools/mgmt-tester: test le off

Test that advertising instances will be removed when disabling the le
capability of a brle bluetooth device.
---
doc/test-coverage.txt | 4 ++--
tools/mgmt-tester.c | 21 +++++++++++++++++++++
2 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/doc/test-coverage.txt b/doc/test-coverage.txt
index 50e29b5..3e1c759 100644
--- a/doc/test-coverage.txt
+++ b/doc/test-coverage.txt
@@ -39,7 +39,7 @@ Automated end-to-end testing

Application Count Description
-------------------------------------------
-mgmt-tester 299 Kernel management interface testing
+mgmt-tester 300 Kernel management interface testing
l2cap-tester 27 Kernel L2CAP implementation testing
rfcomm-tester 9 Kernel RFCOMM implementation testing
bnep-tester 1 Kernel BNEP implementation testing
@@ -49,7 +49,7 @@ gap-tester 1 Daemon D-Bus API testing
hci-tester 14 Controller hardware testing
userchan-tester 3 Kernel HCI User Channel testting
-----
- 370
+ 371


Android end-to-end testing
diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 55a5001..78091c4 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -1550,6 +1550,7 @@ static const struct generic_data set_hs_on_invalid_index_test = {
static uint16_t settings_le[] = { MGMT_OP_SET_LE, 0 };

static const char set_le_on_param[] = { 0x01 };
+static const char set_le_off_param[] = { 0x00 };
static const char set_le_invalid_param[] = { 0x02 };
static const char set_le_garbage_param[] = { 0x01, 0x00 };
static const char set_le_settings_param_1[] = { 0x80, 0x02, 0x00, 0x00 };
@@ -4513,6 +4514,20 @@ static const struct generic_data add_advertising_power_off = {
.expect_alt_ev_len = sizeof(advertising_instance1_param),
};

+static const char set_le_settings_param_off[] = { 0x81, 0x00, 0x00, 0x00 };
+
+static const struct generic_data add_advertising_le_off = {
+ .send_opcode = MGMT_OP_SET_LE,
+ .send_param = set_le_off_param,
+ .send_len = sizeof(set_le_off_param),
+ .expect_status = MGMT_STATUS_SUCCESS,
+ .expect_param = set_le_settings_param_off,
+ .expect_len = sizeof(set_le_settings_param_off),
+ .expect_alt_ev = MGMT_EV_ADVERTISING_REMOVED,
+ .expect_alt_ev_param = advertising_instance1_param,
+ .expect_alt_ev_len = sizeof(advertising_instance1_param),
+};
+
static const struct generic_data add_advertising_success_18 = {
.send_opcode = MGMT_OP_ADD_ADVERTISING,
.send_param = add_advertising_param_uuid,
@@ -6747,6 +6762,12 @@ int main(int argc, char *argv[])
&add_advertising_timeout_expired,
setup_add_advertising_timeout,
test_command_generic, 3);
+ /* LE off will clear (remove) all instances. */
+ test_bredrle("Add Advertising - Success 22 (LE -> off, Remove)",
+ &add_advertising_le_off,
+ setup_add_advertising,
+ test_command_generic);
+

test_bredrle("Remove Advertising - Invalid Params 1",
&remove_advertising_fail_1,
--
1.9.1


2015-06-18 01:17:43

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v9 13/16] tools/mgmt-tester: test advertising timeout

The change introduces an additional test that waits for an advertising
timeout to occur and checks whether the timed out advertising instance
is correctly being removed and - if it was the last instance -
advertising disabled.
---
doc/test-coverage.txt | 4 ++--
tools/mgmt-tester.c | 20 +++++++++++++++++++-
2 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/doc/test-coverage.txt b/doc/test-coverage.txt
index 9c8b9bc..50e29b5 100644
--- a/doc/test-coverage.txt
+++ b/doc/test-coverage.txt
@@ -39,7 +39,7 @@ Automated end-to-end testing

Application Count Description
-------------------------------------------
-mgmt-tester 298 Kernel management interface testing
+mgmt-tester 299 Kernel management interface testing
l2cap-tester 27 Kernel L2CAP implementation testing
rfcomm-tester 9 Kernel RFCOMM implementation testing
bnep-tester 1 Kernel BNEP implementation testing
@@ -49,7 +49,7 @@ gap-tester 1 Daemon D-Bus API testing
hci-tester 14 Controller hardware testing
userchan-tester 3 Kernel HCI User Channel testting
-----
- 369
+ 370


Android end-to-end testing
diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index d019b17..55a5001 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -1628,6 +1628,7 @@ static const char set_adv_on_param[] = { 0x01 };
static const char set_adv_settings_param_1[] = { 0x80, 0x06, 0x00, 0x00 };
static const char set_adv_settings_param_2[] = { 0x81, 0x06, 0x00, 0x00 };
static const char set_adv_on_set_adv_enable_param[] = { 0x01 };
+static const char set_adv_on_set_adv_disable_param[] = { 0x00 };

static const struct generic_data set_adv_on_success_test_1 = {
.setup_settings = settings_le,
@@ -4524,6 +4525,16 @@ static const struct generic_data add_advertising_success_18 = {
.expect_hci_len = sizeof(set_adv_data_uuid),
};

+static const struct generic_data add_advertising_timeout_expired = {
+ .send_opcode = TESTER_NOOP_OPCODE,
+ .expect_alt_ev = MGMT_EV_ADVERTISING_REMOVED,
+ .expect_alt_ev_param = advertising_instance1_param,
+ .expect_alt_ev_len = sizeof(advertising_instance1_param),
+ .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_ENABLE,
+ .expect_hci_param = set_adv_on_set_adv_disable_param,
+ .expect_hci_len = sizeof(set_adv_on_set_adv_disable_param),
+};
+
static const uint8_t remove_advertising_param_1[] = {
0x01,
};
@@ -5117,7 +5128,7 @@ static void setup_add_advertising_timeout(const void *test_data)
memset(cp, 0, sizeof(*cp));

cp->instance = 1;
- cp->timeout = 5;
+ cp->timeout = 1;
cp->adv_data_len = 6;
cp->data[0] = 0x05; /* AD len */
cp->data[1] = 0x08; /* AD type: shortened local name */
@@ -6729,6 +6740,13 @@ int main(int argc, char *argv[])
&add_advertising_success_18,
setup_add_advertising,
test_command_generic);
+ /* An instance should be removed when its timeout has been reached.
+ * Advertising will also be disabled if this was the last instance.
+ */
+ test_bredrle_full("Add Advertising - Success 21 (Timeout expires)",
+ &add_advertising_timeout_expired,
+ setup_add_advertising_timeout,
+ test_command_generic, 3);

test_bredrle("Remove Advertising - Invalid Params 1",
&remove_advertising_fail_1,
--
1.9.1


2015-06-18 01:17:42

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v9 12/16] tools/mgmt-tester: allow for event-only tests

The generic test runner previously expected the test action to always be
a mgmt command. A "no-op" operation is introduced to support tests where
the test scenario is triggered by a timeout rather than a command.
---
tools/mgmt-tester.c | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index bf32192..d019b17 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -437,6 +437,8 @@ struct generic_data {
uint8_t adv_data_len;
};

+# define TESTER_NOOP_OPCODE 0x0000
+
static const char dummy_data[] = { 0x00 };

static const struct generic_data invalid_command_test = {
@@ -5644,6 +5646,11 @@ static void test_command_generic(const void *test_data)
test_add_condition(data);
}

+ if (test->send_opcode == 0x0000) {
+ tester_print("Executing no-op test");
+ return;
+ }
+
tester_print("Sending command 0x%04x", test->send_opcode);

if (test->send_func)
--
1.9.1


2015-06-18 01:17:41

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v9 11/16] tools/mgmt-tester: make test timeout configurable

Currently tests have a hard coded timeout of two seconds. To prepare for
multi-advertising tests we need to be able to extend that timeout, so
that we can test whether instances are switching and expiring as
expected.

This patch therefore introduces a "full" version of the
test_bredrle() macro called test_bredrle_full() that takes an additional
timout parameter.
---
tools/mgmt-tester.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 8e56b6c..bf32192 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -300,7 +300,7 @@ static void test_condition_complete(struct test_data *data)
tester_test_passed();
}

-#define test_bredrle(name, data, setup, func) \
+#define test_bredrle_full(name, data, setup, func, timeout) \
do { \
struct test_data *user; \
user = malloc(sizeof(struct test_data)); \
@@ -316,9 +316,12 @@ static void test_condition_complete(struct test_data *data)
user->unmet_conditions = 0; \
tester_add_full(name, data, \
test_pre_setup, test_setup, func, NULL, \
- test_post_teardown, 2, user, free); \
+ test_post_teardown, timeout, user, free); \
} while (0)

+#define test_bredrle(name, data, setup, func) \
+ test_bredrle_full(name, data, setup, func, 2)
+
#define test_bredr20(name, data, setup, func) \
do { \
struct test_data *user; \
--
1.9.1


2015-06-18 01:17:40

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v9 10/16] tools/mgmt-tester: test adv inst override

This test covers a use case that had not been tested before: When an
advertising instance has already been added and is then added again with
different advertising data, the new advertising data should be
advertised.
---
doc/test-coverage.txt | 4 ++--
tools/mgmt-tester.c | 20 ++++++++++++++++++++
2 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/doc/test-coverage.txt b/doc/test-coverage.txt
index 89d9991..9c8b9bc 100644
--- a/doc/test-coverage.txt
+++ b/doc/test-coverage.txt
@@ -39,7 +39,7 @@ Automated end-to-end testing

Application Count Description
-------------------------------------------
-mgmt-tester 297 Kernel management interface testing
+mgmt-tester 298 Kernel management interface testing
l2cap-tester 27 Kernel L2CAP implementation testing
rfcomm-tester 9 Kernel RFCOMM implementation testing
bnep-tester 1 Kernel BNEP implementation testing
@@ -49,7 +49,7 @@ gap-tester 1 Daemon D-Bus API testing
hci-tester 14 Controller hardware testing
userchan-tester 3 Kernel HCI User Channel testting
-----
- 368
+ 369


Android end-to-end testing
diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 0100f51..8e56b6c 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -4507,6 +4507,18 @@ static const struct generic_data add_advertising_power_off = {
.expect_alt_ev_len = sizeof(advertising_instance1_param),
};

+static const struct generic_data add_advertising_success_18 = {
+ .send_opcode = MGMT_OP_ADD_ADVERTISING,
+ .send_param = add_advertising_param_uuid,
+ .send_len = sizeof(add_advertising_param_uuid),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
+ .expect_status = MGMT_STATUS_SUCCESS,
+ .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
+ .expect_hci_param = set_adv_data_uuid,
+ .expect_hci_len = sizeof(set_adv_data_uuid),
+};
+
static const uint8_t remove_advertising_param_1[] = {
0x01,
};
@@ -6699,6 +6711,14 @@ int main(int argc, char *argv[])
&add_advertising_success_pwron_data,
setup_add_advertising_power_cycle,
test_command_generic);
+ /* Changing an advertising instance while it is still being
+ * advertised will immediately update the advertised data if
+ * there is no other instance to switch to.
+ */
+ test_bredrle("Add Advertising - Success 20 (Add Adv override)",
+ &add_advertising_success_18,
+ setup_add_advertising,
+ test_command_generic);

test_bredrle("Remove Advertising - Invalid Params 1",
&remove_advertising_fail_1,
--
1.9.1


2015-06-18 01:17:39

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v9 09/16] tools/mgmt-tester: keep instances on power cycle

Tests that instances that do not have a timeout will survive a power
cycle.
---
doc/test-coverage.txt | 4 +--
tools/mgmt-tester.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 65 insertions(+), 6 deletions(-)

diff --git a/doc/test-coverage.txt b/doc/test-coverage.txt
index 26e5855..89d9991 100644
--- a/doc/test-coverage.txt
+++ b/doc/test-coverage.txt
@@ -39,7 +39,7 @@ Automated end-to-end testing

Application Count Description
-------------------------------------------
-mgmt-tester 296 Kernel management interface testing
+mgmt-tester 297 Kernel management interface testing
l2cap-tester 27 Kernel L2CAP implementation testing
rfcomm-tester 9 Kernel RFCOMM implementation testing
bnep-tester 1 Kernel BNEP implementation testing
@@ -49,7 +49,7 @@ gap-tester 1 Daemon D-Bus API testing
hci-tester 14 Controller hardware testing
userchan-tester 3 Kernel HCI User Channel testting
-----
- 365
+ 368


Android end-to-end testing
diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index ddf82c1..0100f51 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -4262,7 +4262,7 @@ static const char set_powered_adv_instance_settings_param[] = {
0x81, 0x02, 0x00, 0x00,
};

-static const struct generic_data add_advertising_success_2 = {
+static const struct generic_data add_advertising_success_pwron_data = {
.send_opcode = MGMT_OP_SET_POWERED,
.send_param = set_powered_on_param,
.send_len = sizeof(set_powered_on_param),
@@ -4274,7 +4274,7 @@ static const struct generic_data add_advertising_success_2 = {
.expect_hci_len = sizeof(set_adv_data_test),
};

-static const struct generic_data add_advertising_success_3 = {
+static const struct generic_data add_advertising_success_pwron_enabled = {
.send_opcode = MGMT_OP_SET_POWERED,
.send_param = set_powered_on_param,
.send_len = sizeof(set_powered_on_param),
@@ -5123,6 +5123,59 @@ static void setup_add_advertising_timeout(const void *test_data)
NULL, NULL);
}

+static void setup_power_cycle_callback(uint8_t status, uint16_t length,
+ const void *param, void *user_data)
+{
+ struct test_data *data = tester_get_data();
+ unsigned char param_off[] = { 0x00 };
+
+ if (status != MGMT_STATUS_SUCCESS) {
+ tester_setup_failed();
+ return;
+ }
+
+ mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+ sizeof(param_off), &param_off,
+ NULL, NULL, NULL);
+
+ setup_bthost();
+}
+
+static void setup_add_advertising_power_cycle(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ struct mgmt_cp_add_advertising *cp;
+ unsigned char adv_param[sizeof(*cp) + 6];
+ unsigned char param_on[] = { 0x01 };
+
+ tester_print("Adding instance without timeout and power cycle");
+
+ cp = (struct mgmt_cp_add_advertising *) adv_param;
+ memset(cp, 0, sizeof(*cp));
+
+ cp->instance = 1;
+ cp->adv_data_len = 6;
+ cp->data[0] = 0x05; /* AD len */
+ cp->data[1] = 0x08; /* AD type: shortened local name */
+ cp->data[2] = 't'; /* adv data ... */
+ cp->data[3] = 'e';
+ cp->data[4] = 's';
+ cp->data[5] = 't';
+
+ mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
+ sizeof(param_on), &param_on,
+ NULL, NULL, NULL);
+
+ mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+ sizeof(param_on), &param_on,
+ NULL, NULL, NULL);
+
+ mgmt_send(data->mgmt, MGMT_OP_ADD_ADVERTISING, data->mgmt_index,
+ sizeof(adv_param), adv_param,
+ setup_power_cycle_callback,
+ NULL, NULL);
+}
+
static void setup_set_and_add_advertising(const void *test_data)
{
struct test_data *data = tester_get_data();
@@ -6583,11 +6636,11 @@ int main(int argc, char *argv[])
&add_advertising_success_1,
NULL, test_command_generic);
test_bredrle("Add Advertising - Success 2 (!Powered, Add Adv Inst)",
- &add_advertising_success_2,
+ &add_advertising_success_pwron_data,
setup_add_advertising_not_powered,
test_command_generic);
test_bredrle("Add Advertising - Success 3 (!Powered, Adv Enable)",
- &add_advertising_success_3,
+ &add_advertising_success_pwron_enabled,
setup_add_advertising_not_powered,
test_command_generic);
test_bredrle("Add Advertising - Success 4 (Set Adv on override)",
@@ -6636,10 +6689,16 @@ int main(int argc, char *argv[])
&add_advertising_success_17,
setup_add_advertising_connectable,
test_command_generic);
+ /* Adv instances with a timeout do NOT survive a power cycle. */
test_bredrle("Add Advertising - Success 18 (Power -> off, Remove)",
&add_advertising_power_off,
setup_add_advertising_timeout,
test_command_generic);
+ /* Adv instances without timeout survive a power cycle. */
+ test_bredrle("Add Advertising - Success 19 (Power -> off, Keep)",
+ &add_advertising_success_pwron_data,
+ setup_add_advertising_power_cycle,
+ test_command_generic);

test_bredrle("Remove Advertising - Invalid Params 1",
&remove_advertising_fail_1,
--
1.9.1


2015-06-18 01:17:38

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v9 08/16] tools/mgmt-tester: increase max adv inst

The kernel now allows for up to five concurrent advertising instances.
This patch adapts the tests to the new setting.
---
tools/mgmt-tester.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 089812e..ddf82c1 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -3868,7 +3868,7 @@ static const uint8_t read_adv_features_rsp_1[] = {
0x1f, 0x00, 0x00, 0x00, /* supported flags */
0x1f, /* max_adv_data_len */
0x1f, /* max_scan_rsp_len */
- 0x01, /* max_instances */
+ 0x05, /* max_instances */
0x00, /* num_instances */
};

@@ -3883,7 +3883,7 @@ static const uint8_t read_adv_features_rsp_2[] = {
0x1f, 0x00, 0x00, 0x00, /* supported flags */
0x1f, /* max_adv_data_len */
0x1f, /* max_scan_rsp_len */
- 0x01, /* max_instances */
+ 0x05, /* max_instances */
0x01, /* num_instances */
0x01, /* instance identifiers */
};
--
1.9.1


2015-06-18 01:17:36

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v9 06/16] tools/mgmt-tester: comment add adv test setup

The add advertising test setup data was just a number of arrays with
undocumented hex data. This sometimes made it difficult to understand
the test intent.

Comments have been added to the add advertising mgmt and hci parameter
data arrays to make them more readable and better document the test
intent.
---
tools/mgmt-tester.c | 454 +++++++++++++++++++++++++++++++---------------------
1 file changed, 268 insertions(+), 186 deletions(-)

diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index be0f09a..eda69f7 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -3865,7 +3865,11 @@ static const struct generic_data read_adv_features_invalid_index_test = {
};

static const uint8_t read_adv_features_rsp_1[] = {
- 0x1f, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x01, 0x00,
+ 0x1f, 0x00, 0x00, 0x00, /* supported flags */
+ 0x1f, /* max_adv_data_len */
+ 0x1f, /* max_scan_rsp_len */
+ 0x01, /* max_instances */
+ 0x00, /* num_instances */
};

static const struct generic_data read_adv_features_success_1 = {
@@ -3876,7 +3880,12 @@ static const struct generic_data read_adv_features_success_1 = {
};

static const uint8_t read_adv_features_rsp_2[] = {
- 0x1f, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x01, 0x01, 0x01
+ 0x1f, 0x00, 0x00, 0x00, /* supported flags */
+ 0x1f, /* max_adv_data_len */
+ 0x1f, /* max_scan_rsp_len */
+ 0x01, /* max_instances */
+ 0x01, /* num_instances */
+ 0x01, /* instance identifiers */
};

static const struct generic_data read_adv_features_success_2 = {
@@ -3886,114 +3895,187 @@ static const struct generic_data read_adv_features_success_2 = {
.expect_status = MGMT_STATUS_SUCCESS,
};

-static const uint8_t add_advertising_param_1[] = {
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
-};
-
-static const uint8_t add_advertising_param_2[] = {
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x0a,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
- 0x03, 0x19, 0x40, 0x03,
- 0x05, 0x03, 0x0d, 0x18, 0x0f, 0x18,
-};
-
-static const uint8_t add_advertising_param_3[] = {
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
-};
-
-static const uint8_t add_advertising_param_4[] = {
- 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
-};
-
-static const uint8_t add_advertising_param_5[] = {
- 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
-};
-
-static const uint8_t add_advertising_param_6[] = {
- 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
-};
-
-static const uint8_t add_advertising_param_7[] = {
- 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
-};
-
-static const uint8_t add_advertising_param_8[] = {
- 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
-};
-
-static const uint8_t advertising_instance_param[] = {
+/* simple add advertising command */
+static const uint8_t add_advertising_param_uuid[] = {
+ 0x01, /* adv instance */
+ 0x00, 0x00, 0x00, 0x00, /* flags: none */
+ 0x00, 0x00, /* duration: default */
+ 0x00, 0x00, /* timeout: none */
+ 0x09, /* adv data len */
+ 0x00, /* scan rsp len */
+ /* adv data: */
+ 0x03, /* AD len */
+ 0x02, /* AD type: some 16 bit service class UUIDs */
+ 0x0d, 0x18, /* heart rate monitor */
+ 0x04, /* AD len */
+ 0xff, /* AD type: manufacturer specific data */
+ 0x01, 0x02, 0x03, /* custom advertising data */
+};
+
+/* add advertising with scan response data */
+static const uint8_t add_advertising_param_scanrsp[] = {
+ /* instance, flags, duration, timeout, adv data len: same as before */
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
+ 0x0a, /* scan rsp len */
+ /* adv data: same as before */
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+ /* scan rsp data: */
+ 0x03, /* AD len */
+ 0x19, /* AD type: external appearance */
+ 0x40, 0x03, /* some custom appearance */
+ 0x05, /* AD len */
+ 0x03, /* AD type: all 16 bit service class UUIDs */
+ 0x0d, 0x18, /* heart rate monitor */
+ 0x0f, 0x18, /* battery service */
+};
+
+/* add advertising with timeout */
+static const uint8_t add_advertising_param_timeout[] = {
+ /* instance, flags, duration: same as before */
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x05, 0x00, /* timeout: 5 seconds */
+ /* adv data: same as before */
+ 0x09, 0x00, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+};
+
+/* add advertising with connectable flag */
+static const uint8_t add_advertising_param_connectable[] = {
+ 0x01, /* adv instance */
+ 0x01, 0x00, 0x00, 0x00, /* flags: connectable*/
+ /* duration, timeout, adv/scan data: same as before */
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+};
+
+/* add advertising with general discoverable flag */
+static const uint8_t add_advertising_param_general_discov[] = {
+ 0x01, /* adv instance */
+ 0x02, 0x00, 0x00, 0x00, /* flags: general discoverable*/
+ /* duration, timeout, adv/scan data: same as before */
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+};
+
+/* add advertising with limited discoverable flag */
+static const uint8_t add_advertising_param_limited_discov[] = {
+ 0x01, /* adv instance */
+ 0x04, 0x00, 0x00, 0x00, /* flags: limited discoverable */
+ /* duration, timeout, adv/scan data: same as before */
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+};
+
+/* add advertising with managed flags */
+static const uint8_t add_advertising_param_managed[] = {
+ 0x01, /* adv instance */
+ 0x08, 0x00, 0x00, 0x00, /* flags: managed flags */
+ /* duration, timeout, adv/scan data: same as before */
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+};
+
+/* add advertising with tx power flag */
+static const uint8_t add_advertising_param_txpwr[] = {
+ 0x01, /* adv instance */
+ 0x10, 0x00, 0x00, 0x00, /* flags: tx power */
+ /* duration, timeout, adv/scan data: same as before */
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+};
+
+static const uint8_t advertising_instance1_param[] = {
0x01,
};

-static const uint8_t set_adv_data_1[] = {
- 0x09, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+static const uint8_t set_adv_data_uuid[] = {
+ /* adv data len */
+ 0x09,
+ /* advertise heart rate monitor and manufacturer specific data */
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00,
};

-static const uint8_t set_adv_data_2[] = {
- 0x06, 0x05, 0x08, 0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x00,
+static const uint8_t set_adv_data_test[] = {
+ 0x06, /* adv data len */
+ 0x05, /* AD len */
+ 0x08, /* AD type: shortened local name */
+ 0x74, 0x65, 0x73, 0x74, /* "test" */
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
};

-static const uint8_t set_adv_data_3[] = {
- 0x03, 0x02, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+static const uint8_t set_adv_data_txpwr[] = {
+ 0x03, /* adv data len */
+ 0x02, /* AD len */
+ 0x0a, /* AD type: tx power */
+ 0x00, /* tx power */
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
-};
-
-static const uint8_t set_adv_data_4[] = {
- 0x0c, 0x02, 0x01, 0x02, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff,
- 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const uint8_t set_adv_data_general_discov[] = {
+ 0x0c, /* adv data len */
+ 0x02, /* AD len */
+ 0x01, /* AD type: flags */
+ 0x02, /* general discoverable */
+ 0x03, /* AD len */
+ 0x02, /* AD type: some 16bit service class UUIDs */
+ 0x0d, 0x18, /* heart rate monitor */
+ 0x04, /* AD len */
+ 0xff, /* AD type: manufacturer specific data */
+ 0x01, 0x02, 0x03, /* custom advertising data */
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};

-static const uint8_t set_adv_data_5[] = {
- 0x0c, 0x02, 0x01, 0x01, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff,
- 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+static const uint8_t set_adv_data_limited_discov[] = {
+ 0x0c, /* adv data len */
+ 0x02, /* AD len */
+ 0x01, /* AD type: flags */
+ 0x01, /* limited discoverable */
+ /* rest: same as before */
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
-};
-
-static const uint8_t set_adv_data_6[] = {
- 0x0c, 0x02, 0x01, 0x02, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff,
- 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const uint8_t set_adv_data_uuid_txpwr[] = {
+ 0x0c, /* adv data len */
+ 0x03, /* AD len */
+ 0x02, /* AD type: some 16bit service class UUIDs */
+ 0x0d, 0x18, /* heart rate monitor */
+ 0x04, /* AD len */
+ 0xff, /* AD type: manufacturer specific data */
+ 0x01, 0x02, 0x03, /* custom advertising data */
+ 0x02, /* AD len */
+ 0x0a, /* AD type: tx power */
+ 0x00, /* tx power */
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
-};
-
-static const uint8_t set_adv_data_7[] = {
- 0x0c, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
- 0x02, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const uint8_t set_scan_rsp_uuid[] = {
+ 0x0a, /* scan rsp data len */
+ 0x03, /* AD len */
+ 0x19, /* AD type: external appearance */
+ 0x40, 0x03, /* some custom appearance */
+ 0x05, /* AD len */
+ 0x03, /* AD type: all 16 bit service class UUIDs */
+ 0x0d, 0x18, 0x0f, 0x18, /* heart rate monitor, battery service */
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
-};
-
-static const uint8_t set_scan_rsp_1[] = {
- 0x0a, 0x03, 0x19, 0x40, 0x03, 0x05, 0x03, 0x0d, 0x18, 0x0f,
- 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
+ 0x00,
};

static const uint8_t add_advertising_invalid_param_1[] = {
@@ -4067,8 +4149,8 @@ static const uint8_t add_advertising_invalid_param_10[] = {
static const struct generic_data add_advertising_fail_1 = {
.setup_settings = settings_powered,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_1,
- .send_len = sizeof(add_advertising_param_1),
+ .send_param = add_advertising_param_uuid,
+ .send_len = sizeof(add_advertising_param_uuid),
.expect_status = MGMT_STATUS_REJECTED,
};

@@ -4155,25 +4237,25 @@ static const struct generic_data add_advertising_fail_11 = {
static const struct generic_data add_advertising_fail_12 = {
.setup_settings = settings_le,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_3,
- .send_len = sizeof(add_advertising_param_3),
+ .send_param = add_advertising_param_timeout,
+ .send_len = sizeof(add_advertising_param_timeout),
.expect_status = MGMT_STATUS_REJECTED,
};

static const struct generic_data add_advertising_success_1 = {
.setup_settings = settings_powered_le,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_1,
- .send_len = sizeof(add_advertising_param_1),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_uuid,
+ .send_len = sizeof(add_advertising_param_uuid),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_alt_ev = MGMT_EV_ADVERTISING_ADDED,
- .expect_alt_ev_param = advertising_instance_param,
- .expect_alt_ev_len = sizeof(advertising_instance_param),
+ .expect_alt_ev_param = advertising_instance1_param,
+ .expect_alt_ev_len = sizeof(advertising_instance1_param),
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
- .expect_hci_param = set_adv_data_1,
- .expect_hci_len = sizeof(set_adv_data_1),
+ .expect_hci_param = set_adv_data_uuid,
+ .expect_hci_len = sizeof(set_adv_data_uuid),
};

static const char set_powered_adv_instance_settings_param[] = {
@@ -4188,8 +4270,8 @@ static const struct generic_data add_advertising_success_2 = {
.expect_param = set_powered_adv_instance_settings_param,
.expect_len = sizeof(set_powered_adv_instance_settings_param),
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
- .expect_hci_param = set_adv_data_2,
- .expect_hci_len = sizeof(set_adv_data_2),
+ .expect_hci_param = set_adv_data_test,
+ .expect_hci_len = sizeof(set_adv_data_test),
};

static const struct generic_data add_advertising_success_3 = {
@@ -4212,8 +4294,8 @@ static const struct generic_data add_advertising_success_4 = {
.expect_param = set_adv_settings_param_2,
.expect_len = sizeof(set_adv_settings_param_2),
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
- .expect_hci_param = set_adv_data_3,
- .expect_hci_len = sizeof(set_adv_data_3),
+ .expect_hci_param = set_adv_data_txpwr,
+ .expect_hci_len = sizeof(set_adv_data_txpwr),
};

static const char set_adv_off_param[] = { 0x00 };
@@ -4226,49 +4308,49 @@ static const struct generic_data add_advertising_success_5 = {
.expect_param = set_powered_adv_instance_settings_param,
.expect_len = sizeof(set_powered_adv_instance_settings_param),
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
- .expect_hci_param = set_adv_data_2,
- .expect_hci_len = sizeof(set_adv_data_2),
+ .expect_hci_param = set_adv_data_test,
+ .expect_hci_len = sizeof(set_adv_data_test),
};

static const struct generic_data add_advertising_success_6 = {
.setup_settings = settings_powered_le,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_2,
- .send_len = sizeof(add_advertising_param_2),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_scanrsp,
+ .send_len = sizeof(add_advertising_param_scanrsp),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_alt_ev = MGMT_EV_ADVERTISING_ADDED,
- .expect_alt_ev_param = advertising_instance_param,
- .expect_alt_ev_len = sizeof(advertising_instance_param),
+ .expect_alt_ev_param = advertising_instance1_param,
+ .expect_alt_ev_len = sizeof(advertising_instance1_param),
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
- .expect_hci_param = set_adv_data_1,
- .expect_hci_len = sizeof(set_adv_data_1),
+ .expect_hci_param = set_adv_data_uuid,
+ .expect_hci_len = sizeof(set_adv_data_uuid),
};

static const struct generic_data add_advertising_success_7 = {
.setup_settings = settings_powered_le,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_2,
- .send_len = sizeof(add_advertising_param_2),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_scanrsp,
+ .send_len = sizeof(add_advertising_param_scanrsp),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_alt_ev = MGMT_EV_ADVERTISING_ADDED,
- .expect_alt_ev_param = advertising_instance_param,
- .expect_alt_ev_len = sizeof(advertising_instance_param),
+ .expect_alt_ev_param = advertising_instance1_param,
+ .expect_alt_ev_len = sizeof(advertising_instance1_param),
.expect_hci_command = BT_HCI_CMD_LE_SET_SCAN_RSP_DATA,
- .expect_hci_param = set_scan_rsp_1,
- .expect_hci_len = sizeof(set_scan_rsp_1),
+ .expect_hci_param = set_scan_rsp_uuid,
+ .expect_hci_len = sizeof(set_scan_rsp_uuid),
};

static const struct generic_data add_advertising_success_8 = {
.setup_settings = settings_powered_le,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_4,
- .send_len = sizeof(add_advertising_param_4),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_connectable,
+ .send_len = sizeof(add_advertising_param_connectable),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_PARAMETERS,
.expect_hci_param = set_connectable_on_adv_param,
@@ -4278,53 +4360,53 @@ static const struct generic_data add_advertising_success_8 = {
static const struct generic_data add_advertising_success_9 = {
.setup_settings = settings_powered_le,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_5,
- .send_len = sizeof(add_advertising_param_5),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_general_discov,
+ .send_len = sizeof(add_advertising_param_general_discov),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
- .expect_hci_param = set_adv_data_4,
- .expect_hci_len = sizeof(set_adv_data_4),
+ .expect_hci_param = set_adv_data_general_discov,
+ .expect_hci_len = sizeof(set_adv_data_general_discov),
};

static const struct generic_data add_advertising_success_10 = {
.setup_settings = settings_powered_le,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_6,
- .send_len = sizeof(add_advertising_param_6),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_limited_discov,
+ .send_len = sizeof(add_advertising_param_limited_discov),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
- .expect_hci_param = set_adv_data_5,
- .expect_hci_len = sizeof(set_adv_data_5),
+ .expect_hci_param = set_adv_data_limited_discov,
+ .expect_hci_len = sizeof(set_adv_data_limited_discov),
};

static const struct generic_data add_advertising_success_11 = {
.setup_settings = settings_powered_le_discoverable,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_7,
- .send_len = sizeof(add_advertising_param_7),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_managed,
+ .send_len = sizeof(add_advertising_param_managed),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
- .expect_hci_param = set_adv_data_6,
- .expect_hci_len = sizeof(set_adv_data_6),
+ .expect_hci_param = set_adv_data_general_discov,
+ .expect_hci_len = sizeof(set_adv_data_general_discov),
};

static const struct generic_data add_advertising_success_12 = {
.setup_settings = settings_powered_le_discoverable,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_8,
- .send_len = sizeof(add_advertising_param_8),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_txpwr,
+ .send_len = sizeof(add_advertising_param_txpwr),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
- .expect_hci_param = set_adv_data_7,
- .expect_hci_len = sizeof(set_adv_data_7),
+ .expect_hci_param = set_adv_data_uuid_txpwr,
+ .expect_hci_len = sizeof(set_adv_data_uuid_txpwr),
};

static uint16_t settings_powered_le_connectable[] = {
@@ -4346,10 +4428,10 @@ static uint8_t set_connectable_off_scan_adv_param[] = {
static const struct generic_data add_advertising_success_13 = {
.setup_settings = settings_powered_le,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_2,
- .send_len = sizeof(add_advertising_param_2),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_scanrsp,
+ .send_len = sizeof(add_advertising_param_scanrsp),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_PARAMETERS,
.expect_hci_param = set_connectable_off_scan_adv_param,
@@ -4359,10 +4441,10 @@ static const struct generic_data add_advertising_success_13 = {
static const struct generic_data add_advertising_success_14 = {
.setup_settings = settings_powered_le,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_1,
- .send_len = sizeof(add_advertising_param_1),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_uuid,
+ .send_len = sizeof(add_advertising_param_uuid),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_PARAMETERS,
.expect_hci_param = set_connectable_off_adv_param,
@@ -4372,10 +4454,10 @@ static const struct generic_data add_advertising_success_14 = {
static const struct generic_data add_advertising_success_15 = {
.setup_settings = settings_powered_le_connectable,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_1,
- .send_len = sizeof(add_advertising_param_1),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_uuid,
+ .send_len = sizeof(add_advertising_param_uuid),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_PARAMETERS,
.expect_hci_param = set_connectable_on_adv_param,
@@ -4413,7 +4495,7 @@ static const char set_powered_off_le_settings_param[] = {
0x80, 0x02, 0x00, 0x00
};

-static const struct generic_data add_advertising_timeout_power_off = {
+static const struct generic_data add_advertising_power_off = {
.send_opcode = MGMT_OP_SET_POWERED,
.send_param = set_powered_off_param,
.send_len = sizeof(set_powered_off_param),
@@ -4421,8 +4503,8 @@ static const struct generic_data add_advertising_timeout_power_off = {
.expect_param = set_powered_off_le_settings_param,
.expect_len = sizeof(set_powered_off_le_settings_param),
.expect_alt_ev = MGMT_EV_ADVERTISING_REMOVED,
- .expect_alt_ev_param = advertising_instance_param,
- .expect_alt_ev_len = sizeof(advertising_instance_param),
+ .expect_alt_ev_param = advertising_instance1_param,
+ .expect_alt_ev_len = sizeof(advertising_instance1_param),
};

static const uint8_t remove_advertising_param_1[] = {
@@ -4448,8 +4530,8 @@ static const struct generic_data remove_advertising_success_1 = {
.expect_param = remove_advertising_param_1,
.expect_len = sizeof(remove_advertising_param_1),
.expect_alt_ev = MGMT_EV_ADVERTISING_REMOVED,
- .expect_alt_ev_param = advertising_instance_param,
- .expect_alt_ev_len = sizeof(advertising_instance_param),
+ .expect_alt_ev_param = advertising_instance1_param,
+ .expect_alt_ev_len = sizeof(advertising_instance1_param),
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_ENABLE,
.expect_hci_param = set_adv_off_param,
.expect_hci_len = sizeof(set_adv_off_param),
@@ -4463,8 +4545,8 @@ static const struct generic_data remove_advertising_success_2 = {
.expect_param = remove_advertising_param_2,
.expect_len = sizeof(remove_advertising_param_2),
.expect_alt_ev = MGMT_EV_ADVERTISING_REMOVED,
- .expect_alt_ev_param = advertising_instance_param,
- .expect_alt_ev_len = sizeof(advertising_instance_param),
+ .expect_alt_ev_param = advertising_instance1_param,
+ .expect_alt_ev_len = sizeof(advertising_instance1_param),
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_ENABLE,
.expect_hci_param = set_adv_off_param,
.expect_hci_len = sizeof(set_adv_off_param),
@@ -4914,9 +4996,9 @@ static void setup_add_advertising_not_powered(const void *test_data)

cp->instance = 1;
cp->adv_data_len = 6;
- cp->data[0] = 0x05;
- cp->data[1] = 0x08;
- cp->data[2] = 't';
+ cp->data[0] = 0x05; /* AD len */
+ cp->data[1] = 0x08; /* AD type: shortened local name */
+ cp->data[2] = 't'; /* adv data ... */
cp->data[3] = 'e';
cp->data[4] = 's';
cp->data[5] = 't';
@@ -4945,9 +5027,9 @@ static void setup_add_advertising(const void *test_data)

cp->instance = 1;
cp->adv_data_len = 6;
- cp->data[0] = 0x05;
- cp->data[1] = 0x08;
- cp->data[2] = 't';
+ cp->data[0] = 0x05; /* AD len */
+ cp->data[1] = 0x08; /* AD type: shortened local name */
+ cp->data[2] = 't'; /* adv data ... */
cp->data[3] = 'e';
cp->data[4] = 's';
cp->data[5] = 't';
@@ -4980,9 +5062,9 @@ static void setup_add_advertising_connectable(const void *test_data)

cp->instance = 1;
cp->adv_data_len = 6;
- cp->data[0] = 0x05;
- cp->data[1] = 0x08;
- cp->data[2] = 't';
+ cp->data[0] = 0x05; /* AD len */
+ cp->data[1] = 0x08; /* AD type: shortened local name */
+ cp->data[2] = 't'; /* adv data ... */
cp->data[3] = 'e';
cp->data[4] = 's';
cp->data[5] = 't';
@@ -5020,9 +5102,9 @@ static void setup_add_advertising_timeout(const void *test_data)
cp->instance = 1;
cp->timeout = 5;
cp->adv_data_len = 6;
- cp->data[0] = 0x05;
- cp->data[1] = 0x08;
- cp->data[2] = 't';
+ cp->data[0] = 0x05; /* AD len */
+ cp->data[1] = 0x08; /* AD type: shortened local name */
+ cp->data[2] = 't'; /* adv data ... */
cp->data[3] = 'e';
cp->data[4] = 's';
cp->data[5] = 't';
@@ -5055,9 +5137,9 @@ static void setup_set_and_add_advertising(const void *test_data)

cp->instance = 1;
cp->adv_data_len = 6;
- cp->data[0] = 0x05;
- cp->data[1] = 0x08;
- cp->data[2] = 't';
+ cp->data[0] = 0x05; /* AD len */
+ cp->data[1] = 0x08; /* AD type: shortened local name */
+ cp->data[2] = 't'; /* adv data ... */
cp->data[3] = 'e';
cp->data[4] = 's';
cp->data[5] = 't';
@@ -6498,7 +6580,7 @@ int main(int argc, char *argv[])
&add_advertising_fail_12,
NULL, test_command_generic);
test_bredrle("Add Advertising - Timeout Power off",
- &add_advertising_timeout_power_off,
+ &add_advertising_power_off,
setup_add_advertising_timeout,
test_command_generic);
test_bredrle("Add Advertising - Success 1",
--
1.9.1


2015-06-18 01:17:37

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v9 07/16] tools/mgmt-tester: rename add adv tests

The add advertisement tests were named a bit inconsistently and the test
intent was not always clear from the naming of the test. This has been
improved by introducing a somewhat more consistent naming scheme and
adding additional hints wrt the test intent.
---
tools/mgmt-tester.c | 44 ++++++++++++++++++++++----------------------
1 file changed, 22 insertions(+), 22 deletions(-)

diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index eda69f7..089812e 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -6576,70 +6576,70 @@ int main(int argc, char *argv[])
test_le("Add Advertising - Invalid Params 10 (ScRsp too long)",
&add_advertising_fail_11,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Timeout Not Powered",
+ test_bredrle("Add Advertising - Rejected (Timeout, !Powered)",
&add_advertising_fail_12,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Timeout Power off",
- &add_advertising_power_off,
- setup_add_advertising_timeout,
- test_command_generic);
- test_bredrle("Add Advertising - Success 1",
+ test_bredrle("Add Advertising - Success 1 (Powered, Add Adv Inst)",
&add_advertising_success_1,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 2",
+ test_bredrle("Add Advertising - Success 2 (!Powered, Add Adv Inst)",
&add_advertising_success_2,
setup_add_advertising_not_powered,
test_command_generic);
- test_bredrle("Add Advertising - Success 3",
+ test_bredrle("Add Advertising - Success 3 (!Powered, Adv Enable)",
&add_advertising_success_3,
setup_add_advertising_not_powered,
test_command_generic);
- test_bredrle("Add Advertising - Set Advertising on override 1",
+ test_bredrle("Add Advertising - Success 4 (Set Adv on override)",
&add_advertising_success_4,
setup_add_advertising,
test_command_generic);
- test_bredrle("Add Advertising - Set Advertising off override 2",
+ test_bredrle("Add Advertising - Success 5 (Set Adv off override)",
&add_advertising_success_5,
setup_set_and_add_advertising,
test_command_generic);
- test_bredrle("Add Advertising - Success 4",
+ test_bredrle("Add Advertising - Success 6 (Scan Rsp Dta, Adv ok)",
&add_advertising_success_6,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 5",
+ test_bredrle("Add Advertising - Success 7 (Scan Rsp Dta, Scan ok) ",
&add_advertising_success_7,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 6 - Flag 0",
+ test_bredrle("Add Advertising - Success 8 (Connectable Flag)",
&add_advertising_success_8,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 7 - Flag 1",
+ test_bredrle("Add Advertising - Success 9 (General Discov Flag)",
&add_advertising_success_9,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 8 - Flag 2",
+ test_bredrle("Add Advertising - Success 10 (Limited Discov Flag)",
&add_advertising_success_10,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 8 - Flag 3",
+ test_bredrle("Add Advertising - Success 11 (Managed Flags)",
&add_advertising_success_11,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 9 - Flag 4",
+ test_bredrle("Add Advertising - Success 12 (TX Power Flag)",
&add_advertising_success_12,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 10 - ADV_SCAN_IND",
+ test_bredrle("Add Advertising - Success 13 (ADV_SCAN_IND)",
&add_advertising_success_13,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 11 - ADV_NONCONN_IND",
+ test_bredrle("Add Advertising - Success 14 (ADV_NONCONN_IND)",
&add_advertising_success_14,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 12 - ADV_IND",
+ test_bredrle("Add Advertising - Success 15 (ADV_IND)",
&add_advertising_success_15,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 13 - connectable -> on",
+ test_bredrle("Add Advertising - Success 16 (Connectable -> on)",
&add_advertising_success_16,
setup_add_advertising,
test_command_generic);
- test_bredrle("Add Advertising - Success 14 - connectable -> off",
+ test_bredrle("Add Advertising - Success 17 (Connectable -> off)",
&add_advertising_success_17,
setup_add_advertising_connectable,
test_command_generic);
+ test_bredrle("Add Advertising - Success 18 (Power -> off, Remove)",
+ &add_advertising_power_off,
+ setup_add_advertising_timeout,
+ test_command_generic);

test_bredrle("Remove Advertising - Invalid Params 1",
&remove_advertising_fail_1,
--
1.9.1


2015-06-18 01:17:35

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v9 05/16] tools/mgmt-tester: expect 0 rp when removing all adv inst

The kernel would previously return a hard coded instance value of 0x01
even when removing multiple advertising instances. The correct behavior,
though, would be to return zero when multiple instances have been
removed. This corresponds to the semantics of the mgmt API call made in
the first place.

A fix for this problem has been introduced in the kernel. Now the
corresponding test is updated to reflect that logic.
---
tools/mgmt-tester.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index b581514..be0f09a 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -4460,8 +4460,8 @@ static const struct generic_data remove_advertising_success_2 = {
.send_param = remove_advertising_param_2,
.send_len = sizeof(remove_advertising_param_2),
.expect_status = MGMT_STATUS_SUCCESS,
- .expect_param = remove_advertising_param_1,
- .expect_len = sizeof(remove_advertising_param_1),
+ .expect_param = remove_advertising_param_2,
+ .expect_len = sizeof(remove_advertising_param_2),
.expect_alt_ev = MGMT_EV_ADVERTISING_REMOVED,
.expect_alt_ev_param = advertising_instance_param,
.expect_alt_ev_len = sizeof(advertising_instance_param),
--
1.9.1


2015-06-18 01:17:34

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v9 04/16] tools/mgmt-tester: error message when unexp params

The tester already issues debug messages for unexpected HCI commands but
not for unexpected mgmt command return values. To facilitate test
debugging this patch adds a debug message for unexpected mgmt command
return values, too.
---
tools/mgmt-tester.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 0145435..b581514 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -5389,12 +5389,14 @@ static void command_generic_callback(uint8_t status, uint16_t length,
expect_param = test->expect_func(&expect_len);

if (length != expect_len) {
+ tester_warn("Invalid cmd response parameter size");
tester_test_failed();
return;
}

if (expect_param && expect_len > 0 &&
memcmp(param, expect_param, length)) {
+ tester_warn("Unexpected cmd response parameter value");
tester_test_failed();
return;
}
--
1.9.1


2015-06-18 01:17:33

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v9 03/16] tools/btmgmt: make inst duration configurable

Now that the kernel actually does respect the instance's duration
parameter it should be accessible via btmgmt. An additional parameter
for the add-adv command is therefore being introduced.
---
tools/btmgmt.c | 28 +++++++++++++++++-----------
1 file changed, 17 insertions(+), 11 deletions(-)

diff --git a/tools/btmgmt.c b/tools/btmgmt.c
index 8f8bca1..a100f53 100644
--- a/tools/btmgmt.c
+++ b/tools/btmgmt.c
@@ -3890,15 +3890,16 @@ static void add_adv_rsp(uint8_t status, uint16_t len, const void *param,
static void add_adv_usage(void)
{
print("Usage: add-adv [options] <instance_id>\nOptions:\n"
- "\t -u, --uuid <uuid> Service UUID\n"
- "\t -d, --adv-data <data> Advertising Data bytes\n"
- "\t -s, --scan-rsp <data> Scan Response Data bytes\n"
- "\t -t, --timeout <timeout> Timeout in seconds\n"
- "\t -c, --connectable \"connectable\" flag\n"
- "\t -g, --general-discov \"general-discoverable\" flag\n"
- "\t -l, --limited-discov \"limited-discoverable\" flag\n"
- "\t -m, --managed-flags \"managed-flags\" flag\n"
- "\t -p, --tx-power \"tx-power\" flag\n"
+ "\t -u, --uuid <uuid> Service UUID\n"
+ "\t -d, --adv-data <data> Advertising Data bytes\n"
+ "\t -s, --scan-rsp <data> Scan Response Data bytes\n"
+ "\t -t, --timeout <timeout> Timeout in seconds\n"
+ "\t -D, --duration <duration> Duration in seconds\n"
+ "\t -c, --connectable \"connectable\" flag\n"
+ "\t -g, --general-discov \"general-discoverable\" flag\n"
+ "\t -l, --limited-discov \"limited-discoverable\" flag\n"
+ "\t -m, --managed-flags \"managed-flags\" flag\n"
+ "\t -p, --tx-power \"tx-power\" flag\n"
"e.g.:\n"
"\tadd-adv -u 180d -u 180f -d 080954657374204C45 1");
}
@@ -3909,6 +3910,7 @@ static struct option add_adv_options[] = {
{ "adv-data", 1, 0, 'd' },
{ "scan-rsp", 1, 0, 's' },
{ "timeout", 1, 0, 't' },
+ { "duration", 1, 0, 'D' },
{ "connectable", 0, 0, 'c' },
{ "general-discov", 0, 0, 'g' },
{ "limited-discov", 0, 0, 'l' },
@@ -3970,14 +3972,14 @@ static void cmd_add_adv(struct mgmt *mgmt, uint16_t index,
uint8_t uuids[MAX_AD_UUID_BYTES];
size_t uuid_bytes = 0;
uint8_t uuid_type = 0;
- uint16_t timeout = 0;
+ uint16_t timeout = 0, duration = 0;
uint8_t instance;
uuid_t uuid;
bool success = false;
bool quit = true;
uint32_t flags = 0;

- while ((opt = getopt_long(argc, argv, "+u:d:s:t:cglmph",
+ while ((opt = getopt_long(argc, argv, "+u:d:s:t:D:cglmph",
add_adv_options, NULL)) != -1) {
switch (opt) {
case 'u':
@@ -4038,6 +4040,9 @@ static void cmd_add_adv(struct mgmt *mgmt, uint16_t index,
case 't':
timeout = strtol(optarg, NULL, 0);
break;
+ case 'D':
+ duration = strtol(optarg, NULL, 0);
+ break;
case 'c':
flags |= MGMT_ADV_FLAG_CONNECTABLE;
break;
@@ -4086,6 +4091,7 @@ static void cmd_add_adv(struct mgmt *mgmt, uint16_t index,
cp->instance = instance;
put_le32(flags, &cp->flags);
put_le16(timeout, &cp->timeout);
+ put_le16(duration, &cp->duration);
cp->adv_data_len = adv_len + uuid_bytes;
cp->scan_rsp_len = scan_rsp_len;

--
1.9.1


2015-06-18 01:17:32

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v9 02/16] doc/mgmt-api: fix typos

This patch fixes a few minor typos and grammar errors in the mgmt api
spec.
---
doc/mgmt-api.txt | 32 ++++++++++++++++----------------
1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/doc/mgmt-api.txt b/doc/mgmt-api.txt
index ffa774d..18d7db1 100644
--- a/doc/mgmt-api.txt
+++ b/doc/mgmt-api.txt
@@ -386,7 +386,7 @@ Set Connectable Command
and for LE controllers it changes the advertising type. For
dual mode controllers it affects both settings.

- For LE capable controllers the connectable setting takes affect
+ For LE capable controllers the connectable setting takes effect
when advertising is enabled (peripheral) or when directed
advertising events are received (central).

@@ -887,7 +887,7 @@ Get Connections Command
Address2 { }
...

- This command is used to retreive a list of currently connected
+ This command is used to retrieve a list of currently connected
devices.

Possible values for the Address_Type parameter:
@@ -1039,7 +1039,7 @@ Pair Device Command

To allow tracking of which resolvable random address changed
into which identity address, the New Identity Resolving Key
- event will be send before receiving Command Complete event
+ event will be sent before receiving Command Complete event
for this command.

This command can only be used when the controller is powered.
@@ -1480,7 +1480,7 @@ Block Device Command
Address_Type (1 Octet)

This command is used to add a device to the list of devices
- which should be blocked from being connect to the local
+ which should be blocked from being connected to the local
controller.

Possible values for the Address_Type parameter:
@@ -1488,7 +1488,7 @@ Block Device Command
1 LE Public
2 LE Random

- For Low Energy devices, the blocking of a device take presedence
+ For Low Energy devices, the blocking of a device takes precedence
over auto-connection actions provided by Add Device. Blocked
devices will not be auto-connected or even reported when found
during background scanning. If the controller is connectable
@@ -1558,9 +1558,9 @@ Set Device ID Command
0x0001 Bluetooth SIG
0x0002 USB Implementer’s Forum

- The information are put into the EIR data. If the controller does
+ The information is put into the EIR data. If the controller does
not support EIR or if SSP is disabled, this command will still
- succeed. The information are stored for later use and will survive
+ succeed. The information is stored for later use and will survive
toggling SSP on and off.

This command generates a Command Complete event on success or
@@ -1605,7 +1605,7 @@ Set Advertising Command
The value 0x02 should be the preferred mode of operation when
implementing peripheral mode.

- Using this command will temporarily deactive any configuration
+ Using this command will temporarily deactivate any configuration
made by the Add Advertising command. This command takes precedence.
Once a Set Advertising command with value 0x00 is issued any
previously made configurations via Add/Remove Advertising, including
@@ -1979,17 +1979,17 @@ Add Device Command
2 Auto-connect remote device

With the Action 0, when the device is found, a new Device Found
- event will be send indicating this device is available. This
+ event will be sent indicating this device is available. This
action is only valid for LE Public and LE Random address types.

With the Action 1, the device is allowed to connect. For BR/EDR
address type this means an incoming connection. For LE Public
and LE Random address types, a connection will be established
to devices using directed advertising. If successful a Device
- Connected event will be send.
+ Connected event will be sent.

With the Action 2, when the device is found, it will be connected
- and if successful a Device Connected event will be send. This
+ and if successful a Device Connected event will be sent. This
action is only valid for LE Public and LE Random address types.

When a device is blocked using Block Device command, then it is
@@ -2220,8 +2220,8 @@ Set Public Address Command

For a fully configured controller, the current controller index
will become invalid and an Unconfigured Index Removed event will
- be send. Once the address has been successfully changed an Index
- Added event will be send. There is no guarantee that the controller
+ be sent. Once the address has been successfully changed an Index
+ Added event will be sent. There is no guarantee that the controller
index stays the same.

All previous configured parameters and settings are lost when
@@ -2536,7 +2536,7 @@ Read Advertising Features Command
however might decrease the actual available length in these
data fields.

- With Num_Instances and Instance array the current occupied
+ With Num_Instances and Instance array the currently occupied
Instance identifiers can be retrieved.

This command generates a Command Complete event on success or
@@ -2625,13 +2625,13 @@ Add Advertising Command

The Timeout parameter configures the life-time of an Instance. In
case the value 0 is used it indicates no expiration time. If a
- timeout value is provided, then the advertising Instace will be
+ timeout value is provided, then the advertising Instance will be
automatically removed when the timeout passes. The value for the
timeout is in seconds. Powering down a controller will invalidate
all advertising Instances and it is not possible to add a new
Instance with a timeout when the controller is powered down.

- When a Timeout is provided, then the Duration substracts from
+ When a Timeout is provided, then the Duration subtracts from
the actual Timeout value of that Instance. For example an Instance
with Timeout of 5 and Duration of 2 will be scheduled exactly 3
times, twice with 2 seconds and once with one second. Other
--
1.9.1


2015-06-18 01:17:31

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v9 01/16] doc/mgmt-api: multi-adv implementation details

A few additional decisions have been made while implementing the
multi-advertising feature where the mgmt api spec was leaving room for
interpretation. These changes are being documented in this patch.
---
doc/mgmt-api.txt | 73 ++++++++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 61 insertions(+), 12 deletions(-)

diff --git a/doc/mgmt-api.txt b/doc/mgmt-api.txt
index 4b97aad..ffa774d 100644
--- a/doc/mgmt-api.txt
+++ b/doc/mgmt-api.txt
@@ -305,6 +305,15 @@ Set Powered Command
switching the controller off will expire this timeout and
disable discoverable.

+ Settings programmed via Set Advertising and Add/Remove
+ Advertising while the controller was powered off will be activated
+ when powering the controller on.
+
+ Switching the controller off will permanently cancel and remove
+ all advertising instances with a timeout set, i.e. time limited
+ advertising instances are not being remembered across power cycles.
+ Advertising Removed events will be issued accordingly.
+
This command generates a Command Complete event on success or
a Command Status event on failure.

@@ -585,6 +594,10 @@ Set Low Energy Command
In case the kernel subsystem does not support Low Energy or the
controller does not either, the command will fail regardless.

+ Disabling LE support will permanently disable and remove all
+ advertising instances configured with the Add Advertising
+ command. Advertising Removed events will be issued accordingly.
+
This command generates a Command Complete event on success or
a Command Status event on failure.

@@ -1594,6 +1607,10 @@ Set Advertising Command

Using this command will temporarily deactive any configuration
made by the Add Advertising command. This command takes precedence.
+ Once a Set Advertising command with value 0x00 is issued any
+ previously made configurations via Add/Remove Advertising, including
+ such changes made while Set Advertising was active, will be re-
+ enabled.

A pre-requisite is that LE is already enabled, otherwise this
command will return a "rejected" response.
@@ -2548,9 +2565,11 @@ Add Advertising Command
can be used to switch a Bluetooth Low Energy controller into
advertising mode.

- Added advertising information with this command will be ignored
- when using the Set Advertising command to enable advertising. The
- usage of Set Advertising command take precedence over this command.
+ Added advertising information with this command will not be visible
+ immediately if advertising is enabled via the Set Advertising
+ command. The usage of the Set Advertising command takes precedence
+ over this command. Instance information is stored and will be
+ advertised once advertising via Set Advertising has been disabled.

The Instance identifier is a value between 1 and the number of
supported instances. The value 0 is reserved.
@@ -2593,13 +2612,16 @@ Add Advertising Command
broadcaster role.

The Duration parameter configures the length of an Instance. The
- value is in seconds and a value of 0 indicates an automatic choice
- for the Duration. If only one advertising Instance has been added,
- then the Duration value will be ignored. It only applies for the
- case where multiple Instances are configured. In that case every
- Instance will be available for the Duration time and after that
- it switches to the next one. This is a simple round-robin based
- approach.
+ value is in seconds.
+
+ A value of 0 indicates a default value is chosen for the
+ Duration. The default is 2 seconds.
+
+ If only one advertising Instance has been added, then the Duration
+ value will be ignored. It only applies for the case where multiple
+ Instances are configured. In that case every Instance will be
+ available for the Duration time and after that it switches to
+ the next one. This is a simple round-robin based approach.

The Timeout parameter configures the life-time of an Instance. In
case the value 0 is used it indicates no expiration time. If a
@@ -2611,8 +2633,24 @@ Add Advertising Command

When a Timeout is provided, then the Duration substracts from
the actual Timeout value of that Instance. For example an Instance
- with Timeout of 6 and Duration of 2 will be scheduled exactly 3
- times. Other Instances have no influence on the Timeout.
+ with Timeout of 5 and Duration of 2 will be scheduled exactly 3
+ times, twice with 2 seconds and once with one second. Other
+ Instances have no influence on the Timeout.
+
+ Re-adding an already existing instance (i.e. issuing the Add
+ Advertising command with an Instance identifier of an existing
+ instance) will update that instance's configuration.
+
+ An instance being added or changed while another instance is
+ being advertised will not be visible immediately but only when
+ the new/changed instance is being scheduled by the round robin
+ advertising algorithm.
+
+ Changes to an instance that is currently being advertised will
+ cancel that instance and switch to the next instance. The changes
+ will be visible the next time the instance is scheduled for
+ advertising. In case a single instance is active, this means
+ that changes will be visible right away.

A pre-requisite is that LE is already enabled, otherwise this
command will return a "rejected" response.
@@ -2645,6 +2683,17 @@ Remove Advertising Command
When the Instance parameter is zero, then all previously added
advertising Instances will be removed.

+ Removing advertising information with this command will not be
+ visible as long as advertising is enabled via the Set Advertising
+ command. The usage of the Set Advertising command takes precedence
+ over this command. Changes to Instance information are stored and
+ will be advertised once advertising via Set Advertising has been
+ disabled.
+
+ Removing an instance while it is being advertised will immediately
+ cancel the instance, even when it has been advertised less then its
+ configured Timeout or Duration.
+
This command can be used when the controller is not powered and
all settings will be programmed once powered.

--
1.9.1


2015-06-18 01:17:30

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v9 00/16] Multi-advertising

patch set accompanying the introduction of a multi-advertising
infrastructure in the kernel

v1 ... v4:
- fix tests to test for correct behavior when removing all adv instances
by passing in the 0x00 instance identifier

v4 -> v5:
- factored userland code changes into a separate change set for easier
review

v5 -> v6:
- documented add advertising test setup
- renamed add advertising tests to make them more readable
- added test to reproduce a bug found by Marcel (executing add-adv twice
for the same instance should override the adv data)

v6 -> v7:
- correctly split mangled patches

v7 -> v8:
- several additional test documentation improvements
- documenting multi-adv implementation details in the mgmt api doc
- made the debugging of cmd response messages easier
- made the duration parameter accessible via btmgmt
- provided test infrastructure for timed tests
- fix duplicate code
- fix a few typos
- added test for advertising timeout
- added test for le off
- added multi-adv tests

v8 -> v9 (due to Marcel's review):
- improved and fixed changes to mgmt-api.txt
- added a test that guarantees that instances without a timeout survive
a power cycle

Florian Grandel (16):
doc/mgmt-api: multi-adv implementation details
doc/mgmt-api: fix typos
tools/btmgmt: make inst duration configurable
tools/mgmt-tester: error message when unexp params
tools/mgmt-tester: expect 0 rp when removing all adv inst
tools/mgmt-tester: comment add adv test setup
tools/mgmt-tester: rename add adv tests
tools/mgmt-tester: increase max adv inst
tools/mgmt-tester: keep instances on power cycle
tools/mgmt-tester: test adv inst override
tools/mgmt-tester: make test timeout configurable
tools/mgmt-tester: allow for event-only tests
tools/mgmt-tester: test advertising timeout
tools/mgmt-tester: test le off
tools/mgmt-tester: fix duplicate code
tools/mgmt-tester: test multi-adv

doc/mgmt-api.txt | 105 +++++--
doc/test-coverage.txt | 4 +-
tools/btmgmt.c | 28 +-
tools/mgmt-tester.c | 838 +++++++++++++++++++++++++++++++++++---------------
4 files changed, 681 insertions(+), 294 deletions(-)

--
1.9.1


2015-06-18 01:16:53

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v8 20/20] Bluetooth: hci_core: increase max adv inst

Now that all preconditions are present for actual multi-advertising, the
number of allowed advertising instances can be larger than one. This
patch increases the number of allowed advertising instances to 5.

Signed-off-by: Florian Grandel <[email protected]>
---
include/net/bluetooth/hci_core.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index a6cec6d..3bd618d 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -169,7 +169,7 @@ struct adv_info {
__u8 scan_rsp_data[HCI_MAX_AD_LENGTH];
};

-#define HCI_MAX_ADV_INSTANCES 1
+#define HCI_MAX_ADV_INSTANCES 5
#define HCI_DEFAULT_ADV_DURATION 2

#define HCI_MAX_SHORT_NAME_LENGTH 10
--
1.9.1


2015-06-18 01:16:52

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v8 19/20] Bluetooth: hci_core: remove obsolete adv_instance

Now that the obsolete adv_instance is no longer being referenced
anywhere in the code it can be removed without breaking the build.

Signed-off-by: Florian Grandel <[email protected]>
---
include/net/bluetooth/hci_core.h | 6 ------
net/bluetooth/hci_core.c | 1 -
2 files changed, 7 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 4f58a0e..a6cec6d 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -379,7 +379,6 @@ struct hci_dev {
__u8 scan_rsp_data[HCI_MAX_AD_LENGTH];
__u8 scan_rsp_data_len;

- struct adv_info adv_instance;
struct list_head adv_instances;
unsigned int adv_instance_cnt;
__u8 cur_adv_instance;
@@ -584,11 +583,6 @@ static inline void hci_discovery_filter_clear(struct hci_dev *hdev)
hdev->discovery.scan_duration = 0;
}

-static inline void adv_info_init(struct hci_dev *hdev)
-{
- memset(&hdev->adv_instance, 0, sizeof(struct adv_info));
-}
-
bool hci_discovery_active(struct hci_dev *hdev);

void hci_discovery_set_state(struct hci_dev *hdev, int state);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index e50f7c3..86ed44e 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3224,7 +3224,6 @@ struct hci_dev *hci_alloc_dev(void)

hci_init_sysfs(hdev);
discovery_init(hdev);
- adv_info_init(hdev);

return hdev;
}
--
1.9.1


2015-06-18 01:16:50

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v8 17/20] Bluetooth: mgmt: multi-adv for trigger_le_scan()

This patch ensures that instance advertising is correctly canceled
before starting a le scan.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 57e27b7..f44c6e3 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -4215,6 +4215,7 @@ static bool trigger_le_scan(struct hci_request *req, u16 interval, u8 *status)
return false;
}

+ cancel_adv_timeout(hdev);
disable_advertising(req);
}

--
1.9.1


2015-06-18 01:16:51

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v8 18/20] Bluetooth: mgmt: multi-adv for mgmt_reenable_advertising()

During service discovery, advertising will be disabled. This patch
ensures that it is correctly being re-enabled, both for configuration
made via set advertising and add advertising, once the scanning
times out.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index f44c6e3..b132032 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -8610,13 +8610,24 @@ static void adv_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
void mgmt_reenable_advertising(struct hci_dev *hdev)
{
struct hci_request req;
+ u8 instance;

if (!hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
return;

+ instance = get_current_adv_instance(hdev);
+
hci_req_init(&req, hdev);
- enable_advertising(&req);
+
+ if (instance) {
+ schedule_adv_instance(&req, instance, true);
+ } else {
+ update_adv_data(&req);
+ update_scan_rsp_data(&req);
+ enable_advertising(&req);
+ }
+
hci_req_run(&req, adv_enable_complete);
}

--
1.9.1


2015-06-18 01:16:48

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v8 15/20] Bluetooth: mgmt: multi adv for remove_advertising*()

The remove_advertising() and remove_advertising_complete() functions
had instance identifiers hard coded. Notably, when passing in 0x00 as
an instance identifier to signal that all instances should be removed
then the mgmt API would return a hard coded 0x01 rather than returning
the expected value 0x00. This bug is being fixed by always referencing
the instance identifier from the management API call instead.

remove_advertising() is refactored to use the new dynamic advertising
instance list. The logic is being changed to make multi-instance
advertising actually work, notably the schedule_adv_instance() method is
being referenced to make sure that other instances will continue to
advertise even if one instance is being removed.

The code is made more readable by factoring advertising instance
management and initialization into the low-level
hci_remove_adv_instance() and hci_adv_instances_clear() functions.

The method now references the clear_adv_instance() helper method to
remove duplicate logic and code.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 45 ++++++++++++++++++++++++---------------------
1 file changed, 24 insertions(+), 21 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 0cc6854..c8ed16d 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -7248,6 +7248,7 @@ static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
u16 opcode)
{
struct mgmt_pending_cmd *cmd;
+ struct mgmt_cp_remove_advertising *cp;
struct mgmt_rp_remove_advertising rp;

BT_DBG("status %d", status);
@@ -7262,7 +7263,8 @@ static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
if (!cmd)
goto unlock;

- rp.instance = 1;
+ cp = cmd->param;
+ rp.instance = cp->instance;

mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
&rp, sizeof(rp));
@@ -7277,21 +7279,25 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
{
struct mgmt_cp_remove_advertising *cp = data;
struct mgmt_rp_remove_advertising rp;
+ struct adv_info *adv_instance;
int err;
struct mgmt_pending_cmd *cmd;
struct hci_request req;

BT_DBG("%s", hdev->name);

- /* The current implementation only allows modifying instance no 1. A
- * value of 0 indicates that all instances should be cleared.
- */
- if (cp->instance > 1)
- return mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
- MGMT_STATUS_INVALID_PARAMS);
-
hci_dev_lock(hdev);

+ if (cp->instance)
+ adv_instance = hci_find_adv_instance(hdev, cp->instance);
+
+ if (!(cp->instance == 0x00 || adv_instance)) {
+ err = mgmt_cmd_status(sk, hdev->id,
+ MGMT_OP_REMOVE_ADVERTISING,
+ MGMT_STATUS_INVALID_PARAMS);
+ goto unlock;
+ }
+
if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
pending_find(MGMT_OP_SET_LE, hdev)) {
@@ -7306,21 +7312,21 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}

- if (hdev->adv_instance_timeout)
- cancel_delayed_work(&hdev->adv_instance_expire);
-
- memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
+ hci_req_init(&req, hdev);

- advertising_removed(sk, hdev, 1);
+ clear_adv_instance(hdev, &req, cp->instance, true);

- hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
+ if (list_empty(&hdev->adv_instances))
+ disable_advertising(&req);

- /* If the HCI_ADVERTISING flag is set or the device isn't powered then
- * we have no HCI communication to make. Simply return.
+ /* If no HCI commands have been collected so far or the HCI_ADVERTISING
+ * flag is set or the device isn't powered then we have no HCI
+ * communication to make. Simply return.
*/
- if (!hdev_is_powered(hdev) ||
+ if (skb_queue_empty(&req.cmd_q) ||
+ !hdev_is_powered(hdev) ||
hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
- rp.instance = 1;
+ rp.instance = cp->instance;
err = mgmt_cmd_complete(sk, hdev->id,
MGMT_OP_REMOVE_ADVERTISING,
MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
@@ -7334,9 +7340,6 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}

- hci_req_init(&req, hdev);
- disable_advertising(&req);
-
err = hci_req_run(&req, remove_advertising_complete);
if (err < 0)
mgmt_pending_remove(cmd);
--
1.9.1


2015-06-18 01:16:49

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v8 16/20] Bluetooth: mgmt: program multi-adv on power on

Advertising instances programmed while powered off should be advertised
once the device is powered. This patch ensures that all combinations
of setting and/or adding advertising configuration while powered off
will be correctly activated on power on.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 20 +++++++++++++++++---
1 file changed, 17 insertions(+), 3 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index c8ed16d..57e27b7 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -7564,6 +7564,7 @@ static void powered_complete(struct hci_dev *hdev, u8 status, u16 opcode)
static int powered_update_hci(struct hci_dev *hdev)
{
struct hci_request req;
+ struct adv_info *adv_instance;
u8 link_sec;

hci_req_init(&req, hdev);
@@ -7603,14 +7604,27 @@ static int powered_update_hci(struct hci_dev *hdev)
* advertising data. This also applies to the case
* where BR/EDR was toggled during the AUTO_OFF phase.
*/
- if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
+ if (hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
+ (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
+ !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))) {
update_adv_data(&req);
update_scan_rsp_data(&req);
}

- if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
- hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
+ if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
+ hdev->cur_adv_instance == 0x00 &&
+ !list_empty(&hdev->adv_instances)) {
+ adv_instance = list_first_entry(&hdev->adv_instances,
+ struct adv_info, list);
+ hdev->cur_adv_instance = adv_instance->instance;
+ }
+
+ if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
enable_advertising(&req);
+ else if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
+ hdev->cur_adv_instance)
+ schedule_adv_instance(&req, hdev->cur_adv_instance,
+ true);

restart_le_actions(&req);
}
--
1.9.1


2015-06-18 01:16:47

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v8 14/20] Bluetooth: mgmt/hci_core: multi-adv for add_advertising*()

The add_advertising() and add_advertising_complete() functions reference
the now obsolete hdev->adv_instance struct. Both methods are being
refactored to access the dynamic advertising instance list instead.

This patch also introduces all logic necessary to actually deal with
multiple instance advertising. Notably the mgmt_adv_inst_expired() and
schedule_adv_inst() method are being referenced to schedule instances in
a round robin fashion.

This patch also introduces a "pending" flag into the adv_info struct.
This is necessary to identify and remove recently added advertising
instances when the HCI commands return with an error status code.
Otherwise new advertising instances could be leaked without properly
informing userspace about their existence.

Signed-off-by: Florian Grandel <[email protected]>
---
include/net/bluetooth/hci_core.h | 1 +
net/bluetooth/hci_core.c | 1 +
net/bluetooth/mgmt.c | 108 ++++++++++++++++++++++++++-------------
3 files changed, 75 insertions(+), 35 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index b53e1b1..4f58a0e 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -157,6 +157,7 @@ struct oob_data {

struct adv_info {
struct list_head list;
+ bool pending;
__u8 instance;
__u32 flags;
__u16 timeout;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index d1110db..e50f7c3 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2721,6 +2721,7 @@ int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
return -ENOMEM;

memset(adv_instance, 0, sizeof(*adv_instance));
+ adv_instance->pending = true;
adv_instance->instance = instance;
list_add(&adv_instance->list, &hdev->adv_instances);
hdev->adv_instance_cnt++;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index ac5fc35..0cc6854 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -7033,7 +7033,10 @@ static void add_advertising_complete(struct hci_dev *hdev, u8 status,
u16 opcode)
{
struct mgmt_pending_cmd *cmd;
+ struct mgmt_cp_add_advertising *cp;
struct mgmt_rp_add_advertising rp;
+ struct adv_info *adv_instance, *n;
+ u8 instance;

BT_DBG("status %d", status);

@@ -7041,16 +7044,32 @@ static void add_advertising_complete(struct hci_dev *hdev, u8 status,

cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);

- if (status) {
+ if (status)
hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
- memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
- advertising_removed(cmd ? cmd->sk : NULL, hdev, 1);
+
+ list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
+ if (!adv_instance->pending)
+ continue;
+
+ if (!status) {
+ adv_instance->pending = false;
+ continue;
+ }
+
+ instance = adv_instance->instance;
+
+ if (hdev->cur_adv_instance == instance)
+ cancel_adv_timeout(hdev);
+
+ hci_remove_adv_instance(hdev, instance);
+ advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
}

if (!cmd)
goto unlock;

- rp.instance = 0x01;
+ cp = cmd->param;
+ rp.instance = cp->instance;

if (status)
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
@@ -7098,7 +7117,10 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
u32 flags;
u32 supported_flags;
u8 status;
- u16 timeout;
+ u16 timeout, duration;
+ unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
+ u8 schedule_instance = 0;
+ struct adv_info *next_instance;
int err;
struct mgmt_pending_cmd *cmd;
struct hci_request req;
@@ -7112,12 +7134,13 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,

flags = __le32_to_cpu(cp->flags);
timeout = __le16_to_cpu(cp->timeout);
+ duration = __le16_to_cpu(cp->duration);

- /* The current implementation only supports adding one instance and only
- * a subset of the specified flags.
+ /* The current implementation only supports a subset of the specified
+ * flags.
*/
supported_flags = get_supported_adv_flags(hdev);
- if (cp->instance != 0x01 || (flags & ~supported_flags))
+ if (flags & ~supported_flags)
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
MGMT_STATUS_INVALID_PARAMS);

@@ -7145,36 +7168,51 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}

- hdev->adv_instance.flags = flags;
- hdev->adv_instance.adv_data_len = cp->adv_data_len;
- hdev->adv_instance.scan_rsp_len = cp->scan_rsp_len;
-
- if (cp->adv_data_len)
- memcpy(hdev->adv_instance.adv_data, cp->data, cp->adv_data_len);
-
- if (cp->scan_rsp_len)
- memcpy(hdev->adv_instance.scan_rsp_data,
- cp->data + cp->adv_data_len, cp->scan_rsp_len);
+ err = hci_add_adv_instance(hdev, cp->instance, flags,
+ cp->adv_data_len, cp->data,
+ cp->scan_rsp_len,
+ cp->data + cp->adv_data_len,
+ timeout, duration);
+ if (err < 0) {
+ err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
+ MGMT_STATUS_FAILED);
+ goto unlock;
+ }

- if (hdev->adv_instance_timeout)
- cancel_delayed_work(&hdev->adv_instance_expire);
+ /* Only trigger an advertising added event if a new instance was
+ * actually added.
+ */
+ if (hdev->adv_instance_cnt > prev_instance_cnt)
+ advertising_added(sk, hdev, cp->instance);

- hdev->adv_instance_timeout = timeout;
+ hci_dev_set_flag(hdev, HCI_ADVERTISING_INSTANCE);

- if (timeout)
- queue_delayed_work(hdev->workqueue,
- &hdev->adv_instance_expire,
- msecs_to_jiffies(timeout * 1000));
+ if (hdev->cur_adv_instance == cp->instance) {
+ /* If the currently advertised instance is being changed then
+ * cancel the current advertising and schedule the next
+ * instance. If there is only one instance then the overridden
+ * advertising data will be visible right away.
+ */
+ cancel_adv_timeout(hdev);

- if (!hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING_INSTANCE))
- advertising_added(sk, hdev, 1);
+ next_instance = hci_get_next_instance(hdev, cp->instance);
+ if (next_instance)
+ schedule_instance = next_instance->instance;
+ } else if (!hdev->adv_instance_timeout) {
+ /* Immediately advertise the new instance if no other
+ * instance is currently being advertised.
+ */
+ schedule_instance = cp->instance;
+ }

- /* If the HCI_ADVERTISING flag is set or the device isn't powered then
- * we have no HCI communication to make. Simply return.
+ /* If the HCI_ADVERTISING flag is set or the device isn't powered or
+ * there is no instance to be advertised then we have no HCI
+ * communication to make. Simply return.
*/
if (!hdev_is_powered(hdev) ||
- hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
- rp.instance = 0x01;
+ hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
+ !schedule_instance) {
+ rp.instance = cp->instance;
err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
goto unlock;
@@ -7192,11 +7230,11 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,

hci_req_init(&req, hdev);

- update_adv_data(&req);
- update_scan_rsp_data(&req);
- enable_advertising(&req);
+ err = schedule_adv_instance(&req, schedule_instance, true);
+
+ if (!err)
+ err = hci_req_run(&req, add_advertising_complete);

- err = hci_req_run(&req, add_advertising_complete);
if (err < 0)
mgmt_pending_remove(cmd);

--
1.9.1


2015-06-18 01:16:46

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v8 13/20] Bluetooth: mgmt: multi adv for clear_adv_instances()

The clear_adv_instance() function could not clean up multiple
advertising instances previously. It is being changed to provide both, a
means to clean up a single instance and cleaning up all instances at
once.

An additional instance parameter is being introduced to achieve this.
Passing in 0x00 to this parameter signifies that all instances should be
cleaned up. This semantics has been chosen similarly to the semantics of
the instance parameter in the remove_advertising() function.

When removing a single instance the method also ensures that another
instance will be scheduled if available. When the currently advertising
method is being removed, it will be canceled immediately.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 97 +++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 81 insertions(+), 16 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 55765dd..ac5fc35 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1538,27 +1538,74 @@ static void cancel_adv_timeout(struct hci_dev *hdev)
}
}

-static void clear_adv_instance(struct hci_dev *hdev)
+/* For a single instance:
+ * - force == true: The instance will be removed even when its remaining
+ * lifetime is not zero.
+ * - force == false: the instance will be deactivated but kept stored unless
+ * the remaining lifetime is zero.
+ *
+ * For instance == 0x00:
+ * - force == true: All instances will be removed regardless of their timeout
+ * setting.
+ * - force == false: Only instances that have a timeout will be removed.
+ */
+static void clear_adv_instance(struct hci_dev *hdev, struct hci_request *req,
+ u8 instance, bool force)
{
- struct hci_request req;
+ struct adv_info *adv_instance, *n, *next_instance = NULL;
+ int err;
+ u8 rem_inst;

- if (!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
- return;
+ /* Cancel any timeout concerning the removed instance(s). */
+ if (!instance || hdev->cur_adv_instance == instance)
+ cancel_adv_timeout(hdev);

- if (hdev->adv_instance_timeout)
- cancel_delayed_work(&hdev->adv_instance_expire);
+ /* Get the next instance to advertise BEFORE we remove
+ * the current one. This can be the same instance again
+ * if there is only one instance.
+ */
+ if (instance && hdev->cur_adv_instance == instance)
+ next_instance = hci_get_next_instance(hdev, instance);

- memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
- advertising_removed(NULL, hdev, 1);
- hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
+ if (instance == 0x00) {
+ list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances,
+ list) {
+ if (!(force || adv_instance->timeout))
+ continue;

- if (!hdev_is_powered(hdev) ||
+ rem_inst = adv_instance->instance;
+ err = hci_remove_adv_instance(hdev, rem_inst);
+ if (!err)
+ advertising_removed(NULL, hdev, rem_inst);
+ }
+ hdev->cur_adv_instance = 0x00;
+ } else {
+ adv_instance = hci_find_adv_instance(hdev, instance);
+
+ if (force || (adv_instance && adv_instance->timeout &&
+ !adv_instance->remaining_time)) {
+ /* Don't advertise a removed instance. */
+ if (next_instance &&
+ next_instance->instance == instance)
+ next_instance = NULL;
+
+ err = hci_remove_adv_instance(hdev, instance);
+ if (!err)
+ advertising_removed(NULL, hdev, instance);
+ }
+ }
+
+ if (list_empty(&hdev->adv_instances)) {
+ hdev->cur_adv_instance = 0x00;
+ hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
+ }
+
+ if (!req || !hdev_is_powered(hdev) ||
hci_dev_test_flag(hdev, HCI_ADVERTISING))
return;

- hci_req_init(&req, hdev);
- disable_advertising(&req);
- hci_req_run(&req, NULL);
+ if (next_instance)
+ schedule_adv_instance(req, next_instance->instance, false);
}

static int clean_up_hci_state(struct hci_dev *hdev)
@@ -1576,8 +1623,7 @@ static int clean_up_hci_state(struct hci_dev *hdev)
hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
}

- if (hdev->adv_instance_timeout)
- clear_adv_instance(hdev);
+ clear_adv_instance(hdev, NULL, 0x00, false);

if (hci_dev_test_flag(hdev, HCI_LE_ADV))
disable_advertising(&req);
@@ -2532,6 +2578,9 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
val = !!cp->val;
enabled = lmp_host_le_capable(hdev);

+ if (!val)
+ clear_adv_instance(hdev, NULL, 0x00, true);
+
if (!hdev_is_powered(hdev) || val == enabled) {
bool changed = false;

@@ -7018,10 +7067,26 @@ unlock:

void mgmt_adv_timeout_expired(struct hci_dev *hdev)
{
+ u8 instance;
+ struct hci_request req;
+
hdev->adv_instance_timeout = 0;

+ instance = get_current_adv_instance(hdev);
+ if (instance == 0x00)
+ return;
+
hci_dev_lock(hdev);
- clear_adv_instance(hdev);
+ hci_req_init(&req, hdev);
+
+ clear_adv_instance(hdev, &req, instance, false);
+
+ if (list_empty(&hdev->adv_instances))
+ disable_advertising(&req);
+
+ if (!skb_queue_empty(&req.cmd_q))
+ hci_req_run(&req, NULL);
+
hci_dev_unlock(hdev);
}

--
1.9.1


2015-06-18 01:16:45

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v8 12/20] Bluetooth: mgmt: multi adv for set_advertising*()

The set_advertising() and set_advertising_complete() methods rely on
the now obsolete hci_dev->adv_instance structure. We replace this
reference by an equivalent access to the newly introduced dynamic
advertising instance list.

This patch introduces a helper function that schedules an advertising
instance correctly calculating advertising timing based on the timeout
and duration settings of the instance. Scheduling is factored into
its own function for readability and code sharing.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 94 insertions(+), 6 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 04efc56..55765dd 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1471,6 +1471,73 @@ static void advertising_removed(struct sock *sk, struct hci_dev *hdev,
mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
}

+static int schedule_adv_instance(struct hci_request *req, u8 instance,
+ bool force) {
+ struct hci_dev *hdev = req->hdev;
+ struct adv_info *adv_instance = NULL;
+ u16 timeout;
+
+ if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
+ !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
+ return -EPERM;
+
+ if (hdev->adv_instance_timeout)
+ return -EBUSY;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (!adv_instance)
+ return -ENOENT;
+
+ /* A zero timeout means unlimited advertising. As long as there is
+ * only one instance, duration should be ignored. We still set a timeout
+ * in case further instances are being added later on.
+ *
+ * If the remaining lifetime of the instance is more than the duration
+ * then the timeout corresponds to the duration, otherwise it will be
+ * reduced to the remaining instance lifetime.
+ */
+ if (adv_instance->timeout == 0 ||
+ adv_instance->duration <= adv_instance->remaining_time)
+ timeout = adv_instance->duration;
+ else
+ timeout = adv_instance->remaining_time;
+
+ /* The remaining time is being reduced unless the instance is being
+ * advertised without time limit.
+ */
+ if (adv_instance->timeout)
+ adv_instance->remaining_time =
+ adv_instance->remaining_time - timeout;
+
+ hdev->adv_instance_timeout = timeout;
+ queue_delayed_work(hdev->workqueue,
+ &hdev->adv_instance_expire,
+ msecs_to_jiffies(timeout * 1000));
+
+ /* If we're just re-scheduling the same instance again then do not
+ * execute any HCI commands. This happens when a single instance is
+ * being advertised.
+ */
+ if (!force && hdev->cur_adv_instance == instance &&
+ hci_dev_test_flag(hdev, HCI_LE_ADV))
+ return 0;
+
+ hdev->cur_adv_instance = instance;
+ update_adv_data(req);
+ update_scan_rsp_data(req);
+ enable_advertising(req);
+
+ return 0;
+}
+
+static void cancel_adv_timeout(struct hci_dev *hdev)
+{
+ if (hdev->adv_instance_timeout) {
+ hdev->adv_instance_timeout = 0;
+ cancel_delayed_work(&hdev->adv_instance_expire);
+ }
+}
+
static void clear_adv_instance(struct hci_dev *hdev)
{
struct hci_request req;
@@ -4681,6 +4748,9 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status,
{
struct cmd_lookup match = { NULL, hdev };
struct hci_request req;
+ u8 instance;
+ struct adv_info *adv_instance;
+ int err;

hci_dev_lock(hdev);

@@ -4706,18 +4776,31 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status,
sock_put(match.sk);

/* If "Set Advertising" was just disabled and instance advertising was
- * set up earlier, then enable the advertising instance.
+ * set up earlier, then re-enable multi-instance advertising.
*/
if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
- !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
+ !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) ||
+ list_empty(&hdev->adv_instances))
goto unlock;

+ instance = hdev->cur_adv_instance;
+ if (!instance) {
+ adv_instance = list_first_entry_or_null(&hdev->adv_instances,
+ struct adv_info, list);
+ if (!adv_instance)
+ goto unlock;
+
+ instance = adv_instance->instance;
+ }
+
hci_req_init(&req, hdev);

- update_adv_data(&req);
- enable_advertising(&req);
+ err = schedule_adv_instance(&req, instance, true);
+
+ if (!err)
+ err = hci_req_run(&req, enable_advertising_instance);

- if (hci_req_run(&req, enable_advertising_instance) < 0)
+ if (err)
BT_ERR("Failed to re-configure advertising");

unlock:
@@ -4802,8 +4885,13 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
else
hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);

+ cancel_adv_timeout(hdev);
+
if (val) {
- /* Switch to instance "0" for the Set Advertising setting. */
+ /* Switch to instance "0" for the Set Advertising setting.
+ * We cannot use update_[adv|scan_rsp]_data() here as the
+ * HCI_ADVERTISING flag is not yet set.
+ */
update_inst_adv_data(&req, 0x00);
update_inst_scan_rsp_data(&req, 0x00);
enable_advertising(&req);
--
1.9.1


2015-06-18 01:16:44

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v8 11/20] Bluetooth: mgmt: multi adv for create_instance_adv_data()

The create_instance_adv_data() function could not deal with
multiple advertising instances previously. This is being fixed by
retrieving advertising instances from the newly introduced dynamic
advertising instance list.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 23 ++++++++++++++++-------
1 file changed, 16 insertions(+), 7 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index fc807dc..04efc56 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1014,8 +1014,18 @@ static u8 get_cur_adv_instance_scan_rsp_len(struct hci_dev *hdev)

static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
{
+ struct adv_info *adv_instance = NULL;
u8 ad_len = 0, flags = 0;
- u32 instance_flags = get_adv_instance_flags(hdev, instance);
+ u32 instance_flags;
+
+ /* Return 0 when the current instance identifier is invalid. */
+ if (instance) {
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (!adv_instance)
+ return 0;
+ }
+
+ instance_flags = get_adv_instance_flags(hdev, instance);

/* The Add Advertising command allows userspace to set both the general
* and limited discoverable flags.
@@ -1049,12 +1059,11 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
}
}

- if (instance) {
- memcpy(ptr, hdev->adv_instance.adv_data,
- hdev->adv_instance.adv_data_len);
-
- ad_len += hdev->adv_instance.adv_data_len;
- ptr += hdev->adv_instance.adv_data_len;
+ if (adv_instance) {
+ memcpy(ptr, adv_instance->adv_data,
+ adv_instance->adv_data_len);
+ ad_len += adv_instance->adv_data_len;
+ ptr += adv_instance->adv_data_len;
}

/* Provide Tx Power only if we can provide a valid value for it */
--
1.9.1


2015-06-18 01:16:43

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v8 10/20] Bluetooth: mgmt: multi adv for create_instance_scan_rsp_data()

The create_instance_scan_rsp_data() function could not deal with
multiple advertising instances previously. This is being fixed by adding
an additional instance parameter.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 76aee8a..fc807dc 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -872,15 +872,22 @@ static u8 create_default_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
return ad_len;
}

-static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
+static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 instance,
+ u8 *ptr)
{
+ struct adv_info *adv_instance;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (!adv_instance)
+ return 0;
+
/* TODO: Set the appropriate entries based on advertising instance flags
* here once flags other than 0 are supported.
*/
- memcpy(ptr, hdev->adv_instance.scan_rsp_data,
- hdev->adv_instance.scan_rsp_len);
+ memcpy(ptr, adv_instance->scan_rsp_data,
+ adv_instance->scan_rsp_len);

- return hdev->adv_instance.scan_rsp_len;
+ return adv_instance->scan_rsp_len;
}

static void update_inst_scan_rsp_data(struct hci_request *req, u8 instance)
@@ -895,7 +902,7 @@ static void update_inst_scan_rsp_data(struct hci_request *req, u8 instance)
memset(&cp, 0, sizeof(cp));

if (instance)
- len = create_instance_scan_rsp_data(hdev, cp.data);
+ len = create_instance_scan_rsp_data(hdev, instance, cp.data);
else
len = create_default_scan_rsp_data(hdev, cp.data);

--
1.9.1


2015-06-18 01:16:42

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v8 09/20] Bluetooth: mgmt: multi adv for enable_advertising()

Previously enable_advertising() would rely on
get_adv_instance_scan_rsp_len() which checked for a hard coded instance
identifier. This is being changed to check for the current advertising
instance's scan response length instead. The function is renamed
accordingly.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 47fa16b..76aee8a 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -986,16 +986,23 @@ static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance)
return adv_instance->flags;
}

-static u8 get_adv_instance_scan_rsp_len(struct hci_dev *hdev, u8 instance)
+static u8 get_cur_adv_instance_scan_rsp_len(struct hci_dev *hdev)
{
- /* Ignore instance 0 and other unsupported instances */
- if (instance != 0x01)
+ u8 instance = get_current_adv_instance(hdev);
+ struct adv_info *adv_instance;
+
+ /* Ignore instance 0 */
+ if (instance == 0x00)
+ return 0;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (!adv_instance)
return 0;

/* TODO: Take into account the "appearance" and "local-name" flags here.
* These are currently being ignored as they are not supported.
*/
- return hdev->adv_instance.scan_rsp_len;
+ return adv_instance->scan_rsp_len;
}

static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
@@ -1266,7 +1273,7 @@ static void enable_advertising(struct hci_request *req)

if (connectable)
cp.type = LE_ADV_IND;
- else if (get_adv_instance_scan_rsp_len(hdev, instance))
+ else if (get_cur_adv_instance_scan_rsp_len(hdev))
cp.type = LE_ADV_SCAN_IND;
else
cp.type = LE_ADV_NONCONN_IND;
--
1.9.1


2015-06-18 01:16:41

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v8 08/20] Bluetooth: mgmt: improve get_adv_instance_flags() readability

Switch if and else conditions to replace a negative statement by a
positive one which makes the condition more readable.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 30 ++++++++++++++++--------------
1 file changed, 16 insertions(+), 14 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 05f14c5..47fa16b 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -962,26 +962,28 @@ static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance)
u32 flags;
struct adv_info *adv_instance;

- if (instance != 0x00) {
- adv_instance = hci_find_adv_instance(hdev, instance);
+ if (instance == 0x00) {
+ /* Instance 0 always manages the "Tx Power" and "Flags"
+ * fields
+ */
+ flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS;

- /* Return 0 when we got an invalid instance identifier. */
- if (!adv_instance)
- return 0;
+ /* For instance 0, the HCI_ADVERTISING_CONNECTABLE setting
+ * corresponds to the "connectable" instance flag.
+ */
+ if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
+ flags |= MGMT_ADV_FLAG_CONNECTABLE;

- return adv_instance->flags;
+ return flags;
}

- /* Instance 0 always manages the "Tx Power" and "Flags" fields */
- flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS;
+ adv_instance = hci_find_adv_instance(hdev, instance);

- /* For instance 0, the HCI_ADVERTISING_CONNECTABLE setting corresponds
- * to the "connectable" instance flag.
- */
- if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
- flags |= MGMT_ADV_FLAG_CONNECTABLE;
+ /* Return 0 when we got an invalid instance identifier. */
+ if (!adv_instance)
+ return 0;

- return flags;
+ return adv_instance->flags;
}

static u8 get_adv_instance_scan_rsp_len(struct hci_dev *hdev, u8 instance)
--
1.9.1


2015-06-18 01:16:40

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v8 07/20] Bluetooth: mgmt: multi adv for get_adv_instance_flags()

The get_adv_instance_flags() would not work with instance identifiers
other than 0x01. This is being fixed so that arbitrary instance
identifiers can be dealt with while still correctly dealing with the
special case of the 0x00 identifier.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 55b9153..05f14c5 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -960,12 +960,17 @@ static bool get_connectable(struct hci_dev *hdev)
static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance)
{
u32 flags;
+ struct adv_info *adv_instance;

- if (instance > 0x01)
- return 0;
+ if (instance != 0x00) {
+ adv_instance = hci_find_adv_instance(hdev, instance);

- if (instance == 0x01)
- return hdev->adv_instance.flags;
+ /* Return 0 when we got an invalid instance identifier. */
+ if (!adv_instance)
+ return 0;
+
+ return adv_instance->flags;
+ }

/* Instance 0 always manages the "Tx Power" and "Flags" fields */
flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS;
--
1.9.1


2015-06-18 01:16:39

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v8 06/20] Bluetooth: mgmt: multi adv for get_current_adv_instance()

Replaces the hard coded instance identifier in
get_current_adv_instance() with the actual current instance identifier
so that this method is prepared to work with more than one advertising
instance.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 49356c7..55b9153 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -841,7 +841,7 @@ static u8 get_current_adv_instance(struct hci_dev *hdev)
*/
if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
!hci_dev_test_flag(hdev, HCI_ADVERTISING))
- return 0x01;
+ return hdev->cur_adv_instance;

return 0x00;
}
--
1.9.1


2015-06-18 01:16:38

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v8 05/20] Bluetooth: mgmt: multi adv for read_adv_features()

The read_adv_features() method had a single instance identifier hard
coded. Refer to the advertising instance list instead to return a
dynamically generated list of instance identifiers.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 22 ++++++++++++----------
1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 7fabcb6..49356c7 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -6763,8 +6763,9 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
{
struct mgmt_rp_read_adv_features *rp;
size_t rp_len;
- int err;
+ int err, i;
bool instance;
+ struct adv_info *adv_instance;
u32 supported_flags;

BT_DBG("%s", hdev->name);
@@ -6777,12 +6778,9 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,

rp_len = sizeof(*rp);

- /* Currently only one instance is supported, so just add 1 to the
- * response length.
- */
instance = hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE);
if (instance)
- rp_len++;
+ rp_len += hdev->adv_instance_cnt;

rp = kmalloc(rp_len, GFP_ATOMIC);
if (!rp) {
@@ -6797,12 +6795,16 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
rp->max_instances = HCI_MAX_ADV_INSTANCES;

- /* Currently only one instance is supported, so simply return the
- * current instance number.
- */
if (instance) {
- rp->num_instances = 1;
- rp->instance[0] = 1;
+ i = 0;
+ list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
+ if (i >= hdev->adv_instance_cnt)
+ break;
+
+ rp->instance[i] = adv_instance->instance;
+ i++;
+ }
+ rp->num_instances = hdev->adv_instance_cnt;
} else {
rp->num_instances = 0;
}
--
1.9.1


2015-06-18 01:16:37

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v8 04/20] Bluetooth: mgmt: rename update_*_data_for_instance()

The ...for_instance function name is quite long and does not follow the
..._inst_... convention followed elsewhere in the code. This patch
renames the ...for_instance functions to their shorter ..._inst_...
version.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index c330416..7fabcb6 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -883,8 +883,7 @@ static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
return hdev->adv_instance.scan_rsp_len;
}

-static void update_scan_rsp_data_for_instance(struct hci_request *req,
- u8 instance)
+static void update_inst_scan_rsp_data(struct hci_request *req, u8 instance)
{
struct hci_dev *hdev = req->hdev;
struct hci_cp_le_set_scan_rsp_data cp;
@@ -914,8 +913,7 @@ static void update_scan_rsp_data_for_instance(struct hci_request *req,

static void update_scan_rsp_data(struct hci_request *req)
{
- update_scan_rsp_data_for_instance(req,
- get_current_adv_instance(req->hdev));
+ update_inst_scan_rsp_data(req, get_current_adv_instance(req->hdev));
}

static u8 get_adv_discov_flags(struct hci_dev *hdev)
@@ -1052,7 +1050,7 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
return ad_len;
}

-static void update_adv_data_for_instance(struct hci_request *req, u8 instance)
+static void update_inst_adv_data(struct hci_request *req, u8 instance)
{
struct hci_dev *hdev = req->hdev;
struct hci_cp_le_set_adv_data cp;
@@ -1080,7 +1078,7 @@ static void update_adv_data_for_instance(struct hci_request *req, u8 instance)

static void update_adv_data(struct hci_request *req)
{
- update_adv_data_for_instance(req, get_current_adv_instance(req->hdev));
+ update_inst_adv_data(req, get_current_adv_instance(req->hdev));
}

int mgmt_update_adv_data(struct hci_dev *hdev)
@@ -4776,8 +4774,8 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,

if (val) {
/* Switch to instance "0" for the Set Advertising setting. */
- update_adv_data_for_instance(&req, 0);
- update_scan_rsp_data_for_instance(&req, 0);
+ update_inst_adv_data(&req, 0x00);
+ update_inst_scan_rsp_data(&req, 0x00);
enable_advertising(&req);
} else {
disable_advertising(&req);
--
1.9.1


2015-06-18 01:16:36

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v8 03/20] Bluetooth: mgmt: dry update_scan_rsp_data()

update_scan_rsp_data() duplicates code from get_current_adv_instance().
This is being fixed by letting the former make use of the latter.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 50 +++++++++++++++++---------------------------------
1 file changed, 17 insertions(+), 33 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index a8319f6..c330416 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -832,6 +832,20 @@ static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
}

+static u8 get_current_adv_instance(struct hci_dev *hdev)
+{
+ /* The "Set Advertising" setting supersedes the "Add Advertising"
+ * setting. Here we set the advertising data based on which
+ * setting was set. When neither apply, default to the global settings,
+ * represented by instance "0".
+ */
+ if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
+ !hci_dev_test_flag(hdev, HCI_ADVERTISING))
+ return 0x01;
+
+ return 0x00;
+}
+
static u8 create_default_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
{
u8 ad_len = 0;
@@ -900,21 +914,8 @@ static void update_scan_rsp_data_for_instance(struct hci_request *req,

static void update_scan_rsp_data(struct hci_request *req)
{
- struct hci_dev *hdev = req->hdev;
- u8 instance;
-
- /* The "Set Advertising" setting supersedes the "Add Advertising"
- * setting. Here we set the scan response data based on which
- * setting was set. When neither apply, default to the global settings,
- * represented by instance "0".
- */
- if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
- !hci_dev_test_flag(hdev, HCI_ADVERTISING))
- instance = 0x01;
- else
- instance = 0x00;
-
- update_scan_rsp_data_for_instance(req, instance);
+ update_scan_rsp_data_for_instance(req,
+ get_current_adv_instance(req->hdev));
}

static u8 get_adv_discov_flags(struct hci_dev *hdev)
@@ -941,20 +942,6 @@ static u8 get_adv_discov_flags(struct hci_dev *hdev)
return 0;
}

-static u8 get_current_adv_instance(struct hci_dev *hdev)
-{
- /* The "Set Advertising" setting supersedes the "Add Advertising"
- * setting. Here we set the advertising data based on which
- * setting was set. When neither apply, default to the global settings,
- * represented by instance "0".
- */
- if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
- !hci_dev_test_flag(hdev, HCI_ADVERTISING))
- return 0x01;
-
- return 0x00;
-}
-
static bool get_connectable(struct hci_dev *hdev)
{
struct mgmt_pending_cmd *cmd;
@@ -1093,10 +1080,7 @@ static void update_adv_data_for_instance(struct hci_request *req, u8 instance)

static void update_adv_data(struct hci_request *req)
{
- struct hci_dev *hdev = req->hdev;
- u8 instance = get_current_adv_instance(hdev);
-
- update_adv_data_for_instance(req, instance);
+ update_adv_data_for_instance(req, get_current_adv_instance(req->hdev));
}

int mgmt_update_adv_data(struct hci_dev *hdev)
--
1.9.1


2015-06-18 01:16:34

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v8 01/20] Bluetooth: hci_core/mgmt: Introduce multi-adv list

The current hci dev structure only supports a single advertising
instance. To support multi-instance advertising it is necessary to
introduce a linked list of advertising instances so that multiple
advertising instances can be dynamically added and/or removed.

In a first step, the existing adv_instance member of the hci_dev
struct is supplemented by a linked list of advertising instances.
This patch introduces the list and supporting list management
infrastructure. The list is not being used yet.

Signed-off-by: Florian Grandel <[email protected]>
---
include/net/bluetooth/hci_core.h | 17 ++++++
net/bluetooth/hci_core.c | 117 +++++++++++++++++++++++++++++++++++++++
net/bluetooth/mgmt.c | 2 +-
3 files changed, 135 insertions(+), 1 deletion(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 3fbb793..4242dbf 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -157,15 +157,20 @@ struct oob_data {

struct adv_info {
struct delayed_work timeout_exp;
+ struct list_head list;
__u8 instance;
__u32 flags;
__u16 timeout;
+ __u16 duration;
__u16 adv_data_len;
__u8 adv_data[HCI_MAX_AD_LENGTH];
__u16 scan_rsp_len;
__u8 scan_rsp_data[HCI_MAX_AD_LENGTH];
};

+#define HCI_MAX_ADV_INSTANCES 1
+#define HCI_DEFAULT_ADV_DURATION 2
+
#define HCI_MAX_SHORT_NAME_LENGTH 10

/* Default LE RPA expiry time, 15 minutes */
@@ -374,6 +379,9 @@ struct hci_dev {
__u8 scan_rsp_data_len;

struct adv_info adv_instance;
+ struct list_head adv_instances;
+ unsigned int adv_instance_cnt;
+ __u8 cur_adv_instance;

__u8 irk[16];
__u32 rpa_timeout;
@@ -1019,6 +1027,15 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 bdaddr_type);

+void hci_adv_instances_clear(struct hci_dev *hdev);
+struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance);
+struct adv_info *hci_get_next_instance(struct hci_dev *hdev, u8 instance);
+int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
+ u16 adv_data_len, u8 *adv_data,
+ u16 scan_rsp_len, u8 *scan_rsp_data,
+ u16 timeout, u16 duration);
+int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance);
+
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);

int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 573711c..ebf37eb 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2610,6 +2610,119 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
return 0;
}

+/* This function requires the caller holds hdev->lock */
+struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance)
+{
+ struct adv_info *adv_instance;
+
+ list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
+ if (adv_instance->instance == instance)
+ return adv_instance;
+ }
+
+ return NULL;
+}
+
+/* This function requires the caller holds hdev->lock */
+struct adv_info *hci_get_next_instance(struct hci_dev *hdev, u8 instance) {
+ struct adv_info *cur_instance;
+
+ cur_instance = hci_find_adv_instance(hdev, instance);
+ if (!cur_instance)
+ return NULL;
+
+ if (cur_instance == list_last_entry(&hdev->adv_instances,
+ struct adv_info, list))
+ return list_first_entry(&hdev->adv_instances,
+ struct adv_info, list);
+ else
+ return list_next_entry(cur_instance, list);
+}
+
+/* This function requires the caller holds hdev->lock */
+int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance)
+{
+ struct adv_info *adv_instance;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (!adv_instance)
+ return -ENOENT;
+
+ BT_DBG("%s removing %dMR", hdev->name, instance);
+
+ list_del(&adv_instance->list);
+ kfree(adv_instance);
+
+ hdev->adv_instance_cnt--;
+
+ return 0;
+}
+
+/* This function requires the caller holds hdev->lock */
+void hci_adv_instances_clear(struct hci_dev *hdev)
+{
+ struct adv_info *adv_instance, *n;
+
+ list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
+ list_del(&adv_instance->list);
+ kfree(adv_instance);
+ }
+
+ hdev->adv_instance_cnt = 0;
+}
+
+/* This function requires the caller holds hdev->lock */
+int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
+ u16 adv_data_len, u8 *adv_data,
+ u16 scan_rsp_len, u8 *scan_rsp_data,
+ u16 timeout, u16 duration)
+{
+ struct adv_info *adv_instance;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (adv_instance) {
+ memset(adv_instance->adv_data, 0,
+ sizeof(adv_instance->adv_data));
+ memset(adv_instance->scan_rsp_data, 0,
+ sizeof(adv_instance->scan_rsp_data));
+ } else {
+ if (hdev->adv_instance_cnt >= HCI_MAX_ADV_INSTANCES ||
+ instance < 1 || instance > HCI_MAX_ADV_INSTANCES)
+ return -EOVERFLOW;
+
+ adv_instance = kmalloc(sizeof(*adv_instance), GFP_KERNEL);
+ if (!adv_instance)
+ return -ENOMEM;
+
+ memset(adv_instance, 0, sizeof(*adv_instance));
+ adv_instance->instance = instance;
+ list_add(&adv_instance->list, &hdev->adv_instances);
+ hdev->adv_instance_cnt++;
+ }
+
+ adv_instance->flags = flags;
+ adv_instance->adv_data_len = adv_data_len;
+ adv_instance->scan_rsp_len = scan_rsp_len;
+
+ if (adv_data_len)
+ memcpy(adv_instance->adv_data, adv_data, adv_data_len);
+
+ if (scan_rsp_len)
+ memcpy(adv_instance->scan_rsp_data,
+ scan_rsp_data, scan_rsp_len);
+
+ adv_instance->timeout = timeout;
+
+ if (duration == 0)
+ adv_instance->duration = HCI_DEFAULT_ADV_DURATION;
+ else
+ adv_instance->duration = duration;
+
+ BT_DBG("%s for %dMR", hdev->name, instance);
+
+ return 0;
+}
+
struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *bdaddr_list,
bdaddr_t *bdaddr, u8 type)
{
@@ -3015,6 +3128,8 @@ struct hci_dev *hci_alloc_dev(void)
hdev->manufacturer = 0xffff; /* Default to internal use */
hdev->inq_tx_power = HCI_TX_POWER_INVALID;
hdev->adv_tx_power = HCI_TX_POWER_INVALID;
+ hdev->adv_instance_cnt = 0;
+ hdev->cur_adv_instance = 0x00;

hdev->sniff_max_interval = 800;
hdev->sniff_min_interval = 80;
@@ -3056,6 +3171,7 @@ struct hci_dev *hci_alloc_dev(void)
INIT_LIST_HEAD(&hdev->pend_le_conns);
INIT_LIST_HEAD(&hdev->pend_le_reports);
INIT_LIST_HEAD(&hdev->conn_hash.list);
+ INIT_LIST_HEAD(&hdev->adv_instances);

INIT_WORK(&hdev->rx_work, hci_rx_work);
INIT_WORK(&hdev->cmd_work, hci_cmd_work);
@@ -3249,6 +3365,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
hci_smp_ltks_clear(hdev);
hci_smp_irks_clear(hdev);
hci_remote_oob_data_clear(hdev);
+ hci_adv_instances_clear(hdev);
hci_bdaddr_list_clear(&hdev->le_white_list);
hci_conn_params_clear_all(hdev);
hci_discovery_filter_clear(hdev);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index e41bbe2..92c50a1 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -6813,7 +6813,7 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
rp->supported_flags = cpu_to_le32(supported_flags);
rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
- rp->max_instances = 1;
+ rp->max_instances = HCI_MAX_ADV_INSTANCES;

/* Currently only one instance is supported, so simply return the
* current instance number.
--
1.9.1


2015-06-18 01:16:35

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v8 02/20] Bluetooth: hci_core/mgmt: move adv timeout to hdev

Currently the delayed work managing advertising duration and timeout is
part of the advertising instance structure. This is not correct as only
a single instance can be advertised at any given time. To implement
round robin advertising a single delayed work structure is needed.

To fix this the delayed work structure is being moved to the hci_dev
structure. The instance specific variable is renamed to "remaining_time"
to make it clear that this is the remaining lifetime of the instance and
not the current advertising timeout.

Signed-off-by: Florian Grandel <[email protected]>
---
include/net/bluetooth/hci_core.h | 5 ++++-
net/bluetooth/hci_core.c | 29 +++++++++++++++++++++++++++++
net/bluetooth/mgmt.c | 27 +++++++++++----------------
3 files changed, 44 insertions(+), 17 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 4242dbf..b53e1b1 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -156,11 +156,11 @@ struct oob_data {
};

struct adv_info {
- struct delayed_work timeout_exp;
struct list_head list;
__u8 instance;
__u32 flags;
__u16 timeout;
+ __u16 remaining_time;
__u16 duration;
__u16 adv_data_len;
__u8 adv_data[HCI_MAX_AD_LENGTH];
@@ -382,6 +382,8 @@ struct hci_dev {
struct list_head adv_instances;
unsigned int adv_instance_cnt;
__u8 cur_adv_instance;
+ __u16 adv_instance_timeout;
+ struct delayed_work adv_instance_expire;

__u8 irk[16];
__u32 rpa_timeout;
@@ -1379,6 +1381,7 @@ void mgmt_set_powered_failed(struct hci_dev *hdev, int err);
int mgmt_powered(struct hci_dev *hdev, u8 powered);
int mgmt_update_adv_data(struct hci_dev *hdev);
void mgmt_discoverable_timeout(struct hci_dev *hdev);
+void mgmt_adv_timeout_expired(struct hci_dev *hdev);
void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
bool persistent);
void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index ebf37eb..d1110db 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1591,6 +1591,11 @@ static int hci_dev_do_close(struct hci_dev *hdev)
if (hci_dev_test_flag(hdev, HCI_MGMT))
cancel_delayed_work_sync(&hdev->rpa_expired);

+ if (hdev->adv_instance_timeout) {
+ cancel_delayed_work_sync(&hdev->adv_instance_expire);
+ hdev->adv_instance_timeout = 0;
+ }
+
/* Avoid potential lockdep warnings from the *_flush() calls by
* ensuring the workqueue is empty up front.
*/
@@ -2147,6 +2152,17 @@ static void hci_discov_off(struct work_struct *work)
mgmt_discoverable_timeout(hdev);
}

+static void hci_adv_timeout_expire(struct work_struct *work)
+{
+ struct hci_dev *hdev;
+
+ hdev = container_of(work, struct hci_dev, adv_instance_expire.work);
+
+ BT_DBG("%s", hdev->name);
+
+ mgmt_adv_timeout_expired(hdev);
+}
+
void hci_uuids_clear(struct hci_dev *hdev)
{
struct bt_uuid *uuid, *tmp;
@@ -2650,6 +2666,11 @@ int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance)

BT_DBG("%s removing %dMR", hdev->name, instance);

+ if (hdev->cur_adv_instance == instance && hdev->adv_instance_timeout) {
+ cancel_delayed_work(&hdev->adv_instance_expire);
+ hdev->adv_instance_timeout = 0;
+ }
+
list_del(&adv_instance->list);
kfree(adv_instance);

@@ -2663,6 +2684,11 @@ void hci_adv_instances_clear(struct hci_dev *hdev)
{
struct adv_info *adv_instance, *n;

+ if (hdev->adv_instance_timeout) {
+ cancel_delayed_work(&hdev->adv_instance_expire);
+ hdev->adv_instance_timeout = 0;
+ }
+
list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
list_del(&adv_instance->list);
kfree(adv_instance);
@@ -2712,6 +2738,7 @@ int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
scan_rsp_data, scan_rsp_len);

adv_instance->timeout = timeout;
+ adv_instance->remaining_time = timeout;

if (duration == 0)
adv_instance->duration = HCI_DEFAULT_ADV_DURATION;
@@ -3130,6 +3157,7 @@ struct hci_dev *hci_alloc_dev(void)
hdev->adv_tx_power = HCI_TX_POWER_INVALID;
hdev->adv_instance_cnt = 0;
hdev->cur_adv_instance = 0x00;
+ hdev->adv_instance_timeout = 0;

hdev->sniff_max_interval = 800;
hdev->sniff_min_interval = 80;
@@ -3183,6 +3211,7 @@ struct hci_dev *hci_alloc_dev(void)
INIT_DELAYED_WORK(&hdev->discov_off, hci_discov_off);
INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work);
INIT_DELAYED_WORK(&hdev->le_scan_restart, le_scan_restart_work);
+ INIT_DELAYED_WORK(&hdev->adv_instance_expire, hci_adv_timeout_expire);

skb_queue_head_init(&hdev->rx_q);
skb_queue_head_init(&hdev->cmd_q);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 92c50a1..a8319f6 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1466,8 +1466,8 @@ static void clear_adv_instance(struct hci_dev *hdev)
if (!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
return;

- if (hdev->adv_instance.timeout)
- cancel_delayed_work(&hdev->adv_instance.timeout_exp);
+ if (hdev->adv_instance_timeout)
+ cancel_delayed_work(&hdev->adv_instance_expire);

memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
advertising_removed(NULL, hdev, 1);
@@ -1497,7 +1497,7 @@ static int clean_up_hci_state(struct hci_dev *hdev)
hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
}

- if (hdev->adv_instance.timeout)
+ if (hdev->adv_instance_timeout)
clear_adv_instance(hdev);

if (hci_dev_test_flag(hdev, HCI_LE_ADV))
@@ -6914,12 +6914,9 @@ unlock:
hci_dev_unlock(hdev);
}

-static void adv_timeout_expired(struct work_struct *work)
+void mgmt_adv_timeout_expired(struct hci_dev *hdev)
{
- struct hci_dev *hdev = container_of(work, struct hci_dev,
- adv_instance.timeout_exp.work);
-
- hdev->adv_instance.timeout = 0;
+ hdev->adv_instance_timeout = 0;

hci_dev_lock(hdev);
clear_adv_instance(hdev);
@@ -6981,8 +6978,6 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}

- INIT_DELAYED_WORK(&hdev->adv_instance.timeout_exp, adv_timeout_expired);
-
hdev->adv_instance.flags = flags;
hdev->adv_instance.adv_data_len = cp->adv_data_len;
hdev->adv_instance.scan_rsp_len = cp->scan_rsp_len;
@@ -6994,14 +6989,14 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
memcpy(hdev->adv_instance.scan_rsp_data,
cp->data + cp->adv_data_len, cp->scan_rsp_len);

- if (hdev->adv_instance.timeout)
- cancel_delayed_work(&hdev->adv_instance.timeout_exp);
+ if (hdev->adv_instance_timeout)
+ cancel_delayed_work(&hdev->adv_instance_expire);

- hdev->adv_instance.timeout = timeout;
+ hdev->adv_instance_timeout = timeout;

if (timeout)
queue_delayed_work(hdev->workqueue,
- &hdev->adv_instance.timeout_exp,
+ &hdev->adv_instance_expire,
msecs_to_jiffies(timeout * 1000));

if (!hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING_INSTANCE))
@@ -7106,8 +7101,8 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}

- if (hdev->adv_instance.timeout)
- cancel_delayed_work(&hdev->adv_instance.timeout_exp);
+ if (hdev->adv_instance_timeout)
+ cancel_delayed_work(&hdev->adv_instance_expire);

memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));

--
1.9.1


2015-06-18 01:16:33

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v8 00/20] Multi-advertising

patch set introducing the infrastructure for multi-advertising
capability to the HCI core and mgmt API.

v1 -> v2:
- add missing braces in read_adv_features()

v2 -> v3 (changes due to Johan's review):
- split change-set into several patches
- replace err == 0 by !err
- fix coding style problems

v3 -> v4 (changes due to Arman's review):
- bug fix: when calling remove_advertising with an instance value of
zero (i.e. remove all instances), the command response also returns
an instance value of zero now as it doesn't make sense to return a
single instance id when removing several instances
- splitting the change set into a much larger number of patches to
facilitate review
- use HCI_MAX_ADV_INSTANCES in the same patch that introduces it
- use adv_info->hdev in the same patch that introduces it
- make the logic of hci_find_adv_instance() more readable
- make sure that hci_find_adv_instance() is called while hci_dev is
locked
- replace hci_num_adv_instances() by an instance counter in hci_dev
- add inline comment in get_adv_instance_flags() explaining its return
value in the error case
- generate zero-length adv data if the current instance identifier is
invalid
- revert erroneous changes to the logic in clear_adv_instance()
- use hci_adv_instances_clear() in clear_adv_instance() when removing
all advertising instances also removing a redundant error check
- inserting TODO messages to make sure that advertising will not be
switched off prematurely once we allow more than one advertising
instance
- inserting TODO messages to make sure that multiple advertising
instances will be advertised in a round-robin fashion once we allow
for more than one advertising instance
- identify pending advertising instances (just added but not yet
confirmed in add_advertising_complete) by a boolean flag in the
adv_info struct so that we can identify and remove them even when the
pending add_advertising command cannot be retrieved for some reason -
makes sure that we do not leak advertising instances in this case
- only send HCI commands to update advertising data when a new instance
has actually been added

v4 -> v5 (changes due to Marcel's review):
- split into separate change sets for kernel and userspace
- do not trust the adv instance list length when compiling the adv
features struct
- introduce adv_info->pending in the same patch it's used for the first
time

v5 -> v6 (changes due to Marcel's review):
- fix the add adv override bug
- fix "Using plain integer as NULL pointer" warning in
set_advertising_complete()
- reword the "remove adv instance" commit comment to make it clear that
an existing bug is being fixed

v6 -> v7:
- so far the patch set only contained a functionally neutral refactoring
to provide the basic infrastructure for multi-advertising. It has been
decided, though, that the patch set should provide the whole package
at once, including actual multi-advertising functionality. This has
been implemented and tested in the latest version of the patch set.

v7 -> v8 (changes due to Marcel's review):
- switch to next instance when updating the currently advertised
instance
- keep instances without timeout during power cycles

Florian Grandel (20):
Bluetooth: hci_core/mgmt: Introduce multi-adv list
Bluetooth: hci_core/mgmt: move adv timeout to hdev
Bluetooth: mgmt: dry update_scan_rsp_data()
Bluetooth: mgmt: rename update_*_data_for_instance()
Bluetooth: mgmt: multi adv for read_adv_features()
Bluetooth: mgmt: multi adv for get_current_adv_instance()
Bluetooth: mgmt: multi adv for get_adv_instance_flags()
Bluetooth: mgmt: improve get_adv_instance_flags() readability
Bluetooth: mgmt: multi adv for enable_advertising()
Bluetooth: mgmt: multi adv for create_instance_scan_rsp_data()
Bluetooth: mgmt: multi adv for create_instance_adv_data()
Bluetooth: mgmt: multi adv for set_advertising*()
Bluetooth: mgmt: multi adv for clear_adv_instances()
Bluetooth: mgmt/hci_core: multi-adv for add_advertising*()
Bluetooth: mgmt: multi adv for remove_advertising*()
Bluetooth: mgmt: program multi-adv on power on
Bluetooth: mgmt: multi-adv for trigger_le_scan()
Bluetooth: mgmt: multi-adv for mgmt_reenable_advertising()
Bluetooth: hci_core: remove obsolete adv_instance
Bluetooth: hci_core: increase max adv inst

include/net/bluetooth/hci_core.h | 29 +-
net/bluetooth/hci_core.c | 148 +++++++++-
net/bluetooth/mgmt.c | 563 +++++++++++++++++++++++++++------------
3 files changed, 565 insertions(+), 175 deletions(-)

--
1.9.1


2015-06-16 09:59:44

by Florian Grandel

[permalink] [raw]
Subject: Re: [BlueZ v8 01/15] doc/mgmt-api: multi-adv implementation details

Hi Marcel,

On 06/15/2015 01:33 PM, Marcel Holtmann wrote:
> Hi Floran,
>
>> A few additional decisions have been made while implementing the
>> multi-advertising feature where the mgmt api spec was leaving room for
>> interpretation. These changes are being documented in this patch.
>> ---
>> doc/mgmt-api.txt | 66 +++++++++++++++++++++++++++++++++++++++++++++-----------
>> 1 file changed, 54 insertions(+), 12 deletions(-)
>>
>> diff --git a/doc/mgmt-api.txt b/doc/mgmt-api.txt
>> index 4b97aad..0ac8267 100644
>> --- a/doc/mgmt-api.txt
>> +++ b/doc/mgmt-api.txt
>> @@ -305,6 +305,14 @@ Set Powered Command
>> switching the controller off will expire this timeout and
>> disable discoverable.
>>
>> + Settings programmed via Set Advertising and Add/Remove
>> + Advertising while the controller was powered off will be activated
>> + when powering the controller on.
>> +
>> + Switching the controller off will permanently cancel and remove
>> + all configured advertising instances, i.e. advertising instances
>> + are not being remembered across power cycles.
>> +
>
> actually only the ones with a duration will be cancelled. The ones not having a duration should survive a power cycle. That is how we have done it currently and that is also how discoverable and limited discoverable works.

I assume you mean "timeout" rather than "duration"? That would
correspond to the behavior of adding instances while powered down.

>
>> This command generates a Command Complete event on success or
>> a Command Status event on failure.
>>
>> @@ -585,6 +593,10 @@ Set Low Energy Command
>> In case the kernel subsystem does not support Low Energy or the
>> controller does not either, the command will fail regardless.
>>
>> + Disabling LE support will permanently disable and remove all
>> + advertising instances configured with the Add Advertising
>> + command.
>> +
>
> This something I am actually fine with. As long as we send the correct events to inform that the advertising setting are removed. This should then also apply to everything added via Add Device. In in similar regards apply to disabling BR/EDR.

Yes, these events are being generated (on LE off and on Power down). I
explicitly mention this in the spec now.

>
>> This command generates a Command Complete event on success or
>> a Command Status event on failure.
>>
>> @@ -1594,6 +1606,10 @@ Set Advertising Command
>>
>> Using this command will temporarily deactive any configuration
>> made by the Add Advertising command. This command takes precedence.
>> + Once a Set Advertising command with value 0x00 is issued any
>> + previously made configurations via Add/Remove Advertising, including
>> + such changes made while Set Advertising was active, will be re-
>> + enabled, though.
>
> I assumed this was clear, but I am fine with adding an extra note about this. Just remove the "though" in the text since that does not read well.

Done.

>
>>
>> A pre-requisite is that LE is already enabled, otherwise this
>> command will return a "rejected" response.
>> @@ -2548,9 +2564,11 @@ Add Advertising Command
>> can be used to switch a Bluetooth Low Energy controller into
>> advertising mode.
>>
>> - Added advertising information with this command will be ignored
>> - when using the Set Advertising command to enable advertising. The
>> - usage of Set Advertising command take precedence over this command.
>> + Added advertising information with this command will be ignored as
>> + long as advertising is enabled via the Set Advertising command. The
>> + usage of the Set Advertising command takes precedence over this
>> + command. Instance information is stored, though, and will be
>> + advertised once advertising via Set Advertising has been disabled.
>
> No "though" please in the text. Smaller sentences with clear details make this easier to read.

Done. I also replaced "ignored" by "invisible" as it was misleading in
the same way as it was for the "Remove Advertising" command below.

>
>>
>> The Instance identifier is a value between 1 and the number of
>> supported instances. The value 0 is reserved.
>> @@ -2593,13 +2611,13 @@ Add Advertising Command
>> broadcaster role.
>>
>> The Duration parameter configures the length of an Instance. The
>> - value is in seconds and a value of 0 indicates an automatic choice
>> - for the Duration. If only one advertising Instance has been added,
>> - then the Duration value will be ignored. It only applies for the
>> - case where multiple Instances are configured. In that case every
>> - Instance will be available for the Duration time and after that
>> - it switches to the next one. This is a simple round-robin based
>> - approach.
>> + value is in seconds and a value of 0 indicates a default value
>> + (currently 2 seconds) will be chosen for the Duration. If only
>> + one advertising Instance has been added, then the Duration value
>> + will be ignored. It only applies for the case where multiple
>> + Instances are configured. In that case every Instance will be
>> + available for the Duration time and after that it switches to
>> + the next one. This is a simple round-robin based approach.
>
> Just add a separate paragraph that talks about the default of 2 seconds. And we really need to figure out the best value here.

Done. The value can be easily changed via #define once you decide what
default is appropriate.

>
>>
>> The Timeout parameter configures the life-time of an Instance. In
>> case the value 0 is used it indicates no expiration time. If a
>> @@ -2611,8 +2629,21 @@ Add Advertising Command
>>
>> When a Timeout is provided, then the Duration substracts from
>> the actual Timeout value of that Instance. For example an Instance
>> - with Timeout of 6 and Duration of 2 will be scheduled exactly 3
>> - times. Other Instances have no influence on the Timeout.
>> + with Timeout of 5 and Duration of 2 will be scheduled exactly 3
>> + times, twice with 2 seconds and once with one second. Other
>> + Instances have no influence on the Timeout.
>> +
>> + Re-adding an already existing instance (i.e. issuing the Add
>> + Advertising command with an Instance identifier of an existing
>> + instance) will update that instance's configuration.
>> +
>> + An instance being added or changed while another instance is
>> + being advertised will not be visible immediately but only when
>> + the new/changed instance is being scheduled by the round robin
>> + advertising algorithm. Changes to an instance that is currently
>> + being advertised will be visible right away, i.e. the previous
>> + configuration will be canceled immediately and the new
>> + one activated.
>
> Actually that is not fully correct. I think modifying an existing instance will stop it right away and go to the next instance. In case that only a single instance is active, then it will actually change right away.

Ok. I'll document the behavior as you describe it and change the
implementation accordingly.

>
>>
>> A pre-requisite is that LE is already enabled, otherwise this
>> command will return a "rejected" response.
>> @@ -2645,6 +2676,17 @@ Remove Advertising Command
>> When the Instance parameter is zero, then all previously added
>> advertising Instances will be removed.
>>
>> + Removing advertising information with this command will be ignored
>> + as long as advertising is enabled via the Set Advertising command.
>> + The usage of the Set Advertising command takes precedence over this
>> + command. Changes to Instance information are stored, though, and
>> + will be advertised once advertising via Set Advertising has been
>> + disabled.
>
> This is bogus. The instance will be removed. However it will not change the current active advertising, but it really means that instance is gone.

You are right. That's how it has been implemented anyway. I changed the
text to correctly describe the actual behavior.

>
>> +
>> + Removing an instance while it is being advertised will immediately
>> + cancel the instance, even when it has been advertised less then its
>> + configured Timeout or Duration.
>> +
>> This command can be used when the controller is not powered and
>> all settings will be programmed once powered.
>
> Regards
>
> Marcel

Florian

2015-06-15 11:33:51

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [BlueZ v8 01/15] doc/mgmt-api: multi-adv implementation details

Hi Floran,

> A few additional decisions have been made while implementing the
> multi-advertising feature where the mgmt api spec was leaving room for
> interpretation. These changes are being documented in this patch.
> ---
> doc/mgmt-api.txt | 66 +++++++++++++++++++++++++++++++++++++++++++++-----------
> 1 file changed, 54 insertions(+), 12 deletions(-)
>
> diff --git a/doc/mgmt-api.txt b/doc/mgmt-api.txt
> index 4b97aad..0ac8267 100644
> --- a/doc/mgmt-api.txt
> +++ b/doc/mgmt-api.txt
> @@ -305,6 +305,14 @@ Set Powered Command
> switching the controller off will expire this timeout and
> disable discoverable.
>
> + Settings programmed via Set Advertising and Add/Remove
> + Advertising while the controller was powered off will be activated
> + when powering the controller on.
> +
> + Switching the controller off will permanently cancel and remove
> + all configured advertising instances, i.e. advertising instances
> + are not being remembered across power cycles.
> +

actually only the ones with a duration will be cancelled. The ones not having a duration should survive a power cycle. That is how we have done it currently and that is also how discoverable and limited discoverable works.

> This command generates a Command Complete event on success or
> a Command Status event on failure.
>
> @@ -585,6 +593,10 @@ Set Low Energy Command
> In case the kernel subsystem does not support Low Energy or the
> controller does not either, the command will fail regardless.
>
> + Disabling LE support will permanently disable and remove all
> + advertising instances configured with the Add Advertising
> + command.
> +

This something I am actually fine with. As long as we send the correct events to inform that the advertising setting are removed. This should then also apply to everything added via Add Device. In in similar regards apply to disabling BR/EDR.

> This command generates a Command Complete event on success or
> a Command Status event on failure.
>
> @@ -1594,6 +1606,10 @@ Set Advertising Command
>
> Using this command will temporarily deactive any configuration
> made by the Add Advertising command. This command takes precedence.
> + Once a Set Advertising command with value 0x00 is issued any
> + previously made configurations via Add/Remove Advertising, including
> + such changes made while Set Advertising was active, will be re-
> + enabled, though.

I assumed this was clear, but I am fine with adding an extra note about this. Just remove the "though" in the text since that does not read well.

>
> A pre-requisite is that LE is already enabled, otherwise this
> command will return a "rejected" response.
> @@ -2548,9 +2564,11 @@ Add Advertising Command
> can be used to switch a Bluetooth Low Energy controller into
> advertising mode.
>
> - Added advertising information with this command will be ignored
> - when using the Set Advertising command to enable advertising. The
> - usage of Set Advertising command take precedence over this command.
> + Added advertising information with this command will be ignored as
> + long as advertising is enabled via the Set Advertising command. The
> + usage of the Set Advertising command takes precedence over this
> + command. Instance information is stored, though, and will be
> + advertised once advertising via Set Advertising has been disabled.

No "though" please in the text. Smaller sentences with clear details make this easier to read.

>
> The Instance identifier is a value between 1 and the number of
> supported instances. The value 0 is reserved.
> @@ -2593,13 +2611,13 @@ Add Advertising Command
> broadcaster role.
>
> The Duration parameter configures the length of an Instance. The
> - value is in seconds and a value of 0 indicates an automatic choice
> - for the Duration. If only one advertising Instance has been added,
> - then the Duration value will be ignored. It only applies for the
> - case where multiple Instances are configured. In that case every
> - Instance will be available for the Duration time and after that
> - it switches to the next one. This is a simple round-robin based
> - approach.
> + value is in seconds and a value of 0 indicates a default value
> + (currently 2 seconds) will be chosen for the Duration. If only
> + one advertising Instance has been added, then the Duration value
> + will be ignored. It only applies for the case where multiple
> + Instances are configured. In that case every Instance will be
> + available for the Duration time and after that it switches to
> + the next one. This is a simple round-robin based approach.

Just add a separate paragraph that talks about the default of 2 seconds. And we really need to figure out the best value here.

>
> The Timeout parameter configures the life-time of an Instance. In
> case the value 0 is used it indicates no expiration time. If a
> @@ -2611,8 +2629,21 @@ Add Advertising Command
>
> When a Timeout is provided, then the Duration substracts from
> the actual Timeout value of that Instance. For example an Instance
> - with Timeout of 6 and Duration of 2 will be scheduled exactly 3
> - times. Other Instances have no influence on the Timeout.
> + with Timeout of 5 and Duration of 2 will be scheduled exactly 3
> + times, twice with 2 seconds and once with one second. Other
> + Instances have no influence on the Timeout.
> +
> + Re-adding an already existing instance (i.e. issuing the Add
> + Advertising command with an Instance identifier of an existing
> + instance) will update that instance's configuration.
> +
> + An instance being added or changed while another instance is
> + being advertised will not be visible immediately but only when
> + the new/changed instance is being scheduled by the round robin
> + advertising algorithm. Changes to an instance that is currently
> + being advertised will be visible right away, i.e. the previous
> + configuration will be canceled immediately and the new
> + one activated.

Actually that is not fully correct. I think modifying an existing instance will stop it right away and go to the next instance. In case that only a single instance is active, then it will actually change right away.

>
> A pre-requisite is that LE is already enabled, otherwise this
> command will return a "rejected" response.
> @@ -2645,6 +2676,17 @@ Remove Advertising Command
> When the Instance parameter is zero, then all previously added
> advertising Instances will be removed.
>
> + Removing advertising information with this command will be ignored
> + as long as advertising is enabled via the Set Advertising command.
> + The usage of the Set Advertising command takes precedence over this
> + command. Changes to Instance information are stored, though, and
> + will be advertised once advertising via Set Advertising has been
> + disabled.

This is bogus. The instance will be removed. However it will not change the current active advertising, but it really means that instance is gone.

> +
> + Removing an instance while it is being advertised will immediately
> + cancel the instance, even when it has been advertised less then its
> + configured Timeout or Duration.
> +
> This command can be used when the controller is not powered and
> all settings will be programmed once powered.

Regards

Marcel


2015-06-13 03:42:59

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v8 15/15] tools/mgmt-tester: test multi-adv

This patch adds tests and required test infrastructure for multi
advertising tests.
---
doc/test-coverage.txt | 4 +-
tools/mgmt-tester.c | 211 ++++++++++++++++++++++++++++++++++++++++++++------
2 files changed, 188 insertions(+), 27 deletions(-)

diff --git a/doc/test-coverage.txt b/doc/test-coverage.txt
index 50e29b5..399a960 100644
--- a/doc/test-coverage.txt
+++ b/doc/test-coverage.txt
@@ -39,7 +39,7 @@ Automated end-to-end testing

Application Count Description
-------------------------------------------
-mgmt-tester 299 Kernel management interface testing
+mgmt-tester 301 Kernel management interface testing
l2cap-tester 27 Kernel L2CAP implementation testing
rfcomm-tester 9 Kernel RFCOMM implementation testing
bnep-tester 1 Kernel BNEP implementation testing
@@ -49,7 +49,7 @@ gap-tester 1 Daemon D-Bus API testing
hci-tester 14 Controller hardware testing
userchan-tester 3 Kernel HCI User Channel testting
-----
- 370
+ 372


Android end-to-end testing
diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 465ad42..cf5dc51 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -3990,10 +3990,28 @@ static const uint8_t add_advertising_param_txpwr[] = {
0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
};

+/* add advertising command for a second instance */
+static const uint8_t add_advertising_param_test2[] = {
+ 0x02, /* adv instance */
+ 0x00, 0x00, 0x00, 0x00, /* flags: none */
+ 0x00, 0x00, /* duration: default */
+ 0x01, 0x00, /* timeout: 1 second */
+ 0x07, /* adv data len */
+ 0x00, /* scan rsp len */
+ /* adv data: */
+ 0x06, /* AD len */
+ 0x08, /* AD type: shortened local name */
+ 0x74, 0x65, 0x73, 0x74, 0x32, /* "test2" */
+};
+
static const uint8_t advertising_instance1_param[] = {
0x01,
};

+static const uint8_t advertising_instance2_param[] = {
+ 0x02,
+};
+
static const uint8_t set_adv_data_uuid[] = {
/* adv data len */
0x09,
@@ -4005,15 +4023,26 @@ static const uint8_t set_adv_data_uuid[] = {
0x00, 0x00,
};

-static const uint8_t set_adv_data_test[] = {
- 0x06, /* adv data len */
- 0x05, /* AD len */
- 0x08, /* AD type: shortened local name */
- 0x74, 0x65, 0x73, 0x74, /* "test" */
+static const uint8_t set_adv_data_test1[] = {
+ 0x07, /* adv data len */
+ 0x06, /* AD len */
+ 0x08, /* AD type: shortened local name */
+ 0x74, 0x65, 0x73, 0x74, 0x31, /* "test1" */
/* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+};
+
+static const uint8_t set_adv_data_test2[] = {
+ 0x07, /* adv data len */
+ 0x06, /* AD len */
+ 0x08, /* AD type: shortened local name */
+ 0x74, 0x65, 0x73, 0x74, 0x32, /* "test2" */
+ /* padding */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
};

static const uint8_t set_adv_data_txpwr[] = {
@@ -4277,8 +4306,8 @@ static const struct generic_data add_advertising_success_2 = {
.expect_param = set_powered_adv_instance_settings_param,
.expect_len = sizeof(set_powered_adv_instance_settings_param),
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
- .expect_hci_param = set_adv_data_test,
- .expect_hci_len = sizeof(set_adv_data_test),
+ .expect_hci_param = set_adv_data_test1,
+ .expect_hci_len = sizeof(set_adv_data_test1),
};

static const struct generic_data add_advertising_success_3 = {
@@ -4315,8 +4344,8 @@ static const struct generic_data add_advertising_success_5 = {
.expect_param = set_powered_adv_instance_settings_param,
.expect_len = sizeof(set_powered_adv_instance_settings_param),
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
- .expect_hci_param = set_adv_data_test,
- .expect_hci_len = sizeof(set_adv_data_test),
+ .expect_hci_param = set_adv_data_test1,
+ .expect_hci_len = sizeof(set_adv_data_test1),
};

static const struct generic_data add_advertising_success_6 = {
@@ -4595,6 +4624,31 @@ static const struct generic_data remove_advertising_success_2 = {
.expect_hci_len = sizeof(set_adv_off_param),
};

+static const struct generic_data multi_advertising_switch = {
+ .send_opcode = TESTER_NOOP_OPCODE,
+ .expect_alt_ev = MGMT_EV_ADVERTISING_REMOVED,
+ .expect_alt_ev_param = advertising_instance1_param,
+ .expect_alt_ev_len = sizeof(advertising_instance1_param),
+ .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
+ .expect_hci_param = set_adv_data_test2,
+ .expect_hci_len = sizeof(set_adv_data_test2),
+};
+
+static const struct generic_data multi_advertising_add_second = {
+ .send_opcode = MGMT_OP_ADD_ADVERTISING,
+ .send_param = add_advertising_param_test2,
+ .send_len = sizeof(add_advertising_param_test2),
+ .expect_param = advertising_instance2_param,
+ .expect_len = sizeof(advertising_instance2_param),
+ .expect_status = MGMT_STATUS_SUCCESS,
+ .expect_alt_ev = MGMT_EV_ADVERTISING_ADDED,
+ .expect_alt_ev_param = advertising_instance2_param,
+ .expect_alt_ev_len = sizeof(advertising_instance2_param),
+ .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
+ .expect_hci_param = set_adv_data_test2,
+ .expect_hci_len = sizeof(set_adv_data_test2),
+};
+
/* based on G-Tag ADV_DATA */
static const uint8_t adv_data_invalid_significant_len[] = { 0x02, 0x01, 0x06,
0x0d, 0xff, 0x80, 0x01, 0x02, 0x15, 0x12, 0x34, 0x80, 0x91,
@@ -5015,40 +5069,48 @@ static void setup_add_device(const void *test_data)
static void setup_add_advertising_callback(uint8_t status, uint16_t length,
const void *param, void *user_data)
{
+ struct mgmt_rp_add_advertising *rp =
+ (struct mgmt_rp_add_advertising *) param;
+
if (status != MGMT_STATUS_SUCCESS) {
tester_setup_failed();
return;
}

- tester_print("Add Advertising setup complete");
+ tester_print("Add Advertising setup complete (instance %d)",
+ rp->instance);

setup_bthost();
}

-static void setup_add_adv_param(struct mgmt_cp_add_advertising *cp)
+#define TESTER_ADD_ADV_DATA_LEN 7
+
+static void setup_add_adv_param(struct mgmt_cp_add_advertising *cp,
+ uint8_t instance)
{
memset(cp, 0, sizeof(*cp));
- cp->instance = 1;
- cp->adv_data_len = 6;
- cp->data[0] = 0x05; /* AD len */
+ cp->instance = instance;
+ cp->adv_data_len = TESTER_ADD_ADV_DATA_LEN;
+ cp->data[0] = TESTER_ADD_ADV_DATA_LEN - 1; /* AD len */
cp->data[1] = 0x08; /* AD type: shortened local name */
cp->data[2] = 't'; /* adv data ... */
cp->data[3] = 'e';
cp->data[4] = 's';
cp->data[5] = 't';
+ cp->data[6] = '0' + instance;
}

static void setup_add_advertising_not_powered(const void *test_data)
{
struct test_data *data = tester_get_data();
struct mgmt_cp_add_advertising *cp;
- unsigned char adv_param[sizeof(*cp) + 6];
+ unsigned char adv_param[sizeof(*cp) + TESTER_ADD_ADV_DATA_LEN];
unsigned char param[] = { 0x01 };

tester_print("Adding advertising instance while unpowered");

cp = (struct mgmt_cp_add_advertising *) adv_param;
- setup_add_adv_param(cp);
+ setup_add_adv_param(cp, 1);

mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
sizeof(param), &param,
@@ -5064,13 +5126,13 @@ static void setup_add_advertising(const void *test_data)
{
struct test_data *data = tester_get_data();
struct mgmt_cp_add_advertising *cp;
- unsigned char adv_param[sizeof(*cp) + 6];
+ unsigned char adv_param[sizeof(*cp) + TESTER_ADD_ADV_DATA_LEN];
unsigned char param[] = { 0x01 };

tester_print("Adding advertising instance while powered");

cp = (struct mgmt_cp_add_advertising *) adv_param;
- setup_add_adv_param(cp);
+ setup_add_adv_param(cp, 1);

mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
sizeof(param), &param,
@@ -5090,13 +5152,13 @@ static void setup_add_advertising_connectable(const void *test_data)
{
struct test_data *data = tester_get_data();
struct mgmt_cp_add_advertising *cp;
- unsigned char adv_param[sizeof(*cp) + 6];
+ unsigned char adv_param[sizeof(*cp) + TESTER_ADD_ADV_DATA_LEN];
unsigned char param[] = { 0x01 };

tester_print("Adding advertising instance while connectable");

cp = (struct mgmt_cp_add_advertising *) adv_param;
- setup_add_adv_param(cp);
+ setup_add_adv_param(cp, 1);

mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
sizeof(param), &param,
@@ -5120,13 +5182,13 @@ static void setup_add_advertising_timeout(const void *test_data)
{
struct test_data *data = tester_get_data();
struct mgmt_cp_add_advertising *cp;
- unsigned char adv_param[sizeof(*cp) + 6];
+ unsigned char adv_param[sizeof(*cp) + TESTER_ADD_ADV_DATA_LEN];
unsigned char param[] = { 0x01 };

tester_print("Adding advertising instance with timeout");

cp = (struct mgmt_cp_add_advertising *) adv_param;
- setup_add_adv_param(cp);
+ setup_add_adv_param(cp, 1);
cp->timeout = 1;

mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
@@ -5143,17 +5205,45 @@ static void setup_add_advertising_timeout(const void *test_data)
NULL, NULL);
}

+static void setup_add_advertising_duration(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ struct mgmt_cp_add_advertising *cp;
+ unsigned char adv_param[sizeof(*cp) + TESTER_ADD_ADV_DATA_LEN];
+ unsigned char param[] = { 0x01 };
+
+ tester_print("Adding instance with long timeout/short duration");
+
+ cp = (struct mgmt_cp_add_advertising *) adv_param;
+ setup_add_adv_param(cp, 1);
+ cp->duration = 1;
+ cp->timeout = 30;
+
+ mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
+ sizeof(param), &param,
+ NULL, NULL, NULL);
+
+ mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+ sizeof(param), &param,
+ NULL, NULL, NULL);
+
+ mgmt_send(data->mgmt, MGMT_OP_ADD_ADVERTISING, data->mgmt_index,
+ sizeof(adv_param), adv_param,
+ setup_add_advertising_callback,
+ NULL, NULL);
+}
+
static void setup_set_and_add_advertising(const void *test_data)
{
struct test_data *data = tester_get_data();
struct mgmt_cp_add_advertising *cp;
- unsigned char adv_param[sizeof(*cp) + 6];
+ unsigned char adv_param[sizeof(*cp) + TESTER_ADD_ADV_DATA_LEN];
unsigned char param[] = { 0x01 };

tester_print("Set and add advertising instance");

cp = (struct mgmt_cp_add_advertising *) adv_param;
- setup_add_adv_param(cp);
+ setup_add_adv_param(cp, 1);

mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
sizeof(param), &param,
@@ -5173,6 +5263,61 @@ static void setup_set_and_add_advertising(const void *test_data)
NULL, NULL);
}

+static void setup_multi_adv_second_instance(uint8_t status, uint16_t length,
+ const void *param, void *user_data) {
+ struct mgmt_rp_add_advertising *rp =
+ (struct mgmt_rp_add_advertising *) param;
+ struct test_data *data = tester_get_data();
+ struct mgmt_cp_add_advertising *cp;
+ unsigned char adv_param[sizeof(*cp) + TESTER_ADD_ADV_DATA_LEN];
+
+ if (status != MGMT_STATUS_SUCCESS) {
+ tester_setup_failed();
+ return;
+ }
+
+ tester_print("Add Advertising setup complete (instance %d)",
+ rp->instance);
+
+ cp = (struct mgmt_cp_add_advertising *) adv_param;
+ setup_add_adv_param(cp, 2);
+ cp->timeout = 1;
+ cp->duration = 1;
+
+ mgmt_send(data->mgmt, MGMT_OP_ADD_ADVERTISING, data->mgmt_index,
+ sizeof(adv_param), adv_param,
+ setup_add_advertising_callback,
+ NULL, NULL);
+}
+
+static void setup_multi_adv(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ struct mgmt_cp_add_advertising *cp;
+ unsigned char adv_param[sizeof(*cp) + TESTER_ADD_ADV_DATA_LEN];
+ unsigned char param[] = { 0x01 };
+
+ tester_print("Adding two instances with timeout 1 and duration 1");
+
+ cp = (struct mgmt_cp_add_advertising *) adv_param;
+ setup_add_adv_param(cp, 1);
+ cp->timeout = 1;
+ cp->duration = 1;
+
+ mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
+ sizeof(param), &param,
+ NULL, NULL, NULL);
+
+ mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+ sizeof(param), &param,
+ NULL, NULL, NULL);
+
+ mgmt_send(data->mgmt, MGMT_OP_ADD_ADVERTISING, data->mgmt_index,
+ sizeof(adv_param), adv_param,
+ setup_multi_adv_second_instance,
+ NULL, NULL);
+}
+
static void setup_complete(uint8_t status, uint16_t length,
const void *param, void *user_data)
{
@@ -6689,6 +6834,22 @@ int main(int argc, char *argv[])
setup_add_advertising,
test_command_generic);

+ /* When advertising two instances, the instances should be
+ * advertised in a round-robin fashion.
+ */
+ test_bredrle("Multi Advertising - Success 1 (Instance Switch)",
+ &multi_advertising_switch,
+ setup_multi_adv,
+ test_command_generic);
+ /* Adding a new instance when one is already being advertised
+ * will switch to the new instance after the first has reached
+ * its duration. A long timeout has been set to
+ */
+ test_bredrle_full("Multi Advertising - Success 2 (Add Second Inst)",
+ &multi_advertising_add_second,
+ setup_add_advertising_duration,
+ test_command_generic, 3);
+
test_bredrle("Read Local OOB Data - Not powered",
&read_local_oob_not_powered_test,
NULL, test_command_generic);
--
1.9.1


2015-06-13 03:42:58

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v8 14/15] tools/mgmt-tester: fix duplicate code

The definition of the test advertising instance was duplicated in
several places. This patch refactors the duplicate code into a
common subroutine.
---
tools/mgmt-tester.c | 68 ++++++++++++++---------------------------------------
1 file changed, 18 insertions(+), 50 deletions(-)

diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 315c326..465ad42 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -5025,18 +5025,9 @@ static void setup_add_advertising_callback(uint8_t status, uint16_t length,
setup_bthost();
}

-static void setup_add_advertising_not_powered(const void *test_data)
+static void setup_add_adv_param(struct mgmt_cp_add_advertising *cp)
{
- struct test_data *data = tester_get_data();
- struct mgmt_cp_add_advertising *cp;
- unsigned char adv_param[sizeof(*cp) + 6];
- unsigned char param[] = { 0x01 };
-
- tester_print("Adding advertising instance while unpowered");
-
- cp = (struct mgmt_cp_add_advertising *) adv_param;
memset(cp, 0, sizeof(*cp));
-
cp->instance = 1;
cp->adv_data_len = 6;
cp->data[0] = 0x05; /* AD len */
@@ -5045,6 +5036,19 @@ static void setup_add_advertising_not_powered(const void *test_data)
cp->data[3] = 'e';
cp->data[4] = 's';
cp->data[5] = 't';
+}
+
+static void setup_add_advertising_not_powered(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ struct mgmt_cp_add_advertising *cp;
+ unsigned char adv_param[sizeof(*cp) + 6];
+ unsigned char param[] = { 0x01 };
+
+ tester_print("Adding advertising instance while unpowered");
+
+ cp = (struct mgmt_cp_add_advertising *) adv_param;
+ setup_add_adv_param(cp);

mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
sizeof(param), &param,
@@ -5066,16 +5070,7 @@ static void setup_add_advertising(const void *test_data)
tester_print("Adding advertising instance while powered");

cp = (struct mgmt_cp_add_advertising *) adv_param;
- memset(cp, 0, sizeof(*cp));
-
- cp->instance = 1;
- cp->adv_data_len = 6;
- cp->data[0] = 0x05; /* AD len */
- cp->data[1] = 0x08; /* AD type: shortened local name */
- cp->data[2] = 't'; /* adv data ... */
- cp->data[3] = 'e';
- cp->data[4] = 's';
- cp->data[5] = 't';
+ setup_add_adv_param(cp);

mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
sizeof(param), &param,
@@ -5101,16 +5096,7 @@ static void setup_add_advertising_connectable(const void *test_data)
tester_print("Adding advertising instance while connectable");

cp = (struct mgmt_cp_add_advertising *) adv_param;
- memset(cp, 0, sizeof(*cp));
-
- cp->instance = 1;
- cp->adv_data_len = 6;
- cp->data[0] = 0x05; /* AD len */
- cp->data[1] = 0x08; /* AD type: shortened local name */
- cp->data[2] = 't'; /* adv data ... */
- cp->data[3] = 'e';
- cp->data[4] = 's';
- cp->data[5] = 't';
+ setup_add_adv_param(cp);

mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
sizeof(param), &param,
@@ -5140,17 +5126,8 @@ static void setup_add_advertising_timeout(const void *test_data)
tester_print("Adding advertising instance with timeout");

cp = (struct mgmt_cp_add_advertising *) adv_param;
- memset(cp, 0, sizeof(*cp));
-
- cp->instance = 1;
+ setup_add_adv_param(cp);
cp->timeout = 1;
- cp->adv_data_len = 6;
- cp->data[0] = 0x05; /* AD len */
- cp->data[1] = 0x08; /* AD type: shortened local name */
- cp->data[2] = 't'; /* adv data ... */
- cp->data[3] = 'e';
- cp->data[4] = 's';
- cp->data[5] = 't';

mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
sizeof(param), &param,
@@ -5176,16 +5153,7 @@ static void setup_set_and_add_advertising(const void *test_data)
tester_print("Set and add advertising instance");

cp = (struct mgmt_cp_add_advertising *) adv_param;
- memset(cp, 0, sizeof(*cp));
-
- cp->instance = 1;
- cp->adv_data_len = 6;
- cp->data[0] = 0x05; /* AD len */
- cp->data[1] = 0x08; /* AD type: shortened local name */
- cp->data[2] = 't'; /* adv data ... */
- cp->data[3] = 'e';
- cp->data[4] = 's';
- cp->data[5] = 't';
+ setup_add_adv_param(cp);

mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
sizeof(param), &param,
--
1.9.1


2015-06-13 03:42:57

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v8 13/15] tools/mgmt-tester: test le off

Test that advertising instances will be removed when disabling the le
capability of a brle bluetooth device.
---
doc/test-coverage.txt | 4 ++--
tools/mgmt-tester.c | 21 +++++++++++++++++++++
2 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/doc/test-coverage.txt b/doc/test-coverage.txt
index 9c8b9bc..50e29b5 100644
--- a/doc/test-coverage.txt
+++ b/doc/test-coverage.txt
@@ -39,7 +39,7 @@ Automated end-to-end testing

Application Count Description
-------------------------------------------
-mgmt-tester 298 Kernel management interface testing
+mgmt-tester 299 Kernel management interface testing
l2cap-tester 27 Kernel L2CAP implementation testing
rfcomm-tester 9 Kernel RFCOMM implementation testing
bnep-tester 1 Kernel BNEP implementation testing
@@ -49,7 +49,7 @@ gap-tester 1 Daemon D-Bus API testing
hci-tester 14 Controller hardware testing
userchan-tester 3 Kernel HCI User Channel testting
-----
- 369
+ 370


Android end-to-end testing
diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 581fde6..315c326 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -1550,6 +1550,7 @@ static const struct generic_data set_hs_on_invalid_index_test = {
static uint16_t settings_le[] = { MGMT_OP_SET_LE, 0 };

static const char set_le_on_param[] = { 0x01 };
+static const char set_le_off_param[] = { 0x00 };
static const char set_le_invalid_param[] = { 0x02 };
static const char set_le_garbage_param[] = { 0x01, 0x00 };
static const char set_le_settings_param_1[] = { 0x80, 0x02, 0x00, 0x00 };
@@ -4513,6 +4514,20 @@ static const struct generic_data add_advertising_power_off = {
.expect_alt_ev_len = sizeof(advertising_instance1_param),
};

+static const char set_le_settings_param_off[] = { 0x81, 0x00, 0x00, 0x00 };
+
+static const struct generic_data add_advertising_le_off = {
+ .send_opcode = MGMT_OP_SET_LE,
+ .send_param = set_le_off_param,
+ .send_len = sizeof(set_le_off_param),
+ .expect_status = MGMT_STATUS_SUCCESS,
+ .expect_param = set_le_settings_param_off,
+ .expect_len = sizeof(set_le_settings_param_off),
+ .expect_alt_ev = MGMT_EV_ADVERTISING_REMOVED,
+ .expect_alt_ev_param = advertising_instance1_param,
+ .expect_alt_ev_len = sizeof(advertising_instance1_param),
+};
+
static const struct generic_data add_advertising_success_18 = {
.send_opcode = MGMT_OP_ADD_ADVERTISING,
.send_param = add_advertising_param_uuid,
@@ -6687,6 +6702,12 @@ int main(int argc, char *argv[])
&add_advertising_timeout_expired,
setup_add_advertising_timeout,
test_command_generic, 3);
+ /* Test that le off will clear (remove) all instances */
+ test_bredrle("Add Advertising - Success 21 (LE -> off, Remove)",
+ &add_advertising_le_off,
+ setup_add_advertising,
+ test_command_generic);
+

test_bredrle("Remove Advertising - Invalid Params 1",
&remove_advertising_fail_1,
--
1.9.1


2015-06-13 03:42:56

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v8 12/15] tools/mgmt-tester: test advertising timeout

The change introduces an additional test that waits for an advertising
timeout to occur and checks whether the timed out advertising instance
is correctly being removed and - if it was the last instance -
advertising disabled.
---
doc/test-coverage.txt | 4 ++--
tools/mgmt-tester.c | 20 +++++++++++++++++++-
2 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/doc/test-coverage.txt b/doc/test-coverage.txt
index 89d9991..9c8b9bc 100644
--- a/doc/test-coverage.txt
+++ b/doc/test-coverage.txt
@@ -39,7 +39,7 @@ Automated end-to-end testing

Application Count Description
-------------------------------------------
-mgmt-tester 297 Kernel management interface testing
+mgmt-tester 298 Kernel management interface testing
l2cap-tester 27 Kernel L2CAP implementation testing
rfcomm-tester 9 Kernel RFCOMM implementation testing
bnep-tester 1 Kernel BNEP implementation testing
@@ -49,7 +49,7 @@ gap-tester 1 Daemon D-Bus API testing
hci-tester 14 Controller hardware testing
userchan-tester 3 Kernel HCI User Channel testting
-----
- 368
+ 369


Android end-to-end testing
diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index f612836..581fde6 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -1628,6 +1628,7 @@ static const char set_adv_on_param[] = { 0x01 };
static const char set_adv_settings_param_1[] = { 0x80, 0x06, 0x00, 0x00 };
static const char set_adv_settings_param_2[] = { 0x81, 0x06, 0x00, 0x00 };
static const char set_adv_on_set_adv_enable_param[] = { 0x01 };
+static const char set_adv_on_set_adv_disable_param[] = { 0x00 };

static const struct generic_data set_adv_on_success_test_1 = {
.setup_settings = settings_le,
@@ -4524,6 +4525,16 @@ static const struct generic_data add_advertising_success_18 = {
.expect_hci_len = sizeof(set_adv_data_uuid),
};

+static const struct generic_data add_advertising_timeout_expired = {
+ .send_opcode = TESTER_NOOP_OPCODE,
+ .expect_alt_ev = MGMT_EV_ADVERTISING_REMOVED,
+ .expect_alt_ev_param = advertising_instance1_param,
+ .expect_alt_ev_len = sizeof(advertising_instance1_param),
+ .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_ENABLE,
+ .expect_hci_param = set_adv_on_set_adv_disable_param,
+ .expect_hci_len = sizeof(set_adv_on_set_adv_disable_param),
+};
+
static const uint8_t remove_advertising_param_1[] = {
0x01,
};
@@ -5117,7 +5128,7 @@ static void setup_add_advertising_timeout(const void *test_data)
memset(cp, 0, sizeof(*cp));

cp->instance = 1;
- cp->timeout = 5;
+ cp->timeout = 1;
cp->adv_data_len = 6;
cp->data[0] = 0x05; /* AD len */
cp->data[1] = 0x08; /* AD type: shortened local name */
@@ -6669,6 +6680,13 @@ int main(int argc, char *argv[])
&add_advertising_success_18,
setup_add_advertising,
test_command_generic);
+ /* An instance should be removed and advertising disabled once
+ * the timeout for all instances has been reached.
+ */
+ test_bredrle_full("Add Advertising - Success 20 (Timeout expires)",
+ &add_advertising_timeout_expired,
+ setup_add_advertising_timeout,
+ test_command_generic, 3);

test_bredrle("Remove Advertising - Invalid Params 1",
&remove_advertising_fail_1,
--
1.9.1


2015-06-13 03:42:55

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v8 11/15] tools/mgmt-tester: allow for event-only tests

The generic test runner previously expected the test action to always be
a mgmt command. A "no-op" operation is introduced to support tests where
the test scenario is triggered by a timeout rather than a command.
---
tools/mgmt-tester.c | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 91d154c..f612836 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -437,6 +437,8 @@ struct generic_data {
uint8_t adv_data_len;
};

+# define TESTER_NOOP_OPCODE 0x0000
+
static const char dummy_data[] = { 0x00 };

static const struct generic_data invalid_command_test = {
@@ -5591,6 +5593,11 @@ static void test_command_generic(const void *test_data)
test_add_condition(data);
}

+ if (test->send_opcode == 0x0000) {
+ tester_print("Executing no-op test");
+ return;
+ }
+
tester_print("Sending command 0x%04x", test->send_opcode);

if (test->send_func)
--
1.9.1


2015-06-13 03:42:54

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v8 10/15] tools/mgmt-tester: make test timeout configurable

Currently tests have a hard coded timeout of two seconds. To prepare for
multi-advertising tests we need to be able to extend that timeout, so
that we can test whether instances are switching and expiring as
expected.

This patch therefore introduces a "full" version of the
test_bredrle() macro called test_bredrle_full() that takes an additional
timout parameter.
---
tools/mgmt-tester.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 52a8a19..91d154c 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -300,7 +300,7 @@ static void test_condition_complete(struct test_data *data)
tester_test_passed();
}

-#define test_bredrle(name, data, setup, func) \
+#define test_bredrle_full(name, data, setup, func, timeout) \
do { \
struct test_data *user; \
user = malloc(sizeof(struct test_data)); \
@@ -316,9 +316,12 @@ static void test_condition_complete(struct test_data *data)
user->unmet_conditions = 0; \
tester_add_full(name, data, \
test_pre_setup, test_setup, func, NULL, \
- test_post_teardown, 2, user, free); \
+ test_post_teardown, timeout, user, free); \
} while (0)

+#define test_bredrle(name, data, setup, func) \
+ test_bredrle_full(name, data, setup, func, 2)
+
#define test_bredr20(name, data, setup, func) \
do { \
struct test_data *user; \
--
1.9.1


2015-06-13 03:42:53

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v8 09/15] tools/mgmt-tester: test adv inst override

This test covers a use case that had not been tested before: When an
advertising instance has already been added and is then added again with
different advertising data, the new advertising data should be
advertised.
---
doc/test-coverage.txt | 4 ++--
tools/mgmt-tester.c | 19 +++++++++++++++++++
2 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/doc/test-coverage.txt b/doc/test-coverage.txt
index 26e5855..89d9991 100644
--- a/doc/test-coverage.txt
+++ b/doc/test-coverage.txt
@@ -39,7 +39,7 @@ Automated end-to-end testing

Application Count Description
-------------------------------------------
-mgmt-tester 296 Kernel management interface testing
+mgmt-tester 297 Kernel management interface testing
l2cap-tester 27 Kernel L2CAP implementation testing
rfcomm-tester 9 Kernel RFCOMM implementation testing
bnep-tester 1 Kernel BNEP implementation testing
@@ -49,7 +49,7 @@ gap-tester 1 Daemon D-Bus API testing
hci-tester 14 Controller hardware testing
userchan-tester 3 Kernel HCI User Channel testting
-----
- 365
+ 368


Android end-to-end testing
diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 5aad110..52a8a19 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -4507,6 +4507,18 @@ static const struct generic_data add_advertising_power_off = {
.expect_alt_ev_len = sizeof(advertising_instance1_param),
};

+static const struct generic_data add_advertising_success_18 = {
+ .send_opcode = MGMT_OP_ADD_ADVERTISING,
+ .send_param = add_advertising_param_uuid,
+ .send_len = sizeof(add_advertising_param_uuid),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
+ .expect_status = MGMT_STATUS_SUCCESS,
+ .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
+ .expect_hci_param = set_adv_data_uuid,
+ .expect_hci_len = sizeof(set_adv_data_uuid),
+};
+
static const uint8_t remove_advertising_param_1[] = {
0x01,
};
@@ -6640,6 +6652,13 @@ int main(int argc, char *argv[])
&add_advertising_success_17,
setup_add_advertising_connectable,
test_command_generic);
+ /* Changing an advertising instance while it is still being
+ * advertised should immediately update the advertised data.
+ */
+ test_bredrle("Add Advertising - Success 19 (Add Adv override)",
+ &add_advertising_success_18,
+ setup_add_advertising,
+ test_command_generic);

test_bredrle("Remove Advertising - Invalid Params 1",
&remove_advertising_fail_1,
--
1.9.1


2015-06-13 03:42:52

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v8 08/15] tools/mgmt-tester: increase max adv inst

The kernel now allows for up to five concurrent advertising instances.
This patch adapts the tests to the new setting.
---
tools/mgmt-tester.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 272ac4d..5aad110 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -3868,7 +3868,7 @@ static const uint8_t read_adv_features_rsp_1[] = {
0x1f, 0x00, 0x00, 0x00, /* supported flags */
0x1f, /* max_adv_data_len */
0x1f, /* max_scan_rsp_len */
- 0x01, /* max_instances */
+ 0x05, /* max_instances */
0x00, /* num_instances */
};

@@ -3883,7 +3883,7 @@ static const uint8_t read_adv_features_rsp_2[] = {
0x1f, 0x00, 0x00, 0x00, /* supported flags */
0x1f, /* max_adv_data_len */
0x1f, /* max_scan_rsp_len */
- 0x01, /* max_instances */
+ 0x05, /* max_instances */
0x01, /* num_instances */
0x01, /* instance identifiers */
};
--
1.9.1


2015-06-13 03:42:51

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v8 07/15] tools/mgmt-tester: rename add adv tests

The add advertisement tests were named a bit inconsistently and the test
intent was not always clear from the naming of the test. This has been
improved by introducing a somewhat more consistent naming scheme and
adding additional hints wrt the test intent.
---
tools/mgmt-tester.c | 40 ++++++++++++++++++++--------------------
1 file changed, 20 insertions(+), 20 deletions(-)

diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 664e188..272ac4d 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -6576,67 +6576,67 @@ int main(int argc, char *argv[])
test_le("Add Advertising - Invalid Params 10 (ScRsp too long)",
&add_advertising_fail_11,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Timeout Not Powered",
+ test_bredrle("Add Advertising - Rejected (Timeout, !Powered)",
&add_advertising_fail_12,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Timeout Power off",
- &add_advertising_timeout_power_off,
+ test_bredrle("Add Advertising - Success 1 (Power -> off, Remove)",
+ &add_advertising_power_off,
setup_add_advertising_timeout,
test_command_generic);
- test_bredrle("Add Advertising - Success 1",
+ test_bredrle("Add Advertising - Success 2 (Powered, Add Adv Inst)",
&add_advertising_success_1,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 2",
+ test_bredrle("Add Advertising - Success 3 (!Powered, Add Adv Inst)",
&add_advertising_success_2,
setup_add_advertising_not_powered,
test_command_generic);
- test_bredrle("Add Advertising - Success 3",
+ test_bredrle("Add Advertising - Success 4 (!Powered, Adv Enable)",
&add_advertising_success_3,
setup_add_advertising_not_powered,
test_command_generic);
- test_bredrle("Add Advertising - Set Advertising on override 1",
+ test_bredrle("Add Advertising - Success 5 (Set Adv on override)",
&add_advertising_success_4,
setup_add_advertising,
test_command_generic);
- test_bredrle("Add Advertising - Set Advertising off override 2",
+ test_bredrle("Add Advertising - Success 6 (Set Adv off override)",
&add_advertising_success_5,
setup_set_and_add_advertising,
test_command_generic);
- test_bredrle("Add Advertising - Success 4",
+ test_bredrle("Add Advertising - Success 7 (Scan Rsp Dta, Adv ok)",
&add_advertising_success_6,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 5",
+ test_bredrle("Add Advertising - Success 8 (Scan Rsp Dta, Scan ok) ",
&add_advertising_success_7,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 6 - Flag 0",
+ test_bredrle("Add Advertising - Success 9 (Connectable Flag)",
&add_advertising_success_8,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 7 - Flag 1",
+ test_bredrle("Add Advertising - Success 10 (General Discov Flag)",
&add_advertising_success_9,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 8 - Flag 2",
+ test_bredrle("Add Advertising - Success 11 (Limited Discov Flag)",
&add_advertising_success_10,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 8 - Flag 3",
+ test_bredrle("Add Advertising - Success 12 (Managed Flags)",
&add_advertising_success_11,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 9 - Flag 4",
+ test_bredrle("Add Advertising - Success 13 (TX Power Flag)",
&add_advertising_success_12,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 10 - ADV_SCAN_IND",
+ test_bredrle("Add Advertising - Success 14 (ADV_SCAN_IND)",
&add_advertising_success_13,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 11 - ADV_NONCONN_IND",
+ test_bredrle("Add Advertising - Success 15 (ADV_NONCONN_IND)",
&add_advertising_success_14,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 12 - ADV_IND",
+ test_bredrle("Add Advertising - Success 16 (ADV_IND)",
&add_advertising_success_15,
NULL, test_command_generic);
- test_bredrle("Add Advertising - Success 13 - connectable -> on",
+ test_bredrle("Add Advertising - Success 17 (Connectable -> on)",
&add_advertising_success_16,
setup_add_advertising,
test_command_generic);
- test_bredrle("Add Advertising - Success 14 - connectable -> off",
+ test_bredrle("Add Advertising - Success 18 (Connectable -> off)",
&add_advertising_success_17,
setup_add_advertising_connectable,
test_command_generic);
--
1.9.1


2015-06-13 03:42:50

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v8 06/15] tools/mgmt-tester: comment add adv test setup

The add advertising test setup data was just a number of arrays with
undocumented hex data. This sometimes made it difficult to understand
the test intent.

Comments have been added to the add advertising mgmt and hci parameter
data arrays to make them more readable and better document the test
intent.
---
tools/mgmt-tester.c | 452 +++++++++++++++++++++++++++++++---------------------
1 file changed, 267 insertions(+), 185 deletions(-)

diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 465091a..664e188 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -3865,7 +3865,11 @@ static const struct generic_data read_adv_features_invalid_index_test = {
};

static const uint8_t read_adv_features_rsp_1[] = {
- 0x1f, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x01, 0x00,
+ 0x1f, 0x00, 0x00, 0x00, /* supported flags */
+ 0x1f, /* max_adv_data_len */
+ 0x1f, /* max_scan_rsp_len */
+ 0x01, /* max_instances */
+ 0x00, /* num_instances */
};

static const struct generic_data read_adv_features_success_1 = {
@@ -3876,7 +3880,12 @@ static const struct generic_data read_adv_features_success_1 = {
};

static const uint8_t read_adv_features_rsp_2[] = {
- 0x1f, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x01, 0x01, 0x01
+ 0x1f, 0x00, 0x00, 0x00, /* supported flags */
+ 0x1f, /* max_adv_data_len */
+ 0x1f, /* max_scan_rsp_len */
+ 0x01, /* max_instances */
+ 0x01, /* num_instances */
+ 0x01, /* instance identifiers */
};

static const struct generic_data read_adv_features_success_2 = {
@@ -3886,114 +3895,187 @@ static const struct generic_data read_adv_features_success_2 = {
.expect_status = MGMT_STATUS_SUCCESS,
};

-static const uint8_t add_advertising_param_1[] = {
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
-};
-
-static const uint8_t add_advertising_param_2[] = {
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x0a,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
- 0x03, 0x19, 0x40, 0x03,
- 0x05, 0x03, 0x0d, 0x18, 0x0f, 0x18,
-};
-
-static const uint8_t add_advertising_param_3[] = {
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
-};
-
-static const uint8_t add_advertising_param_4[] = {
- 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
-};
-
-static const uint8_t add_advertising_param_5[] = {
- 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
-};
-
-static const uint8_t add_advertising_param_6[] = {
- 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
-};
-
-static const uint8_t add_advertising_param_7[] = {
- 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
-};
-
-static const uint8_t add_advertising_param_8[] = {
- 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x03, 0x02, 0x0d, 0x18,
- 0x04, 0xff, 0x01, 0x02, 0x03,
-};
-
-static const uint8_t advertising_instance_param[] = {
+/* simple add advertising command */
+static const uint8_t add_advertising_param_uuid[] = {
+ 0x01, /* adv instance */
+ 0x00, 0x00, 0x00, 0x00, /* flags: none */
+ 0x00, 0x00, /* duration: default */
+ 0x00, 0x00, /* timeout: none */
+ 0x09, /* adv data len */
+ 0x00, /* scan rsp len */
+ /* adv data: */
+ 0x03, /* AD len */
+ 0x02, /* AD type: some 16 bit service class UUIDs */
+ 0x0d, 0x18, /* heart rate monitor */
+ 0x04, /* AD len */
+ 0xff, /* AD type: manufacturer specific data */
+ 0x01, 0x02, 0x03, /* custom advertising data */
+};
+
+/* add advertising with scan response data */
+static const uint8_t add_advertising_param_scanrsp[] = {
+ /* instance, flags, duration, timeout, adv data len: same as before */
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
+ 0x0a, /* scan rsp len */
+ /* adv data: same as before */
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+ /* scan rsp data: */
+ 0x03, /* AD len */
+ 0x19, /* AD type: external appearance */
+ 0x40, 0x03, /* some custom appearance */
+ 0x05, /* AD len */
+ 0x03, /* AD type: all 16 bit service class UUIDs */
+ 0x0d, 0x18, /* heart rate monitor */
+ 0x0f, 0x18, /* battery service */
+};
+
+/* add advertising with timeout */
+static const uint8_t add_advertising_param_timeout[] = {
+ /* instance, flags, duration: same as before */
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x05, 0x00, /* timeout: 5 seconds */
+ /* adv data: same as before */
+ 0x09, 0x00, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+};
+
+/* add advertising with connectable flag */
+static const uint8_t add_advertising_param_connectable[] = {
+ 0x01, /* adv instance */
+ 0x01, 0x00, 0x00, 0x00, /* flags: connectable*/
+ /* duration, timeout, adv/scan data: same as before */
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+};
+
+/* add advertising with general discoverable flag */
+static const uint8_t add_advertising_param_general_discov[] = {
+ 0x01, /* adv instance */
+ 0x02, 0x00, 0x00, 0x00, /* flags: general discoverable*/
+ /* duration, timeout, adv/scan data: same as before */
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+};
+
+/* add advertising with limited discoverable flag */
+static const uint8_t add_advertising_param_limited_discov[] = {
+ 0x01, /* adv instance */
+ 0x04, 0x00, 0x00, 0x00, /* flags: limited discoverable */
+ /* duration, timeout, adv/scan data: same as before */
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+};
+
+/* add advertising with managed flags */
+static const uint8_t add_advertising_param_managed[] = {
+ 0x01, /* adv instance */
+ 0x08, 0x00, 0x00, 0x00, /* flags: managed flags */
+ /* duration, timeout, adv/scan data: same as before */
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+};
+
+/* add advertising with tx power flag */
+static const uint8_t add_advertising_param_txpwr[] = {
+ 0x01, /* adv instance */
+ 0x10, 0x00, 0x00, 0x00, /* flags: tx power */
+ /* duration, timeout, adv/scan data: same as before */
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+};
+
+static const uint8_t advertising_instance1_param[] = {
0x01,
};

-static const uint8_t set_adv_data_1[] = {
- 0x09, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+static const uint8_t set_adv_data_uuid[] = {
+ /* adv data len */
+ 0x09,
+ /* advertise heart rate monitor and manufacturer specific data */
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00,
};

-static const uint8_t set_adv_data_2[] = {
- 0x06, 0x05, 0x08, 0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x00,
+static const uint8_t set_adv_data_test[] = {
+ 0x06, /* adv data len */
+ 0x05, /* AD len */
+ 0x08, /* AD type: shortened local name */
+ 0x74, 0x65, 0x73, 0x74, /* "test" */
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
};

-static const uint8_t set_adv_data_3[] = {
- 0x03, 0x02, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+static const uint8_t set_adv_data_txpwr[] = {
+ 0x03, /* adv data len */
+ 0x02, /* AD len */
+ 0x0a, /* AD type: tx power */
+ 0x00, /* tx power */
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
-};
-
-static const uint8_t set_adv_data_4[] = {
- 0x0c, 0x02, 0x01, 0x02, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff,
- 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const uint8_t set_adv_data_general_discov[] = {
+ 0x0c, /* adv data len */
+ 0x02, /* AD len */
+ 0x01, /* AD type: flags */
+ 0x02, /* general discoverable */
+ 0x03, /* AD len */
+ 0x02, /* AD type: some 16bit service class UUIDs */
+ 0x0d, 0x18, /* heart rate monitor */
+ 0x04, /* AD len */
+ 0xff, /* AD type: manufacturer specific data */
+ 0x01, 0x02, 0x03, /* custom advertising data */
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};

-static const uint8_t set_adv_data_5[] = {
- 0x0c, 0x02, 0x01, 0x01, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff,
- 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+static const uint8_t set_adv_data_limited_discov[] = {
+ 0x0c, /* adv data len */
+ 0x02, /* AD len */
+ 0x01, /* AD type: flags */
+ 0x01, /* limited discoverable */
+ /* rest: same as before */
+ 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
-};
-
-static const uint8_t set_adv_data_6[] = {
- 0x0c, 0x02, 0x01, 0x02, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff,
- 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const uint8_t set_adv_data_uuid_txpwr[] = {
+ 0x0c, /* adv data len */
+ 0x03, /* AD len */
+ 0x02, /* AD type: some 16bit service class UUIDs */
+ 0x0d, 0x18, /* heart rate monitor */
+ 0x04, /* AD len */
+ 0xff, /* AD type: manufacturer specific data */
+ 0x01, 0x02, 0x03, /* custom advertising data */
+ 0x02, /* AD len */
+ 0x0a, /* AD type: tx power */
+ 0x00, /* tx power */
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
-};
-
-static const uint8_t set_adv_data_7[] = {
- 0x0c, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
- 0x02, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const uint8_t set_scan_rsp_uuid[] = {
+ 0x0a, /* scan rsp data len */
+ 0x03, /* AD len */
+ 0x19, /* AD type: external appearance */
+ 0x40, 0x03, /* some custom appearance */
+ 0x05, /* AD len */
+ 0x03, /* AD type: all 16 bit service class UUIDs */
+ 0x0d, 0x18, 0x0f, 0x18, /* heart rate monitor, battery service */
+ /* padding */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
-};
-
-static const uint8_t set_scan_rsp_1[] = {
- 0x0a, 0x03, 0x19, 0x40, 0x03, 0x05, 0x03, 0x0d, 0x18, 0x0f,
- 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
+ 0x00,
};

static const uint8_t add_advertising_invalid_param_1[] = {
@@ -4067,8 +4149,8 @@ static const uint8_t add_advertising_invalid_param_10[] = {
static const struct generic_data add_advertising_fail_1 = {
.setup_settings = settings_powered,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_1,
- .send_len = sizeof(add_advertising_param_1),
+ .send_param = add_advertising_param_uuid,
+ .send_len = sizeof(add_advertising_param_uuid),
.expect_status = MGMT_STATUS_REJECTED,
};

@@ -4155,25 +4237,25 @@ static const struct generic_data add_advertising_fail_11 = {
static const struct generic_data add_advertising_fail_12 = {
.setup_settings = settings_le,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_3,
- .send_len = sizeof(add_advertising_param_3),
+ .send_param = add_advertising_param_timeout,
+ .send_len = sizeof(add_advertising_param_timeout),
.expect_status = MGMT_STATUS_REJECTED,
};

static const struct generic_data add_advertising_success_1 = {
.setup_settings = settings_powered_le,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_1,
- .send_len = sizeof(add_advertising_param_1),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_uuid,
+ .send_len = sizeof(add_advertising_param_uuid),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_alt_ev = MGMT_EV_ADVERTISING_ADDED,
- .expect_alt_ev_param = advertising_instance_param,
- .expect_alt_ev_len = sizeof(advertising_instance_param),
+ .expect_alt_ev_param = advertising_instance1_param,
+ .expect_alt_ev_len = sizeof(advertising_instance1_param),
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
- .expect_hci_param = set_adv_data_1,
- .expect_hci_len = sizeof(set_adv_data_1),
+ .expect_hci_param = set_adv_data_uuid,
+ .expect_hci_len = sizeof(set_adv_data_uuid),
};

static const char set_powered_adv_instance_settings_param[] = {
@@ -4188,8 +4270,8 @@ static const struct generic_data add_advertising_success_2 = {
.expect_param = set_powered_adv_instance_settings_param,
.expect_len = sizeof(set_powered_adv_instance_settings_param),
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
- .expect_hci_param = set_adv_data_2,
- .expect_hci_len = sizeof(set_adv_data_2),
+ .expect_hci_param = set_adv_data_test,
+ .expect_hci_len = sizeof(set_adv_data_test),
};

static const struct generic_data add_advertising_success_3 = {
@@ -4212,8 +4294,8 @@ static const struct generic_data add_advertising_success_4 = {
.expect_param = set_adv_settings_param_2,
.expect_len = sizeof(set_adv_settings_param_2),
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
- .expect_hci_param = set_adv_data_3,
- .expect_hci_len = sizeof(set_adv_data_3),
+ .expect_hci_param = set_adv_data_txpwr,
+ .expect_hci_len = sizeof(set_adv_data_txpwr),
};

static const char set_adv_off_param[] = { 0x00 };
@@ -4226,49 +4308,49 @@ static const struct generic_data add_advertising_success_5 = {
.expect_param = set_powered_adv_instance_settings_param,
.expect_len = sizeof(set_powered_adv_instance_settings_param),
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
- .expect_hci_param = set_adv_data_2,
- .expect_hci_len = sizeof(set_adv_data_2),
+ .expect_hci_param = set_adv_data_test,
+ .expect_hci_len = sizeof(set_adv_data_test),
};

static const struct generic_data add_advertising_success_6 = {
.setup_settings = settings_powered_le,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_2,
- .send_len = sizeof(add_advertising_param_2),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_scanrsp,
+ .send_len = sizeof(add_advertising_param_scanrsp),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_alt_ev = MGMT_EV_ADVERTISING_ADDED,
- .expect_alt_ev_param = advertising_instance_param,
- .expect_alt_ev_len = sizeof(advertising_instance_param),
+ .expect_alt_ev_param = advertising_instance1_param,
+ .expect_alt_ev_len = sizeof(advertising_instance1_param),
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
- .expect_hci_param = set_adv_data_1,
- .expect_hci_len = sizeof(set_adv_data_1),
+ .expect_hci_param = set_adv_data_uuid,
+ .expect_hci_len = sizeof(set_adv_data_uuid),
};

static const struct generic_data add_advertising_success_7 = {
.setup_settings = settings_powered_le,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_2,
- .send_len = sizeof(add_advertising_param_2),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_scanrsp,
+ .send_len = sizeof(add_advertising_param_scanrsp),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_alt_ev = MGMT_EV_ADVERTISING_ADDED,
- .expect_alt_ev_param = advertising_instance_param,
- .expect_alt_ev_len = sizeof(advertising_instance_param),
+ .expect_alt_ev_param = advertising_instance1_param,
+ .expect_alt_ev_len = sizeof(advertising_instance1_param),
.expect_hci_command = BT_HCI_CMD_LE_SET_SCAN_RSP_DATA,
- .expect_hci_param = set_scan_rsp_1,
- .expect_hci_len = sizeof(set_scan_rsp_1),
+ .expect_hci_param = set_scan_rsp_uuid,
+ .expect_hci_len = sizeof(set_scan_rsp_uuid),
};

static const struct generic_data add_advertising_success_8 = {
.setup_settings = settings_powered_le,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_4,
- .send_len = sizeof(add_advertising_param_4),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_connectable,
+ .send_len = sizeof(add_advertising_param_connectable),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_PARAMETERS,
.expect_hci_param = set_connectable_on_adv_param,
@@ -4278,53 +4360,53 @@ static const struct generic_data add_advertising_success_8 = {
static const struct generic_data add_advertising_success_9 = {
.setup_settings = settings_powered_le,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_5,
- .send_len = sizeof(add_advertising_param_5),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_general_discov,
+ .send_len = sizeof(add_advertising_param_general_discov),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
- .expect_hci_param = set_adv_data_4,
- .expect_hci_len = sizeof(set_adv_data_4),
+ .expect_hci_param = set_adv_data_general_discov,
+ .expect_hci_len = sizeof(set_adv_data_general_discov),
};

static const struct generic_data add_advertising_success_10 = {
.setup_settings = settings_powered_le,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_6,
- .send_len = sizeof(add_advertising_param_6),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_limited_discov,
+ .send_len = sizeof(add_advertising_param_limited_discov),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
- .expect_hci_param = set_adv_data_5,
- .expect_hci_len = sizeof(set_adv_data_5),
+ .expect_hci_param = set_adv_data_limited_discov,
+ .expect_hci_len = sizeof(set_adv_data_limited_discov),
};

static const struct generic_data add_advertising_success_11 = {
.setup_settings = settings_powered_le_discoverable,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_7,
- .send_len = sizeof(add_advertising_param_7),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_managed,
+ .send_len = sizeof(add_advertising_param_managed),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
- .expect_hci_param = set_adv_data_6,
- .expect_hci_len = sizeof(set_adv_data_6),
+ .expect_hci_param = set_adv_data_general_discov,
+ .expect_hci_len = sizeof(set_adv_data_general_discov),
};

static const struct generic_data add_advertising_success_12 = {
.setup_settings = settings_powered_le_discoverable,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_8,
- .send_len = sizeof(add_advertising_param_8),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_txpwr,
+ .send_len = sizeof(add_advertising_param_txpwr),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
- .expect_hci_param = set_adv_data_7,
- .expect_hci_len = sizeof(set_adv_data_7),
+ .expect_hci_param = set_adv_data_uuid_txpwr,
+ .expect_hci_len = sizeof(set_adv_data_uuid_txpwr),
};

static uint16_t settings_powered_le_connectable[] = {
@@ -4346,10 +4428,10 @@ static uint8_t set_connectable_off_scan_adv_param[] = {
static const struct generic_data add_advertising_success_13 = {
.setup_settings = settings_powered_le,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_2,
- .send_len = sizeof(add_advertising_param_2),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_scanrsp,
+ .send_len = sizeof(add_advertising_param_scanrsp),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_PARAMETERS,
.expect_hci_param = set_connectable_off_scan_adv_param,
@@ -4359,10 +4441,10 @@ static const struct generic_data add_advertising_success_13 = {
static const struct generic_data add_advertising_success_14 = {
.setup_settings = settings_powered_le,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_1,
- .send_len = sizeof(add_advertising_param_1),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_uuid,
+ .send_len = sizeof(add_advertising_param_uuid),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_PARAMETERS,
.expect_hci_param = set_connectable_off_adv_param,
@@ -4372,10 +4454,10 @@ static const struct generic_data add_advertising_success_14 = {
static const struct generic_data add_advertising_success_15 = {
.setup_settings = settings_powered_le_connectable,
.send_opcode = MGMT_OP_ADD_ADVERTISING,
- .send_param = add_advertising_param_1,
- .send_len = sizeof(add_advertising_param_1),
- .expect_param = advertising_instance_param,
- .expect_len = sizeof(advertising_instance_param),
+ .send_param = add_advertising_param_uuid,
+ .send_len = sizeof(add_advertising_param_uuid),
+ .expect_param = advertising_instance1_param,
+ .expect_len = sizeof(advertising_instance1_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_PARAMETERS,
.expect_hci_param = set_connectable_on_adv_param,
@@ -4413,7 +4495,7 @@ static const char set_powered_off_le_settings_param[] = {
0x80, 0x02, 0x00, 0x00
};

-static const struct generic_data add_advertising_timeout_power_off = {
+static const struct generic_data add_advertising_power_off = {
.send_opcode = MGMT_OP_SET_POWERED,
.send_param = set_powered_off_param,
.send_len = sizeof(set_powered_off_param),
@@ -4421,8 +4503,8 @@ static const struct generic_data add_advertising_timeout_power_off = {
.expect_param = set_powered_off_le_settings_param,
.expect_len = sizeof(set_powered_off_le_settings_param),
.expect_alt_ev = MGMT_EV_ADVERTISING_REMOVED,
- .expect_alt_ev_param = advertising_instance_param,
- .expect_alt_ev_len = sizeof(advertising_instance_param),
+ .expect_alt_ev_param = advertising_instance1_param,
+ .expect_alt_ev_len = sizeof(advertising_instance1_param),
};

static const uint8_t remove_advertising_param_1[] = {
@@ -4448,8 +4530,8 @@ static const struct generic_data remove_advertising_success_1 = {
.expect_param = remove_advertising_param_1,
.expect_len = sizeof(remove_advertising_param_1),
.expect_alt_ev = MGMT_EV_ADVERTISING_REMOVED,
- .expect_alt_ev_param = advertising_instance_param,
- .expect_alt_ev_len = sizeof(advertising_instance_param),
+ .expect_alt_ev_param = advertising_instance1_param,
+ .expect_alt_ev_len = sizeof(advertising_instance1_param),
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_ENABLE,
.expect_hci_param = set_adv_off_param,
.expect_hci_len = sizeof(set_adv_off_param),
@@ -4463,8 +4545,8 @@ static const struct generic_data remove_advertising_success_2 = {
.expect_param = remove_advertising_param_2,
.expect_len = sizeof(remove_advertising_param_2),
.expect_alt_ev = MGMT_EV_ADVERTISING_REMOVED,
- .expect_alt_ev_param = advertising_instance_param,
- .expect_alt_ev_len = sizeof(advertising_instance_param),
+ .expect_alt_ev_param = advertising_instance1_param,
+ .expect_alt_ev_len = sizeof(advertising_instance1_param),
.expect_hci_command = BT_HCI_CMD_LE_SET_ADV_ENABLE,
.expect_hci_param = set_adv_off_param,
.expect_hci_len = sizeof(set_adv_off_param),
@@ -4914,9 +4996,9 @@ static void setup_add_advertising_not_powered(const void *test_data)

cp->instance = 1;
cp->adv_data_len = 6;
- cp->data[0] = 0x05;
- cp->data[1] = 0x08;
- cp->data[2] = 't';
+ cp->data[0] = 0x05; /* AD len */
+ cp->data[1] = 0x08; /* AD type: shortened local name */
+ cp->data[2] = 't'; /* adv data ... */
cp->data[3] = 'e';
cp->data[4] = 's';
cp->data[5] = 't';
@@ -4945,9 +5027,9 @@ static void setup_add_advertising(const void *test_data)

cp->instance = 1;
cp->adv_data_len = 6;
- cp->data[0] = 0x05;
- cp->data[1] = 0x08;
- cp->data[2] = 't';
+ cp->data[0] = 0x05; /* AD len */
+ cp->data[1] = 0x08; /* AD type: shortened local name */
+ cp->data[2] = 't'; /* adv data ... */
cp->data[3] = 'e';
cp->data[4] = 's';
cp->data[5] = 't';
@@ -4980,9 +5062,9 @@ static void setup_add_advertising_connectable(const void *test_data)

cp->instance = 1;
cp->adv_data_len = 6;
- cp->data[0] = 0x05;
- cp->data[1] = 0x08;
- cp->data[2] = 't';
+ cp->data[0] = 0x05; /* AD len */
+ cp->data[1] = 0x08; /* AD type: shortened local name */
+ cp->data[2] = 't'; /* adv data ... */
cp->data[3] = 'e';
cp->data[4] = 's';
cp->data[5] = 't';
@@ -5020,9 +5102,9 @@ static void setup_add_advertising_timeout(const void *test_data)
cp->instance = 1;
cp->timeout = 5;
cp->adv_data_len = 6;
- cp->data[0] = 0x05;
- cp->data[1] = 0x08;
- cp->data[2] = 't';
+ cp->data[0] = 0x05; /* AD len */
+ cp->data[1] = 0x08; /* AD type: shortened local name */
+ cp->data[2] = 't'; /* adv data ... */
cp->data[3] = 'e';
cp->data[4] = 's';
cp->data[5] = 't';
@@ -5055,9 +5137,9 @@ static void setup_set_and_add_advertising(const void *test_data)

cp->instance = 1;
cp->adv_data_len = 6;
- cp->data[0] = 0x05;
- cp->data[1] = 0x08;
- cp->data[2] = 't';
+ cp->data[0] = 0x05; /* AD len */
+ cp->data[1] = 0x08; /* AD type: shortened local name */
+ cp->data[2] = 't'; /* adv data ... */
cp->data[3] = 'e';
cp->data[4] = 's';
cp->data[5] = 't';
--
1.9.1


2015-06-13 03:42:49

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v8 05/15] tools/mgmt-tester: expect 0 rp when removing all adv inst

The kernel would previously return a hard coded instance value of 0x01
even when removing multiple advertising instances. The correct behavior,
though, would be to return zero when multiple instances have been
removed. This corresponds to the semantics of the mgmt API call made in
the first place.

A fix for this problem has been introduced in the kernel. Now the
corresponding test is updated to reflect that logic.
---
tools/mgmt-tester.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 083586a..465091a 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -4460,8 +4460,8 @@ static const struct generic_data remove_advertising_success_2 = {
.send_param = remove_advertising_param_2,
.send_len = sizeof(remove_advertising_param_2),
.expect_status = MGMT_STATUS_SUCCESS,
- .expect_param = remove_advertising_param_1,
- .expect_len = sizeof(remove_advertising_param_1),
+ .expect_param = remove_advertising_param_2,
+ .expect_len = sizeof(remove_advertising_param_2),
.expect_alt_ev = MGMT_EV_ADVERTISING_REMOVED,
.expect_alt_ev_param = advertising_instance_param,
.expect_alt_ev_len = sizeof(advertising_instance_param),
--
1.9.1


2015-06-13 03:42:48

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v8 04/15] tools/mgmt-tester: error message when unexp params

The tester already issues debug messages for unexpected HCI commands but
not for unexpected mgmt command return values. To facilitate test
debugging this patch adds a debug message for unexpected mgmt command
return values, too.
---
tools/mgmt-tester.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 3ecddab..083586a 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -5389,12 +5389,14 @@ static void command_generic_callback(uint8_t status, uint16_t length,
expect_param = test->expect_func(&expect_len);

if (length != expect_len) {
+ tester_warn("Invalid cmd response parameter size");
tester_test_failed();
return;
}

if (expect_param && expect_len > 0 &&
memcmp(param, expect_param, length)) {
+ tester_warn("Unexpected cmd response parameter value");
tester_test_failed();
return;
}
--
1.9.1


2015-06-13 03:42:47

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v8 03/15] tools/btmgmt: make inst duration configurable

Now that the kernel actually does respect the instance's duration
parameter it should be accessible via btmgmt. An additional parameter
for the add-adv command is therefore being introduced.
---
tools/btmgmt.c | 28 +++++++++++++++++-----------
1 file changed, 17 insertions(+), 11 deletions(-)

diff --git a/tools/btmgmt.c b/tools/btmgmt.c
index 8f8bca1..a100f53 100644
--- a/tools/btmgmt.c
+++ b/tools/btmgmt.c
@@ -3890,15 +3890,16 @@ static void add_adv_rsp(uint8_t status, uint16_t len, const void *param,
static void add_adv_usage(void)
{
print("Usage: add-adv [options] <instance_id>\nOptions:\n"
- "\t -u, --uuid <uuid> Service UUID\n"
- "\t -d, --adv-data <data> Advertising Data bytes\n"
- "\t -s, --scan-rsp <data> Scan Response Data bytes\n"
- "\t -t, --timeout <timeout> Timeout in seconds\n"
- "\t -c, --connectable \"connectable\" flag\n"
- "\t -g, --general-discov \"general-discoverable\" flag\n"
- "\t -l, --limited-discov \"limited-discoverable\" flag\n"
- "\t -m, --managed-flags \"managed-flags\" flag\n"
- "\t -p, --tx-power \"tx-power\" flag\n"
+ "\t -u, --uuid <uuid> Service UUID\n"
+ "\t -d, --adv-data <data> Advertising Data bytes\n"
+ "\t -s, --scan-rsp <data> Scan Response Data bytes\n"
+ "\t -t, --timeout <timeout> Timeout in seconds\n"
+ "\t -D, --duration <duration> Duration in seconds\n"
+ "\t -c, --connectable \"connectable\" flag\n"
+ "\t -g, --general-discov \"general-discoverable\" flag\n"
+ "\t -l, --limited-discov \"limited-discoverable\" flag\n"
+ "\t -m, --managed-flags \"managed-flags\" flag\n"
+ "\t -p, --tx-power \"tx-power\" flag\n"
"e.g.:\n"
"\tadd-adv -u 180d -u 180f -d 080954657374204C45 1");
}
@@ -3909,6 +3910,7 @@ static struct option add_adv_options[] = {
{ "adv-data", 1, 0, 'd' },
{ "scan-rsp", 1, 0, 's' },
{ "timeout", 1, 0, 't' },
+ { "duration", 1, 0, 'D' },
{ "connectable", 0, 0, 'c' },
{ "general-discov", 0, 0, 'g' },
{ "limited-discov", 0, 0, 'l' },
@@ -3970,14 +3972,14 @@ static void cmd_add_adv(struct mgmt *mgmt, uint16_t index,
uint8_t uuids[MAX_AD_UUID_BYTES];
size_t uuid_bytes = 0;
uint8_t uuid_type = 0;
- uint16_t timeout = 0;
+ uint16_t timeout = 0, duration = 0;
uint8_t instance;
uuid_t uuid;
bool success = false;
bool quit = true;
uint32_t flags = 0;

- while ((opt = getopt_long(argc, argv, "+u:d:s:t:cglmph",
+ while ((opt = getopt_long(argc, argv, "+u:d:s:t:D:cglmph",
add_adv_options, NULL)) != -1) {
switch (opt) {
case 'u':
@@ -4038,6 +4040,9 @@ static void cmd_add_adv(struct mgmt *mgmt, uint16_t index,
case 't':
timeout = strtol(optarg, NULL, 0);
break;
+ case 'D':
+ duration = strtol(optarg, NULL, 0);
+ break;
case 'c':
flags |= MGMT_ADV_FLAG_CONNECTABLE;
break;
@@ -4086,6 +4091,7 @@ static void cmd_add_adv(struct mgmt *mgmt, uint16_t index,
cp->instance = instance;
put_le32(flags, &cp->flags);
put_le16(timeout, &cp->timeout);
+ put_le16(duration, &cp->duration);
cp->adv_data_len = adv_len + uuid_bytes;
cp->scan_rsp_len = scan_rsp_len;

--
1.9.1


2015-06-13 03:42:46

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v8 02/15] doc/mgmt-api: fix typos

This patch fixes a few minor typos and grammar errors in the mgmt api
spec.
---
doc/mgmt-api.txt | 30 +++++++++++++++---------------
1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/doc/mgmt-api.txt b/doc/mgmt-api.txt
index 0ac8267..f6d9e93 100644
--- a/doc/mgmt-api.txt
+++ b/doc/mgmt-api.txt
@@ -385,7 +385,7 @@ Set Connectable Command
and for LE controllers it changes the advertising type. For
dual mode controllers it affects both settings.

- For LE capable controllers the connectable setting takes affect
+ For LE capable controllers the connectable setting takes effect
when advertising is enabled (peripheral) or when directed
advertising events are received (central).

@@ -886,7 +886,7 @@ Get Connections Command
Address2 { }
...

- This command is used to retreive a list of currently connected
+ This command is used to retrieve a list of currently connected
devices.

Possible values for the Address_Type parameter:
@@ -1038,7 +1038,7 @@ Pair Device Command

To allow tracking of which resolvable random address changed
into which identity address, the New Identity Resolving Key
- event will be send before receiving Command Complete event
+ event will be sent before receiving Command Complete event
for this command.

This command can only be used when the controller is powered.
@@ -1479,7 +1479,7 @@ Block Device Command
Address_Type (1 Octet)

This command is used to add a device to the list of devices
- which should be blocked from being connect to the local
+ which should be blocked from being connected to the local
controller.

Possible values for the Address_Type parameter:
@@ -1487,7 +1487,7 @@ Block Device Command
1 LE Public
2 LE Random

- For Low Energy devices, the blocking of a device take presedence
+ For Low Energy devices, the blocking of a device takes precedence
over auto-connection actions provided by Add Device. Blocked
devices will not be auto-connected or even reported when found
during background scanning. If the controller is connectable
@@ -1557,9 +1557,9 @@ Set Device ID Command
0x0001 Bluetooth SIG
0x0002 USB Implementer’s Forum

- The information are put into the EIR data. If the controller does
+ The information is put into the EIR data. If the controller does
not support EIR or if SSP is disabled, this command will still
- succeed. The information are stored for later use and will survive
+ succeed. The information is stored for later use and will survive
toggling SSP on and off.

This command generates a Command Complete event on success or
@@ -1978,17 +1978,17 @@ Add Device Command
2 Auto-connect remote device

With the Action 0, when the device is found, a new Device Found
- event will be send indicating this device is available. This
+ event will be sent indicating this device is available. This
action is only valid for LE Public and LE Random address types.

With the Action 1, the device is allowed to connect. For BR/EDR
address type this means an incoming connection. For LE Public
and LE Random address types, a connection will be established
to devices using directed advertising. If successful a Device
- Connected event will be send.
+ Connected event will be sent.

With the Action 2, when the device is found, it will be connected
- and if successful a Device Connected event will be send. This
+ and if successful a Device Connected event will be sent. This
action is only valid for LE Public and LE Random address types.

When a device is blocked using Block Device command, then it is
@@ -2219,8 +2219,8 @@ Set Public Address Command

For a fully configured controller, the current controller index
will become invalid and an Unconfigured Index Removed event will
- be send. Once the address has been successfully changed an Index
- Added event will be send. There is no guarantee that the controller
+ be sent. Once the address has been successfully changed an Index
+ Added event will be sent. There is no guarantee that the controller
index stays the same.

All previous configured parameters and settings are lost when
@@ -2535,7 +2535,7 @@ Read Advertising Features Command
however might decrease the actual available length in these
data fields.

- With Num_Instances and Instance array the current occupied
+ With Num_Instances and Instance array the currently occupied
Instance identifiers can be retrieved.

This command generates a Command Complete event on success or
@@ -2621,13 +2621,13 @@ Add Advertising Command

The Timeout parameter configures the life-time of an Instance. In
case the value 0 is used it indicates no expiration time. If a
- timeout value is provided, then the advertising Instace will be
+ timeout value is provided, then the advertising Instance will be
automatically removed when the timeout passes. The value for the
timeout is in seconds. Powering down a controller will invalidate
all advertising Instances and it is not possible to add a new
Instance with a timeout when the controller is powered down.

- When a Timeout is provided, then the Duration substracts from
+ When a Timeout is provided, then the Duration subtracts from
the actual Timeout value of that Instance. For example an Instance
with Timeout of 5 and Duration of 2 will be scheduled exactly 3
times, twice with 2 seconds and once with one second. Other
--
1.9.1


2015-06-13 03:42:45

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v8 01/15] doc/mgmt-api: multi-adv implementation details

A few additional decisions have been made while implementing the
multi-advertising feature where the mgmt api spec was leaving room for
interpretation. These changes are being documented in this patch.
---
doc/mgmt-api.txt | 66 +++++++++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 54 insertions(+), 12 deletions(-)

diff --git a/doc/mgmt-api.txt b/doc/mgmt-api.txt
index 4b97aad..0ac8267 100644
--- a/doc/mgmt-api.txt
+++ b/doc/mgmt-api.txt
@@ -305,6 +305,14 @@ Set Powered Command
switching the controller off will expire this timeout and
disable discoverable.

+ Settings programmed via Set Advertising and Add/Remove
+ Advertising while the controller was powered off will be activated
+ when powering the controller on.
+
+ Switching the controller off will permanently cancel and remove
+ all configured advertising instances, i.e. advertising instances
+ are not being remembered across power cycles.
+
This command generates a Command Complete event on success or
a Command Status event on failure.

@@ -585,6 +593,10 @@ Set Low Energy Command
In case the kernel subsystem does not support Low Energy or the
controller does not either, the command will fail regardless.

+ Disabling LE support will permanently disable and remove all
+ advertising instances configured with the Add Advertising
+ command.
+
This command generates a Command Complete event on success or
a Command Status event on failure.

@@ -1594,6 +1606,10 @@ Set Advertising Command

Using this command will temporarily deactive any configuration
made by the Add Advertising command. This command takes precedence.
+ Once a Set Advertising command with value 0x00 is issued any
+ previously made configurations via Add/Remove Advertising, including
+ such changes made while Set Advertising was active, will be re-
+ enabled, though.

A pre-requisite is that LE is already enabled, otherwise this
command will return a "rejected" response.
@@ -2548,9 +2564,11 @@ Add Advertising Command
can be used to switch a Bluetooth Low Energy controller into
advertising mode.

- Added advertising information with this command will be ignored
- when using the Set Advertising command to enable advertising. The
- usage of Set Advertising command take precedence over this command.
+ Added advertising information with this command will be ignored as
+ long as advertising is enabled via the Set Advertising command. The
+ usage of the Set Advertising command takes precedence over this
+ command. Instance information is stored, though, and will be
+ advertised once advertising via Set Advertising has been disabled.

The Instance identifier is a value between 1 and the number of
supported instances. The value 0 is reserved.
@@ -2593,13 +2611,13 @@ Add Advertising Command
broadcaster role.

The Duration parameter configures the length of an Instance. The
- value is in seconds and a value of 0 indicates an automatic choice
- for the Duration. If only one advertising Instance has been added,
- then the Duration value will be ignored. It only applies for the
- case where multiple Instances are configured. In that case every
- Instance will be available for the Duration time and after that
- it switches to the next one. This is a simple round-robin based
- approach.
+ value is in seconds and a value of 0 indicates a default value
+ (currently 2 seconds) will be chosen for the Duration. If only
+ one advertising Instance has been added, then the Duration value
+ will be ignored. It only applies for the case where multiple
+ Instances are configured. In that case every Instance will be
+ available for the Duration time and after that it switches to
+ the next one. This is a simple round-robin based approach.

The Timeout parameter configures the life-time of an Instance. In
case the value 0 is used it indicates no expiration time. If a
@@ -2611,8 +2629,21 @@ Add Advertising Command

When a Timeout is provided, then the Duration substracts from
the actual Timeout value of that Instance. For example an Instance
- with Timeout of 6 and Duration of 2 will be scheduled exactly 3
- times. Other Instances have no influence on the Timeout.
+ with Timeout of 5 and Duration of 2 will be scheduled exactly 3
+ times, twice with 2 seconds and once with one second. Other
+ Instances have no influence on the Timeout.
+
+ Re-adding an already existing instance (i.e. issuing the Add
+ Advertising command with an Instance identifier of an existing
+ instance) will update that instance's configuration.
+
+ An instance being added or changed while another instance is
+ being advertised will not be visible immediately but only when
+ the new/changed instance is being scheduled by the round robin
+ advertising algorithm. Changes to an instance that is currently
+ being advertised will be visible right away, i.e. the previous
+ configuration will be canceled immediately and the new
+ one activated.

A pre-requisite is that LE is already enabled, otherwise this
command will return a "rejected" response.
@@ -2645,6 +2676,17 @@ Remove Advertising Command
When the Instance parameter is zero, then all previously added
advertising Instances will be removed.

+ Removing advertising information with this command will be ignored
+ as long as advertising is enabled via the Set Advertising command.
+ The usage of the Set Advertising command takes precedence over this
+ command. Changes to Instance information are stored, though, and
+ will be advertised once advertising via Set Advertising has been
+ disabled.
+
+ Removing an instance while it is being advertised will immediately
+ cancel the instance, even when it has been advertised less then its
+ configured Timeout or Duration.
+
This command can be used when the controller is not powered and
all settings will be programmed once powered.

--
1.9.1


2015-06-13 03:42:44

by Florian Grandel

[permalink] [raw]
Subject: [BlueZ v8 00/15] doc/tests/btmgmt: multi-advertising

patch set accompanying the introduction of a multi-advertising
infrastructure in the kernel

v1 ... v4:
- fix tests to test for correct behavior when removing all adv instances
by passing in the 0x00 instance identifier

v4 -> v5:
- factored userland code changes into a separate change set for easier
review

v5 -> v6:
- documented add advertising test setup
- renamed add advertising tests to make them more readable
- added test to reproduce a bug found by Marcel (executing add-adv twice
for the same instance should override the adv data)

v6 -> v7
- correctly split mangled patches

v7 -> v8
- several additional test documentation improvements
- documenting multi-adv implementation details in the mgmt api doc
- made the debugging of cmd response messages easier
- made the duration parameter accessible via btmgmt
- provided test infrastructure for timed tests
- fix duplicate code
- fix a few typos
- added test for advertising timeout
- added test for le off
- added multi-adv tests

Florian Grandel (15):
doc/mgmt-api: multi-adv implementation details
doc/mgmt-api: fix typos
tools/btmgmt: make inst duration configurable
tools/mgmt-tester: error message when unexp params
tools/mgmt-tester: expect 0 rp when removing all adv inst
tools/mgmt-tester: comment add adv test setup
tools/mgmt-tester: rename add adv tests
tools/mgmt-tester: increase max adv inst
tools/mgmt-tester: test adv inst override
tools/mgmt-tester: make test timeout configurable
tools/mgmt-tester: allow for event-only tests
tools/mgmt-tester: test advertising timeout
tools/mgmt-tester: test le off
tools/mgmt-tester: fix duplicate code
tools/mgmt-tester: test multi-adv

doc/mgmt-api.txt | 96 +++++--
doc/test-coverage.txt | 4 +-
tools/btmgmt.c | 28 +-
tools/mgmt-tester.c | 775 ++++++++++++++++++++++++++++++++++----------------
4 files changed, 616 insertions(+), 287 deletions(-)

--
1.9.1


2015-06-13 03:41:13

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v7 20/20] Bluetooth: hci_core: increase max adv inst

Now that all preconditions are present for actual multi-advertising, the
number of allowed advertising instances can be larger than one. This
patch increases the number of allowed advertising instances to 5.

Signed-off-by: Florian Grandel <[email protected]>
---
include/net/bluetooth/hci_core.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index a6cec6d..3bd618d 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -169,7 +169,7 @@ struct adv_info {
__u8 scan_rsp_data[HCI_MAX_AD_LENGTH];
};

-#define HCI_MAX_ADV_INSTANCES 1
+#define HCI_MAX_ADV_INSTANCES 5
#define HCI_DEFAULT_ADV_DURATION 2

#define HCI_MAX_SHORT_NAME_LENGTH 10
--
1.9.1


2015-06-13 03:41:12

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v7 19/20] Bluetooth: hci_core: remove obsolete adv_instance

Now that the obsolete adv_instance is no longer being referenced
anywhere in the code it can be removed without breaking the build.

Signed-off-by: Florian Grandel <[email protected]>
---
include/net/bluetooth/hci_core.h | 6 ------
net/bluetooth/hci_core.c | 1 -
2 files changed, 7 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 4f58a0e..a6cec6d 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -379,7 +379,6 @@ struct hci_dev {
__u8 scan_rsp_data[HCI_MAX_AD_LENGTH];
__u8 scan_rsp_data_len;

- struct adv_info adv_instance;
struct list_head adv_instances;
unsigned int adv_instance_cnt;
__u8 cur_adv_instance;
@@ -584,11 +583,6 @@ static inline void hci_discovery_filter_clear(struct hci_dev *hdev)
hdev->discovery.scan_duration = 0;
}

-static inline void adv_info_init(struct hci_dev *hdev)
-{
- memset(&hdev->adv_instance, 0, sizeof(struct adv_info));
-}
-
bool hci_discovery_active(struct hci_dev *hdev);

void hci_discovery_set_state(struct hci_dev *hdev, int state);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index e50f7c3..86ed44e 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3224,7 +3224,6 @@ struct hci_dev *hci_alloc_dev(void)

hci_init_sysfs(hdev);
discovery_init(hdev);
- adv_info_init(hdev);

return hdev;
}
--
1.9.1


2015-06-13 03:41:11

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v7 18/20] Bluetooth: mgmt: multi-adv for mgmt_reenable_advertising()

During service discovery, advertising will be disabled. This patch
ensures that it is correctly being re-enabled, both for configuration
made via set advertising and add advertising, once the scanning
times out.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index e2a0766..5ab7ed5 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -8579,13 +8579,24 @@ static void adv_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
void mgmt_reenable_advertising(struct hci_dev *hdev)
{
struct hci_request req;
+ u8 instance;

if (!hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
return;

+ instance = get_current_adv_instance(hdev);
+
hci_req_init(&req, hdev);
- enable_advertising(&req);
+
+ if (instance) {
+ schedule_adv_instance(&req, instance, true);
+ } else {
+ update_adv_data(&req);
+ update_scan_rsp_data(&req);
+ enable_advertising(&req);
+ }
+
hci_req_run(&req, adv_enable_complete);
}

--
1.9.1


2015-06-13 03:41:10

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v7 17/20] Bluetooth: mgmt: multi-adv for trigger_le_scan()

This patch ensures that instance advertising is correctly canceled
before starting a le scan.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 443ad86..e2a0766 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -4198,6 +4198,7 @@ static bool trigger_le_scan(struct hci_request *req, u16 interval, u8 *status)
return false;
}

+ cancel_adv_timeout(hdev);
disable_advertising(req);
}

--
1.9.1


2015-06-13 03:41:09

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v7 16/20] Bluetooth: mgmt: program multi-adv on power on

Advertising instances programmed while powered off should be advertised
once the device is powered. This patch ensures that all combinations
of setting and/or adding advertising configuration while powered off
will be correctly activated on power on.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 20 +++++++++++++++++---
1 file changed, 17 insertions(+), 3 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index bdfc01b..443ad86 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -7533,6 +7533,7 @@ static void powered_complete(struct hci_dev *hdev, u8 status, u16 opcode)
static int powered_update_hci(struct hci_dev *hdev)
{
struct hci_request req;
+ struct adv_info *adv_instance;
u8 link_sec;

hci_req_init(&req, hdev);
@@ -7572,14 +7573,27 @@ static int powered_update_hci(struct hci_dev *hdev)
* advertising data. This also applies to the case
* where BR/EDR was toggled during the AUTO_OFF phase.
*/
- if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
+ if (hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
+ (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
+ !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))) {
update_adv_data(&req);
update_scan_rsp_data(&req);
}

- if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
- hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
+ if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
+ hdev->cur_adv_instance == 0x00 &&
+ !list_empty(&hdev->adv_instances)) {
+ adv_instance = list_first_entry(&hdev->adv_instances,
+ struct adv_info, list);
+ hdev->cur_adv_instance = adv_instance->instance;
+ }
+
+ if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
enable_advertising(&req);
+ else if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
+ hdev->cur_adv_instance)
+ schedule_adv_instance(&req, hdev->cur_adv_instance,
+ true);

restart_le_actions(&req);
}
--
1.9.1


2015-06-13 03:41:08

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v7 15/20] Bluetooth: mgmt: multi adv for remove_advertising*()

The remove_advertising() and remove_advertising_complete() functions
had instance identifiers hard coded. Notably, when passing in 0x00 as
an instance identifier to signal that all instances should be removed
then the mgmt API would return a hard coded 0x01 rather than returning
the expected value 0x00. This bug is being fixed by always referencing
the instance identifier from the management API call instead.

remove_advertising() is refactored to use the new dynamic advertising
instance list. The logic is being changed to make multi-instance
advertising actually work, notably the schedule_adv_instance() method is
being referenced to make sure that other instances will continue to
advertise even if one instance is being removed.

The code is made more readable by factoring advertising instance
management and initialization into the low-level
hci_remove_adv_instance() and hci_adv_instances_clear() functions.

The method now references the clear_adv_instance() helper method to
remove duplicate logic and code.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 45 ++++++++++++++++++++++++---------------------
1 file changed, 24 insertions(+), 21 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 686d933..bdfc01b 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -7217,6 +7217,7 @@ static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
u16 opcode)
{
struct mgmt_pending_cmd *cmd;
+ struct mgmt_cp_remove_advertising *cp;
struct mgmt_rp_remove_advertising rp;

BT_DBG("status %d", status);
@@ -7231,7 +7232,8 @@ static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
if (!cmd)
goto unlock;

- rp.instance = 1;
+ cp = cmd->param;
+ rp.instance = cp->instance;

mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
&rp, sizeof(rp));
@@ -7246,21 +7248,25 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
{
struct mgmt_cp_remove_advertising *cp = data;
struct mgmt_rp_remove_advertising rp;
+ struct adv_info *adv_instance;
int err;
struct mgmt_pending_cmd *cmd;
struct hci_request req;

BT_DBG("%s", hdev->name);

- /* The current implementation only allows modifying instance no 1. A
- * value of 0 indicates that all instances should be cleared.
- */
- if (cp->instance > 1)
- return mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
- MGMT_STATUS_INVALID_PARAMS);
-
hci_dev_lock(hdev);

+ if (cp->instance)
+ adv_instance = hci_find_adv_instance(hdev, cp->instance);
+
+ if (!(cp->instance == 0x00 || adv_instance)) {
+ err = mgmt_cmd_status(sk, hdev->id,
+ MGMT_OP_REMOVE_ADVERTISING,
+ MGMT_STATUS_INVALID_PARAMS);
+ goto unlock;
+ }
+
if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
pending_find(MGMT_OP_SET_LE, hdev)) {
@@ -7275,21 +7281,21 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}

- if (hdev->adv_instance_timeout)
- cancel_delayed_work(&hdev->adv_instance_expire);
-
- memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
+ hci_req_init(&req, hdev);

- advertising_removed(sk, hdev, 1);
+ clear_adv_instance(hdev, &req, cp->instance, true);

- hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
+ if (list_empty(&hdev->adv_instances))
+ disable_advertising(&req);

- /* If the HCI_ADVERTISING flag is set or the device isn't powered then
- * we have no HCI communication to make. Simply return.
+ /* If no HCI commands have been collected so far or the HCI_ADVERTISING
+ * flag is set or the device isn't powered then we have no HCI
+ * communication to make. Simply return.
*/
- if (!hdev_is_powered(hdev) ||
+ if (skb_queue_empty(&req.cmd_q) ||
+ !hdev_is_powered(hdev) ||
hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
- rp.instance = 1;
+ rp.instance = cp->instance;
err = mgmt_cmd_complete(sk, hdev->id,
MGMT_OP_REMOVE_ADVERTISING,
MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
@@ -7303,9 +7309,6 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}

- hci_req_init(&req, hdev);
- disable_advertising(&req);
-
err = hci_req_run(&req, remove_advertising_complete);
if (err < 0)
mgmt_pending_remove(cmd);
--
1.9.1


2015-06-13 03:41:07

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v7 14/20] Bluetooth: mgmt/hci_core: multi-adv for add_advertising*()

The add_advertising() and add_advertising_complete() functions reference
the now obsolete hdev->adv_instance struct. Both methods are being
refactored to access the dynamic advertising instance list instead.

This patch also introduces all logic necessary to actually deal with
multiple instance advertising. Notably the mgmt_adv_inst_expired() and
schedule_adv_inst() method are being referenced to schedule instances in
a round robin fashion.

This patch also introduces a "pending" flag into the adv_info struct.
This is necessary to identify and remove recently added advertising
instances when the HCI commands return with an error status code.
Otherwise new advertising instances could be leaked without properly
informing userspace about their existence.

Signed-off-by: Florian Grandel <[email protected]>
---
include/net/bluetooth/hci_core.h | 1 +
net/bluetooth/hci_core.c | 1 +
net/bluetooth/mgmt.c | 96 +++++++++++++++++++++++++---------------
3 files changed, 62 insertions(+), 36 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index b53e1b1..4f58a0e 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -157,6 +157,7 @@ struct oob_data {

struct adv_info {
struct list_head list;
+ bool pending;
__u8 instance;
__u32 flags;
__u16 timeout;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index d1110db..e50f7c3 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2721,6 +2721,7 @@ int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
return -ENOMEM;

memset(adv_instance, 0, sizeof(*adv_instance));
+ adv_instance->pending = true;
adv_instance->instance = instance;
list_add(&adv_instance->list, &hdev->adv_instances);
hdev->adv_instance_cnt++;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index cbcc8d9..686d933 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -7016,7 +7016,10 @@ static void add_advertising_complete(struct hci_dev *hdev, u8 status,
u16 opcode)
{
struct mgmt_pending_cmd *cmd;
+ struct mgmt_cp_add_advertising *cp;
struct mgmt_rp_add_advertising rp;
+ struct adv_info *adv_instance, *n;
+ u8 instance;

BT_DBG("status %d", status);

@@ -7024,16 +7027,32 @@ static void add_advertising_complete(struct hci_dev *hdev, u8 status,

cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);

- if (status) {
+ if (status)
hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
- memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
- advertising_removed(cmd ? cmd->sk : NULL, hdev, 1);
+
+ list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
+ if (!adv_instance->pending)
+ continue;
+
+ if (!status) {
+ adv_instance->pending = false;
+ continue;
+ }
+
+ instance = adv_instance->instance;
+
+ if (hdev->cur_adv_instance == instance)
+ cancel_adv_timeout(hdev);
+
+ hci_remove_adv_instance(hdev, instance);
+ advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
}

if (!cmd)
goto unlock;

- rp.instance = 0x01;
+ cp = cmd->param;
+ rp.instance = cp->instance;

if (status)
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
@@ -7081,7 +7100,8 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
u32 flags;
u32 supported_flags;
u8 status;
- u16 timeout;
+ u16 timeout, duration;
+ unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
int err;
struct mgmt_pending_cmd *cmd;
struct hci_request req;
@@ -7095,12 +7115,13 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,

flags = __le32_to_cpu(cp->flags);
timeout = __le16_to_cpu(cp->timeout);
+ duration = __le16_to_cpu(cp->duration);

- /* The current implementation only supports adding one instance and only
- * a subset of the specified flags.
+ /* The current implementation only supports a subset of the specified
+ * flags.
*/
supported_flags = get_supported_adv_flags(hdev);
- if (cp->instance != 0x01 || (flags & ~supported_flags))
+ if (flags & ~supported_flags)
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
MGMT_STATUS_INVALID_PARAMS);

@@ -7128,36 +7149,39 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}

- hdev->adv_instance.flags = flags;
- hdev->adv_instance.adv_data_len = cp->adv_data_len;
- hdev->adv_instance.scan_rsp_len = cp->scan_rsp_len;
-
- if (cp->adv_data_len)
- memcpy(hdev->adv_instance.adv_data, cp->data, cp->adv_data_len);
-
- if (cp->scan_rsp_len)
- memcpy(hdev->adv_instance.scan_rsp_data,
- cp->data + cp->adv_data_len, cp->scan_rsp_len);
-
- if (hdev->adv_instance_timeout)
- cancel_delayed_work(&hdev->adv_instance_expire);
+ err = hci_add_adv_instance(hdev, cp->instance, flags,
+ cp->adv_data_len, cp->data,
+ cp->scan_rsp_len,
+ cp->data + cp->adv_data_len,
+ timeout, duration);
+ if (err < 0) {
+ err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
+ MGMT_STATUS_FAILED);
+ goto unlock;
+ }

- hdev->adv_instance_timeout = timeout;
+ /* Only trigger an advertising added event if a new instance was
+ * actually added.
+ */
+ if (hdev->adv_instance_cnt > prev_instance_cnt)
+ advertising_added(sk, hdev, cp->instance);

- if (timeout)
- queue_delayed_work(hdev->workqueue,
- &hdev->adv_instance_expire,
- msecs_to_jiffies(timeout * 1000));
+ hci_dev_set_flag(hdev, HCI_ADVERTISING_INSTANCE);

- if (!hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING_INSTANCE))
- advertising_added(sk, hdev, 1);
+ /* If the currently advertised instance is being changed then
+ * cancel the current advertising and override it.
+ */
+ if (hdev->cur_adv_instance == cp->instance)
+ cancel_adv_timeout(hdev);

- /* If the HCI_ADVERTISING flag is set or the device isn't powered then
- * we have no HCI communication to make. Simply return.
+ /* If the HCI_ADVERTISING flag is set or the device isn't powered or
+ * another instance is already being advertised then we have no HCI
+ * communication to make. Simply return.
*/
if (!hdev_is_powered(hdev) ||
- hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
- rp.instance = 0x01;
+ hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
+ hdev->adv_instance_timeout) {
+ rp.instance = cp->instance;
err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
goto unlock;
@@ -7175,11 +7199,11 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,

hci_req_init(&req, hdev);

- update_adv_data(&req);
- update_scan_rsp_data(&req);
- enable_advertising(&req);
+ err = schedule_adv_instance(&req, cp->instance, true);
+
+ if (!err)
+ err = hci_req_run(&req, add_advertising_complete);

- err = hci_req_run(&req, add_advertising_complete);
if (err < 0)
mgmt_pending_remove(cmd);

--
1.9.1


2015-06-13 03:41:06

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v7 13/20] Bluetooth: mgmt: multi adv for clear_adv_instances()

The clear_adv_instance() function could not clean up multiple
advertising instances previously. It is being changed to provide both, a
means to clean up a single instance and cleaning up all instances at
once.

An additional instance parameter is being introduced to achieve this.
Passing in 0x00 to this parameter signifies that all instances should be
cleaned up. This semantics has been chosen similarly to the semantics of
the instance parameter in the remove_advertising() function.

When removing a single instance the method also ensures that another
instance will be scheduled if available. When the currently advertising
method is being removed, it will be canceled immediately.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 80 +++++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 64 insertions(+), 16 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index a85b80f..cbcc8d9 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1538,27 +1538,57 @@ static void cancel_adv_timeout(struct hci_dev *hdev)
}
}

-static void clear_adv_instance(struct hci_dev *hdev)
+static void clear_adv_instance(struct hci_dev *hdev, struct hci_request *req,
+ u8 instance, bool force)
{
- struct hci_request req;
+ struct adv_info *adv_instance, *next_instance = NULL;
+ int err;

- if (!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
- return;
+ /* An instance value of 0 indicates that all instances
+ * should be removed and advertising should be disabled.
+ */
+ if (!instance || hdev->cur_adv_instance == instance)
+ cancel_adv_timeout(hdev);

- if (hdev->adv_instance_timeout)
- cancel_delayed_work(&hdev->adv_instance_expire);
+ /* Get the next instance to advertise BEFORE we remove
+ * the current one. This can be the same instance again
+ * if there is only one instance.
+ */
+ if (instance && hdev->cur_adv_instance == instance)
+ next_instance = hci_get_next_instance(hdev, instance);

- memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
- advertising_removed(NULL, hdev, 1);
- hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
+ if (instance == 0x00) {
+ list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
+ advertising_removed(NULL, hdev, adv_instance->instance);
+ }
+ hci_adv_instances_clear(hdev);
+ } else {
+ adv_instance = hci_find_adv_instance(hdev, instance);

- if (!hdev_is_powered(hdev) ||
+ if (force || (adv_instance && adv_instance->timeout &&
+ !adv_instance->remaining_time)) {
+ /* Don't advertise a removed instance. */
+ if (next_instance &&
+ next_instance->instance == instance)
+ next_instance = NULL;
+
+ err = hci_remove_adv_instance(hdev, instance);
+ if (!err)
+ advertising_removed(NULL, hdev, instance);
+ }
+ }
+
+ if (list_empty(&hdev->adv_instances)) {
+ hdev->cur_adv_instance = 0x00;
+ hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
+ }
+
+ if (!req || !hdev_is_powered(hdev) ||
hci_dev_test_flag(hdev, HCI_ADVERTISING))
return;

- hci_req_init(&req, hdev);
- disable_advertising(&req);
- hci_req_run(&req, NULL);
+ if (next_instance)
+ schedule_adv_instance(req, next_instance->instance, false);
}

static int clean_up_hci_state(struct hci_dev *hdev)
@@ -1576,8 +1606,7 @@ static int clean_up_hci_state(struct hci_dev *hdev)
hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
}

- if (hdev->adv_instance_timeout)
- clear_adv_instance(hdev);
+ clear_adv_instance(hdev, NULL, 0x00, true);

if (hci_dev_test_flag(hdev, HCI_LE_ADV))
disable_advertising(&req);
@@ -2532,6 +2561,9 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
val = !!cp->val;
enabled = lmp_host_le_capable(hdev);

+ if (!val)
+ clear_adv_instance(hdev, NULL, 0x00, true);
+
if (!hdev_is_powered(hdev) || val == enabled) {
bool changed = false;

@@ -7018,10 +7050,26 @@ unlock:

void mgmt_adv_timeout_expired(struct hci_dev *hdev)
{
+ u8 instance;
+ struct hci_request req;
+
hdev->adv_instance_timeout = 0;

+ instance = get_current_adv_instance(hdev);
+ if (instance == 0x00)
+ return;
+
hci_dev_lock(hdev);
- clear_adv_instance(hdev);
+ hci_req_init(&req, hdev);
+
+ clear_adv_instance(hdev, &req, instance, false);
+
+ if (list_empty(&hdev->adv_instances))
+ disable_advertising(&req);
+
+ if (!skb_queue_empty(&req.cmd_q))
+ hci_req_run(&req, NULL);
+
hci_dev_unlock(hdev);
}

--
1.9.1


2015-06-13 03:41:05

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v7 12/20] Bluetooth: mgmt: multi adv for set_advertising*()

The set_advertising() and set_advertising_complete() methods rely on
the now obsolete hci_dev->adv_instance structure. We replace this
reference by an equivalent access to the newly introduced dynamic
advertising instance list.

This patch introduces a helper function that schedules an advertising
instance correctly calculating advertising timing based on the timeout
and duration settings of the instance. Scheduling is factored into
its own function for readability and code sharing.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 94 insertions(+), 6 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 04efc56..a85b80f 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1471,6 +1471,73 @@ static void advertising_removed(struct sock *sk, struct hci_dev *hdev,
mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
}

+static int schedule_adv_instance(struct hci_request *req, u8 instance,
+ bool force) {
+ struct hci_dev *hdev = req->hdev;
+ struct adv_info *adv_instance = NULL;
+ u16 timeout;
+
+ if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
+ !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
+ return -EPERM;
+
+ if (hdev->adv_instance_timeout)
+ return -EBUSY;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (!adv_instance)
+ return -ENOENT;
+
+ /* A zero timeout means unlimited advertising. As long as there is
+ * only one instance duration should be ignored. We still set a timeout,
+ * though, in case further instances are being added later on.
+ *
+ * If the remaining lifetime of the instance is more than the duration
+ * then the timeout corresponds to the duration, otherwise it will be
+ * reduced to the remaining instance lifetime.
+ */
+ if (adv_instance->timeout == 0 ||
+ adv_instance->duration <= adv_instance->remaining_time)
+ timeout = adv_instance->duration;
+ else
+ timeout = adv_instance->remaining_time;
+
+ /* The remaining time is being reduced unless the instance is being
+ * advertised without time limit.
+ */
+ if (adv_instance->timeout)
+ adv_instance->remaining_time =
+ adv_instance->remaining_time - timeout;
+
+ hdev->adv_instance_timeout = timeout;
+ queue_delayed_work(hdev->workqueue,
+ &hdev->adv_instance_expire,
+ msecs_to_jiffies(timeout * 1000));
+
+ /* If we're just re-scheduling the same instance again then do not
+ * execute any HCI commands. This happens when a single instance is
+ * being advertised.
+ */
+ if (!force && hdev->cur_adv_instance == instance &&
+ hci_dev_test_flag(hdev, HCI_LE_ADV))
+ return 0;
+
+ hdev->cur_adv_instance = instance;
+ update_adv_data(req);
+ update_scan_rsp_data(req);
+ enable_advertising(req);
+
+ return 0;
+}
+
+static void cancel_adv_timeout(struct hci_dev *hdev)
+{
+ if (hdev->adv_instance_timeout) {
+ hdev->adv_instance_timeout = 0;
+ cancel_delayed_work(&hdev->adv_instance_expire);
+ }
+}
+
static void clear_adv_instance(struct hci_dev *hdev)
{
struct hci_request req;
@@ -4681,6 +4748,9 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status,
{
struct cmd_lookup match = { NULL, hdev };
struct hci_request req;
+ u8 instance;
+ struct adv_info *adv_instance;
+ int err;

hci_dev_lock(hdev);

@@ -4706,18 +4776,31 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status,
sock_put(match.sk);

/* If "Set Advertising" was just disabled and instance advertising was
- * set up earlier, then enable the advertising instance.
+ * set up earlier, then re-enable multi-instance advertising.
*/
if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
- !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
+ !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) ||
+ list_empty(&hdev->adv_instances))
goto unlock;

+ instance = hdev->cur_adv_instance;
+ if (!instance) {
+ adv_instance = list_first_entry_or_null(&hdev->adv_instances,
+ struct adv_info, list);
+ if (!adv_instance)
+ goto unlock;
+
+ instance = adv_instance->instance;
+ }
+
hci_req_init(&req, hdev);

- update_adv_data(&req);
- enable_advertising(&req);
+ err = schedule_adv_instance(&req, instance, true);
+
+ if (!err)
+ err = hci_req_run(&req, enable_advertising_instance);

- if (hci_req_run(&req, enable_advertising_instance) < 0)
+ if (err)
BT_ERR("Failed to re-configure advertising");

unlock:
@@ -4802,8 +4885,13 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
else
hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);

+ cancel_adv_timeout(hdev);
+
if (val) {
- /* Switch to instance "0" for the Set Advertising setting. */
+ /* Switch to instance "0" for the Set Advertising setting.
+ * We cannot use update_[adv|scan_rsp]_data() here as the
+ * HCI_ADVERTISING flag is not yet set.
+ */
update_inst_adv_data(&req, 0x00);
update_inst_scan_rsp_data(&req, 0x00);
enable_advertising(&req);
--
1.9.1


2015-06-13 03:41:04

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v7 11/20] Bluetooth: mgmt: multi adv for create_instance_adv_data()

The create_instance_adv_data() function could not deal with
multiple advertising instances previously. This is being fixed by
retrieving advertising instances from the newly introduced dynamic
advertising instance list.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 23 ++++++++++++++++-------
1 file changed, 16 insertions(+), 7 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index fc807dc..04efc56 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1014,8 +1014,18 @@ static u8 get_cur_adv_instance_scan_rsp_len(struct hci_dev *hdev)

static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
{
+ struct adv_info *adv_instance = NULL;
u8 ad_len = 0, flags = 0;
- u32 instance_flags = get_adv_instance_flags(hdev, instance);
+ u32 instance_flags;
+
+ /* Return 0 when the current instance identifier is invalid. */
+ if (instance) {
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (!adv_instance)
+ return 0;
+ }
+
+ instance_flags = get_adv_instance_flags(hdev, instance);

/* The Add Advertising command allows userspace to set both the general
* and limited discoverable flags.
@@ -1049,12 +1059,11 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
}
}

- if (instance) {
- memcpy(ptr, hdev->adv_instance.adv_data,
- hdev->adv_instance.adv_data_len);
-
- ad_len += hdev->adv_instance.adv_data_len;
- ptr += hdev->adv_instance.adv_data_len;
+ if (adv_instance) {
+ memcpy(ptr, adv_instance->adv_data,
+ adv_instance->adv_data_len);
+ ad_len += adv_instance->adv_data_len;
+ ptr += adv_instance->adv_data_len;
}

/* Provide Tx Power only if we can provide a valid value for it */
--
1.9.1


2015-06-13 03:41:03

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v7 10/20] Bluetooth: mgmt: multi adv for create_instance_scan_rsp_data()

The create_instance_scan_rsp_data() function could not deal with
multiple advertising instances previously. This is being fixed by adding
an additional instance parameter.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 76aee8a..fc807dc 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -872,15 +872,22 @@ static u8 create_default_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
return ad_len;
}

-static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
+static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 instance,
+ u8 *ptr)
{
+ struct adv_info *adv_instance;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (!adv_instance)
+ return 0;
+
/* TODO: Set the appropriate entries based on advertising instance flags
* here once flags other than 0 are supported.
*/
- memcpy(ptr, hdev->adv_instance.scan_rsp_data,
- hdev->adv_instance.scan_rsp_len);
+ memcpy(ptr, adv_instance->scan_rsp_data,
+ adv_instance->scan_rsp_len);

- return hdev->adv_instance.scan_rsp_len;
+ return adv_instance->scan_rsp_len;
}

static void update_inst_scan_rsp_data(struct hci_request *req, u8 instance)
@@ -895,7 +902,7 @@ static void update_inst_scan_rsp_data(struct hci_request *req, u8 instance)
memset(&cp, 0, sizeof(cp));

if (instance)
- len = create_instance_scan_rsp_data(hdev, cp.data);
+ len = create_instance_scan_rsp_data(hdev, instance, cp.data);
else
len = create_default_scan_rsp_data(hdev, cp.data);

--
1.9.1


2015-06-13 03:41:02

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v7 09/20] Bluetooth: mgmt: multi adv for enable_advertising()

Previously enable_advertising() would rely on
get_adv_instance_scan_rsp_len() which checked for a hard coded instance
identifier. This is being changed to check for the current advertising
instance's scan response length instead. The function is renamed
accordingly.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 47fa16b..76aee8a 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -986,16 +986,23 @@ static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance)
return adv_instance->flags;
}

-static u8 get_adv_instance_scan_rsp_len(struct hci_dev *hdev, u8 instance)
+static u8 get_cur_adv_instance_scan_rsp_len(struct hci_dev *hdev)
{
- /* Ignore instance 0 and other unsupported instances */
- if (instance != 0x01)
+ u8 instance = get_current_adv_instance(hdev);
+ struct adv_info *adv_instance;
+
+ /* Ignore instance 0 */
+ if (instance == 0x00)
+ return 0;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (!adv_instance)
return 0;

/* TODO: Take into account the "appearance" and "local-name" flags here.
* These are currently being ignored as they are not supported.
*/
- return hdev->adv_instance.scan_rsp_len;
+ return adv_instance->scan_rsp_len;
}

static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
@@ -1266,7 +1273,7 @@ static void enable_advertising(struct hci_request *req)

if (connectable)
cp.type = LE_ADV_IND;
- else if (get_adv_instance_scan_rsp_len(hdev, instance))
+ else if (get_cur_adv_instance_scan_rsp_len(hdev))
cp.type = LE_ADV_SCAN_IND;
else
cp.type = LE_ADV_NONCONN_IND;
--
1.9.1


2015-06-13 03:41:01

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v7 08/20] Bluetooth: mgmt: improve get_adv_instance_flags() readability

Switch if and else conditions to replace a negative statement by a
positive one which makes the condition more readable.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 30 ++++++++++++++++--------------
1 file changed, 16 insertions(+), 14 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 05f14c5..47fa16b 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -962,26 +962,28 @@ static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance)
u32 flags;
struct adv_info *adv_instance;

- if (instance != 0x00) {
- adv_instance = hci_find_adv_instance(hdev, instance);
+ if (instance == 0x00) {
+ /* Instance 0 always manages the "Tx Power" and "Flags"
+ * fields
+ */
+ flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS;

- /* Return 0 when we got an invalid instance identifier. */
- if (!adv_instance)
- return 0;
+ /* For instance 0, the HCI_ADVERTISING_CONNECTABLE setting
+ * corresponds to the "connectable" instance flag.
+ */
+ if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
+ flags |= MGMT_ADV_FLAG_CONNECTABLE;

- return adv_instance->flags;
+ return flags;
}

- /* Instance 0 always manages the "Tx Power" and "Flags" fields */
- flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS;
+ adv_instance = hci_find_adv_instance(hdev, instance);

- /* For instance 0, the HCI_ADVERTISING_CONNECTABLE setting corresponds
- * to the "connectable" instance flag.
- */
- if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
- flags |= MGMT_ADV_FLAG_CONNECTABLE;
+ /* Return 0 when we got an invalid instance identifier. */
+ if (!adv_instance)
+ return 0;

- return flags;
+ return adv_instance->flags;
}

static u8 get_adv_instance_scan_rsp_len(struct hci_dev *hdev, u8 instance)
--
1.9.1


2015-06-13 03:41:00

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v7 07/20] Bluetooth: mgmt: multi adv for get_adv_instance_flags()

The get_adv_instance_flags() would not work with instance identifiers
other than 0x01. This is being fixed so that arbitrary instance
identifiers can be dealt with while still correctly dealing with the
special case of the 0x00 identifier.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 55b9153..05f14c5 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -960,12 +960,17 @@ static bool get_connectable(struct hci_dev *hdev)
static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance)
{
u32 flags;
+ struct adv_info *adv_instance;

- if (instance > 0x01)
- return 0;
+ if (instance != 0x00) {
+ adv_instance = hci_find_adv_instance(hdev, instance);

- if (instance == 0x01)
- return hdev->adv_instance.flags;
+ /* Return 0 when we got an invalid instance identifier. */
+ if (!adv_instance)
+ return 0;
+
+ return adv_instance->flags;
+ }

/* Instance 0 always manages the "Tx Power" and "Flags" fields */
flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS;
--
1.9.1


2015-06-13 03:40:59

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v7 06/20] Bluetooth: mgmt: multi adv for get_current_adv_instance()

Replaces the hard coded instance identifier in
get_current_adv_instance() with the actual current instance identifier
so that this method is prepared to work with more than one advertising
instance.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 49356c7..55b9153 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -841,7 +841,7 @@ static u8 get_current_adv_instance(struct hci_dev *hdev)
*/
if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
!hci_dev_test_flag(hdev, HCI_ADVERTISING))
- return 0x01;
+ return hdev->cur_adv_instance;

return 0x00;
}
--
1.9.1


2015-06-13 03:40:58

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v7 05/20] Bluetooth: mgmt: multi adv for read_adv_features()

The read_adv_features() method had a single instance identifier hard
coded. Refer to the advertising instance list instead to return a
dynamically generated list of instance identifiers.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 22 ++++++++++++----------
1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 7fabcb6..49356c7 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -6763,8 +6763,9 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
{
struct mgmt_rp_read_adv_features *rp;
size_t rp_len;
- int err;
+ int err, i;
bool instance;
+ struct adv_info *adv_instance;
u32 supported_flags;

BT_DBG("%s", hdev->name);
@@ -6777,12 +6778,9 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,

rp_len = sizeof(*rp);

- /* Currently only one instance is supported, so just add 1 to the
- * response length.
- */
instance = hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE);
if (instance)
- rp_len++;
+ rp_len += hdev->adv_instance_cnt;

rp = kmalloc(rp_len, GFP_ATOMIC);
if (!rp) {
@@ -6797,12 +6795,16 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
rp->max_instances = HCI_MAX_ADV_INSTANCES;

- /* Currently only one instance is supported, so simply return the
- * current instance number.
- */
if (instance) {
- rp->num_instances = 1;
- rp->instance[0] = 1;
+ i = 0;
+ list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
+ if (i >= hdev->adv_instance_cnt)
+ break;
+
+ rp->instance[i] = adv_instance->instance;
+ i++;
+ }
+ rp->num_instances = hdev->adv_instance_cnt;
} else {
rp->num_instances = 0;
}
--
1.9.1


2015-06-13 03:40:57

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v7 04/20] Bluetooth: mgmt: rename update_*_data_for_instance()

The ...for_instance function name is quite long and does not follow the
..._inst_... convention followed elsewhere in the code. This patch
renames the ...for_instance functions to their shorter ..._inst_...
version.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index c330416..7fabcb6 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -883,8 +883,7 @@ static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
return hdev->adv_instance.scan_rsp_len;
}

-static void update_scan_rsp_data_for_instance(struct hci_request *req,
- u8 instance)
+static void update_inst_scan_rsp_data(struct hci_request *req, u8 instance)
{
struct hci_dev *hdev = req->hdev;
struct hci_cp_le_set_scan_rsp_data cp;
@@ -914,8 +913,7 @@ static void update_scan_rsp_data_for_instance(struct hci_request *req,

static void update_scan_rsp_data(struct hci_request *req)
{
- update_scan_rsp_data_for_instance(req,
- get_current_adv_instance(req->hdev));
+ update_inst_scan_rsp_data(req, get_current_adv_instance(req->hdev));
}

static u8 get_adv_discov_flags(struct hci_dev *hdev)
@@ -1052,7 +1050,7 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
return ad_len;
}

-static void update_adv_data_for_instance(struct hci_request *req, u8 instance)
+static void update_inst_adv_data(struct hci_request *req, u8 instance)
{
struct hci_dev *hdev = req->hdev;
struct hci_cp_le_set_adv_data cp;
@@ -1080,7 +1078,7 @@ static void update_adv_data_for_instance(struct hci_request *req, u8 instance)

static void update_adv_data(struct hci_request *req)
{
- update_adv_data_for_instance(req, get_current_adv_instance(req->hdev));
+ update_inst_adv_data(req, get_current_adv_instance(req->hdev));
}

int mgmt_update_adv_data(struct hci_dev *hdev)
@@ -4776,8 +4774,8 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,

if (val) {
/* Switch to instance "0" for the Set Advertising setting. */
- update_adv_data_for_instance(&req, 0);
- update_scan_rsp_data_for_instance(&req, 0);
+ update_inst_adv_data(&req, 0x00);
+ update_inst_scan_rsp_data(&req, 0x00);
enable_advertising(&req);
} else {
disable_advertising(&req);
--
1.9.1


2015-06-13 03:40:56

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v7 03/20] Bluetooth: mgmt: dry update_scan_rsp_data()

update_scan_rsp_data() duplicates code from get_current_adv_instance().
This is being fixed by letting the former make use of the latter.

Signed-off-by: Florian Grandel <[email protected]>
---
net/bluetooth/mgmt.c | 50 +++++++++++++++++---------------------------------
1 file changed, 17 insertions(+), 33 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index a8319f6..c330416 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -832,6 +832,20 @@ static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
}

+static u8 get_current_adv_instance(struct hci_dev *hdev)
+{
+ /* The "Set Advertising" setting supersedes the "Add Advertising"
+ * setting. Here we set the advertising data based on which
+ * setting was set. When neither apply, default to the global settings,
+ * represented by instance "0".
+ */
+ if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
+ !hci_dev_test_flag(hdev, HCI_ADVERTISING))
+ return 0x01;
+
+ return 0x00;
+}
+
static u8 create_default_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
{
u8 ad_len = 0;
@@ -900,21 +914,8 @@ static void update_scan_rsp_data_for_instance(struct hci_request *req,

static void update_scan_rsp_data(struct hci_request *req)
{
- struct hci_dev *hdev = req->hdev;
- u8 instance;
-
- /* The "Set Advertising" setting supersedes the "Add Advertising"
- * setting. Here we set the scan response data based on which
- * setting was set. When neither apply, default to the global settings,
- * represented by instance "0".
- */
- if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
- !hci_dev_test_flag(hdev, HCI_ADVERTISING))
- instance = 0x01;
- else
- instance = 0x00;
-
- update_scan_rsp_data_for_instance(req, instance);
+ update_scan_rsp_data_for_instance(req,
+ get_current_adv_instance(req->hdev));
}

static u8 get_adv_discov_flags(struct hci_dev *hdev)
@@ -941,20 +942,6 @@ static u8 get_adv_discov_flags(struct hci_dev *hdev)
return 0;
}

-static u8 get_current_adv_instance(struct hci_dev *hdev)
-{
- /* The "Set Advertising" setting supersedes the "Add Advertising"
- * setting. Here we set the advertising data based on which
- * setting was set. When neither apply, default to the global settings,
- * represented by instance "0".
- */
- if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
- !hci_dev_test_flag(hdev, HCI_ADVERTISING))
- return 0x01;
-
- return 0x00;
-}
-
static bool get_connectable(struct hci_dev *hdev)
{
struct mgmt_pending_cmd *cmd;
@@ -1093,10 +1080,7 @@ static void update_adv_data_for_instance(struct hci_request *req, u8 instance)

static void update_adv_data(struct hci_request *req)
{
- struct hci_dev *hdev = req->hdev;
- u8 instance = get_current_adv_instance(hdev);
-
- update_adv_data_for_instance(req, instance);
+ update_adv_data_for_instance(req, get_current_adv_instance(req->hdev));
}

int mgmt_update_adv_data(struct hci_dev *hdev)
--
1.9.1


2015-06-13 03:40:55

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v7 02/20] Bluetooth: hci_core/mgmt: move adv timeout to hdev

Currently the delayed work managing advertising duration and timeout is
part of the advertising instance structure. This is not correct as only
a single instance can be advertised at any given time. To implement
round robin advertising a single delayed work structure is needed.

To fix this the delayed work structure is being moved to the hci_dev
structure. The instance specific variable is renamed to "remaining_time"
to make it clear that this is the remaining lifetime of the instance and
not the current advertising timeout.

Signed-off-by: Florian Grandel <[email protected]>
---
include/net/bluetooth/hci_core.h | 5 ++++-
net/bluetooth/hci_core.c | 29 +++++++++++++++++++++++++++++
net/bluetooth/mgmt.c | 27 +++++++++++----------------
3 files changed, 44 insertions(+), 17 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 4242dbf..b53e1b1 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -156,11 +156,11 @@ struct oob_data {
};

struct adv_info {
- struct delayed_work timeout_exp;
struct list_head list;
__u8 instance;
__u32 flags;
__u16 timeout;
+ __u16 remaining_time;
__u16 duration;
__u16 adv_data_len;
__u8 adv_data[HCI_MAX_AD_LENGTH];
@@ -382,6 +382,8 @@ struct hci_dev {
struct list_head adv_instances;
unsigned int adv_instance_cnt;
__u8 cur_adv_instance;
+ __u16 adv_instance_timeout;
+ struct delayed_work adv_instance_expire;

__u8 irk[16];
__u32 rpa_timeout;
@@ -1379,6 +1381,7 @@ void mgmt_set_powered_failed(struct hci_dev *hdev, int err);
int mgmt_powered(struct hci_dev *hdev, u8 powered);
int mgmt_update_adv_data(struct hci_dev *hdev);
void mgmt_discoverable_timeout(struct hci_dev *hdev);
+void mgmt_adv_timeout_expired(struct hci_dev *hdev);
void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
bool persistent);
void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index ebf37eb..d1110db 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1591,6 +1591,11 @@ static int hci_dev_do_close(struct hci_dev *hdev)
if (hci_dev_test_flag(hdev, HCI_MGMT))
cancel_delayed_work_sync(&hdev->rpa_expired);

+ if (hdev->adv_instance_timeout) {
+ cancel_delayed_work_sync(&hdev->adv_instance_expire);
+ hdev->adv_instance_timeout = 0;
+ }
+
/* Avoid potential lockdep warnings from the *_flush() calls by
* ensuring the workqueue is empty up front.
*/
@@ -2147,6 +2152,17 @@ static void hci_discov_off(struct work_struct *work)
mgmt_discoverable_timeout(hdev);
}

+static void hci_adv_timeout_expire(struct work_struct *work)
+{
+ struct hci_dev *hdev;
+
+ hdev = container_of(work, struct hci_dev, adv_instance_expire.work);
+
+ BT_DBG("%s", hdev->name);
+
+ mgmt_adv_timeout_expired(hdev);
+}
+
void hci_uuids_clear(struct hci_dev *hdev)
{
struct bt_uuid *uuid, *tmp;
@@ -2650,6 +2666,11 @@ int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance)

BT_DBG("%s removing %dMR", hdev->name, instance);

+ if (hdev->cur_adv_instance == instance && hdev->adv_instance_timeout) {
+ cancel_delayed_work(&hdev->adv_instance_expire);
+ hdev->adv_instance_timeout = 0;
+ }
+
list_del(&adv_instance->list);
kfree(adv_instance);

@@ -2663,6 +2684,11 @@ void hci_adv_instances_clear(struct hci_dev *hdev)
{
struct adv_info *adv_instance, *n;

+ if (hdev->adv_instance_timeout) {
+ cancel_delayed_work(&hdev->adv_instance_expire);
+ hdev->adv_instance_timeout = 0;
+ }
+
list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
list_del(&adv_instance->list);
kfree(adv_instance);
@@ -2712,6 +2738,7 @@ int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
scan_rsp_data, scan_rsp_len);

adv_instance->timeout = timeout;
+ adv_instance->remaining_time = timeout;

if (duration == 0)
adv_instance->duration = HCI_DEFAULT_ADV_DURATION;
@@ -3130,6 +3157,7 @@ struct hci_dev *hci_alloc_dev(void)
hdev->adv_tx_power = HCI_TX_POWER_INVALID;
hdev->adv_instance_cnt = 0;
hdev->cur_adv_instance = 0x00;
+ hdev->adv_instance_timeout = 0;

hdev->sniff_max_interval = 800;
hdev->sniff_min_interval = 80;
@@ -3183,6 +3211,7 @@ struct hci_dev *hci_alloc_dev(void)
INIT_DELAYED_WORK(&hdev->discov_off, hci_discov_off);
INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work);
INIT_DELAYED_WORK(&hdev->le_scan_restart, le_scan_restart_work);
+ INIT_DELAYED_WORK(&hdev->adv_instance_expire, hci_adv_timeout_expire);

skb_queue_head_init(&hdev->rx_q);
skb_queue_head_init(&hdev->cmd_q);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 92c50a1..a8319f6 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1466,8 +1466,8 @@ static void clear_adv_instance(struct hci_dev *hdev)
if (!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
return;

- if (hdev->adv_instance.timeout)
- cancel_delayed_work(&hdev->adv_instance.timeout_exp);
+ if (hdev->adv_instance_timeout)
+ cancel_delayed_work(&hdev->adv_instance_expire);

memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
advertising_removed(NULL, hdev, 1);
@@ -1497,7 +1497,7 @@ static int clean_up_hci_state(struct hci_dev *hdev)
hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
}

- if (hdev->adv_instance.timeout)
+ if (hdev->adv_instance_timeout)
clear_adv_instance(hdev);

if (hci_dev_test_flag(hdev, HCI_LE_ADV))
@@ -6914,12 +6914,9 @@ unlock:
hci_dev_unlock(hdev);
}

-static void adv_timeout_expired(struct work_struct *work)
+void mgmt_adv_timeout_expired(struct hci_dev *hdev)
{
- struct hci_dev *hdev = container_of(work, struct hci_dev,
- adv_instance.timeout_exp.work);
-
- hdev->adv_instance.timeout = 0;
+ hdev->adv_instance_timeout = 0;

hci_dev_lock(hdev);
clear_adv_instance(hdev);
@@ -6981,8 +6978,6 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}

- INIT_DELAYED_WORK(&hdev->adv_instance.timeout_exp, adv_timeout_expired);
-
hdev->adv_instance.flags = flags;
hdev->adv_instance.adv_data_len = cp->adv_data_len;
hdev->adv_instance.scan_rsp_len = cp->scan_rsp_len;
@@ -6994,14 +6989,14 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
memcpy(hdev->adv_instance.scan_rsp_data,
cp->data + cp->adv_data_len, cp->scan_rsp_len);

- if (hdev->adv_instance.timeout)
- cancel_delayed_work(&hdev->adv_instance.timeout_exp);
+ if (hdev->adv_instance_timeout)
+ cancel_delayed_work(&hdev->adv_instance_expire);

- hdev->adv_instance.timeout = timeout;
+ hdev->adv_instance_timeout = timeout;

if (timeout)
queue_delayed_work(hdev->workqueue,
- &hdev->adv_instance.timeout_exp,
+ &hdev->adv_instance_expire,
msecs_to_jiffies(timeout * 1000));

if (!hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING_INSTANCE))
@@ -7106,8 +7101,8 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}

- if (hdev->adv_instance.timeout)
- cancel_delayed_work(&hdev->adv_instance.timeout_exp);
+ if (hdev->adv_instance_timeout)
+ cancel_delayed_work(&hdev->adv_instance_expire);

memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));

--
1.9.1


2015-06-13 03:40:54

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v7 01/20] Bluetooth: hci_core/mgmt: Introduce multi-adv list

The current hci dev structure only supports a single advertising
instance. To support multi-instance advertising it is necessary to
introduce a linked list of advertising instances so that multiple
advertising instances can be dynamically added and/or removed.

In a first step, the existing adv_instance member of the hci_dev
struct is supplemented by a linked list of advertising instances.
This patch introduces the list and supporting list management
infrastructure. The list is not being used yet.

Signed-off-by: Florian Grandel <[email protected]>
---
include/net/bluetooth/hci_core.h | 17 ++++++
net/bluetooth/hci_core.c | 117 +++++++++++++++++++++++++++++++++++++++
net/bluetooth/mgmt.c | 2 +-
3 files changed, 135 insertions(+), 1 deletion(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 3fbb793..4242dbf 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -157,15 +157,20 @@ struct oob_data {

struct adv_info {
struct delayed_work timeout_exp;
+ struct list_head list;
__u8 instance;
__u32 flags;
__u16 timeout;
+ __u16 duration;
__u16 adv_data_len;
__u8 adv_data[HCI_MAX_AD_LENGTH];
__u16 scan_rsp_len;
__u8 scan_rsp_data[HCI_MAX_AD_LENGTH];
};

+#define HCI_MAX_ADV_INSTANCES 1
+#define HCI_DEFAULT_ADV_DURATION 2
+
#define HCI_MAX_SHORT_NAME_LENGTH 10

/* Default LE RPA expiry time, 15 minutes */
@@ -374,6 +379,9 @@ struct hci_dev {
__u8 scan_rsp_data_len;

struct adv_info adv_instance;
+ struct list_head adv_instances;
+ unsigned int adv_instance_cnt;
+ __u8 cur_adv_instance;

__u8 irk[16];
__u32 rpa_timeout;
@@ -1019,6 +1027,15 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 bdaddr_type);

+void hci_adv_instances_clear(struct hci_dev *hdev);
+struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance);
+struct adv_info *hci_get_next_instance(struct hci_dev *hdev, u8 instance);
+int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
+ u16 adv_data_len, u8 *adv_data,
+ u16 scan_rsp_len, u8 *scan_rsp_data,
+ u16 timeout, u16 duration);
+int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance);
+
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);

int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 573711c..ebf37eb 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2610,6 +2610,119 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
return 0;
}

+/* This function requires the caller holds hdev->lock */
+struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance)
+{
+ struct adv_info *adv_instance;
+
+ list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
+ if (adv_instance->instance == instance)
+ return adv_instance;
+ }
+
+ return NULL;
+}
+
+/* This function requires the caller holds hdev->lock */
+struct adv_info *hci_get_next_instance(struct hci_dev *hdev, u8 instance) {
+ struct adv_info *cur_instance;
+
+ cur_instance = hci_find_adv_instance(hdev, instance);
+ if (!cur_instance)
+ return NULL;
+
+ if (cur_instance == list_last_entry(&hdev->adv_instances,
+ struct adv_info, list))
+ return list_first_entry(&hdev->adv_instances,
+ struct adv_info, list);
+ else
+ return list_next_entry(cur_instance, list);
+}
+
+/* This function requires the caller holds hdev->lock */
+int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance)
+{
+ struct adv_info *adv_instance;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (!adv_instance)
+ return -ENOENT;
+
+ BT_DBG("%s removing %dMR", hdev->name, instance);
+
+ list_del(&adv_instance->list);
+ kfree(adv_instance);
+
+ hdev->adv_instance_cnt--;
+
+ return 0;
+}
+
+/* This function requires the caller holds hdev->lock */
+void hci_adv_instances_clear(struct hci_dev *hdev)
+{
+ struct adv_info *adv_instance, *n;
+
+ list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
+ list_del(&adv_instance->list);
+ kfree(adv_instance);
+ }
+
+ hdev->adv_instance_cnt = 0;
+}
+
+/* This function requires the caller holds hdev->lock */
+int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
+ u16 adv_data_len, u8 *adv_data,
+ u16 scan_rsp_len, u8 *scan_rsp_data,
+ u16 timeout, u16 duration)
+{
+ struct adv_info *adv_instance;
+
+ adv_instance = hci_find_adv_instance(hdev, instance);
+ if (adv_instance) {
+ memset(adv_instance->adv_data, 0,
+ sizeof(adv_instance->adv_data));
+ memset(adv_instance->scan_rsp_data, 0,
+ sizeof(adv_instance->scan_rsp_data));
+ } else {
+ if (hdev->adv_instance_cnt >= HCI_MAX_ADV_INSTANCES ||
+ instance < 1 || instance > HCI_MAX_ADV_INSTANCES)
+ return -EOVERFLOW;
+
+ adv_instance = kmalloc(sizeof(*adv_instance), GFP_KERNEL);
+ if (!adv_instance)
+ return -ENOMEM;
+
+ memset(adv_instance, 0, sizeof(*adv_instance));
+ adv_instance->instance = instance;
+ list_add(&adv_instance->list, &hdev->adv_instances);
+ hdev->adv_instance_cnt++;
+ }
+
+ adv_instance->flags = flags;
+ adv_instance->adv_data_len = adv_data_len;
+ adv_instance->scan_rsp_len = scan_rsp_len;
+
+ if (adv_data_len)
+ memcpy(adv_instance->adv_data, adv_data, adv_data_len);
+
+ if (scan_rsp_len)
+ memcpy(adv_instance->scan_rsp_data,
+ scan_rsp_data, scan_rsp_len);
+
+ adv_instance->timeout = timeout;
+
+ if (duration == 0)
+ adv_instance->duration = HCI_DEFAULT_ADV_DURATION;
+ else
+ adv_instance->duration = duration;
+
+ BT_DBG("%s for %dMR", hdev->name, instance);
+
+ return 0;
+}
+
struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *bdaddr_list,
bdaddr_t *bdaddr, u8 type)
{
@@ -3015,6 +3128,8 @@ struct hci_dev *hci_alloc_dev(void)
hdev->manufacturer = 0xffff; /* Default to internal use */
hdev->inq_tx_power = HCI_TX_POWER_INVALID;
hdev->adv_tx_power = HCI_TX_POWER_INVALID;
+ hdev->adv_instance_cnt = 0;
+ hdev->cur_adv_instance = 0x00;

hdev->sniff_max_interval = 800;
hdev->sniff_min_interval = 80;
@@ -3056,6 +3171,7 @@ struct hci_dev *hci_alloc_dev(void)
INIT_LIST_HEAD(&hdev->pend_le_conns);
INIT_LIST_HEAD(&hdev->pend_le_reports);
INIT_LIST_HEAD(&hdev->conn_hash.list);
+ INIT_LIST_HEAD(&hdev->adv_instances);

INIT_WORK(&hdev->rx_work, hci_rx_work);
INIT_WORK(&hdev->cmd_work, hci_cmd_work);
@@ -3249,6 +3365,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
hci_smp_ltks_clear(hdev);
hci_smp_irks_clear(hdev);
hci_remote_oob_data_clear(hdev);
+ hci_adv_instances_clear(hdev);
hci_bdaddr_list_clear(&hdev->le_white_list);
hci_conn_params_clear_all(hdev);
hci_discovery_filter_clear(hdev);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index e41bbe2..92c50a1 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -6813,7 +6813,7 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
rp->supported_flags = cpu_to_le32(supported_flags);
rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
- rp->max_instances = 1;
+ rp->max_instances = HCI_MAX_ADV_INSTANCES;

/* Currently only one instance is supported, so simply return the
* current instance number.
--
1.9.1


2015-06-13 03:40:53

by Florian Grandel

[permalink] [raw]
Subject: [PATCH v7 00/20] Bluetooth: Multi-advertising

patch set introducing the infrastructure for multi-advertising
capability to the HCI core and mgmt API.

v1 -> v2:
- add missing braces in read_adv_features()

v2 -> v3 (changes due to Johan's review):
- split change-set into several patches
- replace err == 0 by !err
- fix coding style problems

v3 -> v4 (changes due to Arman's review):
- bug fix: when calling remove_advertising with an instance value of
zero (i.e. remove all instances), the command response also returns
an instance value of zero now as it doesn't make sense to return a
single instance id when removing several instances
- splitting the change set into a much larger number of patches to
facilitate review
- use HCI_MAX_ADV_INSTANCES in the same patch that introduces it
- use adv_info->hdev in the same patch that introduces it
- make the logic of hci_find_adv_instance() more readable
- make sure that hci_find_adv_instance() is called while hci_dev is
locked
- replace hci_num_adv_instances() by an instance counter in hci_dev
- add inline comment in get_adv_instance_flags() explaining its return
value in the error case
- generate zero-length adv data if the current instance identifier is
invalid
- revert erroneous changes to the logic in clear_adv_instance()
- use hci_adv_instances_clear() in clear_adv_instance() when removing
all advertising instances also removing a redundant error check
- inserting TODO messages to make sure that advertising will not be
switched off prematurely once we allow more than one advertising
instance
- inserting TODO messages to make sure that multiple advertising
instances will be advertised in a round-robin fashion once we allow
for more than one advertising instance
- identify pending advertising instances (just added but not yet
confirmed in add_advertising_complete) by a boolean flag in the
adv_info struct so that we can identify and remove them even when the
pending add_advertising command cannot be retrieved for some reason -
makes sure that we do not leak advertising instances in this case
- only send HCI commands to update advertising data when a new instance
has actually been added

v4 -> v5 (changes due to Marcel's review):
- split into separate change sets for kernel and userspace
- do not trust the adv instance list length when compiling the adv
features struct
- introduce adv_info->pending in the same patch it's used for the first
time

v5 -> v6 (changes due to Marcel's review):
- fix the add adv override bug
- fix "Using plain integer as NULL pointer" warning in
set_advertising_complete()
- reword the "remove adv instance" commit comment to make it clear that
an existing bug is being fixed

v6 -> v7:
- so far the patch set only contained a functionally neutral refactoring
to provide the basic infrastructure for multi-advertising. It has been
decided, though, that the patch set should provide the whole package
at once, including actual multi-advertising functionality. This has
been implemented and tested in the latest version of the patch set.


Florian Grandel (20):
Bluetooth: hci_core/mgmt: Introduce multi-adv list
Bluetooth: hci_core/mgmt: move adv timeout to hdev
Bluetooth: mgmt: dry update_scan_rsp_data()
Bluetooth: mgmt: rename update_*_data_for_instance()
Bluetooth: mgmt: multi adv for read_adv_features()
Bluetooth: mgmt: multi adv for get_current_adv_instance()
Bluetooth: mgmt: multi adv for get_adv_instance_flags()
Bluetooth: mgmt: improve get_adv_instance_flags() readability
Bluetooth: mgmt: multi adv for enable_advertising()
Bluetooth: mgmt: multi adv for create_instance_scan_rsp_data()
Bluetooth: mgmt: multi adv for create_instance_adv_data()
Bluetooth: mgmt: multi adv for set_advertising*()
Bluetooth: mgmt: multi adv for clear_adv_instances()
Bluetooth: mgmt/hci_core: multi-adv for add_advertising*()
Bluetooth: mgmt: multi adv for remove_advertising*()
Bluetooth: mgmt: program multi-adv on power on
Bluetooth: mgmt: multi-adv for trigger_le_scan()
Bluetooth: mgmt: multi-adv for mgmt_reenable_advertising()
Bluetooth: hci_core: remove obsolete adv_instance
Bluetooth: hci_core: increase max adv inst

include/net/bluetooth/hci_core.h | 29 ++-
net/bluetooth/hci_core.c | 148 ++++++++++-
net/bluetooth/mgmt.c | 532 +++++++++++++++++++++++++++------------
3 files changed, 534 insertions(+), 175 deletions(-)

--
1.9.1


2015-06-01 12:19:37

by Florian Grandel

[permalink] [raw]
Subject: Re: [PATCH v6 00/16] Bluetooth: Multi-advertising infrastructure

Hi Johan,

On 05/31/2015 03:20 AM, Johan Hedberg wrote:
> Hi Florian,
>
> On Wed, May 27, 2015, Florian Grandel wrote:
>>> Are multiple instances suppose to work with this patch set?
>>
>> No. There are a few remaining TODOs (documented in the code) for actual
>> multi-advertising. I mention these in the commit messages where applicable.
>>
>> The idea was to do the more complex changes in a functionally neutral
>> refactoring first as a safe starting point for functional changes (see my
>> conv. with Arman on the list).
>>
>> Of course I'm prepared to resolve those remaining TODOs in a second patch
>> set. I just think it is a good idea if I go full cycle once to avoid those
>> beginner's errors during the next iteration.
>>
>> If you think that there are no more fundamental flaws in that first patch
>> set then I can start with the second one now. What do you think?
>
> I was also under the impression that this set implemented the full
> multi-advertising feature (rather than being refactoring in preparation
> for it). I think a kernel release should contain the whole thing or
> nothing at all, which makes me now a bit doubtful of whether this can
> make it to 4.2.

From my pov: no problem. I prefer us to test this patch really well and
for everybody to really feel comfortable about its inclusion rather then
rushing this into the next release.

> How soon can you send the follow-up set? It will essentially validate
> the work of your first set, so it'd be good to see and test it as soon
> as possible.

As I'm doing this in my spare time I cannot really give you a specific
date but I think I'll be able to provide a patch set with the remaining
functional changes for review within two weeks.

Regards,

Florian