All of lore.kernel.org
 help / color / mirror / Atom feed
* [BlueZ v5 00/13] Implement LE Advertisement D-Bus API
@ 2015-03-25 23:00 Michael Janssen
  2015-03-25 23:00 ` [BlueZ v5 01/13] core: advertising: add LEAdvertisingManager stubs Michael Janssen
                   ` (13 more replies)
  0 siblings, 14 replies; 15+ messages in thread
From: Michael Janssen @ 2015-03-25 23:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Michael Janssen

Implementation of the LE Advertisement API.

Things that are missing still (and added to the TODO):
 * Semantics for multiple Advertisements (currently any more than one will fail)
 * TX Power property parsing / interface

v1 -> v2:
 * Cleanup based on comments from Arman
 * Add g_dbus_proxy_set_read_watch function to avoid ObjectManager dependency
 * Consolidate script updates into single test script

v2 -> v3:
 * Change "ManufacturerSpecificData" to "ManufacturerData"
 * Add advertisement-api.txt to EXTRA_DIST
 * Add Release() callback to org.bluez.LEAdvertisement1
 * Remove IncludePower from the LEAdvertisement1 API

v3 -> v4:
 * Rename "g_dbus_proxy_set_read_watch" to "g_dbus_proxy_set_ready_watch"

v4 -> v5:
 * Rebase
 * Use g_dbus_client_set_proxy_handlers instead of g_dbus_proxy_set_ready_watch
 * Add MGMT interface calls to actually advertise.

Michael Janssen (13):
  core: advertising: add LEAdvertisingManager stubs
  core/advertising: Implement RegisterAdvertisement
  tools: Python script to test Advertisement API
  core/advertising: implement UnregisterAdvertisement
  shared: add advertising-data
  core/advertising: use advertising_data
  core/advertising: Parse ServiceUUIDs
  core/advertising: Parse SolicitUUIDs
  core/advertising: Parse ManufacturerSpecificData
  core/advertising: Parse ServiceData
  Update TODO for LE Advertising
  shared/advertising: implement advertising_data_generate
  core/advertising: Add and Remove AD using MGMT

 Makefile.am                   |   3 +
 TODO                          |  21 +-
 src/adapter.c                 |  19 ++
 src/advertising.c             | 666 ++++++++++++++++++++++++++++++++++++++++++
 src/advertising.h             |  25 ++
 src/shared/advertising-data.c | 585 +++++++++++++++++++++++++++++++++++++
 src/shared/advertising-data.h |  69 +++++
 tools/advertisement-example   | 170 +++++++++++
 8 files changed, 1548 insertions(+), 10 deletions(-)
 create mode 100644 src/advertising.c
 create mode 100644 src/advertising.h
 create mode 100644 src/shared/advertising-data.c
 create mode 100644 src/shared/advertising-data.h
 create mode 100644 tools/advertisement-example

-- 
2.2.0.rc0.207.ga3a616c


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [BlueZ v5 01/13] core: advertising: add LEAdvertisingManager stubs
  2015-03-25 23:00 [BlueZ v5 00/13] Implement LE Advertisement D-Bus API Michael Janssen
@ 2015-03-25 23:00 ` Michael Janssen
  2015-03-25 23:00 ` [BlueZ v5 02/13] core/advertising: Implement RegisterAdvertisement Michael Janssen
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Michael Janssen @ 2015-03-25 23:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Michael Janssen

Introducing src/advertising-manager which will implement the
org.bluez.LEAdvertisingManager1 D-Bus interface defined in
doc/advertising-api.txt.  Each LE-capable controller gets
an instance of the interface.
---
 Makefile.am               |   1 +
 src/adapter.c             |  19 +++++++
 src/advertising-manager.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++
 src/advertising-manager.h |  25 +++++++++
 4 files changed, 177 insertions(+)
 create mode 100644 src/advertising-manager.c
 create mode 100644 src/advertising-manager.h

diff --git a/Makefile.am b/Makefile.am
index af15e9e..db2978e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -175,6 +175,7 @@ src_bluetoothd_SOURCES = $(builtin_sources) \
 			src/uinput.h \
 			src/plugin.h src/plugin.c \
 			src/storage.h src/storage.c \
+			src/advertising-manager.h src/advertising-manager.c \
 			src/agent.h src/agent.c \
 			src/error.h src/error.c \
 			src/adapter.h src/adapter.c \
diff --git a/src/adapter.c b/src/adapter.c
index 6eeb2f9..dbce2c9 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -74,6 +74,7 @@
 #include "attrib/gatt.h"
 #include "attrib-server.h"
 #include "gatt-database.h"
+#include "advertising-manager.h"
 #include "eir.h"
 
 #define ADAPTER_INTERFACE	"org.bluez.Adapter1"
@@ -210,6 +211,7 @@ struct btd_adapter {
 	sdp_list_t *services;		/* Services associated to adapter */
 
 	struct btd_gatt_database *database;
+	struct btd_advertising_manager *adv_manager;
 
 	gboolean initialized;
 
@@ -4607,6 +4609,9 @@ static void adapter_remove(struct btd_adapter *adapter)
 	btd_gatt_database_destroy(adapter->database);
 	adapter->database = NULL;
 
+	btd_advertising_manager_destroy(adapter->adv_manager);
+	adapter->adv_manager = NULL;
+
 	g_slist_free(adapter->pin_callbacks);
 	adapter->pin_callbacks = NULL;
 
@@ -6671,6 +6676,20 @@ static int adapter_register(struct btd_adapter *adapter)
 		return -EINVAL;
 	}
 
