Add APIs for OOB Simple Secure pairing.
Change-Id: Iddc784ef4d0b6e71d15a91061eca51ccbd8c266e
diff --git a/src/adapter.c b/src/adapter.c
index c6dbd05..16334ec 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -1630,8 +1630,8 @@
return IO_CAPABILITY_INVALID;
}
-static DBusMessage *create_paired_device(DBusConnection *conn,
- DBusMessage *msg, void *data)
+static DBusMessage *create_paired_device_generic(DBusConnection *conn,
+ DBusMessage *msg, void *data, const gboolean oob)
{
struct btd_adapter *adapter = data;
struct btd_device *device;
@@ -1664,7 +1664,19 @@
ERROR_INTERFACE ".Failed",
"Unable to create a new device object");
- return device_create_bonding(device, conn, msg, agent_path, cap);
+ return device_create_bonding(device, conn, msg, agent_path, cap, oob);
+}
+
+static DBusMessage *create_paired_device_oob(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return create_paired_device_generic(conn, msg, data, TRUE);
+}
+
+static DBusMessage *create_paired_device(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return create_paired_device_generic(conn, msg, data, FALSE);
}
static gint device_path_cmp(struct btd_device *device, const gchar *path)
@@ -1751,18 +1763,16 @@
adapter->agent = NULL;
}
-static DBusMessage *register_agent(DBusConnection *conn, DBusMessage *msg,
- void *data)
+
+static DBusMessage *register_agent_generic(DBusConnection *conn, DBusMessage *msg,
+ void *data, const char *path, const char *capability,
+ const gboolean oob)
{
- const char *path, *name, *capability;
+ const char *name;
struct agent *agent;
struct btd_adapter *adapter = data;
uint8_t cap;
- if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_STRING, &capability, DBUS_TYPE_INVALID))
- return NULL;
-
if (adapter->agent)
return g_dbus_create_error(msg,
ERROR_INTERFACE ".AlreadyExists",
@@ -1774,7 +1784,7 @@
name = dbus_message_get_sender(msg);
- agent = agent_create(adapter, name, path, cap,
+ agent = agent_create(adapter, name, path, cap, oob,
(agent_remove_cb) agent_removed, adapter);
if (!agent)
return g_dbus_create_error(msg,
@@ -1789,6 +1799,32 @@
return dbus_message_new_method_return(msg);
}
+static DBusMessage *register_agent_oob(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ const char *path, *capability;
+ gboolean oob;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_STRING, &capability,
+ DBUS_TYPE_BOOLEAN, &oob, DBUS_TYPE_INVALID))
+ return NULL;
+
+ return register_agent_generic(conn, msg, data, path, capability, oob);
+}
+
+static DBusMessage *register_agent(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ const char *path, *capability;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_STRING, &capability, DBUS_TYPE_INVALID))
+ return NULL;
+
+ return register_agent_generic(conn, msg, data, path, capability, FALSE);
+}
+
static DBusMessage *unregister_agent(DBusConnection *conn, DBusMessage *msg,
void *data)
{
@@ -1914,6 +1950,44 @@
return dbus_message_new_method_return(msg);
}
+static DBusMessage *read_local_oob_data(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct btd_adapter *adapter = data;
+ DBusMessage *reply;
+
+ uint8_t hash[16], randomizer[16];
+ uint8_t *hash_ptr = hash;
+ uint8_t *r_ptr = randomizer;
+ int dd, err;
+
+ dd = hci_open_dev(adapter->dev_id);
+
+ if (dd < 0) {
+ err = -errno;
+ goto fail;
+ }
+
+ err = hci_read_local_oob_data(dd, hash, randomizer, HCI_REQ_TIMEOUT);
+
+ hci_close_dev(dd);
+
+ if (err < 0) {
+ err = -errno;
+ goto fail;
+ }
+
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_append_args(reply,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &hash_ptr, 16,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &r_ptr, 16,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+fail:
+ return failed_strerror(msg, errno);
+}
+
static DBusMessage *set_link_timeout(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -1973,12 +2047,16 @@
G_DBUS_METHOD_FLAG_ASYNC},
{ "CreatePairedDevice", "sos", "o", create_paired_device,
G_DBUS_METHOD_FLAG_ASYNC},
+ { "CreatePairedDeviceOutOfBand", "sos", "o", create_paired_device_oob,
+ G_DBUS_METHOD_FLAG_ASYNC},
{ "CancelDeviceCreation","s", "", cancel_device_creation,
G_DBUS_METHOD_FLAG_ASYNC},
{ "RemoveDevice", "o", "", remove_device,
G_DBUS_METHOD_FLAG_ASYNC},
{ "FindDevice", "s", "o", find_device },
+ { "ReadLocalOutOfBandData", "", "ayay", read_local_oob_data},
{ "RegisterAgent", "os", "", register_agent },
+ { "RegisterAgent", "osb", "", register_agent_oob },
{ "UnregisterAgent", "o", "", unregister_agent },
{ "AddRfcommServiceRecord", "sttq", "u", add_rfcomm_service_record },
{ "RemoveServiceRecord", "u", "", remove_service_record },
diff --git a/src/agent.c b/src/agent.c
index efa0320..5097241 100644
--- a/src/agent.c
+++ b/src/agent.c
@@ -56,6 +56,8 @@
AGENT_REQUEST_PINCODE,
AGENT_REQUEST_AUTHORIZE,
AGENT_REQUEST_CONFIRM_MODE,
+ AGENT_REQUEST_OOB_AVAILABILITY,
+ AGENT_REQUEST_OOB_DATA,
AGENT_REQUEST_PAIRING_CONSENT,
} agent_request_type_t;
@@ -64,6 +66,7 @@
char *name;
char *path;
uint8_t capability;
+ gboolean oob;
struct agent_request *request;
int exited;
agent_remove_cb remove_cb;
@@ -189,7 +192,8 @@
struct agent *agent_create(struct btd_adapter *adapter, const char *name,
const char *path, uint8_t capability,
- agent_remove_cb cb, void *remove_cb_data)
+ gboolean oob, agent_remove_cb cb,
+ void *remove_cb_data)
{
struct agent *agent;
@@ -199,6 +203,7 @@
agent->name = g_strdup(name);
agent->path = g_strdup(path);
agent->capability = capability;
+ agent->oob = oob;
agent->remove_cb = cb;
agent->remove_cb_data = remove_cb_data;
@@ -355,6 +360,61 @@
return 0;
}
+
+static int agent_call_oob_availability(struct agent_request *req,
+ const char *device_path)
+{
+ struct agent *agent = req->agent;
+
+ req->msg = dbus_message_new_method_call(agent->name, agent->path,
+ "org.bluez.Agent", "OutOfBandAvailable");
+ if (!req->msg) {
+ error("Couldn't allocate D-Bus message");
+ return -ENOMEM;
+ }
+
+ dbus_message_append_args(req->msg,
+ DBUS_TYPE_OBJECT_PATH, &device_path,
+ DBUS_TYPE_INVALID);
+
+ if (dbus_connection_send_with_reply(connection, req->msg,
+ &req->call, REQUEST_TIMEOUT) == FALSE) {
+ error("D-Bus send failed");
+ return -EIO;
+ }
+
+ dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL);
+ return 0;
+}
+
+int agent_request_oob_availability(struct agent *agent,
+ const char *path,
+ agent_cb cb,
+ void *user_data,
+ GDestroyNotify destroy)
+{
+ struct agent_request *req;
+ int err;
+
+ if (agent->request)
+ return -EBUSY;
+
+ req = agent_request_new(agent, AGENT_REQUEST_OOB_AVAILABILITY, cb,
+ user_data, destroy);
+
+ err = agent_call_oob_availability(req, path);
+ if (err < 0) {
+ agent_request_free(req, FALSE);
+ return -ENOMEM;
+ }
+
+ agent->request = req;
+
+ DBG("oob availability request was sent for %s", path);
+
+ return 0;
+}
+
static void pincode_reply(DBusPendingCall *call, void *user_data)
{
struct agent_request *req = user_data;
@@ -637,6 +697,112 @@
return err;
}
+static void oob_data_reply(DBusPendingCall *call, void *user_data)
+{
+ struct agent_request *req = user_data;
+ struct agent *agent = req->agent;
+ agent_oob_data_cb cb = req->cb;
+ DBusMessage *message;
+ DBusError err;
+ uint8_t *hash_ptr, *r_ptr;
+ uint8_t hash_len, r_len;
+
+ /* steal_reply will always return non-NULL since the callback
+ * is only called after a reply has been received */
+ message = dbus_pending_call_steal_reply(call);
+
+ dbus_error_init(&err);
+ if (dbus_set_error_from_message(&err, message)) {
+ if ((g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err.name) ||
+ g_str_equal(DBUS_ERROR_NO_REPLY, err.name)) &&
+ request_fallback(req, oob_data_reply) == 0) {
+ dbus_error_free(&err);
+ return;
+ }
+
+ error("Agent replied with an error: %s, %s",
+ err.name, err.message);
+ cb(agent, &err, 0, 0, req->user_data);
+ dbus_error_free(&err);
+ goto done;
+ }
+
+ if (!dbus_message_get_args(message, &err,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &hash_ptr, &hash_len,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &r_ptr, &r_len,
+ DBUS_TYPE_INVALID)) {
+ error("Wrong OOB data reply signature: %s", err.message);
+ cb(agent, &err, 0, 0, req->user_data);
+ dbus_error_free(&err);
+ goto done;
+ }
+
+ cb(agent, NULL, hash_ptr, r_ptr, req->user_data);
+
+done:
+ if (message)
+ dbus_message_unref(message);
+
+ dbus_pending_call_cancel(req->call);
+ agent->request = NULL;
+ agent_request_free(req, TRUE);
+}
+
+static int oob_data_request_new(struct agent_request *req,
+ const char *device_path)
+{
+ struct agent *agent = req->agent;
+
+ req->msg = dbus_message_new_method_call(agent->name, agent->path,
+ "org.bluez.Agent", "RequestOobData");
+ if (req->msg == NULL) {
+ error("Couldn't allocate D-Bus message");
+ return -ENOMEM;
+ }
+
+ dbus_message_append_args(req->msg, DBUS_TYPE_OBJECT_PATH, &device_path,
+ DBUS_TYPE_INVALID);
+
+ if (dbus_connection_send_with_reply(connection, req->msg,
+ &req->call, REQUEST_TIMEOUT) == FALSE) {
+ error("D-Bus send failed");
+ return -EIO;
+ }
+
+ dbus_pending_call_set_notify(req->call, oob_data_reply, req, NULL);
+ return 0;
+}
+
+int agent_request_oob_data(struct agent *agent, struct btd_device *device,
+ agent_oob_data_cb cb, void *user_data,
+ GDestroyNotify destroy)
+{
+ struct agent_request *req;
+ const gchar *dev_path = device_get_path(device);
+ int err;
+
+ if (agent->request)
+ return -EBUSY;
+
+ DBG("Calling Agent.RequestOobData: name=%s, path=%s",
+ agent->name, agent->path);
+
+ req = agent_request_new(agent, AGENT_REQUEST_OOB_DATA, cb,
+ user_data, destroy);
+
+ err = oob_data_request_new(req, dev_path);
+ if (err < 0)
+ goto failed;
+
+ agent->request = req;
+
+ return 0;
+
+failed:
+ agent_request_free(req, FALSE);
+ return err;
+}
+
static int confirmation_request_new(struct agent_request *req,
const char *device_path,
uint32_t passkey)
@@ -821,6 +987,11 @@
return agent->capability;
}
+gboolean agent_get_oob_capability(struct agent *agent)
+{
+ return agent->oob;
+}
+
gboolean agent_matches(struct agent *agent, const char *name, const char *path)
{
if (g_str_equal(agent->name, name) && g_str_equal(agent->path, path))
diff --git a/src/agent.h b/src/agent.h
index e184250..2f743b8 100644
--- a/src/agent.h
+++ b/src/agent.h
@@ -33,11 +33,16 @@
typedef void (*agent_passkey_cb) (struct agent *agent, DBusError *err,
uint32_t passkey, void *user_data);
+typedef void (*agent_oob_data_cb) (struct agent *agent, DBusError *err,
+ uint8_t *hash, uint8_t *randomizer,
+ void *user_data);
+
typedef void (*agent_remove_cb) (struct agent *agent, void *user_data);
struct agent *agent_create(struct btd_adapter *adapter, const char *name,
const char *path, uint8_t capability,
- agent_remove_cb cb, void *remove_cb_data);
+ gboolean oob, agent_remove_cb cb,
+ void *remove_cb_data);
void agent_free(struct agent *agent);
@@ -57,6 +62,14 @@
agent_passkey_cb cb, void *user_data,
GDestroyNotify destroy);
+int agent_request_oob_data(struct agent *agent, struct btd_device *device,
+ agent_oob_data_cb cb, void *user_data,
+ GDestroyNotify destroy);
+
+int agent_request_oob_availability(struct agent *agent,
+ const char *path, agent_cb cb,
+ void *user_data, GDestroyNotify destroy);
+
int agent_request_confirmation(struct agent *agent, struct btd_device *device,
uint32_t passkey, agent_cb cb,
void *user_data, GDestroyNotify destroy);
@@ -69,6 +82,7 @@
gboolean agent_is_busy(struct agent *agent, void *user_data);
uint8_t agent_get_io_capability(struct agent *agent);
+gboolean agent_get_oob_capability(struct agent *agent);
gboolean agent_matches(struct agent *agent, const char *name, const char *path);
diff --git a/src/dbus-hci.c b/src/dbus-hci.c
index 79bee44..7077b1f 100644
--- a/src/dbus-hci.c
+++ b/src/dbus-hci.c
@@ -59,6 +59,12 @@
#include "storage.h"
#include "dbus-hci.h"
+struct oob_availability_req {
+ struct btd_device *device;
+ uint8_t auth;
+ uint8_t capa;
+};
+
static DBusConnection *connection = NULL;
gboolean get_adapter_and_device(bdaddr_t *src, bdaddr_t *dst,
@@ -287,6 +293,82 @@
hci_close_dev(dd);
}
+static void oob_data_cb(struct agent *agent, DBusError *err, uint8_t *hash,
+ uint8_t *randomizer, void *user_data)
+{
+ struct btd_device *device = user_data;
+ struct btd_adapter *adapter = device_get_adapter(device);
+ remote_oob_data_reply_cp cp;
+ bdaddr_t dba;
+ int dd;
+ uint16_t dev_id = adapter_get_dev_id(adapter);
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ error("Unable to open hci%d", dev_id);
+ return;
+ }
+
+ device_get_address(device, &dba);
+ memset(&cp, 0, sizeof(cp));
+ bacpy(&cp.bdaddr, &dba);
+
+ memcpy(&cp.hash, hash, 16);
+ memcpy(&cp.randomizer, randomizer, 16);
+
+ if (err)
+ hci_send_cmd(dd, OGF_LINK_CTL, OCF_REMOTE_OOB_DATA_NEG_REPLY,
+ 6, &dba);
+
+ else
+ hci_send_cmd(dd, OGF_LINK_CTL, OCF_REMOTE_OOB_DATA_REPLY,
+ REMOTE_OOB_DATA_REPLY_CP_SIZE, &cp);
+
+ hci_close_dev(dd);
+}
+
+static void io_capa_oob_response(struct btd_adapter *adapter, struct btd_device *device,
+ uint8_t cap, uint8_t auth, gboolean oob)
+{
+ io_capability_reply_cp cp;
+ int dd;
+ uint16_t dev_id = adapter_get_dev_id(adapter);
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ error("Unable to open hci%d", dev_id);
+ return;
+ }
+ memset(&cp, 0, sizeof(cp));
+ device_get_address(device, &cp.bdaddr);
+
+ cp.capability = cap;
+ if (oob)
+ cp.oob_data = 0x01;
+ else
+ cp.oob_data = 0x00;
+ cp.authentication = auth;
+
+ hci_send_cmd(dd, OGF_LINK_CTL, OCF_IO_CAPABILITY_REPLY,
+ IO_CAPABILITY_REPLY_CP_SIZE, &cp);
+ hci_close_dev(dd);
+}
+
+static void oob_availability_cb(struct agent *agent, DBusError *err,
+ void *user_data)
+{
+ struct oob_availability_req *oob = user_data;
+ struct btd_device *device = oob->device;
+ struct btd_adapter *adapter = device_get_adapter(device);
+
+ if (err) {
+ io_capa_oob_response(adapter, device, oob->capa, oob->auth, FALSE);
+ } else {
+ io_capa_oob_response(adapter, device, oob->capa, oob->auth, TRUE);
+ }
+}
+
+
static void pairing_consent_cb(struct agent *agent, DBusError *err,
void *user_data)
{
@@ -792,6 +874,25 @@
return 0;
}
+int hcid_dbus_get_oob_data(bdaddr_t *sba, bdaddr_t * dba)
+{
+ struct btd_adapter *adapter;
+ struct btd_device *device;
+ struct agent *agent = NULL;
+
+ if (!get_adapter_and_device(sba, dba, &adapter, &device, TRUE))
+ return -ENODEV;
+
+ agent = device_get_agent(device);
+ if (agent == NULL) {
+ error("No agent available for device");
+ return -1;
+ }
+
+ return device_request_authentication(device, AUTH_TYPE_OOB, 0,
+ oob_data_cb);
+}
+
void hcid_dbus_conn_complete(bdaddr_t *local, uint8_t status, uint16_t handle,
bdaddr_t *peer)
{
@@ -944,24 +1045,26 @@
device_set_paired(device, TRUE);
}
-int hcid_dbus_get_io_cap(bdaddr_t *local, bdaddr_t *remote,
- uint8_t *cap, uint8_t *auth)
+int hcid_dbus_get_io_cap(bdaddr_t *local, bdaddr_t *remote)
{
struct btd_adapter *adapter;
struct btd_device *device;
+ struct oob_availability_req *oob_req;
struct agent *agent = NULL;
- uint8_t agent_cap;
+ uint8_t agent_cap, auth, cap;
+ gboolean oob = FALSE;
+ int ret;
if (!get_adapter_and_device(local, remote, &adapter, &device, TRUE))
return -ENODEV;
- if (get_auth_requirements(local, remote, auth) < 0)
+ if (get_auth_requirements(local, remote, &auth) < 0)
return -1;
- 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 */
@@ -970,11 +1073,11 @@
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;
@@ -990,13 +1093,13 @@
}
/* 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;
}
@@ -1006,7 +1109,7 @@
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) {
@@ -1015,9 +1118,9 @@
* 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
@@ -1025,7 +1128,7 @@
* 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
@@ -1033,14 +1136,32 @@
if (device_get_auth(device) != 0xff &&
(device_get_auth(device) & 0x01) &&
agent_cap != 0x03)
- *auth |= 0x01;
+ auth |= 0x01;
}
- *cap = agent_get_io_capability(agent);
+ DBG("final authentication requirement is 0x%02x", auth);
+ cap = agent_get_io_capability(agent);
+ oob = agent_get_oob_capability(agent);
+
+ // if pairing is not locally initiated
+ if (oob && agent == adapter_get_agent(adapter)) {
+ oob_req = g_new0(struct oob_availability_req, 1);
+ oob_req->device = device;
+ oob_req->auth = auth;
+ oob_req->capa = cap;
+
+ ret = device_request_oob_availability(device, oob_availability_cb,
+ oob_req);
+ if (ret < 0) {
+ g_free(oob_req);
+ oob = FALSE;
+ goto done;
+ }
+ return ret;
+ }
done:
- DBG("final authentication requirement is 0x%02x", *auth);
-
+ io_capa_oob_response(adapter, device, cap, auth, oob);
return 0;
}
diff --git a/src/dbus-hci.h b/src/dbus-hci.h
index 44cd5e5..8ca25aa 100644
--- a/src/dbus-hci.h
+++ b/src/dbus-hci.h
@@ -34,8 +34,7 @@
void hcid_dbus_setscan_enable_complete(bdaddr_t *local);
void hcid_dbus_write_simple_pairing_mode_complete(bdaddr_t *local);
void hcid_dbus_returned_link_key(bdaddr_t *local, bdaddr_t *peer);
-int hcid_dbus_get_io_cap(bdaddr_t *local, bdaddr_t *remote,
- uint8_t *cap, uint8_t *auth);
+int hcid_dbus_get_io_cap(bdaddr_t *local, bdaddr_t *remote);
int hcid_dbus_set_io_cap(bdaddr_t *local, bdaddr_t *remote,
uint8_t cap, uint8_t auth);
int hcid_dbus_user_confirm(bdaddr_t *sba, bdaddr_t *dba, uint32_t passkey);
@@ -44,6 +43,7 @@
int hcid_dbus_link_key_notify(bdaddr_t *local, bdaddr_t *peer,
uint8_t *key, uint8_t key_type,
int pin_length, uint8_t old_key_type);
+int hcid_dbus_get_oob_data(bdaddr_t *sba, bdaddr_t *dba);
gboolean get_adapter_and_device(bdaddr_t *src, bdaddr_t *dst,
struct btd_adapter **adapter,
diff --git a/src/device.c b/src/device.c
index 9d50ad9..53248a5 100644
--- a/src/device.c
+++ b/src/device.c
@@ -1918,7 +1918,8 @@
DBusMessage *msg,
struct btd_device *device,
const char *agent_path,
- uint8_t capability)
+ uint8_t capability,
+ gboolean oob)
{
struct bonding_req *bonding;
const char *name = dbus_message_get_sender(msg);
@@ -1931,6 +1932,7 @@
agent = agent_create(device->adapter, name, agent_path,
capability,
+ oob,
device_agent_removed,
device);
if (!agent) {
@@ -2057,7 +2059,8 @@
DBusConnection *conn,
DBusMessage *msg,
const char *agent_path,
- uint8_t capability)
+ uint8_t capability,
+ gboolean oob)
{
char filename[PATH_MAX + 1];
char *str, srcaddr[18], dstaddr[18];
@@ -2112,7 +2115,7 @@
}
bonding = bonding_request_new(conn, msg, device, agent_path,
- capability);
+ capability, oob);
if (!bonding) {
g_io_channel_shutdown(io, TRUE, NULL);
return NULL;
@@ -2283,6 +2286,22 @@
device->authr->agent = NULL;
}
+static void oob_data_cb(struct agent *agent, DBusError *err,
+ uint8_t *hash, uint8_t *randomizer, void *data)
+{
+ struct authentication_req *auth = data;
+ struct btd_device *device = auth->device;
+
+ /* No need to reply anything if the authentication already failed */
+ if (auth->cb == NULL)
+ return;
+
+ ((agent_oob_data_cb) auth->cb)(agent, err, hash, randomizer, device);
+
+ device->authr->cb = NULL;
+ device->authr->agent = NULL;
+}
+
static void passkey_cb(struct agent *agent, DBusError *err,
uint32_t passkey, void *data)
{
@@ -2313,6 +2332,30 @@
auth->cb = NULL;
}
+int device_request_oob_availability(struct btd_device *device,
+ void *cb, void *user_data)
+{
+ struct agent *agent;
+ int err;
+
+ DBG("%s: requesting agent oob availability", device->path);
+
+ agent = device_get_agent(device);
+ if (!agent) {
+ error("No agent available for OOB request");
+ return -EPERM;
+ }
+
+ err = agent_request_oob_availability(agent, device_get_path(device),
+ cb, user_data, g_free);
+
+ if (err < 0) {
+ error("Failed requesting oob availability");
+ }
+ return err;
+}
+
+
int device_request_authentication(struct btd_device *device, auth_type_t type,
uint32_t passkey, void *cb)
{
@@ -2351,6 +2394,9 @@
case AUTH_TYPE_NOTIFY:
err = agent_display_passkey(agent, device, passkey);
break;
+ case AUTH_TYPE_OOB:
+ err = agent_request_oob_data(agent, device, oob_data_cb, auth, NULL);
+ break;
case AUTH_TYPE_AUTO:
err = 0;
break;
@@ -2396,6 +2442,9 @@
case AUTH_TYPE_PASSKEY:
((agent_passkey_cb) auth->cb)(agent, &err, 0, device);
break;
+ case AUTH_TYPE_OOB:
+ ((agent_oob_data_cb) auth->cb)(agent, &err, 0, 0, device);
+ break;
case AUTH_TYPE_PAIRING_CONSENT:
((agent_cb) auth->cb) (agent, &err, device);
break;
diff --git a/src/device.h b/src/device.h
index 752dad3..31d4fcc 100644
--- a/src/device.h
+++ b/src/device.h
@@ -31,6 +31,7 @@
AUTH_TYPE_PASSKEY,
AUTH_TYPE_CONFIRM,
AUTH_TYPE_NOTIFY,
+ AUTH_TYPE_OOB,
AUTH_TYPE_AUTO,
AUTH_TYPE_PAIRING_CONSENT,
} auth_type_t;
@@ -66,7 +67,8 @@
void device_set_secmode3_conn(struct btd_device *device, gboolean enable);
DBusMessage *device_create_bonding(struct btd_device *device,
DBusConnection *conn, DBusMessage *msg,
- const char *agent_path, uint8_t capability);
+ const char *agent_path, uint8_t capability,
+ gboolean oob);
void device_remove_bonding(struct btd_device *device);
void device_bonding_complete(struct btd_device *device, uint8_t status);
void device_simple_pairing_complete(struct btd_device *device, uint8_t status);
@@ -75,6 +77,8 @@
void device_cancel_bonding(struct btd_device *device, uint8_t status);
int device_request_authentication(struct btd_device *device, auth_type_t type,
uint32_t passkey, void *cb);
+int device_request_oob_availability(struct btd_device *device,
+ void *cb, void *user_data);
void device_cancel_authentication(struct btd_device *device, gboolean aborted);
gboolean device_is_authenticating(struct btd_device *device);
gboolean device_is_authorizing(struct btd_device *device);
diff --git a/src/security.c b/src/security.c
index ca394e1..f91df94 100644
--- a/src/security.c
+++ b/src/security.c
@@ -462,33 +462,28 @@
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);
+ evt_remote_oob_data_request *req = ptr;
+
+ if (hcid_dbus_get_oob_data(sba, &req->bdaddr) < 0)
+ 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);
+ ba2str(sba, sa);
+ ba2str(dba, da);
info("io_capa_request (sba=%s, dba=%s)", sa, da);
- if (hcid_dbus_get_io_cap(sba, dba, &cap, &auth) < 0) {
+ if (hcid_dbus_get_io_cap(sba, dba) < 0) {
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);
}
}