summaryrefslogtreecommitdiffstats
path: root/hcid/dbus-device.c
diff options
context:
space:
mode:
Diffstat (limited to 'hcid/dbus-device.c')
-rw-r--r--hcid/dbus-device.c822
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;
+}