summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@nokia.com>2008-06-05 13:30:11 +0000
committerJohan Hedberg <johan.hedberg@nokia.com>2008-06-05 13:30:11 +0000
commitdac5b3dfc9ce5091315294f938dc84188985dad6 (patch)
tree759f59d04d54bab34950f29d9cd470615ccecb92
parent94f7643c52193c905edaff767c2e9a31b9102a73 (diff)
Implement first part of missing SSP callbacks
-rw-r--r--hcid/agent.c159
-rw-r--r--hcid/agent.h10
-rw-r--r--hcid/dbus-hci.c126
-rw-r--r--hcid/dbus-hci.h2
-rw-r--r--hcid/security.c12
5 files changed, 307 insertions, 2 deletions
diff --git a/hcid/agent.c b/hcid/agent.c
index 5706ea94..c8236892 100644
--- a/hcid/agent.c
+++ b/hcid/agent.c
@@ -56,6 +56,7 @@
typedef enum {
AGENT_REQUEST_PASSKEY,
+ AGENT_REQUEST_CONFIRMATION,
AGENT_REQUEST_PINCODE,
AGENT_REQUEST_AUTHORIZE,
AGENT_REQUEST_CONFIRM_MODE
@@ -518,6 +519,164 @@ failed:
return -1;
}
+static DBusPendingCall *passkey_request_new(struct agent *agent,
+ const char *device_path)
+{
+ DBusMessage *message;
+ DBusPendingCall *call;
+
+ message = dbus_message_new_method_call(agent->name, agent->path,
+ "org.bluez.Agent", "RequestPasskey");
+ if (message == NULL) {
+ error("Couldn't allocate D-Bus message");
+ return NULL;
+ }
+
+ dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &device_path,
+ DBUS_TYPE_INVALID);
+
+ if (dbus_connection_send_with_reply(connection, message,
+ &call, REQUEST_TIMEOUT) == FALSE) {
+ error("D-Bus send failed");
+ dbus_message_unref(message);
+ return NULL;
+ }
+
+ dbus_message_unref(message);
+ return call;
+}
+
+static void passkey_reply(DBusPendingCall *call, void *user_data)
+{
+ struct agent_request *req = user_data;
+ struct agent *agent = req->agent;
+ agent_passkey_cb cb = req->cb;
+ DBusMessage *message;
+ DBusError err;
+ uint32_t passkey;
+
+ /* 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)) {
+ error("Agent replied with an error: %s, %s",
+ err.name, err.message);
+ cb(agent, &err, 0, req->user_data);
+ dbus_error_free(&err);
+ goto done;
+ }
+
+ dbus_error_init(&err);
+ if (!dbus_message_get_args(message, &err,
+ DBUS_TYPE_UINT32, &passkey,
+ DBUS_TYPE_INVALID)) {
+ error("Wrong passkey reply signature: %s", err.message);
+ cb(agent, &err, 0, req->user_data);
+ dbus_error_free(&err);
+ goto done;
+ }
+
+ cb(agent, NULL, passkey, req->user_data);
+
+done:
+ if (message)
+ dbus_message_unref(message);
+
+ dbus_pending_call_cancel(req->call);
+ agent_request_free(req);
+}
+
+int agent_request_passkey(struct agent *agent, struct device *device,
+ agent_passkey_cb cb, void *user_data)
+{
+ struct agent_request *req;
+
+ if (agent->request)
+ return -EBUSY;
+
+ debug("Calling Agent.RequestPasskey: name=%s, path=%s",
+ agent->name, agent->path);
+
+ req = agent_request_new(agent, AGENT_REQUEST_PASSKEY, cb, user_data);
+
+ req->call = passkey_request_new(agent, device->path);
+ if (!req->call)
+ goto failed;
+
+ dbus_pending_call_set_notify(req->call, passkey_reply, req, NULL);
+
+ agent->request = req;
+
+ return 0;
+
+failed:
+ agent_request_free(req);
+ return -1;
+}
+
+static DBusPendingCall *confirmation_request_new(struct agent *agent,
+ const char *device_path,
+ uint32_t passkey)
+{
+ DBusMessage *message;
+ DBusPendingCall *call;
+
+ message = dbus_message_new_method_call(agent->name, agent->path,
+ "org.bluez.Agent", "RequestConfirmation");
+ if (message == NULL) {
+ error("Couldn't allocate D-Bus message");
+ return NULL;
+ }
+
+ dbus_message_append_args(message,
+ DBUS_TYPE_OBJECT_PATH, &device_path,
+ DBUS_TYPE_UINT32, &passkey,
+ DBUS_TYPE_INVALID);
+
+ if (dbus_connection_send_with_reply(connection, message,
+ &call, REQUEST_TIMEOUT) == FALSE) {
+ error("D-Bus send failed");
+ dbus_message_unref(message);
+ return NULL;
+ }
+
+ dbus_message_unref(message);
+
+ return call;
+}
+
+int agent_request_confirmation(struct agent *agent, struct device *device,
+ uint32_t passkey, agent_cb cb,
+ void *user_data)
+{
+ struct agent_request *req;
+
+ if (agent->request)
+ return -EBUSY;
+
+ debug("Calling Agent.RequestConfirmation: name=%s, path=%s, passkey=%06u",
+ agent->name, agent->path, passkey);
+
+ req = agent_request_new(agent, AGENT_REQUEST_CONFIRMATION, cb,
+ user_data);
+
+ req->call = confirmation_request_new(agent, device->path, passkey);
+ if (!req->call)
+ goto failed;
+
+ dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL);
+
+ agent->request = req;
+
+ return 0;
+
+failed:
+ agent_request_free(req);
+ return -1;
+}
+
uint8_t agent_get_io_capability(struct agent *agent)
{
return agent->capability;
diff --git a/hcid/agent.h b/hcid/agent.h
index 2bfe003e..552c91f2 100644
--- a/hcid/agent.h
+++ b/hcid/agent.h
@@ -30,6 +30,9 @@ typedef void (*agent_cb) (struct agent *agent, DBusError *err,
typedef void (*agent_pincode_cb) (struct agent *agent, DBusError *err,
const char *pincode, void *user_data);
+typedef void (*agent_passkey_cb) (struct agent *agent, DBusError *err,
+ uint32_t passkey, void *user_data);
+
typedef void (*agent_remove_cb) (struct agent *agent, void *user_data);
struct agent *agent_create(struct adapter *adapter, const char *name,
@@ -47,6 +50,13 @@ int agent_request_pincode(struct agent *agent, struct device *device,
int agent_confirm_mode_change(struct agent *agent, const char *new_mode,
agent_cb cb, void *user_data);
+int agent_request_passkey(struct agent *agent, struct device *device,
+ agent_passkey_cb cb, void *user_data);
+
+int agent_request_confirmation(struct agent *agent, struct device *device,
+ uint32_t passkey, agent_cb cb,
+ void *user_data);
+
int agent_cancel(struct agent *agent);
uint8_t agent_get_io_capability(struct agent *agent);
diff --git a/hcid/dbus-hci.c b/hcid/dbus-hci.c
index 14261bfe..4822de9a 100644
--- a/hcid/dbus-hci.c
+++ b/hcid/dbus-hci.c
@@ -1032,6 +1032,132 @@ old_fallback:
&ci->bdaddr);
}
+static void confirm_cb(struct agent *agent, DBusError *err, void *user_data)
+{
+ struct device *device = user_data;
+ struct adapter *adapter = device->adapter;
+ user_confirm_reply_cp cp;
+ int dd;
+
+ dd = hci_open_dev(adapter->dev_id);
+ if (dd < 0) {
+ error("Unable to open hci%d", adapter->dev_id);
+ return;
+ }
+
+ memset(&cp, 0, sizeof(cp));
+ str2ba(device->address, &cp.bdaddr);
+
+ if (err)
+ hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_CONFIRM_NEG_REPLY,
+ USER_CONFIRM_REPLY_CP_SIZE, &cp);
+ else
+ hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_CONFIRM_REPLY,
+ USER_CONFIRM_REPLY_CP_SIZE, &cp);
+
+ hci_close_dev(dd);
+}
+
+static void passkey_cb(struct agent *agent, DBusError *err, uint32_t passkey,
+ void *user_data)
+{
+ struct device *device = user_data;
+ struct adapter *adapter = device->adapter;
+ user_passkey_reply_cp cp;
+ bdaddr_t dba;
+ int dd;
+
+ dd = hci_open_dev(adapter->dev_id);
+ if (dd < 0) {
+ error("Unable to open hci%d", adapter->dev_id);
+ return;
+ }
+
+ str2ba(device->address, &dba);
+
+ memset(&cp, 0, sizeof(cp));
+ bacpy(&cp.bdaddr, &dba);
+ cp.passkey = passkey;
+
+ if (err)
+ hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_PASSKEY_NEG_REPLY,
+ 6, &dba);
+ else
+ hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_PASSKEY_REPLY,
+ USER_PASSKEY_REPLY_CP_SIZE, &cp);
+
+ hci_close_dev(dd);
+}
+
+int hcid_dbus_user_confirm(bdaddr_t *sba, bdaddr_t *dba, uint32_t passkey)
+{
+ struct adapter *adapter;
+ struct device *device;
+ struct agent *agent;
+ char addr[18];
+
+ adapter = find_adapter(sba);
+ if (!adapter) {
+ error("No matching adapter found");
+ return -1;
+ }
+
+ ba2str(dba, addr);
+
+ device = adapter_get_device(connection, adapter, addr);
+ if (device && device->agent)
+ agent = device->agent;
+ else
+ agent = adapter->agent;
+
+ if (!agent) {
+ error("No agent available for user confirm request");
+ return -1;
+ }
+
+ if (agent_request_confirmation(agent, device, passkey,
+ confirm_cb, device) < 0) {
+ error("Requesting passkey failed");
+ return -1;
+ }
+
+ return 0;
+}
+
+int hcid_dbus_user_passkey(bdaddr_t *sba, bdaddr_t *dba)
+{
+ struct adapter *adapter;
+ struct device *device;
+ struct agent *agent;
+ char addr[18];
+
+ adapter = find_adapter(sba);
+ if (!adapter) {
+ error("No matching adapter found");
+ return -1;
+ }
+
+ ba2str(dba, addr);
+
+ device = adapter_get_device(connection, adapter, addr);
+ if (device && device->agent)
+ agent = device->agent;
+ else
+ agent = adapter->agent;
+
+ if (!agent) {
+ error("No agent available for user confirm request");
+ return -1;
+ }
+
+ if (agent_request_passkey(agent, device, passkey_cb, device) < 0) {
+ error("Requesting passkey failed");
+ return -1;
+ }
+
+ return 0;
+}
+
int hcid_dbus_confirm_pin(int dev, bdaddr_t *sba, struct hci_conn_info *ci, char *pin)
{
struct adapter *adapter;
diff --git a/hcid/dbus-hci.h b/hcid/dbus-hci.h
index 671c5f1a..167780b4 100644
--- a/hcid/dbus-hci.h
+++ b/hcid/dbus-hci.h
@@ -49,6 +49,8 @@ void hcid_dbus_write_simple_pairing_mode_complete(bdaddr_t *local);
void hcid_dbus_pin_code_reply(bdaddr_t *local, void *ptr);
int hcid_dbus_get_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);
+int hcid_dbus_user_passkey(bdaddr_t *sba, bdaddr_t *dba);
int unregister_adapter_path(const char *path);
diff --git a/hcid/security.c b/hcid/security.c
index 6f8151f8..0df255ab 100644
--- a/hcid/security.c
+++ b/hcid/security.c
@@ -360,12 +360,20 @@ static void return_link_keys(int dev, bdaddr_t *sba, void *ptr)
static void user_confirm_request(int dev, bdaddr_t *sba, void *ptr)
{
- hci_send_cmd(dev, OGF_LINK_CTL, OCF_USER_CONFIRM_NEG_REPLY, 6, ptr);
+ evt_user_confirm_request *req = ptr;
+
+ if (hcid_dbus_user_confirm(sba, &req->bdaddr, req->passkey) < 0)
+ hci_send_cmd(dev, OGF_LINK_CTL, OCF_USER_CONFIRM_NEG_REPLY,
+ 6, ptr);
}
static void user_passkey_request(int dev, bdaddr_t *sba, void *ptr)
{
- hci_send_cmd(dev, OGF_LINK_CTL, OCF_USER_PASSKEY_NEG_REPLY, 6, ptr);
+ evt_user_passkey_request *req = ptr;
+
+ if (hcid_dbus_user_passkey(sba, &req->bdaddr) < 0)
+ hci_send_cmd(dev, OGF_LINK_CTL, OCF_USER_PASSKEY_NEG_REPLY,
+ 6, ptr);
}
static void remote_oob_data_request(int dev, bdaddr_t *sba, void *ptr)