All of lore.kernel.org
 help / color / mirror / Atom feed
* [BlueZ v3 00/15] Introduce LE Advertisement D-Bus API
@ 2015-03-19 17:34 Michael Janssen
  2015-03-19 17:34 ` [BlueZ v3 01/15] doc: Add LE Advertisement D-Bus API documentation Michael Janssen
                   ` (14 more replies)
  0 siblings, 15 replies; 20+ messages in thread
From: Michael Janssen @ 2015-03-19 17:34 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Michael Janssen

Introduces and starts implementation of a LE Advertisement API.

Things that are missing still (and added to the TODO):
 * MGMT API for modifying the LE Advertisements
 * 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

Michael Janssen (15):
  doc: Add LE Advertisement D-Bus API documentation
  core: advertising: add LEAdvertisingManager stubs
  gdbus/client: add g_dbus_proxy_set_read_watch
  unit/test-dbus-client: test for g_dbus_set_read_watch
  advertising-manager: Implement RegisterAdvertisement
  tools: Python script to test Advertisement API
  build: add advertising-api.txt to docs distributed
  advertising-manager: implement UnregisterAdvertisement
  shared: add advertising-data
  advertising-manager: use advertising_data
  advertising-manager: Parse ServiceUUIDs
  advertising-manager: Parse SolicitUUIDs
  advertising-manager: Parse ManufacturerSpecificData
  advertising-manager: Parse ServiceData
  Update TODO for LE Advertising

 Makefile.am                   |   5 +-
 TODO                          |  21 +-
 doc/advertising-api.txt       | 101 +++++++
 gdbus/client.c                |  17 ++
 gdbus/gdbus.h                 |   3 +
 src/adapter.c                 |  19 ++
 src/advertising-manager.c     | 614 ++++++++++++++++++++++++++++++++++++++++++
 src/advertising-manager.h     |  25 ++
 src/shared/advertising-data.c | 349 ++++++++++++++++++++++++
 src/shared/advertising-data.h |  69 +++++
 tools/advertisement-example   | 170 ++++++++++++
 unit/test-gdbus-client.c      |  66 +++++
 12 files changed, 1448 insertions(+), 11 deletions(-)
 create mode 100644 doc/advertising-api.txt
 create mode 100644 src/advertising-manager.c
 create mode 100644 src/advertising-manager.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] 20+ messages in thread

* [BlueZ v3 01/15] doc: Add LE Advertisement D-Bus API documentation
  2015-03-19 17:34 [BlueZ v3 00/15] Introduce LE Advertisement D-Bus API Michael Janssen
@ 2015-03-19 17:34 ` Michael Janssen
  2015-03-19 17:34 ` [BlueZ v3 02/15] core: advertising: add LEAdvertisingManager stubs Michael Janssen
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 20+ messages in thread
From: Michael Janssen @ 2015-03-19 17:34 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Michael Janssen

The LE Advertisement API allows external appications to define
persistent LE Advertisement Data packets.
---
 doc/advertising-api.txt | 101 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 101 insertions(+)
 create mode 100644 doc/advertising-api.txt

diff --git a/doc/advertising-api.txt b/doc/advertising-api.txt
new file mode 100644
index 0000000..7fb34ee
--- /dev/null
+++ b/doc/advertising-api.txt
@@ -0,0 +1,101 @@
+BlueZ D-Bus LE Advertising API Description
+******************************************
+
+Advertising packets are structured data which is broadcast on the LE Advertising
+channels and available for all devices in range.  Because of the limited space
+available in LE Advertising packets (32 bytes), each packet's contents must be
+carefully controlled.
+
+BlueZ acts as a store for the Advertisement Data which is meant to be sent.
+It constructs the correct Advertisement Data from the structured
+data and configured the kernel to send the correct advertisement.
+
+Advertisement Data objects are registered freely and then referenced by BlueZ
+when constructing the data sent to the kernel.
+
+LE Advertisement Data hierarchy
+===============================
+
+Specifies the Advertisement Data to be broadcast and some advertising
+parameters.  Properties which are not present will not be included in the
+data.  Required advertisement data types will always be included.
+All UUIDs are 128-bit versions in the API, and 16 or 32-bit
+versions of the same UUID will be used in the advertising data as appropriate.
+
+Service		org.bluez
+Interface	org.bluez.LEAdvertisement1
+Object path	freely definable
+
+Methods		void Release() [noreply]
+
+			This method gets called when the service daemon
+			removes the Advertisement. A client can use it to do
+			cleanup tasks. There is no need to call
+			UnregisterAdvertisement because when this method gets
+			called it has already been unregistered.
+
+Properties	string Type
+
+			Determines the type of advertising packet requested.
+
+			Possible values: "broadcast" or "peripheral"
+
+		array{string} ServiceUUIDs
+
+			List of UUIDs to include in the "Service UUID" field of
+			the Advertising Data.
+
+		dict ManufacturerData
+
+			Manufactuer Data fields to include in
+			the Advertising Data.  Keys are the Manufacturer ID
+			to associate with the data.
+
+		array{string} SolicitUUIDs
+
+			Array of UUIDs to include in "Service Solicitation"
+			Advertisement Data.
+
+		dict ServiceData
+
+			Service Data elements to include. The keys are the
+			UUID to associate with the data.
+
+
+LE Advertising Manager hierarchy
+================================
+
+The Advertising Manager allows external applications to register Advertisement
+Data which should be broadcast to devices.  Advertisement Data elements must
+follow the API for LE Advertisement Data described above.
+
+Service		org.bluez
+Interface	org.bluez.LEAdvertisingManager1 [Experimental]
+Object path	/org/bluez/{hci0,hci1,...}
+
+Methods		RegisterAdvertisement(object advertisement, dict options)
+
+			Registers an advertisement object to be sent over the LE
+			Advertising channel.  The service must be exported
+			under interface LEAdvertisement1. InvalidArguments
+			indicates that the object has invalid or conflicting
+			properties.  InvalidLength indicates that the data
+			provided generates a data packet which is too long.
+			The properties of this object are parser when it is
+			registered, and any changes are ignored.
+			Currently only one advertisement at a time is supported,
+			attempting to register two advertisements will result in
+			an AlreadyExists error.
+
+			Possible errors: org.bluez.Error.InvalidArguments
+					 org.bluez.Error.AlreadyExists
+					 org.bluez.Error.InvalidLength
+
+		UnregisterAdvertisement(object advertisement)
+
+			This unregisters an advertisement that has been
+			prevously registered.  The object path parameter must
+			match the same value that has been used on registration.
+
+			Possible errors: org.bluez.Error.InvalidArguments
+					 org.bluez.Error.DoesNotExist
-- 
2.2.0.rc0.207.ga3a616c


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

* [BlueZ v3 02/15] core: advertising: add LEAdvertisingManager stubs
  2015-03-19 17:34 [BlueZ v3 00/15] Introduce LE Advertisement D-Bus API Michael Janssen
  2015-03-19 17:34 ` [BlueZ v3 01/15] doc: Add LE Advertisement D-Bus API documentation Michael Janssen
@ 2015-03-19 17:34 ` Michael Janssen
  2015-03-19 17:34 ` [BlueZ v3 03/15] gdbus/client: add g_dbus_proxy_set_read_watch Michael Janssen
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 20+ messages in thread
From: Michael Janssen @ 2015-03-19 17:34 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 90bb86b..1ddf3f2 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] 20+ messages in thread

* [BlueZ v3 03/15] gdbus/client: add g_dbus_proxy_set_read_watch
  2015-03-19 17:34 [BlueZ v3 00/15] Introduce LE Advertisement D-Bus API Michael Janssen
  2015-03-19 17:34 ` [BlueZ v3 01/15] doc: Add LE Advertisement D-Bus API documentation Michael Janssen
  2015-03-19 17:34 ` [BlueZ v3 02/15] core: advertising: add LEAdvertisingManager stubs Michael Janssen
@ 2015-03-19 17:34 ` Michael Janssen
  2015-03-20 13:57   ` Luiz Augusto von Dentz
  2015-03-19 17:34 ` [BlueZ v3 04/15] unit/test-dbus-client: test for g_dbus_set_read_watch Michael Janssen
                   ` (11 subsequent siblings)
  14 siblings, 1 reply; 20+ messages in thread
From: Michael Janssen @ 2015-03-19 17:34 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Michael Janssen

Adds a new gdbus utility function which will set a function to be called
after the properties of a proxy are updated.

This enables using GDBusClient for objects without the ObjectManager
interface as long as you know in advance the object path using
g_dbus_proxy_new
---
 gdbus/client.c | 17 +++++++++++++++++
 gdbus/gdbus.h  |  3 +++
 2 files changed, 20 insertions(+)

diff --git a/gdbus/client.c b/gdbus/client.c
index fe0c0db..c913773 100644
--- a/gdbus/client.c
+++ b/gdbus/client.c
@@ -76,6 +76,8 @@ struct GDBusProxy {
 	void *prop_data;
 	GDBusProxyFunction removed_func;
 	void *removed_data;
+	GDBusProxyFunction read_func;
+	void *read_data;
 };
 
 struct prop_entry {
@@ -297,6 +299,9 @@ static void get_all_properties_reply(DBusPendingCall *call, void *user_data)
 
 	update_properties(proxy, &iter, FALSE);
 
+	if (proxy->read_func)
+		proxy->read_func(proxy, proxy->read_data);
+
 done:
 	if (g_list_find(client->proxy_list, proxy) == NULL) {
 		if (client->proxy_added)
@@ -914,6 +919,18 @@ gboolean g_dbus_proxy_set_removed_watch(GDBusProxy *proxy,
 	return TRUE;
 }
 
+gboolean g_dbus_proxy_set_read_watch(GDBusProxy *proxy,
+				GDBusProxyFunction function, void *user_data)
+{
+	if (proxy == NULL)
+		return FALSE;
+
+	proxy->read_func = function;
+	proxy->read_data = user_data;
+
+	return TRUE;
+}
+
 static void refresh_properties(GDBusClient *client)
 {
 	GList *list;
diff --git a/gdbus/gdbus.h b/gdbus/gdbus.h
index 9814838..ae281d9 100644
--- a/gdbus/gdbus.h
+++ b/gdbus/gdbus.h
@@ -353,6 +353,9 @@ gboolean g_dbus_proxy_set_property_watch(GDBusProxy *proxy,
 gboolean g_dbus_proxy_set_removed_watch(GDBusProxy *proxy,
 			GDBusProxyFunction destroy, void *user_data);
 
+gboolean g_dbus_proxy_set_read_watch(GDBusProxy *proxy,
+			GDBusProxyFunction ready, void *user_data);
+
 GDBusClient *g_dbus_client_new(DBusConnection *connection,
 					const char *service, const char *path);
 GDBusClient *g_dbus_client_new_full(DBusConnection *connection,
-- 
2.2.0.rc0.207.ga3a616c


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

* [BlueZ v3 04/15] unit/test-dbus-client: test for g_dbus_set_read_watch
  2015-03-19 17:34 [BlueZ v3 00/15] Introduce LE Advertisement D-Bus API Michael Janssen
                   ` (2 preceding siblings ...)
  2015-03-19 17:34 ` [BlueZ v3 03/15] gdbus/client: add g_dbus_proxy_set_read_watch Michael Janssen
@ 2015-03-19 17:34 ` Michael Janssen
  2015-03-19 17:34 ` [BlueZ v3 05/15] advertising-manager: Implement RegisterAdvertisement Michael Janssen
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 20+ messages in thread
From: Michael Janssen @ 2015-03-19 17:34 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Michael Janssen

Adds a test for the functionality of g_dbus_set_read_watch.
---
 unit/test-gdbus-client.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 66 insertions(+)

diff --git a/unit/test-gdbus-client.c b/unit/test-gdbus-client.c
index 11ad1f7..d9f4d5c 100644
--- a/unit/test-gdbus-client.c
+++ b/unit/test-gdbus-client.c
@@ -908,6 +908,70 @@ static void client_proxy_removed(void)
 	destroy_context(context);
 }
 
+static void proxy_ready(GDBusProxy *proxy, void *user_data)
+{
+	struct context *context = user_data;
+	DBusMessageIter iter;
+	const char *string;
+
+	if (g_test_verbose())
+		g_print("proxy for %s ready\n",
+					g_dbus_proxy_get_interface(proxy));
+
+	g_assert(context->proxy == proxy);
+
+	g_assert(g_dbus_proxy_get_property(proxy, "String", &iter));
+
+	dbus_message_iter_get_basic(&iter, &string);
+	g_assert(g_strcmp0(string, "value1") == 0);
+
+	g_main_loop_quit(context->main_loop);
+}
+
+static void client_proxy_read(void)
+{
+	struct context *context = create_context();
+	DBusConnection *conn;
+	DBusMessageIter iter;
+	static const GDBusPropertyTable string_properties[] = {
+		{ "String", "s", get_string, set_string, string_exists },
+		{ },
+	};
+
+	if (context == NULL)
+		return;
+
+	conn = g_dbus_setup_private(DBUS_BUS_SESSION, SERVICE_NAME1, NULL);
+	g_assert(conn != NULL);
+
+	context->data = g_strdup("value1");
+
+	g_dbus_register_interface(conn,
+				SERVICE_PATH, SERVICE_NAME1,
+				methods, signals, string_properties,
+				context, NULL);
+
+	context->dbus_client = g_dbus_client_new(context->dbus_conn,
+						SERVICE_NAME1, SERVICE_PATH);
+
+	context->proxy = g_dbus_proxy_new(context->dbus_client, SERVICE_PATH,
+								SERVICE_NAME1);
+
+	g_dbus_proxy_set_read_watch(context->proxy, proxy_ready, context);
+
+	g_assert(!g_dbus_proxy_get_property(context->proxy, "String", &iter));
+
+	g_main_loop_run(context->main_loop);
+
+	g_dbus_unregister_interface(conn, SERVICE_PATH, SERVICE_NAME1);
+
+	dbus_connection_flush(conn);
+	dbus_connection_close(conn);
+	dbus_connection_unref(conn);
+
+	destroy_context(context);
+}
+
 static void proxy_force_disconnect(GDBusProxy *proxy, void *user_data)
 {
 	struct context *context = user_data;
@@ -1051,6 +1115,8 @@ int main(int argc, char *argv[])
 
 	g_test_add_func("/gdbus/client_proxy_removed", client_proxy_removed);
 
+	g_test_add_func("/gdbus/client_proxy_read", client_proxy_read);
+
 	g_test_add_func("/gdbus/client_force_disconnect",
 						client_force_disconnect);
 
-- 
2.2.0.rc0.207.ga3a616c


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

* [BlueZ v3 05/15] advertising-manager: Implement RegisterAdvertisement
  2015-03-19 17:34 [BlueZ v3 00/15] Introduce LE Advertisement D-Bus API Michael Janssen
                   ` (3 preceding siblings ...)
  2015-03-19 17:34 ` [BlueZ v3 04/15] unit/test-dbus-client: test for g_dbus_set_read_watch Michael Janssen
@ 2015-03-19 17:34 ` Michael Janssen
  2015-03-19 17:34 ` [BlueZ v3 06/15] tools: Python script to test Advertisement API Michael Janssen
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 20+ messages in thread
From: Michael Janssen @ 2015-03-19 17:34 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Michael Janssen

Initial implementation of the RegisterAdvertisement function of the
LEAdvertisingManager1 interface.
---
 src/advertising-manager.c | 255 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 254 insertions(+), 1 deletion(-)

diff --git a/src/advertising-manager.c b/src/advertising-manager.c
index c3f85c2..43d3826 100644
--- a/src/advertising-manager.c
+++ b/src/advertising-manager.c
@@ -30,7 +30,9 @@
 
 #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"
@@ -38,15 +40,262 @@
 
 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_ready(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_proxy_set_read_watch(ad->proxy, advertisement_proxy_ready, 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");
 
-	/* TODO */
+	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;
 }
 
@@ -76,6 +325,8 @@ static void advertising_manager_destroy(void *user_data)
 {
 	struct btd_advertising_manager *manager = user_data;
 
+	queue_destroy(manager->adverts, advertisement_destroy);
+
 	free(manager);
 }
 
@@ -100,6 +351,8 @@ advertising_manager_create(struct btd_adapter *adapter)
 		return NULL;
 	}
 
+	manager->adverts = queue_new();
+
 	return manager;
 }
 
-- 
2.2.0.rc0.207.ga3a616c


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

* [BlueZ v3 06/15] tools: Python script to test Advertisement API
  2015-03-19 17:34 [BlueZ v3 00/15] Introduce LE Advertisement D-Bus API Michael Janssen
                   ` (4 preceding siblings ...)
  2015-03-19 17:34 ` [BlueZ v3 05/15] advertising-manager: Implement RegisterAdvertisement Michael Janssen
@ 2015-03-19 17:34 ` Michael Janssen
  2015-03-19 17:34 ` [BlueZ v3 07/15] build: add advertising-api.txt to docs distributed Michael Janssen
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 20+ messages in thread
From: Michael Janssen @ 2015-03-19 17:34 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] 20+ messages in thread

* [BlueZ v3 07/15] build: add advertising-api.txt to docs distributed
  2015-03-19 17:34 [BlueZ v3 00/15] Introduce LE Advertisement D-Bus API Michael Janssen
                   ` (5 preceding siblings ...)
  2015-03-19 17:34 ` [BlueZ v3 06/15] tools: Python script to test Advertisement API Michael Janssen
@ 2015-03-19 17:34 ` Michael Janssen
  2015-03-19 17:34 ` [BlueZ v3 08/15] advertising-manager: implement UnregisterAdvertisement Michael Janssen
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 20+ messages in thread
From: Michael Janssen @ 2015-03-19 17:34 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Michael Janssen

Add doc/advertising-api.txt to the docs.
---
 Makefile.am | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Makefile.am b/Makefile.am
index 1ddf3f2..db2978e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -250,7 +250,7 @@ EXTRA_DIST += doc/mgmt-api.txt \
 EXTRA_DIST += doc/alert-api.txt \
 		doc/proximity-api.txt doc/heartrate-api.txt \
 		doc/thermometer-api.txt doc/cyclingspeed-api.txt \
-		doc/gatt-api.txt
+		doc/gatt-api.txt doc/advertising-api.txt
 
 EXTRA_DIST += doc/obex-api.txt doc/obex-agent-api.txt
 
-- 
2.2.0.rc0.207.ga3a616c


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

* [BlueZ v3 08/15] advertising-manager: implement UnregisterAdvertisement
  2015-03-19 17:34 [BlueZ v3 00/15] Introduce LE Advertisement D-Bus API Michael Janssen
                   ` (6 preceding siblings ...)
  2015-03-19 17:34 ` [BlueZ v3 07/15] build: add advertising-api.txt to docs distributed Michael Janssen
@ 2015-03-19 17:34 ` Michael Janssen
  2015-03-19 17:34 ` [BlueZ v3 09/15] shared: add advertising-data Michael Janssen
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 20+ messages in thread
From: Michael Janssen @ 2015-03-19 17:34 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Michael Janssen

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

diff --git a/src/advertising-manager.c b/src/advertising-manager.c
index 43d3826..f6d9f0e 100644
--- a/src/advertising-manager.c
+++ b/src/advertising-manager.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);
@@ -303,10 +305,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] 20+ messages in thread

* [BlueZ v3 09/15] shared: add advertising-data
  2015-03-19 17:34 [BlueZ v3 00/15] Introduce LE Advertisement D-Bus API Michael Janssen
                   ` (7 preceding siblings ...)
  2015-03-19 17:34 ` [BlueZ v3 08/15] advertising-manager: implement UnregisterAdvertisement Michael Janssen
@ 2015-03-19 17:34 ` Michael Janssen
  2015-03-19 17:34 ` [BlueZ v3 10/15] advertising-manager: use advertising_data Michael Janssen
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 20+ messages in thread
From: Michael Janssen @ 2015-03-19 17:34 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 db2978e..7334b1a 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] 20+ messages in thread

* [BlueZ v3 10/15] advertising-manager: use advertising_data
  2015-03-19 17:34 [BlueZ v3 00/15] Introduce LE Advertisement D-Bus API Michael Janssen
                   ` (8 preceding siblings ...)
  2015-03-19 17:34 ` [BlueZ v3 09/15] shared: add advertising-data Michael Janssen
@ 2015-03-19 17:34 ` Michael Janssen
  2015-03-19 17:34 ` [BlueZ v3 11/15] advertising-manager: Parse ServiceUUIDs Michael Janssen
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 20+ messages in thread
From: Michael Janssen @ 2015-03-19 17:34 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Michael Janssen

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

diff --git a/src/advertising-manager.c b/src/advertising-manager.c
index f6d9f0e..e0259e4 100644
--- a/src/advertising-manager.c
+++ b/src/advertising-manager.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);
@@ -250,6 +253,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] 20+ messages in thread

* [BlueZ v3 11/15] advertising-manager: Parse ServiceUUIDs
  2015-03-19 17:34 [BlueZ v3 00/15] Introduce LE Advertisement D-Bus API Michael Janssen
                   ` (9 preceding siblings ...)
  2015-03-19 17:34 ` [BlueZ v3 10/15] advertising-manager: use advertising_data Michael Janssen
@ 2015-03-19 17:34 ` Michael Janssen
  2015-03-19 17:34 ` [BlueZ v3 12/15] advertising-manager: Parse SolicitUUIDs Michael Janssen
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 20+ messages in thread
From: Michael Janssen @ 2015-03-19 17:34 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Michael Janssen

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

diff --git a/src/advertising-manager.c b/src/advertising-manager.c
index e0259e4..18d0bf3 100644
--- a/src/advertising-manager.c
+++ b/src/advertising-manager.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] 20+ messages in thread

* [BlueZ v3 12/15] advertising-manager: Parse SolicitUUIDs
  2015-03-19 17:34 [BlueZ v3 00/15] Introduce LE Advertisement D-Bus API Michael Janssen
                   ` (10 preceding siblings ...)
  2015-03-19 17:34 ` [BlueZ v3 11/15] advertising-manager: Parse ServiceUUIDs Michael Janssen
@ 2015-03-19 17:34 ` Michael Janssen
  2015-03-19 17:34 ` [BlueZ v3 13/15] advertising-manager: Parse ManufacturerSpecificData Michael Janssen
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 20+ messages in thread
From: Michael Janssen @ 2015-03-19 17:34 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Michael Janssen

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

diff --git a/src/advertising-manager.c b/src/advertising-manager.c
index 18d0bf3..efd05ba 100644
--- a/src/advertising-manager.c
+++ b/src/advertising-manager.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] 20+ messages in thread

* [BlueZ v3 13/15] advertising-manager: Parse ManufacturerSpecificData
  2015-03-19 17:34 [BlueZ v3 00/15] Introduce LE Advertisement D-Bus API Michael Janssen
                   ` (11 preceding siblings ...)
  2015-03-19 17:34 ` [BlueZ v3 12/15] advertising-manager: Parse SolicitUUIDs Michael Janssen
@ 2015-03-19 17:34 ` Michael Janssen
  2015-03-19 17:34 ` [BlueZ v3 14/15] advertising-manager: Parse ServiceData Michael Janssen
  2015-03-19 17:34 ` [BlueZ v3 15/15] Update TODO for LE Advertising Michael Janssen
  14 siblings, 0 replies; 20+ messages in thread
From: Michael Janssen @ 2015-03-19 17:34 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Michael Janssen

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

diff --git a/src/advertising-manager.c b/src/advertising-manager.c
index efd05ba..432cdad 100644
--- a/src/advertising-manager.c
+++ b/src/advertising-manager.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] 20+ messages in thread

* [BlueZ v3 14/15] advertising-manager: Parse ServiceData
  2015-03-19 17:34 [BlueZ v3 00/15] Introduce LE Advertisement D-Bus API Michael Janssen
                   ` (12 preceding siblings ...)
  2015-03-19 17:34 ` [BlueZ v3 13/15] advertising-manager: Parse ManufacturerSpecificData Michael Janssen
@ 2015-03-19 17:34 ` Michael Janssen
  2015-03-19 17:34 ` [BlueZ v3 15/15] Update TODO for LE Advertising Michael Janssen
  14 siblings, 0 replies; 20+ messages in thread
From: Michael Janssen @ 2015-03-19 17:34 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Michael Janssen

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

diff --git a/src/advertising-manager.c b/src/advertising-manager.c
index 432cdad..06c5df3 100644
--- a/src/advertising-manager.c
+++ b/src/advertising-manager.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] 20+ messages in thread

* [BlueZ v3 15/15] Update TODO for LE Advertising
  2015-03-19 17:34 [BlueZ v3 00/15] Introduce LE Advertisement D-Bus API Michael Janssen
                   ` (13 preceding siblings ...)
  2015-03-19 17:34 ` [BlueZ v3 14/15] advertising-manager: Parse ServiceData Michael Janssen
@ 2015-03-19 17:34 ` Michael Janssen
  14 siblings, 0 replies; 20+ messages in thread
From: Michael Janssen @ 2015-03-19 17:34 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] 20+ messages in thread

* Re: [BlueZ v3 03/15] gdbus/client: add g_dbus_proxy_set_read_watch
  2015-03-19 17:34 ` [BlueZ v3 03/15] gdbus/client: add g_dbus_proxy_set_read_watch Michael Janssen
@ 2015-03-20 13:57   ` Luiz Augusto von Dentz
  2015-03-20 14:55     ` Michael Janssen
  0 siblings, 1 reply; 20+ messages in thread
From: Luiz Augusto von Dentz @ 2015-03-20 13:57 UTC (permalink / raw)
  To: Michael Janssen; +Cc: linux-bluetooth

Hi Michael,

On Thu, Mar 19, 2015 at 7:34 PM, Michael Janssen <jamuraa@chromium.org> wrote:
> Adds a new gdbus utility function which will set a function to be called
> after the properties of a proxy are updated.
>
> This enables using GDBusClient for objects without the ObjectManager
> interface as long as you know in advance the object path using
> g_dbus_proxy_new
> ---
>  gdbus/client.c | 17 +++++++++++++++++
>  gdbus/gdbus.h  |  3 +++
>  2 files changed, 20 insertions(+)
>
> diff --git a/gdbus/client.c b/gdbus/client.c
> index fe0c0db..c913773 100644
> --- a/gdbus/client.c
> +++ b/gdbus/client.c
> @@ -76,6 +76,8 @@ struct GDBusProxy {
>         void *prop_data;
>         GDBusProxyFunction removed_func;
>         void *removed_data;
> +       GDBusProxyFunction read_func;
> +       void *read_data;
>  };
>
>  struct prop_entry {
> @@ -297,6 +299,9 @@ static void get_all_properties_reply(DBusPendingCall *call, void *user_data)
>
>         update_properties(proxy, &iter, FALSE);
>
> +       if (proxy->read_func)
> +               proxy->read_func(proxy, proxy->read_data);
> +
>  done:
>         if (g_list_find(client->proxy_list, proxy) == NULL) {
>                 if (client->proxy_added)
> @@ -914,6 +919,18 @@ gboolean g_dbus_proxy_set_removed_watch(GDBusProxy *proxy,
>         return TRUE;
>  }
>
> +gboolean g_dbus_proxy_set_read_watch(GDBusProxy *proxy,
> +                               GDBusProxyFunction function, void *user_data)
> +{
> +       if (proxy == NULL)
> +               return FALSE;
> +
> +       proxy->read_func = function;
> +       proxy->read_data = user_data;
> +
> +       return TRUE;
> +}
> +
>  static void refresh_properties(GDBusClient *client)
>  {
>         GList *list;
> diff --git a/gdbus/gdbus.h b/gdbus/gdbus.h
> index 9814838..ae281d9 100644
> --- a/gdbus/gdbus.h
> +++ b/gdbus/gdbus.h
> @@ -353,6 +353,9 @@ gboolean g_dbus_proxy_set_property_watch(GDBusProxy *proxy,
>  gboolean g_dbus_proxy_set_removed_watch(GDBusProxy *proxy,
>                         GDBusProxyFunction destroy, void *user_data);
>
> +gboolean g_dbus_proxy_set_read_watch(GDBusProxy *proxy,
> +                       GDBusProxyFunction ready, void *user_data);

Is this supposed to be ready or read watch, Id say this is a ready
watch? Also you should name the callback consistently in one place you
call it ready and in the other function, I would go with the later.

Btw, it looks like this would still trigger proxy added callback so I
wonder why you did not use it instead of creating a new callback?

>  GDBusClient *g_dbus_client_new(DBusConnection *connection,
>                                         const char *service, const char *path);
>  GDBusClient *g_dbus_client_new_full(DBusConnection *connection,
> --
> 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] 20+ messages in thread

* Re: [BlueZ v3 03/15] gdbus/client: add g_dbus_proxy_set_read_watch
  2015-03-20 13:57   ` Luiz Augusto von Dentz
@ 2015-03-20 14:55     ` Michael Janssen
  2015-03-20 15:39       ` Marcel Holtmann
  0 siblings, 1 reply; 20+ messages in thread
From: Michael Janssen @ 2015-03-20 14:55 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth

Hi Luiz,

On Fri, Mar 20, 2015 at 6:57 AM, Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
> Hi Michael,
>
> On Thu, Mar 19, 2015 at 7:34 PM, Michael Janssen <jamuraa@chromium.org> wrote:
>> Adds a new gdbus utility function which will set a function to be called
>> after the properties of a proxy are updated.
>>
>> This enables using GDBusClient for objects without the ObjectManager
>> interface as long as you know in advance the object path using
>> g_dbus_proxy_new
>> ---
>>  gdbus/client.c | 17 +++++++++++++++++
>>  gdbus/gdbus.h  |  3 +++
>>  2 files changed, 20 insertions(+)
>>
>> diff --git a/gdbus/client.c b/gdbus/client.c
>> index fe0c0db..c913773 100644
>> --- a/gdbus/client.c
>> +++ b/gdbus/client.c
>> @@ -76,6 +76,8 @@ struct GDBusProxy {
>>         void *prop_data;
>>         GDBusProxyFunction removed_func;
>>         void *removed_data;
>> +       GDBusProxyFunction read_func;
>> +       void *read_data;
>>  };
>>
>>  struct prop_entry {
>> @@ -297,6 +299,9 @@ static void get_all_properties_reply(DBusPendingCall *call, void *user_data)
>>
>>         update_properties(proxy, &iter, FALSE);
>>
>> +       if (proxy->read_func)
>> +               proxy->read_func(proxy, proxy->read_data);
>> +
>>  done:
>>         if (g_list_find(client->proxy_list, proxy) == NULL) {
>>                 if (client->proxy_added)
>> @@ -914,6 +919,18 @@ gboolean g_dbus_proxy_set_removed_watch(GDBusProxy *proxy,
>>         return TRUE;
>>  }
>>
>> +gboolean g_dbus_proxy_set_read_watch(GDBusProxy *proxy,
>> +                               GDBusProxyFunction function, void *user_data)
>> +{
>> +       if (proxy == NULL)
>> +               return FALSE;
>> +
>> +       proxy->read_func = function;
>> +       proxy->read_data = user_data;
>> +
>> +       return TRUE;
>> +}
>> +
>>  static void refresh_properties(GDBusClient *client)
>>  {
>>         GList *list;
>> diff --git a/gdbus/gdbus.h b/gdbus/gdbus.h
>> index 9814838..ae281d9 100644
>> --- a/gdbus/gdbus.h
>> +++ b/gdbus/gdbus.h
>> @@ -353,6 +353,9 @@ gboolean g_dbus_proxy_set_property_watch(GDBusProxy *proxy,
>>  gboolean g_dbus_proxy_set_removed_watch(GDBusProxy *proxy,
>>                         GDBusProxyFunction destroy, void *user_data);
>>
>> +gboolean g_dbus_proxy_set_read_watch(GDBusProxy *proxy,
>> +                       GDBusProxyFunction ready, void *user_data);
>
> Is this supposed to be ready or read watch, Id say this is a ready
> watch? Also you should name the callback consistently in one place you
> call it ready and in the other function, I would go with the later.
>
> Btw, it looks like this would still trigger proxy added callback so I
> wonder why you did not use it instead of creating a new callback?

It is called a read watch because it will be called whenever the
properties are all updated on the proxy.  I would expect a ready watch
to remove itself after it is done.

The proxy added callback requires the use of the ObjectManager
interface, which this method avoids, as mentioned in the commit
message.

Michael Janssen

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

* Re: [BlueZ v3 03/15] gdbus/client: add g_dbus_proxy_set_read_watch
  2015-03-20 14:55     ` Michael Janssen
@ 2015-03-20 15:39       ` Marcel Holtmann
  2015-03-20 15:44         ` Luiz Augusto von Dentz
  0 siblings, 1 reply; 20+ messages in thread
From: Marcel Holtmann @ 2015-03-20 15:39 UTC (permalink / raw)
  To: Michael Janssen; +Cc: Luiz Augusto von Dentz, linux-bluetooth

Hi Michael,

>>> Adds a new gdbus utility function which will set a function to be called
>>> after the properties of a proxy are updated.
>>> 
>>> This enables using GDBusClient for objects without the ObjectManager
>>> interface as long as you know in advance the object path using
>>> g_dbus_proxy_new
>>> ---
>>> gdbus/client.c | 17 +++++++++++++++++
>>> gdbus/gdbus.h  |  3 +++
>>> 2 files changed, 20 insertions(+)
>>> 
>>> diff --git a/gdbus/client.c b/gdbus/client.c
>>> index fe0c0db..c913773 100644
>>> --- a/gdbus/client.c
>>> +++ b/gdbus/client.c
>>> @@ -76,6 +76,8 @@ struct GDBusProxy {
>>>        void *prop_data;
>>>        GDBusProxyFunction removed_func;
>>>        void *removed_data;
>>> +       GDBusProxyFunction read_func;
>>> +       void *read_data;
>>> };
>>> 
>>> struct prop_entry {
>>> @@ -297,6 +299,9 @@ static void get_all_properties_reply(DBusPendingCall *call, void *user_data)
>>> 
>>>        update_properties(proxy, &iter, FALSE);
>>> 
>>> +       if (proxy->read_func)
>>> +               proxy->read_func(proxy, proxy->read_data);
>>> +
>>> done:
>>>        if (g_list_find(client->proxy_list, proxy) == NULL) {
>>>                if (client->proxy_added)
>>> @@ -914,6 +919,18 @@ gboolean g_dbus_proxy_set_removed_watch(GDBusProxy *proxy,
>>>        return TRUE;
>>> }
>>> 
>>> +gboolean g_dbus_proxy_set_read_watch(GDBusProxy *proxy,
>>> +                               GDBusProxyFunction function, void *user_data)
>>> +{
>>> +       if (proxy == NULL)
>>> +               return FALSE;
>>> +
>>> +       proxy->read_func = function;
>>> +       proxy->read_data = user_data;
>>> +
>>> +       return TRUE;
>>> +}
>>> +
>>> static void refresh_properties(GDBusClient *client)
>>> {
>>>        GList *list;
>>> diff --git a/gdbus/gdbus.h b/gdbus/gdbus.h
>>> index 9814838..ae281d9 100644
>>> --- a/gdbus/gdbus.h
>>> +++ b/gdbus/gdbus.h
>>> @@ -353,6 +353,9 @@ gboolean g_dbus_proxy_set_property_watch(GDBusProxy *proxy,
>>> gboolean g_dbus_proxy_set_removed_watch(GDBusProxy *proxy,
>>>                        GDBusProxyFunction destroy, void *user_data);
>>> 
>>> +gboolean g_dbus_proxy_set_read_watch(GDBusProxy *proxy,
>>> +                       GDBusProxyFunction ready, void *user_data);
>> 
>> Is this supposed to be ready or read watch, Id say this is a ready
>> watch? Also you should name the callback consistently in one place you
>> call it ready and in the other function, I would go with the later.
>> 
>> Btw, it looks like this would still trigger proxy added callback so I
>> wonder why you did not use it instead of creating a new callback?
> 
> It is called a read watch because it will be called whenever the
> properties are all updated on the proxy.  I would expect a ready watch
> to remove itself after it is done.

we use the term "ready" before and never "read". So I would rename this. If the caller wants to remove the watch afterwards that is fine, but that is irrelevant.

Regards

Marcel


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

* Re: [BlueZ v3 03/15] gdbus/client: add g_dbus_proxy_set_read_watch
  2015-03-20 15:39       ` Marcel Holtmann
@ 2015-03-20 15:44         ` Luiz Augusto von Dentz
  0 siblings, 0 replies; 20+ messages in thread
From: Luiz Augusto von Dentz @ 2015-03-20 15:44 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: Michael Janssen, linux-bluetooth

Hi Marcel, Michael,

On Fri, Mar 20, 2015 at 5:39 PM, Marcel Holtmann <marcel@holtmann.org> wrote:
> Hi Michael,
>
>>>> Adds a new gdbus utility function which will set a function to be called
>>>> after the properties of a proxy are updated.
>>>>
>>>> This enables using GDBusClient for objects without the ObjectManager
>>>> interface as long as you know in advance the object path using
>>>> g_dbus_proxy_new
>>>> ---
>>>> gdbus/client.c | 17 +++++++++++++++++
>>>> gdbus/gdbus.h  |  3 +++
>>>> 2 files changed, 20 insertions(+)
>>>>
>>>> diff --git a/gdbus/client.c b/gdbus/client.c
>>>> index fe0c0db..c913773 100644
>>>> --- a/gdbus/client.c
>>>> +++ b/gdbus/client.c
>>>> @@ -76,6 +76,8 @@ struct GDBusProxy {
>>>>        void *prop_data;
>>>>        GDBusProxyFunction removed_func;
>>>>        void *removed_data;
>>>> +       GDBusProxyFunction read_func;
>>>> +       void *read_data;
>>>> };
>>>>
>>>> struct prop_entry {
>>>> @@ -297,6 +299,9 @@ static void get_all_properties_reply(DBusPendingCall *call, void *user_data)
>>>>
>>>>        update_properties(proxy, &iter, FALSE);
>>>>
>>>> +       if (proxy->read_func)
>>>> +               proxy->read_func(proxy, proxy->read_data);
>>>> +
>>>> done:
>>>>        if (g_list_find(client->proxy_list, proxy) == NULL) {
>>>>                if (client->proxy_added)
>>>> @@ -914,6 +919,18 @@ gboolean g_dbus_proxy_set_removed_watch(GDBusProxy *proxy,
>>>>        return TRUE;
>>>> }
>>>>
>>>> +gboolean g_dbus_proxy_set_read_watch(GDBusProxy *proxy,
>>>> +                               GDBusProxyFunction function, void *user_data)
>>>> +{
>>>> +       if (proxy == NULL)
>>>> +               return FALSE;
>>>> +
>>>> +       proxy->read_func = function;
>>>> +       proxy->read_data = user_data;
>>>> +
>>>> +       return TRUE;
>>>> +}
>>>> +
>>>> static void refresh_properties(GDBusClient *client)
>>>> {
>>>>        GList *list;
>>>> diff --git a/gdbus/gdbus.h b/gdbus/gdbus.h
>>>> index 9814838..ae281d9 100644
>>>> --- a/gdbus/gdbus.h
>>>> +++ b/gdbus/gdbus.h
>>>> @@ -353,6 +353,9 @@ gboolean g_dbus_proxy_set_property_watch(GDBusProxy *proxy,
>>>> gboolean g_dbus_proxy_set_removed_watch(GDBusProxy *proxy,
>>>>                        GDBusProxyFunction destroy, void *user_data);
>>>>
>>>> +gboolean g_dbus_proxy_set_read_watch(GDBusProxy *proxy,
>>>> +                       GDBusProxyFunction ready, void *user_data);
>>>
>>> Is this supposed to be ready or read watch, Id say this is a ready
>>> watch? Also you should name the callback consistently in one place you
>>> call it ready and in the other function, I would go with the later.
>>>
>>> Btw, it looks like this would still trigger proxy added callback so I
>>> wonder why you did not use it instead of creating a new callback?
>>
>> It is called a read watch because it will be called whenever the
>> properties are all updated on the proxy.  I would expect a ready watch
>> to remove itself after it is done.
>
> we use the term "ready" before and never "read". So I would rename this. If the caller wants to remove the watch afterwards that is fine, but that is irrelevant.

Yep, I would prefer to use ready, but as I commented before this
perhaps is not necessary because even if the user create the proxy
without the use of ObjectManager we still notify via proxy_added in
get_all_properties_reply so I wonder if it is really necessary to have
another callback?


-- 
Luiz Augusto von Dentz

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

end of thread, other threads:[~2015-03-20 15:44 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-03-19 17:34 [BlueZ v3 00/15] Introduce LE Advertisement D-Bus API Michael Janssen
2015-03-19 17:34 ` [BlueZ v3 01/15] doc: Add LE Advertisement D-Bus API documentation Michael Janssen
2015-03-19 17:34 ` [BlueZ v3 02/15] core: advertising: add LEAdvertisingManager stubs Michael Janssen
2015-03-19 17:34 ` [BlueZ v3 03/15] gdbus/client: add g_dbus_proxy_set_read_watch Michael Janssen
2015-03-20 13:57   ` Luiz Augusto von Dentz
2015-03-20 14:55     ` Michael Janssen
2015-03-20 15:39       ` Marcel Holtmann
2015-03-20 15:44         ` Luiz Augusto von Dentz
2015-03-19 17:34 ` [BlueZ v3 04/15] unit/test-dbus-client: test for g_dbus_set_read_watch Michael Janssen
2015-03-19 17:34 ` [BlueZ v3 05/15] advertising-manager: Implement RegisterAdvertisement Michael Janssen
2015-03-19 17:34 ` [BlueZ v3 06/15] tools: Python script to test Advertisement API Michael Janssen
2015-03-19 17:34 ` [BlueZ v3 07/15] build: add advertising-api.txt to docs distributed Michael Janssen
2015-03-19 17:34 ` [BlueZ v3 08/15] advertising-manager: implement UnregisterAdvertisement Michael Janssen
2015-03-19 17:34 ` [BlueZ v3 09/15] shared: add advertising-data Michael Janssen
2015-03-19 17:34 ` [BlueZ v3 10/15] advertising-manager: use advertising_data Michael Janssen
2015-03-19 17:34 ` [BlueZ v3 11/15] advertising-manager: Parse ServiceUUIDs Michael Janssen
2015-03-19 17:34 ` [BlueZ v3 12/15] advertising-manager: Parse SolicitUUIDs Michael Janssen
2015-03-19 17:34 ` [BlueZ v3 13/15] advertising-manager: Parse ManufacturerSpecificData Michael Janssen
2015-03-19 17:34 ` [BlueZ v3 14/15] advertising-manager: Parse ServiceData Michael Janssen
2015-03-19 17:34 ` [BlueZ v3 15/15] Update TODO for LE Advertising Michael Janssen

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.