📄 adapter.c
字号:
/* * * 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 <sys/ioctl.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 "logging.h"#include "textfile.h"#include "hcid.h"#include "sdpd.h"#include "sdp-xml.h"#include "manager.h"#include "adapter.h"#include "device.h"#include "dbus-common.h"#include "dbus-hci.h"#include "error.h"#include "glib-helper.h"#include "agent.h"#include "storage.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#define check_address(address) bachk(address)static DBusConnection *connection = NULL;static GSList *adapter_drivers = NULL;struct session_req { struct btd_adapter *adapter; DBusConnection *conn; /* Connection reference */ DBusMessage *msg; /* Unreplied message ref */ char *owner; /* Bus name of the owner */ guint id; /* Listener id */ uint8_t mode; /* Requested mode */ int refcount; /* Session refcount */};struct service_auth { service_auth_cb cb; void *user_data;};struct btd_adapter { uint16_t dev_id; int up; char *path; /* adapter object path */ bdaddr_t bdaddr; /* adapter Bluetooth Address */ guint discov_timeout_id; /* discoverable timeout id */ uint32_t discov_timeout; /* discoverable time(sec) */ guint pairable_timeout_id; /* pairable timeout id */ uint32_t pairable_timeout; /* pairable time(sec) */ uint8_t scan_mode; /* scan mode: SCAN_DISABLED, SCAN_PAGE, SCAN_INQUIRY */ uint8_t mode; /* off, connectable, discoverable, limited */ uint8_t global_mode; /* last valid global mode */ int state; /* standard inq, periodic inq, name resloving */ GSList *found_devices; GSList *oor_devices; /* out of range device list */ DBusMessage *discovery_cancel; /* discovery cancel message request */ GSList *passkey_agents; struct agent *agent; /* For the new API */ GSList *active_conn; struct bonding_request_info *bonding; GSList *auth_reqs; /* Received and replied HCI authentication requests */ GSList *devices; /* Devices structure pointers */ GSList *mode_sessions; /* Request Mode sessions */ GSList *disc_sessions; /* Discovery sessions */ guint scheduler_id; /* Scheduler handle */ struct hci_dev dev; /* hci info */ gboolean pairable; /* pairable state */ gboolean first_init; /* Needed for offmode=devdown */};static void adapter_set_pairable_timeout(struct btd_adapter *adapter, guint interval);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 DBusHandlerResult error_failed(DBusConnection *conn, DBusMessage *msg, const char * desc){ return error_common_reply(conn, msg, ERROR_INTERFACE ".Failed", desc);}static DBusHandlerResult error_failed_errno(DBusConnection *conn, DBusMessage *msg, int err){ const char *desc = strerror(err); return error_failed(conn, msg, desc);}static DBusHandlerResult error_connection_attempt_failed(DBusConnection *conn, DBusMessage *msg, int err){ return error_common_reply(conn, msg, ERROR_INTERFACE ".ConnectionAttemptFailed", err > 0 ? strerror(err) : "Connection attempt failed");}static void bonding_request_free(struct bonding_request_info *bonding){ struct btd_device *device; char address[18]; struct agent *agent; if (!bonding) return; if (bonding->msg) dbus_message_unref(bonding->msg); if (bonding->conn) dbus_connection_unref(bonding->conn); if (bonding->io) g_io_channel_unref(bonding->io); ba2str(&bonding->bdaddr, address); device = adapter_find_device(bonding->adapter, address); agent = device_get_agent(device); if (device && agent) { agent_destroy(agent, FALSE); device_set_agent(device, NULL); } g_free(bonding);}static int active_conn_find_by_bdaddr(const void *data, const void *user_data){ const struct active_conn_info *con = data; const bdaddr_t *bdaddr = user_data; return bacmp(&con->bdaddr, bdaddr);}static int active_conn_find_by_handle(const void *data, const void *user_data){ const struct active_conn_info *dev = data; const uint16_t *handle = user_data; if (dev->handle == *handle) return 0; return -1;}static void send_out_of_range(const char *path, GSList *l){ while (l) { const char *peer_addr = l->data; g_dbus_emit_signal(connection, path, ADAPTER_INTERFACE, "DeviceDisappeared", DBUS_TYPE_STRING, &peer_addr, DBUS_TYPE_INVALID); l = l->next; }}static int found_device_cmp(const struct remote_dev_info *d1, const struct remote_dev_info *d2){ int ret; if (bacmp(&d2->bdaddr, BDADDR_ANY)) { ret = bacmp(&d1->bdaddr, &d2->bdaddr); if (ret) return ret; } if (d2->name_status != NAME_ANY) { ret = (d1->name_status - d2->name_status); if (ret) return ret; } return 0;}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;}struct pending_auth_info *adapter_find_auth_request(struct btd_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 btd_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 btd_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;}static void dev_info_free(struct remote_dev_info *dev){ g_free(dev->alias); g_free(dev);}int pending_remote_name_cancel(struct btd_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, HCI_REQ_TIMEOUT) < 0) { error("Remote name cancel failed: %s(%d)", strerror(errno), errno); err = -errno; } /* free discovered devices list */ g_slist_foreach(adapter->found_devices, (GFunc) dev_info_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 btd_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 btd_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); struct agent *agent; char addr[18]; bdaddr_t bdaddr; debug("bonding_request_new(%s)", address); device = adapter_get_device(conn, adapter, address); if (!device) return NULL; device_get_address(device, &bdaddr); ba2str(&bdaddr, addr); 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, addr, 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;}static int set_limited_discoverable(int dd, const uint8_t *cls, gboolean limited){ uint32_t dev_class; int num = (limited ? 2 : 1); uint8_t lap[] = { 0x33, 0x8b, 0x9e, 0x00, 0x8b, 0x9e }; /* * 1: giac * 2: giac + liac */ if (hci_write_current_iac_lap(dd, num, lap, HCI_REQ_TIMEOUT) < 0) { int err = -errno; error("Can't write current IAC LAP: %s(%d)", strerror(err), err); return err; } if (limited) { if (cls[1] & 0x20) return 0; /* Already limited */ dev_class = (cls[2] << 16) | ((cls[1] | 0x20) << 8) | cls[0]; } else { if (!(cls[1] & 0x20)) return 0; /* Already clear */ dev_class = (cls[2] << 16) | ((cls[1] & 0xdf) << 8) | cls[0]; } if (hci_write_class_of_dev(dd, dev_class, HCI_REQ_TIMEOUT) < 0) { int err = -errno; error("Can't write class of device: %s (%d)", strerror(err), err); return err; } return 0;}static const char *mode2str(uint8_t mode){ switch(mode) { case MODE_OFF: return "off"; case MODE_CONNECTABLE: return "connectable"; case MODE_DISCOVERABLE: case MODE_LIMITED: return "discoverable"; default: return "unknown"; }}static uint8_t get_mode(const bdaddr_t *bdaddr, 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) { char onmode[14], srcaddr[18]; ba2str(bdaddr, srcaddr); if (read_on_mode(srcaddr, onmode, sizeof(onmode)) < 0) return MODE_CONNECTABLE; return get_mode(bdaddr, onmode); } else return MODE_UNKNOWN;}static void adapter_remove_discov_timeout(struct btd_adapter *adapter){ if (!adapter) return; if(adapter->discov_timeout_id == 0) return; g_source_remove(adapter->discov_timeout_id); adapter->discov_timeout_id = 0;}static gboolean discov_timeout_handler(gpointer user_data){ struct btd_adapter *adapter = user_data;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -