2015-03-24 18:35:08

by Arman Uguray

[permalink] [raw]
Subject: [PATCH 1/4] tools/btmgmt: Observe Advertising Added/Removed

btmgmt now observes Advertising Added/Removed events.
---
tools/btmgmt.c | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)

diff --git a/tools/btmgmt.c b/tools/btmgmt.c
index 0f7fdc7..ea4eba7 100644
--- a/tools/btmgmt.c
+++ b/tools/btmgmt.c
@@ -1068,6 +1068,32 @@ static void local_oob_data_updated(uint16_t index, uint16_t len,
ev->type, eir_len);
}

+static void advertising_added(uint16_t index, uint16_t len,
+ const void *param, void *user_data)
+{
+ const struct mgmt_ev_advertising_added *ev = param;
+
+ if (len < sizeof(*ev)) {
+ error("Too small (%u bytes) advertising_added event", len);
+ return;
+ }
+
+ print("hci%u advertising_added: instance %u", index, ev->instance);
+}
+
+static void advertising_removed(uint16_t index, uint16_t len,
+ const void *param, void *user_data)
+{
+ const struct mgmt_ev_advertising_removed *ev = param;
+
+ if (len < sizeof(*ev)) {
+ error("Too small (%u bytes) advertising_removed event", len);
+ return;
+ }
+
+ print("hci%u advertising_removed: instance %u", index, ev->instance);
+}
+
static void version_rsp(uint8_t status, uint16_t len, const void *param,
void *user_data)
{
@@ -3757,6 +3783,10 @@ static void register_mgmt_callbacks(struct mgmt *mgmt, uint16_t index)
ext_index_removed, NULL, NULL);
mgmt_register(mgmt, MGMT_EV_LOCAL_OOB_DATA_UPDATED, index,
local_oob_data_updated, NULL, NULL);
+ mgmt_register(mgmt, MGMT_EV_ADVERTISING_ADDED, index,
+ advertising_added, NULL, NULL);
+ mgmt_register(mgmt, MGMT_EV_ADVERTISING_REMOVED, index,
+ advertising_removed, NULL, NULL);
}

static void cmd_select(struct mgmt *mgmt, uint16_t index,
--
2.2.0.rc0.207.ga3a616c



2015-03-24 22:47:45

by Johan Hedberg

[permalink] [raw]
Subject: Re: [PATCH 1/4] tools/btmgmt: Observe Advertising Added/Removed

Hi Arman,

On Tue, Mar 24, 2015, Arman Uguray wrote:
> btmgmt now observes Advertising Added/Removed events.
> ---
> tools/btmgmt.c | 30 ++++++++++++++++++++++++++++++
> 1 file changed, 30 insertions(+)

All four patches in the set have been applied. Thanks.

Johan

2015-03-24 18:35:11

by Arman Uguray

[permalink] [raw]
Subject: [PATCH 4/4] tools/btmgmt: Add "--uuid" option to add-adv

This patch adds the --uuid (-u) option to the add-adv command. This
allows callers to specify individual 128-bit or 16-bit UUIDs to be
included in the "Complete List of Service CLass UUIDs" field of
advertising data.
---
tools/btmgmt.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 68 insertions(+), 5 deletions(-)

diff --git a/tools/btmgmt.c b/tools/btmgmt.c
index 06f32f3..a769fc3 100644
--- a/tools/btmgmt.c
+++ b/tools/btmgmt.c
@@ -3693,6 +3693,7 @@ static void add_adv_usage(void)

static struct option add_adv_options[] = {
{ "help", 0, 0, 'h' },
+ { "uuid", 1, 0, 'u' },
{ "adv-data", 1, 0, 'd' },
{ "scan-rsp", 1, 0, 's' },
{ "timeout", 1, 0, 't' },
@@ -3739,6 +3740,8 @@ static bool parse_bytes(char *optarg, uint8_t **bytes, size_t *len)
return true;
}

+#define MAX_AD_UUID_BYTES 32
+
static void cmd_add_adv(struct mgmt *mgmt, uint16_t index,
int argc, char **argv)
{
@@ -3747,19 +3750,70 @@ static void cmd_add_adv(struct mgmt *mgmt, uint16_t index,
uint8_t *adv_data = NULL, *scan_rsp = NULL;
size_t adv_len = 0, scan_rsp_len = 0;
size_t cp_len;
+ uint8_t uuids[MAX_AD_UUID_BYTES];
+ size_t uuid_bytes = 0;
+ uint8_t uuid_type = 0;
uint16_t timeout = 0;
uint8_t instance;
+ uuid_t uuid;
bool success = false;
bool quit = true;

- while ((opt = getopt_long(argc, argv, "+d:s:t:h",
+ while ((opt = getopt_long(argc, argv, "+u:d:s:t:h",
add_adv_options, NULL)) != -1) {
switch (opt) {
+ case 'u':
+ if (bt_string2uuid(&uuid, optarg) < 0) {
+ print("Invalid UUID: %s", optarg);
+ goto done;
+ }
+
+ if (uuid_type && uuid_type != uuid.type) {
+ print("UUID types must be consistent");
+ goto done;
+ }
+
+ if (uuid.type == SDP_UUID16) {
+ if (uuid_bytes + 2 >= MAX_AD_UUID_BYTES) {
+ print("Too many UUIDs");
+ goto done;
+ }
+
+ put_le16(uuid.value.uuid16, uuids + uuid_bytes);
+ uuid_bytes += 2;
+ } else if (uuid.type == SDP_UUID128) {
+ if (uuid_bytes + 16 >= MAX_AD_UUID_BYTES) {
+ print("Too many UUIDs");
+ goto done;
+ }
+
+ bswap_128(uuid.value.uuid128.data,
+ uuids + uuid_bytes);
+ uuid_bytes += 16;
+ } else {
+ printf("Unsupported UUID type");
+ goto done;
+ }
+
+ if (!uuid_type)
+ uuid_type = uuid.type;
+
+ break;
case 'd':
+ if (adv_len) {
+ print("Only one adv-data option allowed");
+ goto done;
+ }
+
if (!parse_bytes(optarg, &adv_data, &adv_len))
goto done;
break;
case 's':
+ if (scan_rsp_len) {
+ print("Only one scan-rsp option allowed");
+ goto done;
+ }
+
if (!parse_bytes(optarg, &scan_rsp, &scan_rsp_len))
goto done;
break;
@@ -3783,23 +3837,32 @@ static void cmd_add_adv(struct mgmt *mgmt, uint16_t index,
goto done;
}

+ if (uuid_bytes)
+ uuid_bytes += 2;
+
instance = strtol(argv[0], NULL, 0);

if (index == MGMT_INDEX_NONE)
index = 0;

- cp_len = sizeof(*cp) + (adv_len + scan_rsp_len) * sizeof(uint8_t);
+ cp_len = sizeof(*cp) + uuid_bytes + adv_len + scan_rsp_len;
cp = malloc0(cp_len);
if (!cp)
goto done;

cp->instance = instance;
put_le16(timeout, &cp->timeout);
- cp->adv_data_len = adv_len;
+ cp->adv_data_len = adv_len + uuid_bytes;
cp->scan_rsp_len = scan_rsp_len;

- memcpy(cp->data, adv_data, adv_len * sizeof(uint8_t));
- memcpy(cp->data + adv_len, scan_rsp, scan_rsp_len * sizeof(uint8_t));
+ if (uuid_bytes) {
+ cp->data[0] = uuid_bytes - 1;
+ cp->data[1] = uuid_type == SDP_UUID16 ? 0x03 : 0x07;
+ memcpy(cp->data + 2, uuids, uuid_bytes - 2);
+ }
+
+ memcpy(cp->data + uuid_bytes, adv_data, adv_len);
+ memcpy(cp->data + uuid_bytes + adv_len, scan_rsp, scan_rsp_len);

if (!mgmt_send(mgmt, MGMT_OP_ADD_ADVERTISING, index, cp_len, cp,
add_adv_rsp, NULL, NULL)) {
--
2.2.0.rc0.207.ga3a616c


2015-03-24 18:35:09

by Arman Uguray

[permalink] [raw]
Subject: [PATCH 2/4] tools/btmgmt: Add the 'add-adv' command

This patch introduces the 'add-adv' command which allows users to
send the MGMT "Add Advertising" command to the kernel.
---
tools/btmgmt.c | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 155 insertions(+)

diff --git a/tools/btmgmt.c b/tools/btmgmt.c
index ea4eba7..06f9a82 100644
--- a/tools/btmgmt.c
+++ b/tools/btmgmt.c
@@ -3664,6 +3664,160 @@ static void cmd_advinfo(struct mgmt *mgmt, uint16_t index,
}
}

+static void add_adv_rsp(uint8_t status, uint16_t len, const void *param,
+ void *user_data)
+{
+ const struct mgmt_rp_add_advertising *rp = param;
+
+ if (status != 0) {
+ error("Add Advertising failed with status 0x%02x (%s)",
+ status, mgmt_errstr(status));
+ return noninteractive_quit(EXIT_FAILURE);
+ }
+
+ if (len != sizeof(*rp)) {
+ error("Invalid Add Advertising response length (%u)", len);
+ return noninteractive_quit(EXIT_FAILURE);
+ }
+
+ print("Instance added: %u", rp->instance);
+
+ return noninteractive_quit(EXIT_SUCCESS);
+}
+
+static void add_adv_usage(void)
+{
+ print("Usage: add-adv [-d adv_data] [-s scan_rsp] "
+ "[-t timeout] <instance_id>");
+}
+
+static struct option add_adv_options[] = {
+ { "help", 0, 0, 'h' },
+ { "adv-data", 1, 0, 'd' },
+ { "scan-rsp", 1, 0, 's' },
+ { "timeout", 1, 0, 't' },
+ { 0, 0, 0, 0}
+};
+
+static bool parse_bytes(char *optarg, uint8_t **bytes, size_t *len)
+{
+ unsigned i;
+
+ if (!optarg) {
+ add_adv_usage();
+ return false;
+ }
+
+ *len = strlen(optarg);
+
+ if (*len % 2) {
+ error("Malformed data");
+ return false;
+ }
+
+ *len /= 2;
+ if (*len > UINT8_MAX) {
+ error("Data too long");
+ return false;
+ }
+
+ *bytes = malloc(*len);
+ if (!*bytes) {
+ error("Failed to allocate memory");
+ return false;
+ }
+
+ for (i = 0; i < *len; i++) {
+ if (sscanf(optarg + (i * 2), "%2hhx", *bytes + i) != 1) {
+ error("Invalid data");
+ free(bytes);
+ *bytes = NULL;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static void cmd_add_adv(struct mgmt *mgmt, uint16_t index,
+ int argc, char **argv)
+{
+ struct mgmt_cp_add_advertising *cp = NULL;
+ int opt;
+ uint8_t *adv_data = NULL, *scan_rsp = NULL;
+ size_t adv_len = 0, scan_rsp_len = 0;
+ size_t cp_len;
+ uint16_t timeout = 0;
+ uint8_t instance;
+ bool success = false;
+ bool quit = true;
+
+ while ((opt = getopt_long(argc, argv, "+d:s:t:h",
+ add_adv_options, NULL)) != -1) {
+ switch (opt) {
+ case 'd':
+ if (!parse_bytes(optarg, &adv_data, &adv_len))
+ goto done;
+ break;
+ case 's':
+ if (!parse_bytes(optarg, &scan_rsp, &scan_rsp_len))
+ goto done;
+ break;
+ case 't':
+ timeout = strtol(optarg, NULL, 0);
+ break;
+ case 'h':
+ success = true;
+ default:
+ add_adv_usage();
+ goto done;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+
+ if (argc != 1) {
+ add_adv_usage();
+ goto done;
+ }
+
+ instance = strtol(argv[0], NULL, 0);
+
+ if (index == MGMT_INDEX_NONE)
+ index = 0;
+
+ cp_len = sizeof(*cp) + (adv_len + scan_rsp_len) * sizeof(uint8_t);
+ cp = malloc0(cp_len);
+ if (!cp)
+ goto done;
+
+ cp->instance = instance;
+ put_le16(timeout, &cp->timeout);
+ cp->adv_data_len = adv_len;
+ cp->scan_rsp_len = scan_rsp_len;
+
+ memcpy(cp->data, adv_data, adv_len * sizeof(uint8_t));
+ memcpy(cp->data + adv_len, scan_rsp, scan_rsp_len * sizeof(uint8_t));
+
+ if (!mgmt_send(mgmt, MGMT_OP_ADD_ADVERTISING, index, cp_len, cp,
+ add_adv_rsp, NULL, NULL)) {
+ error("Unable to send \"Add Advertising\" command");
+ goto done;
+ }
+
+ quit = false;
+
+done:
+ free(adv_data);
+ free(scan_rsp);
+ free(cp);
+
+ if (quit)
+ noninteractive_quit(success ? EXIT_SUCCESS : EXIT_FAILURE);
+}
+
struct cmd_info {
char *cmd;
void (*func)(struct mgmt *mgmt, uint16_t index, int argc, char **argv);
@@ -3727,6 +3881,7 @@ static struct cmd_info all_cmd[] = {
{ "bredr-oob", cmd_bredr_oob, "Local OOB data (BR/EDR)" },
{ "le-oob", cmd_le_oob, "Local OOB data (LE)" },
{ "advinfo", cmd_advinfo, "Show advertising features" },
+ { "add-adv", cmd_add_adv, "Add Advertising Data" },
};

static void cmd_quit(struct mgmt *mgmt, uint16_t index,
--
2.2.0.rc0.207.ga3a616c


2015-03-24 18:35:10

by Arman Uguray

[permalink] [raw]
Subject: [PATCH 3/4] tools/btmgmt: Add the 'rm-adv' command

This patch introduces the add 'rm-adv' command which allows user to
send the MGMT "Remove Advertising" command to the kernel.
---
tools/btmgmt.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 53 insertions(+)

diff --git a/tools/btmgmt.c b/tools/btmgmt.c
index 06f9a82..06f32f3 100644
--- a/tools/btmgmt.c
+++ b/tools/btmgmt.c
@@ -3818,6 +3818,58 @@ done:
noninteractive_quit(success ? EXIT_SUCCESS : EXIT_FAILURE);
}

+static void rm_adv_rsp(uint8_t status, uint16_t len, const void *param,
+ void *user_data)
+{
+ const struct mgmt_rp_remove_advertising *rp = param;
+
+ if (status != 0) {
+ error("Remove Advertising failed with status 0x%02x (%s)",
+ status, mgmt_errstr(status));
+ return noninteractive_quit(EXIT_FAILURE);
+ }
+
+ if (len != sizeof(*rp)) {
+ error("Invalid Remove Advertising response length (%u)", len);
+ return noninteractive_quit(EXIT_FAILURE);
+ }
+
+ print("Instance removed: %u", rp->instance);
+
+ return noninteractive_quit(EXIT_SUCCESS);
+}
+
+static void rm_adv_usage(void)
+{
+ print("Usage: rm-adv <instance_id>");
+}
+
+static void cmd_rm_adv(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
+{
+ struct mgmt_cp_remove_advertising cp;
+ uint8_t instance;
+
+ if (argc != 2) {
+ rm_adv_usage();
+ return noninteractive_quit(EXIT_FAILURE);
+ }
+
+ instance = strtol(argv[1], NULL, 0);
+
+ if (index == MGMT_INDEX_NONE)
+ index = 0;
+
+ memset(&cp, 0, sizeof(cp));
+
+ cp.instance = instance;
+
+ if (!mgmt_send(mgmt, MGMT_OP_REMOVE_ADVERTISING, index, sizeof(cp), &cp,
+ rm_adv_rsp, NULL, NULL)) {
+ error("Unable to send \"Remove Advertising\" command");
+ return noninteractive_quit(EXIT_FAILURE);
+ }
+}
+
struct cmd_info {
char *cmd;
void (*func)(struct mgmt *mgmt, uint16_t index, int argc, char **argv);
@@ -3882,6 +3934,7 @@ static struct cmd_info all_cmd[] = {
{ "le-oob", cmd_le_oob, "Local OOB data (LE)" },
{ "advinfo", cmd_advinfo, "Show advertising features" },
{ "add-adv", cmd_add_adv, "Add Advertising Data" },
+ { "rm-adv", cmd_rm_adv, "Remove Advertising Data" },
};

static void cmd_quit(struct mgmt *mgmt, uint16_t index,
--
2.2.0.rc0.207.ga3a616c