From 3b320a0355706a98f824f4d0abf2d14f820bbd81 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 15 Aug 2007 22:32:33 +0000 Subject: Rename files for adapter interface --- hcid/Makefile.am | 4 +- hcid/adapter.c | 3367 +++++++++++++++++++++++++++++++++++++++++++++++++ hcid/adapter.h | 124 ++ hcid/dbus-adapter.c | 3368 -------------------------------------------------- hcid/dbus-adapter.h | 129 -- hcid/dbus-common.c | 4 +- hcid/dbus-common.h | 5 - hcid/dbus-database.c | 1 + hcid/dbus-device.c | 29 - hcid/dbus-device.h | 22 - hcid/dbus-error.h | 5 - hcid/dbus-hci.c | 6 +- hcid/dbus-hci.h | 8 - hcid/dbus-sdp.c | 2 +- hcid/dbus-sdp.h | 6 - hcid/dbus-security.c | 3 +- hcid/dbus-security.h | 8 - hcid/dbus-service.c | 1 + hcid/dbus-service.h | 5 - hcid/dbus-test.c | 2 +- hcid/dbus-test.h | 5 - hcid/main.c | 1 + hcid/manager.c | 5 +- hcid/security.c | 1 + 24 files changed, 3509 insertions(+), 3602 deletions(-) create mode 100644 hcid/adapter.c create mode 100644 hcid/adapter.h delete mode 100644 hcid/dbus-adapter.c delete mode 100644 hcid/dbus-adapter.h delete mode 100644 hcid/dbus-device.c delete mode 100644 hcid/dbus-device.h diff --git a/hcid/Makefile.am b/hcid/Makefile.am index 77593c36..399a2e87 100644 --- a/hcid/Makefile.am +++ b/hcid/Makefile.am @@ -15,10 +15,10 @@ noinst_LIBRARIES = libhciserver.a libhciserver_a_SOURCES = hcid.h security.c device.c \ storage.c parser.h parser.y lexer.l kword.c kword.h \ - manager.h manager.c server.h server.c \ + server.h server.c manager.h manager.c \ + adapter.h adapter.c \ dbus-common.c dbus-common.h dbus-error.c dbus-error.h \ dbus-database.c dbus-database.h dbus-security.c dbus-security.h \ - dbus-adapter.c dbus-adapter.h dbus-device.c dbus-device.h \ dbus-service.c dbus-service.h dbus-test.c dbus-test.h \ dbus-hci.h dbus-hci.c dbus-sdp.c dbus-sdp.h diff --git a/hcid/adapter.c b/hcid/adapter.c new file mode 100644 index 00000000..17e63f99 --- /dev/null +++ b/hcid/adapter.c @@ -0,0 +1,3367 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2004-2007 Marcel Holtmann + * + * + * 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 +#endif + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include "hcid.h" +#include "dbus.h" + +#include "textfile.h" +#include "oui.h" +#include "adapter.h" +#include "dbus-common.h" +#include "dbus-helper.h" +#include "dbus-hci.h" +#include "dbus-sdp.h" +#include "dbus-error.h" + +#define NUM_ELEMENTS(table) (sizeof(table)/sizeof(const char *)) + +static const char *service_cls[] = { + "positioning", + "networking", + "rendering", + "capturing", + "object transfer", + "audio", + "telephony", + "information" +}; + +static const char *major_cls[] = { + "miscellaneous", + "computer", + "phone", + "access point", + "audio/video", + "peripheral", + "imaging", + "wearable", + "toy", + "uncategorized" +}; + +static const char *computer_minor_cls[] = { + "uncategorized", + "desktop", + "server", + "laptop", + "handheld", + "palm", + "wearable" +}; + +static const char *phone_minor_cls[] = { + "uncategorized", + "cellular", + "cordless", + "smart phone", + "modem", + "isdn" +}; + +static const char *access_point_minor_cls[] = { + "fully", + "1-17 percent", + "17-33 percent", + "33-50 percent", + "50-67 percent", + "67-83 percent", + "83-99 percent", + "not available" +}; + +static const char *audio_video_minor_cls[] = { + "uncategorized", + "headset", + "handsfree", + "unknown", + "microphone", + "loudspeaker", + "headphones", + "portable audio", + "car audio", + "set-top box", + "hifi audio", + "vcr", + "video camera", + "camcorder", + "video monitor", + "video display and loudspeaker", + "video conferencing", + "unknown", + "gaming/toy" +}; + +static const char *peripheral_minor_cls[] = { + "uncategorized", + "keyboard", + "pointing", + "combo" +}; + +#if 0 +static const char *peripheral_2_minor_cls[] = { + "uncategorized", + "joystick", + "gamepad", + "remote control", + "sensing", + "digitizer tablet", + "card reader" +}; +#endif + +static const char *imaging_minor_cls[] = { + "display", + "camera", + "scanner", + "printer" +}; + +static const char *wearable_minor_cls[] = { + "wrist watch", + "pager", + "jacket", + "helmet", + "glasses" +}; + +static const char *toy_minor_cls[] = { + "robot", + "vehicle", + "doll", + "controller", + "game" +}; + +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 struct bonding_request_info *bonding_request_new(bdaddr_t *peer, + DBusConnection *conn, + DBusMessage *msg) +{ + struct bonding_request_info *bonding; + + bonding = g_new0(struct bonding_request_info, 1); + + bacpy(&bonding->bdaddr, peer); + + bonding->conn = dbus_connection_ref(conn); + bonding->rq = dbus_message_ref(msg); + + 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"; + } +} + +uint8_t str2mode(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 + return MODE_UNKNOWN; +} + +static DBusHandlerResult adapter_get_info(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct adapter *adapter = data; + const char *property = adapter->address; + DBusMessage *reply; + DBusMessageIter iter; + DBusMessageIter dict; + bdaddr_t ba; + char str[249]; + uint8_t cls[3]; + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + 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); + + dbus_message_iter_append_dict_entry(&dict, "address", + DBUS_TYPE_STRING, &property); + + 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); + + get_device_version(adapter->dev_id, str, sizeof(str)); + dbus_message_iter_append_dict_entry(&dict, "version", + DBUS_TYPE_STRING, &property); + + get_device_revision(adapter->dev_id, str, sizeof(str)); + dbus_message_iter_append_dict_entry(&dict, "revision", + DBUS_TYPE_STRING, &property); + + get_device_manufacturer(adapter->dev_id, str, sizeof(str)); + dbus_message_iter_append_dict_entry(&dict, "manufacturer", + DBUS_TYPE_STRING, &property); + + get_device_company(adapter->dev_id, str, sizeof(str)); + dbus_message_iter_append_dict_entry(&dict, "company", + DBUS_TYPE_STRING, &property); + + property = mode2str(adapter->mode); + + dbus_message_iter_append_dict_entry(&dict, "mode", + DBUS_TYPE_STRING, &property); + + dbus_message_iter_append_dict_entry(&dict, "discoverable_timeout", + DBUS_TYPE_UINT32, &adapter->discov_timeout); + + if (!read_local_class(&ba, cls)) { + uint32_t class; + + memcpy(&class, cls, 3); + dbus_message_iter_append_dict_entry(&dict, "class", + DBUS_TYPE_UINT32, &class); + + property = major_class_str(class); + dbus_message_iter_append_dict_entry(&dict, "major_class", + DBUS_TYPE_STRING, &property); + + property = minor_class_str(class); + dbus_message_iter_append_dict_entry(&dict, "minor_class", + DBUS_TYPE_STRING, &property); + } + + dbus_message_iter_close_container(&iter, &dict); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_get_address(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct adapter *adapter = data; + const char *paddr = adapter->address; + DBusMessage *reply; + + if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) + return error_invalid_arguments(conn, msg); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, DBUS_TYPE_STRING, &paddr, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_get_version(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct adapter *adapter = data; + DBusMessage *reply; + char str[20], *str_ptr = str; + int err; + + if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) + return error_invalid_arguments(conn, msg); + + err = get_device_version(adapter->dev_id, str, sizeof(str)); + if (err < 0) + return error_failed(conn, msg, -err); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_get_revision(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct adapter *adapter = data; + DBusMessage *reply; + char str[64], *str_ptr = str; + int err; + + if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) + return error_invalid_arguments(conn, msg); + + err = get_device_revision(adapter->dev_id, str, sizeof(str)); + if (err < 0) + return error_failed(conn, msg, -err); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_get_manufacturer(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct adapter *adapter = data; + DBusMessage *reply; + char str[64], *str_ptr = str; + int err; + + if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) + return error_invalid_arguments(conn, msg); + + err = get_device_manufacturer(adapter->dev_id, str, sizeof(str)); + if (err < 0) + return error_failed(conn, msg, -err); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_get_company(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct adapter *adapter = data; + DBusMessage *reply; + char str[64], *str_ptr = str; + int err; + + if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) + return error_invalid_arguments(conn, msg); + + err = get_device_company(adapter->dev_id, str, sizeof(str)); + if (err < 0) + return error_failed(conn, msg, -err); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_list_modes(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + DBusMessage *reply; + DBusMessageIter iter; + DBusMessageIter array_iter; + const char *mode_ptr[] = { "off", "connectable", "discoverable", "limited" }; + int i; + + if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) + return error_invalid_arguments(conn, msg); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_iter_init_append(reply, &iter); + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_STRING_AS_STRING, &array_iter); + for (i = 0; i < 4; i++) + dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING, + &mode_ptr[i]); + + dbus_message_iter_close_container(&iter, &array_iter); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_get_mode(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + const struct adapter *adapter = data; + DBusMessage *reply = NULL; + const char *mode; + + if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) + return error_invalid_arguments(conn, msg); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + mode = mode2str(adapter->mode); + + dbus_message_append_args(reply, DBUS_TYPE_STRING, &mode, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_set_mode(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct adapter *adapter = data; + DBusMessage *reply; + const char *mode; + uint8_t scan_enable; + uint8_t new_mode, current_scan = adapter->scan_enable; + bdaddr_t local; + gboolean limited; + int err, dd; + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &mode, + DBUS_TYPE_INVALID)) + return error_invalid_arguments(conn, msg); + + if (!mode) + return error_invalid_arguments(conn, msg); + + new_mode = str2mode(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 error_invalid_arguments(conn, msg); + } + + dd = hci_open_dev(adapter->dev_id); + if (dd < 0) + return error_no_such_adapter(conn, 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 error_failed(conn, 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 error_failed(conn, msg, errno); + } + + goto done; + } + + limited = (new_mode == MODE_LIMITED ? TRUE : FALSE); + err = set_limited_discoverable(dd, adapter->class, limited); + if (err < 0) { + hci_close_dev(dd); + return error_failed(conn, 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 error_failed(conn, msg, err); + } + + if (status) { + error("Setting scan enable failed with status 0x%02x", + status); + hci_close_dev(dd); + return error_failed(conn, msg, bt_error(status)); + } + } else { + /* discoverable or limited */ + if ((scan_enable & SCAN_INQUIRY) && (new_mode != adapter->mode)) { + dbus_connection_emit_signal(conn, + dbus_message_get_path(msg), + ADAPTER_INTERFACE, + "ModeChanged", + DBUS_TYPE_STRING, &mode, + DBUS_TYPE_INVALID); + + if (adapter->timeout_id) + g_source_remove(adapter->timeout_id); + + if (adapter->discov_timeout != 0) + adapter->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); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + adapter->mode = new_mode; + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_get_discoverable_to(DBusConnection *conn, + DBusMessage *msg, + void *data) +{ + const struct adapter *adapter = data; + DBusMessage *reply; + + if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) + return error_invalid_arguments(conn, msg); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, DBUS_TYPE_UINT32, &adapter->discov_timeout, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_set_discoverable_to(DBusConnection *conn, + DBusMessage *msg, + void *data) +{ + struct adapter *adapter = data; + DBusMessage *reply; + uint32_t timeout; + bdaddr_t bdaddr; + + if (!adapter->up) + return error_not_ready(conn, msg); + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_UINT32, &timeout, + DBUS_TYPE_INVALID)) + return error_invalid_arguments(conn, msg); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + if (adapter->timeout_id) { + g_source_remove(adapter->timeout_id); + adapter->timeout_id = 0; + } + + if ((timeout != 0) && (adapter->scan_enable & SCAN_INQUIRY)) + adapter->timeout_id = g_timeout_add(timeout * 1000, + discov_timeout_handler, + adapter); + + adapter->discov_timeout = timeout; + + str2ba(adapter->address, &bdaddr); + write_discoverable_timeout(&bdaddr, timeout); + + dbus_connection_emit_signal(conn, dbus_message_get_path(msg), + ADAPTER_INTERFACE, + "DiscoverableTimeoutChanged", + DBUS_TYPE_UINT32, &timeout, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_is_connectable(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + const struct adapter *adapter = data; + DBusMessage *reply; + const uint8_t scan_enable = adapter->scan_enable; + dbus_bool_t connectable = FALSE; + + if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) + return error_invalid_arguments(conn, msg); + + if (scan_enable & SCAN_PAGE) + connectable = TRUE; + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connectable, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_is_discoverable(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + const struct adapter *adapter = data; + DBusMessage *reply; + const uint8_t scan_enable = adapter->scan_enable; + dbus_bool_t discoverable = FALSE; + + if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) + return error_invalid_arguments(conn, msg); + + if (scan_enable & SCAN_INQUIRY) + discoverable = TRUE; + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &discoverable, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_is_connected(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + DBusMessage *reply; + dbus_bool_t connected = FALSE; + + struct adapter *adapter = data; + GSList *l = adapter->active_conn; + + const char *peer_addr; + bdaddr_t peer_bdaddr; + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &peer_addr, + DBUS_TYPE_INVALID)) + return error_invalid_arguments(conn, msg); + + if (check_address(peer_addr) < 0) + return error_invalid_arguments(conn, msg); + + str2ba(peer_addr, &peer_bdaddr); + + l = g_slist_find_custom(l, &peer_bdaddr, active_conn_find_by_bdaddr); + if (l) + connected = TRUE; + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connected, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_list_connections(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + DBusMessage *reply; + DBusMessageIter iter; + DBusMessageIter array_iter; + struct adapter *adapter = data; + GSList *l = adapter->active_conn; + + if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) + return error_invalid_arguments(conn, msg); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_iter_init_append(reply, &iter); + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_STRING_AS_STRING, &array_iter); + + while (l) { + char peer_addr[18]; + const char *paddr = peer_addr; + struct active_conn_info *dev = l->data; + + ba2str(&dev->bdaddr, peer_addr); + + dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING, + &paddr); + + l = l->next; + } + + dbus_message_iter_close_container(&iter, &array_iter); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_get_major_class(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + const struct adapter *adapter = data; + DBusMessage *reply; + const char *str_ptr = "computer"; + + if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) + return error_invalid_arguments(conn, msg); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + /* FIXME: Currently, only computer major class is supported */ + if ((adapter->class[1] & 0x1f) != 1) + return error_unsupported_major_class(conn, msg); + + dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_list_minor_classes(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + const struct adapter *adapter = data; + DBusMessage *reply = NULL; + DBusMessageIter iter; + DBusMessageIter array_iter; + const char **minor_ptr; + uint8_t major_class; + int size, i; + + if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) + return error_invalid_arguments(conn, msg); + + major_class = adapter->class[1] & 0x1F; + + switch (major_class) { + case 1: /* computer */ + minor_ptr = computer_minor_cls; + size = sizeof(computer_minor_cls) / sizeof(*computer_minor_cls); + break; + case 2: /* phone */ + minor_ptr = phone_minor_cls; + size = sizeof(phone_minor_cls) / sizeof(*phone_minor_cls); + break; + default: + return error_unsupported_major_class(conn, msg); + } + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_iter_init_append(reply, &iter); + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_STRING_AS_STRING, &array_iter); + for (i = 0; i < size; i++) + dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING, + &minor_ptr[i]); + + dbus_message_iter_close_container(&iter, &array_iter); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_get_minor_class(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct adapter *adapter = data; + DBusMessage *reply; + const char *str_ptr = ""; + uint8_t minor_class; + + if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) + return error_invalid_arguments(conn, msg); + + /* FIXME: Currently, only computer major class is supported */ + if ((adapter->class[1] & 0x1f) != 1) + return error_unsupported_major_class(conn, msg); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + minor_class = adapter->class[0] >> 2; + + /* Validate computer minor class */ + if (minor_class > (sizeof(computer_minor_cls) / sizeof(*computer_minor_cls))) + goto failed; + + str_ptr = computer_minor_cls[minor_class]; + +failed: + dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_set_minor_class(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct adapter *adapter = data; + DBusMessage *reply; + const char *minor; + uint32_t dev_class = 0xFFFFFFFF; + int i, dd; + + if (!adapter->up) + return error_not_ready(conn, msg); + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &minor, + DBUS_TYPE_INVALID)) + return error_invalid_arguments(conn, msg); + + if (!minor) + return error_invalid_arguments(conn, msg); + + dd = hci_open_dev(adapter->dev_id); + if (dd < 0) + return error_no_such_adapter(conn, msg); + + /* Currently, only computer major class is supported */ + if ((adapter->class[1] & 0x1f) != 1) { + hci_close_dev(dd); + return error_unsupported_major_class(conn, msg); + } + for (i = 0; i < sizeof(computer_minor_cls) / sizeof(*computer_minor_cls); i++) + if (!strcasecmp(minor, computer_minor_cls[i])) { + /* Remove the format type */ + dev_class = i << 2; + break; + } + + /* Check if it's a valid minor class */ + if (dev_class == 0xFFFFFFFF) { + hci_close_dev(dd); + return error_invalid_arguments(conn, msg); + } + + /* set the service class and major class */ + dev_class |= (adapter->class[2] << 16) | (adapter->class[1] << 8); + + if (hci_write_class_of_dev(dd, dev_class, 2000) < 0) { + int err = errno; + error("Can't write class of device on hci%d: %s(%d)", + adapter->dev_id, strerror(errno), errno); + hci_close_dev(dd); + return error_failed(conn, msg, err); + } + + dbus_connection_emit_signal(conn, dbus_message_get_path(msg), + ADAPTER_INTERFACE, "MinorClassChanged", + DBUS_TYPE_STRING, &minor, + DBUS_TYPE_INVALID); + + reply = dbus_message_new_method_return(msg); + + hci_close_dev(dd); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_get_service_classes(DBusConnection *conn, + DBusMessage *msg, + void *data) +{ + struct adapter *adapter = data; + DBusMessage *reply; + DBusMessageIter iter; + DBusMessageIter array_iter; + const char *str_ptr; + int i; + + if (!adapter->up) + return error_not_ready(conn, msg); + + if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) + return error_invalid_arguments(conn, msg); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_iter_init_append(reply, &iter); + + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_STRING_AS_STRING, &array_iter); + + for (i = 0; i < (sizeof(service_cls) / sizeof(*service_cls)); i++) { + if (adapter->class[2] & (1 << i)) { + str_ptr = service_cls[i]; + dbus_message_iter_append_basic(&array_iter, + DBUS_TYPE_STRING, &str_ptr); + } + } + + dbus_message_iter_close_container(&iter, &array_iter); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_get_name(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct adapter *adapter = data; + DBusMessage *reply; + char str[249], *str_ptr = str; + int err; + bdaddr_t ba; + + if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) + return error_invalid_arguments(conn, msg); + + str2ba(adapter->address, &ba); + + err = read_local_name(&ba, str); + if (err < 0) { + if (!adapter->up) + return error_not_ready(conn, msg); + + err = get_device_name(adapter->dev_id, str, sizeof(str)); + if (err < 0) + return error_failed(conn, msg, -err); + } + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_set_name(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct adapter *adapter = data; + DBusMessage *reply; + bdaddr_t bdaddr; + char *str_ptr; + int ecode; + + if (!adapter->up) + return error_not_ready(conn, msg); + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &str_ptr, + DBUS_TYPE_INVALID)) + return error_invalid_arguments(conn, msg); + + if (!g_utf8_validate(str_ptr, -1, NULL)) { + error("Name change failed: the supplied name isn't valid UTF-8"); + return error_invalid_arguments(conn, msg); + } + + hci_devba(adapter->dev_id, &bdaddr); + + write_local_name(&bdaddr, str_ptr); + + ecode = set_device_name(adapter->dev_id, str_ptr); + if (ecode < 0) + return error_failed(conn, msg, -ecode); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_get_remote_info(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct adapter *adapter = data; + DBusMessage *reply; + DBusMessageIter iter; + DBusMessageIter dict; + bdaddr_t src, dst; + const char *addr_ptr; + char filename[PATH_MAX + 1]; + char buf[64]; + const char *ptr; + char *str; + dbus_bool_t boolean; + uint32_t class; + int compid, ver, subver; + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &addr_ptr, + DBUS_TYPE_INVALID)) + return error_invalid_arguments(conn, msg); + + if (check_address(addr_ptr) < 0) + return error_invalid_arguments(conn, msg); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + 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); + + /* Name */ + create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "names"); + str = textfile_caseget(filename, addr_ptr); + if (str) { + dbus_message_iter_append_dict_entry(&dict, "name", + DBUS_TYPE_STRING, &str); + free(str); + } + + str2ba(adapter->address, &src); + str2ba(addr_ptr, &dst); + + /* Remote device class */ + if (read_remote_class(&src, &dst, &class) == 0) { + + dbus_message_iter_append_dict_entry(&dict, "class", + DBUS_TYPE_UINT32, &class); + + ptr = major_class_str(class); + dbus_message_iter_append_dict_entry(&dict, "major_class", + DBUS_TYPE_STRING, &ptr); + + ptr = minor_class_str(class); + dbus_message_iter_append_dict_entry(&dict, "minor_class", + DBUS_TYPE_STRING, &ptr); + } + + /* Alias */ + if (get_device_alias(adapter->dev_id, &dst, buf, sizeof(buf)) > 0) { + ptr = buf; + dbus_message_iter_append_dict_entry(&dict, "alias", + DBUS_TYPE_STRING, &ptr); + } + + /* Bonded */ + create_name(filename, PATH_MAX, STORAGEDIR, + adapter->address, "linkkeys"); + str = textfile_caseget(filename, addr_ptr); + if (str) { + boolean = TRUE; + free(str); + } else { + boolean = FALSE; + } + + dbus_message_iter_append_dict_entry(&dict, "bonded", + DBUS_TYPE_BOOLEAN, &boolean); + + /* Trusted */ + boolean = read_trust(&src, addr_ptr, GLOBAL_TRUST); + dbus_message_iter_append_dict_entry(&dict, "trusted", + DBUS_TYPE_BOOLEAN, &boolean); + + /* Connected */ + if (g_slist_find_custom(adapter->active_conn, &dst, + active_conn_find_by_bdaddr)) + boolean = TRUE; + else + boolean = FALSE; + + dbus_message_iter_append_dict_entry(&dict, "connected", + DBUS_TYPE_BOOLEAN, &boolean); + + /* HCI Revision/Manufacturer/Version */ + create_name(filename, PATH_MAX, STORAGEDIR, + adapter->address, "manufacturers"); + + str = textfile_caseget(filename, addr_ptr); + if (!str) + goto done; + + if (sscanf(str, "%d %d %d", &compid, &ver, &subver) != 3) { + /* corrupted file data */ + free(str); + goto done; + } + + free(str); + + ptr = buf; + snprintf(buf, 16, "HCI 0x%X", subver); + dbus_message_iter_append_dict_entry(&dict, "revision", + DBUS_TYPE_STRING, &ptr); + + ptr = bt_compidtostr(compid); + dbus_message_iter_append_dict_entry(&dict, "manufacturer", + DBUS_TYPE_STRING, &ptr); + + str = lmp_vertostr(ver); + snprintf(buf, 64, "Bluetooth %s", str); + bt_free(str); + + create_name(filename, PATH_MAX, STORAGEDIR, + adapter->address, "features"); + + str = textfile_caseget(filename, addr_ptr); + if (str) { + if (strlen(str) == 16) { + uint8_t features; + /* Getting the third byte */ + features = ((str[6] - 48) << 4) | (str[7] - 48); + if (features & (LMP_EDR_ACL_2M | LMP_EDR_ACL_3M)) + snprintf(buf, 64, "Bluetooth %s + EDR", ptr); + + } + free(str); + } + ptr = buf; + dbus_message_iter_append_dict_entry(&dict, "version", + DBUS_TYPE_STRING, &ptr); + +done: + dbus_message_iter_close_container(&iter, &dict); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_get_remote_svc(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + return get_remote_svc_rec(conn, msg, data, SDP_FORMAT_BINARY); +} + +static DBusHandlerResult adapter_get_remote_svc_xml(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + return get_remote_svc_rec(conn, msg, data, SDP_FORMAT_XML); +} + +static DBusHandlerResult adapter_get_remote_svc_handles(DBusConnection *conn, + DBusMessage *msg, + void *data) +{ + return get_remote_svc_handles(conn, msg, data); +} + +static DBusHandlerResult adapter_get_remote_svc_identifiers(DBusConnection *conn, + DBusMessage *msg, + void *data) +{ + return get_remote_svc_identifiers(conn, msg, data); +} + +static DBusHandlerResult adapter_finish_sdp_transact(DBusConnection *conn, + DBusMessage *msg, + void *data) +{ + return finish_remote_svc_transact(conn, msg, data); +} + +static DBusHandlerResult adapter_get_remote_version(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct adapter *adapter = data; + DBusMessage *reply; + char filename[PATH_MAX + 1]; + char *addr_ptr, *str; + char *str_ver = NULL; + char info_array[64], *info = info_array; + int compid, ver, subver; + + memset(info_array, 0, 64); + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &addr_ptr, + DBUS_TYPE_INVALID)) + return error_invalid_arguments(conn, msg); + + if (check_address(addr_ptr) < 0) + return error_invalid_arguments(conn, msg); + + create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, + "manufacturers"); + + str = textfile_caseget(filename, addr_ptr); + if (!str) + return error_not_available(conn, msg); + + if (sscanf(str, "%d %d %d", &compid, &ver, &subver) != 3) { + /* corrupted file data */ + free(str); + goto failed; + } + + free(str); + + str_ver = lmp_vertostr(ver); + + /* Default value */ + snprintf(info, 64, "Bluetooth %s", str_ver); + + create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, + "features"); + + str = textfile_caseget(filename, addr_ptr); + if (!str) + goto failed; + + /* Check if the data is not corrupted */ + if (strlen(str) == 16) { + uint8_t features; + /* Getting the third byte */ + features = ((str[6] - 48) << 4) | (str[7] - 48); + if (features & (LMP_EDR_ACL_2M | LMP_EDR_ACL_3M)) + snprintf(info, 64, "Bluetooth %s + EDR", str_ver); + } + + free(str); + +failed: + if (str_ver) + bt_free(str_ver); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, DBUS_TYPE_STRING, &info, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_get_remote_revision(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct adapter *adapter = data; + DBusMessage *reply; + char filename[PATH_MAX + 1]; + char *addr_ptr, *str; + char info_array[16], *info = info_array; + int compid, ver, subver; + + memset(info_array, 0, 16); + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &addr_ptr, + DBUS_TYPE_INVALID)) + return error_invalid_arguments(conn, msg); + + if (check_address(addr_ptr) < 0) + return error_invalid_arguments(conn, msg); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, + "manufacturers"); + + str = textfile_caseget(filename, addr_ptr); + if (!str) + return error_not_available(conn, msg); + + if (sscanf(str, "%d %d %d", &compid, &ver, &subver) == 3) + snprintf(info, 16, "HCI 0x%X", subver); + + free(str); + + dbus_message_append_args(reply, DBUS_TYPE_STRING, &info, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_get_remote_manufacturer(DBusConnection *conn, + DBusMessage *msg, + void *data) +{ + struct adapter *adapter = data; + DBusMessage *reply; + char filename[PATH_MAX + 1]; + char *addr_ptr, *str; + char info_array[64], *info = info_array; + int compid, ver, subver; + + memset(info_array, 0, 64); + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &addr_ptr, + DBUS_TYPE_INVALID)) + return error_invalid_arguments(conn, msg); + + if (check_address(addr_ptr) < 0) + return error_invalid_arguments(conn, msg); + + create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, + "manufacturers"); + + str = textfile_caseget(filename, addr_ptr); + if (!str) + return error_not_available(conn, msg); + + if (sscanf(str, "%d %d %d", &compid, &ver, &subver) == 3) + info = bt_compidtostr(compid); + + free(str); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, DBUS_TYPE_STRING, &info, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_get_remote_company(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + DBusMessage *reply; + bdaddr_t bdaddr; + char oui[9], *str_bdaddr, *tmp; + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &str_bdaddr, + DBUS_TYPE_INVALID)) + return error_invalid_arguments(conn, msg); + + str2ba(str_bdaddr, &bdaddr); + ba2oui(&bdaddr, oui); + + tmp = ouitocomp(oui); + if (!tmp) + return error_not_available(conn, msg); + + reply = dbus_message_new_method_return(msg); + if (!reply) { + free(tmp); + return DBUS_HANDLER_RESULT_NEED_MEMORY; + } + + dbus_message_append_args(reply, DBUS_TYPE_STRING, &tmp, + DBUS_TYPE_INVALID); + + free(tmp); + + return send_message_and_unref(conn, reply); +} + +static int get_remote_class(DBusConnection *conn, DBusMessage *msg, void *data, + uint32_t *class) +{ + struct adapter *adapter = data; + char *addr_peer; + bdaddr_t local, peer; + int ecode; + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &addr_peer, + DBUS_TYPE_INVALID)) { + error_invalid_arguments(conn, msg); + return -1; + } + + if (check_address(addr_peer) < 0) { + error_invalid_arguments(conn, msg); + return -1; + } + + str2ba(addr_peer, &peer); + str2ba(adapter->address, &local); + + ecode = read_remote_class(&local, &peer, class); + if (ecode < 0) { + error_not_available(conn, msg); + return -1; + } + + return 0; +} + +static DBusHandlerResult adapter_get_remote_major_class(DBusConnection *conn, + DBusMessage *msg, + void *data) +{ + DBusMessage *reply; + const char *major_class; + uint32_t class; + + if (get_remote_class(conn, msg, data, &class) < 0) + return DBUS_HANDLER_RESULT_HANDLED; + + major_class = major_class_str(class); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, DBUS_TYPE_STRING, &major_class, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_get_remote_minor_class(DBusConnection *conn, + DBusMessage *msg, + void *data) +{ + DBusMessage *reply; + const char *minor_class; + uint32_t class; + + if (get_remote_class(conn, msg, data, &class) < 0) + return DBUS_HANDLER_RESULT_HANDLED; + + minor_class = minor_class_str(class); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, DBUS_TYPE_STRING, &minor_class, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static void append_class_string(const char *class, DBusMessageIter *iter) +{ + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &class); +} + +static DBusHandlerResult adapter_get_remote_service_cls(DBusConnection *conn, + DBusMessage *msg, + void *data) +{ + DBusMessage *reply; + DBusMessageIter iter, array_iter; + GSList *service_classes; + uint32_t class; + + if (get_remote_class(conn, msg, data, &class) < 0) + return DBUS_HANDLER_RESULT_HANDLED; + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + service_classes = service_classes_str(class); + + dbus_message_iter_init_append(reply, &iter); + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_STRING_AS_STRING, &array_iter); + + g_slist_foreach(service_classes, (GFunc) append_class_string, + &array_iter); + + dbus_message_iter_close_container(&iter, &array_iter); + + g_slist_free(service_classes); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_get_remote_class(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + DBusMessage *reply; + uint32_t class; + + if (get_remote_class(conn, msg, data, &class) < 0) + return DBUS_HANDLER_RESULT_HANDLED; + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, DBUS_TYPE_UINT32, &class, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_get_remote_features(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + char filename[PATH_MAX + 1]; + struct adapter *adapter = data; + DBusMessage *reply = NULL; + DBusMessageIter iter, array_iter; + uint8_t features[8], *ptr = features; + const char *addr; + char *str; + int i; + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &addr, + DBUS_TYPE_INVALID)) + return error_invalid_arguments(conn, msg); + + if (check_address(addr) < 0) + return error_invalid_arguments(conn, msg); + + create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "features"); + + str = textfile_caseget(filename, addr); + if (!str) + return error_not_available(conn, msg); + + memset(features, 0, sizeof(features)); + for (i = 0; i < sizeof(features); i++) { + char tmp[3]; + + memcpy(tmp, str + (i * 2), 2); + tmp[2] = '\0'; + + features[i] = (uint8_t) strtol(tmp, NULL, 16); + } + + reply = dbus_message_new_method_return(msg); + if (!reply) { + free(str); + return DBUS_HANDLER_RESULT_NEED_MEMORY; + } + + dbus_message_iter_init_append(reply, &iter); + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE_AS_STRING, &array_iter); + + dbus_message_iter_append_fixed_array(&array_iter, + DBUS_TYPE_BYTE, &ptr, sizeof(features)); + + dbus_message_iter_close_container(&iter, &array_iter); + + free(str); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_get_remote_name(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + char filename[PATH_MAX + 1]; + struct adapter *adapter = data; + DBusMessage *reply = NULL; + const char *peer_addr; + bdaddr_t peer_bdaddr; + char *str; + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &peer_addr, + DBUS_TYPE_INVALID)) + return error_invalid_arguments(conn, msg); + + if (check_address(peer_addr) < 0) + return error_invalid_arguments(conn, msg); + + /* check if it is in the cache */ + create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "names"); + + str = textfile_caseget(filename, peer_addr); + + if (str) { + reply = dbus_message_new_method_return(msg); + if (!reply) { + free(str); + return DBUS_HANDLER_RESULT_NEED_MEMORY; + } + + /* send the cached name */ + dbus_message_append_args(reply, DBUS_TYPE_STRING, &str, + DBUS_TYPE_INVALID); + + free(str); + return send_message_and_unref(conn, reply); + } + + if (!adapter->up) + return error_not_ready(conn, msg); + + /* If the discover process is not running, return an error */ + if (!adapter->discov_active && !adapter->pdiscov_active) + return error_not_available(conn, msg); + + /* Queue the request when there is a discovery running */ + str2ba(peer_addr, &peer_bdaddr); + found_device_add(&adapter->found_devices, &peer_bdaddr, 0, NAME_REQUIRED); + + return error_request_deferred(conn, msg); +} + +static DBusHandlerResult adapter_get_remote_alias(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct adapter *adapter = data; + DBusMessage *reply; + char str[249], *str_ptr = str, *addr_ptr; + bdaddr_t bdaddr; + int ecode; + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &addr_ptr, + DBUS_TYPE_INVALID)) + return error_invalid_arguments(conn, msg); + + if (check_address(addr_ptr) < 0) + return error_invalid_arguments(conn, msg); + + str2ba(addr_ptr, &bdaddr); + + ecode = get_device_alias(adapter->dev_id, &bdaddr, str, sizeof(str)); + if (ecode < 0) + return error_not_available(conn, msg); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_set_remote_alias(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct adapter *adapter = data; + DBusMessage *reply; + char *alias, *addr; + bdaddr_t bdaddr; + int ecode; + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &addr, + DBUS_TYPE_STRING, &alias, + DBUS_TYPE_INVALID)) + return error_invalid_arguments(conn, msg); + + if ((strlen(alias) == 0) || (check_address(addr) < 0)) { + error("Alias change failed: Invalid parameter"); + return error_invalid_arguments(conn, msg); + } + + str2ba(addr, &bdaddr); + + ecode = set_device_alias(adapter->dev_id, &bdaddr, alias); + if (ecode < 0) + return error_failed(conn, msg, -ecode); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_connection_emit_signal(conn, dbus_message_get_path(msg), + ADAPTER_INTERFACE, "RemoteAliasChanged", + DBUS_TYPE_STRING, &addr, + DBUS_TYPE_STRING, &alias, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_clear_remote_alias(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct adapter *adapter = data; + DBusMessage *reply; + char *addr_ptr; + bdaddr_t bdaddr; + int ecode, had_alias = 1; + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &addr_ptr, + DBUS_TYPE_INVALID)) + return error_invalid_arguments(conn, msg); + + if (check_address(addr_ptr) < 0) { + error("Alias clear failed: Invalid parameter"); + return error_invalid_arguments(conn, msg); + } + + str2ba(addr_ptr, &bdaddr); + + ecode = get_device_alias(adapter->dev_id, &bdaddr, NULL, 0); + if (ecode == -ENXIO) + had_alias = 0; + + ecode = set_device_alias(adapter->dev_id, &bdaddr, NULL); + if (ecode < 0) + return error_failed(conn, msg, -ecode); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + if (had_alias) + dbus_connection_emit_signal(conn, dbus_message_get_path(msg), + ADAPTER_INTERFACE, + "RemoteAliasCleared", + DBUS_TYPE_STRING, &addr_ptr, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_last_seen(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct adapter *adapter = data; + DBusMessage *reply; + char filename[PATH_MAX + 1]; + char *addr_ptr, *str; + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &addr_ptr, + DBUS_TYPE_INVALID)) + return error_invalid_arguments(conn, msg); + + if (check_address(addr_ptr) < 0) + return error_invalid_arguments(conn, msg); + + create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, + "lastseen"); + + str = textfile_caseget(filename, addr_ptr); + if (!str) + return error_not_available(conn, msg); + + reply = dbus_message_new_method_return(msg); + if (!reply) { + free(str); + return DBUS_HANDLER_RESULT_NEED_MEMORY; + } + + dbus_message_append_args(reply, DBUS_TYPE_STRING, &str, + DBUS_TYPE_INVALID); + + free(str); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_last_used(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct adapter *adapter = data; + DBusMessage *reply; + char filename[PATH_MAX + 1]; + char *addr_ptr, *str; + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &addr_ptr, + DBUS_TYPE_INVALID)) + return error_invalid_arguments(conn, msg); + + if (check_address(addr_ptr) < 0) + return error_invalid_arguments(conn, msg); + + create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, + "lastused"); + + str = textfile_caseget(filename, addr_ptr); + if (!str) + return error_not_available(conn, msg); + + reply = dbus_message_new_method_return(msg); + if (!reply) { + free(str); + return DBUS_HANDLER_RESULT_NEED_MEMORY; + } + + dbus_message_append_args(reply, DBUS_TYPE_STRING, &str, + DBUS_TYPE_INVALID); + + free(str); + + return send_message_and_unref(conn, reply); +} + + +gboolean dc_pending_timeout_handler(void *data) +{ + int dd; + struct adapter *adapter = data; + struct pending_dc_info *pending_dc = adapter->pending_dc; + DBusMessage *reply; + + dd = hci_open_dev(adapter->dev_id); + + if (dd < 0) { + error_no_such_adapter(pending_dc->conn, + pending_dc->msg); + dc_pending_timeout_cleanup(adapter); + return FALSE; + } + + /* Send the HCI disconnect command */ + if (hci_disconnect(dd, pending_dc->conn_handle, + HCI_OE_USER_ENDED_CONNECTION, + 500) < 0) { + int err = errno; + error("Disconnect failed"); + error_failed(pending_dc->conn, pending_dc->msg, err); + } else { + reply = dbus_message_new_method_return(pending_dc->msg); + if (!reply) + error("Failed to allocate disconnect reply"); + else + send_message_and_unref(pending_dc->conn, reply); + } + + hci_close_dev(dd); + dc_pending_timeout_cleanup(adapter); + + return FALSE; +} + +void dc_pending_timeout_cleanup(struct adapter *adapter) +{ + dbus_connection_unref(adapter->pending_dc->conn); + dbus_message_unref(adapter->pending_dc->msg); + g_free(adapter->pending_dc); + adapter->pending_dc = NULL; +} + +static DBusHandlerResult adapter_dc_remote_device(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct adapter *adapter = data; + GSList *l = adapter->active_conn; + const char *peer_addr; + bdaddr_t peer_bdaddr; + + if (!adapter->up) + return error_not_ready(conn, msg); + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &peer_addr, + DBUS_TYPE_INVALID)) + return error_invalid_arguments(conn, msg); + + if (check_address(peer_addr) < 0) + return error_invalid_arguments(conn, msg); + + str2ba(peer_addr, &peer_bdaddr); + + l = g_slist_find_custom(l, &peer_bdaddr, active_conn_find_by_bdaddr); + if (!l) + return error_not_connected(conn, msg); + + if (adapter->pending_dc) + return error_disconnect_in_progress(conn, msg); + + adapter->pending_dc = g_new0(struct pending_dc_info, 1); + + /* Start waiting... */ + adapter->pending_dc->timeout_id = + g_timeout_add(DC_PENDING_TIMEOUT, + dc_pending_timeout_handler, + adapter); + + if (!adapter->pending_dc->timeout_id) { + g_free(adapter->pending_dc); + adapter->pending_dc = NULL; + return DBUS_HANDLER_RESULT_NEED_MEMORY; + } + + adapter->pending_dc->conn = dbus_connection_ref(conn); + adapter->pending_dc->msg = dbus_message_ref(msg); + adapter->pending_dc->conn_handle = + ((struct active_conn_info *) l->data)->handle; + + dbus_connection_emit_signal(conn, dbus_message_get_path(msg), + ADAPTER_INTERFACE, + "RemoteDeviceDisconnectRequested", + DBUS_TYPE_STRING, &peer_addr, + DBUS_TYPE_INVALID); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +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->rq, status); + if (reply) + send_message_and_unref(bonding->conn, reply); +} + +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) { + error_authentication_canceled(adapter->bonding->conn, + adapter->bonding->rq); + 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->rq, + 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(adapter->bonding->conn, adapter->bonding->rq, + 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->rq, + 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(adapter->bonding->conn, adapter->bonding->rq, + errno); + goto failed; + } + + dd = hci_open_dev(adapter->dev_id); + if (dd < 0) { + error_no_such_adapter(adapter->bonding->conn, + adapter->bonding->rq); + 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(adapter->bonding->conn, adapter->bonding->rq, + errno); + hci_close_dev(dd); + goto failed; + } + + if (rp.status) { + error("HCI_Authentication_Requested failed with status 0x%02x", + rp.status); + error_failed(adapter->bonding->conn, adapter->bonding->rq, + 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); + +cleanup: + name_listener_remove(adapter->bonding->conn, + dbus_message_get_sender(adapter->bonding->rq), + (name_cb_t) create_bond_req_exit, adapter); + + bonding_request_free(adapter->bonding); + adapter->bonding = NULL; + + return FALSE; +} + +static DBusHandlerResult adapter_create_bonding(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + char filename[PATH_MAX + 1]; + char *str, *peer_addr = NULL; + struct adapter *adapter = data; + bdaddr_t peer_bdaddr; + int sk; + + if (!adapter->up) + return error_not_ready(conn, msg); + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &peer_addr, + DBUS_TYPE_INVALID)) + return error_invalid_arguments(conn, msg); + + if (check_address(peer_addr) < 0) + return error_invalid_arguments(conn, msg); + + str2ba(peer_addr, &peer_bdaddr); + + /* check if there is a pending discover: requested by D-Bus/non clients */ + if (adapter->discov_active || (adapter->pdiscov_active && !adapter->pinq_idle)) + return error_discover_in_progress(conn, msg); + + pending_remote_name_cancel(adapter); + + if (adapter->bonding) + return error_bonding_in_progress(conn, msg); + + if (g_slist_find_custom(adapter->pin_reqs, &peer_bdaddr, pin_req_cmp)) + return error_bonding_in_progress(conn, msg); + + /* check if a link key already exists */ + create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, + "linkkeys"); + + str = textfile_caseget(filename, peer_addr); + if (str) { + free(str); + return error_bonding_already_exists(conn, msg); + } + + sk = l2raw_connect(adapter->address, &peer_bdaddr); + if (sk < 0) + return error_connection_attempt_failed(conn, msg, 0); + + adapter->bonding = bonding_request_new(&peer_bdaddr, conn, msg); + if (!adapter->bonding) { + close(sk); + return DBUS_HANDLER_RESULT_NEED_MEMORY; + } + + adapter->bonding->io = g_io_channel_unix_new(sk); + adapter->bonding->io_id = g_io_add_watch(adapter->bonding->io, + G_IO_OUT | G_IO_NVAL | G_IO_HUP | G_IO_ERR, + (GIOFunc) create_bonding_conn_complete, + adapter); + + name_listener_add(conn, dbus_message_get_sender(msg), + (name_cb_t) create_bond_req_exit, adapter); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +static DBusHandlerResult adapter_cancel_bonding(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct adapter *adapter = data; + DBusMessage *reply; + bdaddr_t peer_bdaddr; + const char *peer_addr; + GSList *l; + + if (!adapter->up) + return error_not_ready(conn, msg); + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &peer_addr, + DBUS_TYPE_INVALID)) + return error_invalid_arguments(conn, msg); + + if (check_address(peer_addr) < 0) + return error_invalid_arguments(conn, msg); + + str2ba(peer_addr, &peer_bdaddr); + + if (!adapter->bonding || bacmp(&adapter->bonding->bdaddr, &peer_bdaddr)) + return error_bonding_not_in_progress(conn, msg); + + if (strcmp(dbus_message_get_sender(adapter->bonding->rq), + dbus_message_get_sender(msg))) + return error_not_authorized(conn, msg); + + adapter->bonding->cancel = 1; + + l = g_slist_find_custom(adapter->pin_reqs, &peer_bdaddr, pin_req_cmp); + if (l) { + struct pending_pin_info *pin_req = l->data; + + if (pin_req->replied) { + /* + * If disconnect can't be applied and the PIN code + * request was already replied it doesn't make sense + * cancel the remote passkey: return not authorized. + */ + g_io_channel_close(adapter->bonding->io); + return error_not_authorized(conn, msg); + } else { + int dd = hci_open_dev(adapter->dev_id); + if (dd < 0) { + error("Can't open hci%d: %s (%d)", + adapter->dev_id, strerror(errno), errno); + return DBUS_HANDLER_RESULT_HANDLED; + } + + hci_send_cmd(dd, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, + 6, &peer_bdaddr); + + hci_close_dev(dd); + } + + adapter->pin_reqs = g_slist_remove(adapter->pin_reqs, pin_req); + g_free(pin_req); + } + + g_io_channel_close(adapter->bonding->io); + + reply = dbus_message_new_method_return(msg); + send_message_and_unref(conn, reply); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +static DBusHandlerResult adapter_remove_bonding(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct adapter *adapter = data; + GSList *l; + DBusMessage *reply; + char filename[PATH_MAX + 1]; + char *addr_ptr, *str; + bdaddr_t bdaddr; + int dd; + + if (!adapter->up) + return error_not_ready(conn, msg); + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &addr_ptr, + DBUS_TYPE_INVALID)) + return error_invalid_arguments(conn, msg); + + if (check_address(addr_ptr) < 0) + return error_invalid_arguments(conn, msg); + + dd = hci_open_dev(adapter->dev_id); + if (dd < 0) + return error_no_such_adapter(conn, 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, addr_ptr); + if (!str) { + hci_close_dev(dd); + return error_bonding_does_not_exist(conn, msg); + } + + free(str); + + /* Delete the link key from storage */ + if (textfile_casedel(filename, addr_ptr) < 0) { + int err = errno; + hci_close_dev(dd); + return error_failed(conn, msg, err); + } + + str2ba(addr_ptr, &bdaddr); + + /* Delete the link key from the Bluetooth chip */ + hci_delete_stored_link_key(dd, &bdaddr, 0, 1000); + + /* find the connection */ + l = g_slist_find_custom(adapter->active_conn, &bdaddr, + active_conn_find_by_bdaddr); + if (l) { + struct active_conn_info *con = l->data; + /* Send the HCI disconnect command */ + if (hci_disconnect(dd, htobs(con->handle), + HCI_OE_USER_ENDED_CONNECTION, 500) < 0) { + int err = errno; + error("Disconnect failed"); + hci_close_dev(dd); + return error_failed(conn, msg, err); + } + } + + dbus_connection_emit_signal(conn, dbus_message_get_path(msg), + ADAPTER_INTERFACE, "BondingRemoved", + DBUS_TYPE_STRING, &addr_ptr, + DBUS_TYPE_INVALID); + + reply = dbus_message_new_method_return(msg); + + hci_close_dev(dd); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_has_bonding(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct adapter *adapter = data; + DBusMessage *reply; + char filename[PATH_MAX + 1]; + char *addr_ptr, *str; + dbus_bool_t result; + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &addr_ptr, + DBUS_TYPE_INVALID)) + return error_invalid_arguments(conn, msg); + + if (check_address(addr_ptr) < 0) + return error_invalid_arguments(conn, msg); + + create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, + "linkkeys"); + + str = textfile_caseget(filename, addr_ptr); + if (str) { + result = TRUE; + free(str); + } else + result = FALSE; + + reply = dbus_message_new_method_return(msg); + + dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &result, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static void list_bondings_do_append(char *key, char *value, void *data) +{ + DBusMessageIter *iter = data; + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &key); +} + +static DBusHandlerResult adapter_list_bondings(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct adapter *adapter = data; + DBusMessageIter iter; + DBusMessageIter array_iter; + DBusMessage *reply; + char filename[PATH_MAX + 1]; + + if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) + return error_invalid_arguments(conn, msg); + + create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, + "linkkeys"); + + reply = dbus_message_new_method_return(msg); + + dbus_message_iter_init_append(reply, &iter); + + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_STRING_AS_STRING, &array_iter); + + textfile_foreach(filename, list_bondings_do_append, &array_iter); + + dbus_message_iter_close_container(&iter, &array_iter); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_get_pin_code_length(DBusConnection *conn, + DBusMessage *msg, + void *data) +{ + struct adapter *adapter = data; + DBusMessage *reply; + bdaddr_t local, peer; + char *addr_ptr; + uint8_t length; + int len; + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &addr_ptr, + DBUS_TYPE_INVALID)) + return error_invalid_arguments(conn, msg); + + if (check_address(addr_ptr) < 0) + return error_invalid_arguments(conn, msg); + + str2ba(adapter->address, &local); + + str2ba(addr_ptr, &peer); + + len = read_pin_length(&local, &peer); + if (len < 0) + return error_record_does_not_exist(conn, msg); + + reply = dbus_message_new_method_return(msg); + + length = len; + + dbus_message_append_args(reply, DBUS_TYPE_BYTE, &length, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_get_encryption_key_size(DBusConnection *conn, + DBusMessage *msg, + void *data) +{ + struct adapter *adapter = data; + DBusMessage *reply; + bdaddr_t bdaddr; + char *addr_ptr; + uint8_t size; + int val; + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &addr_ptr, + DBUS_TYPE_INVALID)) + return error_invalid_arguments(conn, msg); + + if (check_address(addr_ptr) < 0) + return error_invalid_arguments(conn, msg); + + str2ba(addr_ptr, &bdaddr); + + val = get_encryption_key_size(adapter->dev_id, &bdaddr); + if (val < 0) + return error_failed(conn, msg, -val); + + reply = dbus_message_new_method_return(msg); + + size = val; + + dbus_message_append_args(reply, DBUS_TYPE_BYTE, &size, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_start_periodic(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + DBusMessage *reply; + 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 error_not_ready(conn, msg); + + if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) + return error_invalid_arguments(conn, msg); + + if (adapter->discov_active || adapter->pdiscov_active) + return error_discover_in_progress(conn, msg); + + pending_remote_name_cancel(adapter); + + dd = hci_open_dev(adapter->dev_id); + if (dd < 0) + return error_no_such_adapter(conn, 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 error_failed(conn, msg, err); + } + + if (status) { + error("HCI_Periodic_Inquiry_Mode failed with status 0x%02x", + status); + hci_close_dev(dd); + return error_failed(conn, 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; + + reply = dbus_message_new_method_return(msg); + + hci_close_dev(dd); + + /* track the request owner to cancel it automatically if the owner + * exits */ + name_listener_add(conn, dbus_message_get_sender(msg), + (name_cb_t) periodic_discover_req_exit, + adapter); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_stop_periodic(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + DBusMessage *reply; + struct adapter *adapter = data; + int err; + + if (!adapter->up) + return error_not_ready(conn, msg); + + if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) + return error_invalid_arguments(conn, msg); + + if (!adapter->pdiscov_active) + return error_not_authorized(conn, msg); + + /* + * 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 error_no_such_adapter(conn, msg); + else + return error_failed(conn, msg, -err); + } + + reply = dbus_message_new_method_return(msg); + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_is_periodic(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + DBusMessage *reply; + struct adapter *adapter = data; + dbus_bool_t active = adapter->pdiscov_active; + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &active, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_set_pdiscov_resolve(DBusConnection *conn, + DBusMessage *msg, + void *data) +{ + DBusMessage *reply; + struct adapter *adapter = data; + dbus_bool_t resolve; + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_BOOLEAN, &resolve, + DBUS_TYPE_INVALID)) + return error_invalid_arguments(conn, msg); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + debug("SetPeriodicDiscoveryNameResolving(%s)", + resolve ? "TRUE" : "FALSE"); + + adapter->pdiscov_resolve_names = resolve; + + if (adapter->pdiscov_active) { + if (resolve) + adapter->discov_type |= RESOLVE_NAME; + else + adapter->discov_type &= ~RESOLVE_NAME; + } + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_get_pdiscov_resolve(DBusConnection *conn, + DBusMessage *msg, + void *data) +{ + DBusMessage *reply; + struct adapter *adapter = data; + dbus_bool_t resolve = adapter->pdiscov_resolve_names; + + if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) + return error_invalid_arguments(conn, msg); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &resolve, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_discover_devices(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + DBusMessage *reply; + const char *method; + 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 error_not_ready(conn, msg); + + if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) + return error_invalid_arguments(conn, msg); + + if (adapter->discov_active) + return error_discover_in_progress(conn, msg); + + pending_remote_name_cancel(adapter); + + if (adapter->bonding) + return error_bonding_in_progress(conn, msg); + + dd = hci_open_dev(adapter->dev_id); + if (dd < 0) + return error_no_such_adapter(conn, 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 error_failed(conn, msg, err); + } + + if (rp.status) { + error("HCI_Inquiry command failed with status 0x%02x", + rp.status); + hci_close_dev(dd); + return error_failed(conn, msg, bt_error(rp.status)); + } + + method = dbus_message_get_member(msg); + if (strcmp("DiscoverDevicesWithoutNameResolving", method) == 0) + adapter->discov_type |= STD_INQUIRY; + else + adapter->discov_type |= (STD_INQUIRY | RESOLVE_NAME); + + adapter->discov_requestor = g_strdup(dbus_message_get_sender(msg)); + + reply = dbus_message_new_method_return(msg); + + hci_close_dev(dd); + + /* track the request owner to cancel it automatically if the owner + * exits */ + name_listener_add(conn, dbus_message_get_sender(msg), + (name_cb_t) discover_devices_req_exit, adapter); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_cancel_discovery(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct adapter *adapter = data; + int err; + + if (!adapter->up) + return error_not_ready(conn, msg); + + if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) + return error_invalid_arguments(conn, msg); + + /* is there discover pending? or discovery cancel was requested + * previously */ + if (!adapter->discov_active || adapter->discovery_cancel) + return error_not_authorized(conn, msg); + + /* only the discover requestor can cancel the inquiry process */ + if (!adapter->discov_requestor || + strcmp(adapter->discov_requestor, dbus_message_get_sender(msg))) + return error_not_authorized(conn, msg); + + /* + * 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 error_no_such_adapter(conn, msg); + else + return error_failed(conn, msg, -err); + } + + /* Reply before send DiscoveryCompleted */ + adapter->discovery_cancel = dbus_message_ref(msg); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +struct remote_device_list_t { + GSList *list; + time_t time; +}; + +static void list_remote_devices_do_append(char *key, char *value, void *data) +{ + struct remote_device_list_t *param = data; + char *address; + struct tm date; + + if (g_slist_find_custom(param->list, key, (GCompareFunc) strcasecmp)) + return; + + if (param->time){ + strptime(value, "%Y-%m-%d %H:%M:%S %Z", &date); + if (difftime(mktime(&date), param->time) < 0) + return; + } + + address = g_strdup(key); + + param->list = g_slist_append(param->list, address); +} + +static void remote_devices_do_append(void *data, void *user_data) +{ + DBusMessageIter *iter = user_data; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data); +} + +static DBusHandlerResult adapter_list_remote_devices(DBusConnection *conn, + DBusMessage *msg, + void *data) +{ + struct adapter *adapter = data; + DBusMessageIter iter; + DBusMessageIter array_iter; + DBusMessage *reply; + char filename[PATH_MAX + 1]; + struct remote_device_list_t param = { NULL, 0 }; + + if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) + return error_invalid_arguments(conn, msg); + + /* Add Bonded devices to the list */ + create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "linkkeys"); + textfile_foreach(filename, list_remote_devices_do_append, ¶m); + + /* Add Trusted devices to the list */ + create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "trusts"); + textfile_foreach(filename, list_remote_devices_do_append, ¶m); + + /* Add Last Used devices to the list */ + create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "lastused"); + textfile_foreach(filename, list_remote_devices_do_append, ¶m); + + reply = dbus_message_new_method_return(msg); + + dbus_message_iter_init_append(reply, &iter); + + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_STRING_AS_STRING, &array_iter); + + g_slist_foreach(param.list, remote_devices_do_append, &array_iter); + + g_slist_foreach(param.list, (GFunc) free, NULL); + g_slist_free(param.list); + + dbus_message_iter_close_container(&iter, &array_iter); + + return send_message_and_unref(conn, reply); +} + +static void append_connected(struct active_conn_info *dev, GSList *list) +{ + char address[18]; + + ba2str(&dev->bdaddr, address); + if (g_slist_find_custom(list, address, (GCompareFunc) strcasecmp)) + return; + + list = g_slist_append(list, g_strdup(address)); +} + +static DBusHandlerResult adapter_list_recent_remote_devices(DBusConnection *conn, + DBusMessage *msg, + void *data) +{ + struct adapter *adapter = data; + struct tm date; + const char *string; + DBusMessageIter iter; + DBusMessageIter array_iter; + DBusMessage *reply; + char filename[PATH_MAX + 1]; + struct remote_device_list_t param = { NULL, 0 }; + int len; + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &string, + DBUS_TYPE_INVALID)) + return error_invalid_arguments(conn, msg); + + /* Date format is "YYYY-MM-DD HH:MM:SS GMT" */ + len = strlen(string); + if (len && (strptime(string, "%Y-%m-%d %H:%M:%S", &date) == NULL)) + return error_invalid_arguments(conn, msg); + + /* Bonded and trusted: mandatory entries(no matter the date/time) */ + create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "linkkeys"); + textfile_foreach(filename, list_remote_devices_do_append, ¶m); + + create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "trusts"); + textfile_foreach(filename, list_remote_devices_do_append, ¶m); + + /* Last seen/used: append devices since the date informed */ + if (len) + param.time = mktime(&date); + + create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "lastseen"); + textfile_foreach(filename, list_remote_devices_do_append, ¶m); + + create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "lastused"); + textfile_foreach(filename, list_remote_devices_do_append, ¶m); + + /* connected: force appending connected devices, lastused might not match */ + g_slist_foreach(adapter->active_conn, (GFunc) append_connected, param.list); + + reply = dbus_message_new_method_return(msg); + + dbus_message_iter_init_append(reply, &iter); + + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_STRING_AS_STRING, &array_iter); + + g_slist_foreach(param.list, remote_devices_do_append, &array_iter); + + g_slist_foreach(param.list, (GFunc) free, NULL); + g_slist_free(param.list); + + dbus_message_iter_close_container(&iter, &array_iter); + + return send_message_and_unref(conn, reply); +} + + +static DBusHandlerResult adapter_set_trusted(DBusConnection *conn, + DBusMessage *msg, + void *data) +{ + struct adapter *adapter = data; + DBusMessage *reply; + bdaddr_t local; + const char *address; + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &address, + DBUS_TYPE_INVALID)) + return error_invalid_arguments(conn, msg); + + if (check_address(address) < 0) + return error_invalid_arguments(conn, msg); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + str2ba(adapter->address, &local); + + write_trust(&local, address, GLOBAL_TRUST, TRUE); + + dbus_connection_emit_signal(conn, dbus_message_get_path(msg), + ADAPTER_INTERFACE, "TrustAdded", + DBUS_TYPE_STRING, &address, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_is_trusted(DBusConnection *conn, + DBusMessage *msg, + void *data) +{ + struct adapter *adapter = data; + DBusMessage *reply; + const char *address; + dbus_bool_t trusted; + bdaddr_t local; + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &address, + DBUS_TYPE_INVALID)) + return error_invalid_arguments(conn, msg); + + if (check_address(address) < 0) + return error_invalid_arguments(conn, msg); + + str2ba(adapter->address, &local); + + trusted = read_trust(&local, address, GLOBAL_TRUST); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, + DBUS_TYPE_BOOLEAN, &trusted, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_remove_trust(DBusConnection *conn, + DBusMessage *msg, + void *data) +{ + struct adapter *adapter = data; + DBusMessage *reply; + const char *address; + bdaddr_t local; + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &address, + DBUS_TYPE_INVALID)) + return error_invalid_arguments(conn, msg); + + if (check_address(address) < 0) + return error_invalid_arguments(conn, msg); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + str2ba(adapter->address, &local); + + write_trust(&local, address, GLOBAL_TRUST, FALSE); + + dbus_connection_emit_signal(conn, dbus_message_get_path(msg), + ADAPTER_INTERFACE, "TrustRemoved", + DBUS_TYPE_STRING, &address, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult adapter_list_trusts(DBusConnection *conn, + DBusMessage *msg, + void *data) +{ + struct adapter *adapter = data; + DBusMessage *reply; + GSList *trusts, *l; + char **addrs; + bdaddr_t local; + int len; + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + str2ba(adapter->address, &local); + + trusts = list_trusts(&local, GLOBAL_TRUST); + + addrs = g_new(char *, g_slist_length(trusts)); + + for (l = trusts, len = 0; l; l = l->next, len++) + addrs[len] = l->data; + + dbus_message_append_args(reply, + DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, + &addrs, len, + DBUS_TYPE_INVALID); + + g_free(addrs); + g_slist_foreach(trusts, (GFunc) g_free, NULL); + g_slist_free(trusts); + + return send_message_and_unref(conn, reply); +} + +const char *major_class_str(uint32_t class) +{ + uint8_t index = (class >> 8) & 0x1F; + + if (index > 8) + return major_cls[9]; /* uncategorized */ + + return major_cls[index]; +} + +const char *minor_class_str(uint32_t class) +{ + uint8_t major_index = (class >> 8) & 0x1F; + uint8_t minor_index; + + switch (major_index) { + case 1: /* computer */ + minor_index = (class >> 2) & 0x3F; + if (minor_index < NUM_ELEMENTS(computer_minor_cls)) + return computer_minor_cls[minor_index]; + else + return ""; + case 2: /* phone */ + minor_index = (class >> 2) & 0x3F; + if (minor_index < NUM_ELEMENTS(phone_minor_cls)) + return phone_minor_cls[minor_index]; + return ""; + case 3: /* access point */ + minor_index = (class >> 5) & 0x07; + if (minor_index < NUM_ELEMENTS(access_point_minor_cls)) + return access_point_minor_cls[minor_index]; + else + return ""; + case 4: /* audio/video */ + minor_index = (class >> 2) & 0x3F; + if (minor_index < NUM_ELEMENTS(audio_video_minor_cls)) + return audio_video_minor_cls[minor_index]; + else + return ""; + case 5: /* peripheral */ + minor_index = (class >> 6) & 0x03; + if (minor_index < NUM_ELEMENTS(peripheral_minor_cls)) + return peripheral_minor_cls[minor_index]; + else + return ""; + case 6: /* imaging */ + { + uint8_t shift_minor = 0; + + minor_index = (class >> 4) & 0x0F; + while (shift_minor < (sizeof(imaging_minor_cls) / sizeof(*imaging_minor_cls))) { + if (((minor_index >> shift_minor) & 0x01) == 0x01) + return imaging_minor_cls[shift_minor]; + shift_minor++; + } + } + break; + case 7: /* wearable */ + minor_index = (class >> 2) & 0x3F; + if (minor_index < NUM_ELEMENTS(wearable_minor_cls)) + return wearable_minor_cls[minor_index]; + else + return ""; + case 8: /* toy */ + minor_index = (class >> 2) & 0x3F; + if (minor_index < NUM_ELEMENTS(toy_minor_cls)) + return toy_minor_cls[minor_index]; + else + return ""; + } + + return ""; +} + +GSList *service_classes_str(uint32_t class) +{ + uint8_t services = class >> 16; + GSList *l = NULL; + int i; + + for (i = 0; i < (sizeof(service_cls) / sizeof(*service_cls)); i++) { + if (!(services & (1 << i))) + continue; + + l = g_slist_append(l, (void *) service_cls[i]); + } + + return l; +} + +static DBusMethodVTable adapter_methods[] = { + { "GetInfo", adapter_get_info, + "", "{sv}" }, + { "GetAddress", adapter_get_address, + "", "s" }, + { "GetVersion", adapter_get_version, + "", "s" }, + { "GetRevision", adapter_get_revision, + "", "s" }, + { "GetManufacturer", adapter_get_manufacturer, + "", "s" }, + { "GetCompany", adapter_get_company, + "", "s" }, + { "ListAvailableModes", adapter_list_modes, + "", "as" }, + { "GetMode", adapter_get_mode, + "", "s" }, + { "SetMode", adapter_set_mode, + "s", "" }, + { "GetDiscoverableTimeout", adapter_get_discoverable_to, + "", "u" }, + { "SetDiscoverableTimeout", adapter_set_discoverable_to, + "u", "" }, + { "IsConnectable", adapter_is_connectable, + "", "b" }, + { "IsDiscoverable", adapter_is_discoverable, + "", "b" }, + { "IsConnected", adapter_is_connected, + "s", "b" }, + { "ListConnections", adapter_list_connections, + "", "as" }, + { "GetMajorClass", adapter_get_major_class, + "", "s" }, + { "ListAvailableMinorClasses", adapter_list_minor_classes, + "", "as" }, + { "GetMinorClass", adapter_get_minor_class, + "", "s" }, + { "SetMinorClass", adapter_set_minor_class, + "s", "" }, + { "GetServiceClasses", adapter_get_service_classes, + "", "as" }, + { "GetName", adapter_get_name, + "", "s" }, + { "SetName", adapter_set_name, + "s", "" }, + + { "GetRemoteInfo", adapter_get_remote_info, + "s", "{sv}" }, + { "GetRemoteServiceRecord", adapter_get_remote_svc, + "su", "ay" }, + { "GetRemoteServiceRecordAsXML", adapter_get_remote_svc_xml, + "su", "s" }, + { "GetRemoteServiceHandles", adapter_get_remote_svc_handles, + "ss", "au" }, + { "GetRemoteServiceIdentifiers", adapter_get_remote_svc_identifiers, + "s", "as" }, + { "FinishRemoteServiceTransaction", adapter_finish_sdp_transact, + "s", "" }, + + { "GetRemoteVersion", adapter_get_remote_version, + "s", "s" }, + { "GetRemoteRevision", adapter_get_remote_revision, + "s", "s" }, + { "GetRemoteManufacturer", adapter_get_remote_manufacturer, + "s", "s" }, + { "GetRemoteCompany", adapter_get_remote_company, + "s", "s" }, + { "GetRemoteMajorClass", adapter_get_remote_major_class, + "s", "s" }, + { "GetRemoteMinorClass", adapter_get_remote_minor_class, + "s", "s" }, + { "GetRemoteServiceClasses", adapter_get_remote_service_cls, + "s", "as" }, + { "GetRemoteClass", adapter_get_remote_class, + "s", "u" }, + { "GetRemoteFeatures", adapter_get_remote_features, + "s", "ay" }, + { "GetRemoteName", adapter_get_remote_name, + "s", "s" }, + { "GetRemoteAlias", adapter_get_remote_alias, + "s", "s" }, + { "SetRemoteAlias", adapter_set_remote_alias, + "ss", "" }, + { "ClearRemoteAlias", adapter_clear_remote_alias, + "s", "" }, + + { "LastSeen", adapter_last_seen, + "s", "s" }, + { "LastUsed", adapter_last_used, + "s", "s" }, + + { "DisconnectRemoteDevice", adapter_dc_remote_device, + "s", "" }, + + { "CreateBonding", adapter_create_bonding, + "s", "" }, + { "CancelBondingProcess", adapter_cancel_bonding, + "s", "" }, + { "RemoveBonding", adapter_remove_bonding, + "s", "" }, + { "HasBonding", adapter_has_bonding, + "s", "b" }, + { "ListBondings", adapter_list_bondings, + "", "as" }, + { "GetPinCodeLength", adapter_get_pin_code_length, + "s", "y" }, + { "GetEncryptionKeySize", adapter_get_encryption_key_size, + "s", "y" }, + + { "StartPeriodicDiscovery", adapter_start_periodic, + "", "" }, + { "StopPeriodicDiscovery", adapter_stop_periodic, + "", "" }, + { "IsPeriodicDiscovery", adapter_is_periodic, + "", "b" }, + { "SetPeriodicDiscoveryNameResolving", adapter_set_pdiscov_resolve, + "b", "" }, + { "GetPeriodicDiscoveryNameResolving", adapter_get_pdiscov_resolve, + "", "b" }, + + { "DiscoverDevices", adapter_discover_devices, + "", "" }, + { "DiscoverDevicesWithoutNameResolving", adapter_discover_devices, + "", "" }, + { "CancelDiscovery", adapter_cancel_discovery, + "", "" }, + + { "ListRemoteDevices", adapter_list_remote_devices, + "", "as" }, + { "ListRecentRemoteDevices", adapter_list_recent_remote_devices, + "s", "as" }, + + { "SetTrusted", adapter_set_trusted, + "s", "" }, + { "IsTrusted", adapter_is_trusted, + "s", "b" }, + { "RemoveTrust", adapter_remove_trust, + "s", "" }, + { "ListTrusts", adapter_list_trusts, + "", "as" }, + + { NULL, NULL, NULL, NULL } +}; + +static DBusSignalVTable adapter_signals[] = { + { "ModeChanged", "s" }, + { "DiscoverableTimeoutChanged", "u" }, + { "MinorClassChanged", "s" }, + { "NameChanged", "s" }, + { "DiscoveryStarted", "" }, + { "DiscoveryCompleted", "" }, + { "PeriodicDiscoveryStarted", "" }, + { "PeriodicDiscoveryStopped", "" }, + { "RemoteDeviceFound", "sun" }, + { "RemoteDeviceDisappeared", "s" }, + { "RemoteClassUpdated", "su" }, + { "RemoteNameUpdated", "ss" }, + { "RemoteNameFailed", "s" }, + { "RemoteNameRequested", "s" }, + { "RemoteAliasChanged", "ss" }, + { "RemoteAliasCleared", "s" }, + { "RemoteDeviceConnected", "s" }, + { "RemoteDeviceDisconnectRequested", "s" }, + { "RemoteDeviceDisconnected", "s" }, + { "RemoteIdentifiersUpdated", "sas" }, + { "BondingCreated", "s" }, + { "BondingRemoved", "s" }, + { "TrustAdded", "s" }, + { "TrustRemoved", "s" }, + { NULL, NULL } +}; + +dbus_bool_t adapter_init(DBusConnection *conn, const char *path) +{ + return dbus_connection_register_interface(conn, path, ADAPTER_INTERFACE, + adapter_methods, + adapter_signals, NULL); +} diff --git a/hcid/adapter.h b/hcid/adapter.h new file mode 100644 index 00000000..b48b7fac --- /dev/null +++ b/hcid/adapter.h @@ -0,0 +1,124 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2004-2007 Marcel Holtmann + * + * + * 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 + * + */ + +#include + +#define ADAPTER_INTERFACE "org.bluez.Adapter" + +#define INVALID_DEV_ID 0xFFFF + +#define BONDING_TIMEOUT 45000 /* 45 sec */ + +#define DC_PENDING_TIMEOUT 2000 /* 2 secs */ + +/* Discover types */ +#define DISCOVER_TYPE_NONE 0x00 +#define STD_INQUIRY 0x01 +#define PERIODIC_INQUIRY 0x02 + +/* Actions executed after inquiry complete */ +#define RESOLVE_NAME 0x10 + +typedef enum { + NAME_ANY, + NAME_NOT_REQUIRED, /* used by get remote name without name resolving */ + NAME_REQUIRED, /* remote name needs be resolved */ + NAME_REQUESTED, /* HCI remote name request was sent */ + NAME_SENT /* D-Bus signal RemoteNameUpdated sent */ +} name_status_t; + +struct remote_dev_info { + bdaddr_t bdaddr; + int8_t rssi; + name_status_t name_status; +}; + +struct bonding_request_info { + bdaddr_t bdaddr; + DBusConnection *conn; + DBusMessage *rq; + GIOChannel *io; + guint io_id; + int hci_status; + int cancel; + int auth_active; +}; + +struct pending_pin_info { + bdaddr_t bdaddr; + int replied; /* If we've already replied to the request */ +}; + +struct active_conn_info { + bdaddr_t bdaddr; + uint16_t handle; +}; + +struct pending_dc_info { + DBusConnection *conn; + DBusMessage *msg; + uint16_t conn_handle; + guint timeout_id; +}; + +struct adapter { + uint16_t dev_id; + int up; + char address[18]; /* adapter Bluetooth Address */ + guint timeout_id; /* discoverable timeout id */ + uint32_t discov_timeout; /* discoverable time(msec) */ + uint8_t scan_enable; /* scan mode: SCAN_DISABLED, SCAN_PAGE, SCAN_INQUIRY */ + uint8_t mode; /* off, connectable, discoverable, limited */ + uint8_t class[3]; /* device class */ + int discov_active; /* standard discovery active: includes name resolution step */ + int pdiscov_active; /* periodic discovery active */ + int pinq_idle; /* tracks the idle time for periodic inquiry */ + int discov_type; /* type requested */ + int pdiscov_resolve_names; /* Resolve names when doing periodic discovery */ + GSList *found_devices; + GSList *oor_devices; /* out of range device list */ + char *pdiscov_requestor; /* periodic discovery requestor unique name */ + char *discov_requestor; /* discovery requestor unique name */ + DBusMessage *discovery_cancel; /* discovery cancel message request */ + GSList *passkey_agents; + GSList *auth_agents; /* Authorization agents */ + bdaddr_t agents_disabled; /* temporarely disable agents for bda */ + GSList *active_conn; + struct bonding_request_info *bonding; + GSList *pin_reqs; + struct pending_dc_info *pending_dc; +}; + +dbus_bool_t adapter_init(DBusConnection *conn, const char *path); + +const char *major_class_str(uint32_t class); + +const char *minor_class_str(uint32_t class); + +const char *mode2str(uint8_t mode); + +GSList *service_classes_str(uint32_t class); + +int pending_remote_name_cancel(struct adapter *adapter); + +void dc_pending_timeout_cleanup(struct adapter *adapter); diff --git a/hcid/dbus-adapter.c b/hcid/dbus-adapter.c deleted file mode 100644 index 16bdc20f..00000000 --- a/hcid/dbus-adapter.c +++ /dev/null @@ -1,3368 +0,0 @@ -/* - * - * BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2004-2007 Marcel Holtmann - * - * - * 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 -#endif - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include - -#include "hcid.h" -#include "dbus.h" -#include "dbus-adapter.h" - -#include "textfile.h" -#include "oui.h" -#include "dbus-common.h" -#include "dbus-helper.h" -#include "dbus-hci.h" -#include "dbus-sdp.h" -#include "dbus-error.h" -#include "dbus-adapter.h" - -#define NUM_ELEMENTS(table) (sizeof(table)/sizeof(const char *)) - -static const char *service_cls[] = { - "positioning", - "networking", - "rendering", - "capturing", - "object transfer", - "audio", - "telephony", - "information" -}; - -static const char *major_cls[] = { - "miscellaneous", - "computer", - "phone", - "access point", - "audio/video", - "peripheral", - "imaging", - "wearable", - "toy", - "uncategorized" -}; - -static const char *computer_minor_cls[] = { - "uncategorized", - "desktop", - "server", - "laptop", - "handheld", - "palm", - "wearable" -}; - -static const char *phone_minor_cls[] = { - "uncategorized", - "cellular", - "cordless", - "smart phone", - "modem", - "isdn" -}; - -static const char *access_point_minor_cls[] = { - "fully", - "1-17 percent", - "17-33 percent", - "33-50 percent", - "50-67 percent", - "67-83 percent", - "83-99 percent", - "not available" -}; - -static const char *audio_video_minor_cls[] = { - "uncategorized", - "headset", - "handsfree", - "unknown", - "microphone", - "loudspeaker", - "headphones", - "portable audio", - "car audio", - "set-top box", - "hifi audio", - "vcr", - "video camera", - "camcorder", - "video monitor", - "video display and loudspeaker", - "video conferencing", - "unknown", - "gaming/toy" -}; - -static const char *peripheral_minor_cls[] = { - "uncategorized", - "keyboard", - "pointing", - "combo" -}; - -#if 0 -static const char *peripheral_2_minor_cls[] = { - "uncategorized", - "joystick", - "gamepad", - "remote control", - "sensing", - "digitizer tablet", - "card reader" -}; -#endif - -static const char *imaging_minor_cls[] = { - "display", - "camera", - "scanner", - "printer" -}; - -static const char *wearable_minor_cls[] = { - "wrist watch", - "pager", - "jacket", - "helmet", - "glasses" -}; - -static const char *toy_minor_cls[] = { - "robot", - "vehicle", - "doll", - "controller", - "game" -}; - -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 struct bonding_request_info *bonding_request_new(bdaddr_t *peer, - DBusConnection *conn, - DBusMessage *msg) -{ - struct bonding_request_info *bonding; - - bonding = g_new0(struct bonding_request_info, 1); - - bacpy(&bonding->bdaddr, peer); - - bonding->conn = dbus_connection_ref(conn); - bonding->rq = dbus_message_ref(msg); - - 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"; - } -} - -uint8_t str2mode(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 - return MODE_UNKNOWN; -} - -static DBusHandlerResult adapter_get_info(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - const char *property = adapter->address; - DBusMessage *reply; - DBusMessageIter iter; - DBusMessageIter dict; - bdaddr_t ba; - char str[249]; - uint8_t cls[3]; - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - 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); - - dbus_message_iter_append_dict_entry(&dict, "address", - DBUS_TYPE_STRING, &property); - - 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); - - get_device_version(adapter->dev_id, str, sizeof(str)); - dbus_message_iter_append_dict_entry(&dict, "version", - DBUS_TYPE_STRING, &property); - - get_device_revision(adapter->dev_id, str, sizeof(str)); - dbus_message_iter_append_dict_entry(&dict, "revision", - DBUS_TYPE_STRING, &property); - - get_device_manufacturer(adapter->dev_id, str, sizeof(str)); - dbus_message_iter_append_dict_entry(&dict, "manufacturer", - DBUS_TYPE_STRING, &property); - - get_device_company(adapter->dev_id, str, sizeof(str)); - dbus_message_iter_append_dict_entry(&dict, "company", - DBUS_TYPE_STRING, &property); - - property = mode2str(adapter->mode); - - dbus_message_iter_append_dict_entry(&dict, "mode", - DBUS_TYPE_STRING, &property); - - dbus_message_iter_append_dict_entry(&dict, "discoverable_timeout", - DBUS_TYPE_UINT32, &adapter->discov_timeout); - - if (!read_local_class(&ba, cls)) { - uint32_t class; - - memcpy(&class, cls, 3); - dbus_message_iter_append_dict_entry(&dict, "class", - DBUS_TYPE_UINT32, &class); - - property = major_class_str(class); - dbus_message_iter_append_dict_entry(&dict, "major_class", - DBUS_TYPE_STRING, &property); - - property = minor_class_str(class); - dbus_message_iter_append_dict_entry(&dict, "minor_class", - DBUS_TYPE_STRING, &property); - } - - dbus_message_iter_close_container(&iter, &dict); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_get_address(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - const char *paddr = adapter->address; - DBusMessage *reply; - - if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) - return error_invalid_arguments(conn, msg); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_append_args(reply, DBUS_TYPE_STRING, &paddr, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_get_version(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - DBusMessage *reply; - char str[20], *str_ptr = str; - int err; - - if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) - return error_invalid_arguments(conn, msg); - - err = get_device_version(adapter->dev_id, str, sizeof(str)); - if (err < 0) - return error_failed(conn, msg, -err); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_get_revision(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - DBusMessage *reply; - char str[64], *str_ptr = str; - int err; - - if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) - return error_invalid_arguments(conn, msg); - - err = get_device_revision(adapter->dev_id, str, sizeof(str)); - if (err < 0) - return error_failed(conn, msg, -err); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_get_manufacturer(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - DBusMessage *reply; - char str[64], *str_ptr = str; - int err; - - if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) - return error_invalid_arguments(conn, msg); - - err = get_device_manufacturer(adapter->dev_id, str, sizeof(str)); - if (err < 0) - return error_failed(conn, msg, -err); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_get_company(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - DBusMessage *reply; - char str[64], *str_ptr = str; - int err; - - if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) - return error_invalid_arguments(conn, msg); - - err = get_device_company(adapter->dev_id, str, sizeof(str)); - if (err < 0) - return error_failed(conn, msg, -err); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_list_modes(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - DBusMessage *reply; - DBusMessageIter iter; - DBusMessageIter array_iter; - const char *mode_ptr[] = { "off", "connectable", "discoverable", "limited" }; - int i; - - if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) - return error_invalid_arguments(conn, msg); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_iter_init_append(reply, &iter); - dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, - DBUS_TYPE_STRING_AS_STRING, &array_iter); - for (i = 0; i < 4; i++) - dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING, - &mode_ptr[i]); - - dbus_message_iter_close_container(&iter, &array_iter); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_get_mode(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - const struct adapter *adapter = data; - DBusMessage *reply = NULL; - const char *mode; - - if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) - return error_invalid_arguments(conn, msg); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - mode = mode2str(adapter->mode); - - dbus_message_append_args(reply, DBUS_TYPE_STRING, &mode, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_set_mode(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - DBusMessage *reply; - const char *mode; - uint8_t scan_enable; - uint8_t new_mode, current_scan = adapter->scan_enable; - bdaddr_t local; - gboolean limited; - int err, dd; - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &mode, - DBUS_TYPE_INVALID)) - return error_invalid_arguments(conn, msg); - - if (!mode) - return error_invalid_arguments(conn, msg); - - new_mode = str2mode(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 error_invalid_arguments(conn, msg); - } - - dd = hci_open_dev(adapter->dev_id); - if (dd < 0) - return error_no_such_adapter(conn, 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 error_failed(conn, 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 error_failed(conn, msg, errno); - } - - goto done; - } - - limited = (new_mode == MODE_LIMITED ? TRUE : FALSE); - err = set_limited_discoverable(dd, adapter->class, limited); - if (err < 0) { - hci_close_dev(dd); - return error_failed(conn, 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 error_failed(conn, msg, err); - } - - if (status) { - error("Setting scan enable failed with status 0x%02x", - status); - hci_close_dev(dd); - return error_failed(conn, msg, bt_error(status)); - } - } else { - /* discoverable or limited */ - if ((scan_enable & SCAN_INQUIRY) && (new_mode != adapter->mode)) { - dbus_connection_emit_signal(conn, - dbus_message_get_path(msg), - ADAPTER_INTERFACE, - "ModeChanged", - DBUS_TYPE_STRING, &mode, - DBUS_TYPE_INVALID); - - if (adapter->timeout_id) - g_source_remove(adapter->timeout_id); - - if (adapter->discov_timeout != 0) - adapter->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); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - adapter->mode = new_mode; - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_get_discoverable_to(DBusConnection *conn, - DBusMessage *msg, - void *data) -{ - const struct adapter *adapter = data; - DBusMessage *reply; - - if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) - return error_invalid_arguments(conn, msg); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_append_args(reply, DBUS_TYPE_UINT32, &adapter->discov_timeout, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_set_discoverable_to(DBusConnection *conn, - DBusMessage *msg, - void *data) -{ - struct adapter *adapter = data; - DBusMessage *reply; - uint32_t timeout; - bdaddr_t bdaddr; - - if (!adapter->up) - return error_not_ready(conn, msg); - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_UINT32, &timeout, - DBUS_TYPE_INVALID)) - return error_invalid_arguments(conn, msg); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - if (adapter->timeout_id) { - g_source_remove(adapter->timeout_id); - adapter->timeout_id = 0; - } - - if ((timeout != 0) && (adapter->scan_enable & SCAN_INQUIRY)) - adapter->timeout_id = g_timeout_add(timeout * 1000, - discov_timeout_handler, - adapter); - - adapter->discov_timeout = timeout; - - str2ba(adapter->address, &bdaddr); - write_discoverable_timeout(&bdaddr, timeout); - - dbus_connection_emit_signal(conn, dbus_message_get_path(msg), - ADAPTER_INTERFACE, - "DiscoverableTimeoutChanged", - DBUS_TYPE_UINT32, &timeout, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_is_connectable(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - const struct adapter *adapter = data; - DBusMessage *reply; - const uint8_t scan_enable = adapter->scan_enable; - dbus_bool_t connectable = FALSE; - - if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) - return error_invalid_arguments(conn, msg); - - if (scan_enable & SCAN_PAGE) - connectable = TRUE; - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connectable, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_is_discoverable(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - const struct adapter *adapter = data; - DBusMessage *reply; - const uint8_t scan_enable = adapter->scan_enable; - dbus_bool_t discoverable = FALSE; - - if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) - return error_invalid_arguments(conn, msg); - - if (scan_enable & SCAN_INQUIRY) - discoverable = TRUE; - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &discoverable, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_is_connected(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - DBusMessage *reply; - dbus_bool_t connected = FALSE; - - struct adapter *adapter = data; - GSList *l = adapter->active_conn; - - const char *peer_addr; - bdaddr_t peer_bdaddr; - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &peer_addr, - DBUS_TYPE_INVALID)) - return error_invalid_arguments(conn, msg); - - if (check_address(peer_addr) < 0) - return error_invalid_arguments(conn, msg); - - str2ba(peer_addr, &peer_bdaddr); - - l = g_slist_find_custom(l, &peer_bdaddr, active_conn_find_by_bdaddr); - if (l) - connected = TRUE; - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connected, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_list_connections(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - DBusMessage *reply; - DBusMessageIter iter; - DBusMessageIter array_iter; - struct adapter *adapter = data; - GSList *l = adapter->active_conn; - - if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) - return error_invalid_arguments(conn, msg); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_iter_init_append(reply, &iter); - dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, - DBUS_TYPE_STRING_AS_STRING, &array_iter); - - while (l) { - char peer_addr[18]; - const char *paddr = peer_addr; - struct active_conn_info *dev = l->data; - - ba2str(&dev->bdaddr, peer_addr); - - dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING, - &paddr); - - l = l->next; - } - - dbus_message_iter_close_container(&iter, &array_iter); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_get_major_class(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - const struct adapter *adapter = data; - DBusMessage *reply; - const char *str_ptr = "computer"; - - if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) - return error_invalid_arguments(conn, msg); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - /* FIXME: Currently, only computer major class is supported */ - if ((adapter->class[1] & 0x1f) != 1) - return error_unsupported_major_class(conn, msg); - - dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_list_minor_classes(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - const struct adapter *adapter = data; - DBusMessage *reply = NULL; - DBusMessageIter iter; - DBusMessageIter array_iter; - const char **minor_ptr; - uint8_t major_class; - int size, i; - - if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) - return error_invalid_arguments(conn, msg); - - major_class = adapter->class[1] & 0x1F; - - switch (major_class) { - case 1: /* computer */ - minor_ptr = computer_minor_cls; - size = sizeof(computer_minor_cls) / sizeof(*computer_minor_cls); - break; - case 2: /* phone */ - minor_ptr = phone_minor_cls; - size = sizeof(phone_minor_cls) / sizeof(*phone_minor_cls); - break; - default: - return error_unsupported_major_class(conn, msg); - } - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_iter_init_append(reply, &iter); - dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, - DBUS_TYPE_STRING_AS_STRING, &array_iter); - for (i = 0; i < size; i++) - dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING, - &minor_ptr[i]); - - dbus_message_iter_close_container(&iter, &array_iter); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_get_minor_class(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - DBusMessage *reply; - const char *str_ptr = ""; - uint8_t minor_class; - - if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) - return error_invalid_arguments(conn, msg); - - /* FIXME: Currently, only computer major class is supported */ - if ((adapter->class[1] & 0x1f) != 1) - return error_unsupported_major_class(conn, msg); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - minor_class = adapter->class[0] >> 2; - - /* Validate computer minor class */ - if (minor_class > (sizeof(computer_minor_cls) / sizeof(*computer_minor_cls))) - goto failed; - - str_ptr = computer_minor_cls[minor_class]; - -failed: - dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_set_minor_class(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - DBusMessage *reply; - const char *minor; - uint32_t dev_class = 0xFFFFFFFF; - int i, dd; - - if (!adapter->up) - return error_not_ready(conn, msg); - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &minor, - DBUS_TYPE_INVALID)) - return error_invalid_arguments(conn, msg); - - if (!minor) - return error_invalid_arguments(conn, msg); - - dd = hci_open_dev(adapter->dev_id); - if (dd < 0) - return error_no_such_adapter(conn, msg); - - /* Currently, only computer major class is supported */ - if ((adapter->class[1] & 0x1f) != 1) { - hci_close_dev(dd); - return error_unsupported_major_class(conn, msg); - } - for (i = 0; i < sizeof(computer_minor_cls) / sizeof(*computer_minor_cls); i++) - if (!strcasecmp(minor, computer_minor_cls[i])) { - /* Remove the format type */ - dev_class = i << 2; - break; - } - - /* Check if it's a valid minor class */ - if (dev_class == 0xFFFFFFFF) { - hci_close_dev(dd); - return error_invalid_arguments(conn, msg); - } - - /* set the service class and major class */ - dev_class |= (adapter->class[2] << 16) | (adapter->class[1] << 8); - - if (hci_write_class_of_dev(dd, dev_class, 2000) < 0) { - int err = errno; - error("Can't write class of device on hci%d: %s(%d)", - adapter->dev_id, strerror(errno), errno); - hci_close_dev(dd); - return error_failed(conn, msg, err); - } - - dbus_connection_emit_signal(conn, dbus_message_get_path(msg), - ADAPTER_INTERFACE, "MinorClassChanged", - DBUS_TYPE_STRING, &minor, - DBUS_TYPE_INVALID); - - reply = dbus_message_new_method_return(msg); - - hci_close_dev(dd); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_get_service_classes(DBusConnection *conn, - DBusMessage *msg, - void *data) -{ - struct adapter *adapter = data; - DBusMessage *reply; - DBusMessageIter iter; - DBusMessageIter array_iter; - const char *str_ptr; - int i; - - if (!adapter->up) - return error_not_ready(conn, msg); - - if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) - return error_invalid_arguments(conn, msg); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_iter_init_append(reply, &iter); - - dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, - DBUS_TYPE_STRING_AS_STRING, &array_iter); - - for (i = 0; i < (sizeof(service_cls) / sizeof(*service_cls)); i++) { - if (adapter->class[2] & (1 << i)) { - str_ptr = service_cls[i]; - dbus_message_iter_append_basic(&array_iter, - DBUS_TYPE_STRING, &str_ptr); - } - } - - dbus_message_iter_close_container(&iter, &array_iter); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_get_name(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - DBusMessage *reply; - char str[249], *str_ptr = str; - int err; - bdaddr_t ba; - - if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) - return error_invalid_arguments(conn, msg); - - str2ba(adapter->address, &ba); - - err = read_local_name(&ba, str); - if (err < 0) { - if (!adapter->up) - return error_not_ready(conn, msg); - - err = get_device_name(adapter->dev_id, str, sizeof(str)); - if (err < 0) - return error_failed(conn, msg, -err); - } - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_set_name(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - DBusMessage *reply; - bdaddr_t bdaddr; - char *str_ptr; - int ecode; - - if (!adapter->up) - return error_not_ready(conn, msg); - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &str_ptr, - DBUS_TYPE_INVALID)) - return error_invalid_arguments(conn, msg); - - if (!g_utf8_validate(str_ptr, -1, NULL)) { - error("Name change failed: the supplied name isn't valid UTF-8"); - return error_invalid_arguments(conn, msg); - } - - hci_devba(adapter->dev_id, &bdaddr); - - write_local_name(&bdaddr, str_ptr); - - ecode = set_device_name(adapter->dev_id, str_ptr); - if (ecode < 0) - return error_failed(conn, msg, -ecode); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_get_remote_info(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - DBusMessage *reply; - DBusMessageIter iter; - DBusMessageIter dict; - bdaddr_t src, dst; - const char *addr_ptr; - char filename[PATH_MAX + 1]; - char buf[64]; - const char *ptr; - char *str; - dbus_bool_t boolean; - uint32_t class; - int compid, ver, subver; - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &addr_ptr, - DBUS_TYPE_INVALID)) - return error_invalid_arguments(conn, msg); - - if (check_address(addr_ptr) < 0) - return error_invalid_arguments(conn, msg); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - 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); - - /* Name */ - create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "names"); - str = textfile_caseget(filename, addr_ptr); - if (str) { - dbus_message_iter_append_dict_entry(&dict, "name", - DBUS_TYPE_STRING, &str); - free(str); - } - - str2ba(adapter->address, &src); - str2ba(addr_ptr, &dst); - - /* Remote device class */ - if (read_remote_class(&src, &dst, &class) == 0) { - - dbus_message_iter_append_dict_entry(&dict, "class", - DBUS_TYPE_UINT32, &class); - - ptr = major_class_str(class); - dbus_message_iter_append_dict_entry(&dict, "major_class", - DBUS_TYPE_STRING, &ptr); - - ptr = minor_class_str(class); - dbus_message_iter_append_dict_entry(&dict, "minor_class", - DBUS_TYPE_STRING, &ptr); - } - - /* Alias */ - if (get_device_alias(adapter->dev_id, &dst, buf, sizeof(buf)) > 0) { - ptr = buf; - dbus_message_iter_append_dict_entry(&dict, "alias", - DBUS_TYPE_STRING, &ptr); - } - - /* Bonded */ - create_name(filename, PATH_MAX, STORAGEDIR, - adapter->address, "linkkeys"); - str = textfile_caseget(filename, addr_ptr); - if (str) { - boolean = TRUE; - free(str); - } else { - boolean = FALSE; - } - - dbus_message_iter_append_dict_entry(&dict, "bonded", - DBUS_TYPE_BOOLEAN, &boolean); - - /* Trusted */ - boolean = read_trust(&src, addr_ptr, GLOBAL_TRUST); - dbus_message_iter_append_dict_entry(&dict, "trusted", - DBUS_TYPE_BOOLEAN, &boolean); - - /* Connected */ - if (g_slist_find_custom(adapter->active_conn, &dst, - active_conn_find_by_bdaddr)) - boolean = TRUE; - else - boolean = FALSE; - - dbus_message_iter_append_dict_entry(&dict, "connected", - DBUS_TYPE_BOOLEAN, &boolean); - - /* HCI Revision/Manufacturer/Version */ - create_name(filename, PATH_MAX, STORAGEDIR, - adapter->address, "manufacturers"); - - str = textfile_caseget(filename, addr_ptr); - if (!str) - goto done; - - if (sscanf(str, "%d %d %d", &compid, &ver, &subver) != 3) { - /* corrupted file data */ - free(str); - goto done; - } - - free(str); - - ptr = buf; - snprintf(buf, 16, "HCI 0x%X", subver); - dbus_message_iter_append_dict_entry(&dict, "revision", - DBUS_TYPE_STRING, &ptr); - - ptr = bt_compidtostr(compid); - dbus_message_iter_append_dict_entry(&dict, "manufacturer", - DBUS_TYPE_STRING, &ptr); - - str = lmp_vertostr(ver); - snprintf(buf, 64, "Bluetooth %s", str); - bt_free(str); - - create_name(filename, PATH_MAX, STORAGEDIR, - adapter->address, "features"); - - str = textfile_caseget(filename, addr_ptr); - if (str) { - if (strlen(str) == 16) { - uint8_t features; - /* Getting the third byte */ - features = ((str[6] - 48) << 4) | (str[7] - 48); - if (features & (LMP_EDR_ACL_2M | LMP_EDR_ACL_3M)) - snprintf(buf, 64, "Bluetooth %s + EDR", ptr); - - } - free(str); - } - ptr = buf; - dbus_message_iter_append_dict_entry(&dict, "version", - DBUS_TYPE_STRING, &ptr); - -done: - dbus_message_iter_close_container(&iter, &dict); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_get_remote_svc(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - return get_remote_svc_rec(conn, msg, data, SDP_FORMAT_BINARY); -} - -static DBusHandlerResult adapter_get_remote_svc_xml(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - return get_remote_svc_rec(conn, msg, data, SDP_FORMAT_XML); -} - -static DBusHandlerResult adapter_get_remote_svc_handles(DBusConnection *conn, - DBusMessage *msg, - void *data) -{ - return get_remote_svc_handles(conn, msg, data); -} - -static DBusHandlerResult adapter_get_remote_svc_identifiers(DBusConnection *conn, - DBusMessage *msg, - void *data) -{ - return get_remote_svc_identifiers(conn, msg, data); -} - -static DBusHandlerResult adapter_finish_sdp_transact(DBusConnection *conn, - DBusMessage *msg, - void *data) -{ - return finish_remote_svc_transact(conn, msg, data); -} - -static DBusHandlerResult adapter_get_remote_version(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - DBusMessage *reply; - char filename[PATH_MAX + 1]; - char *addr_ptr, *str; - char *str_ver = NULL; - char info_array[64], *info = info_array; - int compid, ver, subver; - - memset(info_array, 0, 64); - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &addr_ptr, - DBUS_TYPE_INVALID)) - return error_invalid_arguments(conn, msg); - - if (check_address(addr_ptr) < 0) - return error_invalid_arguments(conn, msg); - - create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, - "manufacturers"); - - str = textfile_caseget(filename, addr_ptr); - if (!str) - return error_not_available(conn, msg); - - if (sscanf(str, "%d %d %d", &compid, &ver, &subver) != 3) { - /* corrupted file data */ - free(str); - goto failed; - } - - free(str); - - str_ver = lmp_vertostr(ver); - - /* Default value */ - snprintf(info, 64, "Bluetooth %s", str_ver); - - create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, - "features"); - - str = textfile_caseget(filename, addr_ptr); - if (!str) - goto failed; - - /* Check if the data is not corrupted */ - if (strlen(str) == 16) { - uint8_t features; - /* Getting the third byte */ - features = ((str[6] - 48) << 4) | (str[7] - 48); - if (features & (LMP_EDR_ACL_2M | LMP_EDR_ACL_3M)) - snprintf(info, 64, "Bluetooth %s + EDR", str_ver); - } - - free(str); - -failed: - if (str_ver) - bt_free(str_ver); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_append_args(reply, DBUS_TYPE_STRING, &info, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_get_remote_revision(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - DBusMessage *reply; - char filename[PATH_MAX + 1]; - char *addr_ptr, *str; - char info_array[16], *info = info_array; - int compid, ver, subver; - - memset(info_array, 0, 16); - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &addr_ptr, - DBUS_TYPE_INVALID)) - return error_invalid_arguments(conn, msg); - - if (check_address(addr_ptr) < 0) - return error_invalid_arguments(conn, msg); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, - "manufacturers"); - - str = textfile_caseget(filename, addr_ptr); - if (!str) - return error_not_available(conn, msg); - - if (sscanf(str, "%d %d %d", &compid, &ver, &subver) == 3) - snprintf(info, 16, "HCI 0x%X", subver); - - free(str); - - dbus_message_append_args(reply, DBUS_TYPE_STRING, &info, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_get_remote_manufacturer(DBusConnection *conn, - DBusMessage *msg, - void *data) -{ - struct adapter *adapter = data; - DBusMessage *reply; - char filename[PATH_MAX + 1]; - char *addr_ptr, *str; - char info_array[64], *info = info_array; - int compid, ver, subver; - - memset(info_array, 0, 64); - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &addr_ptr, - DBUS_TYPE_INVALID)) - return error_invalid_arguments(conn, msg); - - if (check_address(addr_ptr) < 0) - return error_invalid_arguments(conn, msg); - - create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, - "manufacturers"); - - str = textfile_caseget(filename, addr_ptr); - if (!str) - return error_not_available(conn, msg); - - if (sscanf(str, "%d %d %d", &compid, &ver, &subver) == 3) - info = bt_compidtostr(compid); - - free(str); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_append_args(reply, DBUS_TYPE_STRING, &info, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_get_remote_company(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - DBusMessage *reply; - bdaddr_t bdaddr; - char oui[9], *str_bdaddr, *tmp; - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &str_bdaddr, - DBUS_TYPE_INVALID)) - return error_invalid_arguments(conn, msg); - - str2ba(str_bdaddr, &bdaddr); - ba2oui(&bdaddr, oui); - - tmp = ouitocomp(oui); - if (!tmp) - return error_not_available(conn, msg); - - reply = dbus_message_new_method_return(msg); - if (!reply) { - free(tmp); - return DBUS_HANDLER_RESULT_NEED_MEMORY; - } - - dbus_message_append_args(reply, DBUS_TYPE_STRING, &tmp, - DBUS_TYPE_INVALID); - - free(tmp); - - return send_message_and_unref(conn, reply); -} - -static int get_remote_class(DBusConnection *conn, DBusMessage *msg, void *data, - uint32_t *class) -{ - struct adapter *adapter = data; - char *addr_peer; - bdaddr_t local, peer; - int ecode; - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &addr_peer, - DBUS_TYPE_INVALID)) { - error_invalid_arguments(conn, msg); - return -1; - } - - if (check_address(addr_peer) < 0) { - error_invalid_arguments(conn, msg); - return -1; - } - - str2ba(addr_peer, &peer); - str2ba(adapter->address, &local); - - ecode = read_remote_class(&local, &peer, class); - if (ecode < 0) { - error_not_available(conn, msg); - return -1; - } - - return 0; -} - -static DBusHandlerResult adapter_get_remote_major_class(DBusConnection *conn, - DBusMessage *msg, - void *data) -{ - DBusMessage *reply; - const char *major_class; - uint32_t class; - - if (get_remote_class(conn, msg, data, &class) < 0) - return DBUS_HANDLER_RESULT_HANDLED; - - major_class = major_class_str(class); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_append_args(reply, DBUS_TYPE_STRING, &major_class, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_get_remote_minor_class(DBusConnection *conn, - DBusMessage *msg, - void *data) -{ - DBusMessage *reply; - const char *minor_class; - uint32_t class; - - if (get_remote_class(conn, msg, data, &class) < 0) - return DBUS_HANDLER_RESULT_HANDLED; - - minor_class = minor_class_str(class); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_append_args(reply, DBUS_TYPE_STRING, &minor_class, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static void append_class_string(const char *class, DBusMessageIter *iter) -{ - dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &class); -} - -static DBusHandlerResult adapter_get_remote_service_cls(DBusConnection *conn, - DBusMessage *msg, - void *data) -{ - DBusMessage *reply; - DBusMessageIter iter, array_iter; - GSList *service_classes; - uint32_t class; - - if (get_remote_class(conn, msg, data, &class) < 0) - return DBUS_HANDLER_RESULT_HANDLED; - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - service_classes = service_classes_str(class); - - dbus_message_iter_init_append(reply, &iter); - dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, - DBUS_TYPE_STRING_AS_STRING, &array_iter); - - g_slist_foreach(service_classes, (GFunc) append_class_string, - &array_iter); - - dbus_message_iter_close_container(&iter, &array_iter); - - g_slist_free(service_classes); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_get_remote_class(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - DBusMessage *reply; - uint32_t class; - - if (get_remote_class(conn, msg, data, &class) < 0) - return DBUS_HANDLER_RESULT_HANDLED; - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_append_args(reply, DBUS_TYPE_UINT32, &class, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_get_remote_features(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - char filename[PATH_MAX + 1]; - struct adapter *adapter = data; - DBusMessage *reply = NULL; - DBusMessageIter iter, array_iter; - uint8_t features[8], *ptr = features; - const char *addr; - char *str; - int i; - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &addr, - DBUS_TYPE_INVALID)) - return error_invalid_arguments(conn, msg); - - if (check_address(addr) < 0) - return error_invalid_arguments(conn, msg); - - create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "features"); - - str = textfile_caseget(filename, addr); - if (!str) - return error_not_available(conn, msg); - - memset(features, 0, sizeof(features)); - for (i = 0; i < sizeof(features); i++) { - char tmp[3]; - - memcpy(tmp, str + (i * 2), 2); - tmp[2] = '\0'; - - features[i] = (uint8_t) strtol(tmp, NULL, 16); - } - - reply = dbus_message_new_method_return(msg); - if (!reply) { - free(str); - return DBUS_HANDLER_RESULT_NEED_MEMORY; - } - - dbus_message_iter_init_append(reply, &iter); - dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, - DBUS_TYPE_BYTE_AS_STRING, &array_iter); - - dbus_message_iter_append_fixed_array(&array_iter, - DBUS_TYPE_BYTE, &ptr, sizeof(features)); - - dbus_message_iter_close_container(&iter, &array_iter); - - free(str); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_get_remote_name(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - char filename[PATH_MAX + 1]; - struct adapter *adapter = data; - DBusMessage *reply = NULL; - const char *peer_addr; - bdaddr_t peer_bdaddr; - char *str; - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &peer_addr, - DBUS_TYPE_INVALID)) - return error_invalid_arguments(conn, msg); - - if (check_address(peer_addr) < 0) - return error_invalid_arguments(conn, msg); - - /* check if it is in the cache */ - create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "names"); - - str = textfile_caseget(filename, peer_addr); - - if (str) { - reply = dbus_message_new_method_return(msg); - if (!reply) { - free(str); - return DBUS_HANDLER_RESULT_NEED_MEMORY; - } - - /* send the cached name */ - dbus_message_append_args(reply, DBUS_TYPE_STRING, &str, - DBUS_TYPE_INVALID); - - free(str); - return send_message_and_unref(conn, reply); - } - - if (!adapter->up) - return error_not_ready(conn, msg); - - /* If the discover process is not running, return an error */ - if (!adapter->discov_active && !adapter->pdiscov_active) - return error_not_available(conn, msg); - - /* Queue the request when there is a discovery running */ - str2ba(peer_addr, &peer_bdaddr); - found_device_add(&adapter->found_devices, &peer_bdaddr, 0, NAME_REQUIRED); - - return error_request_deferred(conn, msg); -} - -static DBusHandlerResult adapter_get_remote_alias(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - DBusMessage *reply; - char str[249], *str_ptr = str, *addr_ptr; - bdaddr_t bdaddr; - int ecode; - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &addr_ptr, - DBUS_TYPE_INVALID)) - return error_invalid_arguments(conn, msg); - - if (check_address(addr_ptr) < 0) - return error_invalid_arguments(conn, msg); - - str2ba(addr_ptr, &bdaddr); - - ecode = get_device_alias(adapter->dev_id, &bdaddr, str, sizeof(str)); - if (ecode < 0) - return error_not_available(conn, msg); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_set_remote_alias(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - DBusMessage *reply; - char *alias, *addr; - bdaddr_t bdaddr; - int ecode; - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &addr, - DBUS_TYPE_STRING, &alias, - DBUS_TYPE_INVALID)) - return error_invalid_arguments(conn, msg); - - if ((strlen(alias) == 0) || (check_address(addr) < 0)) { - error("Alias change failed: Invalid parameter"); - return error_invalid_arguments(conn, msg); - } - - str2ba(addr, &bdaddr); - - ecode = set_device_alias(adapter->dev_id, &bdaddr, alias); - if (ecode < 0) - return error_failed(conn, msg, -ecode); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_connection_emit_signal(conn, dbus_message_get_path(msg), - ADAPTER_INTERFACE, "RemoteAliasChanged", - DBUS_TYPE_STRING, &addr, - DBUS_TYPE_STRING, &alias, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_clear_remote_alias(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - DBusMessage *reply; - char *addr_ptr; - bdaddr_t bdaddr; - int ecode, had_alias = 1; - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &addr_ptr, - DBUS_TYPE_INVALID)) - return error_invalid_arguments(conn, msg); - - if (check_address(addr_ptr) < 0) { - error("Alias clear failed: Invalid parameter"); - return error_invalid_arguments(conn, msg); - } - - str2ba(addr_ptr, &bdaddr); - - ecode = get_device_alias(adapter->dev_id, &bdaddr, NULL, 0); - if (ecode == -ENXIO) - had_alias = 0; - - ecode = set_device_alias(adapter->dev_id, &bdaddr, NULL); - if (ecode < 0) - return error_failed(conn, msg, -ecode); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - if (had_alias) - dbus_connection_emit_signal(conn, dbus_message_get_path(msg), - ADAPTER_INTERFACE, - "RemoteAliasCleared", - DBUS_TYPE_STRING, &addr_ptr, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_last_seen(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - DBusMessage *reply; - char filename[PATH_MAX + 1]; - char *addr_ptr, *str; - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &addr_ptr, - DBUS_TYPE_INVALID)) - return error_invalid_arguments(conn, msg); - - if (check_address(addr_ptr) < 0) - return error_invalid_arguments(conn, msg); - - create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, - "lastseen"); - - str = textfile_caseget(filename, addr_ptr); - if (!str) - return error_not_available(conn, msg); - - reply = dbus_message_new_method_return(msg); - if (!reply) { - free(str); - return DBUS_HANDLER_RESULT_NEED_MEMORY; - } - - dbus_message_append_args(reply, DBUS_TYPE_STRING, &str, - DBUS_TYPE_INVALID); - - free(str); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_last_used(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - DBusMessage *reply; - char filename[PATH_MAX + 1]; - char *addr_ptr, *str; - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &addr_ptr, - DBUS_TYPE_INVALID)) - return error_invalid_arguments(conn, msg); - - if (check_address(addr_ptr) < 0) - return error_invalid_arguments(conn, msg); - - create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, - "lastused"); - - str = textfile_caseget(filename, addr_ptr); - if (!str) - return error_not_available(conn, msg); - - reply = dbus_message_new_method_return(msg); - if (!reply) { - free(str); - return DBUS_HANDLER_RESULT_NEED_MEMORY; - } - - dbus_message_append_args(reply, DBUS_TYPE_STRING, &str, - DBUS_TYPE_INVALID); - - free(str); - - return send_message_and_unref(conn, reply); -} - - -gboolean dc_pending_timeout_handler(void *data) -{ - int dd; - struct adapter *adapter = data; - struct pending_dc_info *pending_dc = adapter->pending_dc; - DBusMessage *reply; - - dd = hci_open_dev(adapter->dev_id); - - if (dd < 0) { - error_no_such_adapter(pending_dc->conn, - pending_dc->msg); - dc_pending_timeout_cleanup(adapter); - return FALSE; - } - - /* Send the HCI disconnect command */ - if (hci_disconnect(dd, pending_dc->conn_handle, - HCI_OE_USER_ENDED_CONNECTION, - 500) < 0) { - int err = errno; - error("Disconnect failed"); - error_failed(pending_dc->conn, pending_dc->msg, err); - } else { - reply = dbus_message_new_method_return(pending_dc->msg); - if (!reply) - error("Failed to allocate disconnect reply"); - else - send_message_and_unref(pending_dc->conn, reply); - } - - hci_close_dev(dd); - dc_pending_timeout_cleanup(adapter); - - return FALSE; -} - -void dc_pending_timeout_cleanup(struct adapter *adapter) -{ - dbus_connection_unref(adapter->pending_dc->conn); - dbus_message_unref(adapter->pending_dc->msg); - g_free(adapter->pending_dc); - adapter->pending_dc = NULL; -} - -static DBusHandlerResult adapter_dc_remote_device(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - GSList *l = adapter->active_conn; - const char *peer_addr; - bdaddr_t peer_bdaddr; - - if (!adapter->up) - return error_not_ready(conn, msg); - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &peer_addr, - DBUS_TYPE_INVALID)) - return error_invalid_arguments(conn, msg); - - if (check_address(peer_addr) < 0) - return error_invalid_arguments(conn, msg); - - str2ba(peer_addr, &peer_bdaddr); - - l = g_slist_find_custom(l, &peer_bdaddr, active_conn_find_by_bdaddr); - if (!l) - return error_not_connected(conn, msg); - - if (adapter->pending_dc) - return error_disconnect_in_progress(conn, msg); - - adapter->pending_dc = g_new0(struct pending_dc_info, 1); - - /* Start waiting... */ - adapter->pending_dc->timeout_id = - g_timeout_add(DC_PENDING_TIMEOUT, - dc_pending_timeout_handler, - adapter); - - if (!adapter->pending_dc->timeout_id) { - g_free(adapter->pending_dc); - adapter->pending_dc = NULL; - return DBUS_HANDLER_RESULT_NEED_MEMORY; - } - - adapter->pending_dc->conn = dbus_connection_ref(conn); - adapter->pending_dc->msg = dbus_message_ref(msg); - adapter->pending_dc->conn_handle = - ((struct active_conn_info *) l->data)->handle; - - dbus_connection_emit_signal(conn, dbus_message_get_path(msg), - ADAPTER_INTERFACE, - "RemoteDeviceDisconnectRequested", - DBUS_TYPE_STRING, &peer_addr, - DBUS_TYPE_INVALID); - - return DBUS_HANDLER_RESULT_HANDLED; -} - -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->rq, status); - if (reply) - send_message_and_unref(bonding->conn, reply); -} - -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) { - error_authentication_canceled(adapter->bonding->conn, - adapter->bonding->rq); - 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->rq, - 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(adapter->bonding->conn, adapter->bonding->rq, - 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->rq, - 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(adapter->bonding->conn, adapter->bonding->rq, - errno); - goto failed; - } - - dd = hci_open_dev(adapter->dev_id); - if (dd < 0) { - error_no_such_adapter(adapter->bonding->conn, - adapter->bonding->rq); - 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(adapter->bonding->conn, adapter->bonding->rq, - errno); - hci_close_dev(dd); - goto failed; - } - - if (rp.status) { - error("HCI_Authentication_Requested failed with status 0x%02x", - rp.status); - error_failed(adapter->bonding->conn, adapter->bonding->rq, - 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); - -cleanup: - name_listener_remove(adapter->bonding->conn, - dbus_message_get_sender(adapter->bonding->rq), - (name_cb_t) create_bond_req_exit, adapter); - - bonding_request_free(adapter->bonding); - adapter->bonding = NULL; - - return FALSE; -} - -static DBusHandlerResult adapter_create_bonding(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - char filename[PATH_MAX + 1]; - char *str, *peer_addr = NULL; - struct adapter *adapter = data; - bdaddr_t peer_bdaddr; - int sk; - - if (!adapter->up) - return error_not_ready(conn, msg); - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &peer_addr, - DBUS_TYPE_INVALID)) - return error_invalid_arguments(conn, msg); - - if (check_address(peer_addr) < 0) - return error_invalid_arguments(conn, msg); - - str2ba(peer_addr, &peer_bdaddr); - - /* check if there is a pending discover: requested by D-Bus/non clients */ - if (adapter->discov_active || (adapter->pdiscov_active && !adapter->pinq_idle)) - return error_discover_in_progress(conn, msg); - - pending_remote_name_cancel(adapter); - - if (adapter->bonding) - return error_bonding_in_progress(conn, msg); - - if (g_slist_find_custom(adapter->pin_reqs, &peer_bdaddr, pin_req_cmp)) - return error_bonding_in_progress(conn, msg); - - /* check if a link key already exists */ - create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, - "linkkeys"); - - str = textfile_caseget(filename, peer_addr); - if (str) { - free(str); - return error_bonding_already_exists(conn, msg); - } - - sk = l2raw_connect(adapter->address, &peer_bdaddr); - if (sk < 0) - return error_connection_attempt_failed(conn, msg, 0); - - adapter->bonding = bonding_request_new(&peer_bdaddr, conn, msg); - if (!adapter->bonding) { - close(sk); - return DBUS_HANDLER_RESULT_NEED_MEMORY; - } - - adapter->bonding->io = g_io_channel_unix_new(sk); - adapter->bonding->io_id = g_io_add_watch(adapter->bonding->io, - G_IO_OUT | G_IO_NVAL | G_IO_HUP | G_IO_ERR, - (GIOFunc) create_bonding_conn_complete, - adapter); - - name_listener_add(conn, dbus_message_get_sender(msg), - (name_cb_t) create_bond_req_exit, adapter); - - return DBUS_HANDLER_RESULT_HANDLED; -} - -static DBusHandlerResult adapter_cancel_bonding(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - DBusMessage *reply; - bdaddr_t peer_bdaddr; - const char *peer_addr; - GSList *l; - - if (!adapter->up) - return error_not_ready(conn, msg); - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &peer_addr, - DBUS_TYPE_INVALID)) - return error_invalid_arguments(conn, msg); - - if (check_address(peer_addr) < 0) - return error_invalid_arguments(conn, msg); - - str2ba(peer_addr, &peer_bdaddr); - - if (!adapter->bonding || bacmp(&adapter->bonding->bdaddr, &peer_bdaddr)) - return error_bonding_not_in_progress(conn, msg); - - if (strcmp(dbus_message_get_sender(adapter->bonding->rq), - dbus_message_get_sender(msg))) - return error_not_authorized(conn, msg); - - adapter->bonding->cancel = 1; - - l = g_slist_find_custom(adapter->pin_reqs, &peer_bdaddr, pin_req_cmp); - if (l) { - struct pending_pin_info *pin_req = l->data; - - if (pin_req->replied) { - /* - * If disconnect can't be applied and the PIN code - * request was already replied it doesn't make sense - * cancel the remote passkey: return not authorized. - */ - g_io_channel_close(adapter->bonding->io); - return error_not_authorized(conn, msg); - } else { - int dd = hci_open_dev(adapter->dev_id); - if (dd < 0) { - error("Can't open hci%d: %s (%d)", - adapter->dev_id, strerror(errno), errno); - return DBUS_HANDLER_RESULT_HANDLED; - } - - hci_send_cmd(dd, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, - 6, &peer_bdaddr); - - hci_close_dev(dd); - } - - adapter->pin_reqs = g_slist_remove(adapter->pin_reqs, pin_req); - g_free(pin_req); - } - - g_io_channel_close(adapter->bonding->io); - - reply = dbus_message_new_method_return(msg); - send_message_and_unref(conn, reply); - - return DBUS_HANDLER_RESULT_HANDLED; -} - -static DBusHandlerResult adapter_remove_bonding(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - GSList *l; - DBusMessage *reply; - char filename[PATH_MAX + 1]; - char *addr_ptr, *str; - bdaddr_t bdaddr; - int dd; - - if (!adapter->up) - return error_not_ready(conn, msg); - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &addr_ptr, - DBUS_TYPE_INVALID)) - return error_invalid_arguments(conn, msg); - - if (check_address(addr_ptr) < 0) - return error_invalid_arguments(conn, msg); - - dd = hci_open_dev(adapter->dev_id); - if (dd < 0) - return error_no_such_adapter(conn, 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, addr_ptr); - if (!str) { - hci_close_dev(dd); - return error_bonding_does_not_exist(conn, msg); - } - - free(str); - - /* Delete the link key from storage */ - if (textfile_casedel(filename, addr_ptr) < 0) { - int err = errno; - hci_close_dev(dd); - return error_failed(conn, msg, err); - } - - str2ba(addr_ptr, &bdaddr); - - /* Delete the link key from the Bluetooth chip */ - hci_delete_stored_link_key(dd, &bdaddr, 0, 1000); - - /* find the connection */ - l = g_slist_find_custom(adapter->active_conn, &bdaddr, - active_conn_find_by_bdaddr); - if (l) { - struct active_conn_info *con = l->data; - /* Send the HCI disconnect command */ - if (hci_disconnect(dd, htobs(con->handle), - HCI_OE_USER_ENDED_CONNECTION, 500) < 0) { - int err = errno; - error("Disconnect failed"); - hci_close_dev(dd); - return error_failed(conn, msg, err); - } - } - - dbus_connection_emit_signal(conn, dbus_message_get_path(msg), - ADAPTER_INTERFACE, "BondingRemoved", - DBUS_TYPE_STRING, &addr_ptr, - DBUS_TYPE_INVALID); - - reply = dbus_message_new_method_return(msg); - - hci_close_dev(dd); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_has_bonding(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - DBusMessage *reply; - char filename[PATH_MAX + 1]; - char *addr_ptr, *str; - dbus_bool_t result; - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &addr_ptr, - DBUS_TYPE_INVALID)) - return error_invalid_arguments(conn, msg); - - if (check_address(addr_ptr) < 0) - return error_invalid_arguments(conn, msg); - - create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, - "linkkeys"); - - str = textfile_caseget(filename, addr_ptr); - if (str) { - result = TRUE; - free(str); - } else - result = FALSE; - - reply = dbus_message_new_method_return(msg); - - dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &result, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static void list_bondings_do_append(char *key, char *value, void *data) -{ - DBusMessageIter *iter = data; - dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &key); -} - -static DBusHandlerResult adapter_list_bondings(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - DBusMessageIter iter; - DBusMessageIter array_iter; - DBusMessage *reply; - char filename[PATH_MAX + 1]; - - if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) - return error_invalid_arguments(conn, msg); - - create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, - "linkkeys"); - - reply = dbus_message_new_method_return(msg); - - dbus_message_iter_init_append(reply, &iter); - - dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, - DBUS_TYPE_STRING_AS_STRING, &array_iter); - - textfile_foreach(filename, list_bondings_do_append, &array_iter); - - dbus_message_iter_close_container(&iter, &array_iter); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_get_pin_code_length(DBusConnection *conn, - DBusMessage *msg, - void *data) -{ - struct adapter *adapter = data; - DBusMessage *reply; - bdaddr_t local, peer; - char *addr_ptr; - uint8_t length; - int len; - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &addr_ptr, - DBUS_TYPE_INVALID)) - return error_invalid_arguments(conn, msg); - - if (check_address(addr_ptr) < 0) - return error_invalid_arguments(conn, msg); - - str2ba(adapter->address, &local); - - str2ba(addr_ptr, &peer); - - len = read_pin_length(&local, &peer); - if (len < 0) - return error_record_does_not_exist(conn, msg); - - reply = dbus_message_new_method_return(msg); - - length = len; - - dbus_message_append_args(reply, DBUS_TYPE_BYTE, &length, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_get_encryption_key_size(DBusConnection *conn, - DBusMessage *msg, - void *data) -{ - struct adapter *adapter = data; - DBusMessage *reply; - bdaddr_t bdaddr; - char *addr_ptr; - uint8_t size; - int val; - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &addr_ptr, - DBUS_TYPE_INVALID)) - return error_invalid_arguments(conn, msg); - - if (check_address(addr_ptr) < 0) - return error_invalid_arguments(conn, msg); - - str2ba(addr_ptr, &bdaddr); - - val = get_encryption_key_size(adapter->dev_id, &bdaddr); - if (val < 0) - return error_failed(conn, msg, -val); - - reply = dbus_message_new_method_return(msg); - - size = val; - - dbus_message_append_args(reply, DBUS_TYPE_BYTE, &size, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_start_periodic(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - DBusMessage *reply; - 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 error_not_ready(conn, msg); - - if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) - return error_invalid_arguments(conn, msg); - - if (adapter->discov_active || adapter->pdiscov_active) - return error_discover_in_progress(conn, msg); - - pending_remote_name_cancel(adapter); - - dd = hci_open_dev(adapter->dev_id); - if (dd < 0) - return error_no_such_adapter(conn, 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 error_failed(conn, msg, err); - } - - if (status) { - error("HCI_Periodic_Inquiry_Mode failed with status 0x%02x", - status); - hci_close_dev(dd); - return error_failed(conn, 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; - - reply = dbus_message_new_method_return(msg); - - hci_close_dev(dd); - - /* track the request owner to cancel it automatically if the owner - * exits */ - name_listener_add(conn, dbus_message_get_sender(msg), - (name_cb_t) periodic_discover_req_exit, - adapter); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_stop_periodic(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - DBusMessage *reply; - struct adapter *adapter = data; - int err; - - if (!adapter->up) - return error_not_ready(conn, msg); - - if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) - return error_invalid_arguments(conn, msg); - - if (!adapter->pdiscov_active) - return error_not_authorized(conn, msg); - - /* - * 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 error_no_such_adapter(conn, msg); - else - return error_failed(conn, msg, -err); - } - - reply = dbus_message_new_method_return(msg); - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_is_periodic(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - DBusMessage *reply; - struct adapter *adapter = data; - dbus_bool_t active = adapter->pdiscov_active; - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &active, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_set_pdiscov_resolve(DBusConnection *conn, - DBusMessage *msg, - void *data) -{ - DBusMessage *reply; - struct adapter *adapter = data; - dbus_bool_t resolve; - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_BOOLEAN, &resolve, - DBUS_TYPE_INVALID)) - return error_invalid_arguments(conn, msg); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - debug("SetPeriodicDiscoveryNameResolving(%s)", - resolve ? "TRUE" : "FALSE"); - - adapter->pdiscov_resolve_names = resolve; - - if (adapter->pdiscov_active) { - if (resolve) - adapter->discov_type |= RESOLVE_NAME; - else - adapter->discov_type &= ~RESOLVE_NAME; - } - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_get_pdiscov_resolve(DBusConnection *conn, - DBusMessage *msg, - void *data) -{ - DBusMessage *reply; - struct adapter *adapter = data; - dbus_bool_t resolve = adapter->pdiscov_resolve_names; - - if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) - return error_invalid_arguments(conn, msg); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &resolve, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_discover_devices(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - DBusMessage *reply; - const char *method; - 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 error_not_ready(conn, msg); - - if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) - return error_invalid_arguments(conn, msg); - - if (adapter->discov_active) - return error_discover_in_progress(conn, msg); - - pending_remote_name_cancel(adapter); - - if (adapter->bonding) - return error_bonding_in_progress(conn, msg); - - dd = hci_open_dev(adapter->dev_id); - if (dd < 0) - return error_no_such_adapter(conn, 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 error_failed(conn, msg, err); - } - - if (rp.status) { - error("HCI_Inquiry command failed with status 0x%02x", - rp.status); - hci_close_dev(dd); - return error_failed(conn, msg, bt_error(rp.status)); - } - - method = dbus_message_get_member(msg); - if (strcmp("DiscoverDevicesWithoutNameResolving", method) == 0) - adapter->discov_type |= STD_INQUIRY; - else - adapter->discov_type |= (STD_INQUIRY | RESOLVE_NAME); - - adapter->discov_requestor = g_strdup(dbus_message_get_sender(msg)); - - reply = dbus_message_new_method_return(msg); - - hci_close_dev(dd); - - /* track the request owner to cancel it automatically if the owner - * exits */ - name_listener_add(conn, dbus_message_get_sender(msg), - (name_cb_t) discover_devices_req_exit, adapter); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_cancel_discovery(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct adapter *adapter = data; - int err; - - if (!adapter->up) - return error_not_ready(conn, msg); - - if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) - return error_invalid_arguments(conn, msg); - - /* is there discover pending? or discovery cancel was requested - * previously */ - if (!adapter->discov_active || adapter->discovery_cancel) - return error_not_authorized(conn, msg); - - /* only the discover requestor can cancel the inquiry process */ - if (!adapter->discov_requestor || - strcmp(adapter->discov_requestor, dbus_message_get_sender(msg))) - return error_not_authorized(conn, msg); - - /* - * 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 error_no_such_adapter(conn, msg); - else - return error_failed(conn, msg, -err); - } - - /* Reply before send DiscoveryCompleted */ - adapter->discovery_cancel = dbus_message_ref(msg); - - return DBUS_HANDLER_RESULT_HANDLED; -} - -struct remote_device_list_t { - GSList *list; - time_t time; -}; - -static void list_remote_devices_do_append(char *key, char *value, void *data) -{ - struct remote_device_list_t *param = data; - char *address; - struct tm date; - - if (g_slist_find_custom(param->list, key, (GCompareFunc) strcasecmp)) - return; - - if (param->time){ - strptime(value, "%Y-%m-%d %H:%M:%S %Z", &date); - if (difftime(mktime(&date), param->time) < 0) - return; - } - - address = g_strdup(key); - - param->list = g_slist_append(param->list, address); -} - -static void remote_devices_do_append(void *data, void *user_data) -{ - DBusMessageIter *iter = user_data; - - dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data); -} - -static DBusHandlerResult adapter_list_remote_devices(DBusConnection *conn, - DBusMessage *msg, - void *data) -{ - struct adapter *adapter = data; - DBusMessageIter iter; - DBusMessageIter array_iter; - DBusMessage *reply; - char filename[PATH_MAX + 1]; - struct remote_device_list_t param = { NULL, 0 }; - - if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) - return error_invalid_arguments(conn, msg); - - /* Add Bonded devices to the list */ - create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "linkkeys"); - textfile_foreach(filename, list_remote_devices_do_append, ¶m); - - /* Add Trusted devices to the list */ - create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "trusts"); - textfile_foreach(filename, list_remote_devices_do_append, ¶m); - - /* Add Last Used devices to the list */ - create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "lastused"); - textfile_foreach(filename, list_remote_devices_do_append, ¶m); - - reply = dbus_message_new_method_return(msg); - - dbus_message_iter_init_append(reply, &iter); - - dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, - DBUS_TYPE_STRING_AS_STRING, &array_iter); - - g_slist_foreach(param.list, remote_devices_do_append, &array_iter); - - g_slist_foreach(param.list, (GFunc) free, NULL); - g_slist_free(param.list); - - dbus_message_iter_close_container(&iter, &array_iter); - - return send_message_and_unref(conn, reply); -} - -static void append_connected(struct active_conn_info *dev, GSList *list) -{ - char address[18]; - - ba2str(&dev->bdaddr, address); - if (g_slist_find_custom(list, address, (GCompareFunc) strcasecmp)) - return; - - list = g_slist_append(list, g_strdup(address)); -} - -static DBusHandlerResult adapter_list_recent_remote_devices(DBusConnection *conn, - DBusMessage *msg, - void *data) -{ - struct adapter *adapter = data; - struct tm date; - const char *string; - DBusMessageIter iter; - DBusMessageIter array_iter; - DBusMessage *reply; - char filename[PATH_MAX + 1]; - struct remote_device_list_t param = { NULL, 0 }; - int len; - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &string, - DBUS_TYPE_INVALID)) - return error_invalid_arguments(conn, msg); - - /* Date format is "YYYY-MM-DD HH:MM:SS GMT" */ - len = strlen(string); - if (len && (strptime(string, "%Y-%m-%d %H:%M:%S", &date) == NULL)) - return error_invalid_arguments(conn, msg); - - /* Bonded and trusted: mandatory entries(no matter the date/time) */ - create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "linkkeys"); - textfile_foreach(filename, list_remote_devices_do_append, ¶m); - - create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "trusts"); - textfile_foreach(filename, list_remote_devices_do_append, ¶m); - - /* Last seen/used: append devices since the date informed */ - if (len) - param.time = mktime(&date); - - create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "lastseen"); - textfile_foreach(filename, list_remote_devices_do_append, ¶m); - - create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "lastused"); - textfile_foreach(filename, list_remote_devices_do_append, ¶m); - - /* connected: force appending connected devices, lastused might not match */ - g_slist_foreach(adapter->active_conn, (GFunc) append_connected, param.list); - - reply = dbus_message_new_method_return(msg); - - dbus_message_iter_init_append(reply, &iter); - - dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, - DBUS_TYPE_STRING_AS_STRING, &array_iter); - - g_slist_foreach(param.list, remote_devices_do_append, &array_iter); - - g_slist_foreach(param.list, (GFunc) free, NULL); - g_slist_free(param.list); - - dbus_message_iter_close_container(&iter, &array_iter); - - return send_message_and_unref(conn, reply); -} - - -static DBusHandlerResult adapter_set_trusted(DBusConnection *conn, - DBusMessage *msg, - void *data) -{ - struct adapter *adapter = data; - DBusMessage *reply; - bdaddr_t local; - const char *address; - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &address, - DBUS_TYPE_INVALID)) - return error_invalid_arguments(conn, msg); - - if (check_address(address) < 0) - return error_invalid_arguments(conn, msg); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - str2ba(adapter->address, &local); - - write_trust(&local, address, GLOBAL_TRUST, TRUE); - - dbus_connection_emit_signal(conn, dbus_message_get_path(msg), - ADAPTER_INTERFACE, "TrustAdded", - DBUS_TYPE_STRING, &address, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_is_trusted(DBusConnection *conn, - DBusMessage *msg, - void *data) -{ - struct adapter *adapter = data; - DBusMessage *reply; - const char *address; - dbus_bool_t trusted; - bdaddr_t local; - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &address, - DBUS_TYPE_INVALID)) - return error_invalid_arguments(conn, msg); - - if (check_address(address) < 0) - return error_invalid_arguments(conn, msg); - - str2ba(adapter->address, &local); - - trusted = read_trust(&local, address, GLOBAL_TRUST); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_append_args(reply, - DBUS_TYPE_BOOLEAN, &trusted, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_remove_trust(DBusConnection *conn, - DBusMessage *msg, - void *data) -{ - struct adapter *adapter = data; - DBusMessage *reply; - const char *address; - bdaddr_t local; - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &address, - DBUS_TYPE_INVALID)) - return error_invalid_arguments(conn, msg); - - if (check_address(address) < 0) - return error_invalid_arguments(conn, msg); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - str2ba(adapter->address, &local); - - write_trust(&local, address, GLOBAL_TRUST, FALSE); - - dbus_connection_emit_signal(conn, dbus_message_get_path(msg), - ADAPTER_INTERFACE, "TrustRemoved", - DBUS_TYPE_STRING, &address, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult adapter_list_trusts(DBusConnection *conn, - DBusMessage *msg, - void *data) -{ - struct adapter *adapter = data; - DBusMessage *reply; - GSList *trusts, *l; - char **addrs; - bdaddr_t local; - int len; - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - str2ba(adapter->address, &local); - - trusts = list_trusts(&local, GLOBAL_TRUST); - - addrs = g_new(char *, g_slist_length(trusts)); - - for (l = trusts, len = 0; l; l = l->next, len++) - addrs[len] = l->data; - - dbus_message_append_args(reply, - DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, - &addrs, len, - DBUS_TYPE_INVALID); - - g_free(addrs); - g_slist_foreach(trusts, (GFunc) g_free, NULL); - g_slist_free(trusts); - - return send_message_and_unref(conn, reply); -} - -const char *major_class_str(uint32_t class) -{ - uint8_t index = (class >> 8) & 0x1F; - - if (index > 8) - return major_cls[9]; /* uncategorized */ - - return major_cls[index]; -} - -const char *minor_class_str(uint32_t class) -{ - uint8_t major_index = (class >> 8) & 0x1F; - uint8_t minor_index; - - switch (major_index) { - case 1: /* computer */ - minor_index = (class >> 2) & 0x3F; - if (minor_index < NUM_ELEMENTS(computer_minor_cls)) - return computer_minor_cls[minor_index]; - else - return ""; - case 2: /* phone */ - minor_index = (class >> 2) & 0x3F; - if (minor_index < NUM_ELEMENTS(phone_minor_cls)) - return phone_minor_cls[minor_index]; - return ""; - case 3: /* access point */ - minor_index = (class >> 5) & 0x07; - if (minor_index < NUM_ELEMENTS(access_point_minor_cls)) - return access_point_minor_cls[minor_index]; - else - return ""; - case 4: /* audio/video */ - minor_index = (class >> 2) & 0x3F; - if (minor_index < NUM_ELEMENTS(audio_video_minor_cls)) - return audio_video_minor_cls[minor_index]; - else - return ""; - case 5: /* peripheral */ - minor_index = (class >> 6) & 0x03; - if (minor_index < NUM_ELEMENTS(peripheral_minor_cls)) - return peripheral_minor_cls[minor_index]; - else - return ""; - case 6: /* imaging */ - { - uint8_t shift_minor = 0; - - minor_index = (class >> 4) & 0x0F; - while (shift_minor < (sizeof(imaging_minor_cls) / sizeof(*imaging_minor_cls))) { - if (((minor_index >> shift_minor) & 0x01) == 0x01) - return imaging_minor_cls[shift_minor]; - shift_minor++; - } - } - break; - case 7: /* wearable */ - minor_index = (class >> 2) & 0x3F; - if (minor_index < NUM_ELEMENTS(wearable_minor_cls)) - return wearable_minor_cls[minor_index]; - else - return ""; - case 8: /* toy */ - minor_index = (class >> 2) & 0x3F; - if (minor_index < NUM_ELEMENTS(toy_minor_cls)) - return toy_minor_cls[minor_index]; - else - return ""; - } - - return ""; -} - -GSList *service_classes_str(uint32_t class) -{ - uint8_t services = class >> 16; - GSList *l = NULL; - int i; - - for (i = 0; i < (sizeof(service_cls) / sizeof(*service_cls)); i++) { - if (!(services & (1 << i))) - continue; - - l = g_slist_append(l, (void *) service_cls[i]); - } - - return l; -} - -static DBusMethodVTable adapter_methods[] = { - { "GetInfo", adapter_get_info, - "", "{sv}" }, - { "GetAddress", adapter_get_address, - "", "s" }, - { "GetVersion", adapter_get_version, - "", "s" }, - { "GetRevision", adapter_get_revision, - "", "s" }, - { "GetManufacturer", adapter_get_manufacturer, - "", "s" }, - { "GetCompany", adapter_get_company, - "", "s" }, - { "ListAvailableModes", adapter_list_modes, - "", "as" }, - { "GetMode", adapter_get_mode, - "", "s" }, - { "SetMode", adapter_set_mode, - "s", "" }, - { "GetDiscoverableTimeout", adapter_get_discoverable_to, - "", "u" }, - { "SetDiscoverableTimeout", adapter_set_discoverable_to, - "u", "" }, - { "IsConnectable", adapter_is_connectable, - "", "b" }, - { "IsDiscoverable", adapter_is_discoverable, - "", "b" }, - { "IsConnected", adapter_is_connected, - "s", "b" }, - { "ListConnections", adapter_list_connections, - "", "as" }, - { "GetMajorClass", adapter_get_major_class, - "", "s" }, - { "ListAvailableMinorClasses", adapter_list_minor_classes, - "", "as" }, - { "GetMinorClass", adapter_get_minor_class, - "", "s" }, - { "SetMinorClass", adapter_set_minor_class, - "s", "" }, - { "GetServiceClasses", adapter_get_service_classes, - "", "as" }, - { "GetName", adapter_get_name, - "", "s" }, - { "SetName", adapter_set_name, - "s", "" }, - - { "GetRemoteInfo", adapter_get_remote_info, - "s", "{sv}" }, - { "GetRemoteServiceRecord", adapter_get_remote_svc, - "su", "ay" }, - { "GetRemoteServiceRecordAsXML", adapter_get_remote_svc_xml, - "su", "s" }, - { "GetRemoteServiceHandles", adapter_get_remote_svc_handles, - "ss", "au" }, - { "GetRemoteServiceIdentifiers", adapter_get_remote_svc_identifiers, - "s", "as" }, - { "FinishRemoteServiceTransaction", adapter_finish_sdp_transact, - "s", "" }, - - { "GetRemoteVersion", adapter_get_remote_version, - "s", "s" }, - { "GetRemoteRevision", adapter_get_remote_revision, - "s", "s" }, - { "GetRemoteManufacturer", adapter_get_remote_manufacturer, - "s", "s" }, - { "GetRemoteCompany", adapter_get_remote_company, - "s", "s" }, - { "GetRemoteMajorClass", adapter_get_remote_major_class, - "s", "s" }, - { "GetRemoteMinorClass", adapter_get_remote_minor_class, - "s", "s" }, - { "GetRemoteServiceClasses", adapter_get_remote_service_cls, - "s", "as" }, - { "GetRemoteClass", adapter_get_remote_class, - "s", "u" }, - { "GetRemoteFeatures", adapter_get_remote_features, - "s", "ay" }, - { "GetRemoteName", adapter_get_remote_name, - "s", "s" }, - { "GetRemoteAlias", adapter_get_remote_alias, - "s", "s" }, - { "SetRemoteAlias", adapter_set_remote_alias, - "ss", "" }, - { "ClearRemoteAlias", adapter_clear_remote_alias, - "s", "" }, - - { "LastSeen", adapter_last_seen, - "s", "s" }, - { "LastUsed", adapter_last_used, - "s", "s" }, - - { "DisconnectRemoteDevice", adapter_dc_remote_device, - "s", "" }, - - { "CreateBonding", adapter_create_bonding, - "s", "" }, - { "CancelBondingProcess", adapter_cancel_bonding, - "s", "" }, - { "RemoveBonding", adapter_remove_bonding, - "s", "" }, - { "HasBonding", adapter_has_bonding, - "s", "b" }, - { "ListBondings", adapter_list_bondings, - "", "as" }, - { "GetPinCodeLength", adapter_get_pin_code_length, - "s", "y" }, - { "GetEncryptionKeySize", adapter_get_encryption_key_size, - "s", "y" }, - - { "StartPeriodicDiscovery", adapter_start_periodic, - "", "" }, - { "StopPeriodicDiscovery", adapter_stop_periodic, - "", "" }, - { "IsPeriodicDiscovery", adapter_is_periodic, - "", "b" }, - { "SetPeriodicDiscoveryNameResolving", adapter_set_pdiscov_resolve, - "b", "" }, - { "GetPeriodicDiscoveryNameResolving", adapter_get_pdiscov_resolve, - "", "b" }, - - { "DiscoverDevices", adapter_discover_devices, - "", "" }, - { "DiscoverDevicesWithoutNameResolving", adapter_discover_devices, - "", "" }, - { "CancelDiscovery", adapter_cancel_discovery, - "", "" }, - - { "ListRemoteDevices", adapter_list_remote_devices, - "", "as" }, - { "ListRecentRemoteDevices", adapter_list_recent_remote_devices, - "s", "as" }, - - { "SetTrusted", adapter_set_trusted, - "s", "" }, - { "IsTrusted", adapter_is_trusted, - "s", "b" }, - { "RemoveTrust", adapter_remove_trust, - "s", "" }, - { "ListTrusts", adapter_list_trusts, - "", "as" }, - - { NULL, NULL, NULL, NULL } -}; - -static DBusSignalVTable adapter_signals[] = { - { "ModeChanged", "s" }, - { "DiscoverableTimeoutChanged", "u" }, - { "MinorClassChanged", "s" }, - { "NameChanged", "s" }, - { "DiscoveryStarted", "" }, - { "DiscoveryCompleted", "" }, - { "PeriodicDiscoveryStarted", "" }, - { "PeriodicDiscoveryStopped", "" }, - { "RemoteDeviceFound", "sun" }, - { "RemoteDeviceDisappeared", "s" }, - { "RemoteClassUpdated", "su" }, - { "RemoteNameUpdated", "ss" }, - { "RemoteNameFailed", "s" }, - { "RemoteNameRequested", "s" }, - { "RemoteAliasChanged", "ss" }, - { "RemoteAliasCleared", "s" }, - { "RemoteDeviceConnected", "s" }, - { "RemoteDeviceDisconnectRequested", "s" }, - { "RemoteDeviceDisconnected", "s" }, - { "RemoteIdentifiersUpdated", "sas" }, - { "BondingCreated", "s" }, - { "BondingRemoved", "s" }, - { "TrustAdded", "s" }, - { "TrustRemoved", "s" }, - { NULL, NULL } -}; - -dbus_bool_t adapter_init(DBusConnection *conn, const char *path) -{ - return dbus_connection_register_interface(conn, path, ADAPTER_INTERFACE, - adapter_methods, - adapter_signals, NULL); -} diff --git a/hcid/dbus-adapter.h b/hcid/dbus-adapter.h deleted file mode 100644 index c87a9829..00000000 --- a/hcid/dbus-adapter.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * - * BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2004-2007 Marcel Holtmann - * - * - * 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 - * - */ - -#ifndef __ADAPTER_H -#define __ADAPTER_H - -#include - -#define ADAPTER_INTERFACE "org.bluez.Adapter" - -#define INVALID_DEV_ID 0xFFFF - -#define BONDING_TIMEOUT 45000 /* 45 sec */ - -#define DC_PENDING_TIMEOUT 2000 /* 2 secs */ - -/* Discover types */ -#define DISCOVER_TYPE_NONE 0x00 -#define STD_INQUIRY 0x01 -#define PERIODIC_INQUIRY 0x02 - -/* Actions executed after inquiry complete */ -#define RESOLVE_NAME 0x10 - -typedef enum { - NAME_ANY, - NAME_NOT_REQUIRED, /* used by get remote name without name resolving */ - NAME_REQUIRED, /* remote name needs be resolved */ - NAME_REQUESTED, /* HCI remote name request was sent */ - NAME_SENT /* D-Bus signal RemoteNameUpdated sent */ -} name_status_t; - -struct remote_dev_info { - bdaddr_t bdaddr; - int8_t rssi; - name_status_t name_status; -}; - -struct bonding_request_info { - bdaddr_t bdaddr; - DBusConnection *conn; - DBusMessage *rq; - GIOChannel *io; - guint io_id; - int hci_status; - int cancel; - int auth_active; -}; - -struct pending_pin_info { - bdaddr_t bdaddr; - int replied; /* If we've already replied to the request */ -}; - -struct active_conn_info { - bdaddr_t bdaddr; - uint16_t handle; -}; - -struct pending_dc_info { - DBusConnection *conn; - DBusMessage *msg; - uint16_t conn_handle; - guint timeout_id; -}; - -struct adapter { - uint16_t dev_id; - int up; - char address[18]; /* adapter Bluetooth Address */ - guint timeout_id; /* discoverable timeout id */ - uint32_t discov_timeout; /* discoverable time(msec) */ - uint8_t scan_enable; /* scan mode: SCAN_DISABLED, SCAN_PAGE, SCAN_INQUIRY */ - uint8_t mode; /* off, connectable, discoverable, limited */ - uint8_t class[3]; /* device class */ - int discov_active; /* standard discovery active: includes name resolution step */ - int pdiscov_active; /* periodic discovery active */ - int pinq_idle; /* tracks the idle time for periodic inquiry */ - int discov_type; /* type requested */ - int pdiscov_resolve_names; /* Resolve names when doing periodic discovery */ - GSList *found_devices; - GSList *oor_devices; /* out of range device list */ - char *pdiscov_requestor; /* periodic discovery requestor unique name */ - char *discov_requestor; /* discovery requestor unique name */ - DBusMessage *discovery_cancel; /* discovery cancel message request */ - GSList *passkey_agents; - GSList *auth_agents; /* Authorization agents */ - bdaddr_t agents_disabled; /* temporarely disable agents for bda */ - GSList *active_conn; - struct bonding_request_info *bonding; - GSList *pin_reqs; - struct pending_dc_info *pending_dc; -}; - -dbus_bool_t adapter_init(DBusConnection *conn, const char *path); - -const char *major_class_str(uint32_t class); - -const char *minor_class_str(uint32_t class); - -const char *mode2str(uint8_t mode); - -GSList *service_classes_str(uint32_t class); - -int pending_remote_name_cancel(struct adapter *adapter); - -void dc_pending_timeout_cleanup(struct adapter *adapter); - -#endif /* __ADAPTER_H */ diff --git a/hcid/dbus-common.c b/hcid/dbus-common.c index 68137875..4caef1ef 100644 --- a/hcid/dbus-common.c +++ b/hcid/dbus-common.c @@ -52,9 +52,9 @@ #include "dbus.h" #include "dbus-helper.h" #include "dbus-error.h" -#include "dbus-hci.h" #include "manager.h" -#include "dbus-adapter.h" +#include "adapter.h" +#include "dbus-hci.h" #include "dbus-service.h" #include "dbus-database.h" #include "dbus-security.h" diff --git a/hcid/dbus-common.h b/hcid/dbus-common.h index d1bc1683..08f83ea3 100644 --- a/hcid/dbus-common.h +++ b/hcid/dbus-common.h @@ -21,9 +21,6 @@ * */ -#ifndef __BLUEZ_DBUS_COMMON_H -#define __BLUEZ_DBUS_COMMON_H - #include #include #include @@ -61,5 +58,3 @@ int register_sdp_record(sdp_record_t *rec); int unregister_sdp_record(uint32_t handle); int update_sdp_record(uint32_t handle, sdp_record_t *rec); void cleanup_sdp_session(void); - -#endif /* __BLUEZ_DBUS_COMMON_H */ diff --git a/hcid/dbus-database.c b/hcid/dbus-database.c index 69ade220..1c770c83 100644 --- a/hcid/dbus-database.c +++ b/hcid/dbus-database.c @@ -44,6 +44,7 @@ #include "hcid.h" #include "sdpd.h" #include "sdp-xml.h" +#include "adapter.h" #include "dbus-hci.h" #include "dbus-common.h" #include "dbus-error.h" diff --git a/hcid/dbus-device.c b/hcid/dbus-device.c deleted file mode 100644 index 0fe884b1..00000000 --- a/hcid/dbus-device.c +++ /dev/null @@ -1,29 +0,0 @@ -/* - * - * BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2004-2007 Marcel Holtmann - * - * - * 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 -#endif - -#include -#include diff --git a/hcid/dbus-device.h b/hcid/dbus-device.h deleted file mode 100644 index e87dd676..00000000 --- a/hcid/dbus-device.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * - * BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2004-2007 Marcel Holtmann - * - * - * 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 - * - */ diff --git a/hcid/dbus-error.h b/hcid/dbus-error.h index 9db9e117..6a2036de 100644 --- a/hcid/dbus-error.h +++ b/hcid/dbus-error.h @@ -21,9 +21,6 @@ * */ -#ifndef __BLUEZ_DBUS_ERROR_H -#define __BLUEZ_DBUS_ERROR_H - #define ERROR_INTERFACE "org.bluez.Error" DBusHandlerResult error_failed(DBusConnection *conn, DBusMessage *msg, int err); @@ -67,5 +64,3 @@ DBusHandlerResult error_audit_already_exists(DBusConnection *conn, DBusMessage * DBusHandlerResult error_trusted_device_already_exists(DBusConnection *conn, DBusMessage *msg); DBusHandlerResult error_trusted_device_does_not_exists(DBusConnection *conn, DBusMessage *msg); DBusHandlerResult error_disconnect_in_progress(DBusConnection *conn, DBusMessage *msg); - -#endif /* __BLUEZ_DBUS_ERROR_H */ diff --git a/hcid/dbus-hci.c b/hcid/dbus-hci.c index fd9fbb47..76e8e5b3 100644 --- a/hcid/dbus-hci.c +++ b/hcid/dbus-hci.c @@ -46,14 +46,14 @@ #include "hcid.h" #include "dbus.h" #include "textfile.h" +#include "manager.h" +#include "adapter.h" #include "dbus-helper.h" #include "dbus-common.h" #include "dbus-error.h" #include "dbus-test.h" -#include "dbus-security.h" #include "dbus-service.h" -#include "manager.h" -#include "dbus-adapter.h" +#include "dbus-security.h" #include "dbus-hci.h" static DBusConnection *connection = NULL; diff --git a/hcid/dbus-hci.h b/hcid/dbus-hci.h index c7b3e1b4..385ed96c 100644 --- a/hcid/dbus-hci.h +++ b/hcid/dbus-hci.h @@ -21,12 +21,6 @@ * */ -#ifndef __H_BLUEZ_DBUS_HCI_H__ -#define __H_BLUEZ_DBUS_HCI_H__ - -#include -#include "dbus-adapter.h" - void hcid_dbus_set_experimental(); int hcid_dbus_use_experimental(); int hcid_dbus_register_device(uint16_t id); @@ -81,5 +75,3 @@ int discov_timeout_handler(void *data); void set_dbus_connection(DBusConnection *conn); DBusConnection *get_dbus_connection(void); - -#endif /* __H_BLUEZ_DBUS_HCI_H__ */ diff --git a/hcid/dbus-sdp.c b/hcid/dbus-sdp.c index aa19c512..7f16aa3e 100644 --- a/hcid/dbus-sdp.c +++ b/hcid/dbus-sdp.c @@ -52,9 +52,9 @@ #include "dbus-helper.h" #include "hcid.h" #include "textfile.h" +#include "adapter.h" #include "dbus-hci.h" #include "dbus-common.h" -#include "dbus-adapter.h" #include "dbus-error.h" #include "dbus-sdp.h" #include "sdp-xml.h" diff --git a/hcid/dbus-sdp.h b/hcid/dbus-sdp.h index c1a7382d..e648b1f4 100644 --- a/hcid/dbus-sdp.h +++ b/hcid/dbus-sdp.h @@ -21,9 +21,6 @@ * */ -#ifndef __BLUEZ_DBUS_SDP_H -#define __BLUEZ_DBUS_SDP_H - #include #include #include @@ -52,6 +49,3 @@ int get_record_with_uuid(DBusConnection *conn, DBusMessage *msg, int get_record_with_handle(DBusConnection *conn, DBusMessage *msg, uint16_t dev_id, const char *dst, uint32_t handle, get_record_cb_t *cb, void *data); - - -#endif /* __BLUEZ_DBUS_SDP_H */ diff --git a/hcid/dbus-security.c b/hcid/dbus-security.c index 1d12eca6..2d3eef8f 100644 --- a/hcid/dbus-security.c +++ b/hcid/dbus-security.c @@ -40,11 +40,12 @@ #include +#include "adapter.h" + #include "dbus.h" #include "dbus-helper.h" #include "hcid.h" #include "dbus-common.h" -#include "dbus-adapter.h" #include "dbus-service.h" #include "dbus-error.h" #include "dbus-security.h" diff --git a/hcid/dbus-security.h b/hcid/dbus-security.h index 1e19653f..60b7790f 100644 --- a/hcid/dbus-security.h +++ b/hcid/dbus-security.h @@ -21,12 +21,6 @@ * */ -#ifndef __BLUEZ_DBUS_SECURITY_H -#define __BLUEZ_DBUS_SECURITY_H - -#include "dbus-adapter.h" -#include "dbus-service.h" - #define SECURITY_INTERFACE "org.bluez.Security" dbus_bool_t security_init(DBusConnection *conn, const char *path); @@ -56,5 +50,3 @@ DBusHandlerResult cancel_authorize_request(DBusConnection *conn, struct service *service, const char *address, const char *path); - -#endif /* __BLUEZ_DBUS_SECURITY_H */ diff --git a/hcid/dbus-service.c b/hcid/dbus-service.c index 49db4e00..9c274ad6 100644 --- a/hcid/dbus-service.c +++ b/hcid/dbus-service.c @@ -47,6 +47,7 @@ #include "dbus-common.h" #include "dbus-error.h" #include "manager.h" +#include "adapter.h" #include "dbus-service.h" #include "dbus-hci.h" diff --git a/hcid/dbus-service.h b/hcid/dbus-service.h index ee38611c..b6f3e630 100644 --- a/hcid/dbus-service.h +++ b/hcid/dbus-service.h @@ -21,9 +21,6 @@ * */ -#ifndef __BLUEZ_DBUS_SERVICE_H -#define __BLUEZ_DBUS_SERVICE_H - #define START_REPLY_TIMEOUT 5000 struct service { @@ -63,5 +60,3 @@ int service_register(DBusConnection *conn, const char *bus_name, const char *ide const char *name, const char *description); int service_unregister(DBusConnection *conn, struct service *service); - -#endif /* __BLUEZ_DBUS_SERVICE_H */ diff --git a/hcid/dbus-test.c b/hcid/dbus-test.c index 23d40b4b..7dea55a4 100644 --- a/hcid/dbus-test.c +++ b/hcid/dbus-test.c @@ -40,8 +40,8 @@ #include "dbus-helper.h" #include "hcid.h" #include "dbus-common.h" +#include "adapter.h" #include "dbus-hci.h" -#include "dbus-adapter.h" #include "dbus-error.h" #include "dbus-test.h" diff --git a/hcid/dbus-test.h b/hcid/dbus-test.h index 455c9293..0a36fb3b 100644 --- a/hcid/dbus-test.h +++ b/hcid/dbus-test.h @@ -21,13 +21,8 @@ * */ -#ifndef __BLUEZ_DBUS_TEST_H -#define __BLUEZ_DBUS_TEST_H - #define TEST_INTERFACE "org.bluez.Test" dbus_bool_t test_init(DBusConnection *conn, const char *path); void process_audits_list(const char *adapter_path); - -#endif /* __BLUEZ_DBUS_TEST_H */ diff --git a/hcid/main.c b/hcid/main.c index 61d2fecd..d3cf2bf4 100644 --- a/hcid/main.c +++ b/hcid/main.c @@ -51,6 +51,7 @@ #include "hcid.h" #include "sdpd.h" #include "server.h" +#include "adapter.h" #include "dbus-common.h" #include "dbus-service.h" #include "dbus-database.h" diff --git a/hcid/manager.c b/hcid/manager.c index e946886f..50cd698e 100644 --- a/hcid/manager.c +++ b/hcid/manager.c @@ -42,14 +42,15 @@ #include #include "hcid.h" +#include "adapter.h" #include "dbus.h" #include "dbus-helper.h" #include "dbus-common.h" #include "dbus-error.h" +#include "dbus-hci.h" +#include "dbus-service.h" #include "dbus-database.h" #include "dbus-security.h" -#include "dbus-service.h" -#include "dbus-hci.h" #include "sdp-xml.h" #include "manager.h" diff --git a/hcid/security.c b/hcid/security.c index 0ef26d25..37f4cc7d 100644 --- a/hcid/security.c +++ b/hcid/security.c @@ -49,6 +49,7 @@ #include "hcid.h" #include "textfile.h" +#include "adapter.h" #include "dbus-hci.h" struct g_io_info { -- cgit