From: Scott James Remnant <scott@netsplit.com>
To: linux-bluetooth@vger.kernel.org
Cc: keybuk@chromium.org, Scott James Remnant <scott@netsplit.com>
Subject: [RFC PATCH 2/2] autopair: add autopair plugin
Date: Fri, 20 Jan 2012 17:59:57 -0800 [thread overview]
Message-ID: <1327111197-11446-3-git-send-email-scott@netsplit.com> (raw)
In-Reply-To: <1327111197-11446-1-git-send-email-scott@netsplit.com>
The autopair plugin sends an initial PIN of 0000 to "dumb" devices such
as mice and headsets (list of classes unashamedly stolen from Android)
and registers a bonding complete callback for that device.
If bonding should fail with the fixed PIN, the device is blacklisted
from auto-pairing and the pairing tried again after a short back-off
period, this time using the Agent's RequestPinCode method.
---
Makefile.am | 5 +
acinclude.m4 | 6 ++
plugins/autopair.c | 209 ++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 220 insertions(+), 0 deletions(-)
create mode 100644 plugins/autopair.c
diff --git a/Makefile.am b/Makefile.am
index 8dbe603..cdfdb93 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -278,6 +278,11 @@ builtin_modules += dbusoob
builtin_sources += plugins/dbusoob.c
endif
+if AUTOPAIRPLUGIN
+builtin_modules += autopair
+builtin_sources += plugins/autopair.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 57fc5e0..187a049 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -218,6 +218,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
dbusoob_enable=no
wiimote_enable=no
thermometer_enable=no
+ autopair_enable=no
AC_ARG_ENABLE(optimization, AC_HELP_STRING([--disable-optimization], [disable code optimization]), [
optimization_enable=${enableval}
@@ -374,6 +375,10 @@ AC_DEFUN([AC_ARG_BLUEZ], [
thermometer_enable=${enableval}
])
+ AC_ARG_ENABLE(autopair, AC_HELP_STRING([--enable-autopair], [enable auto-pairplugin]), [
+ autopair_enable=${enableval}
+ ])
+
if (test "${fortify_enable}" = "yes"); then
CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2"
fi
@@ -432,4 +437,5 @@ AC_DEFUN([AC_ARG_BLUEZ], [
AM_CONDITIONAL(DBUSOOBPLUGIN, test "${dbusoob_enable}" = "yes")
AM_CONDITIONAL(WIIMOTEPLUGIN, test "${wiimote_enable}" = "yes")
AM_CONDITIONAL(THERMOMETERPLUGIN, test "${thermometer_enable}" = "yes")
+ AM_CONDITIONAL(AUTOPAIRPLUGIN, test "${autopair_enable}" = "yes")
])
diff --git a/plugins/autopair.c b/plugins/autopair.c
new file mode 100644
index 0000000..6099b0f
--- /dev/null
+++ b/plugins/autopair.c
@@ -0,0 +1,209 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 Google Inc.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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 <sys/stat.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <glib.h>
+
+#include <bluetooth/bluetooth.h>
+
+#include "glib-compat.h"
+#include "plugin.h"
+#include "adapter.h"
+#include "device.h"
+#include "storage.h"
+#include "textfile.h"
+#include "bt_ids.h"
+#include "log.h"
+
+static GSList *attempting = NULL;
+static GSList *dynamic_blacklist = NULL;
+
+static gboolean autopair_bondingcb(struct btd_device *device, uint8_t status)
+{
+ GSList *match;
+ bdaddr_t *ba;
+
+ match = g_slist_find(attempting, device);
+ if (!match)
+ return FALSE;
+
+ attempting = g_slist_remove_link(attempting, match);
+ btd_device_unref(device);
+
+ /* successful pair */
+ if (!status)
+ return FALSE;
+
+ /* failed: blacklist and retry with the user's agent */
+ ba = g_new0(bdaddr_t, 1);
+ device_get_address(device, ba, NULL);
+ dynamic_blacklist = g_slist_prepend(dynamic_blacklist, ba);
+
+ return TRUE;
+}
+
+static void autopair_bonding_cancelcb(struct btd_device *device)
+{
+ GSList *match;
+
+ if ((match = g_slist_find(attempting, device))) {
+ attempting = g_slist_remove_link(attempting, match);
+ btd_device_unref (device);
+ }
+}
+
+static gboolean autopair_attempt(struct btd_device *device)
+{
+ if (g_slist_find(attempting, device))
+ return FALSE;
+
+ attempting = g_slist_prepend(attempting, btd_device_ref(device));
+
+ btd_device_register_bonding_cb(device, autopair_bondingcb,
+ autopair_bonding_cancelcb);
+ return TRUE;
+}
+
+static ssize_t autopair_pincb(struct btd_adapter *adapter,
+ struct btd_device *device, char *pinbuf)
+{
+ bdaddr_t local, peer;
+ uint32_t class;
+
+ /* Only autopair on host-initiated connections */
+ if (!device_is_bonding(device, NULL))
+ return 0;
+
+ device_get_address(device, &peer, NULL);
+ adapter_get_address(adapter, &local);
+
+ if (g_slist_find_custom(dynamic_blacklist, &peer, (GCompareFunc) bacmp))
+ return 0;
+
+ if (read_remote_class(&local, &peer, &class) != 0)
+ return 0;
+
+ switch (BLUETOOTH_DEVICE_CLASS(class)) {
+ case BLUETOOTH_DEVICE_CLASS_AUDIO_VIDEO_WEARABLE_HEADSET:
+ case BLUETOOTH_DEVICE_CLASS_AUDIO_VIDEO_HANDSFREE:
+ case BLUETOOTH_DEVICE_CLASS_AUDIO_VIDEO_HEADPHONES:
+ case BLUETOOTH_DEVICE_CLASS_AUDIO_VIDEO_PORTABLE_AUDIO:
+ case BLUETOOTH_DEVICE_CLASS_AUDIO_VIDEO_HIFI_AUDIO:
+ /* These are the classes Android attempts auto-pairing with */
+ case BLUETOOTH_DEVICE_CLASS_PERIPHERAL_POINTING:
+ /* Attempt auto-pairing with mice too */
+ if (autopair_attempt(device)) {
+ DBG("attempting auto-pairing with device (%d)", class);
+ memcpy(pinbuf, "0000", 4);
+ return 4;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+static int autopair_probe(struct btd_adapter *adapter)
+{
+ btd_adapter_register_pin_cb(adapter, autopair_pincb);
+
+ return 0;
+}
+
+static void autopair_remove(struct btd_adapter *adapter)
+{
+ btd_adapter_unregister_pin_cb(adapter, autopair_pincb);
+}
+
+static struct btd_adapter_driver autopair_driver = {
+ .name = "autopair",
+ .probe = autopair_probe,
+ .remove = autopair_remove,
+};
+
+static void autopair_add_blacklist(char *key, char *value, void *data)
+{
+ bdaddr_t *ba;
+
+ if (strcmp(value, "blacklist"))
+ return;
+
+ ba = g_new0(bdaddr_t, 1);
+ str2ba(key, ba);
+ dynamic_blacklist = g_slist_prepend(dynamic_blacklist, ba);
+}
+
+static int autopair_init(void)
+{
+ char filename[PATH_MAX + 1];
+
+ /* Load dynamic blacklist */
+ create_name(filename, PATH_MAX, STORAGEDIR, "autopair", "blacklist");
+ textfile_foreach(filename, autopair_add_blacklist, NULL);
+
+ return btd_register_adapter_driver(&autopair_driver);
+}
+
+static void autopair_exit(void)
+{
+ GSList *l;
+ struct btd_device *device;
+ char filename[PATH_MAX + 1];
+ bdaddr_t *ba;
+ char addr[18];
+
+ btd_unregister_adapter_driver(&autopair_driver);
+
+ /* Unregister device-level callbacks and unreference */
+ for (l = attempting; l != NULL; l = g_slist_next(l)) {
+ device = l->data;
+ btd_device_unregister_bonding_cb(device, autopair_bondingcb,
+ autopair_bonding_cancelcb);
+ btd_device_unref(device);
+ }
+ g_slist_free(attempting);
+
+ /* Save dynamic blacklist */
+ create_name(filename, PATH_MAX, STORAGEDIR, "autopair", "blacklist");
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ for (l = dynamic_blacklist; l != NULL; l = g_slist_next(l)) {
+ ba = l->data;
+ ba2str(ba, addr);
+ textfile_put(filename, addr, "blacklist");
+ }
+
+ g_slist_free_full(dynamic_blacklist, g_free);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(autopair, VERSION,
+ BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, autopair_init, autopair_exit)
--
1.7.7.3
next prev parent reply other threads:[~2012-01-21 1:59 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-01-21 1:59 [RFC PATCH 0/2] auto-pairing plugin Scott James Remnant
2012-01-21 1:59 ` [RFC PATCH 1/2] plugin: add bonding complete and cancel callbacks with optional retry Scott James Remnant
2012-01-21 1:59 ` Scott James Remnant [this message]
2012-01-23 14:28 ` [RFC PATCH 0/2] auto-pairing plugin Bastien Nocera
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1327111197-11446-3-git-send-email-scott@netsplit.com \
--to=scott@netsplit.com \
--cc=keybuk@chromium.org \
--cc=linux-bluetooth@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).