2010-11-04 10:10:57

by Szymon Janc

[permalink] [raw]
Subject: [PATCH 0/4] Support for out of band association model

This set of patches add support for out of band association model.
Suggestions from previous discussion ([RFC] D-Bus API for out of
band association model) are taken into account.

Also exemplary plugin which exports OOB functionality over DBus
(proposed API) is included.

Comments are welcome.


Szymon Janc (4):
Add support for Out of Band (OOB) association model.
Add DBus OOB plugin.
Add DBus OOB API documentation.
Add simple-oobprovider for testing.

Makefile.am | 11 ++-
acinclude.m4 | 6 +
doc/oob-api.txt | 62 ++++++++
lib/hci.h | 3 +
plugins/dbusoob.c | 356 +++++++++++++++++++++++++++++++++++++++++++++++
plugins/hciops.c | 70 ++++++++--
src/adapter.c | 5 +
src/adapter.h | 3 +
src/device.c | 80 +++++++++++-
src/device.h | 12 ++
src/event.c | 73 +++++++---
src/event.h | 3 +-
src/oob.c | 61 ++++++++
src/oob.h | 47 ++++++
test/simple-oobprovider | 54 +++++++
15 files changed, 811 insertions(+), 35 deletions(-)
create mode 100644 doc/oob-api.txt
create mode 100644 plugins/dbusoob.c
create mode 100644 src/oob.c
create mode 100644 src/oob.h
create mode 100755 test/simple-oobprovider



2010-11-17 17:15:31

by Jaikumar Ganesh

[permalink] [raw]
Subject: Re: [PATCH 3/4] Add DBus OOB API documentation.

Hi Szymon:

On Tue, Nov 16, 2010 at 2:12 AM, Szymon Janc <[email protected]> wrote:
>> >> Why are we enforcing this limitation ?
>> >
>> > Spec requires that each hash&randomizer values should be used only for one OOB
>> > transfer. Implementation enforces that by allowing only one active OOB plugin
>> > at time and DBUS OOB plugin only 'expose' plugin API over DBUS. So this
>> > limitation is a consequence of that.
>>
>> I don't think the spec says that. It just says every single time the
>> call to read the local adapters hash
>> and randomizer is done you get new values. You can use the value that
>> you have obtained for as many OOB pairings
>> as you wish.
>
> Please see note in Vol2. Part E. 7.3.60:
>
> ? ? ? ?"Each OOB transfer will have unique C and R values so after each OOB
> ? ? ? ?transfer this command shall be used to obtain a new set of values for the next
> ? ? ? ?OOB transfer."
>

Yes we were talking about the same thing, just at different layers. I
was talking about it from the user of the provider.
This looks fine to me.

>
> --
> Szymon Janc
>

2010-11-16 10:12:05

by Szymon Janc

[permalink] [raw]
Subject: Re: [PATCH 3/4] Add DBus OOB API documentation.

> >> Why are we enforcing this limitation ?
> >
> > Spec requires that each hash&randomizer values should be used only for one OOB
> > transfer. Implementation enforces that by allowing only one active OOB plugin
> > at time and DBUS OOB plugin only 'expose' plugin API over DBUS. So this
> > limitation is a consequence of that.
>
> I don't think the spec says that. It just says every single time the
> call to read the local adapters hash
> and randomizer is done you get new values. You can use the value that
> you have obtained for as many OOB pairings
> as you wish.

Please see note in Vol2. Part E. 7.3.60:

"Each OOB transfer will have unique C and R values so after each OOB
transfer this command shall be used to obtain a new set of values for the next
OOB transfer."


--
Szymon Janc

2010-11-16 04:16:39

by Jaikumar Ganesh

[permalink] [raw]
Subject: Re: [PATCH 3/4] Add DBus OOB API documentation.

On Mon, Nov 15, 2010 at 12:54 AM, Szymon Janc <[email protected]> wrote:
> Hi Jaikumar,
>
>> > + ? ? ? ? ? ? ? void Deactivate()
>>
>> Would it better to make this a signal ? Deactivate by itself as the
>> only method doesn't seem to be right.
>
> I'll change it to Release() to be consistent with other (Agent) API as
> suggested by Johan.
>
>> > + ? ? ? ? ? ? ? void RegisterProvider(object provider)
>> > +
>> > + ? ? ? ? ? ? ? ? ? ? ? This method registers provider for DBus OOB plug-in.
>> > + ? ? ? ? ? ? ? ? ? ? ? When provider is successfully registered plug-in becomes
>> > + ? ? ? ? ? ? ? ? ? ? ? active. Only one provider can be registered at time.
>>
>> Why are we enforcing this limitation ?
>
> Spec requires that each hash&randomizer values should be used only for one OOB
> transfer. Implementation enforces that by allowing only one active OOB plugin
> at time and DBUS OOB plugin only 'expose' plugin API over DBUS. So this
> limitation is a consequence of that.

I don't think the spec says that. It just says every single time the
call to read the local adapters hash
and randomizer is done you get new values. You can use the value that
you have obtained for as many OOB pairings
as you wish.

>
> This limitation also allows for (IMHO) simpler plugins implementation as they
> don't have to care about other plugins hanging around to fulfill that
> requirement.
>
>> > + ? ? ? ? ? ? ? array{bye}, array{byte} UpdateLocalOobData(string address)
>>
>> You are not updating anything here. You are just reading the local
>> adapter OOB data
>
> It is updating hash and randomizer. Underlying functions are called Read* as
> this is how corresponding HCI command is called (see Vol2. Part E. 7.3.60).
> I'll change it to Read to keep all calls name consistent with HCI command name
> and add appropriate note in API documentation as this name may be somewhat
> misleading (yet OOB plugin implementer should be aware of that already).
>
> --
> Szymon Janc
>

2010-11-15 10:11:38

by Szymon Janc

[permalink] [raw]
Subject: Re: [PATCH 3/4] Add DBus OOB API documentation.

Hi,

> So the only APIs added are these provider ones and one API in Agent
> code for approval.
>
> So how does bluetoothd decide whether OOB is present for a particular
> remote device for an outgoing pairing case ? Just on the basis of
> whether a provider is registered or am I missing something here.

If there is an active OOB plugin then it is asked for remote OOB data when
io capabilities are established. Based on the answer oob_data field in io
capability reply is set. Dbus OOB plugin becomes active when provider is
registered. If no oob plugin is active oob_data field is always set to 0x00.

> RequestRemoteOobData is called before initiating pairing or when the
> remote end asks for the OOB data ?
> Its unclear from the API description.

I can see that OOB mechanism is somewhat unclear, let me try to clarify:
- local oob data are data generated by local adapter
- remote oob data are data received from remote device
- remote and/or local data are exchange through some OOB mechanism - this takes
place before SSP is started
(note that data exchanged on OOB also contains BT address)
- during SSP active oob plugin is asked for oob data for remote device

So, RequestRemoteOobData is called when io capabilities are being established,
but this asks plugin if it already has OOB data for this device and not
a remote device to provide this data.

Hope this clarifies things a bit :)

--
Szymon Janc

2010-11-15 08:54:23

by Szymon Janc

[permalink] [raw]
Subject: Re: [PATCH 3/4] Add DBus OOB API documentation.

Hi Jaikumar,

> > + void Deactivate()
>
> Would it better to make this a signal ? Deactivate by itself as the
> only method doesn't seem to be right.

I'll change it to Release() to be consistent with other (Agent) API as
suggested by Johan.

> > + void RegisterProvider(object provider)
> > +
> > + This method registers provider for DBus OOB plug-in.
> > + When provider is successfully registered plug-in becomes
> > + active. Only one provider can be registered at time.
>
> Why are we enforcing this limitation ?

Spec requires that each hash&randomizer values should be used only for one OOB
transfer. Implementation enforces that by allowing only one active OOB plugin
at time and DBUS OOB plugin only 'expose' plugin API over DBUS. So this
limitation is a consequence of that.

This limitation also allows for (IMHO) simpler plugins implementation as they
don't have to care about other plugins hanging around to fulfill that
requirement.

> > + array{bye}, array{byte} UpdateLocalOobData(string address)
>
> You are not updating anything here. You are just reading the local
> adapter OOB data

It is updating hash and randomizer. Underlying functions are called Read* as
this is how corresponding HCI command is called (see Vol2. Part E. 7.3.60).
I'll change it to Read to keep all calls name consistent with HCI command name
and add appropriate note in API documentation as this name may be somewhat
misleading (yet OOB plugin implementer should be aware of that already).

--
Szymon Janc

2010-11-12 19:07:06

by Jaikumar Ganesh

[permalink] [raw]
Subject: Re: [PATCH 3/4] Add DBus OOB API documentation.

Hi Szymon:

On Fri, Nov 12, 2010 at 10:29 AM, Johan Hedberg <[email protected]> wrote:
> Hi Jaikumar,
>
> On Fri, Nov 12, 2010, jaikumar Ganesh wrote:
>> > + ? ? ? ? ? ? ? void Deactivate()
>>
>> Would it better to make this a signal ? Deactivate by itself as the
>> only method doesn't seem to be right.
>
> I guess this is analogous to the Release() method which we have for
> agents, so in that sense a method call would be consistent with the rest
> of the BlueZ D-Bus API (but you'd really need to rename this to Release
> then).
>
> Johan
>

So the only APIs added are these provider ones and one API in Agent
code for approval.

So how does bluetoothd decide whether OOB is present for a particular
remote device for an outgoing pairing case ? Just on the basis of
whether a provider is registered or am I missing something here.

RequestRemoteOobData is called before initiating pairing or when the
remote end asks for the OOB data ?
Its unclear from the API description.

Thanks
Jaikumar

2010-11-12 18:29:21

by Johan Hedberg

[permalink] [raw]
Subject: Re: [PATCH 3/4] Add DBus OOB API documentation.

Hi Jaikumar,

On Fri, Nov 12, 2010, jaikumar Ganesh wrote:
> > + ? ? ? ? ? ? ? void Deactivate()
>
> Would it better to make this a signal ? Deactivate by itself as the
> only method doesn't seem to be right.

I guess this is analogous to the Release() method which we have for
agents, so in that sense a method call would be consistent with the rest
of the BlueZ D-Bus API (but you'd really need to rename this to Release
then).

Johan

2010-11-12 18:20:01

by Jaikumar Ganesh

[permalink] [raw]
Subject: Re: [PATCH 3/4] Add DBus OOB API documentation.

Hi Szymon:

On Thu, Nov 4, 2010 at 3:11 AM, Szymon Janc <[email protected]> wrote:
> ---
> ?Makefile.am ? ? | ? ?3 +-
> ?doc/oob-api.txt | ? 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ?2 files changed, 64 insertions(+), 1 deletions(-)
> ?create mode 100644 doc/oob-api.txt
>
> diff --git a/Makefile.am b/Makefile.am
> index d6cbf92..b5157cd 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -358,7 +358,8 @@ EXTRA_DIST += doc/manager-api.txt \
> ? ? ? ? ? ? ? ?doc/service-api.txt doc/agent-api.txt doc/attribute-api.txt \
> ? ? ? ? ? ? ? ?doc/serial-api.txt doc/network-api.txt \
> ? ? ? ? ? ? ? ?doc/input-api.txt doc/audio-api.txt doc/control-api.txt \
> - ? ? ? ? ? ? ? doc/hfp-api.txt doc/assigned-numbers.txt
> + ? ? ? ? ? ? ? doc/hfp-api.txt doc/assigned-numbers.txt doc/oob-api.txt
> +
>
> ?AM_YFLAGS = -d
>
> diff --git a/doc/oob-api.txt b/doc/oob-api.txt
> new file mode 100644
> index 0000000..fce18a7
> --- /dev/null
> +++ b/doc/oob-api.txt
> @@ -0,0 +1,62 @@
> +BlueZ D-Bus OOB API description
> +*******************************
> +
> +Copyright (C) 2010 ?ST-Ericsson SA
> +
> +Author: Szymon Janc <[email protected]> for ST-Ericsson
> +
> +OOB hierarchy
> +=================
> +
> +Service ? ? ? ? unique name
> +Interface ? ? ? org.bluez.OOB
> +Object path ? ? freely definable
> +
> +Methods ? ? ? ? ? ? ? ?array{bye}, array{byte} RequestRemoteOobData(string address)
> +
> + ? ? ? ? ? ? ? ? ? ? ? This method gets called when the service daemon needs to
> + ? ? ? ? ? ? ? ? ? ? ? get hash and randomizer for an OOB authentication.
> +
> + ? ? ? ? ? ? ? ? ? ? ? The return value should be pair of arrays of 16 bytes
> + ? ? ? ? ? ? ? ? ? ? ? each. First hash, second randomizer.
> +
> + ? ? ? ? ? ? ? ? ? ? ? If no OOB data is present for specified address empty
> + ? ? ? ? ? ? ? ? ? ? ? reply should be returned.
> +
> + ? ? ? ? ? ? ? void Deactivate()

Would it better to make this a signal ? Deactivate by itself as the
only method doesn't seem to be right.

> +
> + ? ? ? ? ? ? ? ? ? ? ? This method gets called when DBus plug-in for OOB was
> + ? ? ? ? ? ? ? ? ? ? ? deactivated. There is no need to unregister provider,
> + ? ? ? ? ? ? ? ? ? ? ? because when this method gets called it has already been
> + ? ? ? ? ? ? ? ? ? ? ? unregistered.
> +
> +--------------------------------------------------------------------------------
> +
> +Service ? ? ? ? org.bluez
> +Interface ? ? ? org.bluez.OOB
> +Object path ? ? /org/bluez
> +
> + ? ? ? ? ? ? ? void RegisterProvider(object provider)
> +
> + ? ? ? ? ? ? ? ? ? ? ? This method registers provider for DBus OOB plug-in.
> + ? ? ? ? ? ? ? ? ? ? ? When provider is successfully registered plug-in becomes
> + ? ? ? ? ? ? ? ? ? ? ? active. Only one provider can be registered at time.

Why are we enforcing this limitation ?
> +
> + ? ? ? ? ? ? ? ? ? ? ? Possible errors: org.bluez.Error.AlreadyExists
> +
> + ? ? ? ? ? ? ? void UnregisterProvider(object provider)
> +
> + ? ? ? ? ? ? ? ? ? ? ? This method unregisters provider for DBus OOB plug-in.
> + ? ? ? ? ? ? ? ? ? ? ? When provider is successfully unregistered plug-in
> + ? ? ? ? ? ? ? ? ? ? ? becomes inactive and will emit Deactivated() signal.
> +
> + ? ? ? ? ? ? ? ? ? ? ? Possible errors: org.bluez.Error.DoesNotExist
> +
> + ? ? ? ? ? ? ? array{bye}, array{byte} UpdateLocalOobData(string address)

You are not updating anything here. You are just reading the local
adapter OOB data

> +
> + ? ? ? ? ? ? ? ? ? ? ? This method generates new local OOB data for specified
> + ? ? ? ? ? ? ? ? ? ? ? address (adapter). Return value is pair of arrays 16
> + ? ? ? ? ? ? ? ? ? ? ? bytes each. First hash, second randomizer. Only
> + ? ? ? ? ? ? ? ? ? ? ? registered provider should call this method.
> +
> + ? ? ? ? ? ? ? ? ? ? ? Possible errors: org.bluez.Error.UpdateFailed
> --
> 1.7.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to [email protected]
> More majordomo info at ?http://vger.kernel.org/majordomo-info.html
>

2010-11-04 10:11:01

by Szymon Janc

[permalink] [raw]
Subject: [PATCH 4/4] Add simple-oobprovider for testing.

---
test/simple-oobprovider | 54 +++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 54 insertions(+), 0 deletions(-)
create mode 100755 test/simple-oobprovider

diff --git a/test/simple-oobprovider b/test/simple-oobprovider
new file mode 100755
index 0000000..135f0f7
--- /dev/null
+++ b/test/simple-oobprovider
@@ -0,0 +1,54 @@
+#!/usr/bin/python
+# Copyright (C) 2010 ST-Ericsson SA
+# Author: Szymon Janc <[email protected]> for ST-Ericsson
+
+import gobject
+
+import sys
+import dbus
+import dbus.service
+import dbus.mainloop.glib
+
+class Provider(dbus.service.Object):
+
+ remotedata = None
+
+ @dbus.service.method("org.bluez.OOB",
+ in_signature="s", out_signature="ayay")
+
+ def RequestRemoteOobData(self, address):
+ print "RequestRemoteOobData for %s" % (address)
+ return self.remotedata
+
+if __name__ == '__main__':
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+ bus = dbus.SystemBus()
+
+ manager = dbus.Interface(bus.get_object("org.bluez", "/"),
+ "org.bluez.Manager")
+ adapter = dbus.Interface(bus.get_object("org.bluez",
+ manager.DefaultAdapter()), "org.bluez.Adapter")
+ adr = adapter.GetProperties()['Address']
+
+ oob = dbus.Interface(bus.get_object("org.bluez", "/org/bluez"),
+ "org.bluez.OOB")
+
+ path = "/test/oobprovider"
+ provider = Provider(bus, path)
+
+ mainloop = gobject.MainLoop()
+
+ oob.RegisterProvider(path)
+
+ print "Local data for %s:" % (adr)
+ print oob.UpdateLocalOobData(adr)
+
+ provider.remotedata = input("Provide remote data (in python syntax):\n")
+
+ print "You may try pairing now"
+
+ mainloop.run()
+
+ #adapter.UnregisterProvider(path)
+ #print "Provider unregistered"
--
1.7.1


2010-11-04 10:11:00

by Szymon Janc

[permalink] [raw]
Subject: [PATCH 3/4] Add DBus OOB API documentation.

---
Makefile.am | 3 +-
doc/oob-api.txt | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 64 insertions(+), 1 deletions(-)
create mode 100644 doc/oob-api.txt

diff --git a/Makefile.am b/Makefile.am
index d6cbf92..b5157cd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -358,7 +358,8 @@ EXTRA_DIST += doc/manager-api.txt \
doc/service-api.txt doc/agent-api.txt doc/attribute-api.txt \
doc/serial-api.txt doc/network-api.txt \
doc/input-api.txt doc/audio-api.txt doc/control-api.txt \
- doc/hfp-api.txt doc/assigned-numbers.txt
+ doc/hfp-api.txt doc/assigned-numbers.txt doc/oob-api.txt
+

AM_YFLAGS = -d

diff --git a/doc/oob-api.txt b/doc/oob-api.txt
new file mode 100644
index 0000000..fce18a7
--- /dev/null
+++ b/doc/oob-api.txt
@@ -0,0 +1,62 @@
+BlueZ D-Bus OOB API description
+*******************************
+
+Copyright (C) 2010 ST-Ericsson SA
+
+Author: Szymon Janc <[email protected]> for ST-Ericsson
+
+OOB hierarchy
+=================
+
+Service unique name
+Interface org.bluez.OOB
+Object path freely definable
+
+Methods array{bye}, array{byte} RequestRemoteOobData(string address)
+
+ This method gets called when the service daemon needs to
+ get hash and randomizer for an OOB authentication.
+
+ The return value should be pair of arrays of 16 bytes
+ each. First hash, second randomizer.
+
+ If no OOB data is present for specified address empty
+ reply should be returned.
+
+ void Deactivate()
+
+ This method gets called when DBus plug-in for OOB was
+ deactivated. There is no need to unregister provider,
+ because when this method gets called it has already been
+ unregistered.
+
+--------------------------------------------------------------------------------
+
+Service org.bluez
+Interface org.bluez.OOB
+Object path /org/bluez
+
+ void RegisterProvider(object provider)
+
+ This method registers provider for DBus OOB plug-in.
+ When provider is successfully registered plug-in becomes
+ active. Only one provider can be registered at time.
+
+ Possible errors: org.bluez.Error.AlreadyExists
+
+ void UnregisterProvider(object provider)
+
+ This method unregisters provider for DBus OOB plug-in.
+ When provider is successfully unregistered plug-in
+ becomes inactive and will emit Deactivated() signal.
+
+ Possible errors: org.bluez.Error.DoesNotExist
+
+ array{bye}, array{byte} UpdateLocalOobData(string address)
+
+ This method generates new local OOB data for specified
+ address (adapter). Return value is pair of arrays 16
+ bytes each. First hash, second randomizer. Only
+ registered provider should call this method.
+
+ Possible errors: org.bluez.Error.UpdateFailed
--
1.7.1


