diff options
Diffstat (limited to 'input')
-rw-r--r-- | input/error.c | 9 | ||||
-rw-r--r-- | input/error.h | 3 | ||||
-rw-r--r-- | input/input-api.txt | 18 | ||||
-rw-r--r-- | input/manager.c | 95 | ||||
-rw-r--r-- | input/storage.c | 18 | ||||
-rw-r--r-- | input/storage.h | 2 |
6 files changed, 132 insertions, 13 deletions
diff --git a/input/error.c b/input/error.c index 3049b47f..983cb10d 100644 --- a/input/error.c +++ b/input/error.c @@ -66,6 +66,15 @@ DBusHandlerResult err_already_connected(DBusConnection *conn, DBusMessage *msg) "Already connected to this device")); } +DBusHandlerResult err_authentication_failed(DBusConnection *conn, + DBusMessage *msg) +{ + return send_message_and_unref(conn, + dbus_message_new_error(msg, + INPUT_ERROR_INTERFACE".AuthenticationFailed", + "Authentication failed")); +} + DBusHandlerResult err_already_exists(DBusConnection *conn, DBusMessage *msg, const char *str) { diff --git a/input/error.h b/input/error.h index 32f080fb..7bfdd78a 100644 --- a/input/error.h +++ b/input/error.h @@ -32,6 +32,9 @@ DBusHandlerResult err_connection_failed(DBusConnection *conn, DBusHandlerResult err_already_connected(DBusConnection *conn, DBusMessage *msg); +DBusHandlerResult err_authentication_failed(DBusConnection *conn, + DBusMessage *msg); + DBusHandlerResult err_already_exists(DBusConnection *conn, DBusMessage *msg, const char *str); diff --git a/input/input-api.txt b/input/input-api.txt index 13da80ba..1d9fec1f 100644 --- a/input/input-api.txt +++ b/input/input-api.txt @@ -16,9 +16,7 @@ Methods array{string} ListDevices() string CreateDevice(string address) - Create an input device object. The HID service - record will be retrieved and the pairing will - be initiated if needed. + Create an input device object. On success it will return the path of the newly created device object. @@ -28,6 +26,20 @@ Methods array{string} ListDevices() org.bluez.input.ConnectionAttemptFailed org.bluez.input.Failed + string CreateSecureDevice(string address) + + Create an input device object. Pairing will + be initiated if needed(keyboard/combo devices). + + On success it will return the path of the + newly created device object. + + Possible errors: org.bluez.input.AlreadyExists + org.bluez.input.NotSupported + org.bluez.input.ConnectionAttemptFailed + org.bluez.input.AuthenticationFailed + org.bluez.input.Failed + void RemoveDevice(string path) Remove the input device object for a given path. diff --git a/input/manager.c b/input/manager.c index dc209a44..cd2e8a1d 100644 --- a/input/manager.c +++ b/input/manager.c @@ -229,10 +229,10 @@ static void extract_hid_record(sdp_record_t *rec, struct hidp_connadd_req *req) if (pdlist2) strncpy(req->name, pdlist2->val.str, 127); } - + pdlist = sdp_data_get(rec, SDP_ATTR_HID_PARSER_VERSION); req->parser = pdlist ? pdlist->val.uint16 : 0x0100; - + pdlist = sdp_data_get(rec, SDP_ATTR_HID_DEVICE_SUBCLASS); req->subclass = pdlist ? pdlist->val.uint8 : 0; @@ -420,7 +420,35 @@ failed: return FALSE; } -static void finish_sdp_transaction(bdaddr_t *dba) +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); + err_authentication_failed(pr->conn, pr->msg); + dbus_error_free(&derr); + dbus_message_unref(reply); + pending_req_free(pr); + return; + } + + dbus_message_unref(reply); + + if (l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_CTRL, + (GIOFunc) control_connect_cb, pr) < 0) { + int err = errno; + err_connection_failed(pr->conn, pr->msg, strerror(err)); + error("L2CAP connect failed:%s (%d)", strerror(err), err); + pending_req_free(pr); + } +} + +static void finish_sdp_transaction(bdaddr_t *dba) { char address[18], *addr_ptr = address; DBusMessage *msg, *reply; @@ -455,6 +483,32 @@ static void finish_sdp_transaction(bdaddr_t *dba) dbus_message_unref(reply); } +static int create_bonding(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"); + 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."); + 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); @@ -498,16 +552,36 @@ static void hid_record_reply(DBusPendingCall *call, void *data) goto fail; } + dbus_message_unref(reply); + + if (strcmp("CreateSecureDevice", dbus_message_get_member(pr->msg)) == 0) { + sdp_data_t *d; + + /* Pairing mandatory for keyboard and combo */ + d = sdp_data_get(pr->hid_rec, SDP_ATTR_HID_DEVICE_SUBCLASS); + if (d && (d->val.uint8 & 0x40) && + !has_bonding(&pr->src, &pr->dst)) { + if (create_bonding(pr) < 0) { + err_authentication_failed(pr->conn, pr->msg); + goto fail; + } + /* Wait bonding reply */ + return; + } + + /* Otherwise proceede L2CAP connection */ + } + + /* No encryption or link key already exists -- 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); + /* Wait L2CAP connect */ return; fail: dbus_error_free(&derr); @@ -966,7 +1040,7 @@ static void manager_unregister(DBusConnection *conn, void *data) static void stored_input(char *key, char *value, void *data) { const char *path; - struct hidp_connadd_req hidp; + struct hidp_connadd_req hidp; bdaddr_t dst, *src = data; str2ba(key, &dst); @@ -992,7 +1066,7 @@ cleanup: /* hidd to input transition function */ static void stored_hidd(char *key, char *value, void *data) { - struct hidp_connadd_req hidp; + struct hidp_connadd_req hidp; char *str, filename[PATH_MAX + 1], addr[18]; bdaddr_t dst, *src = data; @@ -1053,9 +1127,10 @@ static void register_stored_inputs(void) } static DBusMethodVTable manager_methods[] = { - { "ListDevices", list_devices, "", "as" }, - { "CreateDevice", create_device, "s", "s" }, - { "RemoveDevice", remove_device, "s", "" }, + { "ListDevices", list_devices, "", "as" }, + { "CreateDevice", create_device, "s", "s" }, + { "CreateSecureDevice", create_device, "s", "s" }, + { "RemoveDevice", remove_device, "s", "" }, { NULL, NULL, NULL, NULL }, }; diff --git a/input/storage.c b/input/storage.c index b20524d9..fe0469e6 100644 --- a/input/storage.c +++ b/input/storage.c @@ -344,3 +344,21 @@ fail: return -err; } + +gboolean has_bonding(bdaddr_t *src, bdaddr_t *dst) +{ + char filename[PATH_MAX + 1]; + char addr[18], *str; + + create_filename(filename, PATH_MAX, src, "linkkeys"); + + ba2str(dst, addr); + + str = textfile_get(filename, addr); + if (!str) + return FALSE; + + free(str); + + return TRUE; +} diff --git a/input/storage.h b/input/storage.h index a5462561..890e14e9 100644 --- a/input/storage.h +++ b/input/storage.h @@ -37,3 +37,5 @@ int read_device_name(bdaddr_t *src, bdaddr_t *dst, char **name); int read_device_class(bdaddr_t *src, bdaddr_t *dst, uint32_t *cls); int encrypt_link(bdaddr_t *src, bdaddr_t *dst); + +gboolean has_bonding(bdaddr_t *src, bdaddr_t *dst); |