📄 dbus-hci.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 <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 <gdbus.h>#include "hcid.h"#include "textfile.h"#include "manager.h"#include "adapter.h"#include "device.h"#include "error.h"#include "glib-helper.h"#include "dbus-common.h"#include "agent.h"#include "dbus-hci.h"static DBusConnection *connection = NULL;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);}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 0x13: /* user ended the connection */ 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 void adapter_mode_changed(struct adapter *adapter, uint8_t scan_mode){ const char *mode; const gchar *path = adapter_get_path(adapter); adapter_set_scan_mode(adapter, scan_mode); switch (scan_mode) { 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_set_discov_timeout(adapter, adapter->discov_timeout * 1000); 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_set_discov_timeout(adapter, adapter->discov_timeout * 1000); /* ignore, this event should not be sent*/ default: /* ignore, reserved */ return; } dbus_connection_emit_property_changed(connection, path, ADAPTER_INTERFACE, "Mode", DBUS_TYPE_STRING, &mode);}/***************************************************************** * * Section reserved to HCI commands confirmation handling and low * level events(eg: device attached/dettached. * *****************************************************************/static void pincode_cb(struct agent *agent, DBusError *err, const char *pincode, struct btd_device *device){ struct adapter *adapter = device_get_adapter(device); pin_code_reply_cp pr; bdaddr_t sba, dba; size_t len; int dev; struct pending_auth_info *auth; const gchar *destination = device_get_address(device); uint16_t dev_id = adapter_get_dev_id(adapter); const gchar *source = adapter_get_address(adapter); /* No need to reply anything if the authentication already failed */ if (adapter->bonding && adapter->bonding->hci_status) return; dev = hci_open_dev(dev_id); if (dev < 0) { error("hci_open_dev(%d): %s (%d)", dev_id, strerror(errno), errno); return; } str2ba(source, &sba); str2ba(destination, &dba); auth = adapter_find_auth_request(adapter, &dba); if (err) { hci_send_cmd(dev, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, 6, &dba); goto done; } len = strlen(pincode); set_pin_length(&sba, len); memset(&pr, 0, sizeof(pr)); bacpy(&pr.bdaddr, &dba); memcpy(pr.pin_code, pincode, len); pr.pin_len = len; hci_send_cmd(dev, OGF_LINK_CTL, OCF_PIN_CODE_REPLY, PIN_CODE_REPLY_CP_SIZE, &pr);done: if (auth) { auth->replied = TRUE; auth->agent = NULL; } hci_close_dev(dev);}int hcid_dbus_request_pin(int dev, bdaddr_t *sba, struct hci_conn_info *ci){ char addr[18]; struct adapter *adapter; struct btd_device *device; struct agent *agent = NULL; int ret; adapter = manager_find_adapter(sba); if (!adapter) { error("No matching adapter found"); return -1; } ba2str(&ci->bdaddr, addr); device = adapter_find_device(adapter, addr); if (device) agent = device_get_agent(device); if (!agent) agent = adapter->agent; if (!agent) return -EPERM; if (!device) { device = adapter_create_device(connection, adapter, addr); if (!device) return -ENODEV; } ret = agent_request_pincode(agent, device, (agent_pincode_cb) pincode_cb, device); if (ret == 0) { struct pending_auth_info *auth; auth = adapter_new_auth_request(adapter, &ci->bdaddr, AUTH_TYPE_PINCODE); auth->agent = agent; } return ret;}static void confirm_cb(struct agent *agent, DBusError *err, void *user_data){ struct btd_device *device = user_data; struct adapter *adapter = device_get_adapter(device); user_confirm_reply_cp cp; int dd; struct pending_auth_info *auth; const gchar *destination = device_get_address(device); uint16_t dev_id = adapter_get_dev_id(adapter); /* No need to reply anything if the authentication already failed */ if (adapter->bonding && adapter->bonding->hci_status) return; dd = hci_open_dev(dev_id); if (dd < 0) { error("Unable to open hci%d", dev_id); return; } memset(&cp, 0, sizeof(cp)); str2ba(destination, &cp.bdaddr); auth = adapter_find_auth_request(adapter, &cp.bdaddr); if (err) hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_CONFIRM_NEG_REPLY, USER_CONFIRM_REPLY_CP_SIZE, &cp); else hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_CONFIRM_REPLY, USER_CONFIRM_REPLY_CP_SIZE, &cp); if (auth) { auth->replied = TRUE; auth->agent = FALSE; } hci_close_dev(dd);}static void passkey_cb(struct agent *agent, DBusError *err, uint32_t passkey, void *user_data){ struct btd_device *device = user_data; struct adapter *adapter = device_get_adapter(device); user_passkey_reply_cp cp; bdaddr_t dba; int dd; struct pending_auth_info *auth; const gchar *destination = device_get_address(device); uint16_t dev_id = adapter_get_dev_id(adapter); /* No need to reply anything if the authentication already failed */ if (adapter->bonding && adapter->bonding->hci_status) return; dd = hci_open_dev(dev_id); if (dd < 0) { error("Unable to open hci%d", dev_id); return; } str2ba(destination, &dba); memset(&cp, 0, sizeof(cp)); bacpy(&cp.bdaddr, &dba); cp.passkey = passkey; auth = adapter_find_auth_request(adapter, &dba); if (err) hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_PASSKEY_NEG_REPLY, 6, &dba); else hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_PASSKEY_REPLY, USER_PASSKEY_REPLY_CP_SIZE, &cp); if (auth) { auth->replied = TRUE; auth->agent = NULL; } hci_close_dev(dd);}static int get_auth_requirements(bdaddr_t *local, bdaddr_t *remote, uint8_t *auth){ struct hci_auth_info_req req; char addr[18]; int err, dd, dev_id; ba2str(local, addr); dev_id = hci_devid(addr);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -