All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH BlueZ 00/25] Broadcaster/Observer implementation
@ 2012-12-21 20:26 Bruna Moreira
  2012-12-21 20:26 ` [PATCH BlueZ 01/25] mgmt-api: Broadcaster/Observer management API Bruna Moreira
                   ` (24 more replies)
  0 siblings, 25 replies; 26+ messages in thread
From: Bruna Moreira @ 2012-12-21 20:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Bruna Moreira

Main changes from RFC series:
- Add version to Observer interface (org.bluez.Observer1)
- Merge some patches to decrease series size.

This series contains the implementation for Broadcaster/Observer roles. It has
changes for adapter API, userspace implementation for MGMT API and new commands
in btmgmt tool.

The kernel patches for new MGMT commands were sent one week ago by Jefferson
Delfes: http://article.gmane.org/gmane.linux.bluez.kernel/32703

For now, only Service Data and Manufacturer Specific Data can be
broadcasted/observed. All other data types defined by BT SIG are not
appropriate for general application use, and should be managed by BlueZ itself.

For Observer role, we have:
* Two methods to register watchers: RegisterServiceObserver() and
  RegisterManufacturerObserver().
* Respective methods to unregister watchers: UnregisterServiceObserver() and
  UnregisterManufacturerObserver()
* The data received are sent to application through ServiceReceived() and/or
  ManufacturerReceived().

An application can register only a observer watcher for each type: one for
Service Data and one for Manufacturer Specific Data. Both types can be enabled
for the same watcher.

For Broadcaster role, we have:
* Two methods to set data in controller: SetServiceData() and
  SetManufacturerData().
* One method for releasing any previously set Advertising data:
  ClearBroadcastData().

The same application can set a new Service Data and a new Manufacturer Specific
Data. To update any data set previously, the application should use
SetServiceData() or SetManufacturerData() using same Service UUID or Company
Identifier Code, respectively. Using ClearBroadcastData() will clean all data
set by application.

For MGMT API, new functions were implemented for Set Observer, Set Broadcaster,
Set Controller Data and Unset Controller Data (see doc/mgmt-api.txt for
details).

Anderson Lizardo (1):
  mgmt-api: Broadcaster/Observer management API

Bruna Moreira (13):
  lib: Add set broadcaster/observer operations
  btmgmt: Add set controller data support
  btmgmt: Add unset controller data support
  doc: Add Broadcaster/Observer D-Bus API documentation
  observer: Add Register/UnregisterManufacturerObserver() D-Bus method
  observer: Add watchers and filters for observers
  observer: Add Service/ManufacturerReceived() D-Bus method
  observer: Add python test script
  lib: Maximum value to advertising and scan response
  broadcaster: Build and send ADV/EIR data blob to kernel
  broadcaster: Add ClearBroadcastData() D-Bus method
  broadcaster: Update some data of already broadcast value
  broadcaster: Add python test script

Jefferson Delfes (11):
  lib: Add set/uset controller data operations
  btmgmt: Add set broadcaster and set observer support
  mgmt: Add set observer and set broadcaster command
  mgmt: Add set controller data command
  mgmt: Add unset controller data command
  adapter: Add D-Bus API for Observer GAP Role
  observer: Add Register/UnregisterServiceObserver() D-Bus method
  eir: Add manufacturer and service data fields
  adapter: Add D-Bus API for Broadcaster GAP Role
  broadcaster: Add SetService/ManufacturerData() D-Bus method
  broadcaster: Add list of broadcaster sessions

 doc/adapter-api.txt   |  117 +++++++
 doc/mgmt-api.txt      |   64 ++++
 lib/hci.h             |    6 +-
 lib/mgmt.h            |   26 ++
 src/adapter.c         |  811 ++++++++++++++++++++++++++++++++++++++++++++++++-
 src/adapter.h         |    3 +
 src/bluetooth.conf    |    1 +
 src/eir.c             |   42 +++
 src/eir.h             |   19 ++
 src/mgmt.c            |  119 ++++++++
 src/mgmt.h            |    6 +
 test/test-broadcaster |   61 ++++
 test/test-observer    |   75 +++++
 tools/btmgmt.c        |  139 +++++++++
 14 files changed, 1486 insertions(+), 3 deletions(-)
 create mode 100755 test/test-broadcaster
 create mode 100755 test/test-observer

-- 
1.7.9.5


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

* [PATCH BlueZ 01/25] mgmt-api: Broadcaster/Observer management API
  2012-12-21 20:26 [PATCH BlueZ 00/25] Broadcaster/Observer implementation Bruna Moreira
@ 2012-12-21 20:26 ` Bruna Moreira
  2012-12-21 20:26 ` [PATCH BlueZ 02/25] lib: Add set/uset controller data operations Bruna Moreira
                   ` (23 subsequent siblings)
  24 siblings, 0 replies; 26+ messages in thread
From: Bruna Moreira @ 2012-12-21 20:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anderson Lizardo

From: Anderson Lizardo <anderson.lizardo@openbossa.org>

Add new management commands for enabling or disabling broadcasting and
observation modes, as defined by the Observer and Broadcaster GAP roles
on the Core specification 4.0.

The commands can also be used for adding information to EIR on BR/EDR
controllers. For a list of all available AD/EIR types, see the Core
Specification Supplement (CSS) document.

Note that some AD/EIR types are managed internally by the kernel and are
not available through these new commands.
---
 doc/mgmt-api.txt |   64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/doc/mgmt-api.txt b/doc/mgmt-api.txt
index 60f4da4..fe052af 100644
--- a/doc/mgmt-api.txt
+++ b/doc/mgmt-api.txt
@@ -141,6 +141,8 @@ Read Controller Information Command
 		8	Basic Rate/Enhanced Data Rate
 		9	High Speed
 		10	Low Energy
+		11	Broadcaster
+		12	Observer
 
 	This command generates a Command Complete event on success or
 	a Command Status event on failure.
@@ -845,6 +847,68 @@ Set Device ID Command
 	a Command Status event on failure.
 
 
+Set Controller Data Command
+===========================
+
+	Command Code:		0x0029
+	Controller Index:	<controller id>
+	Command Parameters:	Flags (1 Octet)
+				Type (1 Octet)
+				Length (1 Octet)
+				Data (0-255 Octets)
+	Return Parameters:
+
+	This command can be used to set AD for LE capable controllers or EIR
+	for BR/EDR controllers. Multiple AD/EIR types can be configured by
+	calling this command multiple times. If the controller is BR/EDR/LE
+	capable (also known as "dual mode"), only the LE advertising is set.
+
+	The Flags parameter is currently unused, but it will contain bitwise
+	flags to fine tune how and when the data will set on the controller.
+
+	This command generates a Command Complete event on success or
+	a Command Status event on failure.
+
+
+Unset Controller Data Command
+=============================
+
+	Command Code:		0x002A
+	Controller Index:	<controller id>
+	Command Parameters:	Type (1 Octet)
+	Return Parameters:
+
+	Remove the AD/EIR information identified by Type, so it will not be
+	broadcasted anymore.
+
+	This command generates a Command Complete event on success or
+	on failure.
+
+
+Set Broadcaster Command
+=======================
+
+	Command Code:		0x002B
+	Controller Index:	<controller id>
+	Command Parameters:	Broadcaster (1 Octet)
+	Return Parameters:	Current_Settings (4 Octets)
+
+	This command generates a Command Complete event on success or
+	a Command Status event on failure.
+
+
+Set Observer Command
+====================
+
+	Command Code:		0x002C
+	Controller Index:	<controller id>
+	Command Parameters:	Observer (1 Octet)
+	Return Parameters:	Current_Settings (4 Octets)
+
+	This command generates a Command Complete event on success or
+	a Command Status event on failure.
+
+
 Command Complete Event
 ======================
 
-- 
1.7.9.5


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

* [PATCH BlueZ 02/25] lib: Add set/uset controller data operations
  2012-12-21 20:26 [PATCH BlueZ 00/25] Broadcaster/Observer implementation Bruna Moreira
  2012-12-21 20:26 ` [PATCH BlueZ 01/25] mgmt-api: Broadcaster/Observer management API Bruna Moreira
@ 2012-12-21 20:26 ` Bruna Moreira
  2012-12-21 20:26 ` [PATCH BlueZ 03/25] lib: Add set broadcaster/observer operations Bruna Moreira
                   ` (22 subsequent siblings)
  24 siblings, 0 replies; 26+ messages in thread
From: Bruna Moreira @ 2012-12-21 20:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jefferson Delfes

From: Jefferson Delfes <jefferson.delfes@openbossa.org>

Add structure for new commands: Set Controller Data and Unset Controller
Data. Add new defines for flags that will be used in Set/Unset
Controller Data operation.
---
 lib/mgmt.h |   18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/lib/mgmt.h b/lib/mgmt.h
index 6c7e44a..fffb0aa 100644
--- a/lib/mgmt.h
+++ b/lib/mgmt.h
@@ -318,6 +318,22 @@ struct mgmt_cp_set_device_id {
 	uint16_t version;
 } __packed;
 
+#define MGMT_DATA_NORMAL_PRIORITY	0x00
+#define MGMT_DATA_HIGH_PRIORITY		0x01
+
+#define MGMT_OP_SET_CONTROLLER_DATA	0x0029
+struct mgmt_cp_set_controller_data {
+	uint8_t flags;
+	uint8_t type;
+	uint8_t length;
+	uint8_t data[0];
+} __packed;
+
+#define MGMT_OP_UNSET_CONTROLLER_DATA	0x002A
+struct mgmt_cp_unset_controller_data {
+	uint8_t type;
+} __packed;
+
 #define MGMT_EV_CMD_COMPLETE		0x0001
 struct mgmt_ev_cmd_complete {
 	uint16_t opcode;
@@ -496,6 +512,8 @@ static const char *mgmt_op[] = {
 	"Block Device",
 	"Unblock Device",
 	"Set Device ID",
+	"Set Controller Data",
+	"Unset Controller Data",
 };
 
 static const char *mgmt_ev[] = {
-- 
1.7.9.5


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

* [PATCH BlueZ 03/25] lib: Add set broadcaster/observer operations
  2012-12-21 20:26 [PATCH BlueZ 00/25] Broadcaster/Observer implementation Bruna Moreira
  2012-12-21 20:26 ` [PATCH BlueZ 01/25] mgmt-api: Broadcaster/Observer management API Bruna Moreira
  2012-12-21 20:26 ` [PATCH BlueZ 02/25] lib: Add set/uset controller data operations Bruna Moreira
@ 2012-12-21 20:26 ` Bruna Moreira
  2012-12-21 20:26 ` [PATCH BlueZ 04/25] btmgmt: Add set broadcaster and set observer support Bruna Moreira
                   ` (21 subsequent siblings)
  24 siblings, 0 replies; 26+ messages in thread
From: Bruna Moreira @ 2012-12-21 20:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Bruna Moreira

Add opcodes for new Set Broadcaster and Set Observer commands.
---
 lib/mgmt.h |    8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/lib/mgmt.h b/lib/mgmt.h
index fffb0aa..44c4405 100644
--- a/lib/mgmt.h
+++ b/lib/mgmt.h
@@ -92,6 +92,8 @@ struct mgmt_rp_read_index_list {
 #define MGMT_SETTING_BREDR		0x00000080
 #define MGMT_SETTING_HS			0x00000100
 #define MGMT_SETTING_LE			0x00000200
+#define MGMT_SETTING_BROADCASTER	0x00000400
+#define MGMT_SETTING_OBSERVER		0x00000800
 
 #define MGMT_OP_READ_INFO		0x0004
 struct mgmt_rp_read_info {
@@ -334,6 +336,10 @@ struct mgmt_cp_unset_controller_data {
 	uint8_t type;
 } __packed;
 
+#define MGMT_OP_SET_BROADCASTER		0x002B
+
+#define MGMT_OP_SET_OBSERVER		0x002C
+
 #define MGMT_EV_CMD_COMPLETE		0x0001
 struct mgmt_ev_cmd_complete {
 	uint16_t opcode;
@@ -514,6 +520,8 @@ static const char *mgmt_op[] = {
 	"Set Device ID",
 	"Set Controller Data",
 	"Unset Controller Data",
+	"Set Broadcaster",
+	"Set Observer",
 };
 
 static const char *mgmt_ev[] = {
-- 
1.7.9.5


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

* [PATCH BlueZ 04/25] btmgmt: Add set broadcaster and set observer support
  2012-12-21 20:26 [PATCH BlueZ 00/25] Broadcaster/Observer implementation Bruna Moreira
                   ` (2 preceding siblings ...)
  2012-12-21 20:26 ` [PATCH BlueZ 03/25] lib: Add set broadcaster/observer operations Bruna Moreira
@ 2012-12-21 20:26 ` Bruna Moreira
  2012-12-21 20:26 ` [PATCH BlueZ 05/25] btmgmt: Add set controller data support Bruna Moreira
                   ` (20 subsequent siblings)
  24 siblings, 0 replies; 26+ messages in thread
From: Bruna Moreira @ 2012-12-21 20:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jefferson Delfes

From: Jefferson Delfes <jefferson.delfes@openbossa.org>

Add new broadcaster command for running the Set Broadcaster operation
from MGMT API. Also, add new observer command for running the Set
Observer operation from MGMT API.
---
 tools/btmgmt.c |   14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/tools/btmgmt.c b/tools/btmgmt.c
index b89bcac..4d9eab6 100644
--- a/tools/btmgmt.c
+++ b/tools/btmgmt.c
@@ -235,6 +235,8 @@ static const char *settings_str[] = {
 				"br/edr",
 				"hs",
 				"le" ,
+				"broadcaster",
+				"observer",
 };
 
 static void print_settings(uint32_t settings)
@@ -1111,6 +1113,16 @@ static void cmd_le(int mgmt_sk, uint16_t index, int argc, char **argv)
 	cmd_setting(mgmt_sk, index, MGMT_OP_SET_LE, argc, argv);
 }
 
+static void cmd_broadcaster(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+	cmd_setting(mgmt_sk, index, MGMT_OP_SET_BROADCASTER, argc, argv);
+}
+
+static void cmd_observer(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+	cmd_setting(mgmt_sk, index, MGMT_OP_SET_OBSERVER, argc, argv);
+}
+
 static void class_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
 				void *rsp, uint16_t len, void *user_data)
 {
@@ -1848,6 +1860,8 @@ static struct {
 	{ "rm-uuid",	cmd_remove_uuid, "Remove UUID"			},
 	{ "clr-uuids",	cmd_clr_uuids,	"Clear UUIDs",			},
 	{ "did",	cmd_did,	"Set Device ID",		},
+	{ "broadcaster",cmd_broadcaster,"Toggle Broadcaster Mode",	},
+	{ "observer",	cmd_observer,	"Toggle Observer Mode",		},
 	{ NULL, NULL, 0 }
 };
 
-- 
1.7.9.5


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

* [PATCH BlueZ 05/25] btmgmt: Add set controller data support
  2012-12-21 20:26 [PATCH BlueZ 00/25] Broadcaster/Observer implementation Bruna Moreira
                   ` (3 preceding siblings ...)
  2012-12-21 20:26 ` [PATCH BlueZ 04/25] btmgmt: Add set broadcaster and set observer support Bruna Moreira
@ 2012-12-21 20:26 ` Bruna Moreira
  2012-12-21 20:26 ` [PATCH BlueZ 06/25] btmgmt: Add unset " Bruna Moreira
                   ` (19 subsequent siblings)
  24 siblings, 0 replies; 26+ messages in thread
From: Bruna Moreira @ 2012-12-21 20:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Bruna Moreira

Add new command set-data for running the Set Controller Data operation
from MGMT API.
---
 tools/btmgmt.c |   85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 85 insertions(+)

diff --git a/tools/btmgmt.c b/tools/btmgmt.c
index 4d9eab6..3ae0ecb 100644
--- a/tools/btmgmt.c
+++ b/tools/btmgmt.c
@@ -1829,6 +1829,90 @@ done:
 	}
 }
 
+static void set_data_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+				void *rsp, uint16_t len, void *user_data)
+{
+	if (status != 0) {
+		fprintf(stderr, "%s failed, status 0x%02x (%s)\n",
+				mgmt_opstr(op), status, mgmt_errstr(status));
+		exit(EXIT_FAILURE);
+	}
+
+	exit(EXIT_SUCCESS);
+}
+
+static void set_data_usage(void)
+{
+	printf("Usage: btmgmt set_data [-p] <data type> <byte array>\n");
+	printf("\nexample: btmgmt set_data -p 0xff 11 11 aa bb cc\n");
+	printf("\nparameters:\n");
+	printf("\tp: controller data priority.\n");
+	printf("\t<data type>: 0x16 (service data) or 0xff (manufacturer\n"
+		"\t specific data). Values different from that will return\n"
+		"\t error from kernel.\n");
+	printf("\t<byte array>: two bytes (service uuid or company identifier\n"
+		"\t code) following by hex encoded bytes (data).\n");
+}
+
+static struct option set_data_options[] = {
+	{ "help",	0, 0, 'h' },
+	{ "priority",	1, 0, 'p' },
+	{ 0, 0, 0, 0 }
+};
+
+static void cmd_set_data(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+	struct mgmt_cp_set_controller_data *cp;
+	uint8_t data_len, flags = 0;
+	unsigned int i;
+	int opt;
+
+	while ((opt = getopt_long(argc, argv, "+ph", set_data_options,
+								NULL)) != -1) {
+		switch (opt) {
+		case 'p':
+			flags = MGMT_DATA_HIGH_PRIORITY;
+			break;
+		case 'h':
+		default:
+			set_data_usage();
+			exit(EXIT_SUCCESS);
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+	optind = 0;
+
+	if (argc < 1) {
+		set_data_usage();
+		exit(EXIT_FAILURE);
+	}
+
+	data_len = argc - 1;
+	cp = malloc(sizeof(*cp) + data_len);
+	cp->flags = flags;
+	sscanf(argv[0], "%hhx", &cp->type);
+
+	for (i = 0; i < data_len; i++)
+		sscanf(argv[i + 1], "%hhx", &cp->data[i]);
+
+	cp->length = data_len;
+
+	if (index == MGMT_INDEX_NONE)
+		index = 0;
+
+	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_SET_CONTROLLER_DATA, index,
+						cp, sizeof(*cp) + data_len,
+						set_data_rsp, NULL) < 0) {
+		free(cp);
+		fprintf(stderr, "Unable to send set controller data cmd\n");
+		exit(EXIT_FAILURE);
+	}
+
+	free(cp);
+}
+
 static struct {
 	char *cmd;
 	void (*func)(int mgmt_sk, uint16_t index, int argc, char **argv);
@@ -1862,6 +1946,7 @@ static struct {
 	{ "did",	cmd_did,	"Set Device ID",		},
 	{ "broadcaster",cmd_broadcaster,"Toggle Broadcaster Mode",	},
 	{ "observer",	cmd_observer,	"Toggle Observer Mode",		},
+	{ "set-data",	cmd_set_data,	"Set Controller Data",		},
 	{ NULL, NULL, 0 }
 };
 
-- 
1.7.9.5


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

* [PATCH BlueZ 06/25] btmgmt: Add unset controller data support
  2012-12-21 20:26 [PATCH BlueZ 00/25] Broadcaster/Observer implementation Bruna Moreira
                   ` (4 preceding siblings ...)
  2012-12-21 20:26 ` [PATCH BlueZ 05/25] btmgmt: Add set controller data support Bruna Moreira
@ 2012-12-21 20:26 ` Bruna Moreira
  2012-12-21 20:26 ` [PATCH BlueZ 07/25] mgmt: Add set observer and set broadcaster command Bruna Moreira
                   ` (18 subsequent siblings)
  24 siblings, 0 replies; 26+ messages in thread
From: Bruna Moreira @ 2012-12-21 20:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Bruna Moreira

Add new command unset-data for running the Unset Controller Data
operation from MGMT API.
---
 tools/btmgmt.c |   40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/tools/btmgmt.c b/tools/btmgmt.c
index 3ae0ecb..99f5562 100644
--- a/tools/btmgmt.c
+++ b/tools/btmgmt.c
@@ -1913,6 +1913,45 @@ static void cmd_set_data(int mgmt_sk, uint16_t index, int argc, char **argv)
 	free(cp);
 }
 
+static void unset_data_rsp(int mgmt_sk, uint16_t op, uint16_t id,
+		uint8_t status, void *rsp, uint16_t len, void *user_data)
+{
+	if (status != 0) {
+		fprintf(stderr, "%s failed, status 0x%02x (%s)\n",
+				mgmt_opstr(op), status, mgmt_errstr(status));
+		exit(EXIT_FAILURE);
+	}
+
+	exit(EXIT_SUCCESS);
+}
+
+static void cmd_unset_data(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+	struct mgmt_cp_unset_controller_data cp;
+
+	if (argc < 2) {
+		printf("Usage: btmgmt %s <data type>\n", argv[0]);
+		printf("\nexample: btmgmt %s 0xff\n", argv[0]);
+		printf("\nparameters:\n");
+		printf("\t<data type>: 0x16 (service data) or 0xff\n"
+				"\t(manufacturer specific data).\n");
+
+		exit(EXIT_FAILURE);
+	}
+
+	memset(&cp, 0, sizeof(cp));
+	sscanf(argv[1], "%hhx", &cp.type);
+
+	if (index == MGMT_INDEX_NONE)
+		index = 0;
+
+	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_UNSET_CONTROLLER_DATA, index,
+				&cp, sizeof(cp), unset_data_rsp, NULL) < 0) {
+		fprintf(stderr, "Unable to send unset controller data cmd\n");
+		exit(EXIT_FAILURE);
+	}
+}
+
 static struct {
 	char *cmd;
 	void (*func)(int mgmt_sk, uint16_t index, int argc, char **argv);
@@ -1947,6 +1986,7 @@ static struct {
 	{ "broadcaster",cmd_broadcaster,"Toggle Broadcaster Mode",	},
 	{ "observer",	cmd_observer,	"Toggle Observer Mode",		},
 	{ "set-data",	cmd_set_data,	"Set Controller Data",		},
+	{ "unset-data",	cmd_unset_data,	"Unset Controller Data",	},
 	{ NULL, NULL, 0 }
 };
 
-- 
1.7.9.5


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

* [PATCH BlueZ 07/25] mgmt: Add set observer and set broadcaster command
  2012-12-21 20:26 [PATCH BlueZ 00/25] Broadcaster/Observer implementation Bruna Moreira
                   ` (5 preceding siblings ...)
  2012-12-21 20:26 ` [PATCH BlueZ 06/25] btmgmt: Add unset " Bruna Moreira
@ 2012-12-21 20:26 ` Bruna Moreira
  2012-12-21 20:26 ` [PATCH BlueZ 08/25] mgmt: Add set controller data command Bruna Moreira
                   ` (17 subsequent siblings)
  24 siblings, 0 replies; 26+ messages in thread
From: Bruna Moreira @ 2012-12-21 20:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jefferson Delfes

From: Jefferson Delfes <jefferson.delfes@openbossa.org>

Implement Set Observer and Set Broadcaster support in MGMT API.

For observer, setting TRUE will make the adapter start LE discovery,
otherwise, setting FALSE will make the adapter stop LE discovery.

For broadcaster, setting TRUE will make the new data sent by Set
Controller Data command to be set in adapter and the advertising will
start. Setting FALSE will stop advertising.
---
 src/mgmt.c |   16 ++++++++++++++++
 src/mgmt.h |    2 ++
 2 files changed, 18 insertions(+)

diff --git a/src/mgmt.c b/src/mgmt.c
index 03ec049..0f212b2 100644
--- a/src/mgmt.c
+++ b/src/mgmt.c
@@ -1651,6 +1651,12 @@ static void mgmt_cmd_complete(int sk, uint16_t index, void *buf, size_t len)
 	case MGMT_OP_SET_DEVICE_ID:
 		DBG("set_did complete");
 		break;
+	case MGMT_OP_SET_BROADCASTER:
+		DBG("set_broadcaster complete");
+		break;
+	case MGMT_OP_SET_OBSERVER:
+		DBG("set_observer complete");
+		break;
 	default:
 		error("Unknown command complete for opcode %u", opcode);
 		break;
@@ -2358,6 +2364,16 @@ int mgmt_set_fast_connectable(int index, gboolean enable)
 	return 0;
 }
 
+int mgmt_set_broadcaster(int index, gboolean enable)
+{
+	return mgmt_set_mode(index, MGMT_OP_SET_BROADCASTER, enable);
+}
+
+int mgmt_set_observer(int index, gboolean enable)
+{
+	return mgmt_set_mode(index, MGMT_OP_SET_OBSERVER, enable);
+}
+
 int mgmt_read_clock(int index, const bdaddr_t *bdaddr, int which, int timeout,
 					uint32_t *clock, uint16_t *accuracy)
 {
diff --git a/src/mgmt.h b/src/mgmt.h
index 1ea8488..1607a95 100644
--- a/src/mgmt.h
+++ b/src/mgmt.h
@@ -32,6 +32,8 @@ int mgmt_set_pairable(int index, gboolean pairable);
 int mgmt_set_name(int index, const char *name);
 int mgmt_set_dev_class(int index, uint8_t major, uint8_t minor);
 int mgmt_set_fast_connectable(int index, gboolean enable);
+int mgmt_set_broadcaster(int index, gboolean enable);
+int mgmt_set_observer(int index, gboolean enable);
 
 int mgmt_start_discovery(int index);
 int mgmt_start_le_scanning(int index);
-- 
1.7.9.5


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

* [PATCH BlueZ 08/25] mgmt: Add set controller data command
  2012-12-21 20:26 [PATCH BlueZ 00/25] Broadcaster/Observer implementation Bruna Moreira
                   ` (6 preceding siblings ...)
  2012-12-21 20:26 ` [PATCH BlueZ 07/25] mgmt: Add set observer and set broadcaster command Bruna Moreira
@ 2012-12-21 20:26 ` Bruna Moreira
  2012-12-21 20:26 ` [PATCH BlueZ 09/25] mgmt: Add unset " Bruna Moreira
                   ` (16 subsequent siblings)
  24 siblings, 0 replies; 26+ messages in thread
From: Bruna Moreira @ 2012-12-21 20:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jefferson Delfes

From: Jefferson Delfes <jefferson.delfes@openbossa.org>

Implement new Set Controller Data command in MGMT API. The maximum size
for new data is 27 bytes. The data sent using this command will be
stored in internal list and it will be set in adapter after receiving a
Set Broadcaster with TRUE.
---
 src/adapter.c |    8 ++++++
 src/adapter.h |    3 +++
 src/mgmt.c    |   78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/mgmt.h    |    3 +++
 4 files changed, 92 insertions(+)

diff --git a/src/adapter.c b/src/adapter.c
index 6ff20e1..d741ae1 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -563,6 +563,10 @@ void adapter_name_changed(struct btd_adapter *adapter, const char *name)
 				(const uint8_t *) name, strlen(name));
 }
 
+void adapter_set_controller_data_complete(struct btd_adapter *adapter)
+{
+}
+
 int adapter_set_name(struct btd_adapter *adapter, const char *name)
 {
 	char maxname[MAX_NAME_LENGTH + 1];
@@ -1150,6 +1154,10 @@ static DBusMessage *remove_device(DBusConnection *conn, DBusMessage *msg,
 	return NULL;
 }
 
+void adapter_set_controller_data_failed(struct btd_adapter *adapter)
+{
+}
+
 static const GDBusMethodTable adapter_methods[] = {
 	{ GDBUS_METHOD("StartDiscovery", NULL, NULL,
 			adapter_start_discovery) },
diff --git a/src/adapter.h b/src/adapter.h
index d35b8db..ad79ae1 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -236,3 +236,6 @@ void adapter_store_cached_name(const bdaddr_t *local, const bdaddr_t *peer,
 void btd_adapter_for_each_device(struct btd_adapter *adapter,
 			void (*cb)(struct btd_device *device, void *data),
 			void *data);
+
+void adapter_set_controller_data_complete(struct btd_adapter *adapter);
+void adapter_set_controller_data_failed(struct btd_adapter *adapter);
diff --git a/src/mgmt.c b/src/mgmt.c
index 0f212b2..d1b5043 100644
--- a/src/mgmt.c
+++ b/src/mgmt.c
@@ -1426,6 +1426,28 @@ static void start_discovery_complete(int sk, uint16_t index, uint8_t status,
 		adapter_set_discovering(adapter, FALSE);
 }
 
+static void set_controller_data_complete(int sk, uint16_t index, void *buf,
+								size_t len)
+{
+	struct btd_adapter *adapter;
+
+	DBG("hci%d", index);
+
+	if (index > max_index) {
+		error("Unexpected index %u in set_controller data complete",
+									index);
+		return;
+	}
+
+	adapter = manager_find_adapter_by_id(index);
+	if (adapter == NULL) {
+		DBG("Adapter not found");
+		return;
+	}
+
+	adapter_set_controller_data_complete(adapter);
+}
+
 static void read_local_oob_data_failed(int sk, uint16_t index)
 {
 	struct btd_adapter *adapter;
@@ -1443,6 +1465,23 @@ static void read_local_oob_data_failed(int sk, uint16_t index)
 		adapter_read_local_oob_data_complete(adapter, NULL, NULL);
 }
 
+static void set_controller_data_failed(int sk, uint16_t index)
+{
+	struct btd_adapter *adapter;
+
+	if (index > max_index) {
+		error("Unexpected index %u in set_controller_data_failed",
+								index);
+		return;
+	}
+
+	DBG("hci%u", index);
+
+	adapter = manager_find_adapter_by_id(index);
+	if (adapter)
+		adapter_set_controller_data_failed(adapter);
+}
+
 static void handle_pending_uuids(uint16_t index)
 {
 	struct controller_info *info;
@@ -1651,6 +1690,10 @@ static void mgmt_cmd_complete(int sk, uint16_t index, void *buf, size_t len)
 	case MGMT_OP_SET_DEVICE_ID:
 		DBG("set_did complete");
 		break;
+	case MGMT_OP_SET_CONTROLLER_DATA:
+		DBG("set_controller_data complete");
+		set_controller_data_complete(sk, index, ev->data, len);
+		break;
 	case MGMT_OP_SET_BROADCASTER:
 		DBG("set_broadcaster complete");
 		break;
@@ -1701,6 +1744,9 @@ static void mgmt_cmd_status(int sk, uint16_t index, void *buf, size_t len)
 			return;
 		}
 		break;
+	case MGMT_OP_SET_CONTROLLER_DATA:
+		set_controller_data_failed(sk, index);
+		break;
 	}
 
 	error("hci%u: %s (0x%04x) failed: %s (0x%02x)", index,
@@ -2821,3 +2867,35 @@ int mgmt_ssp_enabled(int index)
 
 	return mgmt_ssp(info->current_settings);
 }
+
+int mgmt_set_controller_data(int index, uint8_t flags, uint8_t data_type,
+					uint8_t *data, uint8_t data_length)
+{
+	char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_set_controller_data) +
+							HCI_MAX_EIR_LENGTH];
+	struct mgmt_hdr *hdr = (void *) buf;
+	struct mgmt_cp_set_controller_data *cp = (void *) &buf[sizeof(*hdr)];
+	uint16_t cp_size;
+	int err = 0;
+
+	DBG("hci%d flags %d data_type 0x%hhx data_length %d", index, flags,
+							data_type, data_length);
+
+	memset(buf, 0, sizeof(buf));
+
+	cp_size = sizeof(*cp) + data_length;
+
+	hdr->opcode = htobs(MGMT_OP_SET_CONTROLLER_DATA);
+	hdr->index = htobs(index);
+	hdr->len = htobs(cp_size);
+
+	cp->flags = flags;
+	cp->type = data_type;
+	cp->length = data_length;
+	memcpy(cp->data, data, data_length);
+
+	if (write(mgmt_sock, buf, sizeof(*hdr) + cp_size) < 0)
+		err = -errno;
+
+	return err;
+}
diff --git a/src/mgmt.h b/src/mgmt.h
index 1607a95..92b4757 100644
--- a/src/mgmt.h
+++ b/src/mgmt.h
@@ -84,3 +84,6 @@ int mgmt_confirm_name(int index, const bdaddr_t *bdaddr, uint8_t bdaddr_type,
 							gboolean name_known);
 
 int mgmt_ssp_enabled(int index);
+
+int mgmt_set_controller_data(int index, uint8_t flags, uint8_t data_type,
+					uint8_t *data, uint8_t data_length);
-- 
1.7.9.5


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

* [PATCH BlueZ 09/25] mgmt: Add unset controller data command
  2012-12-21 20:26 [PATCH BlueZ 00/25] Broadcaster/Observer implementation Bruna Moreira
                   ` (7 preceding siblings ...)
  2012-12-21 20:26 ` [PATCH BlueZ 08/25] mgmt: Add set controller data command Bruna Moreira
@ 2012-12-21 20:26 ` Bruna Moreira
  2012-12-21 20:26 ` [PATCH BlueZ 10/25] doc: Add Broadcaster/Observer D-Bus API documentation Bruna Moreira
                   ` (15 subsequent siblings)
  24 siblings, 0 replies; 26+ messages in thread
From: Bruna Moreira @ 2012-12-21 20:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jefferson Delfes

From: Jefferson Delfes <jefferson.delfes@openbossa.org>

Implement Unset Controller Data command in MGMT API.  This operation
will remove all data from specific type that was set previously with Set
Controller Data operation.
---
 src/mgmt.c |   25 +++++++++++++++++++++++++
 src/mgmt.h |    1 +
 2 files changed, 26 insertions(+)

diff --git a/src/mgmt.c b/src/mgmt.c
index d1b5043..9a6affc 100644
--- a/src/mgmt.c
+++ b/src/mgmt.c
@@ -1694,6 +1694,9 @@ static void mgmt_cmd_complete(int sk, uint16_t index, void *buf, size_t len)
 		DBG("set_controller_data complete");
 		set_controller_data_complete(sk, index, ev->data, len);
 		break;
+	case MGMT_OP_UNSET_CONTROLLER_DATA:
+		DBG("unset_controller_data complete");
+		break;
 	case MGMT_OP_SET_BROADCASTER:
 		DBG("set_broadcaster complete");
 		break;
@@ -2899,3 +2902,25 @@ int mgmt_set_controller_data(int index, uint8_t flags, uint8_t data_type,
 
 	return err;
 }
+
+int mgmt_unset_controller_data(int index, uint8_t data_type)
+{
+	char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_unset_controller_data)];
+	struct mgmt_hdr *hdr = (void *) buf;
+	struct mgmt_cp_unset_controller_data *cp = (void *) &buf[sizeof(*hdr)];
+
+	DBG("hci%d data_type 0x%hhx", index, data_type);
+
+	memset(buf, 0, sizeof(buf));
+
+	hdr->opcode = htobs(MGMT_OP_UNSET_CONTROLLER_DATA);
+	hdr->index = htobs(index);
+	hdr->len = htobs(sizeof(*cp));
+
+	cp->type = data_type;
+
+	if (write(mgmt_sock, buf, sizeof(buf)) < 0)
+		return -errno;
+
+	return 0;
+}
diff --git a/src/mgmt.h b/src/mgmt.h
index 92b4757..187c971 100644
--- a/src/mgmt.h
+++ b/src/mgmt.h
@@ -87,3 +87,4 @@ int mgmt_ssp_enabled(int index);
 
 int mgmt_set_controller_data(int index, uint8_t flags, uint8_t data_type,
 					uint8_t *data, uint8_t data_length);
+int mgmt_unset_controller_data(int index, uint8_t data_type);
-- 
1.7.9.5


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

* [PATCH BlueZ 10/25] doc: Add Broadcaster/Observer D-Bus API documentation
  2012-12-21 20:26 [PATCH BlueZ 00/25] Broadcaster/Observer implementation Bruna Moreira
                   ` (8 preceding siblings ...)
  2012-12-21 20:26 ` [PATCH BlueZ 09/25] mgmt: Add unset " Bruna Moreira
@ 2012-12-21 20:26 ` Bruna Moreira
  2012-12-21 20:26 ` [PATCH BlueZ 11/25] adapter: Add D-Bus API for Observer GAP Role Bruna Moreira
                   ` (14 subsequent siblings)
  24 siblings, 0 replies; 26+ messages in thread
From: Bruna Moreira @ 2012-12-21 20:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Bruna Moreira

---
 doc/adapter-api.txt |  117 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 117 insertions(+)

diff --git a/doc/adapter-api.txt b/doc/adapter-api.txt
index 62c7a27..e8ca305 100644
--- a/doc/adapter-api.txt
+++ b/doc/adapter-api.txt
@@ -43,6 +43,102 @@ Methods		void StartDiscovery()
 			Possible errors: org.bluez.Error.InvalidArguments
 					 org.bluez.Error.Failed
 
+		void RegisterServiceObserver(object observer,
+							uint16 match_value)
+
+			Registers an observer agent to monitor Service Data
+			broadcasts. This agent will be notified whenever a
+			broadcast is received that matches that filter. It is
+			possible use same object path for two observers:
+			Service Data and Manufacturer Specific Data.
+
+			The match_value parameter must be the 16-bit UUID for
+			the service whose data is to be monitored.
+
+			Possible errors: org.bluez.Error.InvalidArguments
+					 org.bluez.Error.AlreadyExists
+
+		void RegisterManufacturerObserver(object observer,
+							uint16 match_value)
+
+			Registers an observer agent to monitor Manufacturer
+			Specific Data broadcasts. This agent will be notified
+			whenever a broadcast is received that matches that
+			filter. It is possible use same object path for two
+			observers: Service Data and Manufacturer Specific Data.
+
+			The match_value parameter must be the 16-bit Company
+			Identifier Code for the manufacturer whose data is to
+			be monitored.
+
+			Possible errors: org.bluez.Error.InvalidArguments
+					 org.bluez.Error.AlreadyExists
+
+		void UnregisterServiceObserver(object observer)
+
+			Unregisters a Service Data observer. Broadcasts will
+			not be notified to this agent anymore. The observer
+			will be destroyed only if no Manufacturer Specific Data
+			was registered with the same object path.
+
+			Possible errors: org.bluez.Error.InvalidArguments
+					 org.bluez.Error.DoesNotExist
+
+		void UnregisterManufacturerObserver(object observer)
+
+			Unregisters a Manufacturer Specific Data observer.
+			Broadcasts will not be notified to this agent anymore.
+			The observer will be destroyed only if no Service Data
+			was registered with the same object path.
+
+			Possible errors: org.bluez.Error.InvalidArguments
+					 org.bluez.Error.DoesNotExist
+
+		void SetServiceData(uint16 uuid, array{byte} data)
+
+			Set Service Data for broadcast. Different applications
+			can register different Adv. data types, and they are
+			all concatenated to form the Adv. data. Broadcasting is
+			enabled as soon as the first SetServiceData() call is
+			made.
+
+			This method can be used to update service data already
+			being broadcasted.
+
+			Use ClearBroadcastData() to release any Adv. data for
+			the application. Advertising data is also released when
+			application exits, and once the last Broadcaster exits,
+			advertising is disabled.
+
+			Possible Errors: org.bluez.Error.InvalidArguments
+					 org.bluez.Error.Failed
+
+		void SetManufacturerData(uint16 cid, array{byte} data)
+
+			Set Manufacturer Specific Data for broadcast. Different
+			applications can register different Adv. data types,
+			and they are all concatenated to form the Adv. data.
+			Broadcasting is enabled as soon as the first
+			SetManufacturerData() call is made.
+
+			This method can be used to update manufacturer data
+			already being broadcasted.
+
+			Use ClearBroadcastData() to release any Adv. data for
+			the application. Advertising data is also released when
+			application exits, and once the last Broadcaster exits,
+			advertising is disabled.
+
+			Possible Errors: org.bluez.Error.InvalidArguments
+					 org.bluez.Error.Failed
+
+		void ClearBroadcastData()
+
+			This method will release any previously set Advertising
+			data.
+
+			Possible errors: org.bluez.Error.Failed
+
 Properties	string Address [readonly]
 
 			The Bluetooth device address.
@@ -118,3 +214,24 @@ Properties	string Address [readonly]
 
 			List of 128-bit UUIDs that represents the available
 			local services.
+
+Observer hierarchy
+==================
+
+Service		unique name
+Interface	org.bluez.Observer1
+Object path	freely definable
+
+Methods		void ServiceReceived(string address, uint16 uuid,
+							array{byte} data)
+
+			This callback gets called when a broadcast data has
+			arrived that matches filter used in
+			RegisterServiceObserver.
+
+		void ManufacturerReceived(string address, uint16 cid,
+							array{byte} data)
+
+			This callback gets called when a broadcast data has
+			arrived that matches filter used in
+			RegisterManufacturerObserver.
-- 
1.7.9.5


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

* [PATCH BlueZ 11/25] adapter: Add D-Bus API for Observer GAP Role
  2012-12-21 20:26 [PATCH BlueZ 00/25] Broadcaster/Observer implementation Bruna Moreira
                   ` (9 preceding siblings ...)
  2012-12-21 20:26 ` [PATCH BlueZ 10/25] doc: Add Broadcaster/Observer D-Bus API documentation Bruna Moreira
@ 2012-12-21 20:26 ` Bruna Moreira
  2012-12-21 20:26 ` [PATCH BlueZ 12/25] observer: Add Register/UnregisterServiceObserver() D-Bus method Bruna Moreira
                   ` (13 subsequent siblings)
  24 siblings, 0 replies; 26+ messages in thread
From: Bruna Moreira @ 2012-12-21 20:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jefferson Delfes

From: Jefferson Delfes <jefferson.delfes@openbossa.org>

Implement dummy calls for register or unregister Observer Agents.
---
 src/adapter.c      |   38 ++++++++++++++++++++++++++++++++++++++
 src/bluetooth.conf |    1 +
 2 files changed, 39 insertions(+)

diff --git a/src/adapter.c b/src/adapter.c
index d741ae1..34dad6e 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -1154,6 +1154,30 @@ static DBusMessage *remove_device(DBusConnection *conn, DBusMessage *msg,
 	return NULL;
 }
 
+static DBusMessage *register_service_observer(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *unregister_service_observer(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *register_manuf_observer(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *unregister_manuf_observer(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	return dbus_message_new_method_return(msg);
+}
+
 void adapter_set_controller_data_failed(struct btd_adapter *adapter)
 {
 }
@@ -1166,6 +1190,20 @@ static const GDBusMethodTable adapter_methods[] = {
 	{ GDBUS_ASYNC_METHOD("RemoveDevice",
 			GDBUS_ARGS({ "device", "o" }), NULL,
 			remove_device) },
+	{ GDBUS_METHOD("RegisterServiceObserver",
+			GDBUS_ARGS({ "observer", "o" }, { "match_value", "q" }),
+			NULL,
+			register_service_observer) },
+	{ GDBUS_METHOD("UnregisterServiceObserver",
+			GDBUS_ARGS({ "observer", "o" }), NULL,
+			unregister_service_observer) },
+	{ GDBUS_METHOD("RegisterManufacturerObserver",
+			GDBUS_ARGS({ "observer", "o" }, { "match_value", "q" }),
+			NULL,
+			register_manuf_observer) },
+	{ GDBUS_METHOD("UnregisterManufacturerObserver",
+			GDBUS_ARGS({ "observer", "o" }), NULL,
+			unregister_manuf_observer) },
 	{ }
 };
 
diff --git a/src/bluetooth.conf b/src/bluetooth.conf
index 0495200..e8176ed 100644
--- a/src/bluetooth.conf
+++ b/src/bluetooth.conf
@@ -15,6 +15,7 @@
     <allow send_interface="org.bluez.MediaPlayer1"/>
     <allow send_interface="org.bluez.ThermometerWatcher1"/>
     <allow send_interface="org.bluez.AlertAgent1"/>
+    <allow send_interface="org.bluez.Observer1"/>
     <allow send_interface="org.bluez.Profile1"/>
     <allow send_interface="org.bluez.HeartRateWatcher1"/>
     <allow send_interface="org.bluez.CyclingSpeedWatcher1"/>
-- 
1.7.9.5


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

* [PATCH BlueZ 12/25] observer: Add Register/UnregisterServiceObserver() D-Bus method
  2012-12-21 20:26 [PATCH BlueZ 00/25] Broadcaster/Observer implementation Bruna Moreira
                   ` (10 preceding siblings ...)
  2012-12-21 20:26 ` [PATCH BlueZ 11/25] adapter: Add D-Bus API for Observer GAP Role Bruna Moreira
@ 2012-12-21 20:26 ` Bruna Moreira
  2012-12-21 20:26 ` [PATCH BlueZ 13/25] observer: Add Register/UnregisterManufacturerObserver() " Bruna Moreira
                   ` (12 subsequent siblings)
  24 siblings, 0 replies; 26+ messages in thread
From: Bruna Moreira @ 2012-12-21 20:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jefferson Delfes

From: Jefferson Delfes <jefferson.delfes@openbossa.org>

An observer for Service Data must be registered using
RegisterServiceObserver() D-Bus method so it can receive any advertising
which matches with the filter used. Use UnregisterServiceObserver()
D-Bus method for unregistering an observer and stop sending broadcasts
to the agent.
---
 src/adapter.c |   35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/src/adapter.c b/src/adapter.c
index 34dad6e..a5c23da 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -1157,12 +1157,47 @@ static DBusMessage *remove_device(DBusConnection *conn, DBusMessage *msg,
 static DBusMessage *register_service_observer(DBusConnection *conn,
 						DBusMessage *msg, void *data)
 {
+	struct btd_adapter *adapter = data;
+	const char *path, *sender = dbus_message_get_sender(msg);
+	unsigned int uuid;
+	int err;
+
+	if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+					DBUS_TYPE_UINT16, &uuid,
+					DBUS_TYPE_INVALID) == FALSE)
+		return btd_error_invalid_args(msg);
+
+	err = mgmt_set_observer(adapter->dev_id, TRUE);
+	if (err < 0) {
+		error("Failed to set Observer: %s (%d)", strerror(-err), -err);
+
+		return btd_error_failed(msg, strerror(-err));
+	}
+
+	DBG("Service Data Observer registered for hci%d at %s:%s",
+						adapter->dev_id, sender, path);
+
 	return dbus_message_new_method_return(msg);
 }
 
 static DBusMessage *unregister_service_observer(DBusConnection *conn,
 						DBusMessage *msg, void *data)
 {
+	const char *path, *sender = dbus_message_get_sender(msg);
+	struct btd_adapter *adapter = data;
+	int err;
+
+	if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+						DBUS_TYPE_INVALID) == FALSE)
+		return btd_error_invalid_args(msg);
+
+	err = mgmt_set_observer(adapter->dev_id, FALSE);
+	if (err < 0)
+		return btd_error_failed(msg, strerror(-err));
+
+	DBG("Service Data Observer unregistered for hci%d at %s:%s",
+						adapter->dev_id, sender, path);
+
 	return dbus_message_new_method_return(msg);
 }
 
-- 
1.7.9.5


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

* [PATCH BlueZ 13/25] observer: Add Register/UnregisterManufacturerObserver() D-Bus method
  2012-12-21 20:26 [PATCH BlueZ 00/25] Broadcaster/Observer implementation Bruna Moreira
                   ` (11 preceding siblings ...)
  2012-12-21 20:26 ` [PATCH BlueZ 12/25] observer: Add Register/UnregisterServiceObserver() D-Bus method Bruna Moreira
@ 2012-12-21 20:26 ` Bruna Moreira
  2012-12-21 20:26 ` [PATCH BlueZ 14/25] observer: Add watchers and filters for observers Bruna Moreira
                   ` (11 subsequent siblings)
  24 siblings, 0 replies; 26+ messages in thread
From: Bruna Moreira @ 2012-12-21 20:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Bruna Moreira

An observer for Manufacturer Specific Data must be registered using
RegisterManufacturerObserver() D-Bus method so it can receive any
advertising which matches with the filter used. Use
UnregisterManufacturerObserver() D-Bus method for unregistering an
observer avoid stop sending broadcasts to the agent.
---
 src/adapter.c |   35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/src/adapter.c b/src/adapter.c
index a5c23da..60dd54c 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -1204,12 +1204,47 @@ static DBusMessage *unregister_service_observer(DBusConnection *conn,
 static DBusMessage *register_manuf_observer(DBusConnection *conn,
 						DBusMessage *msg, void *data)
 {
+	struct btd_adapter *adapter = data;
+	const char *path, *sender = dbus_message_get_sender(msg);
+	unsigned int company_id;
+	int err;
+
+	if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+					DBUS_TYPE_UINT16, &company_id,
+					DBUS_TYPE_INVALID) == FALSE)
+		return btd_error_invalid_args(msg);
+
+	err = mgmt_set_observer(adapter->dev_id, TRUE);
+	if (err < 0) {
+		error("Failed to set Observer: %s (%d)", strerror(-err), -err);
+
+		return btd_error_failed(msg, strerror(-err));
+	}
+
+	DBG("Manufacturer Specific Data Observer registered for hci%d at %s:%s",
+						adapter->dev_id, sender, path);
+
 	return dbus_message_new_method_return(msg);
 }
 
 static DBusMessage *unregister_manuf_observer(DBusConnection *conn,
 						DBusMessage *msg, void *data)
 {
+	const char *path, *sender = dbus_message_get_sender(msg);
+	struct btd_adapter *adapter = data;
+	int err;
+
+	if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+						DBUS_TYPE_INVALID) == FALSE)
+		return btd_error_invalid_args(msg);
+
+	err = mgmt_set_observer(adapter->dev_id, FALSE);
+	if (err < 0)
+		return btd_error_failed(msg, strerror(-err));
+
+	DBG("Manuf. Specific Data Observer unregistered for hci%d at %s:%s",
+						adapter->dev_id, sender, path);
+
 	return dbus_message_new_method_return(msg);
 }
 
-- 
1.7.9.5


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

* [PATCH BlueZ 14/25] observer: Add watchers and filters for observers
  2012-12-21 20:26 [PATCH BlueZ 00/25] Broadcaster/Observer implementation Bruna Moreira
                   ` (12 preceding siblings ...)
  2012-12-21 20:26 ` [PATCH BlueZ 13/25] observer: Add Register/UnregisterManufacturerObserver() " Bruna Moreira
@ 2012-12-21 20:26 ` Bruna Moreira
  2012-12-21 20:26 ` [PATCH BlueZ 15/25] eir: Add manufacturer and service data fields Bruna Moreira
                   ` (10 subsequent siblings)
  24 siblings, 0 replies; 26+ messages in thread
From: Bruna Moreira @ 2012-12-21 20:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Bruna Moreira

The adapter will keep a list of observers listening for advertising.
The new observer is added on the list when it is registered.

When an observer is registered, the filter must be stored to be used
after receiving a new advertising. The observer will only receive the
data from advertising if the filter matches.
---
 src/adapter.c |  187 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 179 insertions(+), 8 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index 60dd54c..316acb9 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -85,6 +85,11 @@
 #define REMOVE_TEMP_TIMEOUT (3 * 60)
 
 static const char *base_path = "/org/bluez";
+
+/* Filter Types (for Observer) */
+#define FILTER_SERVICE_UUID	0x01
+#define FILTER_COMPANY_IC	0x02
+
 static GSList *adapter_drivers = NULL;
 
 enum session_req_type {
@@ -116,6 +121,16 @@ struct discovery {
 	GSList *found;
 };
 
+struct observer_watcher {
+	struct btd_adapter *adapter;
+	guint id;			/* Listener id */
+	uint8_t filter_type;		/* Filer type: Service or Manufacturer
+					 * data */
+	void *filter_data;		/* Value of filter */
+	char *sender;			/* DBus sender */
+	char *path;			/* DBus path */
+};
+
 struct btd_adapter {
 	uint16_t dev_id;
 	gboolean powered;
@@ -136,6 +151,7 @@ struct btd_adapter {
 	GSList *disc_sessions;		/* Discovery sessions */
 	struct session_req *scanning_session;
 	GSList *connect_list;		/* Devices to connect when found */
+	GSList *observers;		/* Observer watchers */
 	guint discov_id;		/* Discovery timer */
 	struct discovery *discovery;	/* Discovery active */
 	gboolean connecting;		/* Connect active */
@@ -1154,10 +1170,85 @@ static DBusMessage *remove_device(DBusConnection *conn, DBusMessage *msg,
 	return NULL;
 }
 
+static void destroy_observer(gpointer user_data)
+{
+	struct observer_watcher *obs = user_data;
+
+	btd_adapter_unref(obs->adapter);
+
+	g_dbus_remove_watch(btd_get_dbus_connection(), obs->id);
+
+	g_free(obs->path);
+	g_free(obs->sender);
+	g_free(obs);
+}
+
+static gint cmp_observer(gconstpointer a, gconstpointer b)
+{
+	const struct observer_watcher *obs = a;
+	const struct observer_watcher *match = b;
+	int ret;
+
+	ret = g_strcmp0(obs->sender, match->sender);
+	if (ret != 0)
+		return ret;
+
+	ret = g_strcmp0(obs->path, match->path);
+	if (ret != 0)
+		return ret;
+
+	return obs->filter_type - match->filter_type;
+}
+
+static struct observer_watcher *find_observer(GSList *list, const char *sender,
+					const char *path, uint8_t filter)
+{
+	struct observer_watcher *match;
+	GSList *l;
+
+	match = g_new0(struct observer_watcher, 1);
+	match->sender = g_strdup(sender);
+	match->path = g_strdup(path);
+	match->filter_type = filter;
+
+	l = g_slist_find_custom(list, match, cmp_observer);
+	g_free(match->sender);
+	g_free(match->path);
+	g_free(match);
+
+	return l ? l->data : NULL;
+}
+
+static void observer_exit(DBusConnection *conn, void *user_data)
+{
+	struct observer_watcher *obs = user_data;
+	struct btd_adapter *adapter = obs->adapter;
+
+	if (obs->filter_type == FILTER_SERVICE_UUID)
+		DBG("Service Data Observer watcher %s disconnected", obs->path);
+	else
+		DBG("Manufacturer Data Observer watcher %s disconnected",
+								obs->path);
+
+	adapter->observers = g_slist_remove(adapter->observers, obs);
+
+	if (adapter->observers == NULL) {
+		int err;
+
+		err = mgmt_set_observer(adapter->dev_id, FALSE);
+		if (err < 0)
+			error("Failed to set Observer: %s (%d)",
+							strerror(-err), -err);
+	}
+
+	destroy_observer(obs);
+}
+
 static DBusMessage *register_service_observer(DBusConnection *conn,
 						DBusMessage *msg, void *data)
 {
 	struct btd_adapter *adapter = data;
+	struct observer_watcher *obs;
 	const char *path, *sender = dbus_message_get_sender(msg);
 	unsigned int uuid;
 	int err;
@@ -1167,8 +1258,26 @@ static DBusMessage *register_service_observer(DBusConnection *conn,
 					DBUS_TYPE_INVALID) == FALSE)
 		return btd_error_invalid_args(msg);
 
+	obs = find_observer(adapter->observers, sender, path,
+							FILTER_SERVICE_UUID);
+	if (obs)
+		return btd_error_already_exists(msg);
+
+	obs = g_new0(struct observer_watcher, 1);
+	obs->filter_type = FILTER_SERVICE_UUID;
+	obs->filter_data = GUINT_TO_POINTER(uuid);
+	obs->sender = g_strdup(sender);
+	obs->path = g_strdup(path);
+	obs->adapter = btd_adapter_ref(adapter);
+	obs->id = g_dbus_add_disconnect_watch(conn, sender, observer_exit,
+								obs, NULL);
+
+	adapter->observers = g_slist_prepend(adapter->observers, obs);
+
 	err = mgmt_set_observer(adapter->dev_id, TRUE);
 	if (err < 0) {
+		adapter->observers = g_slist_remove(adapter->observers, obs);
+		destroy_observer(obs);
 		error("Failed to set Observer: %s (%d)", strerror(-err), -err);
 
 		return btd_error_failed(msg, strerror(-err));
@@ -1185,15 +1294,28 @@ static DBusMessage *unregister_service_observer(DBusConnection *conn,
 {
 	const char *path, *sender = dbus_message_get_sender(msg);
 	struct btd_adapter *adapter = data;
-	int err;
+	struct observer_watcher *obs;
 
 	if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
 						DBUS_TYPE_INVALID) == FALSE)
 		return btd_error_invalid_args(msg);
 
-	err = mgmt_set_observer(adapter->dev_id, FALSE);
-	if (err < 0)
-		return btd_error_failed(msg, strerror(-err));
+	obs = find_observer(adapter->observers, sender, path,
+							FILTER_SERVICE_UUID);
+	if (obs == NULL)
+		return btd_error_does_not_exist(msg);
+
+	adapter->observers = g_slist_remove(adapter->observers, obs);
+	g_dbus_remove_watch(btd_get_dbus_connection(), obs->id);
+	destroy_observer(obs);
+
+	if (adapter->observers == NULL) {
+		int err;
+
+		err = mgmt_set_observer(adapter->dev_id, FALSE);
+		if (err < 0)
+			return btd_error_failed(msg, strerror(-err));
+	}
 
 	DBG("Service Data Observer unregistered for hci%d at %s:%s",
 						adapter->dev_id, sender, path);
@@ -1205,6 +1327,7 @@ static DBusMessage *register_manuf_observer(DBusConnection *conn,
 						DBusMessage *msg, void *data)
 {
 	struct btd_adapter *adapter = data;
+	struct observer_watcher *obs;
 	const char *path, *sender = dbus_message_get_sender(msg);
 	unsigned int company_id;
 	int err;
@@ -1214,8 +1337,26 @@ static DBusMessage *register_manuf_observer(DBusConnection *conn,
 					DBUS_TYPE_INVALID) == FALSE)
 		return btd_error_invalid_args(msg);
 
+	obs = find_observer(adapter->observers, sender, path,
+							FILTER_COMPANY_IC);
+	if (obs)
+		return btd_error_already_exists(msg);
+
+	obs = g_new0(struct observer_watcher, 1);
+	obs->filter_type = FILTER_COMPANY_IC;
+	obs->filter_data = GUINT_TO_POINTER(company_id);
+	obs->sender = g_strdup(sender);
+	obs->path = g_strdup(path);
+	obs->adapter = btd_adapter_ref(adapter);
+	obs->id = g_dbus_add_disconnect_watch(conn, sender, observer_exit,
+								obs, NULL);
+
+	adapter->observers = g_slist_prepend(adapter->observers, obs);
+
 	err = mgmt_set_observer(adapter->dev_id, TRUE);
 	if (err < 0) {
+		adapter->observers = g_slist_remove(adapter->observers, obs);
+		destroy_observer(obs);
 		error("Failed to set Observer: %s (%d)", strerror(-err), -err);
 
 		return btd_error_failed(msg, strerror(-err));
@@ -1232,15 +1373,28 @@ static DBusMessage *unregister_manuf_observer(DBusConnection *conn,
 {
 	const char *path, *sender = dbus_message_get_sender(msg);
 	struct btd_adapter *adapter = data;
-	int err;
+	struct observer_watcher *obs;
 
 	if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
 						DBUS_TYPE_INVALID) == FALSE)
 		return btd_error_invalid_args(msg);
 
-	err = mgmt_set_observer(adapter->dev_id, FALSE);
-	if (err < 0)
-		return btd_error_failed(msg, strerror(-err));
+	obs = find_observer(adapter->observers, sender, path,
+							FILTER_COMPANY_IC);
+	if (obs == NULL)
+		return btd_error_does_not_exist(msg);
+
+	adapter->observers = g_slist_remove(adapter->observers, obs);
+	g_dbus_remove_watch(btd_get_dbus_connection(), obs->id);
+	destroy_observer(obs);
+
+	if (adapter->observers == NULL) {
+		int err;
+
+		err = mgmt_set_observer(adapter->dev_id, FALSE);
+		if (err < 0)
+			return btd_error_failed(msg, strerror(-err));
+	}
 
 	DBG("Manuf. Specific Data Observer unregistered for hci%d at %s:%s",
 						adapter->dev_id, sender, path);
@@ -2830,6 +2984,21 @@ struct btd_adapter *adapter_create(int id)
 	return btd_adapter_ref(adapter);
 }
 
+static void release_all_obs(struct btd_adapter *adapter)
+{
+	int err;
+
+	if (!adapter->observers)
+		return;
+
+	err = mgmt_set_observer(adapter->dev_id, FALSE);
+	if (err < 0)
+		error("Failed to set Observer: %s (%d)",
+						strerror(-err), -err);
+
+	g_slist_free_full(adapter->observers, destroy_observer);
+}
+
 void adapter_remove(struct btd_adapter *adapter)
 {
 	GSList *l;
@@ -2852,6 +3021,8 @@ void adapter_remove(struct btd_adapter *adapter)
 
 	g_slist_free(adapter->pin_callbacks);
 
+	release_all_obs(adapter);
+
 	if (adapter->powered)
 		mgmt_set_powered(adapter->dev_id, FALSE);
 }
-- 
1.7.9.5


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

* [PATCH BlueZ 15/25] eir: Add manufacturer and service data fields
  2012-12-21 20:26 [PATCH BlueZ 00/25] Broadcaster/Observer implementation Bruna Moreira
                   ` (13 preceding siblings ...)
  2012-12-21 20:26 ` [PATCH BlueZ 14/25] observer: Add watchers and filters for observers Bruna Moreira
@ 2012-12-21 20:26 ` Bruna Moreira
  2012-12-21 20:26 ` [PATCH BlueZ 16/25] observer: Add Service/ManufacturerReceived() D-Bus method Bruna Moreira
                   ` (9 subsequent siblings)
  24 siblings, 0 replies; 26+ messages in thread
From: Bruna Moreira @ 2012-12-21 20:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jefferson Delfes

From: Jefferson Delfes <jefferson.delfes@openbossa.org>

For advertising, there are another possible fields, Service Data and
Manufacturer Specific Data.
---
 src/eir.c |   42 ++++++++++++++++++++++++++++++++++++++++++
 src/eir.h |   16 ++++++++++++++++
 2 files changed, 58 insertions(+)

diff --git a/src/eir.c b/src/eir.c
index 1b6db8c..96adc5c 100644
--- a/src/eir.c
+++ b/src/eir.c
@@ -41,6 +41,22 @@
 
 #define EIR_OOB_MIN (2 + 6)
 
+static void svc_data_free(void *p)
+{
+	struct svc_data *sdata = p;
+
+	g_free(sdata->data);
+	g_free(sdata);
+}
+
+static void manuf_data_free(void *p)
+{
+	struct manuf_data *mdata = p;
+
+	g_free(mdata->data);
+	g_free(mdata);
+}
+
 void eir_data_free(struct eir_data *eir)
 {
 	g_slist_free_full(eir->services, g_free);
@@ -51,6 +67,10 @@ void eir_data_free(struct eir_data *eir)
 	eir->hash = NULL;
 	g_free(eir->randomizer);
 	eir->randomizer = NULL;
+	g_slist_free_full(eir->svcs_data, svc_data_free);
+	eir->svcs_data = NULL;
+	g_slist_free_full(eir->manufs_data, manuf_data_free);
+	eir->manufs_data = NULL;
 }
 
 static void eir_parse_uuid16(struct eir_data *eir, void *data, uint8_t len)
@@ -139,6 +159,8 @@ int eir_parse(struct eir_data *eir, uint8_t *eir_data, uint8_t eir_len)
 	while (len < eir_len - 1) {
 		uint8_t field_len = eir_data[0];
 		uint8_t data_len, *data = &eir_data[2];
+		struct svc_data *sdata;
+		struct manuf_data *mdata;
 
 		/* Check for the end of EIR */
 		if (field_len == 0)
@@ -193,6 +215,16 @@ int eir_parse(struct eir_data *eir, uint8_t *eir_data, uint8_t eir_len)
 							(data[2] << 16);
 			break;
 
+		case EIR_SVC_DATA:
+			if (data_len < 2)
+				break;
+			sdata = g_new(struct svc_data, 1);
+			sdata->uuid = bt_get_le16(data);
+			sdata->data_len = data_len - 2;
+			sdata->data = g_memdup(data + 2, data_len - 2);
+			eir->svcs_data = g_slist_append(eir->svcs_data, sdata);
+			break;
+
 		case EIR_GAP_APPEARANCE:
 			if (data_len < 2)
 				break;
@@ -209,6 +241,16 @@ int eir_parse(struct eir_data *eir, uint8_t *eir_data, uint8_t eir_len)
 			if (data_len < 16)
 				break;
 			eir->randomizer = g_memdup(data, 16);
+
+		case EIR_MANUF_DATA:
+			if (data_len < 2)
+				break;
+			mdata = g_new(struct manuf_data, 1);
+			mdata->company_id = bt_get_le16(data);
+			mdata->data_len = data_len - 2;
+			mdata->data = g_memdup(data + 2, data_len - 2);
+			eir->manufs_data = g_slist_append(eir->manufs_data,
+									mdata);
 			break;
 		}
 
diff --git a/src/eir.h b/src/eir.h
index 91e045e..e410753 100644
--- a/src/eir.h
+++ b/src/eir.h
@@ -36,7 +36,21 @@
 #define EIR_SSP_HASH                0x0E  /* SSP Hash */
 #define EIR_SSP_RANDOMIZER          0x0F  /* SSP Randomizer */
 #define EIR_DEVICE_ID               0x10  /* device ID */
+#define EIR_SVC_DATA                0x16  /* service data */
 #define EIR_GAP_APPEARANCE          0x19  /* GAP appearance */
+#define EIR_MANUF_DATA              0xFF  /* manufacturer specific data */
+
+struct svc_data {
+	uint16_t uuid;
+	uint8_t data_len;
+	uint8_t *data;
+};
+
+struct manuf_data {
+	uint16_t company_id;
+	uint8_t data_len;
+	uint8_t *data;
+};
 
 struct eir_data {
 	GSList *services;
@@ -48,6 +62,8 @@ struct eir_data {
 	uint8_t *hash;
 	uint8_t *randomizer;
 	bdaddr_t addr;
+	GSList *svcs_data;
+	GSList *manufs_data;
 };
 
 void eir_data_free(struct eir_data *eir);
-- 
1.7.9.5


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

* [PATCH BlueZ 16/25] observer: Add Service/ManufacturerReceived() D-Bus method
  2012-12-21 20:26 [PATCH BlueZ 00/25] Broadcaster/Observer implementation Bruna Moreira
                   ` (14 preceding siblings ...)
  2012-12-21 20:26 ` [PATCH BlueZ 15/25] eir: Add manufacturer and service data fields Bruna Moreira
@ 2012-12-21 20:26 ` Bruna Moreira
  2012-12-21 20:26 ` [PATCH BlueZ 17/25] observer: Add python test script Bruna Moreira
                   ` (8 subsequent siblings)
  24 siblings, 0 replies; 26+ messages in thread
From: Bruna Moreira @ 2012-12-21 20:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Bruna Moreira

When an advertising matches with the filter registered in
RegisterServiceObserver() or RegisterManufacturerObserver(), the data is
sent to all observers registered using ServiceReceived() or
ManufacturerReceived(), respectively.
---
 src/adapter.c |  117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 116 insertions(+), 1 deletion(-)

diff --git a/src/adapter.c b/src/adapter.c
index 316acb9..4fc4fa9 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -86,6 +86,8 @@
 
 static const char *base_path = "/org/bluez";
 
+#define OBSERVER_INTERFACE "org.bluez.Observer1"
+
 /* Filter Types (for Observer) */
 #define FILTER_SERVICE_UUID	0x01
 #define FILTER_COMPANY_IC	0x02
@@ -180,6 +182,11 @@ struct btd_adapter {
 
 static gboolean process_auth_queue(gpointer user_data);
 
+struct broadcast_data {
+	struct eir_data *eir_data;
+	char peer_addr[18];
+};
+
 int btd_adapter_set_class(struct btd_adapter *adapter, uint8_t major,
 							uint8_t minor)
 {
@@ -3179,6 +3186,106 @@ static gboolean connect_pending_cb(gpointer user_data)
 	return FALSE;
 }
 
+static void service_received(struct observer_watcher *obs, char *peer_addr,
+							struct svc_data *sdata)
+{
+	const char *paddr = peer_addr;
+	DBusMessage *msg;
+
+	msg = dbus_message_new_method_call(obs->sender, obs->path,
+							OBSERVER_INTERFACE,
+							"ServiceReceived");
+	if (msg == NULL) {
+		error("Unable to allocate new ServiceReceived method");
+		return;
+	}
+
+	dbus_message_append_args(msg, DBUS_TYPE_STRING, &paddr,
+						DBUS_TYPE_UINT16, &sdata->uuid,
+						DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+						&sdata->data, sdata->data_len,
+						DBUS_TYPE_INVALID);
+
+	dbus_message_set_no_reply(msg, TRUE);
+	g_dbus_send_message(btd_get_dbus_connection(), msg);
+}
+
+static void manufacturer_received(struct observer_watcher *obs,
+				char *peer_addr, struct manuf_data *mdata)
+{
+	const char *paddr = peer_addr;
+	DBusMessage *msg;
+
+	msg = dbus_message_new_method_call(obs->sender, obs->path,
+							OBSERVER_INTERFACE,
+							"ManufacturerReceived");
+	if (msg == NULL) {
+		error("Unable to allocate new ManufacturerReceived method");
+		return;
+	}
+
+	dbus_message_append_args(msg, DBUS_TYPE_STRING, &paddr,
+					DBUS_TYPE_UINT16, &mdata->company_id,
+					DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+					&mdata->data, mdata->data_len,
+					DBUS_TYPE_INVALID);
+
+	dbus_message_set_no_reply(msg, TRUE);
+	g_dbus_send_message(btd_get_dbus_connection(), msg);
+}
+
+static void update_observer(gpointer data, gpointer user_data)
+{
+	struct observer_watcher *obs = data;
+	struct broadcast_data *bdata = user_data;
+	struct eir_data *eir = bdata->eir_data;
+	GSList *l;
+
+	if (obs->filter_type == FILTER_SERVICE_UUID) {
+		for (l = eir->svcs_data; l != NULL; l = g_slist_next(l)) {
+			struct svc_data *sdata = l->data;
+			uint16_t uuid = GPOINTER_TO_UINT(obs->filter_data);
+
+			if (uuid == sdata->uuid)
+				service_received(obs, bdata->peer_addr, sdata);
+		}
+	} else if (obs->filter_type == FILTER_COMPANY_IC) {
+		for (l = eir->manufs_data; l != NULL; l = g_slist_next(l)) {
+			struct manuf_data *mdata = l->data;
+			uint16_t company_id =
+					GPOINTER_TO_UINT(obs->filter_data);
+
+			if (company_id == mdata->company_id)
+				manufacturer_received(obs, bdata->peer_addr,
+									mdata);
+		}
+	}
+}
+
+static void adapter_broadcast_received(struct btd_adapter *adapter,
+			const bdaddr_t *bdaddr, struct eir_data *eir_data)
+{
+	struct broadcast_data *bdata;
+
+	/* No observers listening for advertising */
+	if (adapter->observers == NULL)
+		return;
+
+	/* No service/manufacturer data was sent */
+	if (eir_data->svcs_data == NULL && eir_data->manufs_data == NULL)
+		return;
+
+	bdata = g_new(struct broadcast_data, 1);
+	bdata->eir_data = eir_data;
+	ba2str(bdaddr, bdata->peer_addr);
+
+	DBG("Broadcast received from %s", bdata->peer_addr);
+
+	g_slist_foreach(adapter->observers, update_observer, bdata);
+
+	g_free(bdata);
+}
+
 void adapter_update_found_devices(struct btd_adapter *adapter,
 					const bdaddr_t *bdaddr,
 					uint8_t bdaddr_type, int8_t rssi,
@@ -3192,7 +3299,7 @@ void adapter_update_found_devices(struct btd_adapter *adapter,
 	int err;
 	GSList *l;
 
-	if (!discovery) {
+	if (!discovery && !adapter->observers) {
 		error("Device found event while no discovery in progress");
 		return;
 	}
@@ -3204,6 +3311,14 @@ void adapter_update_found_devices(struct btd_adapter *adapter,
 		return;
 	}
 
+	/* Send advertising to observers */
+	adapter_broadcast_received(adapter, bdaddr, &eir_data);
+
+	if (!discovery) {
+		eir_data_free(&eir_data);
+		return;
+	}
+
 	if (eir_data.name != NULL && eir_data.name_complete)
 		adapter_store_cached_name(&adapter->bdaddr, bdaddr,
 								eir_data.name);
-- 
1.7.9.5


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

* [PATCH BlueZ 17/25] observer: Add python test script
  2012-12-21 20:26 [PATCH BlueZ 00/25] Broadcaster/Observer implementation Bruna Moreira
                   ` (15 preceding siblings ...)
  2012-12-21 20:26 ` [PATCH BlueZ 16/25] observer: Add Service/ManufacturerReceived() D-Bus method Bruna Moreira
@ 2012-12-21 20:26 ` Bruna Moreira
  2012-12-21 20:26 ` [PATCH BlueZ 18/25] adapter: Add D-Bus API for Broadcaster GAP Role Bruna Moreira
                   ` (7 subsequent siblings)
  24 siblings, 0 replies; 26+ messages in thread
From: Bruna Moreira @ 2012-12-21 20:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Bruna Moreira

---
 test/test-observer |   75 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 75 insertions(+)
 create mode 100755 test/test-observer

diff --git a/test/test-observer b/test/test-observer
new file mode 100755
index 0000000..04d3f05
--- /dev/null
+++ b/test/test-observer
@@ -0,0 +1,75 @@
+#!/usr/bin/python
+
+'''Observer test script
+'''
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+from gi.repository import GObject
+
+import sys
+import dbus
+import dbus.service
+import dbus.mainloop.glib
+from optparse import OptionParser, make_option
+import bluezutils
+
+def dbus_data(data):
+	return "".join(["%02x" % c for c in data])
+
+class Observer(dbus.service.Object):
+	@dbus.service.method("org.bluez.Observer1",
+					in_signature="sqay", out_signature="")
+	def ServiceReceived(self, address, uuid, value):
+		print("[ " + address + " ]")
+		print("    Service UUID = 0x%04x" % int(uuid))
+		print("    Data = %s" % dbus_data(value))
+		print()
+
+	@dbus.service.method("org.bluez.Observer1",
+					in_signature="sqay", out_signature="")
+	def ManufacturerReceived(self, address, cid, value):
+		print("[ " + address + " ]")
+		print("    Company ID = 0x%04x" % int(cid))
+		print("    Data = %s" % dbus_data(value))
+		print()
+
+if __name__ == "__main__":
+	dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+	bus = dbus.SystemBus()
+
+	manager = dbus.Interface(bus.get_object("org.bluez", "/"),
+					"org.bluez.Manager")
+
+	option_list = [
+		make_option("-i", "--adapter", action="store",
+			type="string", dest="adapter"),
+		make_option("-s", "--service", action="store",
+			type="int", dest="service_uuid",
+			help="Service UUID (e.g. \"0x0001\")"),
+		make_option("-c", "--company", action="store",
+			type="int", dest="company_id",
+			help="Company Identifier Code (e.g. \"0x0002\")"),
+		]
+
+	parser = OptionParser(option_list=option_list)
+
+	(options, args) = parser.parse_args()
+
+	if not options.service_uuid and not options.company_id:
+		parser.error("At least one option is required: -c or -s")
+
+	adapter = bluezutils.find_adapter(options.adapter)
+
+	path = "/test/observer"
+	observer = Observer(bus, path)
+
+	if options.service_uuid:
+		adapter.RegisterServiceObserver(path, dbus.UInt16(options.service_uuid))
+
+	if options.company_id:
+		adapter.RegisterManufacturerObserver(path, dbus.UInt16(options.company_id))
+
+	mainloop = GObject.MainLoop()
+	mainloop.run()
-- 
1.7.9.5


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

* [PATCH BlueZ 18/25] adapter: Add D-Bus API for Broadcaster GAP Role
  2012-12-21 20:26 [PATCH BlueZ 00/25] Broadcaster/Observer implementation Bruna Moreira
                   ` (16 preceding siblings ...)
  2012-12-21 20:26 ` [PATCH BlueZ 17/25] observer: Add python test script Bruna Moreira
@ 2012-12-21 20:26 ` Bruna Moreira
  2012-12-21 20:26 ` [PATCH BlueZ 19/25] lib: Maximum value to advertising and scan response Bruna Moreira
                   ` (6 subsequent siblings)
  24 siblings, 0 replies; 26+ messages in thread
From: Bruna Moreira @ 2012-12-21 20:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jefferson Delfes

From: Jefferson Delfes <jefferson.delfes@openbossa.org>

Implement dummy calls for register or unregister Broadcaster.
---
 src/adapter.c |   27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/src/adapter.c b/src/adapter.c
index 4fc4fa9..90aab94 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -1413,6 +1413,24 @@ void adapter_set_controller_data_failed(struct btd_adapter *adapter)
 {
 }
 
+static DBusMessage *set_service_data(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *set_manufacturer_data(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *clear_broadcast_data(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	return dbus_message_new_method_return(msg);
+}
+
 static const GDBusMethodTable adapter_methods[] = {
 	{ GDBUS_METHOD("StartDiscovery", NULL, NULL,
 			adapter_start_discovery) },
@@ -1435,6 +1453,15 @@ static const GDBusMethodTable adapter_methods[] = {
 	{ GDBUS_METHOD("UnregisterManufacturerObserver",
 			GDBUS_ARGS({ "observer", "o" }), NULL,
 			unregister_manuf_observer) },
+	{ GDBUS_ASYNC_METHOD("SetServiceData", GDBUS_ARGS({ "uuid", "q" },
+			{ "data", "ay" }), NULL,
+			set_service_data) },
+	{ GDBUS_ASYNC_METHOD("SetManufacturerData",
+			GDBUS_ARGS({ "company_id", "q" },
+			{ "data", "ay" }), NULL,
+			set_manufacturer_data) },
+	{ GDBUS_METHOD("ClearBroadcastData", NULL, NULL,
+			clear_broadcast_data) },
 	{ }
 };
 
-- 
1.7.9.5


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

* [PATCH BlueZ 19/25] lib: Maximum value to advertising and scan response
  2012-12-21 20:26 [PATCH BlueZ 00/25] Broadcaster/Observer implementation Bruna Moreira
                   ` (17 preceding siblings ...)
  2012-12-21 20:26 ` [PATCH BlueZ 18/25] adapter: Add D-Bus API for Broadcaster GAP Role Bruna Moreira
@ 2012-12-21 20:26 ` Bruna Moreira
  2012-12-21 20:26 ` [PATCH BlueZ 20/25] broadcaster: Add SetService/ManufacturerData() D-Bus method Bruna Moreira
                   ` (5 subsequent siblings)
  24 siblings, 0 replies; 26+ messages in thread
From: Bruna Moreira @ 2012-12-21 20:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Bruna Moreira

Create a constant to define the maximum lenght for advertising and scan
response data format.
---
 lib/hci.h |    6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/lib/hci.h b/lib/hci.h
index 56c9316..bce6b41 100644
--- a/lib/hci.h
+++ b/lib/hci.h
@@ -1505,17 +1505,19 @@ typedef struct {
 } __attribute__ ((packed)) le_read_advertising_channel_tx_power_rp;
 #define LE_READ_ADVERTISING_CHANNEL_TX_POWER_RP_SIZE 2
 
+#define HCI_LE_MAX_ADV_DATA_LENGTH		31
+
 #define OCF_LE_SET_ADVERTISING_DATA		0x0008
 typedef struct {
 	uint8_t		length;
-	uint8_t		data[31];
+	uint8_t		data[HCI_LE_MAX_ADV_DATA_LENGTH];
 } __attribute__ ((packed)) le_set_advertising_data_cp;
 #define LE_SET_ADVERTISING_DATA_CP_SIZE 32
 
 #define OCF_LE_SET_SCAN_RESPONSE_DATA		0x0009
 typedef struct {
 	uint8_t		length;
-	uint8_t		data[31];
+	uint8_t		data[HCI_LE_MAX_ADV_DATA_LENGTH];
 } __attribute__ ((packed)) le_set_scan_response_data_cp;
 #define LE_SET_SCAN_RESPONSE_DATA_CP_SIZE 32
 
-- 
1.7.9.5


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

* [PATCH BlueZ 20/25] broadcaster: Add SetService/ManufacturerData() D-Bus method
  2012-12-21 20:26 [PATCH BlueZ 00/25] Broadcaster/Observer implementation Bruna Moreira
                   ` (18 preceding siblings ...)
  2012-12-21 20:26 ` [PATCH BlueZ 19/25] lib: Maximum value to advertising and scan response Bruna Moreira
@ 2012-12-21 20:26 ` Bruna Moreira
  2012-12-21 20:26 ` [PATCH BlueZ 21/25] broadcaster: Add list of broadcaster sessions Bruna Moreira
                   ` (4 subsequent siblings)
  24 siblings, 0 replies; 26+ messages in thread
From: Bruna Moreira @ 2012-12-21 20:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jefferson Delfes

From: Jefferson Delfes <jefferson.delfes@openbossa.org>

For SetServiceData(), receive the service UUID with advertising data
that will be set in device.

For SetManufacturerData(), receive the Company Identifier Code with
advertising data that will be set in device.
---
 src/adapter.c |   34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/src/adapter.c b/src/adapter.c
index 90aab94..60c0697 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -1416,12 +1416,46 @@ void adapter_set_controller_data_failed(struct btd_adapter *adapter)
 static DBusMessage *set_service_data(DBusConnection *conn,
 						DBusMessage *msg, void *data)
 {
+	struct btd_adapter *adapter = data;
+	const char *sender;
+	uint16_t uuid;
+	uint8_t *sdata;
+	int ssize;
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT16, &uuid,
+						DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+						&sdata, &ssize,
+						DBUS_TYPE_INVALID))
+		return btd_error_invalid_args(msg);
+
+	sender = dbus_message_get_sender(msg);
+
+	DBG("Service Data Broadcaster registered for hci%d at %s",
+						adapter->dev_id, sender);
+
 	return dbus_message_new_method_return(msg);
 }
 
 static DBusMessage *set_manufacturer_data(DBusConnection *conn,
 						DBusMessage *msg, void *data)
 {
+	struct btd_adapter *adapter = data;
+	const char *sender;
+	uint16_t company_id;
+	uint8_t *mdata;
+	int msize;
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT16, &company_id,
+						DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+						&mdata, &msize,
+						DBUS_TYPE_INVALID))
+		return btd_error_invalid_args(msg);
+
+	sender = dbus_message_get_sender(msg);
+
+	DBG("Manufacturer Specific Data Broadcaster registered for hci%d at %s",
+						adapter->dev_id, sender);
+
 	return dbus_message_new_method_return(msg);
 }
 
-- 
1.7.9.5


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

* [PATCH BlueZ 21/25] broadcaster: Add list of broadcaster sessions
  2012-12-21 20:26 [PATCH BlueZ 00/25] Broadcaster/Observer implementation Bruna Moreira
                   ` (19 preceding siblings ...)
  2012-12-21 20:26 ` [PATCH BlueZ 20/25] broadcaster: Add SetService/ManufacturerData() D-Bus method Bruna Moreira
@ 2012-12-21 20:26 ` Bruna Moreira
  2012-12-21 20:26 ` [PATCH BlueZ 22/25] broadcaster: Build and send ADV/EIR data blob to kernel Bruna Moreira
                   ` (3 subsequent siblings)
  24 siblings, 0 replies; 26+ messages in thread
From: Bruna Moreira @ 2012-12-21 20:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jefferson Delfes

From: Jefferson Delfes <jefferson.delfes@openbossa.org>

The adapter will keep a list of broadcasters which set new advertising
data values. The new broadcaster is added to the list when the function
SetServiceData() or SetManufacturerData() is called.
---
 src/adapter.c |  159 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/eir.h     |    3 ++
 2 files changed, 162 insertions(+)

diff --git a/src/adapter.c b/src/adapter.c
index 60c0697..7e0f2b5 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -133,6 +133,18 @@ struct observer_watcher {
 	char *path;			/* DBus path */
 };
 
+struct bcast_session {
+	struct btd_adapter	*adapter;
+	DBusMessage		*msg;
+	guint			id;
+	char			*owner;
+	uint8_t			data_type;
+	uint16_t		data_id;
+	uint8_t			data_len;
+	/* Reserve 2 octets for ServiceUUID/CompanyId */
+	uint8_t			data[EIR_DATA_MAX_LEN - sizeof(uint16_t)];
+};
+
 struct btd_adapter {
 	uint16_t dev_id;
 	gboolean powered;
@@ -154,6 +166,7 @@ struct btd_adapter {
 	struct session_req *scanning_session;
 	GSList *connect_list;		/* Devices to connect when found */
 	GSList *observers;		/* Observer watchers */
+	GSList *bcast_sessions;		/* Broadcast sessions */
 	guint discov_id;		/* Discovery timer */
 	struct discovery *discovery;	/* Discovery active */
 	gboolean connecting;		/* Connect active */
@@ -1409,6 +1422,81 @@ static DBusMessage *unregister_manuf_observer(DBusConnection *conn,
 	return dbus_message_new_method_return(msg);
 }
 
+static void free_bcast_session(gpointer user_data)
+{
+	struct bcast_session *session = user_data;
+
+	btd_adapter_unref(session->adapter);
+	if (session->msg)
+		dbus_message_unref(session->msg);
+
+	g_dbus_remove_watch(btd_get_dbus_connection(), session->id);
+
+	g_free(session->owner);
+	g_free(session);
+}
+
+static gint cmp_bcast_session(gconstpointer a, gconstpointer b)
+{
+	const struct bcast_session *session = a;
+	const struct bcast_session *match = b;
+	int ret;
+
+	ret = g_strcmp0(session->owner, match->owner);
+	if (ret)
+		return ret;
+
+	ret = session->data_type - match->data_type;
+	if (ret)
+		return ret;
+
+	return session->data_id - match->data_id;
+}
+
+static struct bcast_session *find_bcast_session(GSList *list,
+			const char *sender, uint8_t type, uint16_t data_id)
+{
+	struct bcast_session *match;
+	GSList *l;
+
+	match = g_new0(struct bcast_session, 1);
+	match->owner = g_strdup(sender);
+	match->data_type = type;
+	match->data_id = data_id;
+
+	l = g_slist_find_custom(list, match, cmp_bcast_session);
+	g_free(match->owner);
+	g_free(match);
+
+	return l ? l->data : NULL;
+}
+
+static void bcast_session_exit(DBusConnection *conn, void *user_data)
+{
+	struct bcast_session *session = user_data;
+	struct btd_adapter *adapter = session->adapter;
+	uint8_t type = session->data_type;
+
+	if (type == EIR_SVC_DATA)
+		DBG("Service Data Broadcaster watcher %s disconnected",
+								session->owner);
+	else
+		DBG("Manufacturer Data Broadcasterer watcher %s disconnected",
+								session->owner);
+
+	adapter->bcast_sessions = g_slist_remove(adapter->bcast_sessions,
+								session);
+	free_bcast_session(session);
+
+	/* FIXME: Stop advertising, send data blob from others apps to kernel
+	 * with same type and restart advertising*/
+}
+
+static void update_adv_data(struct btd_adapter *adapter,
+		struct bcast_session *session, uint8_t *data, int size)
+{
+}
+
 void adapter_set_controller_data_failed(struct btd_adapter *adapter)
 {
 }
@@ -1417,6 +1505,7 @@ static DBusMessage *set_service_data(DBusConnection *conn,
 						DBusMessage *msg, void *data)
 {
 	struct btd_adapter *adapter = data;
+	struct bcast_session *session;
 	const char *sender;
 	uint16_t uuid;
 	uint8_t *sdata;
@@ -1430,9 +1519,30 @@ static DBusMessage *set_service_data(DBusConnection *conn,
 
 	sender = dbus_message_get_sender(msg);
 
+	session = find_bcast_session(adapter->bcast_sessions, sender,
+							EIR_SVC_DATA, uuid);
+	if (session) {
+		update_adv_data(adapter, session, sdata, ssize);
+		goto done;
+	}
+
+	session = g_new(struct bcast_session, 1);
+	session->data_id = uuid;
+	session->owner = g_strdup(sender);
+	session->adapter = btd_adapter_ref(adapter);
+	session->data_type = EIR_SVC_DATA;
+	session->msg = dbus_message_ref(msg);
+	session->id = g_dbus_add_disconnect_watch(conn, sender,
+						bcast_session_exit, session,
+						NULL);
+
+	adapter->bcast_sessions = g_slist_prepend(adapter->bcast_sessions,
+								session);
+
 	DBG("Service Data Broadcaster registered for hci%d at %s",
 						adapter->dev_id, sender);
 
+done:
 	return dbus_message_new_method_return(msg);
 }
 
@@ -1440,6 +1550,7 @@ static DBusMessage *set_manufacturer_data(DBusConnection *conn,
 						DBusMessage *msg, void *data)
 {
 	struct btd_adapter *adapter = data;
+	struct bcast_session *session;
 	const char *sender;
 	uint16_t company_id;
 	uint8_t *mdata;
@@ -1453,9 +1564,30 @@ static DBusMessage *set_manufacturer_data(DBusConnection *conn,
 
 	sender = dbus_message_get_sender(msg);
 
+	session = find_bcast_session(adapter->bcast_sessions, sender,
+						EIR_MANUF_DATA, company_id);
+	if (session != NULL) {
+		update_adv_data(adapter, session, mdata, msize);
+		goto done;
+	}
+
+	session = g_new(struct bcast_session, 1);
+	session->data_id = company_id;
+	session->owner = g_strdup(sender);
+	session->adapter = btd_adapter_ref(adapter);
+	session->data_type = EIR_MANUF_DATA;
+	session->msg = dbus_message_ref(msg);
+	session->id = g_dbus_add_disconnect_watch(conn, sender,
+						bcast_session_exit, session,
+						NULL);
+
+	adapter->bcast_sessions = g_slist_prepend(adapter->bcast_sessions,
+								session);
+
 	DBG("Manufacturer Specific Data Broadcaster registered for hci%d at %s",
 						adapter->dev_id, sender);
 
+done:
 	return dbus_message_new_method_return(msg);
 }
 
@@ -3067,6 +3199,31 @@ static void release_all_obs(struct btd_adapter *adapter)
 	g_slist_free_full(adapter->observers, destroy_observer);
 }
 
+static void release_all_bcast(struct btd_adapter *adapter)
+{
+	int err;
+
+	if (!adapter->bcast_sessions)
+		return;
+
+	err = mgmt_set_broadcaster(adapter->dev_id, FALSE);
+	if (err < 0)
+		error("Failed to set Broadcaster: %s (%d)", strerror(-err),
+									-err);
+
+	err = mgmt_unset_controller_data(adapter->dev_id, EIR_SVC_DATA);
+	if (err < 0)
+		error("Failed to unset service data: %s (%d)", strerror(-err),
+									-err);
+
+	err = mgmt_unset_controller_data(adapter->dev_id, EIR_MANUF_DATA);
+	if (err < 0)
+		error("Failed to unset manufacturer spcific data: %s (%d)",
+							strerror(-err), -err);
+
+	g_slist_free_full(adapter->bcast_sessions, free_bcast_session);
+}
+
 void adapter_remove(struct btd_adapter *adapter)
 {
 	GSList *l;
@@ -3091,6 +3248,8 @@ void adapter_remove(struct btd_adapter *adapter)
 
 	release_all_obs(adapter);
 
+	release_all_bcast(adapter);
+
 	if (adapter->powered)
 		mgmt_set_powered(adapter->dev_id, FALSE);
 }
diff --git a/src/eir.h b/src/eir.h
index e410753..9fb0ba1 100644
--- a/src/eir.h
+++ b/src/eir.h
@@ -40,6 +40,9 @@
 #define EIR_GAP_APPEARANCE          0x19  /* GAP appearance */
 #define EIR_MANUF_DATA              0xFF  /* manufacturer specific data */
 
+/* Reserve 2 octets for length and data type */
+#define EIR_DATA_MAX_LEN            (HCI_LE_MAX_ADV_DATA_LENGTH - 2)
+
 struct svc_data {
 	uint16_t uuid;
 	uint8_t data_len;
-- 
1.7.9.5


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

* [PATCH BlueZ 22/25] broadcaster: Build and send ADV/EIR data blob to kernel
  2012-12-21 20:26 [PATCH BlueZ 00/25] Broadcaster/Observer implementation Bruna Moreira
                   ` (20 preceding siblings ...)
  2012-12-21 20:26 ` [PATCH BlueZ 21/25] broadcaster: Add list of broadcaster sessions Bruna Moreira
@ 2012-12-21 20:26 ` Bruna Moreira
  2012-12-21 20:26 ` [PATCH BlueZ 23/25] broadcaster: Add ClearBroadcastData() D-Bus method Bruna Moreira
                   ` (2 subsequent siblings)
  24 siblings, 0 replies; 26+ messages in thread
From: Bruna Moreira @ 2012-12-21 20:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Bruna Moreira

SetServiceData() and SetManufacturerData() operations will save all data
and send the ADV/EIR data to kernel. The new ADV/EIR data will be added
to the current one.

Note: For now, the maximum ADV/EIR data length is limited to 27
(HCI_LE_MAX_ADV_DATA_LENGTH - 4) octets. This is needed to reserve 2
octets for length and data type and more 2 octets for UUID/CompanyID. If
the ADV/EIR data from new broadcaster session tries to insert more
octets than 27 bytes the operation will fail.
---
 src/adapter.c |  130 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 119 insertions(+), 11 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index 7e0f2b5..45471dc 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -92,6 +92,9 @@ static const char *base_path = "/org/bluez";
 #define FILTER_SERVICE_UUID	0x01
 #define FILTER_COMPANY_IC	0x02
 
+/* Flags for Broadcaster */
+#define BCAST_DATA_NORMAL_PRIORITY	0x00
+
 static GSList *adapter_drivers = NULL;
 
 enum session_req_type {
@@ -601,6 +604,31 @@ void adapter_name_changed(struct btd_adapter *adapter, const char *name)
 
 void adapter_set_controller_data_complete(struct btd_adapter *adapter)
 {
+	struct bcast_session *session = adapter->bcast_sessions->data;
+	DBusMessage *msg = session->msg;
+	DBusMessage *reply;
+	int err;
+
+	if (!adapter->bcast_sessions)
+		error("No Broadcaster session running");
+
+	err = mgmt_set_broadcaster(adapter->dev_id, TRUE);
+	if (err < 0) {
+		error("Failed to set Broadcaster: %s (%d)", strerror(-err),
+									-err);
+		reply = btd_error_failed(msg, strerror(-err));
+	} else
+		reply = dbus_message_new_method_return(msg);
+
+
+	if (session->data_type == EIR_SVC_DATA)
+		DBG("Service Data Broadcaster registered for hci%d at %s",
+					adapter->dev_id, session->owner);
+	else
+		DBG("Manufacturer Data Broadcaster registered for hci%d at %s",
+					adapter->dev_id, session->owner);
+
+	g_dbus_send_message(btd_get_dbus_connection(), reply);
 }
 
 int adapter_set_name(struct btd_adapter *adapter, const char *name)
@@ -1471,6 +1499,53 @@ static struct bcast_session *find_bcast_session(GSList *list,
 	return l ? l->data : NULL;
 }
 
+static void send_advdata_blob(struct btd_adapter *adapter,
+						struct bcast_session *session)
+{
+	uint8_t data[EIR_DATA_MAX_LEN];
+	uint16_t *u16 = (void *) data;
+	int err;
+
+	bt_put_unaligned(htobs(session->data_id), u16);
+	memcpy(data + sizeof(session->data_id), session->data,
+							session->data_len);
+
+	err = mgmt_set_controller_data(adapter->dev_id,
+				BCAST_DATA_NORMAL_PRIORITY,
+				session->data_type, data,
+				session->data_len + sizeof(session->data_id));
+	if (err < 0)
+		error("Failed to set controller data in Broadcaster: %s (%d)",
+							strerror(-err), -err);
+}
+
+static void restore_bcast_type(struct btd_adapter *adapter, uint8_t type)
+{
+	GSList *l;
+	int err;
+
+	err = mgmt_unset_controller_data(adapter->dev_id, type);
+	if (err < 0) {
+		error("Failed to unset controller data: %s (%d)",
+							strerror(-err), -err);
+		return;
+	}
+
+	for (l = adapter->bcast_sessions; l; l = g_slist_next(l)) {
+		struct bcast_session *session = l->data;
+
+		if (session->data_type == type)
+			send_advdata_blob(adapter, session);
+	}
+
+	if (!adapter->bcast_sessions) {
+		err = mgmt_set_broadcaster(adapter->dev_id, FALSE);
+		if (err < 0)
+			error("Failed to set Broadcaster: %s (%d)",
+							strerror(-err), -err);
+	}
+}
+
 static void bcast_session_exit(DBusConnection *conn, void *user_data)
 {
 	struct bcast_session *session = user_data;
@@ -1486,10 +1561,10 @@ static void bcast_session_exit(DBusConnection *conn, void *user_data)
 
 	adapter->bcast_sessions = g_slist_remove(adapter->bcast_sessions,
 								session);
-	free_bcast_session(session);
 
-	/* FIXME: Stop advertising, send data blob from others apps to kernel
-	 * with same type and restart advertising*/
+	restore_bcast_type(adapter, type);
+
+	free_bcast_session(session);
 }
 
 static void update_adv_data(struct btd_adapter *adapter,
@@ -1499,6 +1574,21 @@ static void update_adv_data(struct btd_adapter *adapter,
 
 void adapter_set_controller_data_failed(struct btd_adapter *adapter)
 {
+	struct bcast_session *session = adapter->bcast_sessions->data;
+	DBusMessage *msg = session->msg;
+	DBusMessage *reply;
+
+	DBG("Manufacturer Specific Data Broadcaster failed for hci%d at %s",
+					adapter->dev_id, session->owner);
+
+	reply = btd_error_failed(msg,
+				"Broadcaster: No resources, data too long");
+	g_dbus_send_message(btd_get_dbus_connection(), reply);
+
+	adapter->bcast_sessions = g_slist_remove(adapter->bcast_sessions,
+								session);
+
+	free_bcast_session(session);
 }
 
 static DBusMessage *set_service_data(DBusConnection *conn,
@@ -1517,6 +1607,12 @@ static DBusMessage *set_service_data(DBusConnection *conn,
 						DBUS_TYPE_INVALID))
 		return btd_error_invalid_args(msg);
 
+	/* It will accept new ADV/EIR data only if there is space for complete
+	 * data. Reserve 2 octets for Service UUID */
+	if (ssize + sizeof(uint16_t) > EIR_DATA_MAX_LEN)
+		return btd_error_failed(msg,
+				"ADV/EIR data is bigger than permitted");
+
 	sender = dbus_message_get_sender(msg);
 
 	session = find_bcast_session(adapter->bcast_sessions, sender,
@@ -1528,22 +1624,25 @@ static DBusMessage *set_service_data(DBusConnection *conn,
 
 	session = g_new(struct bcast_session, 1);
 	session->data_id = uuid;
+	session->data_len = ssize;
 	session->owner = g_strdup(sender);
 	session->adapter = btd_adapter_ref(adapter);
 	session->data_type = EIR_SVC_DATA;
 	session->msg = dbus_message_ref(msg);
+
+	memcpy(session->data, sdata, ssize);
+
 	session->id = g_dbus_add_disconnect_watch(conn, sender,
 						bcast_session_exit, session,
 						NULL);
 
+	send_advdata_blob(adapter, session);
+
 	adapter->bcast_sessions = g_slist_prepend(adapter->bcast_sessions,
 								session);
 
-	DBG("Service Data Broadcaster registered for hci%d at %s",
-						adapter->dev_id, sender);
-
 done:
-	return dbus_message_new_method_return(msg);
+	return NULL;
 }
 
 static DBusMessage *set_manufacturer_data(DBusConnection *conn,
@@ -1562,6 +1661,12 @@ static DBusMessage *set_manufacturer_data(DBusConnection *conn,
 						DBUS_TYPE_INVALID))
 		return btd_error_invalid_args(msg);
 
+	/* It will accept new ADV/EIR data only if there is space for complete
+	 * data. Reserve 2 octets for Company Identifier Code */
+	if (msize + sizeof(uint16_t) > EIR_DATA_MAX_LEN)
+		return btd_error_failed(msg,
+				"ADV/EIR data is bigger than permitted");
+
 	sender = dbus_message_get_sender(msg);
 
 	session = find_bcast_session(adapter->bcast_sessions, sender,
@@ -1573,22 +1678,25 @@ static DBusMessage *set_manufacturer_data(DBusConnection *conn,
 
 	session = g_new(struct bcast_session, 1);
 	session->data_id = company_id;
+	session->data_len = msize;
 	session->owner = g_strdup(sender);
 	session->adapter = btd_adapter_ref(adapter);
 	session->data_type = EIR_MANUF_DATA;
 	session->msg = dbus_message_ref(msg);
+
+	memcpy(session->data, mdata, msize);
+
 	session->id = g_dbus_add_disconnect_watch(conn, sender,
 						bcast_session_exit, session,
 						NULL);
 
+	send_advdata_blob(adapter, session);
+
 	adapter->bcast_sessions = g_slist_prepend(adapter->bcast_sessions,
 								session);
 
-	DBG("Manufacturer Specific Data Broadcaster registered for hci%d at %s",
-						adapter->dev_id, sender);
-
 done:
-	return dbus_message_new_method_return(msg);
+	return NULL;
 }
 
 static DBusMessage *clear_broadcast_data(DBusConnection *conn,
-- 
1.7.9.5


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

* [PATCH BlueZ 23/25] broadcaster: Add ClearBroadcastData() D-Bus method
  2012-12-21 20:26 [PATCH BlueZ 00/25] Broadcaster/Observer implementation Bruna Moreira
                   ` (21 preceding siblings ...)
  2012-12-21 20:26 ` [PATCH BlueZ 22/25] broadcaster: Build and send ADV/EIR data blob to kernel Bruna Moreira
@ 2012-12-21 20:26 ` Bruna Moreira
  2012-12-21 20:26 ` [PATCH BlueZ 24/25] broadcaster: Update some data of already broadcast value Bruna Moreira
  2012-12-21 20:26 ` [PATCH BlueZ 25/25] broadcaster: Add python test script Bruna Moreira
  24 siblings, 0 replies; 26+ messages in thread
From: Bruna Moreira @ 2012-12-21 20:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Bruna Moreira

The ClearBroadcastData() function will clean all data (Service Data or
Manufacturer Specific Data) set by the current application. All data set
by any other application will be kept.
---
 src/adapter.c |   75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 75 insertions(+)

diff --git a/src/adapter.c b/src/adapter.c
index 45471dc..9c99070 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -1699,9 +1699,84 @@ done:
 	return NULL;
 }
 
+static void restore_bcast_data(gpointer data, gpointer user_data)
+{
+	struct bcast_session *session = data, *cleared = user_data;
+
+	if (session == cleared)
+		return;
+
+	if (session->data_type != cleared->data_type)
+		return;
+
+	send_advdata_blob(session->adapter, session);
+}
+
+static gint cmp_bcast_session_owner(gconstpointer a, gconstpointer b)
+{
+	const struct bcast_session *session = a;
+	const char *owner = b;
+
+	return g_strcmp0(session->owner, owner);
+}
+
+static gboolean find_bcast_session_by_owner(struct btd_adapter *adapter,
+						const char *sender,
+						struct bcast_session **session)
+{
+	GSList *l;
+
+	l = g_slist_find_custom(adapter->bcast_sessions, sender,
+						cmp_bcast_session_owner);
+	if (!l)
+		return FALSE;
+
+	if (session)
+		*session = l->data;
+
+	return TRUE;
+}
+
 static DBusMessage *clear_broadcast_data(DBusConnection *conn,
 						DBusMessage *msg, void *data)
 {
+	struct btd_adapter *adapter = data;
+	struct bcast_session *session;
+	const char *sender;
+	int err;
+
+	sender = dbus_message_get_sender(msg);
+
+	DBG("Clear all data in broadcaster registered for hci%d at %s",
+						adapter->dev_id, sender);
+
+	while (find_bcast_session_by_owner(adapter, sender, &session)) {
+		uint8_t type = session->data_type;
+
+		err = mgmt_unset_controller_data(adapter->dev_id, type);
+		if (err < 0)
+			error("Failed to set Broadcaster: %s (%d)",
+							strerror(-err), -err);
+
+		/* mgmt_unset_controller_data() also clears broadcast data from
+		 * other clients with the same data type, so they need to be
+		 * restored. */
+		g_slist_foreach(adapter->bcast_sessions, restore_bcast_data,
+								session);
+
+		adapter->bcast_sessions =
+			g_slist_remove(adapter->bcast_sessions, session);
+
+		free_bcast_session(session);
+	}
+
+	if (!adapter->bcast_sessions) {
+		err = mgmt_set_broadcaster(adapter->dev_id, FALSE);
+		if (err < 0)
+			error("Failed to set Broadcaster: %s (%d)",
+							strerror(-err), -err);
+	}
+
 	return dbus_message_new_method_return(msg);
 }
 
-- 
1.7.9.5


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

* [PATCH BlueZ 24/25] broadcaster: Update some data of already broadcast value
  2012-12-21 20:26 [PATCH BlueZ 00/25] Broadcaster/Observer implementation Bruna Moreira
                   ` (22 preceding siblings ...)
  2012-12-21 20:26 ` [PATCH BlueZ 23/25] broadcaster: Add ClearBroadcastData() D-Bus method Bruna Moreira
@ 2012-12-21 20:26 ` Bruna Moreira
  2012-12-21 20:26 ` [PATCH BlueZ 25/25] broadcaster: Add python test script Bruna Moreira
  24 siblings, 0 replies; 26+ messages in thread
From: Bruna Moreira @ 2012-12-21 20:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Bruna Moreira

To update previously set data, it is necessary to use same Service UUID
or Company Identifier Code in SetServiceData() and
SetManufacturerData().
---
 src/adapter.c |    4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/adapter.c b/src/adapter.c
index 9c99070..96badfd 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -1570,6 +1570,10 @@ static void bcast_session_exit(DBusConnection *conn, void *user_data)
 static void update_adv_data(struct btd_adapter *adapter,
 		struct bcast_session *session, uint8_t *data, int size)
 {
+	session->data_len = size;
+	memcpy(session->data, data, size);
+
+	restore_bcast_type(adapter, session->data_type);
 }
 
 void adapter_set_controller_data_failed(struct btd_adapter *adapter)
-- 
1.7.9.5


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

* [PATCH BlueZ 25/25] broadcaster: Add python test script
  2012-12-21 20:26 [PATCH BlueZ 00/25] Broadcaster/Observer implementation Bruna Moreira
                   ` (23 preceding siblings ...)
  2012-12-21 20:26 ` [PATCH BlueZ 24/25] broadcaster: Update some data of already broadcast value Bruna Moreira
@ 2012-12-21 20:26 ` Bruna Moreira
  24 siblings, 0 replies; 26+ messages in thread
From: Bruna Moreira @ 2012-12-21 20:26 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Bruna Moreira

---
 test/test-broadcaster |   61 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 61 insertions(+)
 create mode 100755 test/test-broadcaster

diff --git a/test/test-broadcaster b/test/test-broadcaster
new file mode 100755
index 0000000..237887d
--- /dev/null
+++ b/test/test-broadcaster
@@ -0,0 +1,61 @@
+#!/usr/bin/python
+
+'''Broadcaster test script
+'''
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+from gi.repository import GObject
+
+import sys
+import dbus
+import dbus.service
+import dbus.mainloop.glib
+from optparse import OptionParser, make_option
+import time
+import bluezutils
+
+if __name__ == "__main__":
+	dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+	bus = dbus.SystemBus()
+
+	option_list = [
+		make_option("-i", "--adapter", action="store",
+			type="string", dest="adapter"),
+		make_option("-s", "--service", action="store",
+			type="int", dest="service",
+			help="Format: Service UUID (0xNNNN) followed by" +
+			" Service Data (e.g. aa bb cc)"),
+		make_option("-m", "--manufacturer", action="store",
+			type="int", dest="manufacturer",
+			help="Format: Company Identifier Code (0xNNNN)" +
+			" followed by Manufacturer Specific Data (e.g. 11 22 aa)"),
+		]
+
+	parser = OptionParser(option_list=option_list,
+			usage="Usage: %prog <-s uuid | -m cid> <data bytes in hex>")
+
+	(options, args) = parser.parse_args()
+	if not args:
+		parser.error("Hex encoded data is required.")
+
+	if options.service and options.manufacturer:
+		parser.error("options -m and -s are mutually exclusive")
+
+	try:
+		data = dbus.Array(map(lambda i: dbus.Byte(int(i, 16)), args))
+	except ValueError:
+		parser.error("Invalid data. Should be hex encoded bytes" +
+		" separated by whitespace.")
+
+	adapter = bluezutils.find_adapter(options.adapter)
+
+	if options.service:
+		adapter.SetServiceData(dbus.UInt16(options.service), data)
+
+	if options.manufacturer:
+		adapter.SetManufacturerData(dbus.UInt16(options.manufacturer), data)
+
+	mainloop = GObject.MainLoop()
+	mainloop.run()
-- 
1.7.9.5


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

end of thread, other threads:[~2012-12-21 20:26 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-12-21 20:26 [PATCH BlueZ 00/25] Broadcaster/Observer implementation Bruna Moreira
2012-12-21 20:26 ` [PATCH BlueZ 01/25] mgmt-api: Broadcaster/Observer management API Bruna Moreira
2012-12-21 20:26 ` [PATCH BlueZ 02/25] lib: Add set/uset controller data operations Bruna Moreira
2012-12-21 20:26 ` [PATCH BlueZ 03/25] lib: Add set broadcaster/observer operations Bruna Moreira
2012-12-21 20:26 ` [PATCH BlueZ 04/25] btmgmt: Add set broadcaster and set observer support Bruna Moreira
2012-12-21 20:26 ` [PATCH BlueZ 05/25] btmgmt: Add set controller data support Bruna Moreira
2012-12-21 20:26 ` [PATCH BlueZ 06/25] btmgmt: Add unset " Bruna Moreira
2012-12-21 20:26 ` [PATCH BlueZ 07/25] mgmt: Add set observer and set broadcaster command Bruna Moreira
2012-12-21 20:26 ` [PATCH BlueZ 08/25] mgmt: Add set controller data command Bruna Moreira
2012-12-21 20:26 ` [PATCH BlueZ 09/25] mgmt: Add unset " Bruna Moreira
2012-12-21 20:26 ` [PATCH BlueZ 10/25] doc: Add Broadcaster/Observer D-Bus API documentation Bruna Moreira
2012-12-21 20:26 ` [PATCH BlueZ 11/25] adapter: Add D-Bus API for Observer GAP Role Bruna Moreira
2012-12-21 20:26 ` [PATCH BlueZ 12/25] observer: Add Register/UnregisterServiceObserver() D-Bus method Bruna Moreira
2012-12-21 20:26 ` [PATCH BlueZ 13/25] observer: Add Register/UnregisterManufacturerObserver() " Bruna Moreira
2012-12-21 20:26 ` [PATCH BlueZ 14/25] observer: Add watchers and filters for observers Bruna Moreira
2012-12-21 20:26 ` [PATCH BlueZ 15/25] eir: Add manufacturer and service data fields Bruna Moreira
2012-12-21 20:26 ` [PATCH BlueZ 16/25] observer: Add Service/ManufacturerReceived() D-Bus method Bruna Moreira
2012-12-21 20:26 ` [PATCH BlueZ 17/25] observer: Add python test script Bruna Moreira
2012-12-21 20:26 ` [PATCH BlueZ 18/25] adapter: Add D-Bus API for Broadcaster GAP Role Bruna Moreira
2012-12-21 20:26 ` [PATCH BlueZ 19/25] lib: Maximum value to advertising and scan response Bruna Moreira
2012-12-21 20:26 ` [PATCH BlueZ 20/25] broadcaster: Add SetService/ManufacturerData() D-Bus method Bruna Moreira
2012-12-21 20:26 ` [PATCH BlueZ 21/25] broadcaster: Add list of broadcaster sessions Bruna Moreira
2012-12-21 20:26 ` [PATCH BlueZ 22/25] broadcaster: Build and send ADV/EIR data blob to kernel Bruna Moreira
2012-12-21 20:26 ` [PATCH BlueZ 23/25] broadcaster: Add ClearBroadcastData() D-Bus method Bruna Moreira
2012-12-21 20:26 ` [PATCH BlueZ 24/25] broadcaster: Update some data of already broadcast value Bruna Moreira
2012-12-21 20:26 ` [PATCH BlueZ 25/25] broadcaster: Add python test script Bruna Moreira

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.