diff options
Diffstat (limited to 'hcid/dbus-device.c')
-rw-r--r-- | hcid/dbus-device.c | 822 |
1 files changed, 822 insertions, 0 deletions
diff --git a/hcid/dbus-device.c b/hcid/dbus-device.c new file mode 100644 index 00000000..d129effc --- /dev/null +++ b/hcid/dbus-device.c @@ -0,0 +1,822 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2004-2006 Marcel Holtmann <marcel@holtmann.org> + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <sys/socket.h> + +#include <bluetooth/bluetooth.h> +#include <bluetooth/hci.h> +#include <bluetooth/hci_lib.h> + +#include <dbus/dbus.h> + +#include "hcid.h" +#include "dbus.h" + +#include "textfile.h" + +static char *get_peer_name(const bdaddr_t *local, const bdaddr_t *peer) +{ + char filename[PATH_MAX + 1], addr[18]; + + ba2str(local, addr); + snprintf(filename, PATH_MAX, "%s/%s/names", STORAGEDIR, addr); + + ba2str(peer, addr); + return textfile_get(filename, addr); +} + +static DBusMessage* handle_dev_get_address_req(DBusMessage *msg, void *data) +{ + struct hci_dbus_data *dbus_data = data; + DBusMessage *reply; + char str[18], *str_ptr = str; + + get_device_address(dbus_data->dev_id, str, sizeof(str)); + + reply = dbus_message_new_method_return(msg); + + dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, + DBUS_TYPE_INVALID); + + return reply; +} + +static DBusMessage* handle_dev_get_version_req(DBusMessage *msg, void *data) +{ + struct hci_dbus_data *dbus_data = data; + DBusMessage *reply; + char str[20], *str_ptr = str; + + get_device_version(dbus_data->dev_id, str, sizeof(str)); + + reply = dbus_message_new_method_return(msg); + + dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, + DBUS_TYPE_INVALID); + + return reply; +} + +static DBusMessage* handle_dev_get_revision_req(DBusMessage *msg, void *data) +{ + struct hci_dbus_data *dbus_data = data; + DBusMessage *reply; + char str[20], *str_ptr = str; + + get_device_revision(dbus_data->dev_id, str, sizeof(str)); + + reply = dbus_message_new_method_return(msg); + + dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, + DBUS_TYPE_INVALID); + + return reply; +} + +static DBusMessage* handle_dev_get_manufacturer_req(DBusMessage *msg, void *data) +{ + struct hci_dbus_data *dbus_data = data; + DBusMessage *reply; + char str[64], *str_ptr = str; + + get_device_manufacturer(dbus_data->dev_id, str, sizeof(str)); + + reply = dbus_message_new_method_return(msg); + + dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, + DBUS_TYPE_INVALID); + + return reply; +} + +static DBusMessage* handle_dev_get_company_req(DBusMessage *msg, void *data) +{ + struct hci_dbus_data *dbus_data = data; + DBusMessage *reply; + char str[64], *str_ptr = str; + + get_device_company(dbus_data->dev_id, str, sizeof(str)); + + reply = dbus_message_new_method_return(msg); + + dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, + DBUS_TYPE_INVALID); + + return reply; +} + +static DBusMessage* handle_dev_get_features_req(DBusMessage *msg, void *data) +{ + return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED); +} + +static DBusMessage* handle_dev_get_name_req(DBusMessage *msg, void *data) +{ + struct hci_dbus_data *dbus_data = data; + DBusMessage *reply; + char str[249], *str_ptr = str; + + get_device_name(dbus_data->dev_id, str, sizeof(str)); + + reply = dbus_message_new_method_return(msg); + + dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, + DBUS_TYPE_INVALID); + + return reply; +} + +static DBusMessage* handle_dev_set_name_req(DBusMessage *msg, void *data) +{ + struct hci_dbus_data *dbus_data = data; + DBusMessageIter iter; + DBusMessage *reply; + char *str_ptr; + + dbus_message_iter_init(msg, &iter); + dbus_message_iter_get_basic(&iter, &str_ptr); + + if (strlen(str_ptr) == 0) { + syslog(LOG_ERR, "Name change failed: Invalid parameter"); + return bluez_new_failure_msg(msg, BLUEZ_EDBUS_WRONG_PARAM); + } + + set_device_name(dbus_data->dev_id, str_ptr); + + reply = dbus_message_new_method_return(msg); + + return reply; +} + +static DBusMessage* handle_dev_get_alias_req(DBusMessage *msg, void *data) +{ + struct hci_dbus_data *dbus_data = data; + DBusMessageIter iter; + DBusMessage *reply; + char str[249], *str_ptr = str, *addr_ptr; + bdaddr_t bdaddr; + + dbus_message_iter_init(msg, &iter); + dbus_message_iter_get_basic(&iter, &addr_ptr); + + str2ba(addr_ptr, &bdaddr); + + get_device_alias(dbus_data->dev_id, &bdaddr, str, sizeof(str)); + + reply = dbus_message_new_method_return(msg); + + dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr, + DBUS_TYPE_INVALID); + + return reply; +} + +static DBusMessage* handle_dev_set_alias_req(DBusMessage *msg, void *data) +{ + struct hci_dbus_data *dbus_data = data; + DBusConnection *connection = get_dbus_connection(); + DBusMessageIter iter; + DBusMessage *reply, *signal; + char *str_ptr, *addr_ptr; + bdaddr_t bdaddr; + + dbus_message_iter_init(msg, &iter); + dbus_message_iter_get_basic(&iter, &addr_ptr); + dbus_message_iter_next(&iter); + dbus_message_iter_get_basic(&iter, &str_ptr); + + if (strlen(str_ptr) == 0) { + syslog(LOG_ERR, "Alias change failed: Invalid parameter"); + return bluez_new_failure_msg(msg, BLUEZ_EDBUS_WRONG_PARAM); + } + + str2ba(addr_ptr, &bdaddr); + + set_device_alias(dbus_data->dev_id, &bdaddr, str_ptr); + + signal = dev_signal_factory(dbus_data->dev_id, "AliasChanged", + DBUS_TYPE_STRING, &addr_ptr, + DBUS_TYPE_STRING, &str_ptr, + DBUS_TYPE_INVALID); + if (signal) { + dbus_connection_send(connection, signal, NULL); + dbus_connection_flush(connection); + dbus_message_unref(signal); + } + + signal = dev_signal_factory(dbus_data->dev_id, "RemoteAlias", + DBUS_TYPE_STRING, &addr_ptr, + DBUS_TYPE_STRING, &str_ptr, + DBUS_TYPE_INVALID); + if (signal) { + dbus_connection_send(connection, signal, NULL); + dbus_connection_flush(connection); + dbus_message_unref(signal); + } + + reply = dbus_message_new_method_return(msg); + + return reply; +} + +static DBusMessage* handle_dev_get_discoverable_to_req(DBusMessage *msg, void *data) +{ + /*FIXME: */ + return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED); +} + +static DBusMessage* handle_dev_get_mode_req(DBusMessage *msg, void *data) +{ + const struct hci_dbus_data *dbus_data = data; + DBusMessage *reply = NULL; + const uint8_t hci_mode = dbus_data->path_data; + uint8_t scan_mode; + + switch (hci_mode) { + case SCAN_DISABLED: + scan_mode = MODE_OFF; + break; + case SCAN_PAGE: + scan_mode = MODE_CONNECTABLE; + break; + case (SCAN_PAGE | SCAN_INQUIRY): + scan_mode = MODE_DISCOVERABLE; + break; + case SCAN_INQUIRY: + /* inquiry scan mode is not handled, return 0xff */ + default: + /* reserved */ + scan_mode = 0xff; + } + + reply = dbus_message_new_method_return(msg); + + dbus_message_append_args(reply, + DBUS_TYPE_BYTE, &scan_mode, + DBUS_TYPE_INVALID); + + return reply; +} + +static DBusMessage* handle_dev_is_connectable_req(DBusMessage *msg, void *data) +{ + /*FIXME: */ + return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED); +} + +static DBusMessage* handle_dev_is_discoverable_req(DBusMessage *msg, void *data) +{ + /*FIXME: */ + return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED); +} + +static DBusMessage* handle_dev_set_class_req(DBusMessage *msg, void *data) +{ + /*FIXME: */ + return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED); +} + +static DBusMessage* handle_dev_set_discoverable_to_req(DBusMessage *msg, void *data) +{ + /*FIXME: */ + return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED); +} + +static DBusMessage* handle_dev_set_mode_req(DBusMessage *msg, void *data) +{ + const struct hci_dbus_data *dbus_data = data; + DBusMessage *reply = NULL; + struct hci_request rq; + int dd = -1; + const uint8_t scan_mode; + uint8_t hci_mode; + uint8_t status = 0; + const uint8_t current_mode = dbus_data->path_data; + + dbus_message_get_args(msg, NULL, + DBUS_TYPE_BYTE, &scan_mode, + DBUS_TYPE_INVALID); + + switch (scan_mode) { + case MODE_OFF: + hci_mode = SCAN_DISABLED; + break; + case MODE_CONNECTABLE: + hci_mode = SCAN_PAGE; + break; + case MODE_DISCOVERABLE: + hci_mode = (SCAN_PAGE | SCAN_INQUIRY); + break; + default: + /* invalid mode */ + reply = bluez_new_failure_msg(msg, BLUEZ_EDBUS_WRONG_PARAM); + goto failed; + } + + dd = hci_open_dev(dbus_data->dev_id); + if (dd < 0) { + syslog(LOG_ERR, "HCI device open failed: hci%d", dbus_data->dev_id); + reply = bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_ENODEV); + goto failed; + } + + /* Check if the new requested mode is different from the current */ + if (current_mode != hci_mode) { + memset(&rq, 0, sizeof(rq)); + rq.ogf = OGF_HOST_CTL; + rq.ocf = OCF_WRITE_SCAN_ENABLE; + rq.cparam = &hci_mode; + rq.clen = sizeof(hci_mode); + rq.rparam = &status; + rq.rlen = sizeof(status); + + if (hci_send_req(dd, &rq, 100) < 0) { + syslog(LOG_ERR, "Sending write scan enable command failed: %s (%d)", + strerror(errno), errno); + reply = bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET | errno); + goto failed; + } + if (status) { + syslog(LOG_ERR, "Setting scan enable failed with status 0x%02x", status); + reply = bluez_new_failure_msg(msg, BLUEZ_EBT_OFFSET | status); + goto failed; + } + + } + + reply = dbus_message_new_method_return(msg); + +failed: + if (dd >= 0) + close(dd); + + return reply; +} + +static DBusMessage* handle_dev_discover_req(DBusMessage *msg, void *data) +{ + DBusMessage *reply = NULL; + inquiry_cp cp; + evt_cmd_status rp; + struct hci_request rq; + struct hci_dbus_data *dbus_data = data; + int dd = -1; + uint8_t length = 8, num_rsp = 0; + uint32_t lap = 0x9e8b33; + + dd = hci_open_dev(dbus_data->dev_id); + if (dd < 0) { + syslog(LOG_ERR, "Unable to open device %d: %s (%d)", + dbus_data->dev_id, strerror(errno), errno); + reply = bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET + errno); + goto failed; + } + + memset(&cp, 0, sizeof(cp)); + cp.lap[0] = lap & 0xff; + cp.lap[1] = (lap >> 8) & 0xff; + cp.lap[2] = (lap >> 16) & 0xff; + cp.length = length; + cp.num_rsp = num_rsp; + + 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, 100) < 0) { + syslog(LOG_ERR, "Unable to start inquiry: %s (%d)", + strerror(errno), errno); + reply = bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET + errno); + goto failed; + } + + reply = dbus_message_new_method_return(msg); + +failed: + if (dd >= 0) + hci_close_dev(dd); + + return reply; + +} + +static DBusMessage* handle_dev_discover_cache_req(DBusMessage *msg, void *data) +{ + /*FIXME: */ + return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED); +} + +static DBusMessage* handle_dev_discover_cancel_req(DBusMessage *msg, void *data) +{ + DBusMessage *reply = NULL; + struct hci_request rq; + struct hci_dbus_data *dbus_data = data; + uint8_t status; + int dd = -1; + + dd = hci_open_dev(dbus_data->dev_id); + if (dd < 0) { + syslog(LOG_ERR, "Unable to open device %d: %s (%d)", + dbus_data->dev_id, strerror(errno), errno); + reply = bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET + errno); + goto failed; + } + + memset(&rq, 0, sizeof(rq)); + rq.ogf = OGF_LINK_CTL; + rq.ocf = OCF_INQUIRY_CANCEL; + rq.rparam = &status; + rq.rlen = sizeof(status); + + if (hci_send_req(dd, &rq, 100) < 0) { + syslog(LOG_ERR, "Sending cancel inquiry failed: %s (%d)", + strerror(errno), errno); + reply = bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET + errno); + goto failed; + } + + if (status) { + syslog(LOG_ERR, "Cancel inquiry failed with status 0x%02x", status); + reply = bluez_new_failure_msg(msg, BLUEZ_EBT_OFFSET + status); + goto failed; + } + + reply = dbus_message_new_method_return(msg); + +failed: + if (dd >= 0) + hci_close_dev(dd); + + return reply; +} + +static DBusMessage* handle_dev_discover_service_req(DBusMessage *msg, void *data) +{ + /*FIXME: */ + return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED); +} + +static DBusMessage* handle_dev_last_seen_req(DBusMessage *msg, void *data) +{ + /*FIXME: */ + return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED); +} + +static DBusMessage* handle_dev_last_used_req(DBusMessage *msg, void *data) +{ + /*FIXME: */ + return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED); +} + +static DBusMessage* handle_dev_remote_alias_req(DBusMessage *msg, void *data) +{ + /*FIXME: */ + return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED); +} + +static DBusMessage* handle_dev_remote_name_req(DBusMessage *msg, void *data) +{ + DBusConnection *connection = get_dbus_connection(); + DBusMessage *reply = NULL; + DBusMessage *signal = NULL; + struct hci_dbus_data *dbus_data = data; + const char *str_bdaddr; + char *name; + char path[MAX_PATH_LENGTH]; + bdaddr_t bdaddr; + struct hci_dev_info di; + struct hci_request rq; + remote_name_req_cp cp; + evt_cmd_status rp; + int dd = -1; + + dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &str_bdaddr, + DBUS_TYPE_INVALID); + + str2ba(str_bdaddr, &bdaddr); + if (hci_devinfo(dbus_data->dev_id, &di) < 0) { + syslog(LOG_ERR, "Can't get device info"); + reply = bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_ENODEV); + goto failed; + } + + /* Try retrieve from local cache */ + name = get_peer_name(&di.bdaddr, &bdaddr); + if (name) { + + reply = dbus_message_new_method_return(msg); + + snprintf(path, sizeof(path), "%s/hci%d", DEVICE_PATH, dbus_data->dev_id); + + signal = dbus_message_new_signal(path, DEVICE_INTERFACE, + DEV_SIG_REMOTE_NAME); + + dbus_message_append_args(signal, + DBUS_TYPE_STRING, &str_bdaddr, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_INVALID); + + if (dbus_connection_send(connection, signal, NULL) == FALSE) { + syslog(LOG_ERR, "Can't send D-BUS remote name signal message"); + goto failed; + } + + dbus_message_unref(signal); + free(name); + + } else { + + /* Send HCI command */ + dd = hci_open_dev(dbus_data->dev_id); + if (dd < 0) { + syslog(LOG_ERR, "Unable to open device %d: %s (%d)", + dbus_data->dev_id, strerror(errno), errno); + reply = bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET | errno); + goto failed; + } + + memset(&cp, 0, sizeof(cp)); + cp.bdaddr = bdaddr; + cp.pscan_rep_mode = 0x02; + + memset(&rq, 0, sizeof(rq)); + rq.ogf = OGF_LINK_CTL; + rq.ocf = OCF_REMOTE_NAME_REQ; + rq.cparam = &cp; + rq.clen = REMOTE_NAME_REQ_CP_SIZE; + rq.rparam = &rp; + rq.rlen = EVT_CMD_STATUS_SIZE; + rq.event = EVT_CMD_STATUS; + + if (hci_send_req(dd, &rq, 100) < 0) { + syslog(LOG_ERR, "Unable to send remote name request: %s (%d)", + strerror(errno), errno); + reply = bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET | errno); + goto failed; + } + + if (rp.status) { + syslog(LOG_ERR, "Remote name request failed"); + reply = bluez_new_failure_msg(msg, BLUEZ_EBT_OFFSET | rp.status); + goto failed; + } + } + + reply = dbus_message_new_method_return(msg); +failed: + if (dd >= 0) + hci_close_dev(dd); + + return reply; +} + +static DBusMessage* handle_dev_remote_version_req(DBusMessage *msg, void *data) +{ + /*FIXME: */ + return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED); +} + +static DBusMessage* handle_dev_create_bonding_req(DBusMessage *msg, void *data) +{ + struct hci_request rq; + auth_requested_cp cp; + evt_cmd_status rp; + DBusMessage *reply = NULL; + char *str_bdaddr = NULL; + struct hci_dbus_data *dbus_data = data; + struct hci_conn_info_req *cr = NULL; + bdaddr_t bdaddr; + int dev_id = -1; + int dd = -1; + + dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &str_bdaddr, + DBUS_TYPE_INVALID); + + str2ba(str_bdaddr, &bdaddr); + + dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr); + + if (dev_id < 0) { + reply = bluez_new_failure_msg(msg, BLUEZ_EDBUS_CONN_NOT_FOUND); + goto failed; + } + + if (dbus_data->dev_id != dev_id) { + reply = bluez_new_failure_msg(msg, BLUEZ_EDBUS_CONN_NOT_FOUND); + goto failed; + } + + dd = hci_open_dev(dev_id); + if (dd < 0) { + reply = bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_ENODEV); + goto failed; + } + + cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); + if (!cr) { + reply = bluez_new_failure_msg(msg, BLUEZ_EDBUS_NO_MEM); + goto failed; + } + + bacpy(&cr->bdaddr, &bdaddr); + cr->type = ACL_LINK; + + if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) { + reply = bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET + errno); + goto failed; + } + + memset(&cp, 0, sizeof(cp)); + cp.handle = cr->conn_info->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, 100) < 0) { + syslog(LOG_ERR, "Unable to send authentication request: %s (%d)", + strerror(errno), errno); + reply = bluez_new_failure_msg(msg, BLUEZ_ESYSTEM_OFFSET + errno); + goto failed; + } + + reply = dbus_message_new_method_return(msg); + +failed: + if (dd >= 0) + close(dd); + + if (cr) + free(cr); + + return reply; +} + +static DBusMessage* handle_dev_list_bondings_req(DBusMessage *msg, void *data) +{ + /*FIXME: */ + return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED); +} + +static DBusMessage* handle_dev_has_bonding_req(DBusMessage *msg, void *data) +{ + /*FIXME: */ + return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED); +} + +static DBusMessage* handle_dev_remove_bonding_req(DBusMessage *msg, void *data) +{ + /*FIXME: */ + return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED); +} + + +static DBusMessage* handle_dev_pin_code_length_req(DBusMessage *msg, void *data) +{ + /*FIXME: */ + return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED); +} + +static DBusMessage* handle_dev_encryption_key_size_req(DBusMessage *msg, void *data) +{ + /*FIXME: */ + return bluez_new_failure_msg(msg, BLUEZ_EDBUS_NOT_IMPLEMENTED); +} + +static const struct service_data dev_services[] = { + { DEV_GET_ADDRESS, handle_dev_get_address_req, DEV_GET_ADDRESS_SIGNATURE }, + { DEV_GET_ALIAS, handle_dev_get_alias_req, DEV_GET_ALIAS_SIGNATURE }, + { DEV_GET_COMPANY, handle_dev_get_company_req, DEV_GET_COMPANY_SIGNATURE }, + { DEV_GET_DISCOVERABLE_TO, handle_dev_get_discoverable_to_req, DEV_GET_DISCOVERABLE_TO_SIGNATURE }, + { DEV_GET_FEATURES, handle_dev_get_features_req, DEV_GET_FEATURES_SIGNATURE }, + { DEV_GET_MANUFACTURER, handle_dev_get_manufacturer_req, DEV_GET_MANUFACTURER_SIGNATURE }, + { DEV_GET_MODE, handle_dev_get_mode_req, DEV_GET_MODE_SIGNATURE }, + { DEV_GET_NAME, handle_dev_get_name_req, DEV_GET_NAME_SIGNATURE }, + { DEV_GET_REVISION, handle_dev_get_revision_req, DEV_GET_REVISION_SIGNATURE }, + { DEV_GET_VERSION, handle_dev_get_version_req, DEV_GET_VERSION_SIGNATURE }, + + { DEV_IS_CONNECTABLE, handle_dev_is_connectable_req, DEV_IS_CONNECTABLE_SIGNATURE }, + { DEV_IS_DISCOVERABLE, handle_dev_is_discoverable_req, DEV_IS_DISCOVERABLE_SIGNATURE }, + + { DEV_SET_ALIAS, handle_dev_set_alias_req, DEV_SET_ALIAS_SIGNATURE }, + { DEV_SET_CLASS, handle_dev_set_class_req, DEV_SET_CLASS_SIGNATURE }, + { DEV_SET_DISCOVERABLE_TO, handle_dev_set_discoverable_to_req, DEV_SET_DISCOVERABLE_TO_SIGNATURE }, + { DEV_SET_MODE, handle_dev_set_mode_req, DEV_SET_MODE_SIGNATURE }, + { DEV_SET_NAME, handle_dev_set_name_req, DEV_SET_NAME_SIGNATURE }, + + { DEV_DISCOVER, handle_dev_discover_req, DEV_DISCOVER_SIGNATURE }, + { DEV_DISCOVER_CACHE, handle_dev_discover_cache_req, DEV_DISCOVER_CACHE_SIGNATURE }, + { DEV_DISCOVER_CANCEL, handle_dev_discover_cancel_req, DEV_DISCOVER_CANCEL_SIGNATURE }, + { DEV_DISCOVER_SERVICE, handle_dev_discover_service_req, DEV_DISCOVER_SERVICE_SIGNATURE }, + + { DEV_LAST_SEEN, handle_dev_last_seen_req, DEV_LAST_SEEN_SIGNATURE }, + { DEV_LAST_USED, handle_dev_last_used_req, DEV_LAST_USED_SIGNATURE }, + + { DEV_REMOTE_ALIAS, handle_dev_remote_alias_req, DEV_REMOTE_ALIAS_SIGNATURE }, + { DEV_REMOTE_NAME, handle_dev_remote_name_req, DEV_REMOTE_NAME_SIGNATURE }, + { DEV_REMOTE_VERSION, handle_dev_remote_version_req, DEV_REMOTE_VERSION_SIGNATURE }, + + { DEV_CREATE_BONDING, handle_dev_create_bonding_req, DEV_CREATE_BONDING_SIGNATURE }, + { DEV_LIST_BONDINGS, handle_dev_list_bondings_req, DEV_LIST_BONDINGS_SIGNATURE }, + { DEV_HAS_BONDING_NAME, handle_dev_has_bonding_req, DEV_HAS_BONDING_SIGNATURE }, + { DEV_REMOVE_BONDING, handle_dev_remove_bonding_req, DEV_REMOVE_BONDING_SIGNATURE }, + + { DEV_PIN_CODE_LENGTH, handle_dev_pin_code_length_req, DEV_PIN_CODE_LENGTH_SIGNATURE }, + { DEV_ENCRYPTION_KEY_SIZE, handle_dev_encryption_key_size_req, DEV_ENCRYPTION_KEY_SIZE_SIGNATURE }, + + { NULL, NULL, NULL} +}; + +DBusHandlerResult msg_func_device(DBusConnection *conn, DBusMessage *msg, void *data) +{ + const struct service_data *handlers = dev_services; + DBusMessage *reply = NULL; + struct hci_dbus_data *dbus_data = data; + const char *method; + const char *signature; + uint32_t error = BLUEZ_EDBUS_UNKNOWN_METHOD; + DBusHandlerResult ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + method = dbus_message_get_member(msg); + signature = dbus_message_get_signature(msg); + + syslog(LOG_INFO, "[%s,%d] path:%s, method:%s", __PRETTY_FUNCTION__, __LINE__, dbus_message_get_path(msg), method); + + if (dbus_data->path_id == DEVICE_ROOT_ID) { + /* Device is down(path unregistered) or the path is wrong */ + ret = DBUS_HANDLER_RESULT_HANDLED; + error = BLUEZ_EDBUS_UNKNOWN_PATH; + goto failed; + } + + /* It's a device path id */ + for (; handlers->name != NULL; handlers++) { + if (strcmp(handlers->name, method)) + continue; + + ret = DBUS_HANDLER_RESULT_HANDLED; + + if (!strcmp(handlers->signature, signature)) { + reply = handlers->handler_func(msg, data); + error = 0; + break; + } else { + /* Set the error, but continue looping incase there is + * another method with the same name but a different + * signature */ + error = BLUEZ_EDBUS_WRONG_SIGNATURE; + continue; + } + } + +failed: + if (error) + reply = bluez_new_failure_msg(msg, error); + + if (reply) { + if (!dbus_connection_send (conn, reply, NULL)) + syslog(LOG_ERR, "Can't send reply message!"); + dbus_message_unref(reply); + } + + return ret; +} |