summaryrefslogtreecommitdiffstats
path: root/input
diff options
context:
space:
mode:
Diffstat (limited to 'input')
-rw-r--r--input/error.c9
-rw-r--r--input/error.h3
-rw-r--r--input/input-api.txt18
-rw-r--r--input/manager.c95
-rw-r--r--input/storage.c18
-rw-r--r--input/storage.h2
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);