2010-11-04 10:10:59

by Szymon Janc

[permalink] [raw]
Subject: [PATCH 2/4] Add DBus OOB plugin.

---
Makefile.am | 5 +
acinclude.m4 | 6 +
plugins/dbusoob.c | 356 +++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 367 insertions(+), 0 deletions(-)
create mode 100644 plugins/dbusoob.c

diff --git a/Makefile.am b/Makefile.am
index 1b71cc4..d6cbf92 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -216,6 +216,11 @@ builtin_modules += maemo6
builtin_sources += plugins/maemo6.c
endif

+if DBUSOOBPLUGIN
+builtin_modules += dbusoob
+builtin_sources += plugins/dbusoob.c
+endif
+
sbin_PROGRAMS += src/bluetoothd

src_bluetoothd_SOURCES = $(gdbus_sources) $(builtin_sources) \
diff --git a/acinclude.m4 b/acinclude.m4
index 287f07d..a52d063 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -193,6 +193,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
configfiles_enable=yes
telephony_driver=dummy
maemo6_enable=no
+ dbusoob_enable=no

AC_ARG_ENABLE(optimization, AC_HELP_STRING([--disable-optimization], [disable code optimization]), [
optimization_enable=${enableval}
@@ -316,6 +317,10 @@ AC_DEFUN([AC_ARG_BLUEZ], [
maemo6_enable=${enableval}
])

+ AC_ARG_ENABLE(dbusoob, AC_HELP_STRING([--enable-dbusoob], [compile with DBUS OOB plugin]), [
+ dbusoob_enable=${enableval}
+ ])
+
AC_ARG_ENABLE(hal, AC_HELP_STRING([--enable-hal], [Use HAL to determine adapter class]), [
hal_enable=${enableval}
])
@@ -372,4 +377,5 @@ AC_DEFUN([AC_ARG_BLUEZ], [
AM_CONDITIONAL(UDEVRULES, test "${udevrules_enable}" = "yes")
AM_CONDITIONAL(CONFIGFILES, test "${configfiles_enable}" = "yes")
AM_CONDITIONAL(MAEMO6PLUGIN, test "${maemo6_enable}" = "yes")
+ AM_CONDITIONAL(DBUSOOBPLUGIN, test "${dbusoob_enable}" = "yes")
])
diff --git a/plugins/dbusoob.c b/plugins/dbusoob.c
new file mode 100644
index 0000000..335de76
--- /dev/null
+++ b/plugins/dbusoob.c
@@ -0,0 +1,356 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 ST-Ericsson SA
+ *
+ * Author: Szymon Janc <[email protected]> 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
+ *
+ */
+
+#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 "manager.h"
+#include "device.h"
+#include "adapter.h"
+#include "dbus-common.h"
+#include "event.h"
+#include "error.h"
+#include "oob.h"
+
+#define OOB_INTERFACE "org.bluez.OOB"
+#define OOB_PATH "/org/bluez"
+
+struct oob_provider {
+ char *name;
+ char *path;
+
+ struct btd_adapter *adapter;
+ DBusMessage *msg;
+
+ guint listener_id;
+ gboolean exited;
+};
+
+static struct oob_provider *provider = NULL;
+static DBusConnection *connection = NULL;
+static struct oob_plugin dbusoob;
+
+static void destroy_provider(void)
+{
+ if (!provider->exited)
+ g_dbus_remove_watch(connection, provider->listener_id);
+
+ if (provider->msg)
+ dbus_message_unref(provider->msg);
+
+ g_free(provider->name);
+ g_free(provider->path);
+ g_free(provider);
+ provider = NULL;
+
+ oob_deactivate_plugin(&dbusoob);
+}
+
+static void provider_exited(DBusConnection *conn, void *user_data)
+{
+ DBG("Provider exited without calling Unregister");
+
+ provider->exited = TRUE;
+ destroy_provider();
+}
+
+static void create_provider(const char *path, const char *name)
+{
+ provider = g_new(struct oob_provider, 1);
+ provider->path = g_strdup(path);
+ provider->name = g_strdup(name);
+ provider->adapter = NULL;
+ provider->msg = NULL;
+ provider->exited = FALSE;
+ provider->listener_id = g_dbus_add_disconnect_watch(connection, name,
+ provider_exited, NULL, NULL);
+
+ oob_activate_plugin(&dbusoob);
+}
+
+static void request_remote_data_reply(DBusPendingCall *call, void *user_data)
+{
+ DBusMessage *msg;
+ DBusError err;
+ struct btd_device *device = user_data;
+ uint8_t *hash = NULL;
+ uint8_t *randomizer = NULL;
+ int32_t hash_len;
+ int32_t rand_len;
+
+ msg = dbus_pending_call_steal_reply(call);
+
+ dbus_error_init(&err);
+ if (dbus_set_error_from_message(&err, msg)) {
+ error("Provider replied with an error: %s, %s", err.name,
+ err.message);
+ dbus_error_free(&err);
+ goto error;
+ }
+
+ dbus_error_init(&err);
+ if (!dbus_message_get_args(msg, &err,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &hash, &hash_len,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &randomizer, &rand_len,
+ DBUS_TYPE_INVALID)
+ || hash_len != 16 || rand_len != 16) {
+ error("RequestRemoteOobData reply signature error: %s, %s",
+ err.name, err.message);
+ dbus_error_free(&err);
+ hash = NULL;
+ randomizer = NULL;
+ }
+
+error:
+ dbus_message_unref(msg);
+ dbus_pending_call_unref(call);
+
+ device_set_oob_data(device, hash, randomizer);
+}
+
+static gboolean request_remote_data(struct btd_device *device)
+{
+ DBusMessage* msg;
+ DBusPendingCall *call = NULL;
+ bdaddr_t ba;
+ char addr[18];
+ const char *paddr = addr;
+ gboolean ret = FALSE;
+
+ msg = dbus_message_new_method_call(provider->name, provider->path,
+ OOB_INTERFACE, "RequestRemoteOobData");
+
+ if (!msg) {
+ error("Couldn't allocate D-Bus message");
+ goto error;
+ }
+
+ device_get_address(device, &ba);
+ ba2str(&ba, addr);
+
+ if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &paddr,
+ DBUS_TYPE_INVALID)) {
+ error ("Couldn't append arguments");
+ goto error;
+ }
+
+ if (!dbus_connection_send_with_reply(connection, msg, &call, -1)) {
+ error("D-Bus send failed");
+ goto error;
+ }
+
+ if (!dbus_pending_call_set_notify(call, request_remote_data_reply,
+ device, NULL)) {
+ error("Couldn't set reply notification.");
+ dbus_pending_call_unref(call);
+ goto error;
+ }
+
+ ret = TRUE;
+
+error:
+ if (msg)
+ dbus_message_unref(msg);
+
+ return ret;
+}
+
+static void local_data_updated(bdaddr_t *ba, uint8_t *hash, uint8_t *randomizer)
+{
+ struct DBusMessage *reply;
+ bdaddr_t addr;
+
+ if (!provider)
+ return;
+
+ adapter_get_address(provider->adapter, &addr);
+ if (bacmp(ba, &addr))
+ return;
+
+ if (hash && randomizer)
+ reply = g_dbus_create_reply(provider->msg,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &hash, 16,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &randomizer, 16,
+ DBUS_TYPE_INVALID);
+ else
+ reply = g_dbus_create_error(provider->msg,
+ ERROR_INTERFACE ".UpdateFailed",
+ "Failed to update local OOB.");
+
+ dbus_message_unref(provider->msg);
+ provider->msg = NULL;
+ provider->adapter = NULL;
+
+ if (!reply) {
+ error("Couldn't allocate D-Bus message");
+ return;
+ }
+
+ if (!g_dbus_send_message(connection, reply))
+ error("D-Bus send failed");
+
+}
+
+static DBusMessage *update_local_data(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ const char *name;
+ const char *addr;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &addr,
+ DBUS_TYPE_INVALID))
+ return NULL;
+
+ name = dbus_message_get_sender(msg);
+ if (!provider || provider->name != name)
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".UpdateFailed",
+ "Not a OOB provider or no provider registered");
+
+ if (provider->msg)
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".UpdateFailed",
+ "Another request in progress.");
+
+ provider->adapter = manager_find_adapter_by_address(addr);
+ if (!provider->adapter)
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".UpdateFailed",
+ "No adapter with given address found");
+
+ if (btd_adapter_read_local_oob_data(provider->adapter))
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".UpdateFailed",
+ "HCI request failed");
+
+ provider->msg = dbus_message_ref(msg);
+ return NULL;
+}
+
+static void plugin_deactivated(void)
+{
+ DBusMessage *msg;
+
+ msg = dbus_message_new_method_call(provider->name, provider->path,
+ OOB_INTERFACE, "Deactivate");
+
+ if (!msg)
+ error("Couldn't allocate D-Bus message");
+ else if (!g_dbus_send_message(connection, msg))
+ error("D-Bus send failed");
+
+ destroy_provider();
+}
+
+static DBusMessage *register_provider(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ const char *path;
+ const char *name;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID))
+ return NULL;
+
+ if (provider)
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".AlreadyExists",
+ "OOB provider already registered");
+
+ name = dbus_message_get_sender(msg);
+ create_provider(path, name);
+
+ DBG("OOB provider registered at %s:%s", provider->name, provider->path);
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *unregister_provider(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ const char *path;
+ const char *name;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID))
+ return NULL;
+
+ name = dbus_message_get_sender(msg);
+
+ if (!provider || !g_str_equal(provider->path, path)
+ || !g_str_equal(provider->name, name))
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".DoesNotExist",
+ "No such OOB provider registered");
+
+ DBG("OOB provider (%s:%s) unregistered", provider->name, provider->path);
+
+ destroy_provider();
+
+ return dbus_message_new_method_return(msg);
+}
+
+static GDBusMethodTable oob_methods[] = {
+ { "RegisterProvider", "o", "", register_provider},
+ { "UnregisterProvider", "o", "", unregister_provider},
+ { "UpdateLocalOobData", "s", "ayay", update_local_data, G_DBUS_METHOD_FLAG_ASYNC},
+ { }
+};
+
+static gboolean register_on_dbus(void)
+{
+ connection = get_dbus_connection();
+
+ if (!g_dbus_register_interface(connection, OOB_PATH, OOB_INTERFACE,
+ oob_methods, NULL, NULL, NULL, NULL)) {
+ error("OOB interface init failed on path %s", OOB_PATH);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static int dbusoob_init(void)
+{
+ DBG("Setup dbusoob plugin");
+
+ dbusoob.request_remote_data = request_remote_data;
+ dbusoob.local_data_updated = local_data_updated;
+ dbusoob.plugin_deactivated = plugin_deactivated;
+
+ return register_on_dbus();
+}
+
+static void dbusoob_exit(void)
+{
+ DBG("Cleanup dbusoob plugin");
+ oob_deactivate_plugin(&dbusoob);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(dbusoob, VERSION,
+ BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, dbusoob_init, dbusoob_exit)
--
1.7.1


2010-11-04 10:10:58

by Szymon Janc

[permalink] [raw]
Subject: [PATCH 1/4] Add support for Out of Band (OOB) association model.

---
Makefile.am | 3 +-
lib/hci.h | 3 ++
plugins/hciops.c | 70 +++++++++++++++++++++++++++++++++++++++--------
src/adapter.c | 5 +++
src/adapter.h | 3 ++
src/device.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
src/device.h | 12 ++++++++
src/event.c | 73 +++++++++++++++++++++++++++++++++++++------------
src/event.h | 3 +-
src/oob.c | 61 +++++++++++++++++++++++++++++++++++++++++
src/oob.h | 47 +++++++++++++++++++++++++++++++
11 files changed, 326 insertions(+), 34 deletions(-)
create mode 100644 src/oob.c
create mode 100644 src/oob.h

diff --git a/Makefile.am b/Makefile.am
index 873f2df..1b71cc4 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -238,7 +238,8 @@ src_bluetoothd_SOURCES = $(gdbus_sources) $(builtin_sources) \
src/adapter.h src/adapter.c \
src/device.h src/device.c \
src/dbus-common.c src/dbus-common.h \
- src/event.h src/event.c
+ src/event.h src/event.c \
+ src/oob.c
src_bluetoothd_LDADD = lib/libbluetooth.la @GLIB_LIBS@ @DBUS_LIBS@ \
@CAPNG_LIBS@ -ldl -lrt
src_bluetoothd_LDFLAGS = -Wl,--export-dynamic \
diff --git a/lib/hci.h b/lib/hci.h
index 0cb120f..409abd9 100644
--- a/lib/hci.h
+++ b/lib/hci.h
@@ -524,6 +524,9 @@ typedef struct {

#define OCF_REMOTE_OOB_DATA_NEG_REPLY 0x0033

+#define OOB_DATA_NOT_PRESENT 0x00
+#define OOB_DATA_PRESENT 0x01
+
#define OCF_IO_CAPABILITY_NEG_REPLY 0x0034
typedef struct {
bdaddr_t bdaddr;
diff --git a/plugins/hciops.c b/plugins/hciops.c
index 8a79010..d8a1d2c 100644
--- a/plugins/hciops.c
+++ b/plugins/hciops.c
@@ -3,6 +3,7 @@
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2004-2010 Marcel Holtmann <[email protected]>
+ * Copyright (C) 2010 ST-Ericsson SA
*
* 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
@@ -47,6 +48,7 @@
#include "event.h"
#include "device.h"
#include "manager.h"
+#include "oob.h"

#define HCI_REQ_TIMEOUT 5000

@@ -504,33 +506,45 @@ static void user_passkey_notify(int dev, bdaddr_t *sba, void *ptr)

static void remote_oob_data_request(int dev, bdaddr_t *sba, void *ptr)
{
- hci_send_cmd(dev, OGF_LINK_CTL, OCF_REMOTE_OOB_DATA_NEG_REPLY, 6, ptr);
+ bdaddr_t *dba = ptr;
+ struct btd_adapter *adapter;
+ struct btd_device *device;
+ char da[18];
+
+ ba2str(dba, da);
+ adapter = manager_find_adapter(sba);
+ device = adapter_find_device(adapter, da);
+
+ if (device_has_oob_data(device)) {
+ remote_oob_data_reply_cp cp;
+
+ bacpy(&cp.bdaddr, dba);
+ device_get_oob_data(device,cp.hash,cp.randomizer);
+
+ hci_send_cmd(dev, OGF_LINK_CTL, OCF_REMOTE_OOB_DATA_REPLY,
+ REMOTE_OOB_DATA_REPLY_CP_SIZE, &cp);
+ } else
+ hci_send_cmd(dev, OGF_LINK_CTL, OCF_REMOTE_OOB_DATA_NEG_REPLY,
+ 6, ptr);
}

static void io_capa_request(int dev, bdaddr_t *sba, bdaddr_t *dba)
{
char sa[18], da[18];
- uint8_t cap, auth;

ba2str(sba, sa); ba2str(dba, da);
info("io_capa_request (sba=%s, dba=%s)", sa, da);

- if (btd_event_get_io_cap(sba, dba, &cap, &auth) < 0) {
+ /* If failed to establish IO capabilities then send negative reply
+ * immediately. Positive reply will be sent when IO capabilities are
+ * established. */
+ if (btd_event_request_io_cap(sba, dba)) {
io_capability_neg_reply_cp cp;
memset(&cp, 0, sizeof(cp));
bacpy(&cp.bdaddr, dba);
cp.reason = HCI_PAIRING_NOT_ALLOWED;
hci_send_cmd(dev, OGF_LINK_CTL, OCF_IO_CAPABILITY_NEG_REPLY,
IO_CAPABILITY_NEG_REPLY_CP_SIZE, &cp);
- } else {
- io_capability_reply_cp cp;
- memset(&cp, 0, sizeof(cp));
- bacpy(&cp.bdaddr, dba);
- cp.capability = cap;
- cp.oob_data = 0x00;
- cp.authentication = auth;
- hci_send_cmd(dev, OGF_LINK_CTL, OCF_IO_CAPABILITY_REPLY,
- IO_CAPABILITY_REPLY_CP_SIZE, &cp);
}
}

@@ -731,6 +745,15 @@ static void read_scan_complete(bdaddr_t *sba, uint8_t status, void *ptr)
adapter_mode_changed(adapter, rp->enable);
}

+static void read_local_oob_data_complete(bdaddr_t *local, uint8_t status,
+ read_local_oob_data_rp *rp)
+{
+ if (status)
+ oob_local_data_updated(local, NULL, NULL);
+ else
+ oob_local_data_updated(local, rp->hash, rp->randomizer);
+}
+
static inline void cmd_complete(int dev, bdaddr_t *sba, void *ptr)
{
evt_cmd_complete *evt = ptr;
@@ -785,6 +808,10 @@ static inline void cmd_complete(int dev, bdaddr_t *sba, void *ptr)
ptr += sizeof(evt_cmd_complete);
adapter_update_tx_power(sba, status, ptr);
break;
+ case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_LOCAL_OOB_DATA):
+ ptr += sizeof(evt_cmd_complete);
+ read_local_oob_data_complete(sba, status, ptr);
+ break;
};
}

@@ -2289,6 +2316,24 @@ static int hciops_get_remote_version(int index, uint16_t handle,
return 0;
}

+static int hciops_read_local_oob_data(int index)
+{
+ int dd;
+ int err = 0;
+
+ dd = hci_open_dev(index);
+ if (dd < 0)
+ return -EIO;
+
+ err = hci_send_cmd(dd, OGF_HOST_CTL, OCF_READ_LOCAL_OOB_DATA, 0, 0);
+ if (err < 0)
+ err = -errno;
+
+ hci_close_dev(dd);
+
+ return err;
+}
+
static struct btd_adapter_ops hci_ops = {
.setup = hciops_setup,
.cleanup = hciops_cleanup,
@@ -2335,6 +2380,7 @@ static struct btd_adapter_ops hci_ops = {
.write_le_host = hciops_write_le_host,
.get_remote_version = hciops_get_remote_version,
.encrypt_link = hciops_encrypt_link,
+ .read_local_oob_data = hciops_read_local_oob_data,
};

static int hciops_init(void)
diff --git a/src/adapter.c b/src/adapter.c
index b25a7fc..3ec562b 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -3752,3 +3752,8 @@ int btd_adapter_encrypt_link(struct btd_adapter *adapter, bdaddr_t *bdaddr,
{
return adapter_ops->encrypt_link(adapter->dev_id, bdaddr, cb, user_data);
}
+
+int btd_adapter_read_local_oob_data(struct btd_adapter *adapter)
+{
+ return adapter_ops->read_local_oob_data(adapter->dev_id);
+}
diff --git a/src/adapter.h b/src/adapter.h
index aa4d686..4ca82b3 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -231,6 +231,7 @@ struct btd_adapter_ops {
gboolean delayed);
int (*encrypt_link) (int index, bdaddr_t *bdaddr, bt_hci_result_t cb,
gpointer user_data);
+ int (*read_local_oob_data) (int index);
};

int btd_register_adapter_ops(struct btd_adapter_ops *ops, gboolean priority);
@@ -291,3 +292,5 @@ int btd_adapter_get_remote_version(struct btd_adapter *adapter,

int btd_adapter_encrypt_link(struct btd_adapter *adapter, bdaddr_t *bdaddr,
bt_hci_result_t cb, gpointer user_data);
+
+int btd_adapter_read_local_oob_data(struct btd_adapter *adapter);
diff --git a/src/device.c b/src/device.c
index b14865c..31cfd89 100644
--- a/src/device.c
+++ b/src/device.c
@@ -4,6 +4,7 @@
*
* Copyright (C) 2006-2010 Nokia Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <[email protected]>
+ * Copyright (C) 2010 ST-Ericsson SA
*
*
* This program is free software; you can redistribute it and/or modify
@@ -59,6 +60,7 @@
#include "sdp-xml.h"
#include "storage.h"
#include "btio.h"
+#include "oob.h"

#define DEFAULT_XML_BUF_SIZE 1024
#define DISCONNECT_TIMER 2
@@ -132,6 +134,9 @@ struct btd_device {
uint8_t cap;
uint8_t auth;

+ uint8_t local_cap;
+ uint8_t local_auth;
+
uint16_t handle; /* Connection handle */

/* Whether were creating a security mode 3 connection */
@@ -149,6 +154,13 @@ struct btd_device {

gboolean has_debug_key;
uint8_t debug_key[16];
+
+ /* For OOB association model */
+ void (*oob_request_cb)(struct btd_device *device);
+ gboolean was_oob_ssp;
+ gboolean has_oob_data;
+ uint8_t hash[16];
+ uint8_t randomizer[16];
};

static uint16_t uuid_list[] = {
@@ -830,6 +842,72 @@ static DBusMessage *disconnect(DBusConnection *conn, DBusMessage *msg,
return NULL;
}

+void device_set_oob_data(struct btd_device *device, uint8_t *hash,
+ uint8_t *randomizer)
+{
+ if (!device)
+ return;
+
+ if (hash && randomizer) {
+ memcpy(device->hash, hash, 16);
+ memcpy(device->randomizer, randomizer, 16);
+ device->has_oob_data = TRUE;
+ device->was_oob_ssp = TRUE;
+ }
+
+ if (device->oob_request_cb) {
+ device->oob_request_cb(device);
+ device->oob_request_cb = NULL;
+ }
+}
+
+gboolean device_get_oob_data(struct btd_device *device, uint8_t *hash,
+ uint8_t *randomizer)
+{
+ if (!device || !device->has_oob_data)
+ return FALSE;
+
+ memcpy(hash, device->hash, 16);
+ memcpy(randomizer, device->randomizer, 16);
+ device->has_oob_data = FALSE;
+
+ return TRUE;
+}
+
+gboolean device_has_oob_data(struct btd_device *device)
+{
+ return device && device->has_oob_data;
+}
+
+gboolean device_request_oob_data(struct btd_device *device, void *cb)
+{
+ if (!device)
+ return FALSE;
+
+ device->was_oob_ssp = FALSE;
+ device->oob_request_cb = cb;
+ return oob_request_remote_data(device);
+}
+
+void device_set_local_auth_cap(struct btd_device *device, uint8_t auth,
+ uint8_t cap)
+{
+ if (!device)
+ return;
+
+ device->local_auth = auth;
+ device->local_cap = cap;
+}
+void device_get_local_auth_cap(struct btd_device *device, uint8_t *auth,
+ uint8_t *cap)
+{
+ if (!device)
+ return;
+
+ *auth = device->local_auth;
+ *cap = device->local_cap;
+}
+
static GDBusMethodTable device_methods[] = {
{ "GetProperties", "", "a{sv}", get_properties },
{ "SetProperty", "sv", "", set_property },
@@ -2282,7 +2360,7 @@ void device_cancel_authentication(struct btd_device *device, gboolean aborted)

gboolean device_is_authenticating(struct btd_device *device)
{
- return (device->authr != NULL);
+ return (device->authr != NULL || device->was_oob_ssp);
}

gboolean device_is_authorizing(struct btd_device *device)
diff --git a/src/device.h b/src/device.h
index b570bd1..b62cdc5 100644
--- a/src/device.h
+++ b/src/device.h
@@ -4,6 +4,7 @@
*
* Copyright (C) 2006-2010 Nokia Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <[email protected]>
+ * Copyright (C) 2010 ST-Ericsson SA
*
*
* This program is free software; you can redistribute it and/or modify
@@ -89,6 +90,17 @@ void device_remove_connection(struct btd_device *device, DBusConnection *conn,
gboolean device_has_connection(struct btd_device *device, uint16_t handle);
void device_request_disconnect(struct btd_device *device, DBusMessage *msg);

+void device_set_oob_data(struct btd_device *device, uint8_t *hash,
+ uint8_t *randomizer);
+gboolean device_get_oob_data(struct btd_device *device, uint8_t *hash,
+ uint8_t *randomizer);
+gboolean device_has_oob_data(struct btd_device *device);
+gboolean device_request_oob_data(struct btd_device *device, void *cb);
+void device_set_local_auth_cap(struct btd_device *device, uint8_t auth,
+ uint8_t cap);
+void device_get_local_auth_cap(struct btd_device *device, uint8_t *auth,
+ uint8_t *cap);
+
typedef void (*disconnect_watch) (struct btd_device *device, gboolean removal,
void *user_data);

diff --git a/src/event.c b/src/event.c
index 60249f0..b551020 100644
--- a/src/event.c
+++ b/src/event.c
@@ -4,6 +4,7 @@
*
* Copyright (C) 2006-2010 Nokia Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <[email protected]>
+ * Copyright (C) 2010 ST-Ericsson SA
*
*
* This program is free software; you can redistribute it and/or modify
@@ -757,26 +758,56 @@ void btd_event_returned_link_key(bdaddr_t *local, bdaddr_t *peer)
device_set_paired(device, TRUE);
}

-int btd_event_get_io_cap(bdaddr_t *local, bdaddr_t *remote,
- uint8_t *cap, uint8_t *auth)
+static void btd_event_io_cap_reply(struct btd_device *device)
+{
+ io_capability_reply_cp cp;
+ int dev;
+ struct btd_adapter *adapter = device_get_adapter(device);
+ uint16_t dev_id = adapter_get_dev_id(adapter);
+
+ dev = hci_open_dev(dev_id);
+ if (dev < 0) {
+ error("hci_open_dev(%d): %s (%d)", dev_id,
+ strerror(errno), errno);
+ return;
+ }
+
+ memset(&cp, 0, sizeof(cp));
+ device_get_address(device, &cp.bdaddr);
+ device_get_local_auth_cap(device, &cp.authentication, &cp.capability);
+ cp.oob_data = device_has_oob_data(device)
+ ? OOB_DATA_PRESENT : OOB_DATA_NOT_PRESENT;
+
+ DBG("final capabilities reply is cap=0x%02x, auth=0x%02x, oob=0x%02x",
+ cp.capability, cp.authentication, cp.oob_data);
+
+ hci_send_cmd(dev, OGF_LINK_CTL, OCF_IO_CAPABILITY_REPLY,
+ IO_CAPABILITY_REPLY_CP_SIZE, &cp);
+
+ hci_close_dev(dev);
+}
+
+int btd_event_request_io_cap(bdaddr_t *local, bdaddr_t *remote)
{
struct btd_adapter *adapter;
struct btd_device *device;
struct agent *agent = NULL;
uint8_t agent_cap;
int err;
+ uint8_t cap;
+ uint8_t auth;

if (!get_adapter_and_device(local, remote, &adapter, &device, TRUE))
return -ENODEV;

- err = btd_adapter_get_auth_info(adapter, remote, auth);
+ err = btd_adapter_get_auth_info(adapter, remote, &auth);
if (err < 0)
return err;

- DBG("initial authentication requirement is 0x%02x", *auth);
+ DBG("initial authentication requirement is 0x%02x", auth);

- if (*auth == 0xff)
- *auth = device_get_auth(device);
+ if (auth == 0xff)
+ auth = device_get_auth(device);

/* Check if the adapter is not pairable and if there isn't a bonding
* in progress */
@@ -785,11 +816,11 @@ int btd_event_get_io_cap(bdaddr_t *local, bdaddr_t *remote,
if (device_get_auth(device) < 0x02) {
DBG("Allowing no bonding in non-bondable mode");
/* No input, no output */
- *cap = 0x03;
+ cap = 0x03;
/* Kernel defaults to general bonding and so
* overwrite for this special case. Otherwise
* non-pairable test cases will fail. */
- *auth = 0x00;
+ auth = 0x00;
goto done;
}
return -EPERM;
@@ -805,13 +836,13 @@ int btd_event_get_io_cap(bdaddr_t *local, bdaddr_t *remote,
}

/* No agent available, and no bonding case */
- if (*auth == 0x00 || *auth == 0x04) {
+ if (auth == 0x00 || auth == 0x04) {
DBG("Allowing no bonding without agent");
/* No input, no output */
- *cap = 0x03;
+ cap = 0x03;
/* If kernel defaults to general bonding, set it
* back to no bonding */
- *auth = 0x00;
+ auth = 0x00;
goto done;
}

@@ -821,7 +852,7 @@ int btd_event_get_io_cap(bdaddr_t *local, bdaddr_t *remote,

agent_cap = agent_get_io_capability(agent);

- if (*auth == 0x00 || *auth == 0x04) {
+ if (auth == 0x00 || auth == 0x04) {
/* If remote requests dedicated bonding follow that lead */
if (device_get_auth(device) == 0x02 ||
device_get_auth(device) == 0x03) {
@@ -830,9 +861,9 @@ int btd_event_get_io_cap(bdaddr_t *local, bdaddr_t *remote,
* then require it, otherwise don't */
if (device_get_cap(device) == 0x03 ||
agent_cap == 0x03)
- *auth = 0x02;
+ auth = 0x02;
else
- *auth = 0x03;
+ auth = 0x03;
}

/* If remote indicates no bonding then follow that. This
@@ -840,7 +871,7 @@ int btd_event_get_io_cap(bdaddr_t *local, bdaddr_t *remote,
* as default. */
if (device_get_auth(device) == 0x00 ||
device_get_auth(device) == 0x01)
- *auth = 0x00;
+ auth = 0x00;

/* If remote requires MITM then also require it, unless
* our IO capability is NoInputNoOutput (so some
@@ -848,13 +879,19 @@ int btd_event_get_io_cap(bdaddr_t *local, bdaddr_t *remote,
if (device_get_auth(device) != 0xff &&
(device_get_auth(device) & 0x01) &&
agent_cap != 0x03)
- *auth |= 0x01;
+ auth |= 0x01;
}

- *cap = agent_get_io_capability(agent);
+ cap = agent_get_io_capability(agent);

done:
- DBG("final authentication requirement is 0x%02x", *auth);
+ DBG("final authentication requirement is 0x%02x", auth);
+
+ device_set_local_auth_cap(device, auth, cap);
+
+ /* If failed to request remote OOB data then reply immediately. */
+ if (!device_request_oob_data(device, btd_event_io_cap_reply))
+ btd_event_io_cap_reply(device);

return 0;
}
diff --git a/src/event.h b/src/event.h
index e918c9e..33d2f76 100644
--- a/src/event.h
+++ b/src/event.h
@@ -36,8 +36,7 @@ void btd_event_le_set_scan_enable_complete(bdaddr_t *local, uint8_t status);
void btd_event_write_simple_pairing_mode_complete(bdaddr_t *local);
void btd_event_read_simple_pairing_mode_complete(bdaddr_t *local, void *ptr);
void btd_event_returned_link_key(bdaddr_t *local, bdaddr_t *peer);
-int btd_event_get_io_cap(bdaddr_t *local, bdaddr_t *remote,
- uint8_t *cap, uint8_t *auth);
+int btd_event_request_io_cap(bdaddr_t *local, bdaddr_t *remote);
int btd_event_set_io_cap(bdaddr_t *local, bdaddr_t *remote,
uint8_t cap, uint8_t auth);
int btd_event_user_confirm(bdaddr_t *sba, bdaddr_t *dba, uint32_t passkey);
diff --git a/src/oob.c b/src/oob.c
new file mode 100644
index 0000000..cc20c67
--- /dev/null
+++ b/src/oob.c
@@ -0,0 +1,61 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 ST-Ericsson SA
+ *
+ * Author: Szymon Janc <[email protected]> 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 <glib.h>
+#include "manager.h"
+#include "adapter.h"
+#include "oob.h"
+
+static struct oob_plugin *active_plugin = NULL;
+
+void oob_activate_plugin(struct oob_plugin *plugin)
+{
+ if (!plugin || !plugin->local_data_updated|| !plugin->plugin_deactivated
+ || !plugin->request_remote_data
+ || active_plugin == plugin)
+ return;
+
+ if (active_plugin)
+ active_plugin->plugin_deactivated();
+
+ active_plugin = plugin;
+}
+
+void oob_deactivate_plugin(struct oob_plugin *plugin)
+{
+ if (active_plugin == plugin)
+ active_plugin = NULL;
+}
+
+gboolean oob_request_remote_data(struct btd_device *device)
+{
+ return active_plugin && active_plugin->request_remote_data(device);
+}
+
+void oob_local_data_updated(bdaddr_t *ba, uint8_t *hash, uint8_t *randomizer)
+{
+ if (active_plugin)
+ active_plugin->local_data_updated(ba, hash, randomizer);
+}
diff --git a/src/oob.h b/src/oob.h
new file mode 100644
index 0000000..ed9fe84
--- /dev/null
+++ b/src/oob.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 ST-Ericsson SA
+ *
+ * Author: Szymon Janc <[email protected]> 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
+ *
+ */
+
+struct oob_plugin
+{
+ /* If request was successfully send this functions should return TRUE.
+ * Function should not block for too long. */
+ gboolean (*request_remote_data)(struct btd_device *device);
+
+ /* Local OOB data updated. If corresponding HCI command failed, hash
+ * and randomizer are NULL */
+ void (*local_data_updated)(bdaddr_t *ba, uint8_t *hash,
+ uint8_t *randomizer);
+
+ /* Plug-in was deactivated (called only for active plug-in). */
+ void (*plugin_deactivated)(void);
+};
+
+/* These functions are called by OOB plug-in.*/
+void oob_activate_plugin(struct oob_plugin *plugin);
+void oob_deactivate_plugin(struct oob_plugin *plugin);
+
+/* These functions are called from stack to interact with OOB plug-in. */
+gboolean oob_request_remote_data(struct btd_device *device);
+void oob_local_data_updated(bdaddr_t *ba, uint8_t *hash, uint8_t *randomizer);
--
1.7.1