[PATCH BlueZ 5/7] client: Add set-advertise-service command

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Luiz Augusto von Dentz <luiz.von.dentz@xxxxxxxxx>

This adds set-advertise-service which can be used set UUID data to be
advertised:

set-advertise-service [uuid][data=[xx xx ...]
[bluetooth]# set-advertise-service 180D 0xff 0xff
[bluetooth]# advertise on

@ Advertising Added: 1
< HCI Command: LE Set Advertising Data (0x08|0x0008) plen 32
        Length: 9
        Flags: 0x02
          LE General Discoverable Mode
        Service Data (UUID 0x180d): ffff
---
 client/advertising.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++
 client/main.c        |   8 ++++
 2 files changed, 136 insertions(+)

diff --git a/client/advertising.c b/client/advertising.c
index e74221f..3e4e10c 100644
--- a/client/advertising.c
+++ b/client/advertising.c
@@ -42,6 +42,9 @@ static gboolean registered = FALSE;
 static char *ad_type = NULL;
 static char **ad_uuids = NULL;
 static size_t ad_uuids_len = 0;
+static char *ad_service_uuid = NULL;
+static uint8_t ad_service_data[25];
+static uint8_t ad_service_data_len = 0;
 
 static void ad_release(DBusConnection *conn)
 {
@@ -134,9 +137,85 @@ static gboolean get_uuids(const GDBusPropertyTable *property,
 	return TRUE;
 }
 
+static void append_array_variant(DBusMessageIter *iter, int type, void *val,
+							int n_elements)
+{
+	DBusMessageIter variant, array;
+	char type_sig[2] = { type, '\0' };
+	char array_sig[3] = { DBUS_TYPE_ARRAY, type, '\0' };
+
+	dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+						array_sig, &variant);
+
+	dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
+						type_sig, &array);
+
+	if (dbus_type_is_fixed(type) == TRUE) {
+		dbus_message_iter_append_fixed_array(&array, type, val,
+							n_elements);
+	} else if (type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH) {
+		const char ***str_array = val;
+		int i;
+
+		for (i = 0; i < n_elements; i++)
+			dbus_message_iter_append_basic(&array, type,
+							&((*str_array)[i]));
+	}
+
+	dbus_message_iter_close_container(&variant, &array);
+
+	dbus_message_iter_close_container(iter, &variant);
+}
+
+static void dict_append_basic_array(DBusMessageIter *dict, int key_type,
+					const void *key, int type, void *val,
+					int n_elements)
+{
+	DBusMessageIter entry;
+
+	dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+						NULL, &entry);
+
+	dbus_message_iter_append_basic(&entry, key_type, key);
+
+	append_array_variant(&entry, type, val, n_elements);
+
+	dbus_message_iter_close_container(dict, &entry);
+}
+
+static void dict_append_array(DBusMessageIter *dict, const char *key, int type,
+				void *val, int n_elements)
+{
+	dict_append_basic_array(dict, DBUS_TYPE_STRING, &key, type, val,
+								n_elements);
+}
+
+static gboolean service_data_exists(const GDBusPropertyTable *property,
+								void *data)
+{
+	return ad_service_uuid != NULL;
+}
+
+static gboolean get_service_data(const GDBusPropertyTable *property,
+				DBusMessageIter *iter, void *user_data)
+{
+	DBusMessageIter dict;
+	const uint8_t *data = ad_service_data;
+
+	dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{sv}", &dict);
+
+	dict_append_array(&dict, ad_service_uuid, DBUS_TYPE_BYTE, &data,
+							ad_service_data_len);
+
+	dbus_message_iter_close_container(iter, &dict);
+
+	return TRUE;
+}
+
 static const GDBusPropertyTable ad_props[] = {
 	{ "Type", "s", get_type },
 	{ "ServiceUUIDs", "as", get_uuids, NULL, uuids_exists },
+	{ "ServiceData", "a{sv}", get_service_data, NULL, service_data_exists },
 	{ }
 };
 
@@ -220,3 +299,52 @@ void ad_advertise_uuids(const char *arg)
 
 	ad_uuids_len = g_strv_length(ad_uuids);
 }
+
+static void ad_clear_service(void)
+{
+	g_free(ad_service_uuid);
+	ad_service_uuid = NULL;
+	memset(ad_service_data, 0, sizeof(ad_service_data));
+	ad_service_data_len = 0;
+}
+
+void ad_advertise_service(const char *arg)
+{
+	wordexp_t w;
+	unsigned int i;
+
+	if (wordexp(arg, &w, WRDE_NOCMD)) {
+		rl_printf("Invalid argument\n");
+		return;
+	}
+
+	ad_clear_service();
+
+	if (w.we_wordc == 0)
+		goto done;
+
+	ad_service_uuid = g_strdup(w.we_wordv[0]);
+
+	for (i = 1; i < w.we_wordc; i++) {
+		long int val;
+		char *endptr = NULL;
+
+		if (i >= G_N_ELEMENTS(ad_service_data)) {
+			rl_printf("Too much data\n");
+			goto done;
+		}
+
+		val = strtol(w.we_wordv[i], &endptr, 0);
+		if (!endptr || *endptr != '\0' || val > UINT8_MAX) {
+			rl_printf("Invalid value at index %d\n", i);
+			ad_clear_service();
+			goto done;
+		}
+
+		ad_service_data[ad_service_data_len] = val;
+		ad_service_data_len++;
+	}
+
+done:
+	wordfree(&w);
+}
diff --git a/client/main.c b/client/main.c
index d6b52c4..72c2cd9 100644
--- a/client/main.c
+++ b/client/main.c
@@ -1878,6 +1878,11 @@ static void cmd_set_advertise_uuids(const char *arg)
 	ad_advertise_uuids(arg);
 }
 
+static void cmd_set_advertise_service(const char *arg)
+{
+	ad_advertise_service(arg);
+}
+
 static const struct {
 	const char *cmd;
 	const char *arg;
@@ -1911,6 +1916,9 @@ static const struct {
 							ad_generator},
 	{ "set-advertise-uuids", "[uuid1 uuid2 ...]",
 			cmd_set_advertise_uuids, "Set advertise uuids" },
+	{ "set-advertise-service", "[uuid][data=[xx xx ...]",
+			cmd_set_advertise_service,
+			"Set advertise service data" },
 	{ "set-scan-filter-uuids", "[uuid1 uuid2 ...]",
 			cmd_set_scan_filter_uuids, "Set scan filter uuids" },
 	{ "set-scan-filter-rssi", "[rssi]", cmd_set_scan_filter_rssi,
-- 
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux