diff options
Diffstat (limited to 'hcid/agent.c')
-rw-r--r-- | hcid/agent.c | 733 |
1 files changed, 0 insertions, 733 deletions
diff --git a/hcid/agent.c b/hcid/agent.c deleted file mode 100644 index 3cae00a5..00000000 --- a/hcid/agent.c +++ /dev/null @@ -1,733 +0,0 @@ -/* - * - * BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2006-2008 Nokia Corporation - * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org> - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdio.h> -#include <errno.h> -#include <stdlib.h> -#include <sys/socket.h> -#include <sys/ioctl.h> - -#include <bluetooth/bluetooth.h> -#include <bluetooth/hci.h> -#include <bluetooth/hci_lib.h> -#include <bluetooth/sdp.h> - -#include <glib.h> -#include <dbus/dbus.h> -#include <gdbus.h> - -#include "hcid.h" -#include "dbus-common.h" -#include "error.h" -#include "adapter.h" -#include "dbus-hci.h" -#include "device.h" -#include "agent.h" - -#define REQUEST_TIMEOUT (60 * 1000) /* 60 seconds */ -#define AGENT_TIMEOUT (10 * 60 * 1000) /* 10 minutes */ - -typedef enum { - AGENT_REQUEST_PASSKEY, - AGENT_REQUEST_CONFIRMATION, - AGENT_REQUEST_PINCODE, - AGENT_REQUEST_AUTHORIZE, - AGENT_REQUEST_CONFIRM_MODE -} agent_request_type_t; - -struct agent { - struct adapter *adapter; - char *name; - char *path; - uint8_t capability; - struct agent_request *request; - int exited; - agent_remove_cb remove_cb; - void *remove_cb_data; - guint listener_id; -}; - -struct agent_request { - agent_request_type_t type; - struct agent *agent; - DBusPendingCall *call; - void *cb; - void *user_data; -}; - -static DBusConnection *connection = NULL; - -static void agent_release(struct agent *agent) -{ - DBusMessage *message; - - debug("Releasing agent %s, %s", agent->name, agent->path); - - if (agent->request) - agent_cancel(agent); - - message = dbus_message_new_method_call(agent->name, agent->path, - "org.bluez.Agent", "Release"); - if (message == NULL) { - error("Couldn't allocate D-Bus message"); - return; - } - - dbus_message_set_no_reply(message, TRUE); - - dbus_connection_send(connection, message, NULL); - - dbus_message_unref(message); -} - -static int send_cancel_request(struct agent_request *req) -{ - DBusMessage *message; - - message = dbus_message_new_method_call(req->agent->name, req->agent->path, - "org.bluez.Agent", "Cancel"); - if (message == NULL) { - error("Couldn't allocate D-Bus message"); - return -ENOMEM; - } - - dbus_message_set_no_reply(message, TRUE); - - dbus_connection_send(connection, message, NULL); - - dbus_message_unref(message); - - return 0; -} - -static void agent_request_free(struct agent_request *req) -{ - if (req->call) - dbus_pending_call_unref(req->call); - if (req->agent && req->agent->request) - req->agent->request = NULL; - g_free(req); -} - -static void agent_exited(void *user_data) -{ - struct agent *agent = user_data; - - debug("Agent exited without calling Unregister"); - - agent_destroy(agent, TRUE); -} - -static void agent_free(struct agent *agent) -{ - if (!agent) - return; - - if (agent->remove_cb) - agent->remove_cb(agent, agent->remove_cb_data); - - if (agent->request) { - DBusError err; - agent_pincode_cb pincode_cb; - agent_cb cb; - - dbus_error_init(&err); - dbus_set_error_const(&err, "org.bluez.Error.Failed", "Canceled"); - - switch (agent->request->type) { - case AGENT_REQUEST_PINCODE: - pincode_cb = agent->request->cb; - pincode_cb(agent, &err, NULL, agent->request->user_data); - break; - default: - cb = agent->request->cb; - cb(agent, &err, agent->request->user_data); - } - - dbus_error_free(&err); - - agent_cancel(agent); - } - - if (!agent->exited) { - g_dbus_remove_watch(connection, agent->listener_id); - agent_release(agent); - } - - g_free(agent->name); - g_free(agent->path); - - g_free(agent); -} - -struct agent *agent_create(struct adapter *adapter, const char *name, - const char *path, uint8_t capability, - agent_remove_cb cb, void *remove_cb_data) -{ - struct agent *agent; - - if (adapter->agent && g_str_equal(adapter->agent->name, name)) - return NULL; - - agent = g_new0(struct agent, 1); - - agent->adapter = adapter; - agent->name = g_strdup(name); - agent->path = g_strdup(path); - agent->capability = capability; - agent->remove_cb = cb; - agent->remove_cb_data = remove_cb_data; - - agent->listener_id = g_dbus_add_disconnect_watch(connection, name, - agent_exited, agent, - NULL); - - return agent; -} - -int agent_destroy(struct agent *agent, gboolean exited) -{ - agent->exited = exited; - agent_free(agent); - return 0; -} - -static struct agent_request *agent_request_new(struct agent *agent, - agent_request_type_t type, - void *cb, - void *user_data) -{ - struct agent_request *req; - - req = g_new0(struct agent_request, 1); - - req->agent = agent; - req->type = type; - req->cb = cb; - req->user_data = user_data; - - return req; -} - -int agent_cancel(struct agent *agent) -{ - if (!agent->request) - return -EINVAL; - - if (agent->request->call) - dbus_pending_call_cancel(agent->request->call); - - if (!agent->exited) - send_cancel_request(agent->request); - - agent_request_free(agent->request); - agent->request = NULL; - - return 0; -} - -static DBusPendingCall *agent_call_authorize(struct agent *agent, - const char *device_path, - const char *uuid) -{ - DBusMessage *message; - DBusPendingCall *call; - - message = dbus_message_new_method_call(agent->name, agent->path, - "org.bluez.Agent", "Authorize"); - if (!message) { - error("Couldn't allocate D-Bus message"); - return NULL; - } - - dbus_message_append_args(message, - DBUS_TYPE_OBJECT_PATH, &device_path, - DBUS_TYPE_STRING, &uuid, - 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 simple_agent_reply(DBusPendingCall *call, void *user_data) -{ - struct agent_request *req = user_data; - struct agent *agent = req->agent; - DBusMessage *message; - DBusError err; - agent_cb cb = req->cb; - - /* 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, req->user_data); - dbus_error_free(&err); - goto done; - } - - dbus_error_init(&err); - if (!dbus_message_get_args(message, &err, DBUS_TYPE_INVALID)) { - error("Wrong reply signature: %s", err.message); - cb(agent, &err, req->user_data); - dbus_error_free(&err); - goto done; - } - - cb(agent, NULL, req->user_data); -done: - dbus_message_unref(message); - - agent->request = NULL; - agent_request_free(req); -} - -int agent_authorize(struct agent *agent, - const char *path, - const char *uuid, - agent_cb cb, - void *user_data) -{ - struct agent_request *req; - - if (agent->request) - return -EBUSY; - - req = agent_request_new(agent, AGENT_REQUEST_AUTHORIZE, cb, user_data); - - req->call = agent_call_authorize(agent, path, uuid); - if (!req->call) { - agent_request_free(req); - return DBUS_HANDLER_RESULT_NEED_MEMORY; - } - - dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL); - agent->request = req; - - debug("authorize request was sent for %s", path); - - return 0; -} - -static DBusPendingCall *pincode_request_new(struct agent *agent, - const char *device_path, - dbus_bool_t numeric) -{ - DBusMessage *message; - DBusPendingCall *call; - - message = dbus_message_new_method_call(agent->name, agent->path, - "org.bluez.Agent", "RequestPinCode"); - 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 pincode_reply(DBusPendingCall *call, void *user_data) -{ - struct agent_request *req = user_data; - struct agent *agent = req->agent; - struct adapter *adapter = agent->adapter; - agent_pincode_cb cb = req->cb; - DBusMessage *message; - DBusError err; - bdaddr_t sba; - size_t len; - char *pin; - const gchar *source = adapter_get_address(adapter); - - /* 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, NULL, req->user_data); - dbus_error_free(&err); - goto done; - } - - dbus_error_init(&err); - if (!dbus_message_get_args(message, &err, - DBUS_TYPE_STRING, &pin, - DBUS_TYPE_INVALID)) { - error("Wrong passkey reply signature: %s", err.message); - cb(agent, &err, NULL, req->user_data); - dbus_error_free(&err); - goto done; - } - - len = strlen(pin); - - dbus_error_init(&err); - if (len > 16 || len < 1) { - error("Invalid passkey length from handler"); - dbus_set_error_const(&err, "org.bluez.Error.InvalidArgs", - "Invalid passkey length"); - cb(agent, &err, NULL, req->user_data); - dbus_error_free(&err); - goto done; - } - - str2ba(source, &sba); - - set_pin_length(&sba, len); - - cb(agent, NULL, pin, req->user_data); - -done: - if (message) - dbus_message_unref(message); - - dbus_pending_call_cancel(req->call); - agent_request_free(req); -} - -int agent_request_pincode(struct agent *agent, struct btd_device *device, - agent_pincode_cb cb, void *user_data) -{ - struct agent_request *req; - const gchar *dev_path = device_get_path(device); - - if (agent->request) - return -EBUSY; - - req = agent_request_new(agent, AGENT_REQUEST_PINCODE, cb, user_data); - - req->call = pincode_request_new(agent, dev_path, FALSE); - if (!req->call) - goto failed; - - dbus_pending_call_set_notify(req->call, pincode_reply, req, NULL); - - agent->request = req; - - return 0; - -failed: - g_free(req); - return -1; -} - -static DBusPendingCall *confirm_mode_change_request_new(struct agent *agent, - const char *mode) -{ - DBusMessage *message; - DBusPendingCall *call; - - message = dbus_message_new_method_call(agent->name, agent->path, - "org.bluez.Agent", "ConfirmModeChange"); - if (message == NULL) { - error("Couldn't allocate D-Bus message"); - return NULL; - } - - dbus_message_append_args(message, - DBUS_TYPE_STRING, &mode, - 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_confirm_mode_change(struct agent *agent, const char *new_mode, - agent_cb cb, void *user_data) -{ - struct agent_request *req; - - if (agent->request) - return -EBUSY; - - debug("Calling Agent.ConfirmModeChange: name=%s, path=%s, mode=%s", - agent->name, agent->path, new_mode); - - req = agent_request_new(agent, AGENT_REQUEST_CONFIRM_MODE, - cb, user_data); - - req->call = confirm_mode_change_request_new(agent, new_mode); - 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; -} - -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 btd_device *device, - agent_passkey_cb cb, void *user_data) -{ - struct agent_request *req; - const gchar *dev_path = device_get_path(device); - - 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, dev_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 btd_device *device, - uint32_t passkey, agent_cb cb, - void *user_data) -{ - struct agent_request *req; - const gchar *dev_path = device_get_path(device); - - 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, dev_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; -} - -int agent_display_passkey(struct agent *agent, struct btd_device *device, - uint32_t passkey) -{ - DBusMessage *message; - const gchar *dev_path = device_get_path(device); - - message = dbus_message_new_method_call(agent->name, agent->path, - "org.bluez.Agent", "DisplayPasskey"); - if (!message) { - error("Couldn't allocate D-Bus message"); - return -1; - } - - dbus_message_append_args(message, - DBUS_TYPE_OBJECT_PATH, &dev_path, - DBUS_TYPE_UINT32, &passkey, - DBUS_TYPE_INVALID); - - if (!g_dbus_send_message(connection, message)) { - error("D-Bus send failed"); - dbus_message_unref(message); - return -1; - } - - return 0; -} - -uint8_t agent_get_io_capability(struct agent *agent) -{ - return agent->capability; -} - -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)) - return TRUE; - - return FALSE; -} - -void agent_exit(void) -{ - dbus_connection_unref(connection); -} - -void agent_init(void) -{ - connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); -} |