📄 dbus-hci.c
字号:
/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2007 Nokia Corporation * Copyright (C) 2004-2007 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 <unistd.h>#include <stdlib.h>#include <string.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/sdp.h>#include <glib.h>#include <dbus/dbus.h>#include "hcid.h"#include "dbus.h"#include "textfile.h"#include "manager.h"#include "adapter.h"#include "error.h"#include "dbus-helper.h"#include "dbus-common.h"#include "dbus-error.h"#include "dbus-test.h"#include "dbus-service.h"#include "dbus-security.h"#include "dbus-hci.h"static DBusConnection *connection = NULL;void bonding_request_free(struct bonding_request_info *bonding){ if (!bonding) return; if (bonding->rq) dbus_message_unref(bonding->rq); if (bonding->conn) dbus_connection_unref(bonding->conn); if (bonding->io) g_io_channel_unref(bonding->io); g_free(bonding);}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;}int dev_rssi_cmp(struct remote_dev_info *d1, struct remote_dev_info *d2){ int rssi1, rssi2; rssi1 = d1->rssi < 0 ? -d1->rssi : d1->rssi; rssi2 = d2->rssi < 0 ? -d2->rssi : d2->rssi; return rssi1 - rssi2;}int found_device_add(GSList **list, bdaddr_t *bdaddr, int8_t rssi, name_status_t name_status){ struct remote_dev_info *dev, match; GSList *l; memset(&match, 0, sizeof(struct remote_dev_info)); bacpy(&match.bdaddr, bdaddr); match.name_status = NAME_ANY; /* ignore repeated entries */ l = g_slist_find_custom(*list, &match, (GCompareFunc) found_device_cmp); if (l) { /* device found, update the attributes */ dev = l->data; if (rssi != 0) dev->rssi = rssi; /* Get remote name can be received while inquiring. * Keep in mind that multiple inquiry result events can * be received from the same remote device. */ if (name_status != NAME_NOT_REQUIRED) dev->name_status = name_status; *list = g_slist_sort(*list, (GCompareFunc) dev_rssi_cmp); return -EALREADY; } dev = g_new0(struct remote_dev_info, 1); bacpy(&dev->bdaddr, bdaddr); dev->rssi = rssi; dev->name_status = name_status; *list = g_slist_insert_sorted(*list, dev, (GCompareFunc) dev_rssi_cmp); return 0;}static int found_device_remove(GSList **list, bdaddr_t *bdaddr){ struct remote_dev_info *dev, match; GSList *l; memset(&match, 0, sizeof(struct remote_dev_info)); bacpy(&match.bdaddr, bdaddr); l = g_slist_find_custom(*list, &match, (GCompareFunc) found_device_cmp); if (!l) return -1; dev = l->data; *list = g_slist_remove(*list, dev); g_free(dev); return 0;}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 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;}DBusMessage *new_authentication_return(DBusMessage *msg, uint8_t status){ switch (status) { case 0x00: /* success */ return dbus_message_new_method_return(msg); case 0x04: /* page timeout */ case 0x08: /* connection timeout */ case 0x10: /* connection accept timeout */ case 0x22: /* LMP response timeout */ case 0x28: /* instant passed - is this a timeout? */ return dbus_message_new_error(msg, ERROR_INTERFACE ".AuthenticationTimeout", "Authentication Timeout"); case 0x17: /* too frequent pairing attempts */ return dbus_message_new_error(msg, ERROR_INTERFACE ".RepeatedAttempts", "Repeated Attempts"); case 0x06: case 0x18: /* pairing not allowed (e.g. gw rejected attempt) */ return dbus_message_new_error(msg, ERROR_INTERFACE ".AuthenticationRejected", "Authentication Rejected"); case 0x07: /* memory capacity */ case 0x09: /* connection limit */ case 0x0a: /* synchronous connection limit */ case 0x0d: /* limited resources */ case 0x14: /* terminated due to low resources */ return dbus_message_new_error(msg, ERROR_INTERFACE ".AuthenticationCanceled", "Authentication Canceled"); case 0x05: /* authentication failure */ case 0x0E: /* rejected due to security reasons - is this auth failure? */ case 0x25: /* encryption mode not acceptable - is this auth failure? */ case 0x26: /* link key cannot be changed - is this auth failure? */ case 0x29: /* pairing with unit key unsupported - is this auth failure? */ case 0x2f: /* insufficient security - is this auth failure? */ default: return dbus_message_new_error(msg, ERROR_INTERFACE ".AuthenticationFailed", "Authentication Failed"); }}static dbus_bool_t send_adapter_signal(DBusConnection *conn, int devid, const char *name, int first, ...){ va_list var_args; dbus_bool_t ret; char path[MAX_PATH_LENGTH]; snprintf(path, sizeof(path)-1, "%s/hci%d", BASE_PATH, devid); va_start(var_args, first); ret = dbus_connection_emit_signal_valist(conn, path, ADAPTER_INTERFACE, name, first, var_args); va_end(var_args); return ret;}static void adapter_mode_changed(struct adapter *adapter, const char *path, uint8_t scan_enable){ const char *mode; adapter->scan_enable = scan_enable; switch (scan_enable) { case SCAN_DISABLED: mode = "off"; adapter->mode = MODE_OFF; break; case SCAN_PAGE: mode = "connectable"; adapter->mode = MODE_CONNECTABLE; break; case (SCAN_PAGE | SCAN_INQUIRY): if (adapter->discov_timeout != 0) adapter->timeout_id = g_timeout_add(adapter->discov_timeout * 1000, discov_timeout_handler, adapter); if (adapter->mode == MODE_LIMITED) { mode = "limited"; } else { adapter->mode = MODE_DISCOVERABLE; mode = "discoverable"; } break; case SCAN_INQUIRY: /* Address the scenario where another app changed the scan mode */ if (adapter->discov_timeout != 0) adapter->timeout_id = g_timeout_add(adapter->discov_timeout * 1000, discov_timeout_handler, adapter); /* ignore, this event should not be sent*/ default: /* ignore, reserved */ return; } dbus_connection_emit_signal(connection, path, ADAPTER_INTERFACE, "ModeChanged", DBUS_TYPE_STRING, &mode, DBUS_TYPE_INVALID);}/* * HCI D-Bus services */static void reply_pending_requests(const char *path, struct adapter *adapter){ if (!path || !adapter) return; /* pending bonding */ if (adapter->bonding) { error_authentication_canceled(connection, adapter->bonding->rq); name_listener_remove(connection, dbus_message_get_sender(adapter->bonding->rq), (name_cb_t) create_bond_req_exit, adapter); 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) { DBusMessage *reply; reply = dbus_message_new_method_return(adapter->discovery_cancel); send_message_and_unref(connection, 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 */ dbus_connection_emit_signal(connection, 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) { /* Send periodic discovery stopped signal exit or stop * the device */ dbus_connection_emit_signal(connection, path, ADAPTER_INTERFACE, "PeriodicDiscoveryStopped", DBUS_TYPE_INVALID); /* Stop periodic inquiry initiated by D-Bus client */ if (adapter->pdiscov_requestor) cancel_periodic_discovery(adapter); }}int unregister_adapter_path(const char *path){ struct adapter *adapter = NULL; info("Unregister path: %s", path); dbus_connection_get_object_user_data(connection, path, (void *) &adapter); if (!adapter) goto unreg; /* check pending requests */ reply_pending_requests(path, adapter); cancel_passkey_agent_requests(adapter->passkey_agents, path, NULL); release_passkey_agents(adapter, NULL); if (adapter->discov_requestor) { name_listener_remove(connection, adapter->discov_requestor, (name_cb_t) discover_devices_req_exit, adapter); g_free(adapter->discov_requestor); adapter->discov_requestor = NULL; } if (adapter->pdiscov_requestor) { name_listener_remove(connection, adapter->pdiscov_requestor, (name_cb_t) periodic_discover_req_exit, adapter); 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->pin_reqs) { g_slist_foreach(adapter->pin_reqs, (GFunc) g_free, NULL); g_slist_free(adapter->pin_reqs); adapter->pin_reqs = NULL; } if (adapter->active_conn) { g_slist_foreach(adapter->active_conn, (GFunc) free, NULL); g_slist_free(adapter->active_conn); adapter->active_conn = NULL; } /* Check if there is a pending RemoteDeviceDisconnect request */ if (adapter->pending_dc) { error_no_such_adapter(adapter->pending_dc->conn, adapter->pending_dc->msg); g_source_remove(adapter->pending_dc->timeout_id); dc_pending_timeout_cleanup(adapter); } g_free(adapter);unreg: if (!dbus_connection_destroy_object_path(connection, path)) { error("D-Bus failed to unregister %s object", path); return -1; } return 0;}/***************************************************************** * * Section reserved to HCI commands confirmation handling and low * level events(eg: device attached/dettached. * *****************************************************************/int hcid_dbus_register_device(uint16_t id){ char path[MAX_PATH_LENGTH]; char *pptr = path; struct adapter *adapter; snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id); adapter = g_try_new0(struct adapter, 1); if (!adapter) { error("Failed to alloc memory to D-Bus path register data (%s)", path); return -1; } adapter->dev_id = id; adapter->pdiscov_resolve_names = 1; if (!dbus_connection_create_object_path(connection, path, adapter, NULL)) { error("D-Bus failed to register %s object", path); g_free(adapter); return -1; } if (!adapter_init(connection, path)) { error("Adapter interface init failed"); goto failed; } if (!security_init(connection, path)) { error("Security interface init failed"); goto failed; } if (!test_init(connection, path)) { error("Test interface init failed"); goto failed; } /* * Send the adapter added signal */ dbus_connection_emit_signal(connection, BASE_PATH, MANAGER_INTERFACE, "AdapterAdded", DBUS_TYPE_STRING, &pptr, DBUS_TYPE_INVALID); return 0;failed: dbus_connection_destroy_object_path(connection, path); g_free(adapter); return -1;}int hcid_dbus_unregister_device(uint16_t id){ char path[MAX_PATH_LENGTH]; char *pptr = path; int ret; snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id); dbus_connection_emit_signal(connection, BASE_PATH, MANAGER_INTERFACE, "AdapterRemoved", DBUS_TYPE_STRING, &pptr, DBUS_TYPE_INVALID); ret = unregister_adapter_path(path); if (ret == 0 && get_default_adapter() == id) { int new_default = hci_get_route(NULL); set_default_adapter(new_default); if (new_default >= 0) { snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, new_default); dbus_connection_emit_signal(connection, BASE_PATH, MANAGER_INTERFACE, "DefaultAdapterChanged", DBUS_TYPE_STRING, &pptr, DBUS_TYPE_INVALID); } } return ret;}int hcid_dbus_start_device(uint16_t id){ char path[MAX_PATH_LENGTH]; struct hci_dev_info di; struct adapter* adapter; struct hci_conn_list_req *cl = NULL; struct hci_conn_info *ci; const char *mode; int i, err, dd = -1, ret = -1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -