Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH BlueZ 2/2] build-sys: Don't use deprecated INCLUDES variable
From: Lucas De Marchi @ 2012-10-04  6:37 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Lucas De Marchi
In-Reply-To: <1349332630-8901-1-git-send-email-lucas.de.marchi@gmail.com>

Makefile.am:410: warning: 'INCLUDES' is the old name for 'AM_CPPFLAGS' (or '*_CPPFLAGS')
---
 Makefile.am | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index dea207e..3b08f9a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -407,13 +407,13 @@ AM_YFLAGS = -d
 
 AM_CFLAGS += @DBUS_CFLAGS@ @GLIB_CFLAGS@
 
-INCLUDES = -I$(builddir)/lib -I$(builddir)/src -I$(srcdir)/src \
+AM_CPPFLAGS = -I$(builddir)/lib -I$(builddir)/src -I$(srcdir)/src \
 			-I$(srcdir)/audio -I$(srcdir)/sbc -I$(srcdir)/gdbus \
 			-I$(srcdir)/attrib -I$(srcdir)/btio -I$(srcdir)/tools \
 			-I$(builddir)/tools -I$(srcdir)/monitor
 
 if MCAP
-INCLUDES += -I$(builddir)/health
+AM_CPPFLAGS += -I$(builddir)/health
 endif
 
 unit_objects =
-- 
1.7.12.2


^ permalink raw reply related

* [PATCH BlueZ 1/2] build-sys: Don't use deprecated AM_PROG_MKDIR_P
From: Lucas De Marchi @ 2012-10-04  6:37 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Lucas De Marchi

AM_PROG_MKDIR_P is deprecated since:

configure.ac:23: warning: The 'AM_PROG_MKDIR_P' macro is deprecated, and will soon be removed.
configure.ac:23: You should use the Autoconf-provided 'AC_PROG_MKDIR_P' macro instead,
configure.ac:23: and use '$(MKDIR_P)' instead of '$(mkdir_p)'in your Makefile.am files.

We are already using $(MKDIR_P) so we just need to call the right macro.
---
 configure.ac | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/configure.ac b/configure.ac
index 7d9a34d..deab9e9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -20,7 +20,7 @@ AC_PROG_CC
 AM_PROG_CC_C_O
 AC_PROG_CC_PIE
 AC_PROG_INSTALL
-AM_PROG_MKDIR_P
+AC_PROG_MKDIR_P
 
 m4_define([_LT_AC_TAGCONFIG], [])
 m4_ifdef([AC_LIBTOOL_TAGS], [AC_LIBTOOL_TAGS([])])
-- 
1.7.12.2


^ permalink raw reply related

* [PATCH BlueZ] core: Fix walking the list while removing elements
From: Lucas De Marchi @ 2012-10-04  6:06 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Lucas De Marchi

If we are walking a GSList and remove the element we are pointing to,
the next iteration g_slist_next() will access previously freed
memory.
---

This was caught only by inspecting the code. I don't know why valgrind
didn't complain about accessing previously freed memory region.

 src/device.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/device.c b/src/device.c
index c659164..6150963 100644
--- a/src/device.c
+++ b/src/device.c
@@ -1498,7 +1498,7 @@ static void device_remove_profiles(struct btd_device *device, GSList *uuids)
 	if (records)
 		sdp_list_free(records, (sdp_free_func_t) sdp_record_free);
 
-	for (l = device->profiles; l != NULL; l = g_slist_next(l)) {
+	for (l = device->profiles; l != NULL;) {
 		struct btd_profile *profile = l->data;
 		GSList *probe_uuids;
 
@@ -1506,9 +1506,11 @@ static void device_remove_profiles(struct btd_device *device, GSList *uuids)
 								device->uuids);
 		if (probe_uuids != NULL) {
 			g_slist_free(probe_uuids);
+			l = l->next;
 			continue;
 		}
 
+		l = l->next;
 		profile->device_remove(profile, device);
 		device->profiles = g_slist_remove(device->profiles, profile);
 	}
-- 
1.7.12.2


^ permalink raw reply related

* [PATCH BlueZ 2/2] AVDTP: Remove hand-written function name from log
From: Lucas De Marchi @ 2012-10-04  5:14 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Lucas De Marchi
In-Reply-To: <1349327674-23672-1-git-send-email-lucas.demarchi@profusion.mobi>

From: Lucas De Marchi <lucas.de.marchi@gmail.com>

---
 audio/avdtp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/audio/avdtp.c b/audio/avdtp.c
index 8836ca1..7db3c02 100644
--- a/audio/avdtp.c
+++ b/audio/avdtp.c
@@ -770,7 +770,7 @@ static void avdtp_set_state(struct avdtp *session,
 	avdtp_get_peers(session, &src, &dst);
 	dev = manager_get_device(&src, &dst, FALSE);
 	if (dev == NULL) {
-		error("avdtp_set_state(): no matching audio device");
+		error("%s(): No matching audio device", __func__);
 		return;
 	}
 
-- 
1.7.12.2


^ permalink raw reply related

* [PATCH BlueZ 1/2] AVCTP: Remove hand-written function name from log
From: Lucas De Marchi @ 2012-10-04  5:14 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Lucas De Marchi

From: Lucas De Marchi <lucas.de.marchi@gmail.com>

Besides being hand-written, it was wrong which leads to confusion with
the AVDTP.
---
 audio/avctp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/audio/avctp.c b/audio/avctp.c
index b7b3083..53c28ec 100644
--- a/audio/avctp.c
+++ b/audio/avctp.c
@@ -392,7 +392,7 @@ static void avctp_set_state(struct avctp *session, avctp_state_t new_state)
 
 	dev = manager_get_device(&session->server->src, &session->dst, FALSE);
 	if (dev == NULL) {
-		error("avdtp_set_state(): no matching audio device");
+		error("%s(): No matching audio device", __func__);
 		return;
 	}
 
-- 
1.7.12.2


^ permalink raw reply related

* Re: [PATCH v4 BlueZ 01/27] doc: Introduce Alert API
From: Anderson Lizardo @ 2012-10-03 20:17 UTC (permalink / raw)
  To: Anderson Lizardo, linux-bluetooth
In-Reply-To: <20121003193921.GA32176@x220.P-661HNU-F1>

Hi Johan,

On Wed, Oct 3, 2012 at 3:39 PM, Johan Hedberg <johan.hedberg@gmail.com> wrote:
> Hi Lizardo,
>
> On Wed, Oct 03, 2012, Anderson Lizardo wrote:
>> This API will be implemented and initially used by Phone Alert Status
>> and Alert Notification GATT profiles (server role).
>> ---
>>
>> v4: Modify enumeration strings to use "-" as word separator.
>>
>>  Makefile.am       |    2 +-
>>  doc/alert-api.txt |  109 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 110 insertions(+), 1 deletion(-)
>>  create mode 100644 doc/alert-api.txt
>
> Thanks. All patches from this set are now upstream. I also pushed one
> additional coding style patch since I didn't want to bother with another
> review round for such a large patch set (and please don't do these huge
> sets in the future - keep them under 10 or so).

Thanks! We'll try to keep future series under a reasonable size.
Unfortunately, this one aggregated features too fast while the API was
being defined, but we could have split at least the skeleton GATT
server stuff to send earlier.

Regards,
-- 
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil

^ permalink raw reply

* Re: [PATCH] storage: Move adapter info to adapter.conf
From: Anderson Lizardo @ 2012-10-03 20:14 UTC (permalink / raw)
  To: Frédéric Danis; +Cc: linux-bluetooth
In-Reply-To: <1349274401-32012-1-git-send-email-frederic.danis@linux.intel.com>

Hi Frédéric,

On Wed, Oct 3, 2012 at 10:26 AM, Frédéric Danis
<frederic.danis@linux.intel.com> wrote:
> +int keyfile_put_string(const char *pathname, const char *group,
> +                               const char *key, const char *value);
> +int keyfile_put_boolean(const char *pathname, const char *group,
> +                               const char *key, gboolean value);
> +int keyfile_put_integer(const char *pathname, const char *group,
> +                               const char *key, int value);
> +
> +char *keyfile_get_string(const char *pathname, const char *group,
> +                               const char *key);

One suggestion (which may or may not be acked by core devs), what
about being consistent here and use:

int keyfile_get_string(const char *pathname, const char *group, const
char *key, char **value);

(i.e. use return value for error and value pointer on last parameter).

> +int keyfile_get_boolean(const char *pathname, const char *group,
> +                               const char *key, gboolean *value);
> +int keyfile_get_integer(const char *pathname, const char *group,
> +                               const char *key, int *value);
> +
> +int keyfile_del(const char *pathname, const char *group, const char *key);
> +
> +typedef void (*keyfile_key_cb) (char *key, char *value, void *data);
> +typedef void (*keyfile_group_cb) (char *group, void *data);
> +
> +int keyfile_foreach_key(const char *pathname, const char *group,
> +                               keyfile_key_cb func, void *data);
> +int keyfile_foreach_group(const char *pathname,
> +                               keyfile_group_cb func, void *data);
> +
> +#endif /* __KEYFILE_H */

Regards,
-- 
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil

^ permalink raw reply

* Re: [PATCH] storage: Move adapter info to adapter.conf
From: Johan Hedberg @ 2012-10-03 19:59 UTC (permalink / raw)
  To: Frédéric Danis; +Cc: linux-bluetooth
In-Reply-To: <1349274401-32012-1-git-send-email-frederic.danis@linux.intel.com>

Hi Frédéric,

On Wed, Oct 03, 2012, Frédéric Danis wrote:
> Add functions to read and write to .conf files.
> Convert adapter "config" file to "adapter.conf".
> ---
>  .gitignore          |    1 +
>  Makefile.am         |    3 +-
>  Makefile.tools      |    6 +-
>  src/keyfile.c       |  282 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  src/keyfile.h       |   51 ++++++++++
>  src/storage.c       |  100 +++++++-----------
>  test/test-keyfile.c |  252 +++++++++++++++++++++++++++++++++++++++++++++
>  7 files changed, 627 insertions(+), 68 deletions(-)
>  create mode 100644 src/keyfile.c
>  create mode 100644 src/keyfile.h
>  create mode 100644 test/test-keyfile.c

The keyfile.[ch] files should be split into their own patch along with
test-keyfile.c.

> +int keyfile_put_string(const char *pathname, const char *group,
> +				const char *key, const char *value)
> +{
> +	GKeyFile *key_file;
> +	char *data;
> +	FILE *file;
> +
> +	key_file = g_key_file_new();
> +
> +	g_key_file_load_from_file(key_file, pathname, 0, NULL);
> +
> +	g_key_file_set_string(key_file, group, key, value);
> +
> +	data = g_key_file_to_data(key_file, NULL, NULL);
> +	file = fopen(pathname, "w");
> +	fputs(data, file);
> +	fclose(file);

It seems like there's some error checking missing here as both
g_key_file_load_from_file and fopen could fail.

> +}
> +
> +
> +int keyfile_get_boolean(const char *pathname, const char *group,

Two consecutive empty lines above. Please remove one.

> +				const char *key, gboolean *value)
> +{
> +	GKeyFile *key_file;
> +	GError *error = NULL;

Please don't reuse the symbol name "error" since we already have that
for error logging. Use gerr instead

> +	int err = 0;

This initialization upon declaration is unnecessary. Set to 0 at the end
of the success path instead.

> +	if (error) {
> +		g_error_free(error);
> +		err = -EINVAL;
> +	}

< i.e. here >

> +
> +failed:
> +	g_key_file_free(key_file);
> +	errno = -err;

Don't mix errno into this. It should be considered "owned" by libc and
we should only read it and not write to it. Return the error in the
function return value instead.

> +	return keyfile_put_integer(filename, "General", "DiscovTO", timeout);

I really dislike this "TO" short-hand for timeout. I think we can use
longer and more readable names in the INI-format files. In this case
DiscoverableTimeout should be perfectly fine. 

> +	return keyfile_put_integer(filename, "General", "PairTO", timeout);

Same here. PairableTimeout should be fine.

Johan

^ permalink raw reply

* Re: [PATCH v4 00/18] neard plugin
From: Johan Hedberg @ 2012-10-03 19:48 UTC (permalink / raw)
  To: Szymon Janc; +Cc: linux-bluetooth
In-Reply-To: <1349270311-31103-1-git-send-email-szymon.janc@tieto.com>

Hi Szymon,

On Wed, Oct 03, 2012, Szymon Janc wrote:
> Next round of neard plugin patches.
> 
> Changes since v3:
> - enable neard support with --enable-neard
> - use g_memdup instead of g_malloc+memcpy
> - introduce oob_handler functionality that allows to register cb to be called
>   when certain adapter actions are completed (dbusoob plugin adjusted)
> - remove static pointers from neard plugin, this data is now passed to/from
>   callback as user data
> - other small fixes
> 
> Comments are welcome.
> 
> Szymon Janc (18):
>   Handle missing randomizer in mgmt_add_remote_oob_data
>   eir: Add support for parsing SSP hash and randomizer
>   eir: Store class in struct eir_data as uint32_t
>   eir: Add eir_parse_oob function
>   eir: Add support creating EIR with hash and randomizer fields
>   eir: Add support for creating EIR with CoD field
>   eir: Rename eir_create to eir_create_oob
>   eir: Remove support for creating EIR with tx_power fields
>   eir: Return number of bytes written by eir_create_oob
>   eir: Remove struct uuid_info
>   eir: Add support for creating proper OOB EIR
>   adapter: Add btd_adapter_get_services function
>   adapter: Rename btd_adapter_get_class to btd_adapter_read_class
>   adapter: Add btd_adapter_get_class function
>   oob: Refactor oob callback handling and move it to adapter code
>   Add initial neard plugin implementation
>   neard: Implement PushOOB function
>   neard: Implement RequestOOB function
> 
>  Makefile.am         |    8 +-
>  acinclude.m4        |    6 +
>  bootstrap-configure |    1 +
>  plugins/dbusoob.c   |   69 ++-----
>  plugins/neard.c     |  546 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  src/adapter.c       |   67 ++++++-
>  src/adapter.h       |   25 ++-
>  src/eir.c           |  153 ++++++++++++---
>  src/eir.h           |   21 +-
>  src/event.c         |   11 +-
>  src/event.h         |    2 +-
>  src/mgmt.c          |   16 +-
>  src/oob.c           |   41 ----
>  src/oob.h           |   32 ---
>  14 files changed, 801 insertions(+), 197 deletions(-)
>  create mode 100644 plugins/neard.c
>  delete mode 100644 src/oob.c
>  delete mode 100644 src/oob.h

I didn't find any major issues so all patches in this set have now been
applied. Thanks.

Johan

^ permalink raw reply

* Re: [PATCH v4 BlueZ 01/27] doc: Introduce Alert API
From: Johan Hedberg @ 2012-10-03 19:39 UTC (permalink / raw)
  To: Anderson Lizardo; +Cc: linux-bluetooth
In-Reply-To: <1349268398-14620-1-git-send-email-anderson.lizardo@openbossa.org>

Hi Lizardo,

On Wed, Oct 03, 2012, Anderson Lizardo wrote:
> This API will be implemented and initially used by Phone Alert Status
> and Alert Notification GATT profiles (server role).
> ---
> 
> v4: Modify enumeration strings to use "-" as word separator.
> 
>  Makefile.am       |    2 +-
>  doc/alert-api.txt |  109 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 110 insertions(+), 1 deletion(-)
>  create mode 100644 doc/alert-api.txt

Thanks. All patches from this set are now upstream. I also pushed one
additional coding style patch since I didn't want to bother with another
review round for such a large patch set (and please don't do these huge
sets in the future - keep them under 10 or so).

Johan

^ permalink raw reply

* [PATCH 5/5] bt tool: add cmd 'remove'
From: Gustavo Padovan @ 2012-10-03 17:34 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: travis.reitter
In-Reply-To: <1349285669-20464-1-git-send-email-gustavo@padovan.org>

From: Travis Reitter <travis.reitter@collabora.co.uk>

'bt remove <device address>' will remove a previous paired device
---
 tools/bt-tool.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 136 insertions(+)

diff --git a/tools/bt-tool.c b/tools/bt-tool.c
index 11d26c5..aeb47e4 100644
--- a/tools/bt-tool.c
+++ b/tools/bt-tool.c
@@ -102,6 +102,7 @@ static void show_help()
 	"	discover				Scan for devices\n"
 	"	pair <device address>			Start pairing\n"
 	"	agent					Run BlueZ agent\n"
+	"	remove					Remove a paired device\n"
 							"\n", program_name);
 
 	if(mainloop != NULL)
@@ -740,6 +741,94 @@ static gboolean stop_discovery_cb(gpointer data)
 	return FALSE;
 }
 
+/* Handle the D-Bus method reply for RemoveDevice. See comments on
+ * get_adapter_reply() for more details */
+static void remove_device_reply(DBusPendingCall *pending, void *user_data)
+{
+	const char *device_path = user_data;
+	DBusMessage *reply;
+
+	reply = dbus_pending_call_steal_reply(pending);
+	if (!reply) {
+		ERR("Failed to get RemoveDevice reply");
+		exit(1);
+	}
+
+	if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
+		ERR("Remove device failed.");
+		exit(1);
+	}
+
+	printf("Device %s successfully removed.\n", device_path);
+	g_main_loop_quit(mainloop);
+}
+
+static int remove_device(DBusConnection *conn, const char *adapter_path,
+							const char *device_path)
+{
+	DBusMessage *msg;
+	int retval = 0;
+
+	if (!(msg = create_method_call(adapter_path, BLUEZ_ADAPTER,
+							"RemoveDevice")))
+		return -1;
+
+	dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &device_path,
+							DBUS_TYPE_INVALID);
+
+	if (!send_with_reply_and_set_notify(msg, remove_device_reply,
+						g_strdup(device_path), g_free))
+		retval = -1;
+
+	dbus_message_unref(msg);
+
+	return retval;
+}
+
+/* Handle the D-Bus method reply for FindDevice. See comments on
+ * get_adapter_reply() for more details */
+static void find_device_reply(DBusPendingCall *pending, void *user_data)
+{
+	const char *adapter_path = user_data;
+	DBusMessage *reply;
+	const char *device_path;
+
+	if (!pending)
+		return;
+
+	dbus_pending_call_ref(pending);
+
+	reply = dbus_pending_call_steal_reply(pending);
+	if (!reply) {
+		ERR("Failed to get FindDevice() reply");
+		exit(1);
+	}
+
+	if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
+		ERR("Failed to find device.");
+		exit(1);
+	} else {
+		struct DBusError err;
+		dbus_error_init(&err);
+
+		if (!dbus_message_get_args(reply, &err,
+					DBUS_TYPE_OBJECT_PATH, &device_path,
+					DBUS_TYPE_INVALID)) {
+			if (dbus_error_is_set(&err)) {
+				ERR("Failed to find device %s", err.message);
+				dbus_error_free(&err);
+			}
+			exit(1);
+		}
+	}
+
+	if (remove_device(conn, adapter_path, device_path) < 0)
+		exit(1);
+
+	dbus_message_unref(reply);
+	dbus_pending_call_unref(pending);
+}
+
 /* Listen for Bluetooth devices broadcasting their availability, then display
  * the results */
 static gboolean cmd_discover(gpointer data)
@@ -829,6 +918,52 @@ static gboolean cmd_agent(gpointer data)
 	return FALSE;
 }
 
+/* Remove a pairing with a given Bluetooth device */
+static gboolean cmd_remove(gpointer data)
+{
+	struct cmd_param *param = data;
+	char *device_addr;
+	DBusMessage *msg;
+	gboolean retval = FALSE;
+
+	device_addr = param->argv[0];
+	if (!device_addr) {
+		ERR("%s: missing device address paramenter", program_name);
+		show_help();
+		exit(1);
+	}
+
+	/* Register a D-Bus interface for our agent to handle our removal
+	 * request */
+	if (!g_dbus_register_interface(conn, "/tool/agent", BLUEZ_AGENT,
+					agent_methods, NULL, NULL, NULL,
+									NULL)) {
+		ERR("Adapter interface init failed for path %s", param->path);
+		return FALSE;
+	}
+
+	device_addr = param->argv[0];
+
+	if (!(msg = create_method_call(param->path, BLUEZ_ADAPTER,
+								"FindDevice")))
+		return FALSE;
+
+	dbus_message_append_args(msg, DBUS_TYPE_STRING, &device_addr,
+							DBUS_TYPE_INVALID);
+
+	/* Set up our notify function and provide it both the extra data it
+	 * requires and another function to free this data when our notify
+	 * function is done with it */
+	if (!send_with_reply_and_set_notify(msg, find_device_reply,
+							g_strdup(param->path),
+							g_free))
+		retval = FALSE;
+
+	dbus_message_unref(msg);
+
+	return retval;
+}
+
 static void run_func(const char *adapter_path, GSourceFunc fn,
 							struct cmd_param *param)
 {
@@ -960,6 +1095,7 @@ static struct cmd_struct commands[] = {
 	{ "discover", cmd_discover},
 	{ "pair", cmd_pair},
 	{ "agent", cmd_agent},
+	{ "remove", cmd_remove},
 };
 
 /* Returns FALSE in case the command could not be parsed. Any failures during
-- 
1.7.11.4


^ permalink raw reply related

* [PATCH 4/5] bt tool: add cmd 'pair'
From: Gustavo Padovan @ 2012-10-03 17:34 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: travis.reitter
In-Reply-To: <1349285669-20464-1-git-send-email-gustavo@padovan.org>

From: Travis Reitter <travis.reitter@collabora.co.uk>

'bt pair <device address>' starts a pairing procedure with a remote
device.
---
 tools/bt-tool.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 83 insertions(+)

diff --git a/tools/bt-tool.c b/tools/bt-tool.c
index 6035eda..11d26c5 100644
--- a/tools/bt-tool.c
+++ b/tools/bt-tool.c
@@ -575,6 +575,65 @@ static int register_agent(DBusConnection *conn, const char *adapter_path,
 	return 0;
 }
 
+/* Handle the D-Bus method reply for CreatePairedDevice. See comments on
+ * get_adapter_reply() for more details */
+static void create_paired_device_reply(DBusPendingCall *pending,
+								void *user_data)
+{
+	const char *device = user_data;
+	const char *device_path;
+	DBusMessage *reply;
+	DBusError err;
+
+	reply = dbus_pending_call_steal_reply(pending);
+
+	if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
+		ERR("Pairing Failed.");
+		exit(1);
+	}
+
+	dbus_error_init(&err);
+	if (!dbus_message_get_args(reply, &err, DBUS_TYPE_OBJECT_PATH,
+					&device_path, DBUS_TYPE_INVALID)) {
+		if (dbus_error_is_set(&err)) {
+			ERR("Paring failed: %s", err.message);
+			dbus_error_free(&err);
+		}
+		exit(1);
+	}
+
+	printf("Device %s successfully paired.\n", device);
+	g_main_loop_quit(mainloop);
+}
+
+static int create_paired_device(DBusConnection *conn, const char *adapter_path,
+						const char *agent_path,
+						const char *capabilities,
+						const char *device)
+{
+	DBusMessage *msg;
+	int retval = 0;
+
+	if (!(msg = create_method_call(adapter_path, BLUEZ_ADAPTER,
+							"CreatePairedDevice")))
+		return -1;
+
+	dbus_message_append_args(msg, DBUS_TYPE_STRING, &device,
+					DBUS_TYPE_OBJECT_PATH, &agent_path,
+					DBUS_TYPE_STRING, &capabilities,
+					DBUS_TYPE_INVALID);
+
+	if (!send_with_reply_and_set_notify(msg, create_paired_device_reply,
+						g_strdup(device), g_free))
+		retval = -1;
+
+	dbus_message_unref(msg);
+
+	exit_on_release = FALSE;
+
+	return retval;
+}
+
 /* This is the table of methods that our agent supports, including their name,
  * and arguments (including their D-Bus types). See the D-Bus documentation for
  * details on the type notation */
@@ -726,6 +785,29 @@ static gboolean cmd_discover(gpointer data)
 	return FALSE;
 }
 
+/* Pair (connect) our Bluetooth adapter with an external Bluetooth device */
+static gboolean cmd_pair(gpointer data)
+{
+	struct cmd_param *param = data;
+	char *device;
+
+	if (!g_dbus_register_interface(conn, "/tool/agent", BLUEZ_AGENT,
+					agent_methods, NULL, NULL, NULL,
+									NULL)) {
+		ERR("Adapter interface init failed on path %s", param->path);
+		return FALSE;
+	}
+
+	device = param->argv[0];
+
+	if (create_paired_device(conn, param->path, "/tool/agent",
+						"DisplayYesNo", device) < 0) {
+		exit(1);
+	}
+
+	return FALSE;
+}
+
 /* Register this program as an agent itself, to handle other BlueZ clients'
  * requests */
 static gboolean cmd_agent(gpointer data)
@@ -876,6 +958,7 @@ static void bluetoothd_disconnect(DBusConnection *conn, void *user_data)
 
 static struct cmd_struct commands[] = {
 	{ "discover", cmd_discover},
+	{ "pair", cmd_pair},
 	{ "agent", cmd_agent},
 };
 
-- 
1.7.11.4


^ permalink raw reply related

* [PATCH 3/5] bt tool: add cmd 'agent'
From: Gustavo Padovan @ 2012-10-03 17:34 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: travis.reitter, Gustavo Padovan
In-Reply-To: <1349285669-20464-1-git-send-email-gustavo@padovan.org>

From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>

'bt agent' command register a agent in BlueZ that will loop waiting for
pairing and incoming connection requests.
---
 tools/bt-tool.c | 352 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 352 insertions(+)

diff --git a/tools/bt-tool.c b/tools/bt-tool.c
index 48521fd..6035eda 100644
--- a/tools/bt-tool.c
+++ b/tools/bt-tool.c
@@ -82,6 +82,8 @@ struct find_adapter_cb_data {
 static GMainLoop *mainloop = NULL;
 static gchar *program_name = NULL;
 
+static gboolean exit_on_release = TRUE;
+
 static bdaddr_t bdaddr;
 static DBusConnection *conn;
 
@@ -280,6 +282,334 @@ static gboolean send_with_reply_and_set_notify(DBusMessage *msg,
 	return TRUE;
 }
 
+static DBusMessage *agent_request_confirmation(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	DBusMessage *reply;
+	const char *path;
+	unsigned int passkey;
+	char conf[16];
+	int ret;
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+						DBUS_TYPE_UINT32, &passkey,
+						DBUS_TYPE_INVALID)) {
+		ERR("Invalid arguments for RequestConfirmation method");
+		reply = dbus_message_new_error(msg,
+					BLUEZ_ERROR".InvalidArguments", "");
+		goto send;
+	}
+
+	printf("Pairing request confirmation for %s.\n"
+		"Confirm the passkey %6.6d (yes/no): ", path, passkey);
+	ret = scanf("%3s", conf);
+	if (!ret)
+		return NULL;
+
+	if (g_str_equal(conf, "yes"))
+		reply = dbus_message_new_method_return(msg);
+	else
+		reply = dbus_message_new_error(msg, BLUEZ_ERROR".Rejected",
+						"Passkey doesn't match");
+
+	if (!reply) {
+		ERR("Can't create reply message");
+		return NULL;
+	}
+
+send:
+	dbus_connection_send(conn, reply, NULL);
+
+	dbus_message_unref(reply);
+
+	return NULL;
+}
+
+static DBusMessage *agent_request_pincode(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	DBusMessage *reply;
+	const char *path;
+	char pin[64];
+	char *str;
+	int ret;
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+						DBUS_TYPE_INVALID)) {
+		ERR("Invalid arguments for RequestPinCode method");
+		reply = dbus_message_new_error(msg,
+					BLUEZ_ERROR".InvalidArguments", "");
+		goto send;
+	}
+
+	printf("Pairing request for  %s.\nType the PIN code: ", path);
+	ret = scanf("%s", pin);
+	if (!ret)
+		return NULL;
+
+	if (!(reply = dbus_message_new_method_return(msg))) {
+		ERR("Not enough memory to construct message");
+		return NULL;
+	}
+
+	str = pin;
+	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str,
+							DBUS_TYPE_INVALID);
+
+send:
+	dbus_connection_send(conn, reply, NULL);
+
+	dbus_message_unref(reply);
+
+	return NULL;
+}
+
+static DBusMessage *agent_request_passkey(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	DBusMessage *reply;
+	const char *path;
+	unsigned int passkey;
+	int ret;
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+						DBUS_TYPE_INVALID)) {
+		ERR("Invalid arguments for RequestPasskey method");
+		reply = dbus_message_new_error(msg,
+					BLUEZ_ERROR".InvalidArguments", "");
+		goto send;
+	}
+
+	printf("Pairing request for  %s.\nType the Passkey: ", path);
+	ret = scanf("%u", &passkey);
+	if (!ret)
+		return NULL;
+
+	reply = dbus_message_new_method_return(msg);
+
+	dbus_message_append_args(reply, DBUS_TYPE_STRING, passkey,
+							DBUS_TYPE_INVALID);
+
+send:
+	if (!dbus_connection_send(conn, reply, NULL))
+		ERR("Not enough memory to send message");
+
+	dbus_message_unref(reply);
+
+	return NULL;
+}
+
+static DBusMessage *agent_authorize(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	DBusMessage *reply;
+	const char *path, *uuid;
+	char conf[16];
+	int ret;
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+						DBUS_TYPE_STRING, &uuid,
+						DBUS_TYPE_INVALID)) {
+		ERR("Invalid arguments for Authorize method");
+		reply = dbus_message_new_error(msg,
+					BLUEZ_ERROR".InvalidArguments", "");
+		goto send;
+	}
+
+	printf("Incoming connection request for %s (%s).\n"
+		"Authorize (yes/no): ", path, uuid);
+	ret = scanf("%3s", conf);
+	if (!ret)
+		return NULL;
+
+	if (g_str_equal(conf, "yes"))
+		reply = dbus_message_new_method_return(msg);
+	else
+		reply = dbus_message_new_error(msg, BLUEZ_ERROR".Rejected",
+						"Connection Rejected");
+
+	if (!reply) {
+		ERR("Can't create reply message");
+		return NULL;
+	}
+
+send:
+	dbus_connection_send(conn, reply, NULL);
+
+	dbus_message_unref(reply);
+
+	return NULL;
+}
+
+static DBusMessage *agent_confirm_mode_change(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	DBusMessage *reply;
+	const char *mode;
+	char conf[16];
+	int ret;
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &mode,
+							DBUS_TYPE_INVALID)) {
+		ERR("Invalid arguments for ConfirmModeChange");
+		reply = dbus_message_new_error(msg,
+					BLUEZ_ERROR".InvalidArguments", "");
+		goto send;
+	}
+
+	printf("Authorize mode change to %s (yes/no): ", mode);
+	ret = scanf("%3s", conf);
+	if (!ret)
+		return NULL;
+
+	if (g_str_equal(conf, "yes"))
+		reply = dbus_message_new_method_return(msg);
+	else
+		reply = dbus_message_new_error(msg, BLUEZ_ERROR".Rejected",
+						"Mode Change Rejected");
+
+	if (!reply) {
+		ERR("Can't create reply message");
+		return NULL;
+	}
+
+send:
+	dbus_connection_send(conn, reply, NULL);
+
+	dbus_message_unref(reply);
+
+	return NULL;
+}
+
+static DBusMessage *agent_cancel(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	DBusMessage *reply;
+
+	printf("Request canceled\n");
+
+	reply = dbus_message_new_method_return(msg);
+	if (!reply) {
+		ERR("Can't create reply message");
+		return NULL;
+	}
+
+	dbus_connection_send(conn, reply, NULL);
+
+	dbus_message_unref(reply);
+
+	g_main_loop_quit(mainloop);
+
+	return NULL;
+}
+
+static DBusMessage *agent_release(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	DBusMessage *reply;
+
+	printf("Agent released\n");
+
+	reply = dbus_message_new_method_return(msg);
+	if (!reply) {
+		ERR("Can't create reply message");
+		return NULL;
+	}
+
+	dbus_connection_send(conn, reply, NULL);
+
+	dbus_message_unref(reply);
+
+	/* Only exit the mainloop in case there are no other D-Bus methods, such
+	 * as CreatePairedDevice, pending */
+	if (exit_on_release)
+		g_main_loop_quit(mainloop);
+
+	return NULL;
+}
+
+/* Handle the D-Bus method reply for RegisterAgent. See comments on
+ * get_adapter_reply() for more details */
+static void register_agent_reply(DBusPendingCall *pending, void *user_data)
+{
+	DBusMessage *reply;
+
+	reply = dbus_pending_call_steal_reply(pending);
+
+	if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
+		ERR("Agent Registration failed.");
+		exit(1);
+	}
+
+	printf("Agent registered\n");
+}
+
+static int register_agent(DBusConnection *conn, const char *adapter_path,
+						const char *agent_path,
+						const char *capabilities)
+{
+	dbus_bool_t success;
+	DBusMessage *msg;
+	DBusPendingCall *pending;
+
+	if (!(msg = create_method_call(adapter_path, BLUEZ_ADAPTER,
+							"RegisterAgent")))
+		return -1;
+
+	dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &agent_path,
+					DBUS_TYPE_STRING, &capabilities,
+					DBUS_TYPE_INVALID);
+
+	success = dbus_connection_send_with_reply(conn, msg, &pending, -1);
+	if (pending)
+		dbus_pending_call_set_notify(pending, register_agent_reply,
+								NULL, NULL);
+
+	dbus_message_unref(msg);
+
+	if (!success) {
+		ERR("Not enough memory for message send");
+		return -1;
+	}
+
+	return 0;
+}
+
+/* This is the table of methods that our agent supports, including their name,
+ * and arguments (including their D-Bus types). See the D-Bus documentation for
+ * details on the type notation */
+static const GDBusMethodTable agent_methods[] = {
+	{ GDBUS_ASYNC_METHOD("RequestConfirmation",
+			GDBUS_ARGS({ "device", "o" }, { "passkey", "u" }),
+			NULL,
+			agent_request_confirmation) },
+	{ GDBUS_ASYNC_METHOD("RequestPinCode",
+			GDBUS_ARGS({ "device", "o" }),
+			GDBUS_ARGS({"pincode", "s"}),
+			agent_request_pincode) },
+	{ GDBUS_ASYNC_METHOD("RequestPasskey",
+			GDBUS_ARGS({ "device", "o" }),
+			GDBUS_ARGS({"passkey", "u"}),
+			agent_request_passkey) },
+	{ GDBUS_ASYNC_METHOD("Authorize",
+			GDBUS_ARGS({ "device", "o" }, { "uuid", "s" }),
+			NULL,
+			agent_authorize) },
+	{ GDBUS_ASYNC_METHOD("ConfirmModeChange",
+			GDBUS_ARGS( { "mode", "s" }),
+			NULL,
+			agent_confirm_mode_change) },
+	{ GDBUS_ASYNC_METHOD("Cancel",
+			NULL,
+			NULL,
+			agent_cancel) },
+	{ GDBUS_ASYNC_METHOD("Release",
+			NULL,
+			NULL,
+			agent_release) },
+	{ }
+};
+
 /* Handle BlueZ's DeviceFound signal */
 static gboolean device_found(DBusConnection *conn, DBusMessage *message,
 							void *user_data)
@@ -396,6 +726,27 @@ static gboolean cmd_discover(gpointer data)
 	return FALSE;
 }
 
+/* Register this program as an agent itself, to handle other BlueZ clients'
+ * requests */
+static gboolean cmd_agent(gpointer data)
+{
+	struct cmd_param *param = data;
+
+	if (!g_dbus_register_interface(conn, "/tool/agent", BLUEZ_AGENT,
+					agent_methods, NULL, NULL, NULL,
+									NULL)) {
+		ERR("Agent interface init failed");
+		return FALSE;
+	}
+
+	if (register_agent(conn, param->path, "/tool/agent", "DisplayYesNo")
+									< 0) {
+		exit(1);
+	}
+
+	return FALSE;
+}
+
 static void run_func(const char *adapter_path, GSourceFunc fn,
 							struct cmd_param *param)
 {
@@ -525,6 +876,7 @@ static void bluetoothd_disconnect(DBusConnection *conn, void *user_data)
 
 static struct cmd_struct commands[] = {
 	{ "discover", cmd_discover},
+	{ "agent", cmd_agent},
 };
 
 /* Returns FALSE in case the command could not be parsed. Any failures during
-- 
1.7.11.4


^ permalink raw reply related

* [PATCH 2/5] bt tool: add cmd 'discover'
From: Gustavo Padovan @ 2012-10-03 17:34 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: travis.reitter
In-Reply-To: <1349285669-20464-1-git-send-email-gustavo@padovan.org>

From: Travis Reitter <travis.reitter@collabora.co.uk>

 $ bt discover

will start a discovery for devices nearby and display them. We display
the device when we receive its first Device Found signal. If the
DeviceFound signal doesn't contains the device's name it will not be
displayed.

Steal bluetooth_parse_properties() from oFono code.
---
 tools/bt-tool.c | 242 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 241 insertions(+), 1 deletion(-)

diff --git a/tools/bt-tool.c b/tools/bt-tool.c
index 4edc255..48521fd 100644
--- a/tools/bt-tool.c
+++ b/tools/bt-tool.c
@@ -5,6 +5,7 @@
  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *  Copyright (C) 2011 Bruno Dilly <bdilly@profusion.mobi>
  *  Copyright (C) 2011 Gustavo Padovan <gustavo@padovan.org>
+ *  Copyright (C) 2011 Intel Corporation. All rights reserved.
  *  Copyright (C) 2012 Collabora Limited.
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -84,6 +85,8 @@ static gchar *program_name = NULL;
 static bdaddr_t bdaddr;
 static DBusConnection *conn;
 
+static GHashTable *device_addrs = NULL;
+
 static void show_help()
 {
 	printf("usage: %s [-i interface] <command> [<args>]\n"
@@ -115,6 +118,127 @@ static struct find_adapter_cb_data *find_adapter_cb_data_new(GSourceFunc fn,
 	return cb_data;
 }
 
+static void parse_bool(DBusMessageIter *iter, gpointer user_data)
+{
+	gboolean *boolean = user_data;
+	int arg_type = dbus_message_iter_get_arg_type(iter);
+
+	if (arg_type != DBUS_TYPE_BOOLEAN)
+		return;
+
+	dbus_message_iter_get_basic(iter, boolean);
+}
+
+static void parse_string(DBusMessageIter *iter, gpointer user_data)
+{
+	char **str = user_data;
+	int arg_type = dbus_message_iter_get_arg_type(iter);
+
+	if (arg_type != DBUS_TYPE_OBJECT_PATH && arg_type != DBUS_TYPE_STRING)
+		return;
+
+	dbus_message_iter_get_basic(iter, str);
+}
+
+typedef void (*PropertyHandler)(DBusMessageIter *iter, gpointer user_data);
+
+struct property_handler {
+	const char *property;
+	PropertyHandler callback;
+	gpointer user_data;
+};
+
+static gint property_handler_compare(gconstpointer a, gconstpointer b)
+{
+	const struct property_handler *handler = a;
+	const char *property = b;
+
+	return strcmp(handler->property, property);
+}
+
+/* Demarshall the content of a D-Bus message reply for a given property.
+ *
+ * After the first argument, all arguments must be triplets of:
+ *
+ *   const char* property_name,
+ *   void (parse_func*) (DBusMessageIter *iter, gpointer user_data),
+ *   void** result,
+ *
+ * result must be large enough to store the type of data corresponding to
+ * property_name.
+ *
+ * Finally, a NULL must be appended as the last argument.
+ */
+static void bluetooth_parse_properties(DBusMessage *reply,
+						const char *property, ...)
+{
+	va_list args;
+	GSList *prop_handlers = NULL;
+	DBusMessageIter array, dict;
+
+	va_start(args, property);
+
+	while (property != NULL) {
+		struct property_handler *handler = g_new0(struct property_handler, 1);
+
+		handler->property = property;
+		handler->callback = va_arg(args, PropertyHandler);
+		handler->user_data = va_arg(args, gpointer);
+
+		property = va_arg(args, const char *);
+
+		prop_handlers = g_slist_prepend(prop_handlers, handler);
+	}
+
+	va_end(args);
+
+	if (dbus_message_iter_init(reply, &array) == FALSE)
+		goto done;
+
+	if (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING)
+		dbus_message_iter_next(&array);
+
+	if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
+		goto done;
+
+	dbus_message_iter_recurse(&array, &dict);
+
+	while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+		DBusMessageIter entry, value;
+		const char *key;
+		GSList *l;
+
+		dbus_message_iter_recurse(&dict, &entry);
+
+		if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
+			goto done;
+
+		dbus_message_iter_get_basic(&entry, &key);
+
+		dbus_message_iter_next(&entry);
+
+		if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
+			goto done;
+
+		dbus_message_iter_recurse(&entry, &value);
+
+		l = g_slist_find_custom(prop_handlers, key,
+					property_handler_compare);
+
+		if (l) {
+			struct property_handler *handler = l->data;
+
+			handler->callback(&value, handler->user_data);
+		}
+
+		dbus_message_iter_next(&dict);
+	}
+
+done:
+	g_slist_foreach(prop_handlers, (GFunc) g_free, NULL);
+	g_slist_free(prop_handlers);
+}
+
 static DBusMessage* create_method_call(const char *adapter_path,
 							const char *interface,
 							const char *method_name)
@@ -156,6 +280,122 @@ static gboolean send_with_reply_and_set_notify(DBusMessage *msg,
 	return TRUE;
 }
 
+/* Handle BlueZ's DeviceFound signal */
+static gboolean device_found(DBusConnection *conn, DBusMessage *message,
+							void *user_data)
+{
+	const char *alias = NULL;
+	const char *address = NULL;
+	gboolean paired, trusted;
+	DBusMessageIter array;
+
+	if (dbus_message_iter_init(message, &array) == FALSE)
+		return TRUE;
+
+	if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING)
+		return TRUE;
+
+	bluetooth_parse_properties(message, "Alias", parse_string, &alias,
+				"Address", parse_string, &address,
+				"Paired", parse_bool, &paired,
+				"Trusted", parse_bool, &trusted,
+				NULL);
+
+	/* Only list new devices if we have not yet listed them. BlueZ will emit
+	 * this signal multiple times for the same device because it may receive
+	 * additional information from the device in subsequent transmissions */
+	if (!g_hash_table_contains(device_addrs, address)) {
+		gint alias_len;
+		const char *alias_status_gap = " ";
+
+		/* Make sure everything aligns under each header; this assumes
+		 * 8-character tabs and 17-character BT address */
+		alias_len = (alias == NULL ? 0 : strlen(alias));
+		if (FALSE) { }
+		else if (alias_len < 3)
+			alias_status_gap = "\t\t\t\t";
+		else if (alias_len < 11)
+			alias_status_gap = "\t\t\t";
+		else if (alias_len < 19)
+			alias_status_gap = "\t\t";
+		else
+			alias_status_gap = "\t";
+
+		g_hash_table_insert(device_addrs, g_strdup (address), NULL);
+		printf("%s    %s%s%s%s\n", address, alias, alias_status_gap,
+						paired ? "paired": "unpaired",
+						trusted ? ", trusted" : "");
+	}
+
+	return TRUE;
+}
+
+static void stop_discovery_reply(DBusPendingCall *pending, void *user_data)
+{
+	/* Once we're done discovering and displaying devices, exit gracefully
+	 */
+	g_main_loop_quit(mainloop);
+}
+
+static gboolean stop_discovery_cb(gpointer data)
+{
+	const char *path = data;
+	DBusMessage *msg;
+
+	if (!(msg = create_method_call(path, BLUEZ_ADAPTER, "StopDiscovery")))
+		return FALSE;
+	send_with_reply_and_set_notify(msg, stop_discovery_reply, NULL, NULL);
+
+	dbus_message_unref(msg);
+
+	return FALSE;
+}
+
+/* Listen for Bluetooth devices broadcasting their availability, then display
+ * the results */
+static gboolean cmd_discover(gpointer data)
+{
+	struct cmd_param *param = data;
+	dbus_bool_t success;
+	DBusMessage *msg;
+
+	/* We may recieve multiple messages for each device, because BlueZ
+	 * notifies us any time it gets additional information for a given
+	 * device, we need to prevent printing duplicate information.
+	 *
+	 * So, we use this hash table as a (unique) set to avoid displaying
+	 * information about a single device more than once. */
+	device_addrs = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
+									NULL);
+
+	g_dbus_add_signal_watch(conn, BLUEZ_SERVICE, NULL, BLUEZ_ADAPTER,
+				"DeviceFound", device_found, NULL, NULL);
+
+	if (!(msg = create_method_call(param->path, BLUEZ_ADAPTER,
+							"StartDiscovery")))
+		return FALSE;
+
+	printf("Device Address       Name\t\t\tStatus\n");
+	printf("--------------       ----\t\t\t------\n");
+
+	/* Send the message without registering a notify function. This means we
+	 * won't recieve indication of any errors (which may be acceptable in
+	 * certain instances, such as when discovering visible devices) */
+	success = dbus_connection_send(conn, msg, NULL);
+
+	/* We can't know for sure when we've heard back from all Bluetooth
+	 * devices within range, so we need to wait some number of seconds and
+	 * print details as they come in */
+	if (success)
+		g_timeout_add_seconds(12, stop_discovery_cb, param->path);
+	else
+		ERR("Not enough memory to send message");
+
+	dbus_message_unref(msg);
+
+	return FALSE;
+}
+
 static void run_func(const char *adapter_path, GSourceFunc fn,
 							struct cmd_param *param)
 {
@@ -284,7 +524,7 @@ static void bluetoothd_disconnect(DBusConnection *conn, void *user_data)
 }
 
 static struct cmd_struct commands[] = {
-	{ NULL, NULL},
+	{ "discover", cmd_discover},
 };
 
 /* Returns FALSE in case the command could not be parsed. Any failures during
-- 
1.7.11.4


^ permalink raw reply related

* [PATCH 1/5] bt tool: initial tool handling
From: Gustavo Padovan @ 2012-10-03 17:34 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: travis.reitter, Gustavo Padovan
In-Reply-To: <1349285669-20464-1-git-send-email-gustavo@padovan.org>

From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>

All core code to using this tool is here, the nexts steps will add
commands like 'discover' 'pair' 'agent', etc.
---
 Makefile.tools  |   7 +-
 tools/bt-tool.c | 421 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 427 insertions(+), 1 deletion(-)
 create mode 100644 tools/bt-tool.c

diff --git a/Makefile.tools b/Makefile.tools
index 9637a9f..a7f5827 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -1,7 +1,8 @@
 
 if TOOLS
 bin_PROGRAMS += tools/rfcomm tools/l2ping \
-				tools/hcitool tools/sdptool tools/ciptool
+				tools/hcitool tools/sdptool tools/ciptool \
+				tools/bt
 
 sbin_PROGRAMS += tools/hciattach tools/hciconfig
 
@@ -30,6 +31,10 @@ tools_hcitool_SOURCES = tools/hcitool.c src/oui.h src/oui.c \
 						src/textfile.h src/textfile.c
 tools_hcitool_LDADD = lib/libbluetooth-private.la
 
+tools_bt_SOURCES = $(gdbus_sources) tools/bt-tool.c
+
+tools_bt_LDADD = lib/libbluetooth-private.la @DBUS_LIBS@ @GLIB_LIBS@
+
 tools_sdptool_SOURCES = tools/sdptool.c src/sdp-xml.h src/sdp-xml.c
 tools_sdptool_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@
 
diff --git a/tools/bt-tool.c b/tools/bt-tool.c
new file mode 100644
index 0000000..4edc255
--- /dev/null
+++ b/tools/bt-tool.c
@@ -0,0 +1,421 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2011 Bruno Dilly <bdilly@profusion.mobi>
+ *  Copyright (C) 2011 Gustavo Padovan <gustavo@padovan.org>
+ *  Copyright (C) 2012 Collabora Limited.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+/*
+ * This code is meant, in part, to be a working example of a BlueZ client
+ * written in C.
+ *
+ * If you are new to BlueZ, we recommend you read the code breadth-first,
+ * starting with main(). The function and variable names should be fairly
+ * self-explanatory, with comments filling in details along the way.
+ *
+ * You will also want to reference the BlueZ D-Bus API, which is documented in
+ * /doc of this soruce tree, and the libdbus API, documented here:
+ *
+ *   http://dbus.freedesktop.org/doc/api/html/index.html
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include <dbus/dbus.h>
+#include <gdbus.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#define BLUEZ_SERVICE	"org.bluez"
+#define BLUEZ_MANAGER	"org.bluez.Manager"
+#define BLUEZ_ADAPTER	"org.bluez.Adapter"
+#define BLUEZ_AGENT	"org.bluez.Agent"
+#define BLUEZ_ERROR	"org.bluez.Error"
+
+#define ARRAY_SIZE(x) (int)(sizeof(x)/sizeof(x[0]))
+
+#define ERR(fmt, ...)	fprintf(stderr, fmt "\n", ##__VA_ARGS__)
+
+struct cmd_param {
+	char	*path;
+	int	argc;
+	char	**argv;
+};
+
+struct cmd_struct {
+	const char	*cmd;
+	GSourceFunc	fn;
+};
+
+struct find_adapter_cb_data {
+	GSourceFunc		fn;
+	struct cmd_param	*param;
+};
+
+static GMainLoop *mainloop = NULL;
+static gchar *program_name = NULL;
+
+static bdaddr_t bdaddr;
+static DBusConnection *conn;
+
+static void show_help()
+{
+	printf("usage: %s [-i interface] <command> [<args>]\n"
+	"\n"
+	"options:\n"
+	"	-i <hci dev>, --interface <hci dev>	HCI device\n"
+	"	--help					This help\n"
+	"	--version				Version\n"
+	"\n"
+	"commands:\n"
+	"	discover				Scan for devices\n"
+	"	pair <device address>			Start pairing\n"
+	"	agent					Run BlueZ agent\n"
+							"\n", program_name);
+
+	if(mainloop != NULL)
+		g_main_loop_quit(mainloop);
+}
+
+static struct find_adapter_cb_data *find_adapter_cb_data_new(GSourceFunc fn,
+							struct cmd_param *param)
+{
+	struct find_adapter_cb_data *cb_data;
+
+	cb_data = g_new0(struct find_adapter_cb_data, 1);
+	cb_data->fn = fn;
+	cb_data->param = param;
+
+	return cb_data;
+}
+
+static DBusMessage* create_method_call(const char *adapter_path,
+							const char *interface,
+							const char *method_name)
+{
+	DBusMessage *msg;
+
+	msg = dbus_message_new_method_call(BLUEZ_SERVICE, adapter_path,
+						interface, method_name);
+	if (msg == NULL)
+		ERR("Can't allocate new method call");
+
+	return msg;
+}
+
+/* Utility function to call a D-Bus method and register a notify function to
+ * handle the reply */
+static gboolean send_with_reply_and_set_notify(DBusMessage *msg,
+				DBusPendingCallNotifyFunction notify_func,
+				gpointer user_data,
+				DBusFreeFunction user_data_free)
+{
+	DBusPendingCall *pending;
+	dbus_bool_t success;
+
+	success = dbus_connection_send_with_reply(conn, msg, &pending, -1);
+	if (pending) {
+		dbus_pending_call_set_notify(pending, notify_func, user_data,
+								user_data_free);
+	} else {
+		ERR("D-Bus connection lost before message could be sent");
+		return FALSE;
+	}
+
+	if (!success) {
+		ERR("Not enough memory to send D-Bus message");
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static void run_func(const char *adapter_path, GSourceFunc fn,
+							struct cmd_param *param)
+{
+	param->path = strdup(adapter_path);
+
+	/* track timeout source */
+	g_timeout_add(50, fn, param);
+}
+
+/* Handle the D-Bus method reply for FindAdapter or DefaultAdapter */
+static void get_adapter_reply(DBusPendingCall *pending, void *user_data)
+{
+	struct find_adapter_cb_data *cb_data = user_data;
+	DBusMessage *reply;
+	const char *adapter_path;
+
+	if (!pending)
+		return;
+
+	/* We must ensure that this object remains alive while we need it and
+	 * objects it references (such as the reply) */
+	dbus_pending_call_ref(pending);
+
+	/* By "stealing" the reply, we are accepting responsibility to
+	 * unreference it below. Otherwise, its memory will be leaked */
+	reply = dbus_pending_call_steal_reply(pending);
+	if (!reply) {
+		ERR("FindAdapter() failed.");
+		exit(1);
+	}
+
+	/* Ensure that the reply does not indicate an error */
+	if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
+		ERR("FindAdapter() failed");
+		exit(1);
+	} else {
+		struct DBusError err;
+		dbus_error_init(&err);
+
+		if (!dbus_message_get_args(reply, &err,
+					DBUS_TYPE_OBJECT_PATH, &adapter_path,
+					DBUS_TYPE_INVALID)) {
+			/* Ensure that there was not an error retrieving the
+			 * reply arguments */
+			if (dbus_error_is_set(&err)) {
+				ERR("FindAdapter() failed: %s", err.message);
+				dbus_error_free(&err);
+			} else {
+				ERR("FindAdapter() failed.");
+			}
+			exit(1);
+		}
+	}
+
+	/* In case we successfully retrieved the adapter object, execute our
+	 * core command using its path */
+	if (adapter_path != NULL && strlen(adapter_path) > 0) {
+		run_func(adapter_path, cb_data->fn, cb_data->param);
+	} else {
+		ERR("No such adapter");
+		exit(1);
+	}
+
+	/* Drop our references to these objects to avoid memory leaks */
+	dbus_message_unref(reply);
+	dbus_pending_call_unref(pending);
+}
+
+/* Looks up the adapter D-Bus object which corresponds to the Bluetooth device
+ * we will use (whether the user specified one or we fall back to the default.
+ *
+ * Once we have that object, we execute the core command. */
+static void get_adapter_and_run_func(GSourceFunc fn, struct cmd_param *param)
+{
+	DBusMessage *msg;
+	char *bt_str = NULL;
+	const char *method_name = NULL;
+	gpointer user_data;
+
+	/* The bacmp(), ba2str(), and other Bluetooth address utilities are
+	 * defined in bluetooth.h, in this source tree */
+	if (!bacmp(&bdaddr, BDADDR_ANY)) {
+		method_name = "DefaultAdapter";
+	} else {
+		method_name = "FindAdapter";
+
+		/* Allocate a string large enough for the biggest BT address */
+		bt_str = g_new(char, 18);
+		ba2str(&bdaddr, bt_str);
+	}
+
+	/* Create a new D-Bus method call */
+	if (!(msg = create_method_call("/", BLUEZ_MANAGER, method_name)))
+		exit(1);
+
+	/* In case we're making the FindAdapter D-Bus method call, we need to
+	 * append a method argument */
+	if (bt_str != NULL)
+		dbus_message_append_args(msg, DBUS_TYPE_STRING, &bt_str,
+							DBUS_TYPE_INVALID);
+
+	/* Finally, we need to asynchronously send and receive a response for
+	 * the D-Bus method call. This function does not block at all. Instead,
+	 * the GMainLoop will continue iterating until we get a response, which
+	 * will be passed to the notify function we specify here.
+	 *
+	 * We use only async D-Bus messaging because some of these D-Bus methods
+	 * could potentially take several seconds to complete, In the meantime,
+	 * if we were blocking, our application would be unresponsive and look
+	 * as if it (or * even the entire system upon which it is running) had
+	 * frozen. */
+	user_data = find_adapter_cb_data_new(fn, param);
+	if (!send_with_reply_and_set_notify(msg,  get_adapter_reply, user_data,
+									g_free))
+		exit(1);
+
+	dbus_message_unref(msg);
+}
+
+static void bluetoothd_disconnect(DBusConnection *conn, void *user_data)
+{
+	g_main_loop_quit(mainloop);
+
+	printf("Bluetooth daemon exited.\n");
+
+}
+
+static struct cmd_struct commands[] = {
+	{ NULL, NULL},
+};
+
+/* Returns FALSE in case the command could not be parsed. Any failures during
+ * execution will be handled later */
+static gboolean run_argv(int argc, char **argv)
+{
+	const char *cmd = argv[0];
+	struct cmd_param *param;
+	int i;
+
+	if (argc > 1 && g_str_equal(argv[1], "--help"))
+		cmd = "help";
+
+	for (i = 0; i < ARRAY_SIZE(commands); i++) {
+		struct cmd_struct *p = commands+i;
+		if (cmd == NULL || !g_str_equal(p->cmd, cmd))
+			continue;
+
+		param = malloc(sizeof(*param));
+		if (!param)
+			exit(1);
+
+		/* skip over the name of this program itself */
+		argc--;
+		argv++;
+
+		param->argc = argc;
+		param->argv = argv;
+
+		get_adapter_and_run_func(p->fn, param);
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+static gboolean handle_options(int *argc, char ***argv)
+{
+	gboolean terminal_opt = FALSE;
+
+	bacpy(&bdaddr, BDADDR_ANY);
+
+	while (*argc > 0) {
+		const char *cmd = (*argv)[0];
+		if (cmd != NULL && cmd[0] != '-')
+			break;
+
+		if (g_str_equal(cmd, "--help") ||
+						g_str_equal(cmd, "--version")) {
+			terminal_opt = TRUE;
+			break;
+		}
+
+		/*
+		 * Check remaining flags.
+		 */
+		if(g_str_equal(cmd, "-i") || g_str_equal(cmd, "--interface")) {
+			const char *iface;
+			(*argv)++;
+			(*argc)--;
+			iface = (*argv)[0];
+			if (!strncasecmp(iface, "hci", 3))
+				hci_devba(atoi(iface + 3), &bdaddr);
+			else
+				str2ba(iface, &bdaddr);
+		}
+
+		(*argv)++;
+		(*argc)--;
+	}
+
+	return terminal_opt;
+}
+
+int main(int argc, char **argv)
+{
+	DBusError err;
+	gboolean terminal_opt;
+
+	program_name = g_strdup(argv[0]);
+
+	argv++;
+	argc--;
+	terminal_opt = handle_options(&argc, &argv);
+
+	if (terminal_opt) {
+		if (g_str_equal(argv[0], "--help"))
+			show_help();
+		else if (g_str_equal(argv[0], "--version"))
+			printf("%s\n", VERSION);
+
+		exit(0);
+	}
+
+	mainloop = g_main_loop_new(NULL, FALSE);
+
+	/* This structure must be initialized before it can be used */
+	dbus_error_init(&err);
+
+	/* Set up our connection to the D-Bus system bus, which we will use
+	 * throughout this code.
+	 *
+	 * NOTE: the "g_dbus" namespace used in this file is due to BlueZ's
+	 * internal "gdbus" D-Bus client library (included by gdbus.h), which is
+	 * not to be confused with libgio's D-Bus client functionality with the
+	 * same namespace (which would be included by gio.h) */
+	conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, &err);
+	if (!conn) {
+		if (dbus_error_is_set(&err)) {
+			ERR("Can't connect to system bus: %s", err.message);
+			dbus_error_free(&err);
+		} else {
+			ERR("Can't connect to system bus");
+		}
+
+		exit(1);
+	}
+
+	/* Run the command given in the command line */
+	if (!run_argv(argc, argv)) {
+		ERR("%s: command not understood.", program_name);
+		show_help();
+		exit(1);
+	}
+
+	/* Set up handler in case the bluetooth daemon exits and it disappears
+	 * from the bus */
+	g_dbus_add_service_watch(conn, BLUEZ_SERVICE, NULL,
+					bluetoothd_disconnect, NULL, NULL);
+
+	g_main_loop_run(mainloop);
+
+	return 0;
+}
-- 
1.7.11.4


^ permalink raw reply related

* [PATCH 0/5] add bt command line tool
From: Gustavo Padovan @ 2012-10-03 17:34 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: travis.reitter, Gustavo Padovan

From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>

The following patches add a new tool to handle BlueZ from the comand line.
Today the only code we have for this is the new python scripts. A proper tool
written in C was missing.

This work has two purposes provide a nice tool to use BlueZ and provide a
very nice sample on how to write code that uses the BlueZ's API. You will find
a well documented code in the commits here.

More work is planned on that, I already started some code to handle adapter
and device API's but it is still a work in progress. Should hit them mailing
list any time soon.

After applying this we should consider remove the test/agent.c code since this
one is a much better piece of code.

Thanks to everyone tat helped on this, about a year ago Bruno Dilly and me
started the very first bits of this. And to Travis Reitter that helped a lot
to make this possible.

Gustavo Padovan (2):
  bt tool: initial tool handling
  bt tool: add cmd 'agent'

Travis Reitter (3):
  bt tool: add cmd 'discover'
  bt tool: add cmd 'pair'
  bt tool: add cmd 'remove'

 Makefile.tools  |    7 +-
 tools/bt-tool.c | 1232 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 1238 insertions(+), 1 deletion(-)
 create mode 100644 tools/bt-tool.c

-- 
1.7.11.4


^ permalink raw reply

* [PATCH] storage: Move adapter info to adapter.conf
From: Frédéric Danis @ 2012-10-03 14:26 UTC (permalink / raw)
  To: linux-bluetooth

Add functions to read and write to .conf files.
Convert adapter "config" file to "adapter.conf".
---
 .gitignore          |    1 +
 Makefile.am         |    3 +-
 Makefile.tools      |    6 +-
 src/keyfile.c       |  282 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/keyfile.h       |   51 ++++++++++
 src/storage.c       |  100 +++++++-----------
 test/test-keyfile.c |  252 +++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 627 insertions(+), 68 deletions(-)
 create mode 100644 src/keyfile.c
 create mode 100644 src/keyfile.h
 create mode 100644 test/test-keyfile.c

diff --git a/.gitignore b/.gitignore
index c9f293a..2f89353 100644
--- a/.gitignore
+++ b/.gitignore
@@ -82,6 +82,7 @@ unit/test-eir
 tools/btmgmt
 monitor/btmon
 emulator/btvirt
+test/test-keyfile
 
 doc/*.bak
 doc/*.stamp
diff --git a/Makefile.am b/Makefile.am
index c27eb01..ba7c8d8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -309,7 +309,8 @@ src_bluetoothd_SOURCES = $(gdbus_sources) $(builtin_sources) \
 			src/dbus-common.c src/dbus-common.h \
 			src/event.h src/event.c \
 			src/oob.h src/oob.c src/eir.h src/eir.c \
-			src/mgmt.c src/mgmt.h
+			src/mgmt.c src/mgmt.h \
+			src/keyfile.h src/keyfile.c
 src_bluetoothd_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@ @DBUS_LIBS@ \
 								-ldl -lrt
 src_bluetoothd_LDFLAGS = $(AM_LDFLAGS) -Wl,--export-dynamic \
diff --git a/Makefile.tools b/Makefile.tools
index 9637a9f..e122b0a 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -157,7 +157,8 @@ noinst_PROGRAMS += test/gaptest test/sdptest test/scotest \
 			test/attest test/hstest test/avtest \
 					test/lmptest test/bdaddr test/agent \
 					test/btiotest test/test-textfile \
-					test/uuidtest test/mpris-player
+					test/uuidtest test/mpris-player \
+					test/test-keyfile
 
 test_hciemu_LDADD = lib/libbluetooth-private.la
 
@@ -195,6 +196,9 @@ test_mpris_player_LDADD = @DBUS_LIBS@ @GLIB_LIBS@
 
 test_test_textfile_SOURCES = test/test-textfile.c src/textfile.h src/textfile.c
 
+test_test_keyfile_SOURCES = test/test-keyfile.c src/keyfile.h src/keyfile.c
+test_test_keyfile_LDADD = @GLIB_LIBS@
+
 dist_man_MANS += test/rctest.1 test/hciemu.1
 
 EXTRA_DIST += test/bdaddr.8
diff --git a/src/keyfile.c b/src/keyfile.c
new file mode 100644
index 0000000..ea5f0bf
--- /dev/null
+++ b/src/keyfile.c
@@ -0,0 +1,282 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include "keyfile.h"
+
+int keyfile_put_string(const char *pathname, const char *group,
+				const char *key, const char *value)
+{
+	GKeyFile *key_file;
+	char *data;
+	FILE *file;
+
+	key_file = g_key_file_new();
+
+	g_key_file_load_from_file(key_file, pathname, 0, NULL);
+
+	g_key_file_set_string(key_file, group, key, value);
+
+	data = g_key_file_to_data(key_file, NULL, NULL);
+	file = fopen(pathname, "w");
+	fputs(data, file);
+	fclose(file);
+
+	g_free(data);
+	g_key_file_free(key_file);
+
+	return 0;
+}
+
+int keyfile_put_boolean(const char *pathname, const char *group,
+				const char *key, gboolean value)
+{
+	GKeyFile *key_file;
+	char *data;
+	FILE *file;
+
+	key_file = g_key_file_new();
+
+	g_key_file_load_from_file(key_file, pathname, 0, NULL);
+
+	g_key_file_set_boolean(key_file, group, key, value);
+
+	data = g_key_file_to_data(key_file, NULL, NULL);
+	file = fopen(pathname, "w");
+	fputs(data, file);
+	fclose(file);
+
+	g_free(data);
+	g_key_file_free(key_file);
+
+	return 0;
+}
+
+int keyfile_put_integer(const char *pathname, const char *group,
+				const char *key, int value)
+{
+	GKeyFile *key_file;
+	char *data;
+	FILE *file;
+
+	key_file = g_key_file_new();
+
+	g_key_file_load_from_file(key_file, pathname, 0, NULL);
+
+	g_key_file_set_integer(key_file, group, key, value);
+
+	data = g_key_file_to_data(key_file, NULL, NULL);
+	file = fopen(pathname, "w");
+	fputs(data, file);
+	fclose(file);
+
+	g_free(data);
+	g_key_file_free(key_file);
+
+	return 0;
+}
+
+char *keyfile_get_string(const char *pathname, const char *group,
+				const char *key)
+{
+	char *str = NULL;
+	GKeyFile *key_file;
+	int err = 0;
+
+	key_file = g_key_file_new();
+
+	if (!g_key_file_load_from_file(key_file, pathname, 0, NULL)) {
+		err = -ENOENT;
+		goto failed;
+	}
+
+	str = g_key_file_get_string(key_file, group, key, NULL);
+	if (!str)
+		err = -EINVAL;
+
+failed:
+	g_key_file_free(key_file);
+	errno = -err;
+
+	return str;
+}
+
+
+int keyfile_get_boolean(const char *pathname, const char *group,
+				const char *key, gboolean *value)
+{
+	GKeyFile *key_file;
+	GError *error = NULL;
+	int err = 0;
+
+	key_file = g_key_file_new();
+
+	if (!g_key_file_load_from_file(key_file, pathname, 0, NULL)) {
+		err = -ENOENT;
+		goto failed;
+	}
+
+	*value = g_key_file_get_boolean(key_file, group, key, &error);
+	if (error) {
+		g_error_free(error);
+		err = -EINVAL;
+	}
+
+failed:
+	g_key_file_free(key_file);
+	errno = -err;
+
+	return 0;
+}
+
+int keyfile_get_integer(const char *pathname, const char *group,
+				const char *key, int *value)
+{
+	GKeyFile *key_file;
+	GError *error = NULL;
+	int err = 0;
+
+	key_file = g_key_file_new();
+
+	if (!g_key_file_load_from_file(key_file, pathname, 0, NULL)) {
+		err = -ENOENT;
+		goto failed;
+	}
+
+	*value = g_key_file_get_integer(key_file, group, key, &error);
+	if (error) {
+		g_error_free(error);
+		err = -EINVAL;
+	}
+
+failed:
+	g_key_file_free(key_file);
+	errno = -err;
+
+	return 0;
+}
+
+int keyfile_del(const char *pathname, const char *group, const char *key)
+{
+	GKeyFile *key_file;
+	char *data;
+	FILE *file;
+	GError *error = NULL;
+	int err = 0;
+
+	key_file = g_key_file_new();
+
+	g_key_file_load_from_file(key_file, pathname, 0, NULL);
+
+	if (key)
+		g_key_file_remove_key(key_file, group, key, &error);
+	else
+		g_key_file_remove_group(key_file, group, &error);
+
+	if (error) {
+		if (error->code != G_KEY_FILE_ERROR_GROUP_NOT_FOUND &&
+				error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND)
+			err = -EINVAL;
+
+		g_error_free(error);
+		goto failed;
+	}
+
+	data = g_key_file_to_data(key_file, NULL, NULL);
+	file = fopen(pathname, "w");
+	fputs(data, file);
+	fclose(file);
+
+	g_free(data);
+
+failed:
+	g_key_file_free(key_file);
+	errno = -err;
+
+	return err;
+}
+
+int keyfile_foreach_key(const char *pathname, const char *group,
+				keyfile_key_cb func, void *data)
+{
+	GKeyFile *key_file;
+	char **keys, **key, *value;
+	int err = 0;
+
+	key_file = g_key_file_new();
+
+	g_key_file_load_from_file(key_file, pathname, 0, NULL);
+	keys = g_key_file_get_keys(key_file, group, NULL, NULL);
+
+	if (!keys) {
+		err = -EINVAL;
+		goto failed;
+	}
+
+	for (key = keys; *key; key++) {
+		value = g_key_file_get_string(key_file, group, *key, NULL);
+		func(*key, value, data);
+	}
+
+failed:
+	g_key_file_free(key_file);
+	errno = -err;
+
+	return err;
+}
+
+int keyfile_foreach_group(const char *pathname,
+				keyfile_group_cb func, void *data)
+{
+	GKeyFile *key_file;
+	char **groups, **group;
+	int err = 0;
+
+	key_file = g_key_file_new();
+
+	g_key_file_load_from_file(key_file, pathname, 0, NULL);
+	groups = g_key_file_get_groups(key_file, NULL);
+
+	if (!groups) {
+		err = -EINVAL;
+		goto failed;
+	}
+
+	for (group = groups; *group; group++)
+		func(*group, data);
+
+failed:
+	g_key_file_free(key_file);
+	errno = -err;
+
+	return err;
+}
diff --git a/src/keyfile.h b/src/keyfile.h
new file mode 100644
index 0000000..b2e19c3
--- /dev/null
+++ b/src/keyfile.h
@@ -0,0 +1,51 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __KEYFILE_H
+#define __KEYFILE_H
+
+int keyfile_put_string(const char *pathname, const char *group,
+				const char *key, const char *value);
+int keyfile_put_boolean(const char *pathname, const char *group,
+				const char *key, gboolean value);
+int keyfile_put_integer(const char *pathname, const char *group,
+				const char *key, int value);
+
+char *keyfile_get_string(const char *pathname, const char *group,
+				const char *key);
+int keyfile_get_boolean(const char *pathname, const char *group,
+				const char *key, gboolean *value);
+int keyfile_get_integer(const char *pathname, const char *group,
+				const char *key, int *value);
+
+int keyfile_del(const char *pathname, const char *group, const char *key);
+
+typedef void (*keyfile_key_cb) (char *key, char *value, void *data);
+typedef void (*keyfile_group_cb) (char *group, void *data);
+
+int keyfile_foreach_key(const char *pathname, const char *group,
+				keyfile_key_cb func, void *data);
+int keyfile_foreach_group(const char *pathname,
+				keyfile_group_cb func, void *data);
+
+#endif /* __KEYFILE_H */
diff --git a/src/storage.c b/src/storage.c
index 96db6f5..eeae246 100644
--- a/src/storage.c
+++ b/src/storage.c
@@ -44,6 +44,7 @@
 #include <bluetooth/uuid.h>
 
 #include "textfile.h"
+#include "keyfile.h"
 #include "glib-helper.h"
 #include "storage.h"
 
@@ -112,91 +113,65 @@ int write_device_alias(const char *src, const char *dst, uint8_t dst_type,
 
 int write_discoverable_timeout(bdaddr_t *bdaddr, int timeout)
 {
-	char filename[PATH_MAX + 1], str[32];
-
-	snprintf(str, sizeof(str), "%d", timeout);
+	char filename[PATH_MAX + 1];
 
-	create_filename(filename, PATH_MAX, bdaddr, "config");
+	create_filename(filename, PATH_MAX, bdaddr, "adapter.conf");
 
 	create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
 
-	return textfile_put(filename, "discovto", str);
+	return keyfile_put_integer(filename, "General", "DiscovTO", timeout);
 }
 
 int read_discoverable_timeout(const char *src, int *timeout)
 {
-	char filename[PATH_MAX + 1], *str;
-
-	create_name(filename, PATH_MAX, STORAGEDIR, src, "config");
-
-	str = textfile_get(filename, "discovto");
-	if (!str)
-		return -ENOENT;
-
-	if (sscanf(str, "%d", timeout) != 1) {
-		free(str);
-		return -ENOENT;
-	}
+	char filename[PATH_MAX + 1];
 
-	free(str);
+	create_name(filename, PATH_MAX, STORAGEDIR, src, "adapter.conf");
 
-	return 0;
+	return keyfile_get_integer(filename, "General", "DiscovTO", timeout);
 }
 
 int write_pairable_timeout(bdaddr_t *bdaddr, int timeout)
 {
-	char filename[PATH_MAX + 1], str[32];
-
-	snprintf(str, sizeof(str), "%d", timeout);
+	char filename[PATH_MAX + 1];
 
-	create_filename(filename, PATH_MAX, bdaddr, "config");
+	create_filename(filename, PATH_MAX, bdaddr, "adapter.conf");
 
 	create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
 
-	return textfile_put(filename, "pairto", str);
+	return keyfile_put_integer(filename, "General", "PairTO", timeout);
 }
 
 int read_pairable_timeout(const char *src, int *timeout)
 {
-	char filename[PATH_MAX + 1], *str;
-
-	create_name(filename, PATH_MAX, STORAGEDIR, src, "config");
-
-	str = textfile_get(filename, "pairto");
-	if (!str)
-		return -ENOENT;
-
-	if (sscanf(str, "%d", timeout) != 1) {
-		free(str);
-		return -ENOENT;
-	}
+	char filename[PATH_MAX + 1];
 
-	free(str);
+	create_name(filename, PATH_MAX, STORAGEDIR, src, "adapter.conf");
 
-	return 0;
+	return keyfile_get_integer(filename, "General", "PairTO", timeout);
 }
 
 int write_device_mode(bdaddr_t *bdaddr, const char *mode)
 {
 	char filename[PATH_MAX + 1];
 
-	create_filename(filename, PATH_MAX, bdaddr, "config");
+	create_filename(filename, PATH_MAX, bdaddr, "adapter.conf");
 
 	create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
 
 	if (strcmp(mode, "off") != 0)
-		textfile_put(filename, "onmode", mode);
+		keyfile_put_string(filename, "General", "OnMode", mode);
 
-	return textfile_put(filename, "mode", mode);
+	return keyfile_put_string(filename, "General", "Mode", mode);
 }
 
 int read_device_mode(const char *src, char *mode, int length)
 {
 	char filename[PATH_MAX + 1], *str;
 
-	create_name(filename, PATH_MAX, STORAGEDIR, src, "config");
+	create_name(filename, PATH_MAX, STORAGEDIR, src, "adapter.conf");
 
-	str = textfile_get(filename, "mode");
+	str = keyfile_get_string(filename, "General", "Mode");
 	if (!str)
 		return -ENOENT;
 
@@ -212,9 +187,9 @@ int read_on_mode(const char *src, char *mode, int length)
 {
 	char filename[PATH_MAX + 1], *str;
 
-	create_name(filename, PATH_MAX, STORAGEDIR, src, "config");
+	create_name(filename, PATH_MAX, STORAGEDIR, src, "adapter.conf");
 
-	str = textfile_get(filename, "onmode");
+	str = keyfile_get_string(filename, "General", "OnMode");
 	if (!str)
 		return -ENOENT;
 
@@ -238,11 +213,11 @@ int write_local_name(bdaddr_t *bdaddr, const char *name)
 		else
 			str[i] = name[i];
 
-	create_filename(filename, PATH_MAX, bdaddr, "config");
+	create_filename(filename, PATH_MAX, bdaddr, "adapter.conf");
 
 	create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
 
-	return textfile_put(filename, "name", str);
+	return keyfile_put_string(filename, "General", "Name", str);
 }
 
 int read_local_name(bdaddr_t *bdaddr, char *name)
@@ -250,9 +225,10 @@ int read_local_name(bdaddr_t *bdaddr, char *name)
 	char filename[PATH_MAX + 1], *str;
 	int len;
 
-	create_filename(filename, PATH_MAX, bdaddr, "config");
+	create_filename(filename, PATH_MAX, bdaddr, "adapter.conf");
+
+	str = keyfile_get_string(filename, "General", "Name");
 
-	str = textfile_get(filename, "name");
 	if (!str)
 		return -ENOENT;
 
@@ -272,11 +248,11 @@ int write_local_class(bdaddr_t *bdaddr, uint8_t *class)
 
 	sprintf(str, "0x%2.2x%2.2x%2.2x", class[2], class[1], class[0]);
 
-	create_filename(filename, PATH_MAX, bdaddr, "config");
+	create_filename(filename, PATH_MAX, bdaddr, "adapter.conf");
 
 	create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
 
-	return textfile_put(filename, "class", str);
+	return keyfile_put_string(filename, "General", "Class", str);
 }
 
 int read_local_class(bdaddr_t *bdaddr, uint8_t *class)
@@ -284,9 +260,9 @@ int read_local_class(bdaddr_t *bdaddr, uint8_t *class)
 	char filename[PATH_MAX + 1], tmp[3], *str;
 	int i;
 
-	create_filename(filename, PATH_MAX, bdaddr, "config");
+	create_filename(filename, PATH_MAX, bdaddr, "adapter.conf");
 
-	str = textfile_get(filename, "class");
+	str = keyfile_get_string(filename, "General", "Class");
 	if (!str)
 		return -ENOENT;
 
@@ -1151,28 +1127,20 @@ int write_device_pairable(bdaddr_t *bdaddr, gboolean mode)
 {
 	char filename[PATH_MAX + 1];
 
-	create_filename(filename, PATH_MAX, bdaddr, "config");
+	create_filename(filename, PATH_MAX, bdaddr, "adapter.conf");
 
 	create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
 
-	return textfile_put(filename, "pairable", mode ? "yes" : "no");
+	return keyfile_put_boolean(filename, "General", "Pairable", mode);
 }
 
 int read_device_pairable(bdaddr_t *bdaddr, gboolean *mode)
 {
-	char filename[PATH_MAX + 1], *str;
-
-	create_filename(filename, PATH_MAX, bdaddr, "config");
-
-	str = textfile_get(filename, "pairable");
-	if (!str)
-		return -ENOENT;
-
-	*mode = strcmp(str, "yes") == 0 ? TRUE : FALSE;
+	char filename[PATH_MAX + 1];
 
-	free(str);
+	create_filename(filename, PATH_MAX, bdaddr, "adapter.conf");
 
-	return 0;
+	return keyfile_get_boolean(filename, "General", "Pairable", mode);
 }
 
 gboolean read_blocked(const bdaddr_t *local, const bdaddr_t *remote,
diff --git a/test/test-keyfile.c b/test/test-keyfile.c
new file mode 100644
index 0000000..61d3929
--- /dev/null
+++ b/test/test-keyfile.c
@@ -0,0 +1,252 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2012  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include "keyfile.h"
+
+#define GROUP_1	 "Test strings"
+#define GROUP_2 "others"
+
+static void print_entry(char *key, char *value, void *data)
+{
+	printf("%s %s\n", key, value);
+}
+
+static void print_group(char *group, void *data)
+{
+	char *filename = data;
+
+	printf("[%s]\n", group);
+	keyfile_foreach_key(filename, group, print_entry, NULL);
+}
+
+int main(int argc, char *argv[])
+{
+	char filename[] = "/tmp/keyfile.conf";
+	char key[18], value[512], *str;
+	unsigned int i, j, size, max = 10;
+	gboolean bval;
+	int ival;
+	int fd;
+
+	size = getpagesize();
+	printf("System uses a page size of %d bytes\n\n", size);
+
+	fd = creat(filename, 0644);
+	if (ftruncate(fd, 0) < 0)
+		return -errno;
+
+	memset(value, 0, sizeof(value));
+	for (i = 0; i < (size / sizeof(value)); i++) {
+		if (write(fd, value, sizeof(value)) < 0)
+			return -errno;
+	}
+
+	close(fd);
+
+	/* Test retrieval for non existent group and string key */
+	sprintf(key, "11:11:11:11:11:11");
+	str = keyfile_get_string(filename, GROUP_1, key);
+
+	if (truncate(filename, 0) < 0)
+		return -errno;
+
+	/* Test deletion for non existent group and key */
+	sprintf(key, "00:00:00:00:00:00");
+	if (keyfile_del(filename, GROUP_1, key) < 0)
+		fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
+
+	/* Test retrieval for existent group and string key */
+	memset(value, 0, sizeof(value));
+	if (keyfile_put_string(filename, GROUP_1, key, value) < 0)
+		fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
+
+	str = keyfile_get_string(filename, GROUP_1, key);
+	if (!str)
+		fprintf(stderr, "No value for %s\n", key);
+	else
+		free(str);
+
+	/* Test multiple write of same key before deletion */
+	snprintf(value, sizeof(value), "Test");
+	if (keyfile_put_string(filename, GROUP_1, key, value) < 0)
+		fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
+
+	if (keyfile_put_string(filename, GROUP_1, key, value) < 0)
+		fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
+
+	if (keyfile_put_string(filename, GROUP_1, key, value) < 0)
+		fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
+
+	if (keyfile_del(filename, GROUP_1, key) < 0)
+		fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
+
+	str = keyfile_get_string(filename, GROUP_1, key);
+	if (str) {
+		fprintf(stderr, "Found value for %s\n", key);
+		free(str);
+	}
+
+	/* Test retrieval for existent group and boolean key */
+	if (keyfile_put_boolean(filename, GROUP_2, "bool_key", FALSE) < 0)
+		fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
+
+	if (keyfile_get_boolean(filename, GROUP_2, "bool_key", &bval) < 0)
+		fprintf(stderr, "No value for bool_key\n");
+
+	if (bval)
+		fprintf(stderr, "Error on bool_key\n");
+
+	if (keyfile_put_boolean(filename, GROUP_2, "bool_key", TRUE) < 0)
+		fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
+
+	if (keyfile_get_boolean(filename, GROUP_2, "bool_key", &bval) < 0)
+		fprintf(stderr, "No value for bool_key\n");
+
+	if (!bval)
+		fprintf(stderr, "Error on bool_key\n");
+
+	/* Test retrieval for existent group and integer key */
+	if (keyfile_put_integer(filename, GROUP_2, "int_key", 42) < 0)
+		fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
+
+	if (keyfile_get_integer(filename, GROUP_2, "int_key", &ival) < 0)
+		fprintf(stderr, "No value for int_key\n");
+
+	if (ival != 42)
+		fprintf(stderr, "Error on int_key\n");
+
+	if (keyfile_put_integer(filename, GROUP_2, "int_key", 1) < 0)
+		fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
+
+	if (keyfile_get_integer(filename, GROUP_2, "int_key", &ival) < 0)
+		fprintf(stderr, "No value for int_key\n");
+
+	if (ival != 1)
+		fprintf(stderr, "Error on int_key\n");
+
+	/* Write multiple string keys and check them */
+	for (i = 1; i < max + 1; i++) {
+		sprintf(key, "00:00:00:00:00:%02X", i);
+
+		memset(value, 0, sizeof(value));
+		for (j = 0; j < i; j++)
+			value[j] = 'x';
+
+		printf("%s %s\n", key, value);
+
+		if (keyfile_put_string(filename, GROUP_1, key, value) < 0) {
+			fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
+			break;
+		}
+
+		str = keyfile_get_string(filename, GROUP_1, key);
+		if (!str)
+			fprintf(stderr, "No value for %s\n", key);
+		else
+			free(str);
+	}
+
+	/* Re-write first and last keys */
+	sprintf(key, "00:00:00:00:00:%02X", max);
+
+	memset(value, 0, sizeof(value));
+	for (j = 0; j < max; j++)
+		value[j] = 'y';
+
+	if (keyfile_put_string(filename, GROUP_1, key, value) < 0)
+		fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
+
+	sprintf(key, "00:00:00:00:00:%02X", 1);
+
+	memset(value, 0, sizeof(value));
+	for (j = 0; j < max; j++)
+		value[j] = 'z';
+
+	if (keyfile_put_string(filename, GROUP_1, key, value) < 0)
+		fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
+
+	printf("\n");
+
+	for (i = 1; i < max + 1; i++) {
+		sprintf(key, "00:00:00:00:00:%02X", i);
+
+		str = keyfile_get_string(filename, GROUP_1, key);
+		if (str) {
+			printf("%s %s\n", key, str);
+			free(str);
+		}
+	}
+
+
+	/* Remove 2nd and (max - 3) keys */
+	sprintf(key, "00:00:00:00:00:%02X", 2);
+
+	if (keyfile_del(filename, GROUP_1, key) < 0)
+		fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
+
+	sprintf(key, "00:00:00:00:00:%02X", max - 3);
+
+	if (keyfile_del(filename, GROUP_1, key) < 0)
+		fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
+
+	printf("\n");
+
+	keyfile_foreach_key(filename, GROUP_1, print_entry, NULL);
+
+
+	/* Remove first, last and non-existent keys */
+	sprintf(key, "00:00:00:00:00:%02X", 1);
+
+	if (keyfile_del(filename, GROUP_1, key) < 0)
+		fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
+
+	sprintf(key, "00:00:00:00:00:%02X", max);
+
+	if (keyfile_del(filename, GROUP_1, key) < 0)
+		fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
+
+	sprintf(key, "00:00:00:00:00:%02X", max + 1);
+
+	if (keyfile_del(filename, GROUP_1, key) < 0)
+		fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
+
+	printf("\n");
+
+	keyfile_foreach_group(filename, print_group, filename);
+
+	return 0;
+}
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v4 18/18] neard: Implement RequestOOB function
From: Szymon Janc @ 2012-10-03 13:18 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1349270311-31103-1-git-send-email-szymon.janc@tieto.com>

This function is used by neard to request data to be transmitted over
OOB channel. It also allows neard to provide data to be used in OOB
pairing without initializing pairing it self.

---
 plugins/neard.c |   90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 89 insertions(+), 1 deletion(-)

diff --git a/plugins/neard.c b/plugins/neard.c
index d44e5c2..632d454 100644
--- a/plugins/neard.c
+++ b/plugins/neard.c
@@ -41,6 +41,7 @@
 #include "eir.h"
 #include "storage.h"
 #include "agent.h"
+#include "hcid.h"
 
 #define NEARD_NAME "org.neard"
 #define NEARD_PATH "/"
@@ -53,6 +54,9 @@ static guint watcher_id = 0;
 static gboolean agent_registered = FALSE;
 static gboolean agent_register_postpone = FALSE;
 
+/* For NFC mimetype limits max OOB EIR size */
+#define NFC_OOB_EIR_MAX UINT8_MAX
+
 static DBusMessage *error_reply(DBusMessage *msg, int error)
 {
 	switch (error) {
@@ -153,6 +157,67 @@ unregister:
 							AGENT_INTERFACE);
 }
 
+static void read_local_complete(struct btd_adapter *adapter, uint8_t *hash,
+					uint8_t *randomizer, void *user_data)
+{
+	DBusMessage *msg = user_data;
+	DBusMessage *reply;
+
+	DBG("");
+
+	if (!agent_registered) {
+		dbus_message_unref(msg);
+
+		if (agent_register_postpone) {
+			agent_register_postpone = FALSE;
+			register_agent();
+		}
+
+		return;
+	}
+
+	if (hash && randomizer) {
+		int len;
+		uint8_t eir[NFC_OOB_EIR_MAX];
+		uint8_t *peir = eir;
+		bdaddr_t addr;
+		DBusMessageIter iter;
+		DBusMessageIter dict;
+
+		adapter_get_address(adapter, &addr);
+
+		len = eir_create_oob(&addr, btd_adapter_get_name(adapter),
+				btd_adapter_get_class(adapter), hash,
+				randomizer, main_opts.did_vendor,
+				main_opts.did_product, main_opts.did_version,
+				main_opts.did_source,
+				btd_adapter_get_services(adapter), eir);
+
+		reply = dbus_message_new_method_return(msg);
+
+		dbus_message_iter_init_append(reply, &iter);
+
+		dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+					DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+					DBUS_TYPE_STRING_AS_STRING
+					DBUS_TYPE_VARIANT_AS_STRING
+					DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+					&dict);
+
+		dict_append_array(&dict, "EIR", DBUS_TYPE_BYTE, &peir, len);
+
+		dbus_message_iter_close_container(&iter, &dict);
+
+	} else {
+		reply = error_reply(msg, EIO);
+	}
+
+	dbus_message_unref(msg);
+
+	if (!g_dbus_send_message(btd_get_dbus_connection(), reply))
+		error("D-Bus send failed");
+}
+
 static void bonding_complete(struct btd_adapter *adapter, bdaddr_t *bdaddr,
 					uint8_t status, void *user_data)
 {
@@ -368,9 +433,32 @@ static DBusMessage *push_oob(DBusConnection *conn, DBusMessage *msg, void *data)
 static DBusMessage *request_oob(DBusConnection *conn, DBusMessage *msg,
 								void *data)
 {
+	struct btd_adapter *adapter;
+	struct oob_handler *handler;
+	int ret;
+
 	DBG("");
 
-	return error_reply(msg, ENOTSUP);
+	adapter = manager_get_default_adapter();
+	ret = check_adapter(adapter);
+	if (ret < 0)
+		return error_reply(msg, -ret);
+
+	ret = process_params(msg, adapter, NULL);
+	if (ret < 0)
+		return error_reply(msg, -ret);
+
+	ret = btd_adapter_read_local_oob_data(adapter);
+	if (ret < 0)
+		return error_reply(msg, -ret);
+
+	handler = g_new0(struct oob_handler, 1);
+	handler->read_local_cb = read_local_complete;
+	handler->user_data = dbus_message_ref(msg);
+
+	btd_adapter_set_oob_handler(adapter, handler);
+
+	return NULL;
 }
 
 static DBusMessage *release(DBusConnection *conn, DBusMessage *msg,
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v4 17/18] neard: Implement PushOOB function
From: Szymon Janc @ 2012-10-03 13:18 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1349270311-31103-1-git-send-email-szymon.janc@tieto.com>

This implements PushOOB function which allows neard to pass data used
for discovery and pairing. Only EIR data type is supported.

---
 plugins/neard.c |  254 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 247 insertions(+), 7 deletions(-)

diff --git a/plugins/neard.c b/plugins/neard.c
index b98c0fe..d44e5c2 100644
--- a/plugins/neard.c
+++ b/plugins/neard.c
@@ -36,6 +36,11 @@
 #include "log.h"
 #include "dbus-common.h"
 #include "adapter.h"
+#include "manager.h"
+#include "device.h"
+#include "eir.h"
+#include "storage.h"
+#include "agent.h"
 
 #define NEARD_NAME "org.neard"
 #define NEARD_PATH "/"
@@ -46,11 +51,31 @@
 
 static guint watcher_id = 0;
 static gboolean agent_registered = FALSE;
+static gboolean agent_register_postpone = FALSE;
 
-static DBusMessage *error_failed(DBusMessage *msg, int error)
+static DBusMessage *error_reply(DBusMessage *msg, int error)
 {
-	return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+	switch (error) {
+	case ENOTSUP:
+		return g_dbus_create_error(msg, ERROR_INTERFACE ".NotSupported",
+						"Operation is not supported");
+
+	case ENOENT:
+		return g_dbus_create_error(msg, ERROR_INTERFACE ".NoSuchDevice",
+							"No such device");
+
+	case EINPROGRESS:
+		return g_dbus_create_error(msg, ERROR_INTERFACE ".InProgress",
+						"Operation already in progress");
+
+	case ENONET:
+		return g_dbus_create_error(msg, ERROR_INTERFACE ".Disabled",
+							"Device disabled");
+
+	default:
+		return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
 							"%s", strerror(error));
+	}
 }
 
 static void register_agent_cb(DBusPendingCall *call, void *user_data)
@@ -128,12 +153,216 @@ unregister:
 							AGENT_INTERFACE);
 }
 
-static DBusMessage *push_oob(DBusConnection *conn, DBusMessage *msg,
-							void *user_data)
+static void bonding_complete(struct btd_adapter *adapter, bdaddr_t *bdaddr,
+					uint8_t status, void *user_data)
+{
+	DBusMessage *msg = user_data;
+	DBusMessage *reply;
+
+	DBG("");
+
+	if (!agent_registered) {
+		dbus_message_unref(msg);
+
+		if (agent_register_postpone) {
+			agent_register_postpone = FALSE;
+			register_agent();
+		}
+
+		return;
+	}
+
+	if (status)
+		reply = error_reply(msg, EIO);
+	else
+		reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+
+	dbus_message_unref(msg);
+
+	if (!g_dbus_send_message(btd_get_dbus_connection(), reply))
+		error("D-Bus send failed");
+}
+
+/* returns 1 if pairing is not needed */
+static int process_eir(struct btd_adapter *adapter, uint8_t *eir, size_t size,
+							bdaddr_t *remote)
+{
+	struct btd_device *device;
+	struct eir_data eir_data;
+	bdaddr_t local;
+	char remote_address[18];
+
+	DBG("size %zu", size);
+
+	memset(&eir_data, 0, sizeof(eir_data));
+
+	if (eir_parse_oob(&eir_data, eir, size) < 0)
+		return -EINVAL;
+
+	ba2str(&eir_data.addr, remote_address);
+
+	DBG("hci%u remote:%s", adapter_get_dev_id(adapter), remote_address);
+
+	device = adapter_find_device(adapter, remote_address);
+
+	/* If already paired do nothing */
+	if (device && device_is_paired(device)) {
+		DBG("already paired");
+		eir_data_free(&eir_data);
+		return 1;
+	}
+
+	/* Pairing in progress... */
+	if (device && device_is_bonding(device, NULL)) {
+		DBG("pairing in progress");
+		eir_data_free(&eir_data);
+		return -EINPROGRESS;
+	}
+
+	/* If we have unpaired device hanging around, purge it */
+	if (device)
+		adapter_remove_device(adapter, device, TRUE);
+
+	adapter_get_address(adapter, &local);
+
+	/* store OOB data */
+	if (eir_data.class != 0)
+		write_remote_class(&local, &eir_data.addr, eir_data.class);
+
+	/* TODO handle incomplete name? */
+	if (eir_data.name)
+		write_device_name(&local, &eir_data.addr, BDADDR_BREDR,
+								eir_data.name);
+
+	if (eir_data.hash)
+		btd_adapter_add_remote_oob_data(adapter, &eir_data.addr,
+					eir_data.hash, eir_data.randomizer);
+
+	/* TODO handle UUIDs? */
+
+	if (remote)
+		bacpy(remote, &eir_data.addr);
+
+	eir_data_free(&eir_data);
+
+	return 0;
+}
+
+static int process_params(DBusMessage *msg, struct btd_adapter *adapter,
+							bdaddr_t *remote)
 {
+	DBusMessageIter iter;
+	DBusMessageIter dict;
+	DBusMessageIter value;
+	DBusMessageIter entry;
+	const char *key;
+	int type;
+
+	dbus_message_iter_init(msg, &iter);
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+		return -EINVAL;
+
+	dbus_message_iter_recurse(&iter, &dict);
+
+	type = dbus_message_iter_get_arg_type(&dict);
+	if (type != DBUS_TYPE_DICT_ENTRY) {
+		if (!remote && type == DBUS_TYPE_INVALID)
+			return 1;
+
+		return -EINVAL;
+	}
+
+	dbus_message_iter_recurse(&dict, &entry);
+
+	if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
+		return -EINVAL;
+
+	dbus_message_iter_get_basic(&entry, &key);
+	dbus_message_iter_next(&entry);
+
+	dbus_message_iter_recurse(&entry, &value);
+
+	/* All keys have byte array type values */
+	if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_ARRAY)
+		return -EINVAL;
+
+	if (strcasecmp(key, "EIR") == 0) {
+		DBusMessageIter array;
+		uint8_t *eir;
+		int size;
+
+		dbus_message_iter_recurse(&value, &array);
+		dbus_message_iter_get_fixed_array(&array, &eir, &size);
+
+		return process_eir(adapter, eir, size, remote);
+	} else if (strcasecmp(key, "nokia.com:bt") == 0) {
+		/* TODO add support for Nokia BT 2.0 proprietary stuff */
+		return -ENOTSUP;
+	}
+
+	return -EINVAL;
+}
+
+static int check_adapter(struct btd_adapter *adapter)
+{
+	gboolean pairable;
+
+	if (!adapter)
+		return -ENOENT;
+
+	if (btd_adapter_check_oob_handler(adapter))
+		return -EINPROGRESS;
+
+	btd_adapter_get_mode(adapter, NULL, NULL, NULL, &pairable);
+
+	if (!pairable || !adapter_get_agent(adapter))
+		return -ENOENT;
+
+	if (!btd_adapter_ssp_enabled(adapter))
+		return -ENOTSUP;
+
+	return 0;
+}
+
+static DBusMessage *push_oob(DBusConnection *conn, DBusMessage *msg, void *data)
+{
+	struct btd_adapter *adapter;
+	struct agent *agent;
+	struct oob_handler *handler;
+	bdaddr_t remote;
+	int ret;
+
 	DBG("");
 
-	return error_failed(msg, ENOTSUP);
+	adapter = manager_get_default_adapter();
+	ret = check_adapter(adapter);
+	if (ret < 0)
+		return error_reply(msg, -ret);
+
+	ret = process_params(msg, adapter, &remote);
+	if (ret < 0)
+		return error_reply(msg, -ret);
+
+	/* already paired, reply immediately */
+	if (ret > 0)
+		return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+
+	agent = adapter_get_agent(adapter);
+
+	ret = adapter_create_bonding(adapter, &remote, BDADDR_BREDR,
+					agent_get_io_capability(agent));
+	if (ret < 0)
+		return error_reply(msg, -ret);
+
+	handler = g_new0(struct oob_handler, 1);
+	handler->bonding_cb = bonding_complete;
+	bacpy(&handler->remote_addr, &remote);
+	handler->user_data = dbus_message_ref(msg);
+
+	btd_adapter_set_oob_handler(adapter, handler);
+
+	return NULL;
 }
 
 static DBusMessage *request_oob(DBusConnection *conn, DBusMessage *msg,
@@ -141,7 +370,7 @@ static DBusMessage *request_oob(DBusConnection *conn, DBusMessage *msg,
 {
 	DBG("");
 
-	return error_failed(msg, ENOTSUP);
+	return error_reply(msg, ENOTSUP);
 }
 
 static DBusMessage *release(DBusConnection *conn, DBusMessage *msg,
@@ -167,6 +396,8 @@ static const GDBusMethodTable neard_methods[] = {
 
 static void neard_appeared(DBusConnection *conn, void *user_data)
 {
+	struct btd_adapter *adapter;
+
 	DBG("");
 
 	if (!g_dbus_register_interface(conn, AGENT_PATH, AGENT_INTERFACE,
@@ -176,7 +407,16 @@ static void neard_appeared(DBusConnection *conn, void *user_data)
 		return;
 	}
 
-	register_agent();
+	/*
+	 * If there is pending action ongoing when neard appeared, possibly
+	 * due to neard crash or release before action was completed, postpone
+	 * register until action is finished.
+	 */
+	adapter = manager_get_default_adapter();
+	if (adapter && btd_adapter_check_oob_handler(adapter))
+		agent_register_postpone = TRUE;
+	else
+		register_agent();
 }
 
 static void neard_vanished(DBusConnection *conn, void *user_data)
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v4 16/18] Add initial neard plugin implementation
From: Szymon Janc @ 2012-10-03 13:18 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1349270311-31103-1-git-send-email-szymon.janc@tieto.com>

Initial implementation. Only register and unregister support.

---
 Makefile.am         |    5 ++
 acinclude.m4        |    6 ++
 bootstrap-configure |    1 +
 plugins/neard.c     |  218 +++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 230 insertions(+)
 create mode 100644 plugins/neard.c

diff --git a/Makefile.am b/Makefile.am
index 9868710..19dd602 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -275,6 +275,11 @@ builtin_modules += dbusoob
 builtin_sources += plugins/dbusoob.c
 endif
 
+if NEARDPLUGIN
+builtin_modules += neard
+builtin_sources += plugins/neard.c
+endif
+
 if MAINTAINER_MODE
 plugin_LTLIBRARIES += plugins/external-dummy.la
 plugins_external_dummy_la_SOURCES = plugins/external-dummy.c
diff --git a/acinclude.m4 b/acinclude.m4
index 9f4b11f..4bac3f0 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -189,6 +189,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
 	dbusoob_enable=no
 	wiimote_enable=no
 	gatt_enable=no
+	neard_enable=no
 
 	AC_ARG_ENABLE(optimization, AC_HELP_STRING([--disable-optimization], [disable code optimization]), [
 		optimization_enable=${enableval}
@@ -299,6 +300,10 @@ AC_DEFUN([AC_ARG_BLUEZ], [
 		gatt_enable=${enableval}
 	])
 
+	AC_ARG_ENABLE(neard, AC_HELP_STRING([--enable-neard], [compile with neard plugin]), [
+		neard_enable=${enableval}
+	])
+
 	misc_cflags=""
 	misc_ldflags=""
 
@@ -350,4 +355,5 @@ AC_DEFUN([AC_ARG_BLUEZ], [
 	AM_CONDITIONAL(WIIMOTEPLUGIN, test "${wiimote_enable}" = "yes")
 	AM_CONDITIONAL(GATTMODULES, test "${gatt_enable}" = "yes")
 	AM_CONDITIONAL(HOGPLUGIN, test "${gatt_enable}" = "yes" && test "${input_enable}" = "yes")
+	AM_CONDITIONAL(NEARDPLUGIN, test "${neard_enable}" = "yes")
 ])
diff --git a/bootstrap-configure b/bootstrap-configure
index 7177c65..c02c246 100755
--- a/bootstrap-configure
+++ b/bootstrap-configure
@@ -24,6 +24,7 @@ fi
 		--enable-test \
 		--enable-cups \
 		--enable-dbusoob \
+		--enable-neard \
 		--enable-sap \
 		--enable-wiimote \
 		--disable-pcmcia \
diff --git a/plugins/neard.c b/plugins/neard.c
new file mode 100644
index 0000000..b98c0fe
--- /dev/null
+++ b/plugins/neard.c
@@ -0,0 +1,218 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012  Tieto Poland
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <gdbus.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/sdp.h>
+
+#include "plugin.h"
+#include "log.h"
+#include "dbus-common.h"
+#include "adapter.h"
+
+#define NEARD_NAME "org.neard"
+#define NEARD_PATH "/"
+#define NEARD_MANAGER_INTERFACE "org.neard.Manager"
+#define AGENT_INTERFACE "org.neard.HandoverAgent"
+#define AGENT_PATH "/org/bluez/neard_handover_agent"
+#define ERROR_INTERFACE "org.neard.HandoverAgent.Error"
+
+static guint watcher_id = 0;
+static gboolean agent_registered = FALSE;
+
+static DBusMessage *error_failed(DBusMessage *msg, int error)
+{
+	return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+							"%s", strerror(error));
+}
+
+static void register_agent_cb(DBusPendingCall *call, void *user_data)
+{
+	DBusMessage *reply;
+	DBusError err;
+
+	reply = dbus_pending_call_steal_reply(call);
+
+	dbus_error_init(&err);
+	if (dbus_set_error_from_message(&err, reply)) {
+		error("neard manager replied with an error: %s, %s",
+						err.name, err.message);
+		dbus_error_free(&err);
+		dbus_message_unref(reply);
+
+		g_dbus_unregister_interface(btd_get_dbus_connection(),
+						AGENT_PATH, AGENT_INTERFACE);
+		return;
+	}
+
+	dbus_message_unref(reply);
+	agent_registered = TRUE;
+}
+
+static void register_agent(void)
+{
+	DBusMessage *message;
+	DBusPendingCall *call;
+	const gchar *path = AGENT_PATH;
+
+	message = dbus_message_new_method_call(NEARD_NAME, NEARD_PATH,
+			NEARD_MANAGER_INTERFACE, "RegisterHandoverAgent");
+	if (!message) {
+		error("Couldn't allocate D-Bus message");
+		return;
+	}
+
+	dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &path,
+							DBUS_TYPE_INVALID);
+
+	if (!dbus_connection_send_with_reply(btd_get_dbus_connection(),
+							message, &call, -1)) {
+		error("D-Bus send failed");
+		return;
+	}
+
+	dbus_pending_call_set_notify(call, register_agent_cb, NULL, NULL);
+	dbus_pending_call_unref(call);
+}
+
+static void unregister_agent(void)
+{
+	DBusMessage *message;
+	const gchar *path = AGENT_PATH;
+
+	agent_registered = FALSE;
+
+	message = dbus_message_new_method_call(NEARD_NAME, NEARD_PATH,
+			NEARD_MANAGER_INTERFACE, "UnregisterHandoverAgent");
+
+	if (!message) {
+		error("Couldn't allocate D-Bus message");
+		goto unregister;
+	}
+
+	dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &path,
+						DBUS_TYPE_INVALID);
+
+	if (!g_dbus_send_message(btd_get_dbus_connection(), message))
+		error("D-Bus send failed");
+
+unregister:
+	g_dbus_unregister_interface(btd_get_dbus_connection(), AGENT_PATH,
+							AGENT_INTERFACE);
+}
+
+static DBusMessage *push_oob(DBusConnection *conn, DBusMessage *msg,
+							void *user_data)
+{
+	DBG("");
+
+	return error_failed(msg, ENOTSUP);
+}
+
+static DBusMessage *request_oob(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	DBG("");
+
+	return error_failed(msg, ENOTSUP);
+}
+
+static DBusMessage *release(DBusConnection *conn, DBusMessage *msg,
+							void *user_data)
+{
+	DBG("");
+
+	agent_registered = FALSE;
+	g_dbus_unregister_interface(conn, AGENT_PATH, AGENT_INTERFACE);
+
+	return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static const GDBusMethodTable neard_methods[] = {
+	{ GDBUS_ASYNC_METHOD("RequestOOB",
+			GDBUS_ARGS({ "data", "a{sv}" }),
+			GDBUS_ARGS({ "data", "a{sv}" }), request_oob) },
+	{ GDBUS_ASYNC_METHOD("PushOOB",
+			GDBUS_ARGS({ "data", "a{sv}"}), NULL, push_oob) },
+	{ GDBUS_METHOD("Release", NULL, NULL, release) },
+	{ }
+};
+
+static void neard_appeared(DBusConnection *conn, void *user_data)
+{
+	DBG("");
+
+	if (!g_dbus_register_interface(conn, AGENT_PATH, AGENT_INTERFACE,
+						neard_methods,
+						NULL, NULL, NULL, NULL)) {
+		error("neard interface init failed on path " AGENT_PATH);
+		return;
+	}
+
+	register_agent();
+}
+
+static void neard_vanished(DBusConnection *conn, void *user_data)
+{
+	DBG("");
+
+	/* neard existed without unregistering agent */
+	if (agent_registered) {
+		agent_registered = FALSE;
+		g_dbus_unregister_interface(conn, AGENT_PATH, AGENT_INTERFACE);
+	}
+}
+
+static int neard_init(void)
+{
+	DBG("Setup neard plugin");
+
+	watcher_id = g_dbus_add_service_watch(btd_get_dbus_connection(),
+						NEARD_NAME, neard_appeared,
+						neard_vanished, NULL, NULL);
+	if (watcher_id == 0)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void neard_exit(void)
+{
+	DBG("Cleanup neard plugin");
+
+	g_dbus_remove_watch(btd_get_dbus_connection(), watcher_id);
+	watcher_id = 0;
+
+	if (agent_registered)
+		unregister_agent();
+}
+
+BLUETOOTH_PLUGIN_DEFINE(neard, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+						neard_init, neard_exit)
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v4 15/18] oob: Refactor oob callback handling and move it to adapter code
From: Szymon Janc @ 2012-10-03 13:18 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1349270311-31103-1-git-send-email-szymon.janc@tieto.com>

This allows oob plugin to register for callback after executing
certain action on adapter. Currently reading local OOB data and
pairing is supported. It should be easy to support more callbacks
in future if needed e.g. powering on.

Thanks to this plugin is not required to duplicate code that would
validate adapter/device when callback is received as callback condition
is check in adapter.

It also allows to pass user data which will be provided back when cb
is called further reducing plugin code.

---
 Makefile.am       |    3 +--
 plugins/dbusoob.c |   62 +++++++++++------------------------------------------
 src/adapter.c     |   44 +++++++++++++++++++++++++++++++++++++
 src/adapter.h     |   20 +++++++++++++++++
 src/mgmt.c        |    8 +++----
 src/oob.c         |   41 -----------------------------------
 src/oob.h         |   32 ---------------------------
 7 files changed, 81 insertions(+), 129 deletions(-)
 delete mode 100644 src/oob.c
 delete mode 100644 src/oob.h

diff --git a/Makefile.am b/Makefile.am
index c27eb01..9868710 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -307,8 +307,7 @@ src_bluetoothd_SOURCES = $(gdbus_sources) $(builtin_sources) \
 			src/profile.h src/profile.c \
 			src/device.h src/device.c src/attio.h \
 			src/dbus-common.c src/dbus-common.h \
-			src/event.h src/event.c \
-			src/oob.h src/oob.c src/eir.h src/eir.c \
+			src/event.h src/event.c src/eir.h src/eir.c \
 			src/mgmt.c src/mgmt.h
 src_bluetoothd_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@ @DBUS_LIBS@ \
 								-ldl -lrt
diff --git a/plugins/dbusoob.c b/plugins/dbusoob.c
index d3bca9e..ea40355 100644
--- a/plugins/dbusoob.c
+++ b/plugins/dbusoob.c
@@ -44,16 +44,10 @@
 #include "dbus-common.h"
 #include "event.h"
 #include "error.h"
-#include "oob.h"
 #include "storage.h"
 
 #define OOB_INTERFACE	"org.bluez.OutOfBand"
 
-struct oob_request {
-	struct btd_adapter *adapter;
-	DBusMessage *msg;
-};
-
 struct oob_data {
 	char *addr;
 	uint8_t *hash;
@@ -62,47 +56,22 @@ struct oob_data {
 	const char *name;
 };
 
-static GSList *oob_requests = NULL;
-
-static gint oob_request_cmp(gconstpointer a, gconstpointer b)
-{
-	const struct oob_request *data = a;
-	const struct btd_adapter *adapter = b;
-
-	return data->adapter != adapter;
-}
-
-static struct oob_request *find_oob_request(struct btd_adapter *adapter)
-{
-	GSList *match;
-
-	match = g_slist_find_custom(oob_requests, adapter, oob_request_cmp);
-
-	if (match)
-		return match->data;
-
-	return NULL;
-}
-
 static void read_local_data_complete(struct btd_adapter *adapter, uint8_t *hash,
-				uint8_t *randomizer)
+				uint8_t *randomizer, void *user_data)
 {
 	struct DBusMessage *reply;
-	struct oob_request *oob_request;
 	DBusMessageIter iter;
 	DBusMessageIter dict;
+	DBusMessage *msg = user_data;
 
-	oob_request = find_oob_request(adapter);
-	if (!oob_request)
-		return;
+	DBG("");
 
 	if (!hash || !randomizer) {
-		reply = btd_error_failed(oob_request->msg,
-					"Failed to read local OOB data.");
+		reply = btd_error_failed(msg, "Failed to read local OOB data");
 		goto done;
 	}
 
-	reply = dbus_message_new_method_return(oob_request->msg);
+	reply = dbus_message_new_method_return(msg);
 	if (!reply)
 		goto done;
 
@@ -119,9 +88,7 @@ static void read_local_data_complete(struct btd_adapter *adapter, uint8_t *hash,
 	dbus_message_iter_close_container(&iter, &dict);
 
 done:
-	oob_requests = g_slist_remove(oob_requests, oob_request);
-	dbus_message_unref(oob_request->msg);
-	g_free(oob_request);
+	dbus_message_unref(msg);
 
 	if (!reply) {
 		error("Couldn't allocate D-Bus message");
@@ -136,21 +103,22 @@ static DBusMessage *read_local_data(DBusConnection *conn, DBusMessage *msg,
 								void *data)
 {
 	struct btd_adapter *adapter = data;
-	struct oob_request *oob_request;
+	struct oob_handler *handler;
 
 	if (!btd_adapter_ssp_enabled(adapter))
 		return btd_error_not_supported(msg);
 
-	if (find_oob_request(adapter))
+	if (btd_adapter_check_oob_handler(adapter))
 		return btd_error_in_progress(msg);
 
 	if (btd_adapter_read_local_oob_data(adapter))
 		return btd_error_failed(msg, "Request failed.");
 
-	oob_request = g_new(struct oob_request, 1);
-	oob_request->adapter = adapter;
-	oob_requests = g_slist_append(oob_requests, oob_request);
-	oob_request->msg = dbus_message_ref(msg);
+	handler = g_new0(struct oob_handler, 1);
+	handler->read_local_cb = read_local_data_complete;
+	handler->user_data = dbus_message_ref(msg);
+
+	btd_adapter_set_oob_handler(adapter, handler);
 
 	return NULL;
 }
@@ -336,8 +304,6 @@ static int oob_probe(struct btd_adapter *adapter)
 
 static void oob_remove(struct btd_adapter *adapter)
 {
-	read_local_data_complete(adapter, NULL, NULL);
-
 	g_dbus_unregister_interface(btd_get_dbus_connection(),
 				adapter_get_path(adapter), OOB_INTERFACE);
 }
@@ -352,8 +318,6 @@ static int dbusoob_init(void)
 {
 	DBG("Setup dbusoob plugin");
 
-	oob_register_cb(read_local_data_complete);
-
 	return btd_register_adapter_driver(&oob_driver);
 }
 
diff --git a/src/adapter.c b/src/adapter.c
index 0871a37..073c722 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -157,6 +157,8 @@ struct btd_adapter {
 
 	GSList *drivers;
 	GSList *profiles;
+
+	struct oob_handler *oob_handler;
 };
 
 static gboolean process_auth_queue(gpointer user_data);
@@ -3716,6 +3718,22 @@ int adapter_cancel_bonding(struct btd_adapter *adapter, bdaddr_t *bdaddr)
 	return mgmt_cancel_bonding(adapter->dev_id, bdaddr);
 }
 
+static void check_oob_bonding_complete(struct btd_adapter *adapter,
+					bdaddr_t *bdaddr, uint8_t status)
+{
+	if (!adapter->oob_handler || !adapter->oob_handler->bonding_cb)
+		return;
+
+	if (bacmp(bdaddr, &adapter->oob_handler->remote_addr) != 0)
+		return;
+
+	adapter->oob_handler->bonding_cb(adapter, bdaddr, status,
+					adapter->oob_handler->user_data);
+
+	g_free(adapter->oob_handler);
+	adapter->oob_handler = NULL;
+}
+
 void adapter_bonding_complete(struct btd_adapter *adapter, bdaddr_t *bdaddr,
 								uint8_t status)
 {
@@ -3735,6 +3753,8 @@ void adapter_bonding_complete(struct btd_adapter *adapter, bdaddr_t *bdaddr,
 		adapter->discov_suspended = FALSE;
 		mgmt_start_discovery(adapter->dev_id);
 	}
+
+	check_oob_bonding_complete(adapter, bdaddr, status);
 }
 
 int btd_adapter_read_local_oob_data(struct btd_adapter *adapter)
@@ -3759,3 +3779,27 @@ int btd_adapter_ssp_enabled(struct btd_adapter *adapter)
 {
 	return mgmt_ssp_enabled(adapter->dev_id);
 }
+
+void btd_adapter_set_oob_handler(struct btd_adapter *adapter,
+						struct oob_handler *handler)
+{
+	adapter->oob_handler = handler;
+}
+
+gboolean btd_adapter_check_oob_handler(struct btd_adapter *adapter)
+{
+	return adapter->oob_handler != NULL;
+}
+
+void adapter_read_local_oob_data_complete(struct btd_adapter *adapter,
+					uint8_t *hash, uint8_t *randomizer)
+{
+	if (!adapter->oob_handler || !adapter->oob_handler->read_local_cb)
+		return;
+
+	adapter->oob_handler->read_local_cb(adapter, hash, randomizer,
+					adapter->oob_handler->user_data);
+
+	g_free(adapter->oob_handler);
+	adapter->oob_handler = NULL;
+}
diff --git a/src/adapter.h b/src/adapter.h
index f41ca55..7ca8d95 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -43,6 +43,20 @@
 
 struct btd_adapter;
 
+typedef void (*oob_read_local_cb_t) (struct btd_adapter *adapter,
+					uint8_t *hash, uint8_t *randomizer,
+					void *user_data);
+typedef void (*oob_bonding_cb_t) (struct btd_adapter *adapter,
+					bdaddr_t *bdaddr, uint8_t status,
+					void *user_data);
+
+struct oob_handler {
+	oob_read_local_cb_t read_local_cb;
+	oob_bonding_cb_t bonding_cb;
+	bdaddr_t remote_addr;
+	void *user_data;
+};
+
 struct link_key_info {
 	bdaddr_t bdaddr;
 	unsigned char key[16];
@@ -226,6 +240,8 @@ void adapter_bonding_complete(struct btd_adapter *adapter, bdaddr_t *bdaddr,
 							uint8_t status);
 
 int btd_adapter_read_local_oob_data(struct btd_adapter *adapter);
+void adapter_read_local_oob_data_complete(struct btd_adapter *adapter,
+					uint8_t *hash, uint8_t *randomizer);
 
 int btd_adapter_add_remote_oob_data(struct btd_adapter *adapter,
 			bdaddr_t *bdaddr, uint8_t *hash, uint8_t *randomizer);
@@ -242,3 +258,7 @@ void adapter_connect_list_add(struct btd_adapter *adapter,
 						struct btd_device *device);
 void adapter_connect_list_remove(struct btd_adapter *adapter,
 						struct btd_device *device);
+
+void btd_adapter_set_oob_handler(struct btd_adapter *adapter,
+						struct oob_handler *handler);
+gboolean btd_adapter_check_oob_handler(struct btd_adapter *adapter);
diff --git a/src/mgmt.c b/src/mgmt.c
index d273b2b..b689be8 100644
--- a/src/mgmt.c
+++ b/src/mgmt.c
@@ -48,7 +48,6 @@
 #include "manager.h"
 #include "device.h"
 #include "event.h"
-#include "oob.h"
 #include "eir.h"
 #include "mgmt.h"
 
@@ -1277,9 +1276,9 @@ static void read_local_oob_data_complete(int sk, uint16_t index, void *buf,
 	DBG("hci%u", index);
 
 	adapter = manager_find_adapter_by_id(index);
-
 	if (adapter)
-		oob_read_local_data_complete(adapter, rp->hash, rp->randomizer);
+		adapter_read_local_oob_data_complete(adapter, rp->hash,
+							rp->randomizer);
 }
 
 static void start_discovery_complete(int sk, uint16_t index, uint8_t status,
@@ -1323,9 +1322,8 @@ static void read_local_oob_data_failed(int sk, uint16_t index)
 	DBG("hci%u", index);
 
 	adapter = manager_find_adapter_by_id(index);
-
 	if (adapter)
-		oob_read_local_data_complete(adapter, NULL, NULL);
+		adapter_read_local_oob_data_complete(adapter, NULL, NULL);
 }
 
 static void handle_pending_uuids(uint16_t index)
diff --git a/src/oob.c b/src/oob.c
deleted file mode 100644
index 75798fb..0000000
--- a/src/oob.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011  ST-Ericsson SA
- *
- *  Author: Szymon Janc <szymon.janc@tieto.com> for ST-Ericsson
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#include "adapter.h"
-#include "oob.h"
-
-static oob_read_cb_t local_oob_read_cb = NULL;
-
-void oob_register_cb(oob_read_cb_t cb)
-{
-	local_oob_read_cb = cb;
-}
-
-void oob_read_local_data_complete(struct btd_adapter *adapter, uint8_t *hash,
-							uint8_t *randomizer)
-{
-	if (local_oob_read_cb)
-		local_oob_read_cb(adapter, hash, randomizer);
-}
diff --git a/src/oob.h b/src/oob.h
deleted file mode 100644
index 5805082..0000000
--- a/src/oob.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011  ST-Ericsson SA
- *
- *  Author: Szymon Janc <szymon.janc@tieto.com> for ST-Ericsson
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-typedef void (*oob_read_cb_t) (struct btd_adapter *adapter, uint8_t *hash,
-							uint8_t *randomizer);
-
-void oob_register_cb(oob_read_cb_t cb);
-
-void oob_read_local_data_complete(struct btd_adapter *adapter, uint8_t *hash,
-							uint8_t *randomizer);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v4 14/18] adapter: Add btd_adapter_get_class function
From: Szymon Janc @ 2012-10-03 13:18 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1349270311-31103-1-git-send-email-szymon.janc@tieto.com>

This is a simple getter to get current Class Of Device of adapter.

---
 src/adapter.c |    5 +++++
 src/adapter.h |    2 ++
 2 files changed, 7 insertions(+)

diff --git a/src/adapter.c b/src/adapter.c
index 8c94574..0871a37 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -2259,6 +2259,11 @@ void btd_adapter_read_class(struct btd_adapter *adapter, uint8_t *major,
 	*minor = cls[0];
 }
 
+uint32_t btd_adapter_get_class(struct btd_adapter *adapter)
+{
+	return adapter->dev_class;
+}
+
 const char *btd_adapter_get_name(struct btd_adapter *adapter)
 {
 	return adapter->name;
diff --git a/src/adapter.h b/src/adapter.h
index 0d5857c..f41ca55 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -86,6 +86,8 @@ void btd_adapter_get_mode(struct btd_adapter *adapter, uint8_t *mode,
 
 void btd_adapter_read_class(struct btd_adapter *adapter, uint8_t *major,
 							uint8_t *minor);
+
+uint32_t btd_adapter_get_class(struct btd_adapter *adapter);
 const char *btd_adapter_get_name(struct btd_adapter *adapter);
 struct btd_device *adapter_get_device(struct btd_adapter *adapter,
 							const char *address);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v4 13/18] adapter: Rename btd_adapter_get_class to btd_adapter_read_class
From: Szymon Janc @ 2012-10-03 13:18 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1349270311-31103-1-git-send-email-szymon.janc@tieto.com>

It better suits what this function really does.

---
 src/adapter.c |    2 +-
 src/adapter.h |    2 +-
 src/mgmt.c    |    2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index d31862f..8c94574 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -2245,7 +2245,7 @@ void btd_adapter_get_mode(struct btd_adapter *adapter, uint8_t *mode,
 		*pairable = adapter->pairable;
 }
 
-void btd_adapter_get_class(struct btd_adapter *adapter, uint8_t *major,
+void btd_adapter_read_class(struct btd_adapter *adapter, uint8_t *major,
 								uint8_t *minor)
 {
 	uint8_t cls[3];
diff --git a/src/adapter.h b/src/adapter.h
index 340d55c..0d5857c 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -84,7 +84,7 @@ void btd_adapter_get_mode(struct btd_adapter *adapter, uint8_t *mode,
 						uint16_t *discoverable_timeout,
 						gboolean *pairable);
 
-void btd_adapter_get_class(struct btd_adapter *adapter, uint8_t *major,
+void btd_adapter_read_class(struct btd_adapter *adapter, uint8_t *major,
 							uint8_t *minor);
 const char *btd_adapter_get_name(struct btd_adapter *adapter);
 struct btd_device *adapter_get_device(struct btd_adapter *adapter,
diff --git a/src/mgmt.c b/src/mgmt.c
index 462e02b..d273b2b 100644
--- a/src/mgmt.c
+++ b/src/mgmt.c
@@ -1116,7 +1116,7 @@ static void read_info_complete(int sk, uint16_t index, void *buf, size_t len)
 	else
 		adapter_name_changed(adapter, (char *) rp->name);
 
-	btd_adapter_get_class(adapter, &major, &minor);
+	btd_adapter_read_class(adapter, &major, &minor);
 	mgmt_set_dev_class(index, major, minor);
 
 	btd_adapter_get_mode(adapter, &mode, NULL, NULL, NULL);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v4 12/18] adapter: Add btd_adapter_get_services function
From: Szymon Janc @ 2012-10-03 13:18 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1349270311-31103-1-git-send-email-szymon.janc@tieto.com>

Services will be used to create EIR to be send over OOB.

---
 src/adapter.c |    5 +++++
 src/adapter.h |    1 +
 2 files changed, 6 insertions(+)

diff --git a/src/adapter.c b/src/adapter.c
index 4ca0c53..d31862f 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -1031,6 +1031,11 @@ struct btd_device *adapter_get_device(struct btd_adapter *adapter,
 	return adapter_create_device(adapter, address, BDADDR_BREDR);
 }
 
+sdp_list_t *btd_adapter_get_services(struct btd_adapter *adapter)
+{
+	return adapter->services;
+}
+
 static gboolean discovery_cb(gpointer user_data)
 {
 	struct btd_adapter *adapter = user_data;
diff --git a/src/adapter.h b/src/adapter.h
index 436f167..340d55c 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -89,6 +89,7 @@ void btd_adapter_get_class(struct btd_adapter *adapter, uint8_t *major,
 const char *btd_adapter_get_name(struct btd_adapter *adapter);
 struct btd_device *adapter_get_device(struct btd_adapter *adapter,
 							const char *address);
+sdp_list_t *btd_adapter_get_services(struct btd_adapter *adapter);
 
 struct btd_device *adapter_find_device(struct btd_adapter *adapter, const char *dest);
 
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v4 11/18] eir: Add support for creating proper OOB EIR
From: Szymon Janc @ 2012-10-03 13:18 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1349270311-31103-1-git-send-email-szymon.janc@tieto.com>

Address and total length field are mandatory part of OOB EIR.

---
 src/eir.c |   39 ++++++++++++++++++++++++++-------------
 src/eir.h |    2 +-
 2 files changed, 27 insertions(+), 14 deletions(-)

diff --git a/src/eir.c b/src/eir.c
index 98a6607..d9fdb32 100644
--- a/src/eir.c
+++ b/src/eir.c
@@ -280,7 +280,7 @@ static void eir_generate_uuid128(sdp_list_t *list, uint8_t *ptr,
 	}
 }
 
-int eir_create_oob(const char *name, uint32_t cod,
+int eir_create_oob(bdaddr_t *addr, const char *name, uint32_t cod,
 			uint8_t *hash, uint8_t *randomizer,
 			uint16_t did_vendor, uint16_t did_product,
 			uint16_t did_version, uint16_t did_source,
@@ -288,12 +288,19 @@ int eir_create_oob(const char *name, uint32_t cod,
 {
 	sdp_list_t *l;
 	uint8_t *ptr = data;
-	uint16_t eir_len = 0;
+	uint16_t eir_optional_len = 0;
+	uint16_t eir_total_len;
 	uint16_t uuid16[HCI_MAX_EIR_LENGTH / 2];
 	int i, uuid_count = 0;
 	gboolean truncated = FALSE;
 	size_t name_len;
 
+	eir_total_len =  sizeof(uint16_t) + sizeof(bdaddr_t);
+	ptr += sizeof(uint16_t);
+
+	memcpy(ptr, addr, sizeof(bdaddr_t));
+	ptr += sizeof(bdaddr_t);
+
 	if (cod > 0) {
 		uint8_t class[3];
 
@@ -307,7 +314,7 @@ int eir_create_oob(const char *name, uint32_t cod,
 		memcpy(ptr, class, sizeof(class));
 		ptr += sizeof(class);
 
-		eir_len += sizeof(class) + 2;
+		eir_optional_len += sizeof(class) + 2;
 	}
 
 	if (hash) {
@@ -317,7 +324,7 @@ int eir_create_oob(const char *name, uint32_t cod,
 		memcpy(ptr, hash, 16);
 		ptr += 16;
 
-		eir_len += 16 + 2;
+		eir_optional_len += 16 + 2;
 	}
 
 	if (randomizer) {
@@ -327,7 +334,7 @@ int eir_create_oob(const char *name, uint32_t cod,
 		memcpy(ptr, randomizer, 16);
 		ptr += 16;
 
-		eir_len += 16 + 2;
+		eir_optional_len += 16 + 2;
 	}
 
 	name_len = strlen(name);
@@ -345,7 +352,7 @@ int eir_create_oob(const char *name, uint32_t cod,
 
 		memcpy(ptr + 2, name, name_len);
 
-		eir_len += (name_len + 2);
+		eir_optional_len += (name_len + 2);
 		ptr += (name_len + 2);
 	}
 
@@ -360,7 +367,7 @@ int eir_create_oob(const char *name, uint32_t cod,
 		*ptr++ = (did_product & 0xff00) >> 8;
 		*ptr++ = (did_version & 0x00ff);
 		*ptr++ = (did_version & 0xff00) >> 8;
-		eir_len += 10;
+		eir_optional_len += 10;
 	}
 
 	/* Group all UUID16 types */
@@ -378,7 +385,8 @@ int eir_create_oob(const char *name, uint32_t cod,
 			continue;
 
 		/* Stop if not enough space to put next UUID16 */
-		if ((eir_len + 2 + sizeof(uint16_t)) > HCI_MAX_EIR_LENGTH) {
+		if ((eir_optional_len + 2 + sizeof(uint16_t)) >
+				HCI_MAX_EIR_LENGTH) {
 			truncated = TRUE;
 			break;
 		}
@@ -392,7 +400,7 @@ int eir_create_oob(const char *name, uint32_t cod,
 			continue;
 
 		uuid16[uuid_count++] = uuid->value.uuid16;
-		eir_len += sizeof(uint16_t);
+		eir_optional_len += sizeof(uint16_t);
 	}
 
 	if (uuid_count > 0) {
@@ -402,7 +410,7 @@ int eir_create_oob(const char *name, uint32_t cod,
 		ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
 
 		ptr += 2;
-		eir_len += 2;
+		eir_optional_len += 2;
 
 		for (i = 0; i < uuid_count; i++) {
 			*ptr++ = (uuid16[i] & 0x00ff);
@@ -411,10 +419,15 @@ int eir_create_oob(const char *name, uint32_t cod,
 	}
 
 	/* Group all UUID128 types */
-	if (eir_len <= HCI_MAX_EIR_LENGTH - 2)
-		eir_generate_uuid128(uuids, ptr, &eir_len);
+	if (eir_optional_len <= HCI_MAX_EIR_LENGTH - 2)
+		eir_generate_uuid128(uuids, ptr, &eir_optional_len);
 
-	return eir_len;
+	eir_total_len += eir_optional_len;
+
+	/* store total length */
+	bt_put_le16(eir_total_len, data);
+
+	return eir_total_len;
 }
 
 gboolean eir_has_data_type(uint8_t *data, size_t len, uint8_t type)
diff --git a/src/eir.h b/src/eir.h
index 0755da5..d8c5e32 100644
--- a/src/eir.h
+++ b/src/eir.h
@@ -53,7 +53,7 @@ struct eir_data {
 void eir_data_free(struct eir_data *eir);
 int eir_parse(struct eir_data *eir, uint8_t *eir_data, uint8_t eir_len);
 int eir_parse_oob(struct eir_data *eir, uint8_t *eir_data, uint16_t eir_len);
-int eir_create_oob(const char *name, uint32_t cod,
+int eir_create_oob(bdaddr_t *addr, const char *name, uint32_t cod,
 			uint8_t *hash, uint8_t *randomizer,
 			uint16_t did_vendor, uint16_t did_product,
 			uint16_t did_version, uint16_t did_source,
-- 
1.7.9.5


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox