diff options
Diffstat (limited to 'hcid/adapter.c')
-rw-r--r-- | hcid/adapter.c | 2680 |
1 files changed, 0 insertions, 2680 deletions
diff --git a/hcid/adapter.c b/hcid/adapter.c deleted file mode 100644 index cb2eba0a..00000000 --- a/hcid/adapter.c +++ /dev/null @@ -1,2680 +0,0 @@ -/* - * - * BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2006-2007 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 - -#define _GNU_SOURCE -#include <stdio.h> -#include <errno.h> -#include <fcntl.h> -#include <unistd.h> -#include <stdlib.h> -#include <time.h> -#include <sys/param.h> -#include <sys/ioctl.h> -#include <sys/socket.h> - -#include <bluetooth/bluetooth.h> -#include <bluetooth/hci.h> -#include <bluetooth/hci_lib.h> -#include <bluetooth/l2cap.h> -#include <bluetooth/sdp.h> -#include <bluetooth/sdp_lib.h> - -#include <glib.h> -#include <dbus/dbus.h> -#include <gdbus.h> - -#include "hcid.h" -#include "sdpd.h" - -#include "adapter.h" -#include "device.h" - -#include "textfile.h" -#include "oui.h" -#include "dbus-common.h" -#include "dbus-hci.h" -#include "dbus-database.h" -#include "error.h" -#include "glib-helper.h" -#include "logging.h" -#include "agent.h" - -#define NUM_ELEMENTS(table) (sizeof(table)/sizeof(const char *)) - -#define IO_CAPABILITY_DISPLAYONLY 0x00 -#define IO_CAPABILITY_DISPLAYYESNO 0x01 -#define IO_CAPABILITY_KEYBOARDONLY 0x02 -#define IO_CAPABILITY_NOINPUTOUTPUT 0x03 -#define IO_CAPABILITY_INVALID 0xFF - -static DBusConnection *connection = NULL; - -struct record_list { - sdp_list_t *recs; - const gchar *addr; -}; - -struct mode_req { - struct adapter *adapter; - DBusConnection *conn; /* Connection reference */ - DBusMessage *msg; /* Message reference */ - uint8_t mode; /* Requested mode */ - guint id; /* Listener id */ -}; - -static inline DBusMessage *invalid_args(DBusMessage *msg) -{ - return g_dbus_create_error(msg, ERROR_INTERFACE ".InvalidArguments", - "Invalid arguments in method call"); -} - -static inline DBusMessage *not_available(DBusMessage *msg) -{ - return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAvailable", - "Not Available"); -} - -static inline DBusMessage *adapter_not_ready(DBusMessage *msg) -{ - return g_dbus_create_error(msg, ERROR_INTERFACE ".NotReady", - "Adapter is not ready"); -} - -static inline DBusMessage *no_such_adapter(DBusMessage *msg) -{ - return g_dbus_create_error(msg, ERROR_INTERFACE ".NoSuchAdapter", - "No such adapter"); -} - -static inline DBusMessage *failed_strerror(DBusMessage *msg, int err) -{ - return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", - strerror(err)); -} - -static inline DBusMessage *in_progress(DBusMessage *msg, const char *str) -{ - return g_dbus_create_error(msg, ERROR_INTERFACE ".InProgress", str); -} - -static inline DBusMessage *not_in_progress(DBusMessage *msg, const char *str) -{ - return g_dbus_create_error(msg, ERROR_INTERFACE ".NotInProgress", str); -} - -static inline DBusMessage *not_authorized(DBusMessage *msg) -{ - return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAuthorized", - "Not authorized"); -} - -static inline DBusMessage *unsupported_major_class(DBusMessage *msg) -{ - return g_dbus_create_error(msg, - ERROR_INTERFACE ".UnsupportedMajorClass", - "Unsupported Major Class"); -} - -static int auth_req_cmp(const void *p1, const void *p2) -{ - const struct pending_auth_info *pb1 = p1; - const bdaddr_t *bda = p2; - - return bda ? bacmp(&pb1->bdaddr, bda) : -1; -} - -void adapter_auth_request_replied(struct adapter *adapter, bdaddr_t *dba) -{ - GSList *l; - struct pending_auth_info *auth; - - l = g_slist_find_custom(adapter->auth_reqs, dba, auth_req_cmp); - if (!l) - return; - - auth = l->data; - - auth->replied = TRUE; -} - -struct pending_auth_info *adapter_find_auth_request(struct adapter *adapter, - bdaddr_t *dba) -{ - GSList *l; - - l = g_slist_find_custom(adapter->auth_reqs, dba, auth_req_cmp); - if (l) - return l->data; - - return NULL; -} - -void adapter_remove_auth_request(struct adapter *adapter, bdaddr_t *dba) -{ - GSList *l; - struct pending_auth_info *auth; - - l = g_slist_find_custom(adapter->auth_reqs, dba, auth_req_cmp); - if (!l) - return; - - auth = l->data; - - adapter->auth_reqs = g_slist_remove(adapter->auth_reqs, auth); - - g_free(auth); -} - -struct pending_auth_info *adapter_new_auth_request(struct adapter *adapter, - bdaddr_t *dba, - auth_type_t type) -{ - struct pending_auth_info *info; - - debug("hcid_dbus_new_auth_request"); - - info = g_new0(struct pending_auth_info, 1); - - bacpy(&info->bdaddr, dba); - info->type = type; - adapter->auth_reqs = g_slist_append(adapter->auth_reqs, info); - - if (adapter->bonding && !bacmp(dba, &adapter->bonding->bdaddr)) - adapter->bonding->auth_active = 1; - - return info; -} - -int pending_remote_name_cancel(struct adapter *adapter) -{ - struct remote_dev_info *dev, match; - GSList *l; - int dd, err = 0; - - /* find the pending remote name request */ - memset(&match, 0, sizeof(struct remote_dev_info)); - bacpy(&match.bdaddr, BDADDR_ANY); - match.name_status = NAME_REQUESTED; - - l = g_slist_find_custom(adapter->found_devices, &match, - (GCompareFunc) found_device_cmp); - if (!l) /* no pending request */ - return 0; - - dd = hci_open_dev(adapter->dev_id); - if (dd < 0) - return -ENODEV; - - dev = l->data; - - if (hci_read_remote_name_cancel(dd, &dev->bdaddr, 1000) < 0) { - error("Remote name cancel failed: %s(%d)", strerror(errno), errno); - err = -errno; - } - - /* free discovered devices list */ - g_slist_foreach(adapter->found_devices, (GFunc) g_free, NULL); - g_slist_free(adapter->found_devices); - adapter->found_devices = NULL; - - hci_close_dev(dd); - return err; -} - -static int auth_info_agent_cmp(const void *a, const void *b) -{ - const struct pending_auth_info *auth = a; - const struct agent *agent = b; - - if (auth->agent == agent) - return 0; - - return -1; -} - -static void device_agent_removed(struct agent *agent, void *user_data) -{ - struct btd_device *device = user_data; - struct pending_auth_info *auth; - GSList *l; - struct adapter *adapter; - - adapter = device_get_adapter(device); - device_set_agent(device, NULL); - - l = g_slist_find_custom(adapter->auth_reqs, agent, - auth_info_agent_cmp); - if (!l) - return; - - auth = l->data; - auth->agent = NULL; -} - -static struct bonding_request_info *bonding_request_new(DBusConnection *conn, - DBusMessage *msg, - struct adapter *adapter, - const char *address, - const char *agent_path, - uint8_t capability) -{ - struct bonding_request_info *bonding; - struct btd_device *device; - const char *name = dbus_message_get_sender(msg); - const gchar *destination; - struct agent *agent; - - debug("bonding_request_new(%s)", address); - - device = adapter_get_device(conn, adapter, address); - if (!device) - return NULL; - - destination = device_get_address(device); - agent = agent_create(adapter, name, agent_path, - capability, - device_agent_removed, - device); - - device_set_agent(device, agent); - - debug("Temporary agent registered for hci%d/%s at %s:%s", - adapter->dev_id, destination, name, - agent_path); - - bonding = g_new0(struct bonding_request_info, 1); - - bonding->conn = dbus_connection_ref(conn); - bonding->msg = dbus_message_ref(msg); - bonding->adapter = adapter; - - str2ba(address, &bonding->bdaddr); - - return bonding; -} - -const char *mode2str(uint8_t mode) -{ - switch(mode) { - case MODE_OFF: - return "off"; - case MODE_CONNECTABLE: - return "connectable"; - case MODE_DISCOVERABLE: - return "discoverable"; - case MODE_LIMITED: - return "limited"; - default: - return "unknown"; - } -} - -static uint8_t on_mode(const char *addr) -{ - char mode[14]; - bdaddr_t sba; - - str2ba(addr, &sba); - - if (read_on_mode(&sba, mode, sizeof(mode)) < 0) - return MODE_CONNECTABLE; - - return str2mode(addr, mode); -} - -uint8_t str2mode(const char *addr, const char *mode) -{ - if (strcasecmp("off", mode) == 0) - return MODE_OFF; - else if (strcasecmp("connectable", mode) == 0) - return MODE_CONNECTABLE; - else if (strcasecmp("discoverable", mode) == 0) - return MODE_DISCOVERABLE; - else if (strcasecmp("limited", mode) == 0) - return MODE_LIMITED; - else if (strcasecmp("on", mode) == 0) - return on_mode(addr); - else - return MODE_UNKNOWN; -} - -static DBusMessage *set_mode(DBusConnection *conn, DBusMessage *msg, - uint8_t new_mode, void *data) -{ - struct adapter *adapter = data; - uint8_t scan_enable; - uint8_t current_scan = adapter->scan_mode; - bdaddr_t local; - gboolean limited; - int err, dd; - const char *mode; - - switch(new_mode) { - case MODE_OFF: - scan_enable = SCAN_DISABLED; - break; - case MODE_CONNECTABLE: - scan_enable = SCAN_PAGE; - break; - case MODE_DISCOVERABLE: - case MODE_LIMITED: - scan_enable = (SCAN_PAGE | SCAN_INQUIRY); - break; - default: - return invalid_args(msg); - } - - /* Do reverse resolution in case of "on" mode */ - mode = mode2str(new_mode); - - dd = hci_open_dev(adapter->dev_id); - if (dd < 0) - return no_such_adapter(msg); - - if (!adapter->up && - (hcid.offmode == HCID_OFFMODE_NOSCAN || - (hcid.offmode == HCID_OFFMODE_DEVDOWN && - scan_enable != SCAN_DISABLED))) { - /* Start HCI device */ - if (ioctl(dd, HCIDEVUP, adapter->dev_id) == 0) - goto done; /* on success */ - - if (errno != EALREADY) { - err = errno; - error("Can't init device hci%d: %s (%d)\n", - adapter->dev_id, strerror(errno), errno); - - hci_close_dev(dd); - return failed_strerror(msg, err); - } - } - - if (adapter->up && scan_enable == SCAN_DISABLED && - hcid.offmode == HCID_OFFMODE_DEVDOWN) { - if (ioctl(dd, HCIDEVDOWN, adapter->dev_id) < 0) { - hci_close_dev(dd); - return failed_strerror(msg, errno); - } - - goto done; - } - - limited = (new_mode == MODE_LIMITED ? TRUE : FALSE); - err = set_limited_discoverable(dd, adapter->dev.class, limited); - if (err < 0) { - hci_close_dev(dd); - return failed_strerror(msg, -err); - } - - if (current_scan != scan_enable) { - struct hci_request rq; - uint8_t status = 0; - - memset(&rq, 0, sizeof(rq)); - rq.ogf = OGF_HOST_CTL; - rq.ocf = OCF_WRITE_SCAN_ENABLE; - rq.cparam = &scan_enable; - rq.clen = sizeof(scan_enable); - rq.rparam = &status; - rq.rlen = sizeof(status); - rq.event = EVT_CMD_COMPLETE; - - if (hci_send_req(dd, &rq, 1000) < 0) { - err = errno; - error("Sending write scan enable command failed: %s (%d)", - strerror(errno), errno); - hci_close_dev(dd); - return failed_strerror(msg, err); - } - - if (status) { - error("Setting scan enable failed with status 0x%02x", - status); - hci_close_dev(dd); - return failed_strerror(msg, bt_error(status)); - } - } else { - /* discoverable or limited */ - if ((scan_enable & SCAN_INQUIRY) && (new_mode != adapter->mode)) { - if (adapter->discov_timeout_id) - g_source_remove(adapter->discov_timeout_id); - - if (!adapter->sessions && !adapter->discov_timeout) - adapter->discov_timeout_id = g_timeout_add(adapter->discov_timeout * 1000, - discov_timeout_handler, adapter); - } - } -done: - str2ba(adapter->address, &local); - write_device_mode(&local, mode); - - hci_close_dev(dd); - - adapter->mode = new_mode; - - return dbus_message_new_method_return(msg); -} - -gint find_session(struct mode_req *req, DBusMessage *msg) -{ - const char *name = dbus_message_get_sender(req->msg); - const char *sender = dbus_message_get_sender(msg); - - return strcmp(name, sender); -} - -static void confirm_mode_cb(struct agent *agent, DBusError *err, void *data) -{ - struct mode_req *req = data; - DBusMessage *reply; - - if (err && dbus_error_is_set(err)) { - reply = dbus_message_new_error(req->msg, err->name, err->message); - dbus_connection_send(req->conn, reply, NULL); - dbus_message_unref(reply); - goto cleanup; - } - - reply = set_mode(req->conn, req->msg, req->mode, req->adapter); - dbus_connection_send(req->conn, reply, NULL); - dbus_message_unref(reply); - - if (!g_slist_find_custom(req->adapter->sessions, req->msg, - (GCompareFunc) find_session)) - goto cleanup; - - return; - -cleanup: - dbus_message_unref(req->msg); - if (req->id) - g_dbus_remove_watch(req->conn, req->id); - dbus_connection_unref(req->conn); - g_free(req); -} - -static DBusMessage *confirm_mode(DBusConnection *conn, DBusMessage *msg, - const char *mode, void *data) -{ - struct adapter *adapter = data; - struct mode_req *req; - int ret; - - if (!adapter->agent) - return dbus_message_new_method_return(msg); - - req = g_new0(struct mode_req, 1); - req->adapter = adapter; - req->conn = dbus_connection_ref(conn); - req->msg = dbus_message_ref(msg); - req->mode = str2mode(adapter->address, mode); - - ret = agent_confirm_mode_change(adapter->agent, mode, confirm_mode_cb, - req); - if (ret < 0) { - dbus_connection_unref(req->conn); - dbus_message_unref(req->msg); - g_free(req); - return invalid_args(msg); - } - - return NULL; -} - -static DBusMessage *set_discoverable_timeout(DBusConnection *conn, - DBusMessage *msg, - uint32_t timeout, - void *data) -{ - struct adapter *adapter = data; - bdaddr_t bdaddr; - const char *path; - - if (adapter->discov_timeout_id) { - g_source_remove(adapter->discov_timeout_id); - adapter->discov_timeout_id = 0; - } - - if ((timeout != 0) && (adapter->scan_mode & SCAN_INQUIRY)) - adapter->discov_timeout_id = g_timeout_add(timeout * 1000, - discov_timeout_handler, - adapter); - - adapter->discov_timeout = timeout; - - str2ba(adapter->address, &bdaddr); - write_discoverable_timeout(&bdaddr, timeout); - - path = dbus_message_get_path(msg); - - dbus_connection_emit_property_changed(conn, path, - ADAPTER_INTERFACE, - "DiscoverableTimeout", - DBUS_TYPE_UINT32, &timeout); - - return dbus_message_new_method_return(msg); -} - -static void update_ext_inquiry_response(int dd, struct hci_dev *dev) -{ - uint8_t fec = 0, data[240]; - - if (!(dev->features[6] & LMP_EXT_INQ)) - return; - - memset(data, 0, sizeof(data)); - - if (dev->ssp_mode > 0) - create_ext_inquiry_response((char *) dev->name, data); - - if (hci_write_ext_inquiry_response(dd, fec, data, 2000) < 0) - error("Can't write extended inquiry response: %s (%d)", - strerror(errno), errno); -} - -static int adapter_set_name(struct adapter *adapter, const char *name) -{ - struct hci_dev *dev = &adapter->dev; - int dd, err; - bdaddr_t bdaddr; - - str2ba(adapter->address, &bdaddr); - - write_local_name(&bdaddr, (char *) name); - - if (!adapter->up) - return 0; - - dd = hci_open_dev(adapter->dev_id); - if (dd < 0) { - err = errno; - error("Can't open device hci%d: %s (%d)", - adapter->dev_id, strerror(err), err); - return -err; - } - - if (hci_write_local_name(dd, name, 5000) < 0) { - err = errno; - error("Can't write name for hci%d: %s (%d)", - adapter->dev_id, strerror(err), err); - hci_close_dev(dd); - return -err; - } - - strncpy((char *) dev->name, name, 248); - - update_ext_inquiry_response(dd, dev); - - hci_close_dev(dd); - - return 0; -} - -static DBusMessage *set_name(DBusConnection *conn, DBusMessage *msg, - const char *name, void *data) -{ - struct adapter *adapter = data; - int ecode; - const char *path; - - if (!g_utf8_validate(name, -1, NULL)) { - error("Name change failed: the supplied name isn't valid UTF-8"); - return invalid_args(msg); - } - - ecode = adapter_set_name(adapter, name); - if (ecode < 0) - return failed_strerror(msg, -ecode); - - path = dbus_message_get_path(msg); - - dbus_connection_emit_property_changed(conn, path, - ADAPTER_INTERFACE, - "Name", DBUS_TYPE_STRING, - &name); - - return dbus_message_new_method_return(msg); -} - -static void reply_authentication_failure(struct bonding_request_info *bonding) -{ - DBusMessage *reply; - int status; - - status = bonding->hci_status ? - bonding->hci_status : HCI_AUTHENTICATION_FAILURE; - - reply = new_authentication_return(bonding->msg, status); - if (reply) { - dbus_connection_send(bonding->conn, reply, NULL); - dbus_message_unref(reply); - } -} - -struct btd_device *adapter_find_device(struct adapter *adapter, const char *dest) -{ - struct btd_device *device; - GSList *l; - - if (!adapter) - return NULL; - - l = g_slist_find_custom(adapter->devices, - dest, (GCompareFunc) device_address_cmp); - if (!l) - return NULL; - - device = l->data; - - return device; -} - -struct btd_device *adapter_create_device(DBusConnection *conn, - struct adapter *adapter, const char *address) -{ - struct btd_device *device; - - debug("adapter_create_device(%s)", address); - - device = device_create(conn, adapter, address); - if (!device) - return NULL; - - device_set_temporary(device, TRUE); - - adapter->devices = g_slist_append(adapter->devices, device); - - return device; -} - -static DBusMessage *remove_bonding(DBusConnection *conn, DBusMessage *msg, - const char *address, void *data) -{ - struct adapter *adapter = data; - struct btd_device *device; - char filename[PATH_MAX + 1]; - char *str; - bdaddr_t src, dst; - GSList *l; - int dev, err; - gboolean paired; - - str2ba(adapter->address, &src); - str2ba(address, &dst); - - dev = hci_open_dev(adapter->dev_id); - if (dev < 0 && msg) - return no_such_adapter(msg); - - create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, - "linkkeys"); - - /* textfile_del doesn't return an error when the key is not found */ - str = textfile_caseget(filename, address); - paired = str ? TRUE : FALSE; - g_free(str); - - if (!paired && msg) { - hci_close_dev(dev); - return g_dbus_create_error(msg, - ERROR_INTERFACE ".DoesNotExist", - "Bonding does not exist"); - } - - /* Delete the link key from storage */ - if (textfile_casedel(filename, address) < 0 && msg) { - hci_close_dev(dev); - err = errno; - return failed_strerror(msg, err); - } - - /* Delete the link key from the Bluetooth chip */ - hci_delete_stored_link_key(dev, &dst, 0, 1000); - - /* find the connection */ - l = g_slist_find_custom(adapter->active_conn, &dst, - active_conn_find_by_bdaddr); - if (l) { - struct active_conn_info *con = l->data; - /* Send the HCI disconnect command */ - if ((hci_disconnect(dev, htobs(con->handle), - HCI_OE_USER_ENDED_CONNECTION, 500) < 0) - && msg){ - int err = errno; - error("Disconnect failed"); - hci_close_dev(dev); - return failed_strerror(msg, err); - } - } - - hci_close_dev(dev); - - device = adapter_find_device(adapter, address); - if (!device) - goto proceed; - - if (paired) { - gboolean paired = FALSE; - - const gchar *dev_path = device_get_path(device); - - dbus_connection_emit_property_changed(conn, dev_path, - DEVICE_INTERFACE, "Paired", - DBUS_TYPE_BOOLEAN, &paired); - } - -proceed: - if(!msg) - goto done; - - return dbus_message_new_method_return(msg); - -done: - return NULL; -} - - -void adapter_remove_device(DBusConnection *conn, struct adapter *adapter, - struct btd_device *device) -{ - bdaddr_t src; - const gchar *destination = device_get_address(device); - const gchar *dev_path = device_get_path(device); - struct agent *agent; - - str2ba(adapter->address, &src); - delete_entry(&src, "profiles", destination); - - remove_bonding(conn, NULL, destination, adapter); - - if (!device_is_temporary(device)) { - g_dbus_emit_signal(conn, adapter->path, - ADAPTER_INTERFACE, - "DeviceRemoved", - DBUS_TYPE_OBJECT_PATH, &dev_path, - DBUS_TYPE_INVALID); - } - - agent = device_get_agent(device); - - if (agent) { - agent_destroy(agent, FALSE); - device_set_agent(device, NULL); - } - - adapter->devices = g_slist_remove(adapter->devices, device); - - device_remove(conn, device); -} - -struct btd_device *adapter_get_device(DBusConnection *conn, - struct adapter *adapter, const gchar *address) -{ - struct btd_device *device; - - debug("adapter_get_device(%s)", address); - - if (!adapter) - return NULL; - - device = adapter_find_device(adapter, address); - if (device) - return device; - - return adapter_create_device(conn, adapter, address); -} - -void remove_pending_device(struct adapter *adapter) -{ - struct btd_device *device; - char address[18]; - - ba2str(&adapter->bonding->bdaddr, address); - device = adapter_find_device(adapter, address); - if (!device) - return; - - if (device_is_temporary(device)) - adapter_remove_device(adapter->bonding->conn, adapter, device); -} - -static gboolean create_bonding_conn_complete(GIOChannel *io, GIOCondition cond, - struct adapter *adapter) -{ - struct hci_request rq; - auth_requested_cp cp; - evt_cmd_status rp; - struct l2cap_conninfo cinfo; - socklen_t len; - int sk, dd, ret; - - if (!adapter->bonding) { - /* If we come here it implies a bug somewhere */ - debug("create_bonding_conn_complete: no pending bonding!"); - g_io_channel_close(io); - g_io_channel_unref(io); - return FALSE; - } - - if (cond & G_IO_NVAL) { - DBusMessage *reply; - reply = new_authentication_return(adapter->bonding->msg, 0x09); - g_dbus_send_message(adapter->bonding->conn, reply); - goto cleanup; - } - - if (cond & (G_IO_HUP | G_IO_ERR)) { - debug("Hangup or error on bonding IO channel"); - - if (!adapter->bonding->auth_active) - error_connection_attempt_failed(adapter->bonding->conn, - adapter->bonding->msg, - ENETDOWN); - else - reply_authentication_failure(adapter->bonding); - - goto failed; - } - - sk = g_io_channel_unix_get_fd(io); - - len = sizeof(ret); - if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { - error("Can't get socket error: %s (%d)", - strerror(errno), errno); - error_failed_errno(adapter->bonding->conn, adapter->bonding->msg, - errno); - goto failed; - } - - if (ret != 0) { - if (adapter->bonding->auth_active) - reply_authentication_failure(adapter->bonding); - else - error_connection_attempt_failed(adapter->bonding->conn, - adapter->bonding->msg, - ret); - goto failed; - } - - len = sizeof(cinfo); - if (getsockopt(sk, SOL_L2CAP, L2CAP_CONNINFO, &cinfo, &len) < 0) { - error("Can't get connection info: %s (%d)", - strerror(errno), errno); - error_failed_errno(adapter->bonding->conn, adapter->bonding->msg, - errno); - goto failed; - } - - dd = hci_open_dev(adapter->dev_id); - if (dd < 0) { - DBusMessage *reply = no_such_adapter(adapter->bonding->msg); - g_dbus_send_message(adapter->bonding->conn, reply); - goto failed; - } - - memset(&rp, 0, sizeof(rp)); - - memset(&cp, 0, sizeof(cp)); - cp.handle = htobs(cinfo.hci_handle); - - memset(&rq, 0, sizeof(rq)); - rq.ogf = OGF_LINK_CTL; - rq.ocf = OCF_AUTH_REQUESTED; - rq.cparam = &cp; - rq.clen = AUTH_REQUESTED_CP_SIZE; - rq.rparam = &rp; - rq.rlen = EVT_CMD_STATUS_SIZE; - rq.event = EVT_CMD_STATUS; - - if (hci_send_req(dd, &rq, 500) < 0) { - error("Unable to send HCI request: %s (%d)", - strerror(errno), errno); - error_failed_errno(adapter->bonding->conn, adapter->bonding->msg, - errno); - hci_close_dev(dd); - goto failed; - } - - if (rp.status) { - error("HCI_Authentication_Requested failed with status 0x%02x", - rp.status); - error_failed_errno(adapter->bonding->conn, adapter->bonding->msg, - bt_error(rp.status)); - hci_close_dev(dd); - goto failed; - } - - hci_close_dev(dd); - - adapter->bonding->auth_active = 1; - - adapter->bonding->io_id = g_io_add_watch(io, - G_IO_NVAL | G_IO_HUP | G_IO_ERR, - (GIOFunc) create_bonding_conn_complete, - adapter); - - return FALSE; - -failed: - g_io_channel_close(io); - remove_pending_device(adapter); - -cleanup: - g_dbus_remove_watch(adapter->bonding->conn, - adapter->bonding->listener_id); - bonding_request_free(adapter->bonding); - adapter->bonding = NULL; - - return FALSE; -} - -static void cancel_auth_request(struct pending_auth_info *auth, int dev_id) -{ - int dd; - - if (auth->replied) - return; - - dd = hci_open_dev(dev_id); - if (dd < 0) { - error("hci_open_dev: %s (%d)", strerror(errno), errno); - return; - } - - switch (auth->type) { - case AUTH_TYPE_PINCODE: - hci_send_cmd(dd, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, - 6, &auth->bdaddr); - break; - case AUTH_TYPE_CONFIRM: - hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_CONFIRM_NEG_REPLY, - 6, &auth->bdaddr); - break; - case AUTH_TYPE_PASSKEY: - hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_PASSKEY_NEG_REPLY, - 6, &auth->bdaddr); - break; - case AUTH_TYPE_NOTIFY: - /* User Notify doesn't require any reply */ - break; - } - - auth->replied = TRUE; - - hci_close_dev(dd); -} - -static void create_bond_req_exit(void *user_data) -{ - struct adapter *adapter = user_data; - struct pending_auth_info *auth; - - debug("CreateConnection requestor exited before bonding was completed"); - - auth = adapter_find_auth_request(adapter, &adapter->bonding->bdaddr); - if (auth) { - cancel_auth_request(auth, adapter->dev_id); - if (auth->agent) - agent_cancel(auth->agent); - adapter_remove_auth_request(adapter, &adapter->bonding->bdaddr); - } - - remove_pending_device(adapter); - - g_io_channel_close(adapter->bonding->io); - if (adapter->bonding->io_id) - g_source_remove(adapter->bonding->io_id); - bonding_request_free(adapter->bonding); - adapter->bonding = NULL; -} - -static DBusMessage *create_bonding(DBusConnection *conn, DBusMessage *msg, - const char *address, const char *agent_path, - uint8_t capability, void *data) -{ - char filename[PATH_MAX + 1]; - char *str; - struct adapter *adapter = data; - struct bonding_request_info *bonding; - bdaddr_t bdaddr; - int sk; - - str2ba(address, &bdaddr); - - /* check if there is a pending discover: requested by D-Bus/non clients */ - if (adapter->discov_active) - return in_progress(msg, "Discover in progress"); - - pending_remote_name_cancel(adapter); - - if (adapter->bonding) - return in_progress(msg, "Bonding in progress"); - - if (adapter_find_auth_request(adapter, &bdaddr)) - return in_progress(msg, "Bonding in progress"); - - /* check if a link key already exists */ - create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, - "linkkeys"); - - str = textfile_caseget(filename, address); - if (str) { - free(str); - return g_dbus_create_error(msg, - ERROR_INTERFACE ".AlreadyExists", - "Bonding already exists"); - } - - sk = l2raw_connect(adapter->address, &bdaddr); - if (sk < 0) - return g_dbus_create_error(msg, - ERROR_INTERFACE ".ConnectionAttemptFailed", - "Connection attempt failed"); - - bonding = bonding_request_new(conn, msg, adapter, address, agent_path, - capability); - if (!bonding) { - close(sk); - return NULL; - } - - bonding->io = g_io_channel_unix_new(sk); - bonding->io_id = g_io_add_watch(bonding->io, - G_IO_OUT | G_IO_NVAL | G_IO_HUP | G_IO_ERR, - (GIOFunc) create_bonding_conn_complete, - adapter); - - bonding->listener_id = g_dbus_add_disconnect_watch(conn, - dbus_message_get_sender(msg), - create_bond_req_exit, adapter, - NULL); - - adapter->bonding = bonding; - - return NULL; -} - -static void periodic_discover_req_exit(void *user_data) -{ - struct adapter *adapter = user_data; - - debug("PeriodicDiscovery requestor exited"); - - /* Cleanup the discovered devices list and send the cmd to exit from - * periodic inquiry or cancel remote name request. The return value can - * be ignored. */ - - cancel_periodic_discovery(adapter); -} - -static DBusMessage *adapter_start_periodic(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - periodic_inquiry_cp cp; - struct hci_request rq; - struct adapter *adapter = data; - uint8_t lap[3] = { 0x33, 0x8b, 0x9e }; - uint8_t status; - int dd; - - if (!adapter->up) - return adapter_not_ready(msg); - - if (dbus_message_is_method_call(msg, ADAPTER_INTERFACE, - "StartPeriodicDiscovery")) { - if (!dbus_message_has_signature(msg, - DBUS_TYPE_INVALID_AS_STRING)) - return invalid_args(msg); - } - - if (adapter->discov_active || adapter->pdiscov_active) - return in_progress(msg, "Discover in progress"); - - pending_remote_name_cancel(adapter); - - dd = hci_open_dev(adapter->dev_id); - if (dd < 0) - return no_such_adapter(msg); - - memset(&cp, 0, sizeof(cp)); - memcpy(&cp.lap, lap, 3); - cp.max_period = htobs(24); - cp.min_period = htobs(16); - cp.length = 0x08; - cp.num_rsp = 0x00; - - memset(&rq, 0, sizeof(rq)); - rq.ogf = OGF_LINK_CTL; - rq.ocf = OCF_PERIODIC_INQUIRY; - rq.cparam = &cp; - rq.clen = PERIODIC_INQUIRY_CP_SIZE; - rq.rparam = &status; - rq.rlen = sizeof(status); - rq.event = EVT_CMD_COMPLETE; - - if (hci_send_req(dd, &rq, 1000) < 0) { - int err = errno; - error("Unable to start periodic inquiry: %s (%d)", - strerror(errno), errno); - hci_close_dev(dd); - return failed_strerror(msg, err); - } - - if (status) { - error("HCI_Periodic_Inquiry_Mode failed with status 0x%02x", - status); - hci_close_dev(dd); - return failed_strerror(msg, bt_error(status)); - } - - adapter->pdiscov_requestor = g_strdup(dbus_message_get_sender(msg)); - - if (adapter->pdiscov_resolve_names) - adapter->discov_type = PERIODIC_INQUIRY | RESOLVE_NAME; - else - adapter->discov_type = PERIODIC_INQUIRY; - - hci_close_dev(dd); - - /* track the request owner to cancel it automatically if the owner - * exits */ - adapter->pdiscov_listener = g_dbus_add_disconnect_watch(conn, - dbus_message_get_sender(msg), - periodic_discover_req_exit, - adapter, NULL); - - return dbus_message_new_method_return(msg); -} - -static DBusMessage *adapter_stop_periodic(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - int err; - - if (!adapter->up) - return adapter_not_ready(msg); - - if (!adapter->pdiscov_active) - return g_dbus_create_error(msg, - ERROR_INTERFACE ".NotAuthorized", - "Not authorized"); - /* - * Cleanup the discovered devices list and send the cmd to exit - * from periodic inquiry mode or cancel remote name request. - */ - err = cancel_periodic_discovery(adapter); - if (err < 0) { - if (err == -ENODEV) - return no_such_adapter(msg); - - else - return failed_strerror(msg, -err); - } - - return dbus_message_new_method_return(msg); -} - -static void discover_devices_req_exit(void *user_data) -{ - struct adapter *adapter = user_data; - - debug("DiscoverDevices requestor exited"); - - /* Cleanup the discovered devices list and send the command to cancel - * inquiry or cancel remote name request. The return can be ignored. */ - cancel_discovery(adapter); -} - -static DBusMessage *adapter_discover_devices(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - inquiry_cp cp; - evt_cmd_status rp; - struct hci_request rq; - struct adapter *adapter = data; - uint8_t lap[3] = { 0x33, 0x8b, 0x9e }; - int dd; - - if (!adapter->up) - return adapter_not_ready(msg); - - if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) - return invalid_args(msg); - - if (adapter->discov_active) - return in_progress(msg, "Discover in progress"); - - pending_remote_name_cancel(adapter); - - if (adapter->bonding) - return in_progress(msg, "Bonding in progress"); - - dd = hci_open_dev(adapter->dev_id); - if (dd < 0) - return no_such_adapter(msg); - - memset(&cp, 0, sizeof(cp)); - memcpy(&cp.lap, lap, 3); - cp.length = 0x08; - cp.num_rsp = 0x00; - - memset(&rq, 0, sizeof(rq)); - rq.ogf = OGF_LINK_CTL; - rq.ocf = OCF_INQUIRY; - rq.cparam = &cp; - rq.clen = INQUIRY_CP_SIZE; - rq.rparam = &rp; - rq.rlen = EVT_CMD_STATUS_SIZE; - rq.event = EVT_CMD_STATUS; - - if (hci_send_req(dd, &rq, 500) < 0) { - int err = errno; - error("Unable to start inquiry: %s (%d)", - strerror(errno), errno); - hci_close_dev(dd); - return failed_strerror(msg, err); - } - - if (rp.status) { - error("HCI_Inquiry command failed with status 0x%02x", - rp.status); - hci_close_dev(dd); - return failed_strerror(msg, bt_error(rp.status)); - } - - adapter->discov_type |= (STD_INQUIRY | RESOLVE_NAME); - - adapter->discov_requestor = g_strdup(dbus_message_get_sender(msg)); - - hci_close_dev(dd); - - /* track the request owner to cancel it automatically if the owner - * exits */ - adapter->discov_listener = g_dbus_add_disconnect_watch(conn, - dbus_message_get_sender(msg), - discover_devices_req_exit, - adapter, NULL); - - return dbus_message_new_method_return(msg); -} - -static DBusMessage *adapter_cancel_discovery(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - int err; - - if (!adapter->up) - return adapter_not_ready(msg); - - if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) - return invalid_args(msg); - - /* is there discover pending? or discovery cancel was requested - * previously */ - if (!adapter->discov_active || adapter->discovery_cancel) - return g_dbus_create_error(msg, - ERROR_INTERFACE ".NotAuthorized", - "Not Authorized"); - - /* only the discover requestor can cancel the inquiry process */ - if (!adapter->discov_requestor || - strcmp(adapter->discov_requestor, dbus_message_get_sender(msg))) - return g_dbus_create_error(msg, - ERROR_INTERFACE ".NotAuthorized", - "Not Authorized"); - - /* Cleanup the discovered devices list and send the cmd to cancel - * inquiry or cancel remote name request */ - err = cancel_discovery(adapter); - if (err < 0) { - if (err == -ENODEV) - return no_such_adapter(msg); - else - return failed_strerror(msg, -err); - } - - /* Reply before send DiscoveryCompleted */ - adapter->discovery_cancel = dbus_message_ref(msg); - - return NULL; -} - -struct remote_device_list_t { - GSList *list; - time_t time; -}; - -static DBusMessage *get_properties(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - const char *property; - DBusMessage *reply; - DBusMessageIter iter; - DBusMessageIter dict; - bdaddr_t ba; - char str[249]; - - if (check_address(adapter->address) < 0) - return adapter_not_ready(msg); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return NULL; - - dbus_message_iter_init_append(reply, &iter); - - dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, - DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING - DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING - DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); - - /* Address */ - property = adapter->address; - dbus_message_iter_append_dict_entry(&dict, "Address", - DBUS_TYPE_STRING, &property); - - /* Name */ - memset(str, 0, sizeof(str)); - property = str; - str2ba(adapter->address, &ba); - - if (!read_local_name(&ba, str)) - dbus_message_iter_append_dict_entry(&dict, "Name", - DBUS_TYPE_STRING, &property); - - /* Mode */ - property = mode2str(adapter->mode); - - dbus_message_iter_append_dict_entry(&dict, "Mode", - DBUS_TYPE_STRING, &property); - - /* DiscoverableTimeout */ - dbus_message_iter_append_dict_entry(&dict, "DiscoverableTimeout", - DBUS_TYPE_UINT32, &adapter->discov_timeout); - - /* PeriodicDiscovery */ - dbus_message_iter_append_dict_entry(&dict, "PeriodicDiscovery", - DBUS_TYPE_BOOLEAN, &adapter->pdiscov_active); - - dbus_message_iter_close_container(&iter, &dict); - - return reply; -} - -static DBusMessage *set_property(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - DBusMessageIter iter; - DBusMessageIter sub; - const char *property; - - if (!dbus_message_iter_init(msg, &iter)) - return invalid_args(msg); - - if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) - return invalid_args(msg); - - dbus_message_iter_get_basic(&iter, &property); - dbus_message_iter_next(&iter); - - if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) - return invalid_args(msg); - dbus_message_iter_recurse(&iter, &sub); - - if (g_str_equal("Name", property)) { - const char *name; - - if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) - return invalid_args(msg); - dbus_message_iter_get_basic(&sub, &name); - - return set_name(conn, msg, name, data); - } else if (g_str_equal("DiscoverableTimeout", property)) { - uint32_t timeout; - - if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT32) - return invalid_args(msg); - dbus_message_iter_get_basic(&sub, &timeout); - - return set_discoverable_timeout(conn, msg, timeout, data); - } else if (g_str_equal("PeriodicDiscovery", property)) { - dbus_bool_t value; - - if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN) - return invalid_args(msg); - dbus_message_iter_get_basic(&sub, &value); - - if (value) - return adapter_start_periodic(conn, msg, data); - else - return adapter_stop_periodic(conn, msg, data); - } else if (g_str_equal("Mode", property)) { - const char *mode; - - if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) - return invalid_args(msg); - - dbus_message_iter_get_basic(&sub, &mode); - - adapter->global_mode = str2mode(adapter->address, mode); - - if (adapter->global_mode == adapter->mode) - return dbus_message_new_method_return(msg); - - if (adapter->sessions && adapter->global_mode < adapter->mode) - return confirm_mode(conn, msg, mode, data); - - return set_mode(conn, msg, str2mode(adapter->address, mode), - data); - } - - return invalid_args(msg); -} - -static void session_exit(void *data) -{ - struct mode_req *req = data; - struct adapter *adapter = req->adapter; - - adapter->sessions = g_slist_remove(adapter->sessions, req); - - if (!adapter->sessions) { - debug("Falling back to '%s' mode", mode2str(adapter->global_mode)); - /* FIXME: fallback to previous mode - set_mode(req->conn, req->msg, adapter->global_mode, adapter); - */ - } - dbus_connection_unref(req->conn); - dbus_message_unref(req->msg); - g_free(req); -} - -static DBusMessage *request_mode(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - const char *mode; - struct adapter *adapter = data; - struct mode_req *req; - uint8_t new_mode; - int ret; - - if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &mode, - DBUS_TYPE_INVALID)) - return invalid_args(msg); - - new_mode = str2mode(adapter->address, mode); - if (new_mode != MODE_CONNECTABLE && new_mode != MODE_DISCOVERABLE) - return invalid_args(msg); - - if (!adapter->agent) - return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", - "No agent registered"); - - if (g_slist_find_custom(adapter->sessions, msg, - (GCompareFunc) find_session)) - return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", - "Mode already requested"); - - req = g_new0(struct mode_req, 1); - req->adapter = adapter; - req->conn = dbus_connection_ref(conn); - req->msg = dbus_message_ref(msg); - req->mode = new_mode; - req->id = g_dbus_add_disconnect_watch(conn, - dbus_message_get_sender(msg), - session_exit, req, NULL); - - if (!adapter->sessions) - adapter->global_mode = adapter->mode; - adapter->sessions = g_slist_append(adapter->sessions, req); - - /* No need to change mode */ - if (adapter->mode >= new_mode) - return dbus_message_new_method_return(msg); - - ret = agent_confirm_mode_change(adapter->agent, mode, confirm_mode_cb, - req); - if (ret < 0) { - dbus_message_unref(req->msg); - g_dbus_remove_watch(req->conn, req->id); - dbus_connection_unref(req->conn); - g_free(req); - return invalid_args(msg); - } - - return NULL; -} - -static DBusMessage *release_mode(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - GSList *l; - - l = g_slist_find_custom(adapter->sessions, msg, - (GCompareFunc) find_session); - if (!l) - return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", - "No Mode to release"); - - session_exit(l->data); - - return dbus_message_new_method_return(msg); -} - -static DBusMessage *list_devices(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - DBusMessage *reply; - GSList *l; - DBusMessageIter iter; - DBusMessageIter array_iter; - const gchar *dev_path; - - if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) - return invalid_args(msg); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return NULL; - - dbus_message_iter_init_append(reply, &iter); - dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, - DBUS_TYPE_OBJECT_PATH_AS_STRING, &array_iter); - - for (l = adapter->devices; l; l = l->next) { - struct btd_device *device = l->data; - - if (device_is_temporary(device)) - continue; - - dev_path = device_get_path(device); - - dbus_message_iter_append_basic(&array_iter, - DBUS_TYPE_OBJECT_PATH, &dev_path); - } - - dbus_message_iter_close_container(&iter, &array_iter); - - return reply; -} - -static DBusMessage *create_device(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - struct btd_device *device; - const gchar *address; - - if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address, - DBUS_TYPE_INVALID) == FALSE) - return invalid_args(msg); - - if (check_address(address) < 0) - return invalid_args(msg); - - if (adapter_find_device(adapter, address)) - return g_dbus_create_error(msg, - ERROR_INTERFACE ".AlreadyExists", - "Device already exists"); - - debug("create_device(%s)", address); - - device = device_create(conn, adapter, address); - if (!device) - return NULL; - - device_set_temporary(device, FALSE); - - device_browse(device, conn, msg, NULL); - - adapter->devices = g_slist_append(adapter->devices, device); - - return NULL; -} - -static uint8_t parse_io_capability(const char *capability) -{ - if (g_str_equal(capability, "")) - return IO_CAPABILITY_DISPLAYYESNO; - if (g_str_equal(capability, "DisplayOnly")) - return IO_CAPABILITY_DISPLAYONLY; - if (g_str_equal(capability, "DisplayYesNo")) - return IO_CAPABILITY_DISPLAYYESNO; - if (g_str_equal(capability, "KeyboardOnly")) - return IO_CAPABILITY_KEYBOARDONLY; - if (g_str_equal(capability, "NoInputOutput")) - return IO_CAPABILITY_NOINPUTOUTPUT; - return IO_CAPABILITY_INVALID; -} - -static DBusMessage *create_paired_device(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - const gchar *address, *agent_path, *capability; - uint8_t cap; - - if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address, - DBUS_TYPE_OBJECT_PATH, &agent_path, - DBUS_TYPE_STRING, &capability, - DBUS_TYPE_INVALID) == FALSE) - return invalid_args(msg); - - if (check_address(address) < 0) - return invalid_args(msg); - - cap = parse_io_capability(capability); - if (cap == IO_CAPABILITY_INVALID) - return invalid_args(msg); - - return create_bonding(conn, msg, address, agent_path, cap, data); -} - -static gint device_path_cmp(struct btd_device *device, const gchar *path) -{ - const gchar *dev_path = device_get_path(device); - - return strcasecmp(dev_path, path); -} - -static DBusMessage *remove_device(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - struct btd_device *device; - const char *path; - GSList *l; - - if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID) == FALSE) - return invalid_args(msg); - - l = g_slist_find_custom(adapter->devices, - path, (GCompareFunc) device_path_cmp); - if (!l) - return g_dbus_create_error(msg, - ERROR_INTERFACE ".DoesNotExist", - "Device does not exist"); - device = l->data; - - if (device_is_temporary(device) || device_is_busy(device)) - return g_dbus_create_error(msg, - ERROR_INTERFACE ".DoesNotExist", - "Device creation in progress"); - - adapter_remove_device(conn, adapter, device); - - return dbus_message_new_method_return(msg); -} - -static DBusMessage *find_device(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - struct btd_device *device; - DBusMessage *reply; - const gchar *address; - GSList *l; - const gchar *dev_path; - - if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address, - DBUS_TYPE_INVALID)) - return invalid_args(msg); - - l = g_slist_find_custom(adapter->devices, - address, (GCompareFunc) device_address_cmp); - if (!l) - return g_dbus_create_error(msg, - ERROR_INTERFACE ".DoesNotExist", - "Device does not exist"); - - device = l->data; - - if (device_is_temporary(device)) - return g_dbus_create_error(msg, - ERROR_INTERFACE ".DoesNotExist", - "Device creation in progress"); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return NULL; - - dev_path = device_get_path(device); - - dbus_message_append_args(reply, - DBUS_TYPE_OBJECT_PATH, &dev_path, - DBUS_TYPE_INVALID); - - return reply; -} - -static void agent_removed(struct agent *agent, struct adapter *adapter) -{ - struct pending_auth_info *auth; - GSList *l; - - adapter->agent = NULL; - - l = g_slist_find_custom(adapter->auth_reqs, agent, - auth_info_agent_cmp); - if (!l) - return; - - auth = l->data; - auth->agent = NULL; -} - -static DBusMessage *register_agent(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - const char *path, *name, *capability; - struct agent *agent; - struct 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", - "Agent already exists"); - - cap = parse_io_capability(capability); - if (cap == IO_CAPABILITY_INVALID) - return invalid_args(msg); - - name = dbus_message_get_sender(msg); - - agent = agent_create(adapter, name, path, cap, - (agent_remove_cb) agent_removed, adapter); - if (!agent) - return g_dbus_create_error(msg, - ERROR_INTERFACE ".Failed", - "Failed to create a new agent"); - - adapter->agent = agent; - - debug("Agent registered for hci%d at %s:%s", adapter->dev_id, name, - path); - - return dbus_message_new_method_return(msg); -} - -static DBusMessage *unregister_agent(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - const char *path, *name; - struct adapter *adapter = data; - - if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) - return NULL; - - name = dbus_message_get_sender(msg); - - if (!adapter->agent || !agent_matches(adapter->agent, name, path)) - return g_dbus_create_error(msg, - ERROR_INTERFACE ".DoesNotExist", - "No such agent"); - - agent_destroy(adapter->agent, FALSE); - adapter->agent = NULL; - - return dbus_message_new_method_return(msg); -} - -static DBusMessage *add_service_record(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - DBusMessage *reply; - const char *sender, *record; - dbus_uint32_t handle; - bdaddr_t src; - int err; - - if (dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &record, DBUS_TYPE_INVALID) == FALSE) - return NULL; - - sender = dbus_message_get_sender(msg); - str2ba(adapter->address, &src); - err = add_xml_record(conn, sender, &src, record, &handle); - if (err < 0) - return failed_strerror(msg, err); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return NULL; - - dbus_message_append_args(reply, DBUS_TYPE_UINT32, &handle, - DBUS_TYPE_INVALID); - - return reply; -} - -static DBusMessage *update_service_record(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - bdaddr_t src; - - str2ba(adapter->address, &src); - - return update_xml_record(conn, msg, &src); -} - -static DBusMessage *remove_service_record(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - dbus_uint32_t handle; - const char *sender; - - if (dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &handle, - DBUS_TYPE_INVALID) == FALSE) - return NULL; - - sender = dbus_message_get_sender(msg); - - if (remove_record(conn, sender, handle) < 0) - return not_available(msg); - - return dbus_message_new_method_return(msg); -} - -static DBusMessage *request_authorization(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - /* FIXME implement the request */ - - return NULL; -} - -static DBusMessage *cancel_authorization(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - /* FIXME implement cancel request */ - - return dbus_message_new_method_return(msg); -} - -/* BlueZ 4.0 API */ -static GDBusMethodTable adapter_methods[] = { - { "GetProperties", "", "a{sv}",get_properties }, - { "SetProperty", "sv", "", set_property, - G_DBUS_METHOD_FLAG_ASYNC}, - { "RequestMode", "s", "", request_mode, - G_DBUS_METHOD_FLAG_ASYNC}, - { "ReleaseMode", "", "", release_mode }, - { "DiscoverDevices", "", "", adapter_discover_devices}, - { "CancelDiscovery", "", "", adapter_cancel_discovery, - G_DBUS_METHOD_FLAG_ASYNC}, - { "ListDevices", "", "ao", list_devices }, - { "CreateDevice", "s", "o", create_device, - G_DBUS_METHOD_FLAG_ASYNC}, - { "CreatePairedDevice", "sos", "o", create_paired_device, - G_DBUS_METHOD_FLAG_ASYNC}, - { "RemoveDevice", "o", "", remove_device }, - { "FindDevice", "s", "o", find_device }, - { "RegisterAgent", "os", "", register_agent }, - { "UnregisterAgent", "o", "", unregister_agent }, - { "AddServiceRecord", "s", "u", add_service_record }, - { "UpdateServiceRecord","us", "", update_service_record }, - { "RemoveServiceRecord","u", "", remove_service_record }, - { "RequestAuthorization","su", "", request_authorization, - G_DBUS_METHOD_FLAG_ASYNC}, - { "CancelAuthorization","", "", cancel_authorization }, - { } -}; - -static GDBusSignalTable adapter_signals[] = { - { "DiscoveryStarted", "" }, - { "DiscoveryCompleted", "" }, - { "DeviceCreated", "o" }, - { "DeviceRemoved", "o" }, - { "DeviceFound", "sa{sv}" }, - { "PropertyChanged", "sv" }, - { "DeviceDisappeared", "s" }, - { } -}; - -dbus_bool_t adapter_init(DBusConnection *conn, - const char *path, struct adapter *adapter) -{ - if (!connection) - connection = conn; - - return g_dbus_register_interface(conn, path, - ADAPTER_INTERFACE, adapter_methods, - adapter_signals, NULL, adapter, NULL); -} - -dbus_bool_t adapter_cleanup(DBusConnection *conn, const char *path) -{ - return g_dbus_unregister_interface(conn, path, ADAPTER_INTERFACE); -} - -static inline uint8_t get_inquiry_mode(struct hci_dev *dev) -{ - if (dev->features[6] & LMP_EXT_INQ) - return 2; - - if (dev->features[3] & LMP_RSSI_INQ) - return 1; - - if (dev->manufacturer == 11 && - dev->hci_rev == 0x00 && dev->lmp_subver == 0x0757) - return 1; - - if (dev->manufacturer == 15) { - if (dev->hci_rev == 0x03 && dev->lmp_subver == 0x6963) - return 1; - if (dev->hci_rev == 0x09 && dev->lmp_subver == 0x6963) - return 1; - if (dev->hci_rev == 0x00 && dev->lmp_subver == 0x6965) - return 1; - } - - if (dev->manufacturer == 31 && - dev->hci_rev == 0x2005 && dev->lmp_subver == 0x1805) - return 1; - - return 0; -} - -static int device_read_bdaddr(uint16_t dev_id, const char *address) -{ - int dd, err; - bdaddr_t bdaddr; - - dd = hci_open_dev(dev_id); - if (dd < 0) { - err = errno; - error("Can't open device hci%d: %s (%d)", - dev_id, strerror(err), err); - return -err; - } - - str2ba(address, &bdaddr); - if (hci_read_bd_addr(dd, &bdaddr, 2000) < 0) { - err = errno; - error("Can't read address for hci%d: %s (%d)", - dev_id, strerror(err), err); - hci_close_dev(dd); - return -err; - } - - hci_close_dev(dd); - - return 0; -} - -static int adapter_setup(struct adapter *adapter, int dd) -{ - struct hci_dev *dev = &adapter->dev; - uint8_t events[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00 }; - uint8_t inqmode; - bdaddr_t bdaddr; - int err; - char name[249]; - - if (dev->hci_rev > 1) { - if (dev->features[5] & LMP_SNIFF_SUBR) - events[5] |= 0x20; - - if (dev->features[5] & LMP_PAUSE_ENC) - events[5] |= 0x80; - - if (dev->features[6] & LMP_EXT_INQ) - events[5] |= 0x40; - - if (dev->features[6] & LMP_NFLUSH_PKTS) - events[7] |= 0x01; - - if (dev->features[7] & LMP_LSTO) - events[6] |= 0x80; - - if (dev->features[6] & LMP_SIMPLE_PAIR) { - events[6] |= 0x01; /* IO Capability Request */ - events[6] |= 0x02; /* IO Capability Response */ - events[6] |= 0x04; /* User Confirmation Request */ - events[6] |= 0x08; /* User Passkey Request */ - events[6] |= 0x10; /* Remote OOB Data Request */ - events[6] |= 0x20; /* Simple Pairing Complete */ - events[7] |= 0x04; /* User Passkey Notification */ - events[7] |= 0x08; /* Keypress Notification */ - events[7] |= 0x10; /* Remote Host Supported Features Notification */ - } - - hci_send_cmd(dd, OGF_HOST_CTL, OCF_SET_EVENT_MASK, - sizeof(events), events); - } - - str2ba(adapter->address, &bdaddr); - if (read_local_name(&bdaddr, name) == 0) { - memcpy(dev->name, name, 248); - hci_write_local_name(dd, name, 5000); - } - - update_ext_inquiry_response(dd, dev); - - inqmode = get_inquiry_mode(dev); - if (inqmode < 1) - return 0; - - if (hci_write_inquiry_mode(dd, inqmode, 2000) < 0) { - err = errno; - error("Can't write inquiry mode for %s: %s (%d)", - adapter->path, strerror(err), err); - hci_close_dev(dd); - return -err; - } - - return 0; -} - -static int active_conn_append(GSList **list, bdaddr_t *bdaddr, - uint16_t handle) -{ - struct active_conn_info *dev; - - dev = g_new0(struct active_conn_info, 1); - - bacpy(&dev->bdaddr, bdaddr); - dev->handle = handle; - - *list = g_slist_append(*list, dev); - return 0; -} - -static void create_stored_records_from_keys(char *key, char *value, - void *user_data) -{ - struct record_list *rec_list = user_data; - const gchar *addr = rec_list->addr; - sdp_record_t *rec; - int size, i, len; - uint8_t *pdata; - char tmp[3] = ""; - - if (strstr(key, addr) == NULL) - return; - - size = strlen(value)/2; - pdata = g_malloc0(size); - - for (i = 0; i < size; i++) { - memcpy(tmp, value + (i*2), 2); - pdata[i] = (uint8_t) strtol(tmp, NULL, 16); - } - - rec = sdp_extract_pdu(pdata, &len); - free(pdata); - - rec_list->recs = sdp_list_append(rec_list->recs, rec); -} - -static void create_stored_device_from_profiles(char *key, char *value, - void *user_data) -{ - char filename[PATH_MAX + 1]; - struct adapter *adapter = user_data; - GSList *uuids = bt_string2list(value); - struct btd_device *device; - const gchar *src; - struct record_list rec_list; - - if (g_slist_find_custom(adapter->devices, - key, (GCompareFunc) device_address_cmp)) - return; - - device = device_create(connection, adapter, key); - if (!device) - return; - - device_set_temporary(device, FALSE); - adapter->devices = g_slist_append(adapter->devices, device); - - src = adapter->address; - rec_list.addr = device_get_address(device); - rec_list.recs = NULL; - - create_name(filename, PATH_MAX, STORAGEDIR, src, "sdp"); - textfile_foreach(filename, create_stored_records_from_keys, &rec_list); - - device_probe_drivers(device, uuids, rec_list.recs); - - if (rec_list.recs != NULL) - sdp_list_free(rec_list.recs, (sdp_free_func_t) sdp_record_free); - - g_slist_free(uuids); -} - -static void create_stored_device_from_linkkeys(char *key, char *value, - void *user_data) -{ - struct adapter *adapter = user_data; - struct btd_device *device; - - if (g_slist_find_custom(adapter->devices, - key, (GCompareFunc) device_address_cmp)) - return; - - device = device_create(connection, adapter, key); - if (device) { - device_set_temporary(device, FALSE); - adapter->devices = g_slist_append(adapter->devices, device); - } -} - -static void load_devices(struct adapter *adapter) -{ - char filename[PATH_MAX + 1]; - - create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "profiles"); - textfile_foreach(filename, create_stored_device_from_profiles, adapter); - - create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "linkkeys"); - textfile_foreach(filename, create_stored_device_from_linkkeys, adapter); -} - - -static void adapter_up(struct adapter *adapter, int dd) -{ - struct hci_conn_list_req *cl = NULL; - struct hci_conn_info *ci; - const char *mode; - int i; - - adapter->up = 1; - adapter->discov_timeout = get_discoverable_timeout(adapter->dev_id); - adapter->discov_type = DISCOVER_TYPE_NONE; - - adapter->scan_mode = get_startup_scan(adapter->dev_id); - hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE, - 1, &adapter->scan_mode); - - adapter->mode = get_startup_mode(adapter->dev_id); - if (adapter->mode == MODE_LIMITED) - set_limited_discoverable(dd, adapter->dev.class, TRUE); - - /* - * retrieve the active connections: address the scenario where - * the are active connections before the daemon've started - */ - - cl = g_malloc0(10 * sizeof(*ci) + sizeof(*cl)); - - cl->dev_id = adapter->dev_id; - cl->conn_num = 10; - ci = cl->conn_info; - - if (ioctl(dd, HCIGETCONNLIST, cl) == 0) { - for (i = 0; i < cl->conn_num; i++, ci++) - active_conn_append(&adapter->active_conn, - &ci->bdaddr, ci->handle); - } - g_free(cl); - - mode = mode2str(adapter->mode); - - dbus_connection_emit_property_changed(connection, adapter->path, - ADAPTER_INTERFACE, "Mode", - DBUS_TYPE_STRING, &mode); - - load_devices(adapter); -} - -int adapter_start(struct adapter *adapter) -{ - struct hci_dev *dev = &adapter->dev; - struct hci_dev_info di; - struct hci_version ver; - uint8_t features[8]; - int dd, err; - char name[249]; - - if (hci_devinfo(adapter->dev_id, &di) < 0) - return -errno; - - if (hci_test_bit(HCI_RAW, &di.flags)) { - dev->ignore = 1; - return -1; - } - - if (bacmp(&di.bdaddr, BDADDR_ANY)) - ba2str(&di.bdaddr, adapter->address); - else { - int err = device_read_bdaddr(adapter->dev_id, adapter->address); - if (err < 0) - return err; - } - memcpy(dev->features, di.features, 8); - - dd = hci_open_dev(adapter->dev_id); - if (dd < 0) { - err = errno; - error("Can't open adapter %s: %s (%d)", - adapter->path, strerror(err), err); - return -err; - } - - if (hci_read_local_version(dd, &ver, 1000) < 0) { - err = errno; - error("Can't read version info for %s: %s (%d)", - adapter->path, strerror(err), err); - hci_close_dev(dd); - return -err; - } - - dev->hci_rev = ver.hci_rev; - dev->lmp_ver = ver.lmp_ver; - dev->lmp_subver = ver.lmp_subver; - dev->manufacturer = ver.manufacturer; - - if (hci_read_local_features(dd, features, 1000) < 0) { - err = errno; - error("Can't read features for %s: %s (%d)", - adapter->path, strerror(err), err); - hci_close_dev(dd); - return -err; - } - - memcpy(dev->features, features, 8); - - if (hci_read_class_of_dev(dd, dev->class, 1000) < 0) { - err = errno; - error("Can't read class of adapter on %s: %s (%d)", - adapter->path, strerror(err), err); - hci_close_dev(dd); - return -err; - } - - if (hci_read_local_name(dd, sizeof(name), name, 2000) < 0) { - err = errno; - error("Can't read local name on %s: %s (%d)", - adapter->path, strerror(err), err); - hci_close_dev(dd); - return -err; - } - - memcpy(dev->name, name, 248); - - if (!(features[6] & LMP_SIMPLE_PAIR)) - goto setup; - - if (hcid_dbus_use_experimental()) { - if (ioctl(dd, HCIGETAUTHINFO, NULL) < 0 && errno != EINVAL) - hci_write_simple_pairing_mode(dd, 0x01, 2000); - } - - if (hci_read_simple_pairing_mode(dd, &dev->ssp_mode, 1000) < 0) { - err = errno; - error("Can't read simple pairing mode on %s: %s (%d)", - adapter->path, strerror(err), err); - hci_close_dev(dd); - return -err; - } - -setup: - if (hci_test_bit(HCI_INQUIRY, &di.flags)) - adapter->discov_active = 1; - else - adapter->discov_active = 0; - - adapter_setup(adapter, dd); - adapter_up(adapter, dd); - - hci_close_dev(dd); - - info("Adapter %s has been enabled", adapter->path); - - return 0; -} - -static void reply_pending_requests(struct adapter *adapter) -{ - DBusMessage *reply; - - if (!adapter) - return; - - /* pending bonding */ - if (adapter->bonding) { - reply = new_authentication_return(adapter->bonding->msg, - HCI_OE_USER_ENDED_CONNECTION); - g_dbus_send_message(connection, reply); - remove_pending_device(adapter); - - g_dbus_remove_watch(adapter->bonding->conn, - adapter->bonding->listener_id); - - if (adapter->bonding->io_id) - g_source_remove(adapter->bonding->io_id); - g_io_channel_close(adapter->bonding->io); - bonding_request_free(adapter->bonding); - adapter->bonding = NULL; - } - - /* If there is a pending reply for discovery cancel */ - if (adapter->discovery_cancel) { - reply = dbus_message_new_method_return(adapter->discovery_cancel); - dbus_connection_send(connection, reply, NULL); - dbus_message_unref(reply); - dbus_message_unref(adapter->discovery_cancel); - adapter->discovery_cancel = NULL; - } - - if (adapter->discov_active) { - /* Send discovery completed signal if there isn't name - * to resolve */ - g_dbus_emit_signal(connection, adapter->path, - ADAPTER_INTERFACE, "DiscoveryCompleted", - DBUS_TYPE_INVALID); - - /* Cancel inquiry initiated by D-Bus client */ - if (adapter->discov_requestor) - cancel_discovery(adapter); - } - - if (adapter->pdiscov_active) { - /* Stop periodic inquiry initiated by D-Bus client */ - if (adapter->pdiscov_requestor) - cancel_periodic_discovery(adapter); - } -} - - -int adapter_stop(struct adapter *adapter) -{ - const char *mode = "off"; - - /* cancel pending timeout */ - if (adapter->discov_timeout_id) { - g_source_remove(adapter->discov_timeout_id); - adapter->discov_timeout_id = 0; - } - - /* check pending requests */ - reply_pending_requests(adapter); - - if (adapter->discov_requestor) { - g_dbus_remove_watch(connection, adapter->discov_listener); - adapter->discov_listener = 0; - g_free(adapter->discov_requestor); - adapter->discov_requestor = NULL; - } - - if (adapter->pdiscov_requestor) { - g_dbus_remove_watch(connection, adapter->pdiscov_listener); - adapter->pdiscov_listener = 0; - g_free(adapter->pdiscov_requestor); - adapter->pdiscov_requestor = NULL; - } - - if (adapter->found_devices) { - g_slist_foreach(adapter->found_devices, (GFunc) g_free, NULL); - g_slist_free(adapter->found_devices); - adapter->found_devices = NULL; - } - - if (adapter->oor_devices) { - g_slist_foreach(adapter->oor_devices, (GFunc) free, NULL); - g_slist_free(adapter->oor_devices); - adapter->oor_devices = NULL; - } - - if (adapter->auth_reqs) { - g_slist_foreach(adapter->auth_reqs, (GFunc) g_free, NULL); - g_slist_free(adapter->auth_reqs); - adapter->auth_reqs = NULL; - } - - if (adapter->active_conn) { - g_slist_foreach(adapter->active_conn, (GFunc) g_free, NULL); - g_slist_free(adapter->active_conn); - adapter->active_conn = NULL; - } - - dbus_connection_emit_property_changed(connection, adapter->path, - ADAPTER_INTERFACE, "Mode", - DBUS_TYPE_STRING, &mode); - - adapter->up = 0; - adapter->scan_mode = SCAN_DISABLED; - adapter->mode = MODE_OFF; - adapter->discov_active = 0; - adapter->pdiscov_active = 0; - adapter->pinq_idle = 0; - adapter->discov_type = DISCOVER_TYPE_NONE; - - info("Adapter %s has been disabled", adapter->path); - - return 0; -} - -int adapter_update(struct adapter *adapter) -{ - struct hci_dev *dev = &adapter->dev; - int dd; - - if (dev->ignore) - return 0; - - dd = hci_open_dev(adapter->dev_id); - if (dd < 0) { - int err = errno; - error("Can't open adapter %s: %s (%d)", - adapter->path, strerror(err), err); - return -err; - } - - update_ext_inquiry_response(dd, dev); - - hci_close_dev(dd); - - return 0; -} - -int adapter_get_class(struct adapter *adapter, uint8_t *cls) -{ - struct hci_dev *dev = &adapter->dev; - - memcpy(cls, dev->class, 3); - - return 0; -} - -int adapter_set_class(struct adapter *adapter, uint8_t *cls) -{ - struct hci_dev *dev = &adapter->dev; - - memcpy(dev->class, cls, 3); - - return 0; -} - -int adapter_update_ssp_mode(struct adapter *adapter, int dd, uint8_t mode) -{ - struct hci_dev *dev = &adapter->dev; - - dev->ssp_mode = mode; - - update_ext_inquiry_response(dd, dev); - - hci_close_dev(dd); - - return 0; -} - -struct adapter *adapter_create(int id) -{ - char path[MAX_PATH_LENGTH]; - struct adapter *adapter; - - snprintf(path, sizeof(path), "/hci%d", id); - - adapter = g_try_new0(struct adapter, 1); - if (!adapter) { - error("Failed to alloc memory to D-Bus path register data (%s)", - path); - return NULL; - } - - adapter->dev_id = id; - adapter->pdiscov_resolve_names = 1; - adapter->path = g_strdup(path); - - return adapter; -} - -uint16_t adapter_get_dev_id(struct adapter *adapter) -{ - return adapter->dev_id; -} - -const gchar *adapter_get_path(struct adapter *adapter) -{ - if (!adapter) - return NULL; - - return adapter->path; -} - -const gchar *adapter_get_address(struct adapter *adapter) -{ - if (!adapter) - return NULL; - - return adapter->address; -} - -void adapter_free(struct adapter *adapter) -{ - if (!adapter) - return; - - g_free(adapter->path); - g_free(adapter); - - return; -} -gboolean discov_timeout_handler(void *data) -{ - struct adapter *adapter = data; - struct hci_request rq; - int dd; - uint8_t scan_enable = adapter->scan_mode; - uint8_t status = 0; - gboolean retval = TRUE; - uint16_t dev_id = adapter->dev_id; - - scan_enable &= ~SCAN_INQUIRY; - - dd = hci_open_dev(dev_id); - if (dd < 0) { - error("HCI device open failed: hci%d", dev_id); - return TRUE; - } - - memset(&rq, 0, sizeof(rq)); - rq.ogf = OGF_HOST_CTL; - rq.ocf = OCF_WRITE_SCAN_ENABLE; - rq.cparam = &scan_enable; - rq.clen = sizeof(scan_enable); - rq.rparam = &status; - rq.rlen = sizeof(status); - rq.event = EVT_CMD_COMPLETE; - - if (hci_send_req(dd, &rq, 1000) < 0) { - error("Sending write scan enable command to hci%d failed: %s (%d)", - dev_id, strerror(errno), errno); - goto failed; - } - if (status) { - error("Setting scan enable failed with status 0x%02x", status); - goto failed; - } - - set_limited_discoverable(dd, adapter->dev.class, FALSE); - - adapter_remove_discov_timeout(adapter); - retval = FALSE; - -failed: - if (dd >= 0) - hci_close_dev(dd); - - return retval; -} - -void adapter_set_discov_timeout(struct adapter *adapter, guint interval) -{ - if (!adapter) - return; - - if (adapter->discov_timeout_id) { - error("Timeout already added for adapter %s", adapter->path); - return; - } - - adapter->discov_timeout_id = g_timeout_add(interval, discov_timeout_handler, adapter); -} - -void adapter_remove_discov_timeout(struct adapter *adapter) -{ - if (!adapter) - return; - - if(adapter->discov_timeout_id == 0) - return; - - g_source_remove(adapter->discov_timeout_id); - adapter->discov_timeout_id = 0; -} - -void adapter_set_scan_mode(struct adapter *adapter, uint8_t scan_mode) -{ - if (!adapter) - return; - - adapter->scan_mode = scan_mode; -} - -uint8_t adapter_get_scan_mode(struct adapter *adapter) -{ - return adapter->scan_mode; -} |