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