[Bluez-devel] [PATCH] Attempt bonding with keyboards.

David Woodhouse
2007-09-22T17:49:02Z

My Nokia SU-8W keyboard will never attempt to reconnect to the computer
after a power cycle unless we actually pair with it. With the input
service as it currently stands, we don't -- so it works once, but then
next time I want to use it I need to go through the whole search and
'add new input device' process again (and the bluetooth-properties
applet crashes when you try to add a device which already exists, which
is not so cute).

This patch makes the input service attempt bonding with new keyboards.
It will ignore errors though -- if bonding fails, it still goes ahead
and connects as before.

I've tested this with the two input devices I have to hand -- both with
successful pairing and when I allow pairing to fail. It would be
interesting to test it on the keyboards which have problems with
pairing.

A critical pair of eyes over my first attempt at using dbus probably
wouldn't go amiss. :)

diff --git a/input/manager.c b/input/manager.c
index 5dfb064..f1d25dc 100644
--- a/input/manager.c
+++ b/input/manager.c
@@ -415,6 +415,29 @@ failed:
return FALSE;
}

+static void create_bonding_reply(DBusPendingCall *call, void *data)
+{
+ DBusMessage *reply = dbus_pending_call_steal_reply(call);
+ struct pending_req *pr = data;
+ DBusError derr;
+
+ dbus_error_init(&derr);
+ if (dbus_set_error_from_message(&derr, reply)) {
+ error("CreateBonding failed: %s(%s)",
+ derr.name, derr.message);
+ /* But ignore the error */
+ }
+
+ dbus_message_unref(reply);
+
+ if (l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_CTRL,
+ (GIOFunc) control_connect_cb, pr) < 0) {
+ int err = errno;
+ error("L2CAP connect failed:%s (%d)", strerror(err), err);
+ err_connection_failed(pr->conn, pr->msg, strerror(err));
+ }
+}
+
static void finish_sdp_transaction(bdaddr_t *dba)
{
char address[18], *addr_ptr = address;
@@ -450,6 +473,34 @@ static void finish_sdp_transaction(bdaddr_t *dba)
dbus_message_unref(reply);
}

+static int start_bonding_attempt(DBusPendingCall *call, struct pending_req *pr)
+{
+ DBusPendingCall *pending;
+ DBusMessage *msg;
+ char address[18], *addr_ptr = address;
+
+ msg = dbus_message_new_method_call("org.bluez", pr->adapter_path,
+ "org.bluez.Adapter", "CreateBonding");
+ if (!msg) {
+ error("Unable to allocate new method call");
+ err_not_supported(pr->conn, pr->msg);
+ return -1;
+ }
+
+ ba2str(&pr->dst, address);
+ dbus_message_append_args(msg, DBUS_TYPE_STRING, &addr_ptr, DBUS_TYPE_INVALID);
+ if (dbus_connection_send_with_reply(pr->conn, msg, &pending, -1) == FALSE) {
+ error("Can't send D-Bus message.");
+ err_not_supported(pr->conn, pr->msg);
+ dbus_message_unref(msg);
+ return -1;
+ }
+ dbus_pending_call_set_notify(pending, create_bonding_reply, pr, NULL);
+ dbus_pending_call_unref(pending);
+ dbus_message_unref(msg);
+ return 0;
+}
+
static void hid_record_reply(DBusPendingCall *call, void *data)
{
DBusMessage *reply = dbus_pending_call_steal_reply(call);
@@ -457,6 +508,7 @@ static void hid_record_reply(DBusPendingCall *call, void *data)
DBusError derr;
uint8_t *rec_bin;
int len, scanned;
+ sdp_data_t *pdlist;

dbus_error_init(&derr);
if (dbus_set_error_from_message(&derr, reply)) {
@@ -493,13 +545,19 @@ static void hid_record_reply(DBusPendingCall *call, void *data)
goto fail;
}

- if (l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_CTRL,
- (GIOFunc) control_connect_cb, pr) < 0) {
- int err = errno;
- error("L2CAP connect failed:%s (%d)", strerror(err), err);
- err_connection_failed(pr->conn, pr->msg, strerror(err));
- goto fail;
-
+ pdlist = sdp_data_get(pr->hid_rec, SDP_ATTR_HID_DEVICE_SUBCLASS);
+ if (pdlist && (pdlist->val.uint8 & 0x40)) {
+ if (start_bonding_attempt(call, pr))
+ goto fail;
+ } else {
+ /* No encryption -- connect control channel */
+ if (l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_CTRL,
+ (GIOFunc) control_connect_cb, pr) < 0) {
+ int err = errno;
+ error("L2CAP connect failed:%s (%d)", strerror(err), err);
+ err_connection_failed(pr->conn, pr->msg, strerror(err));
+ goto fail;
+ }
}
dbus_message_unref(reply);