diff options
author | Johan Hedberg <johan.hedberg@nokia.com> | 2008-06-05 13:30:11 +0000 |
---|---|---|
committer | Johan Hedberg <johan.hedberg@nokia.com> | 2008-06-05 13:30:11 +0000 |
commit | dac5b3dfc9ce5091315294f938dc84188985dad6 (patch) | |
tree | 759f59d04d54bab34950f29d9cd470615ccecb92 /hcid | |
parent | 94f7643c52193c905edaff767c2e9a31b9102a73 (diff) |
Implement first part of missing SSP callbacks
Diffstat (limited to 'hcid')
-rw-r--r-- | hcid/agent.c | 159 | ||||
-rw-r--r-- | hcid/agent.h | 10 | ||||
-rw-r--r-- | hcid/dbus-hci.c | 126 | ||||
-rw-r--r-- | hcid/dbus-hci.h | 2 | ||||
-rw-r--r-- | hcid/security.c | 12 |
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) |