+	/* Don't start advertising managers on non-LE controllers. */
+	if (adapter->supported_settings & MGMT_SETTING_LE) {
+		adapter->adv_manager = btd_advertising_manager_new(adapter);
+		if (!adapter->adv_manager) {
+			error("Failed to register LEAdvertisingManager1 "
+						"interface for adapter");
+			btd_gatt_database_destroy(adapter->database);
+			adapter->database = NULL;
+			return -EINVAL;
+		}
+	} else {
+		info("Not starting LEAdvertisingManager, LE not supported");
+	}
+
 	db = btd_gatt_database_get_db(adapter->database);
 	adapter->db_id = gatt_db_register(db, services_modified,
 							services_modified,
diff --git a/src/advertising-manager.c b/src/advertising-manager.c
new file mode 100644
index 0000000..c3f85c2
--- /dev/null
+++ b/src/advertising-manager.c
@@ -0,0 +1,132 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2015  Google Inc.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ */
+
+#include "advertising-manager.h"
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <dbus/dbus.h>
+#include <gdbus/gdbus.h>
+
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+
+#include "adapter.h"
+#include "dbus-common.h"
+#include "log.h"
+#include "src/shared/util.h"
+
+#define LE_ADVERTISING_MGR_IFACE "org.bluez.LEAdvertisingManager1"
+#define LE_ADVERTISEMENT_IFACE "org.bluez.LEAdvertisement1"
+
+struct btd_advertising_manager {
+	struct btd_adapter *adapter;
+};
+
+static DBusMessage *register_advertisement(DBusConnection *conn,
+						DBusMessage *msg,
+						void *user_data)
+{
+	DBG("RegisterAdvertisement");
+
+	/* TODO */
+	return NULL;
+}
+
+static DBusMessage *unregister_advertisement(DBusConnection *conn,
+						DBusMessage *msg,
+						void *user_data)
+{
+	DBG("UnregisterAdvertisement");
+
+	/* TODO */
+	return NULL;
+}
+
+static const GDBusMethodTable methods[] = {
+	{ GDBUS_EXPERIMENTAL_ASYNC_METHOD("RegisterAdvertisement",
+					GDBUS_ARGS({ "advertisement", "o" },
+							{ "options", "a{sv}" }),
+					NULL, register_advertisement) },
+	{ GDBUS_EXPERIMENTAL_ASYNC_METHOD("UnregisterAdvertisement",
+						GDBUS_ARGS({ "service", "o" }),
+						NULL,
+						unregister_advertisement) },
+	{ }
+};
+
+static void advertising_manager_destroy(void *user_data)
+{
+	struct btd_advertising_manager *manager = user_data;
+
+	free(manager);
+}
+
+static struct btd_advertising_manager *
+advertising_manager_create(struct btd_adapter *adapter)
+{
+	struct btd_advertising_manager *manager;
+
+	manager = new0(struct btd_advertising_manager, 1);
+	if (!manager)
+		return NULL;
+
+	manager->adapter = adapter;
+
+	if (!g_dbus_register_interface(btd_get_dbus_connection(),
+						adapter_get_path(adapter),
+						LE_ADVERTISING_MGR_IFACE,
+						methods, NULL, NULL, manager,
+						advertising_manager_destroy)) {
+		error("Failed to register " LE_ADVERTISING_MGR_IFACE);
+		free(manager);
+		return NULL;
+	}
+
+	return manager;
+}
+
+struct btd_advertising_manager *
+btd_advertising_manager_new(struct btd_adapter *adapter)
+{
+	struct btd_advertising_manager *manager;
+
+	if (!adapter)
+		return NULL;
+
+	manager = advertising_manager_create(adapter);
+	if (!manager)
+		return NULL;
+
+	DBG("LE Advertising Manager created for adapter: %s",
+						adapter_get_path(adapter));
+
+	return manager;
+}
+
+void btd_advertising_manager_destroy(struct btd_advertising_manager *manager)
+{
+	if (!manager)
+		return;
+
+	g_dbus_unregister_interface(btd_get_dbus_connection(),
+					adapter_get_path(manager->adapter),
+					LE_ADVERTISING_MGR_IFACE);
+}
diff --git a/src/advertising-manager.h b/src/advertising-manager.h
new file mode 100644
index 0000000..4046013
--- /dev/null
+++ b/src/advertising-manager.h
@@ -0,0 +1,25 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2015  Google Inc.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ */
+
+struct btd_adapter;
+struct btd_advertising_manager;
+
+struct btd_advertising_manager *btd_advertising_manager_new(
+						struct btd_adapter *adapter);
+void btd_advertising_manager_destroy(struct btd_advertising_manager *manager);
-- 
2.2.0.rc0.207.ga3a616c


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [BlueZ v5 02/13] core/advertising: Implement RegisterAdvertisement
  2015-03-25 23:00 [BlueZ v5 00/13] Implement LE Advertisement D-Bus API Michael Janssen
  2015-03-25 23:00 ` [BlueZ v5 01/13] core: advertising: add LEAdvertisingManager stubs Michael Janssen
@ 2015-03-25 23:00 ` Michael Janssen
  2015-03-25 23:00 ` [BlueZ v5 03/13] tools: Python script to test Advertisement API Michael Janssen
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Michael Janssen @ 2015-03-25 23:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Michael Janssen

Initial implementation of the RegisterAdvertisement function of the
LEAdvertisingManager1 interface.
---
 Makefile.am               |   2 +-
 src/adapter.c             |   2 +-
 src/advertising-manager.c | 132 ----------------
 src/advertising-manager.h |  25 ---
 src/advertising.c         | 386 ++++++++++++++++++++++++++++++++++++++++++++++
 src/advertising.h         |  25 +++
 6 files changed, 413 insertions(+), 159 deletions(-)
 delete mode 100644 src/advertising-manager.c
 delete mode 100644 src/advertising-manager.h
 create mode 100644 src/advertising.c
 create mode 100644 src/advertising.h

diff --git a/Makefile.am b/Makefile.am
index db2978e..676d929 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -175,7 +175,7 @@ src_bluetoothd_SOURCES = $(builtin_sources) \
 			src/uinput.h \
 			src/plugin.h src/plugin.c \
 			src/storage.h src/storage.c \
-			src/advertising-manager.h src/advertising-manager.c \
+			src/advertising.h src/advertising.c \
 			src/agent.h src/agent.c \
 			src/error.h src/error.c \
 			src/adapter.h src/adapter.c \
diff --git a/src/adapter.c b/src/adapter.c
index dbce2c9..0c66e2c 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -74,7 +74,7 @@
 #include "attrib/gatt.h"
 #include "attrib-server.h"
 #include "gatt-database.h"
-#include "advertising-manager.h"
+#include "advertising.h"
 #include "eir.h"
 
 #define ADAPTER_INTERFACE	"org.bluez.Adapter1"
diff --git a/src/advertising-manager.c b/src/advertising-manager.c
deleted file mode 100644
index c3f85c2..0000000
--- a/src/advertising-manager.c
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2015  Google Inc.
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- */
-
-#include "advertising-manager.h"
-
-#include <stdint.h>
-#include <stdbool.h>
-
-#include <dbus/dbus.h>
-#include <gdbus/gdbus.h>
-
-#include "lib/bluetooth.h"
-#include "lib/sdp.h"
-
-#include "adapter.h"
-#include "dbus-common.h"
-#include "log.h"
-#include "src/shared/util.h"
-
-#define LE_ADVERTISING_MGR_IFACE "org.bluez.LEAdvertisingManager1"
-#define LE_ADVERTISEMENT_IFACE "org.bluez.LEAdvertisement1"
-
-struct btd_advertising_manager {
-	struct btd_adapter *adapter;
-};
-
-static DBusMessage *register_advertisement(DBusConnection *conn,
-						DBusMessage *msg,
-						void *user_data)
-{
-	DBG("RegisterAdvertisement");
-
-	/* TODO */
-	return NULL;
-}
-
-static DBusMessage *unregister_advertisement(DBusConnection *conn,
-						DBusMessage *msg,
-						void *user_data)
-{
-	DBG("UnregisterAdvertisement");
-
-	/* TODO */
-	return NULL;
-}
-
-static const GDBusMethodTable methods[] = {
-	{ GDBUS_EXPERIMENTAL_ASYNC_METHOD("RegisterAdvertisement",
-					GDBUS_ARGS({ "advertisement", "o" },
-							{ "options", "a{sv}" }),
-					NULL, register_advertisement) },
-	{ GDBUS_EXPERIMENTAL_ASYNC_METHOD("UnregisterAdvertisement",
-						GDBUS_ARGS({ "service", "o" }),
-						NULL,
-						unregister_advertisement) },
-	{ }
-};
-
-static void advertising_manager_destroy(void *user_data)
-{
-	struct btd_advertising_manager *manager = user_data;
-
-	free(manager);
-}
-
-static struct btd_advertising_manager *
-advertising_manager_create(struct btd_adapter *adapter)
-{
-	struct btd_advertising_manager *manager;
-
-	manager = new0(struct btd_advertising_manager, 1);
-	if (!manager)
-		return NULL;
-
-	manager->adapter = adapter;
-
-	if (!g_dbus_register_interface(btd_get_dbus_connection(),
-						adapter_get_path(adapter),
-						LE_ADVERTISING_MGR_IFACE,
-						methods, NULL, NULL, manager,
-						advertising_manager_destroy)) {
-		error("Failed to register " LE_ADVERTISING_MGR_IFACE);
-		free(manager);
-		return NULL;
-	}
-
-	return manager;
-}
-
-struct btd_advertising_manager *
-btd_advertising_manager_new(struct btd_adapter *adapter)
-{
-	struct btd_advertising_manager *manager;
-
-	if (!adapter)
-		return NULL;
-
-	manager = advertising_manager_create(adapter);
-	if (!manager)
-		return NULL;
-
-	DBG("LE Advertising Manager created for adapter: %s",
-						adapter_get_path(adapter));
-
-	return manager;
-}
-
-void btd_advertising_manager_destroy(struct btd_advertising_manager *manager)
-{
-	if (!manager)
-		return;
-
-	g_dbus_unregister_interface(btd_get_dbus_connection(),
-					adapter_get_path(manager->adapter),
-					LE_ADVERTISING_MGR_IFACE);
-}
diff --git a/src/advertising-manager.h b/src/advertising-manager.h
deleted file mode 100644
index 4046013..0000000
--- a/src/advertising-manager.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2015  Google Inc.
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- */
-
-struct btd_adapter;
-struct btd_advertising_manager;
-
-struct btd_advertising_manager *btd_advertising_manager_new(
-						struct btd_adapter *adapter);
-void btd_advertising_manager_destroy(struct btd_advertising_manager *manager);
diff --git a/src/advertising.c b/src/advertising.c
new file mode 100644
index 0000000..eb70177
--- /dev/null
+++ b/src/advertising.c
@@ -0,0 +1,386 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2015  Google Inc.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ */
+
+#include "advertising.h"
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <dbus/dbus.h>
+#include <gdbus/gdbus.h>
+
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+
+#include "adapter.h"
+#include "dbus-common.h"
+#include "error.h"
+#include "log.h"
+#include "src/shared/queue.h"
+#include "src/shared/util.h"
+
+#define LE_ADVERTISING_MGR_IFACE "org.bluez.LEAdvertisingManager1"
+#define LE_ADVERTISEMENT_IFACE "org.bluez.LEAdvertisement1"
+
+struct btd_advertising_manager {
+	struct btd_adapter *adapter;
+	struct queue *adverts;
+};
+
+#define AD_TYPE_BROADCAST 0
+#define AD_TYPE_PERIPHERAL 1
+
+struct advertisement {
+	struct btd_advertising_manager *manager;
+	char *owner;
+	char *path;
+	GDBusClient *client;
+	GDBusProxy *proxy;
+	DBusMessage *reg;
+	uint8_t type; /* Advertising type */
+	bool published;
+};
+
+static bool match_advertisement_path(const void *a, const void *b)
+{
+	const struct advertisement *ad = a;
+	const char *path = b;
+
+	return g_strcmp0(ad->path, path);
+}
+
+static void advertisement_free(void *data)
+{
+	struct advertisement *ad = data;
+
+	if (ad->client) {
+		g_dbus_client_set_disconnect_watch(ad->client, NULL, NULL);
+		g_dbus_client_unref(ad->client);
+	}
+
+	if (ad->proxy)
+		g_dbus_proxy_unref(ad->proxy);
+
+	if (ad->owner)
+		g_free(ad->owner);
+
+	if (ad->path)
+		g_free(ad->path);
+
+	free(ad);
+}
+
+static gboolean advertisement_free_idle_cb(void *data)
+{
+	advertisement_free(data);
+
+	return FALSE;
+}
+
+static void advertisement_release(void *data)
+{
+	struct advertisement *ad = data;
+	DBusMessage *message;
+
+	DBG("Releasing advertisement %s, %s", ad->owner, ad->path);
+
+	message = dbus_message_new_method_call(ad->owner, ad->path,
+							LE_ADVERTISEMENT_IFACE,
+							"Release");
+
+	if (message == NULL) {
+		error("Couldn't allocate D-Bus message");
+		return;
+	}
+
+	g_dbus_send_message(btd_get_dbus_connection(), message);
+}
+
+static void advertisement_destroy(void *data)
+{
+	advertisement_release(data);
+	advertisement_free(data);
+}
+
+
+static void advertisement_remove(void *data)
+{
+	struct advertisement *ad = data;
+
+	g_dbus_client_set_disconnect_watch(ad->client, NULL, NULL);
+
+	queue_remove(ad->manager->adverts, ad);
+
+	g_idle_add(advertisement_free_idle_cb, ad);
+}
+
+static void client_disconnect_cb(DBusConnection *conn, void *user_data)
+{
+	DBG("Client disconnected");
+
+	advertisement_remove(user_data);
+}
+
+static bool parse_advertising_type(GDBusProxy *proxy, uint8_t *type)
+{
+	DBusMessageIter iter;
+	const char *msg_type;
+
+	if (!g_dbus_proxy_get_property(proxy, "Type", &iter))
+		return false;
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+		return false;
+
+	dbus_message_iter_get_basic(&iter, &msg_type);
+
+	if (!g_strcmp0(msg_type, "broadcast")) {
+		*type = AD_TYPE_BROADCAST;
+		return true;
+	}
+
+	if (!g_strcmp0(msg_type, "peripheral")) {
+		*type = AD_TYPE_PERIPHERAL;
+		return true;
+	}
+
+	return false;
+}
+
+static void refresh_advertisement(struct advertisement *ad)
+{
+	DBG("Refreshing advertisement: %s", ad->path);
+	if (!ad->published) {
+		/* TODO: MGMT API call to update the advertisement */
+	}
+}
+
+static bool parse_advertisement(struct advertisement *ad)
+{
+	if (!parse_advertising_type(ad->proxy, &ad->type)) {
+		error("Failed to read \"Type\" property of advertisement");
+		return false;
+	}
+
+	/* TODO: parse the remaining properties into a shared structure */
+
+	refresh_advertisement(ad);
+
+	return true;
+}
+
+static void advertisement_proxy_added(GDBusProxy *proxy, void *data)
+{
+	struct advertisement *ad = data;
+	DBusMessage *reply;
+
+	if (!parse_advertisement(ad)) {
+		error("Failed to parse advertisement");
+
+		reply = btd_error_failed(ad->reg,
+					"Failed to register advertisement");
+		goto done;
+	}
+
+	g_dbus_client_set_disconnect_watch(ad->client, client_disconnect_cb,
+									ad);
+
+	reply = dbus_message_new_method_return(ad->reg);
+
+	DBG("Advertisement registered: %s", ad->path);
+
+done:
+	g_dbus_send_message(btd_get_dbus_connection(), reply);
+
+	dbus_message_unref(ad->reg);
+	ad->reg = NULL;
+}
+
+static struct advertisement *advertisement_create(DBusConnection *conn,
+					DBusMessage *msg, const char *path)
+{
+	struct advertisement *ad;
+	const char *sender = dbus_message_get_sender(msg);
+
+	if (!path || !g_str_has_prefix(path, "/"))
+		return NULL;
+
+	ad = new0(struct advertisement, 1);
+	if (!ad)
+		return NULL;
+
+	ad->published = false;
+
+	ad->client = g_dbus_client_new_full(conn, sender, path, path);
+	if (!ad->client)
+		goto fail;
+
+	ad->owner = g_strdup(sender);
+	if (!ad->owner)
+		goto fail;
+
+	ad->path = g_strdup(path);
+	if (!ad->path)
+		goto fail;
+
+	DBG("Adding proxy for %s", path);
+	ad->proxy = g_dbus_proxy_new(ad->client, path, LE_ADVERTISEMENT_IFACE);
+	if (!ad->proxy)
+		goto fail;
+
+	g_dbus_client_set_proxy_handlers(ad->client, advertisement_proxy_added,
+								NULL, NULL, ad);
+
+	ad->reg = dbus_message_ref(msg);
+
+	return ad;
+
+fail:
+	advertisement_free(ad);
+	return NULL;
+}
+
+static DBusMessage *register_advertisement(DBusConnection *conn,
+						DBusMessage *msg,
+						void *user_data)
+{
+	struct btd_advertising_manager *manager = user_data;
+	DBusMessageIter args;
+	const char *path;
+	struct advertisement *ad;
+
+	DBG("RegisterAdvertisement");
+
+	if (!dbus_message_iter_init(msg, &args))
+		return btd_error_invalid_args(msg);
+
+	if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
+		return btd_error_invalid_args(msg);
+
+	dbus_message_iter_get_basic(&args, &path);
+
+	if (queue_find(manager->adverts, match_advertisement_path, path))
+		return btd_error_already_exists(msg);
+
+	/* TODO: support more than one advertisement */
+	if (!queue_isempty(manager->adverts))
+		return btd_error_failed(msg, "Already advertising");
+
+	dbus_message_iter_next(&args);
+
+	if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY)
+		return btd_error_invalid_args(msg);
+
+	ad = advertisement_create(conn, msg, path);
+	if (!ad)
+		return btd_error_failed(msg,
+					"Failed to register advertisement");
+
+	DBG("Registered advertisement at path %s", path);
+
+	ad->manager = manager;
+	queue_push_tail(manager->adverts, ad);
+
+	return NULL;
+}
+
+static DBusMessage *unregister_advertisement(DBusConnection *conn,
+						DBusMessage *msg,
+						void *user_data)
+{
+	DBG("UnregisterAdvertisement");
+
+	/* TODO */
+	return NULL;
+}
+
+static const GDBusMethodTable methods[] = {
+	{ GDBUS_EXPERIMENTAL_ASYNC_METHOD("RegisterAdvertisement",
+					GDBUS_ARGS({ "advertisement", "o" },
+							{ "options", "a{sv}" }),
+					NULL, register_advertisement) },
+	{ GDBUS_EXPERIMENTAL_ASYNC_METHOD("UnregisterAdvertisement",
+						GDBUS_ARGS({ "service", "o" }),
+						NULL,
+						unregister_advertisement) },
+	{ }
+};
+
+static void advertising_manager_destroy(void *user_data)
+{
+	struct btd_advertising_manager *manager = user_data;
+
+	queue_destroy(manager->adverts, advertisement_destroy);
+
+	free(manager);
+}
+
+static struct btd_advertising_manager *
+advertising_manager_create(struct btd_adapter *adapter)
+{
+	struct btd_advertising_manager *manager;
+
+	manager = new0(struct btd_advertising_manager, 1);
+	if (!manager)
+		return NULL;
+
+	manager->adapter = adapter;
+
+	if (!g_dbus_register_interface(btd_get_dbus_connection(),
+						adapter_get_path(adapter),
+						LE_ADVERTISING_MGR_IFACE,
+						methods, NULL, NULL, manager,
+						advertising_manager_destroy)) {
+		error("Failed to register " LE_ADVERTISING_MGR_IFACE);
+		free(manager);
+		return NULL;
+	}
+
+	manager->adverts = queue_new();
+
+	return manager;
+}
+
+struct btd_advertising_manager *
+btd_advertising_manager_new(struct btd_adapter *adapter)
+{
+	struct btd_advertising_manager *manager;
+
+	if (!adapter)
+		return NULL;
+
+	manager = advertising_manager_create(adapter);
+	if (!manager)
+		return NULL;
+
+	DBG("LE Advertising Manager created for adapter: %s",
+						adapter_get_path(adapter));
+
+	return manager;
+}
+
+void btd_advertising_manager_destroy(struct btd_advertising_manager *manager)
+{
+	if (!manager)
+		return;
+
+	g_dbus_unregister_interface(btd_get_dbus_connection(),
+					adapter_get_path(manager->adapter),
+					LE_ADVERTISING_MGR_IFACE);
+}
diff --git a/src/advertising.h b/src/advertising.h
new file mode 100644
index 0000000..4046013
--- /dev/null
+++ b/src/advertising.h
@@ -0,0 +1,25 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2015  Google Inc.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ */
+
+struct btd_adapter;
+struct btd_advertising_manager;
+
+struct btd_advertising_manager *btd_advertising_manager_new(
+						struct btd_adapter *adapter);
+void btd_advertising_manager_destroy(struct btd_advertising_manager *manager);
-- 
2.2.0.rc0.207.ga3a616c


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [BlueZ v5 03/13] tools: Python script to test Advertisement API
  2015-03-25 23:00 [BlueZ v5 00/13] Implement LE Advertisement D-Bus API Michael Janssen
  2015-03-25 23:00 ` [BlueZ v5 01/13] core: advertising: add LEAdvertisingManager stubs Michael Janssen
  2015-03-25 23:00 ` [BlueZ v5 02/13] core/advertising: Implement RegisterAdvertisement Michael Janssen
@ 2015-03-25 23:00 ` Michael Janssen
  2015-03-25 23:00 ` [BlueZ v5 04/13] core/advertising: implement UnregisterAdvertisement Michael Janssen
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Michael Janssen @ 2015-03-25 23:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Michael Janssen

This script provides an example of using the advertisement-data
D-Bus API from python.
---
 tools/advertisement-example | 170 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 170 insertions(+)
 create mode 100644 tools/advertisement-example

diff --git a/tools/advertisement-example b/tools/advertisement-example
new file mode 100644
index 0000000..98aeafa
--- /dev/null
+++ b/tools/advertisement-example
@@ -0,0 +1,170 @@
+#!/usr/bin/python
+
+import dbus
+import dbus.exceptions
+import dbus.mainloop.glib
+import dbus.service
+
+import array
+import gobject
+
+from random import randint
+
+mainloop = None
+
+BLUEZ_SERVICE_NAME = 'org.bluez'
+LE_ADVERTISING_MANAGER_IFACE = 'org.bluez.LEAdvertisingManager1'
+DBUS_OM_IFACE = 'org.freedesktop.DBus.ObjectManager'
+DBUS_PROP_IFACE = 'org.freedesktop.DBus.Properties'
+
+LE_ADVERTISEMENT_IFACE = 'org.bluez.LEAdvertisement1'
+
+
+class InvalidArgsException(dbus.exceptions.DBusException):
+    _dbus_error_name = 'org.freedesktop.DBus.Error.InvalidArgs'
+
+
+class NotSupportedException(dbus.exceptions.DBusException):
+    _dbus_error_name = 'org.bluez.Error.NotSupported'
+
+
+class NotPermittedException(dbus.exceptions.DBusException):
+    _dbus_error_name = 'org.bluez.Error.NotPermitted'
+
+
+class InvalidValueLengthException(dbus.exceptions.DBusException):
+    _dbus_error_name = 'org.bluez.Error.InvalidValueLength'
+
+
+class FailedException(dbus.exceptions.DBusException):
+    _dbus_error_name = 'org.bluez.Error.Failed'
+
+
+class Advertisement(dbus.service.Object):
+    PATH_BASE = '/org/bluez/example/advertisement'
+
+    def __init__(self, bus, index, advertising_type):
+        self.path = self.PATH_BASE + str(index)
+        self.bus = bus
+        self.ad_type = advertising_type
+        self.service_uuids = None
+        self.manufacturer_data = None
+        self.solicit_uuids = None
+        self.service_data = None
+        dbus.service.Object.__init__(self, bus, self.path)
+
+    def get_properties(self):
+        properties = dict()
+        properties['Type'] = self.ad_type
+        if self.service_uuids is not None:
+            properties['ServiceUUIDs'] = dbus.Array(self.service_uuids,
+                                                    signature='s')
+        if self.solicit_uuids is not None:
+            properties['SolicitUUIDs'] = dbus.Array(self.solicit_uuids,
+                                                    signature='s')
+        if self.manufacturer_data is not None:
+            properties['ManufacturerData'] = dbus.Dictionary(
+                self.manufacturer_data, signature='qay')
+        if self.service_data is not None:
+            properties['ServiceData'] = dbus.Dictionary(self.service_data,
+                                                        signature='say')
+        return {LE_ADVERTISEMENT_IFACE: properties}
+
+    def get_path(self):
+        return dbus.ObjectPath(self.path)
+
+    def add_service_uuid(self, uuid):
+        if not self.service_uuids:
+            self.service_uuids = []
+        self.service_uuids.append(uuid)
+
+    def add_solicit_uuid(self, uuid):
+        if not self.solicit_uuids:
+            self.solicit_uuids = []
+        self.solicit_uuids.append(uuid)
+
+    def add_manufacturer_data(self, manuf_code, data):
+        if not self.manufacturer_data:
+            self.manufacturer_data = dict()
+        self.manufacturer_data[manuf_code] = data
+
+    def add_service_data(self, uuid, data):
+        if not self.service_data:
+            self.service_data = dict()
+        self.service_data[uuid] = data
+
+    @dbus.service.method(DBUS_PROP_IFACE,
+                         in_signature='s',
+                         out_signature='a{sv}')
+    def GetAll(self, interface):
+        print 'GetAll'
+        if interface != LE_ADVERTISEMENT_IFACE:
+            raise InvalidArgsException()
+        print 'returning props'
+        return self.get_properties()[LE_ADVERTISEMENT_IFACE]
+
+    @dbus.service.method(LE_ADVERTISEMENT_IFACE,
+                         in_signature='',
+                         out_signature='')
+    def Release(self):
+        print '%s: Released!' % self.path
+
+class TestAdvertisement(Advertisement):
+
+    def __init__(self, bus, index):
+        Advertisement.__init__(self, bus, index, 'broadcast')
+        self.add_service_uuid('0000180D-0000-1000-8000-00805F9B34FB')
+        self.add_service_uuid('0000180F-0000-1000-8000-00805F9B34FB')
+        self.add_manufacturer_data(0xffff, [0x00, 0x01, 0x02, 0x03, 0x04])
+        self.add_service_data('00009999-0000-1000-8000-00805F9B34FB',
+                              [0x00, 0x01, 0x02, 0x03, 0x04])
+
+
+def register_ad_cb():
+    print 'Advertisement registered'
+
+
+def register_ad_error_cb(error):
+    print 'Failed to register advertisement: ' + str(error)
+    mainloop.quit()
+
+
+def find_adapter(bus):
+    remote_om = dbus.Interface(bus.get_object(BLUEZ_SERVICE_NAME, '/'),
+                               DBUS_OM_IFACE)
+    objects = remote_om.GetManagedObjects()
+
+    for o, props in objects.iteritems():
+        if LE_ADVERTISING_MANAGER_IFACE in props:
+            return o
+
+    return None
+
+
+def main():
+    global mainloop
+
+    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+    bus = dbus.SystemBus()
+
+    adapter = find_adapter(bus)
+    if not adapter:
+        print 'LEAdvertisingManager1 interface not found'
+        return
+
+    ad_manager = dbus.Interface(bus.get_object(BLUEZ_SERVICE_NAME, adapter),
+                                LE_ADVERTISING_MANAGER_IFACE)
+
+    test_advertisement = TestAdvertisement(bus, 0)
+
+    mainloop = gobject.MainLoop()
+
+    ad_manager.RegisterAdvertisement(test_advertisement.get_path(), {},
+                                     reply_handler=register_ad_cb,
+                                     error_handler=register_ad_error_cb)
+
+    mainloop.run()
+
+if __name__ == '__main__':
+    main()
-- 
2.2.0.rc0.207.ga3a616c


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [BlueZ v5 04/13] core/advertising: implement UnregisterAdvertisement
  2015-03-25 23:00 [BlueZ v5 00/13] Implement LE Advertisement D-Bus API Michael Janssen
                   ` (2 preceding siblings ...)
  2015-03-25 23:00 ` [BlueZ v5 03/13] tools: Python script to test Advertisement API Michael Janssen
@ 2015-03-25 23:00 ` Michael Janssen
  2015-03-25 23:00 ` [BlueZ v5 05/13] shared: add advertising-data Michael Janssen
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Michael Janssen @ 2015-03-25 23:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Michael Janssen

Implement the UnregisterAdvertisement method of the
LEAdvertisingManager1 interface.
---
 src/advertising.c | 24 ++++++++++++++++++++++--
 1 file changed, 22 insertions(+), 2 deletions(-)

diff --git a/src/advertising.c b/src/advertising.c
index eb70177..9b82b40 100644
--- a/src/advertising.c
+++ b/src/advertising.c
@@ -125,6 +125,8 @@ static void advertisement_remove(void *data)
 
 	g_dbus_client_set_disconnect_watch(ad->client, NULL, NULL);
 
+	/* TODO: mgmt API call to remove advert */
+
 	queue_remove(ad->manager->adverts, ad);
 
 	g_idle_add(advertisement_free_idle_cb, ad);
@@ -304,10 +306,28 @@ static DBusMessage *unregister_advertisement(DBusConnection *conn,
 						DBusMessage *msg,
 						void *user_data)
 {
+	struct btd_advertising_manager *manager = user_data;
+	DBusMessageIter args;
+	const char *path;
+	struct advertisement *ad;
+
 	DBG("UnregisterAdvertisement");
 
-	/* TODO */
-	return NULL;
+	if (!dbus_message_iter_init(msg, &args))
+		return btd_error_invalid_args(msg);
+
+	if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
+		return btd_error_invalid_args(msg);
+
+	dbus_message_iter_get_basic(&args, &path);
+
+	ad = queue_find(manager->adverts, match_advertisement_path, path);
+	if (!ad)
+		return btd_error_does_not_exist(msg);
+
+	advertisement_remove(ad);
+
+	return dbus_message_new_method_return(msg);
 }
 
 static const GDBusMethodTable methods[] = {
-- 
2.2.0.rc0.207.ga3a616c


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [BlueZ v5 05/13] shared: add advertising-data
  2015-03-25 23:00 [BlueZ v5 00/13] Implement LE Advertisement D-Bus API Michael Janssen
                   ` (3 preceding siblings ...)
  2015-03-25 23:00 ` [BlueZ v5 04/13] core/advertising: implement UnregisterAdvertisement Michael Janssen
@ 2015-03-25 23:00 ` Michael Janssen
  2015-03-25 23:00 ` [BlueZ v5 06/13] core/advertising: use advertising_data Michael Janssen
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Michael Janssen @ 2015-03-25 23:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Michael Janssen

The advetising_data structure provides an abstraction for easy
translation of defined Advertisement Data fields into the resulting
raw bytes needed by the Bluetooth HCI LE Set Advertising Data command.
---
 Makefile.am                   |   2 +
 src/shared/advertising-data.c | 349 ++++++++++++++++++++++++++++++++++++++++++
 src/shared/advertising-data.h |  69 +++++++++
 3 files changed, 420 insertions(+)
 create mode 100644 src/shared/advertising-data.c
 create mode 100644 src/shared/advertising-data.h

diff --git a/Makefile.am b/Makefile.am
index 676d929..5c556d3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -111,6 +111,8 @@ shared_sources = src/shared/io.h src/shared/timeout.h \
 			src/shared/uhid.h src/shared/uhid.c \
 			src/shared/pcap.h src/shared/pcap.c \
 			src/shared/btsnoop.h src/shared/btsnoop.c \
+			src/shared/advertising-data.h \
+			src/shared/advertising-data.c \
 			src/shared/att-types.h \
 			src/shared/att.h src/shared/att.c \
 			src/shared/gatt-helpers.h src/shared/gatt-helpers.c \
diff --git a/src/shared/advertising-data.c b/src/shared/advertising-data.c
new file mode 100644
index 0000000..800856c
--- /dev/null
+++ b/src/shared/advertising-data.c
@@ -0,0 +1,349 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2015  Google Inc.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ */
+
+#include "src/shared/advertising-data.h"
+
+#include "src/shared/queue.h"
+#include "src/shared/util.h"
+
+struct advertising_data {
+	int ref_count;
+	struct queue *service_uuids;
+	struct queue *manufacturer_data;
+	struct queue *solicit_uuids;
+	struct queue *service_data;
+};
+
+struct uuid_tagged_data {
+	bt_uuid_t uuid;
+	uint8_t *data;
+	size_t len;
+};
+
+struct manufacturer_tagged_data {
+	uint16_t manufacturer_id;
+	uint8_t *data;
+	size_t len;
+};
+
+struct advertising_data *advertising_data_new(void)
+{
+	struct advertising_data *ad;
+
+	ad = new0(struct advertising_data, 1);
+	if (!ad)
+		return NULL;
+
+	ad->service_uuids = queue_new();
+	if (!ad->service_uuids)
+		goto fail;
+
+	ad->manufacturer_data = queue_new();
+	if (!ad->manufacturer_data)
+		goto fail;
+
+	ad->solicit_uuids = queue_new();
+	if (!ad->solicit_uuids)
+		goto fail;
+
+	ad->service_data = queue_new();
+	if (!ad->service_data)
+		goto fail;
+
+	return advertising_data_ref(ad);
+
+fail:
+	queue_destroy(ad->service_uuids, NULL);
+	queue_destroy(ad->manufacturer_data, NULL);
+	queue_destroy(ad->solicit_uuids, NULL);
+	queue_destroy(ad->service_data, NULL);
+
+	free(ad);
+
+	return NULL;
+}
+
+struct advertising_data *advertising_data_ref(struct advertising_data *ad)
+{
+	ad->ref_count++;
+	return ad;
+}
+
+static void uuid_tagged_destroy(void *data)
+{
+	struct uuid_tagged_data *tagged = data;
+
+	free(tagged->data);
+	free(tagged);
+}
+
+static bool uuid_tagged_match(const void *data, const void *elem)
+{
+	const struct uuid_tagged_data *tagged = elem;
+	const bt_uuid_t *uuid = data;
+
+	return !bt_uuid_cmp(&tagged->uuid, uuid);
+}
+
+static void manuf_tagged_destroy(void *data)
+{
+	struct manufacturer_tagged_data *tagged = data;
+
+	free(tagged->data);
+	free(tagged);
+}
+
+static bool manuf_tagged_match(const void *data, const void *elem)
+{
+	const struct manufacturer_tagged_data *tagged = elem;
+	uint16_t manuf_id = PTR_TO_UINT(elem);
+
+	return tagged->manufacturer_id == manuf_id;
+}
+
+void advertising_data_unref(struct advertising_data *ad)
+{
+	if (!ad)
+		return;
+
+	if (__sync_sub_and_fetch(&ad->ref_count, 1))
+		return;
+
+	queue_destroy(ad->service_uuids, free);
+
+	queue_destroy(ad->manufacturer_data, manuf_tagged_destroy);
+
+	queue_destroy(ad->solicit_uuids, free);
+
+	queue_destroy(ad->service_data, uuid_tagged_destroy);
+
+	free(ad);
+}
+
+uint8_t *advertising_data_generate(struct advertising_data *ad, uint8_t *length)
+{
+	/* TODO: implement */
+	return NULL;
+}
+
+static bool queue_add_uuid(struct queue *queue, const bt_uuid_t *uuid)
+{
+	bt_uuid_t *new_uuid;
+
+	if (!queue)
+		return false;
+
+	new_uuid = new0(bt_uuid_t, 1);
+	if (!new_uuid)
+		return false;
+
+	bt_uuid_to_uuid128(uuid, new_uuid);
+
+	queue_push_tail(queue, new_uuid);
+
+	return true;
+}
+
+static bool uuid_match(const void *data, const void *elem)
+{
+	const bt_uuid_t *match_uuid = data;
+	const bt_uuid_t *uuid = elem;
+
+	return bt_uuid_cmp(match_uuid, uuid);
+}
+
+static bool queue_remove_uuid(struct queue *queue, bt_uuid_t *uuid)
+{
+	bt_uuid_t *removed;
+
+	if (!queue || !uuid)
+		return false;
+
+	removed = queue_remove_if(queue, uuid_match, uuid);
+
+	if (removed) {
+		free(removed);
+		return true;
+	}
+
+	return false;
+}
+
+bool advertising_data_add_service_uuid(struct advertising_data *ad,
+							const bt_uuid_t *uuid)
+{
+	if (!ad)
+		return false;
+
+	return queue_add_uuid(ad->service_uuids, uuid);
+}
+
+bool advertising_data_remove_service_uuid(struct advertising_data *ad,
+							bt_uuid_t *uuid)
+{
+	if (!ad)
+		return false;
+
+	return queue_remove_uuid(ad->service_uuids, uuid);
+}
+
+void advertising_data_clear_service_uuid(struct advertising_data *ad)
+{
+	queue_destroy(ad->service_uuids, free);
+
+	ad->service_uuids = queue_new();
+}
+
+bool advertising_data_add_manufacturer_data(struct advertising_data *ad,
+						uint16_t manufacturer_id,
+						void *data, size_t len)
+{
+	struct manufacturer_tagged_data *new_data;
+
+	if (!ad)
+		return false;
+
+	new_data = new0(struct manufacturer_tagged_data, 1);
+	if (!new_data)
+		return false;
+
+	new_data->manufacturer_id = manufacturer_id;
+
+	new_data->data = malloc(len);
+	if (!new_data->data) {
+		free(new_data);
+		return false;
+	}
+
+	memcpy(new_data->data, data, len);
+
+	if (queue_push_tail(ad->manufacturer_data, new_data))
+		return true;
+
+	manuf_tagged_destroy(new_data);
+
+	return false;
+}
+
+bool advertising_data_remove_manufacturer_data(struct advertising_data *ad,
+						uint16_t manufacturer_id)
+{
+	struct manufacturer_tagged_data *data;
+
+	if (!ad)
+		return false;
+
+	data = queue_remove_if(ad->manufacturer_data, manuf_tagged_match,
+						UINT_TO_PTR(manufacturer_id));
+
+	if (!data)
+		return false;
+
+	manuf_tagged_destroy(data);
+
+	return true;
+}
+
+void advertising_data_clear_manufacturer_data(struct advertising_data *ad)
+{
+	queue_destroy(ad->manufacturer_data, manuf_tagged_destroy);
+
+	ad->manufacturer_data = queue_new();
+}
+
+bool advertising_data_add_solicit_uuid(struct advertising_data *ad,
+							const bt_uuid_t *uuid)
+{
+	if (!ad)
+		return false;
+
+	return queue_add_uuid(ad->solicit_uuids, uuid);
+}
+
+bool advertising_data_remove_solicit_uuid(struct advertising_data *ad,
+							bt_uuid_t *uuid)
+{
+	if (!ad)
+		return false;
+
+	return queue_remove_uuid(ad->solicit_uuids, uuid);
+}
+
+void advertising_data_clear_solicit_uuid(struct advertising_data *ad)
+{
+	queue_destroy(ad->solicit_uuids, free);
+
+	ad->solicit_uuids = queue_new();
+}
+
+bool advertising_data_add_service_data(struct advertising_data *ad,
+						const bt_uuid_t *uuid,
+						void *data, size_t len)
+{
+	struct uuid_tagged_data *new_data;
+
+	if (!ad)
+		return false;
+
+	new_data = new0(struct uuid_tagged_data, 1);
+	if (!new_data)
+		return false;
+
+	bt_uuid_to_uuid128(uuid, &new_data->uuid);
+
+	new_data->data = malloc(len);
+	if (!new_data) {
+		free(new_data);
+		return false;
+	}
+
+	memcpy(new_data->data, data, len);
+
+	if (queue_push_tail(ad->service_data, new_data))
+		return true;
+
+	uuid_tagged_destroy(new_data);
+
+	return false;
+}
+
+bool advertising_data_remove_service_data(struct advertising_data *ad,
+							bt_uuid_t *uuid)
+{
+	struct uuid_tagged_data *data;
+
+	if (!ad)
+		return false;
+
+	data = queue_remove_if(ad->service_data, uuid_tagged_match, uuid);
+
+	if (!data)
+		return false;
+
+	uuid_tagged_destroy(data);
+
+	return true;
+}
+
+void advertising_data_clear_service_data(struct advertising_data *ad)
+{
+	queue_destroy(ad->service_data, uuid_tagged_destroy);
+
+	ad->service_data = queue_new();
+}
diff --git a/src/shared/advertising-data.h b/src/shared/advertising-data.h
new file mode 100644
index 0000000..05d2b51
--- /dev/null
+++ b/src/shared/advertising-data.h
@@ -0,0 +1,69 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2015  Google Inc.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ */
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include "lib/bluetooth.h"
+#include "lib/uuid.h"
+
+struct advertising_data;
+
+struct advertising_data *advertising_data_new(void);
+
+struct advertising_data *advertising_data_ref(struct advertising_data *ad);
+
+void advertising_data_unref(struct advertising_data *ad);
+
+uint8_t *advertising_data_generate(struct advertising_data *ad,
+							uint8_t *length);
+
+bool advertising_data_add_service_uuid(struct advertising_data *ad,
+							const bt_uuid_t *uuid);
+
+bool advertising_data_remove_service_uuid(struct advertising_data *ad,
+							bt_uuid_t *uuid);
+
+void advertising_data_clear_service_uuid(struct advertising_data *ad);
+
+bool advertising_data_add_manufacturer_data(struct advertising_data *ad,
+						uint16_t manufacturer_data,
+						void *data, size_t len);
+
+bool advertising_data_remove_manufacturer_data(struct advertising_data *ad,
+						uint16_t manufacturer_id);
+
+void advertising_data_clear_manufacturer_data(struct advertising_data *ad);
+
+bool advertising_data_add_solicit_uuid(struct advertising_data *ad,
+							const bt_uuid_t *uuid);
+
+bool advertising_data_remove_solicit_uuid(struct advertising_data *ad,
+							bt_uuid_t *uuid);
+
+void advertising_data_clear_solicit_uuid(struct advertising_data *ad);
+
+bool advertising_data_add_service_data(struct advertising_data *ad,
+						const bt_uuid_t *uuid,
+						void *data, size_t len);
+
+bool advertising_data_remove_service_data(struct advertising_data *ad,
+							bt_uuid_t *uuid);
+
+void advertising_data_clear_service_data(struct advertising_data *ad);
-- 
2.2.0.rc0.207.ga3a616c


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [BlueZ v5 06/13] core/advertising: use advertising_data
  2015-03-25 23:00 [BlueZ v5 00/13] Implement LE Advertisement D-Bus API Michael Janssen
                   ` (4 preceding siblings ...)
  2015-03-25 23:00 ` [BlueZ v5 05/13] shared: add advertising-data Michael Janssen
@ 2015-03-25 23:00 ` Michael Janssen
  2015-03-25 23:00 ` [BlueZ v5 07/13] core/advertising: Parse ServiceUUIDs Michael Janssen
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Michael Janssen @ 2015-03-25 23:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Michael Janssen

Start using the newly introduced struct advertising_data API.
---
 src/advertising.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/src/advertising.c b/src/advertising.c
index 9b82b40..9ac39bf 100644
--- a/src/advertising.c
+++ b/src/advertising.c
@@ -32,6 +32,7 @@
 #include "dbus-common.h"
 #include "error.h"
 #include "log.h"
+#include "src/shared/advertising-data.h"
 #include "src/shared/queue.h"
 #include "src/shared/util.h"
 
@@ -55,6 +56,7 @@ struct advertisement {
 	DBusMessage *reg;
 	uint8_t type; /* Advertising type */
 	bool published;
+	struct advertising_data *data;
 };
 
 static bool match_advertisement_path(const void *a, const void *b)
@@ -74,8 +76,9 @@ static void advertisement_free(void *data)
 		g_dbus_client_unref(ad->client);
 	}
 
-	if (ad->proxy)
-		g_dbus_proxy_unref(ad->proxy);
+	advertising_data_unref(ad->data);
+
+	g_dbus_proxy_unref(ad->proxy);
 
 	if (ad->owner)
 		g_free(ad->owner);
@@ -251,6 +254,10 @@ static struct advertisement *advertisement_create(DBusConnection *conn,
 
 	ad->reg = dbus_message_ref(msg);
 
+	ad->data = advertising_data_new();
+	if (!ad->data)
+		goto fail;
+
 	return ad;
 
 fail:
-- 
2.2.0.rc0.207.ga3a616c


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [BlueZ v5 07/13] core/advertising: Parse ServiceUUIDs
  2015-03-25 23:00 [BlueZ v5 00/13] Implement LE Advertisement D-Bus API Michael Janssen
                   ` (5 preceding siblings ...)
  2015-03-25 23:00 ` [BlueZ v5 06/13] core/advertising: use advertising_data Michael Janssen
@ 2015-03-25 23:00 ` Michael Janssen
  2015-03-25 23:00 ` [BlueZ v5 08/13] core/advertising: Parse SolicitUUIDs Michael Janssen
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Michael Janssen @ 2015-03-25 23:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Michael Janssen

Parse the ServiceUUIDs property of the LEAdvertisement1 object.
---
 src/advertising.c | 45 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 44 insertions(+), 1 deletion(-)

diff --git a/src/advertising.c b/src/advertising.c
index 9ac39bf..a121034 100644
--- a/src/advertising.c
+++ b/src/advertising.c
@@ -168,6 +168,44 @@ static bool parse_advertising_type(GDBusProxy *proxy, uint8_t *type)
 	return false;
 }
 
+static bool parse_advertising_service_uuids(GDBusProxy *proxy,
+					struct advertising_data *data)
+{
+	DBusMessageIter iter, ariter;
+
+	if (!g_dbus_proxy_get_property(proxy, "ServiceUUIDs", &iter))
+		return true;
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+		return false;
+
+	dbus_message_iter_recurse(&iter, &ariter);
+
+	advertising_data_clear_service_uuid(data);
+
+	while (dbus_message_iter_get_arg_type(&ariter) == DBUS_TYPE_STRING) {
+		const char *uuid_str;
+		bt_uuid_t uuid;
+
+		dbus_message_iter_get_basic(&ariter, &uuid_str);
+
+		DBG("Adding ServiceUUID: %s", uuid_str);
+
+		if (bt_string_to_uuid(&uuid, uuid_str) < 0)
+			goto fail;
+
+		advertising_data_add_service_uuid(data, &uuid);
+
+		dbus_message_iter_next(&ariter);
+	}
+
+	return true;
+
+fail:
+	advertising_data_clear_service_uuid(data);
+	return false;
+}
+
 static void refresh_advertisement(struct advertisement *ad)
 {
 	DBG("Refreshing advertisement: %s", ad->path);
@@ -183,7 +221,12 @@ static bool parse_advertisement(struct advertisement *ad)
 		return false;
 	}
 
-	/* TODO: parse the remaining properties into a shared structure */
+	if (!parse_advertising_service_uuids(ad->proxy, ad->data)) {
+		error("Property \"ServiceUUIDs\" failed to parse correctly");
+		return false;
+	}
+
+	/* TODO: parse the rest of the properties */
 
 	refresh_advertisement(ad);
 
-- 
2.2.0.rc0.207.ga3a616c


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [BlueZ v5 08/13] core/advertising: Parse SolicitUUIDs
  2015-03-25 23:00 [BlueZ v5 00/13] Implement LE Advertisement D-Bus API Michael Janssen
                   ` (6 preceding siblings ...)
  2015-03-25 23:00 ` [BlueZ v5 07/13] core/advertising: Parse ServiceUUIDs Michael Janssen
@ 2015-03-25 23:00 ` Michael Janssen
  2015-03-25 23:00 ` [BlueZ v5 09/13] core/advertising: Parse ManufacturerSpecificData Michael Janssen
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Michael Janssen @ 2015-03-25 23:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Michael Janssen

Parse the SolicitUUIDs property of the LEAdvertisement1 object.
---
 src/advertising.c | 43 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/src/advertising.c b/src/advertising.c
index a121034..24a0063 100644
--- a/src/advertising.c
+++ b/src/advertising.c
@@ -206,6 +206,44 @@ fail:
 	return false;
 }
 
+static bool parse_advertising_solicit_uuids(GDBusProxy *proxy,
+					struct advertising_data *data)
+{
+	DBusMessageIter iter, ariter;
+
+	if (!g_dbus_proxy_get_property(proxy, "SolicitUUIDs", &iter))
+		return true;
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+		return false;
+
+	dbus_message_iter_recurse(&iter, &ariter);
+
+	advertising_data_clear_solicit_uuid(data);
+
+	while (dbus_message_iter_get_arg_type(&ariter) == DBUS_TYPE_STRING) {
+		const char *uuid_str;
+		bt_uuid_t uuid;
+
+		dbus_message_iter_get_basic(&ariter, &uuid_str);
+
+		DBG("Adding SolicitUUID: %s", uuid_str);
+
+		if (bt_string_to_uuid(&uuid, uuid_str) < 0)
+			goto fail;
+
+		advertising_data_add_solicit_uuid(data, &uuid);
+
+		dbus_message_iter_next(&ariter);
+	}
+
+	return true;
+
+fail:
+	advertising_data_clear_solicit_uuid(data);
+	return false;
+}
+
 static void refresh_advertisement(struct advertisement *ad)
 {
 	DBG("Refreshing advertisement: %s", ad->path);
@@ -226,6 +264,11 @@ static bool parse_advertisement(struct advertisement *ad)
 		return false;
 	}
 
+	if (!parse_advertising_solicit_uuids(ad->proxy, ad->data)) {
+		error("Property \"SolicitUUIDs\" failed to parse correctly");
+		return false;
+	}
+
 	/* TODO: parse the rest of the properties */
 
 	refresh_advertisement(ad);
-- 
2.2.0.rc0.207.ga3a616c


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [BlueZ v5 09/13] core/advertising: Parse ManufacturerSpecificData
  2015-03-25 23:00 [BlueZ v5 00/13] Implement LE Advertisement D-Bus API Michael Janssen
                   ` (7 preceding siblings ...)
  2015-03-25 23:00 ` [BlueZ v5 08/13] core/advertising: Parse SolicitUUIDs Michael Janssen
@ 2015-03-25 23:00 ` Michael Janssen
  2015-03-25 23:00 ` [BlueZ v5 10/13] core/advertising: Parse ServiceData Michael Janssen
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Michael Janssen @ 2015-03-25 23:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Michael Janssen

Parse the ManufacturerSpecificData property of the LEAdvertisement1
---
 src/advertising.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 58 insertions(+), 2 deletions(-)

diff --git a/src/advertising.c b/src/advertising.c
index 24a0063..1bd657c 100644
--- a/src/advertising.c
+++ b/src/advertising.c
@@ -244,6 +244,57 @@ fail:
 	return false;
 }
 
+static bool parse_advertising_manufacturer_data(GDBusProxy *proxy,
+						struct advertising_data *data)
+{
+	DBusMessageIter iter, entries;
+
+	if (!g_dbus_proxy_get_property(proxy, "ManufacturerData", &iter))
+		return true;
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+		return false;
+
+	dbus_message_iter_recurse(&iter, &entries);
+
+	advertising_data_clear_manufacturer_data(data);
+
+	while (dbus_message_iter_get_arg_type(&entries)
+						== DBUS_TYPE_DICT_ENTRY) {
+		DBusMessageIter value, entry;
+		uint16_t manuf_id;
+		uint8_t *manuf_data;
+		int len;
+
+		dbus_message_iter_recurse(&entries, &entry);
+		dbus_message_iter_get_basic(&entry, &manuf_id);
+
+		dbus_message_iter_next(&entry);
+		if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_ARRAY)
+			goto fail;
+
+		dbus_message_iter_recurse(&entry, &value);
+
+		if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_BYTE)
+			goto fail;
+
+		dbus_message_iter_get_fixed_array(&value, &manuf_data, &len);
+
+		DBG("Adding ManufacturerData for %04x", manuf_id);
+
+		advertising_data_add_manufacturer_data(data, manuf_id,
+							manuf_data, len);
+
+		dbus_message_iter_next(&entries);
+	}
+
+	return true;
+
+fail:
+	advertising_data_clear_manufacturer_data(data);
+	return false;
+}
+
 static void refresh_advertisement(struct advertisement *ad)
 {
 	DBG("Refreshing advertisement: %s", ad->path);
@@ -260,12 +311,17 @@ static bool parse_advertisement(struct advertisement *ad)
 	}
 
 	if (!parse_advertising_service_uuids(ad->proxy, ad->data)) {
-		error("Property \"ServiceUUIDs\" failed to parse correctly");
+		error("Property \"ServiceUUIDs\" failed to parse");
 		return false;
 	}
 
 	if (!parse_advertising_solicit_uuids(ad->proxy, ad->data)) {
-		error("Property \"SolicitUUIDs\" failed to parse correctly");
+		error("Property \"SolicitUUIDs\" failed to parse");
+		return false;
+	}
+
+	if (!parse_advertising_manufacturer_data(ad->proxy, ad->data)) {
+		error("Property \"ManufacturerData\" failed to parse");
 		return false;
 	}
 
-- 
2.2.0.rc0.207.ga3a616c


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [BlueZ v5 10/13] core/advertising: Parse ServiceData
  2015-03-25 23:00 [BlueZ v5 00/13] Implement LE Advertisement D-Bus API Michael Janssen
                   ` (8 preceding siblings ...)
  2015-03-25 23:00 ` [BlueZ v5 09/13] core/advertising: Parse ManufacturerSpecificData Michael Janssen
@ 2015-03-25 23:00 ` Michael Janssen
  2015-03-25 23:00 ` [BlueZ v5 11/13] Update TODO for LE Advertising Michael Janssen
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Michael Janssen @ 2015-03-25 23:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Michael Janssen

Parse the ServiceData property of LEAdvertisement1
---
 src/advertising.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)

diff --git a/src/advertising.c b/src/advertising.c
index 1bd657c..604f7ac 100644
--- a/src/advertising.c
+++ b/src/advertising.c
@@ -295,6 +295,61 @@ fail:
 	return false;
 }
 
+static bool parse_advertising_service_data(GDBusProxy *proxy,
+						struct advertising_data *data)
+{
+	DBusMessageIter iter, entries;
+
+	if (!g_dbus_proxy_get_property(proxy, "ServiceData", &iter))
+		return true;
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+		return false;
+
+	dbus_message_iter_recurse(&iter, &entries);
+
+	advertising_data_clear_manufacturer_data(data);
+
+	while (dbus_message_iter_get_arg_type(&entries)
+						== DBUS_TYPE_DICT_ENTRY) {
+		DBusMessageIter value, entry;
+		const char *uuid_str;
+		bt_uuid_t uuid;
+		uint8_t *service_data;
+		int len;
+
+		dbus_message_iter_recurse(&entries, &entry);
+		dbus_message_iter_get_basic(&entry, &uuid_str);
+
+		if (bt_string_to_uuid(&uuid, uuid_str) < 0)
+			goto fail;
+
+		dbus_message_iter_next(&entry);
+		if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_ARRAY)
+			goto fail;
+
+		dbus_message_iter_recurse(&entry, &value);
+
+		if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_BYTE)
+			goto fail;
+
+		dbus_message_iter_get_fixed_array(&value, &service_data, &len);
+
+		DBG("Adding ServiceData for %s", uuid_str);
+
+		advertising_data_add_service_data(data, &uuid,
+							service_data, len);
+
+		dbus_message_iter_next(&entries);
+	}
+
+	return true;
+
+fail:
+	advertising_data_clear_manufacturer_data(data);
+	return false;
+}
+
 static void refresh_advertisement(struct advertisement *ad)
 {
 	DBG("Refreshing advertisement: %s", ad->path);
@@ -325,6 +380,11 @@ static bool parse_advertisement(struct advertisement *ad)
 		return false;
 	}
 
+	if (!parse_advertising_service_data(ad->proxy, ad->data)) {
+		error("Property \"ServiceData\" failed to parse correctly");
+		return false;
+	}
+
 	/* TODO: parse the rest of the properties */
 
 	refresh_advertisement(ad);
-- 
2.2.0.rc0.207.ga3a616c


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [BlueZ v5 11/13] Update TODO for LE Advertising
  2015-03-25 23:00 [BlueZ v5 00/13] Implement LE Advertisement D-Bus API Michael Janssen
                   ` (9 preceding siblings ...)
  2015-03-25 23:00 ` [BlueZ v5 10/13] core/advertising: Parse ServiceData Michael Janssen
@ 2015-03-25 23:00 ` Michael Janssen
  2015-03-25 23:01 ` [BlueZ v5 12/13] shared/advertising: implement advertising_data_generate Michael Janssen
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Michael Janssen @ 2015-03-25 23:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Michael Janssen

---
 TODO | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/TODO b/TODO
index 65e19ee..f9c1843 100644
--- a/TODO
+++ b/TODO
@@ -64,16 +64,17 @@ General
 Low Energy
 ==========
 
-- Advertising management. Adapter interface needs to be changed to manage
-  connection modes, adapter type and advertising policy. See Volume 3,
-  Part C, section 9.3. If Attribute Server is enabled the LE capable
-  adapter shall to start advertising. Further investigation is necessary
-  to define which connectable mode needs to be supported: Non-connectable,
-  directed connectable and undirected connectable. Basically, two connectable
-  scenarios shall be addressed:
-  1. GATT client is disconnected, but intends to become a Peripheral to
-     receive indications/notifications.
-  2. GATT server intends to accept connections.
+- Connection modes. Adapter interface needs to be changed to manage
+  connection modes and adapter type. See Volume 3, Part C, section 9.3.
+  1. Mode management: Peripheral / Central
+
+  Priority: Medium
+  Complexity: C2
+
+- Advertising data. A MGMT interface is needed for setting LE Advertisement Data
+  and Scan Response data.  An adapter should be advertising whenever it is
+  appropriate to advertise, and it should be possible to determine what advertising
+  is occurring.
 
   Priority: Medium
   Complexity: C2
-- 
2.2.0.rc0.207.ga3a616c


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [BlueZ v5 12/13] shared/advertising: implement advertising_data_generate
  2015-03-25 23:00 [BlueZ v5 00/13] Implement LE Advertisement D-Bus API Michael Janssen
                   ` (10 preceding siblings ...)
  2015-03-25 23:00 ` [BlueZ v5 11/13] Update TODO for LE Advertising Michael Janssen
@ 2015-03-25 23:01 ` Michael Janssen
  2015-03-25 23:01 ` [BlueZ v5 13/13] core/advertising: Add and Remove AD using MGMT Michael Janssen
  2015-03-26 14:22 ` [BlueZ v5 00/13] Implement LE Advertisement D-Bus API Luiz Augusto von Dentz
  13 siblings, 0 replies; 15+ messages in thread
From: Michael Janssen @ 2015-03-25 23:01 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Michael Janssen

Implements the function to provide a raw version of the advertising data
packet for passing to the kernel.
---
 src/shared/advertising-data.c | 240 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 238 insertions(+), 2 deletions(-)

diff --git a/src/shared/advertising-data.c b/src/shared/advertising-data.c
index 800856c..ccef2a4 100644
--- a/src/shared/advertising-data.c
+++ b/src/shared/advertising-data.c
@@ -22,6 +22,21 @@
 #include "src/shared/queue.h"
 #include "src/shared/util.h"
 
+#define MAX_ADV_DATA_LEN 31
+
+#define LE_AD_TYPE_UUID16_ALL		0x03 /* 16-bit service UUIDs, all */
+#define LE_AD_TYPE_UUID32_ALL		0x05 /* 16-bit service UUIDs, all */
+#define LE_AD_TYPE_UUID128_ALL		0x07 /* 16-bit service UUIDs, all */
+#define LE_AD_TYPE_SOLICIT16		0x14 /* 16-bit service solic. UUIDs */
+#define LE_AD_TYPE_SOLICIT32		0x1F /* 32-bit service solic. UUIDs */
+#define LE_AD_TYPE_SOLICIT128		0x15 /* 128-bit service solic. UUIDs */
+#define LE_AD_TYPE_SVC_DATA16		0x16 /* Service Data - 16-bit UUID */
+#define LE_AD_TYPE_SVC_DATA32		0x20 /* Service Data - 32-bit UUID */
+#define LE_AD_TYPE_SVC_DATA128		0x21 /* Service Data - 128-bit UUID */
+#define LE_AD_TYPE_PUB_TRGT_ADDR	0x17 /* Public Target Address */
+#define LE_AD_TYPE_RND_TRGT_ADDR	0x18 /* Random Target Address */
+#define LE_AD_TYPE_MANUF_DATA		0xFF /* Manufacturer Specific Data */
+
 struct advertising_data {
 	int ref_count;
 	struct queue *service_uuids;
@@ -136,10 +151,231 @@ void advertising_data_unref(struct advertising_data *ad)
 	free(ad);
 }
 
+static uint8_t uuid_list_length(struct queue *uuid_queue)
+{
+	bool uuid16_included = false;
+	bool uuid32_included = false;
+	bool uuid128_included = false;
+	uint8_t length = 0;
+	const struct queue_entry *entry;
+
+	entry = queue_get_entries(uuid_queue);
+
+	while (entry) {
+		bt_uuid_t *uuid = entry->data;
+		uint8_t uuid_len = bt_uuid_len(uuid);
+
+		length += uuid_len;
+
+		if (uuid_len == 2)
+			uuid16_included = true;
+		else if (uuid_len == 4)
+			uuid32_included = true;
+		else
+			uuid128_included = true;
+
+		entry = entry->next;
+	}
+
+	if (uuid16_included)
+		length += 2;
+
+	if (uuid32_included)
+		length += 2;
+
+	if (uuid128_included)
+		length += 2;
+
+	return length;
+}
+
+static uint8_t mfg_data_length(struct queue *manuf_data)
+{
+	uint8_t length = 0;
+	const struct queue_entry *entry;
+
+	entry = queue_get_entries(manuf_data);
+
+	while (entry) {
+		struct manufacturer_tagged_data *data = entry->data;
+
+		length += 2 + sizeof(uint16_t) + data->len;
+
+		entry = entry->next;
+	}
+
+	return length;
+}
+
+static uint8_t uuid_data_length(struct queue *tagged_data)
+{
+	uint8_t length = 0;
+	const struct queue_entry *entry;
+
+	entry = queue_get_entries(tagged_data);
+
+	while (entry) {
+		struct uuid_tagged_data *data = entry->data;
+
+		length += 2 + bt_uuid_len(&data->uuid) + data->len;
+
+		entry = entry->next;
+	}
+
+	return length;
+}
+
+static uint8_t calculate_length(struct advertising_data *ad)
+{
+	uint8_t length = 0;
+
+	length += uuid_list_length(ad->service_uuids);
+
+	length += uuid_list_length(ad->solicit_uuids);
+
+	length += mfg_data_length(ad->manufacturer_data);
+
+	length += uuid_data_length(ad->service_data);
+
+	return length;
+}
+
+static void serialize_uuids(struct queue *uuids, uint8_t uuid_type,
+					uint8_t ad_type, uint8_t *buf,
+					uint8_t *pos)
+{
+	const struct queue_entry *entry = queue_get_entries(uuids);
+	bool added = false;
+	uint8_t length_pos = 0;
+
+	while (entry) {
+		bt_uuid_t *uuid = entry->data;
+
+		if (uuid->type == uuid_type) {
+			if (!added) {
+				length_pos = (*pos)++;
+				buf[(*pos)++] = ad_type;
+				added = true;
+			}
+
+			if (uuid_type != BT_UUID32)
+				bt_uuid_to_le(uuid, buf + *pos);
+			else
+				bt_put_le32(uuid->value.u32, buf + *pos);
+
+			*pos += bt_uuid_len(uuid);
+		}
+
+		entry = entry->next;
+	}
+
+	if (added)
+		buf[length_pos] = *pos - length_pos;
+}
+
+static void serialize_service_uuids(struct queue *uuids, uint8_t *buf,
+								uint8_t *pos)
+{
+	serialize_uuids(uuids, BT_UUID16, LE_AD_TYPE_UUID16_ALL, buf, pos);
+
+	serialize_uuids(uuids, BT_UUID32, LE_AD_TYPE_UUID32_ALL, buf, pos);
+
+	serialize_uuids(uuids, BT_UUID128, LE_AD_TYPE_UUID128_ALL, buf, pos);
+}
+
+static void serialize_solicit_uuids(struct queue *uuids, uint8_t *buf,
+								uint8_t *pos)
+{
+	serialize_uuids(uuids, BT_UUID16, LE_AD_TYPE_SOLICIT16, buf, pos);
+
+	serialize_uuids(uuids, BT_UUID32, LE_AD_TYPE_SOLICIT32, buf, pos);
+
+	serialize_uuids(uuids, BT_UUID128, LE_AD_TYPE_SOLICIT128, buf, pos);
+}
+
+static void serialize_manuf_data(struct queue *manuf_data, uint8_t *buf,
+								uint8_t *pos)
+{
+	const struct queue_entry *entry = queue_get_entries(manuf_data);
+
+	while (entry) {
+		struct manufacturer_tagged_data *data = entry->data;
+
+		buf[(*pos)++] = data->len + 2 + 1;
+
+		buf[(*pos)++] = LE_AD_TYPE_MANUF_DATA;
+
+		bt_put_le16(data->manufacturer_id, buf + (*pos));
+
+		*pos += 2;
+
+		memcpy(buf + *pos, data->data, data->len);
+
+		*pos += data->len;
+
+		entry = entry->next;
+	}
+}
+
+static void serialize_service_data(struct queue *service_data, uint8_t *buf,
+								uint8_t *pos)
+{
+	const struct queue_entry *entry = queue_get_entries(service_data);
+
+	while (entry) {
+		struct uuid_tagged_data *data = entry->data;
+		int uuid_len = bt_uuid_len(&data->uuid);
+
+		buf[(*pos)++] =  uuid_len + data->len + 1;
+
+		switch (uuid_len) {
+		case 2:
+			buf[(*pos)++] = LE_AD_TYPE_SVC_DATA16;
+			break;
+		case 4:
+			buf[(*pos)++] = LE_AD_TYPE_SVC_DATA32;
+			break;
+		case 16:
+			buf[(*pos)++] = LE_AD_TYPE_SVC_DATA128;
+			break;
+		}
+
+		if (uuid_len != 4)
+			bt_uuid_to_le(&data->uuid, buf + *pos);
+		else
+			bt_put_le32(data->uuid.value.u32, buf + *pos);
+
+		*pos += uuid_len;
+
+		memcpy(buf + *pos, data->data, data->len);
+
+		*pos += data->len;
+
+		entry = entry->next;
+	}
+}
+
 uint8_t *advertising_data_generate(struct advertising_data *ad, uint8_t *length)
 {
-	/* TODO: implement */
-	return NULL;
+	uint8_t *adv_data;
+	uint8_t pos = 0;
+
+	*length = calculate_length(ad);
+
+	if (*length > MAX_ADV_DATA_LEN)
+		return NULL;
+
+	adv_data = malloc(*length);
+
+	serialize_service_uuids(ad->service_uuids, adv_data, &pos);
+
+	serialize_solicit_uuids(ad->solicit_uuids, adv_data, &pos);
+
+	serialize_manuf_data(ad->manufacturer_data, adv_data, &pos);
+
+	serialize_service_data(ad->service_data, adv_data, &pos);
+
+	return adv_data;
 }
 
 static bool queue_add_uuid(struct queue *queue, const bt_uuid_t *uuid)
-- 
2.2.0.rc0.207.ga3a616c


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [BlueZ v5 13/13] core/advertising: Add and Remove AD using MGMT
  2015-03-25 23:00 [BlueZ v5 00/13] Implement LE Advertisement D-Bus API Michael Janssen
                   ` (11 preceding siblings ...)
  2015-03-25 23:01 ` [BlueZ v5 12/13] shared/advertising: implement advertising_data_generate Michael Janssen
@ 2015-03-25 23:01 ` Michael Janssen
  2015-03-26 14:22 ` [BlueZ v5 00/13] Implement LE Advertisement D-Bus API Luiz Augusto von Dentz
  13 siblings, 0 replies; 15+ messages in thread
From: Michael Janssen @ 2015-03-25 23:01 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Michael Janssen

Updates the advertising manager to add and remove the LE Advertising Data
using MGMT interface commands.
---
 src/advertising.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 57 insertions(+), 6 deletions(-)

diff --git a/src/advertising.c b/src/advertising.c
index 604f7ac..2fab8d0 100644
--- a/src/advertising.c
+++ b/src/advertising.c
@@ -26,6 +26,7 @@
 #include <gdbus/gdbus.h>
 
 #include "lib/bluetooth.h"
+#include "lib/mgmt.h"
 #include "lib/sdp.h"
 
 #include "adapter.h"
@@ -33,6 +34,7 @@
 #include "error.h"
 #include "log.h"
 #include "src/shared/advertising-data.h"
+#include "src/shared/mgmt.h"
 #include "src/shared/queue.h"
 #include "src/shared/util.h"
 
@@ -41,6 +43,8 @@
 
 struct btd_advertising_manager {
 	struct btd_adapter *adapter;
+	struct mgmt *mgmt;
+	uint16_t mgmt_index;
 	struct queue *adverts;
 };
 
@@ -55,7 +59,7 @@ struct advertisement {
 	GDBusProxy *proxy;
 	DBusMessage *reg;
 	uint8_t type; /* Advertising type */
-	bool published;
+	uint8_t instance;
 	struct advertising_data *data;
 };
 
@@ -125,10 +129,15 @@ static void advertisement_destroy(void *data)
 static void advertisement_remove(void *data)
 {
 	struct advertisement *ad = data;
+	struct mgmt_cp_remove_advertising cp;
 
 	g_dbus_client_set_disconnect_watch(ad->client, NULL, NULL);
 
-	/* TODO: mgmt API call to remove advert */
+	cp.instance = ad->instance;
+
+	mgmt_send(ad->manager->mgmt, MGMT_OP_REMOVE_ADVERTISING,
+			ad->manager->mgmt_index, sizeof(cp), &cp, NULL, NULL,
+			NULL);
 
 	queue_remove(ad->manager->adverts, ad);
 
@@ -350,12 +359,44 @@ fail:
 	return false;
 }
 
+static void add_advertising_callback(uint8_t status, uint16_t length,
+					  const void *param, void *user_data)
+{
+	struct advertisement *ad = user_data;
+	const struct mgmt_rp_add_advertising *rp = param;
+
+	if (status || !param) {
+		error("Failed to set advertising data!");
+		return;
+	}
+
+	ad->instance = rp->instance;
+}
+
 static void refresh_advertisement(struct advertisement *ad)
 {
+	struct mgmt_cp_add_advertising *cp;
+	uint8_t adv_data_len, param_len;
+	uint8_t *adv_data;
+
 	DBG("Refreshing advertisement: %s", ad->path);
-	if (!ad->published) {
-		/* TODO: MGMT API call to update the advertisement */
-	}
+
+	adv_data = advertising_data_generate(ad->data, &adv_data_len);
+
+	param_len = sizeof(struct mgmt_cp_add_advertising) + adv_data_len;
+
+	cp = malloc(param_len);
+
+	cp->instance = ad->instance;
+	cp->flags = 0;
+	cp->duration = 0;
+	cp->timeout = 0;
+	cp->adv_data_len = adv_data_len;
+	memcpy(cp->data, adv_data, adv_data_len);
+
+	mgmt_send(ad->manager->mgmt, MGMT_OP_ADD_ADVERTISING,
+					ad->manager->mgmt_index, param_len, cp,
+					add_advertising_callback, ad, NULL);
 }
 
 static bool parse_advertisement(struct advertisement *ad)
@@ -432,7 +473,7 @@ static struct advertisement *advertisement_create(DBusConnection *conn,
 	if (!ad)
 		return NULL;
 
-	ad->published = false;
+	ad->instance = 1;
 
 	ad->client = g_dbus_client_new_full(conn, sender, path, path);
 	if (!ad->client)
@@ -571,6 +612,16 @@ advertising_manager_create(struct btd_adapter *adapter)
 
 	manager->adapter = adapter;
 
+	manager->mgmt = mgmt_new_default();
+
+	if (!manager->mgmt) {
+		error("Failed to access management interface");
+		free(manager);
+		return NULL;
+	}
+
+	manager->mgmt_index = btd_adapter_get_index(adapter);
+
 	if (!g_dbus_register_interface(btd_get_dbus_connection(),
 						adapter_get_path(adapter),
 						LE_ADVERTISING_MGR_IFACE,
-- 
2.2.0.rc0.207.ga3a616c


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [BlueZ v5 00/13] Implement LE Advertisement D-Bus API
  2015-03-25 23:00 [BlueZ v5 00/13] Implement LE Advertisement D-Bus API Michael Janssen
                   ` (12 preceding siblings ...)
  2015-03-25 23:01 ` [BlueZ v5 13/13] core/advertising: Add and Remove AD using MGMT Michael Janssen
@ 2015-03-26 14:22 ` Luiz Augusto von Dentz
  13 siblings, 0 replies; 15+ messages in thread
From: Luiz Augusto von Dentz @ 2015-03-26 14:22 UTC (permalink / raw)
  To: Michael Janssen; +Cc: linux-bluetooth

Hi Michael,

On Thu, Mar 26, 2015 at 1:00 AM, Michael Janssen <jamuraa@chromium.org> wrote:
> Implementation of the LE Advertisement API.
>
> Things that are missing still (and added to the TODO):
>  * Semantics for multiple Advertisements (currently any more than one will fail)
>  * TX Power property parsing / interface
>
> v1 -> v2:
>  * Cleanup based on comments from Arman
>  * Add g_dbus_proxy_set_read_watch function to avoid ObjectManager dependency
>  * Consolidate script updates into single test script
>
> v2 -> v3:
>  * Change "ManufacturerSpecificData" to "ManufacturerData"
>  * Add advertisement-api.txt to EXTRA_DIST
>  * Add Release() callback to org.bluez.LEAdvertisement1
>  * Remove IncludePower from the LEAdvertisement1 API
>
> v3 -> v4:
>  * Rename "g_dbus_proxy_set_read_watch" to "g_dbus_proxy_set_ready_watch"
>
> v4 -> v5:
>  * Rebase
>  * Use g_dbus_client_set_proxy_handlers instead of g_dbus_proxy_set_ready_watch
>  * Add MGMT interface calls to actually advertise.

Apparently you forgot to rename advertising-manager.c to
advertising.c, the former is awful long and I would also change to the
struct name to btd_advertising.

> Michael Janssen (13):
>   core: advertising: add LEAdvertisingManager stubs
>   core/advertising: Implement RegisterAdvertisement
>   tools: Python script to test Advertisement API
>   core/advertising: implement UnregisterAdvertisement
>   shared: add advertising-data
>   core/advertising: use advertising_data
>   core/advertising: Parse ServiceUUIDs
>   core/advertising: Parse SolicitUUIDs
>   core/advertising: Parse ManufacturerSpecificData
>   core/advertising: Parse ServiceData
>   Update TODO for LE Advertising
>   shared/advertising: implement advertising_data_generate
>   core/advertising: Add and Remove AD using MGMT
>
>  Makefile.am                   |   3 +
>  TODO                          |  21 +-
>  src/adapter.c                 |  19 ++
>  src/advertising.c             | 666 ++++++++++++++++++++++++++++++++++++++++++
>  src/advertising.h             |  25 ++
>  src/shared/advertising-data.c | 585 +++++++++++++++++++++++++++++++++++++
>  src/shared/advertising-data.h |  69 +++++
>  tools/advertisement-example   | 170 +++++++++++
>  8 files changed, 1548 insertions(+), 10 deletions(-)
>  create mode 100644 src/advertising.c
>  create mode 100644 src/advertising.h
>  create mode 100644 src/shared/advertising-data.c
>  create mode 100644 src/shared/advertising-data.h
>  create mode 100644 tools/advertisement-example
>
> --
> 2.2.0.rc0.207.ga3a616c
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html



-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2015-03-26 14:22 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-03-25 23:00 [BlueZ v5 00/13] Implement LE Advertisement D-Bus API Michael Janssen
2015-03-25 23:00 ` [BlueZ v5 01/13] core: advertising: add LEAdvertisingManager stubs Michael Janssen
2015-03-25 23:00 ` [BlueZ v5 02/13] core/advertising: Implement RegisterAdvertisement Michael Janssen
2015-03-25 23:00 ` [BlueZ v5 03/13] tools: Python script to test Advertisement API Michael Janssen
2015-03-25 23:00 ` [BlueZ v5 04/13] core/advertising: implement UnregisterAdvertisement Michael Janssen
2015-03-25 23:00 ` [BlueZ v5 05/13] shared: add advertising-data Michael Janssen
2015-03-25 23:00 ` [BlueZ v5 06/13] core/advertising: use advertising_data Michael Janssen
2015-03-25 23:00 ` [BlueZ v5 07/13] core/advertising: Parse ServiceUUIDs Michael Janssen
2015-03-25 23:00 ` [BlueZ v5 08/13] core/advertising: Parse SolicitUUIDs Michael Janssen
2015-03-25 23:00 ` [BlueZ v5 09/13] core/advertising: Parse ManufacturerSpecificData Michael Janssen
2015-03-25 23:00 ` [BlueZ v5 10/13] core/advertising: Parse ServiceData Michael Janssen
2015-03-25 23:00 ` [BlueZ v5 11/13] Update TODO for LE Advertising Michael Janssen
2015-03-25 23:01 ` [BlueZ v5 12/13] shared/advertising: implement advertising_data_generate Michael Janssen
2015-03-25 23:01 ` [BlueZ v5 13/13] core/advertising: Add and Remove AD using MGMT Michael Janssen
2015-03-26 14:22 ` [BlueZ v5 00/13] Implement LE Advertisement D-Bus API Luiz Augusto von Dentz

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.