📄 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 "logging.h"#include "textfile.h"#include "hcid.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 "storage.h"static DBusConnection *connection = NULL;const char *class_to_icon(uint32_t class){ switch ((class & 0x1f00) >> 8) { case 0x01: return "computer"; case 0x02: switch ((class & 0xfc) >> 2) { case 0x01: case 0x02: case 0x03: case 0x05: return "phone"; case 0x04: return "modem"; } break; case 0x03: return "network-wireless"; case 0x04: switch ((class & 0xfc) >> 2) { case 0x01: case 0x02: return "audio-card"; /* Headset */ case 0x06: return "audio-card"; /* Headphone */ } break; case 0x05: switch ((class & 0xc0) >> 6) { case 0x00: switch ((class & 0x1e) >> 2) { case 0x01: case 0x02: return "input-gaming"; } break; case 0x01: return "input-keyboard"; case 0x02: switch ((class & 0x1e) >> 2) { case 0x05: return "input-tablet"; default: return "input-mouse"; } } break; case 0x06: if (class & 0x80) return "printer"; if (class & 0x20) return "camera-photo"; break; } return NULL;}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"); }}/***************************************************************** * * 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 btd_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; uint16_t dev_id = adapter_get_dev_id(adapter); struct bonding_request_info *bonding = adapter_get_bonding_info(adapter); /* No need to reply anything if the authentication already failed */ if (bonding && 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; } adapter_get_address(adapter, &sba); device_get_address(device, &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 btd_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; } if (!adapter_pairing_initiator(adapter, &ci->bdaddr) && !adapter_is_pairable(adapter)) return -EPERM; ba2str(&ci->bdaddr, addr); device = adapter_find_device(adapter, addr); if (device) agent = device_get_agent(device); if (!agent) agent = adapter_get_agent(adapter); 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 btd_adapter *adapter = device_get_adapter(device); user_confirm_reply_cp cp; int dd; struct pending_auth_info *auth; uint16_t dev_id = adapter_get_dev_id(adapter); struct bonding_request_info *bonding = adapter_get_bonding_info(adapter); /* No need to reply anything if the authentication already failed */ if (bonding && 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)); device_get_address(device, &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 btd_adapter *adapter = device_get_adapter(device); user_passkey_reply_cp cp; bdaddr_t dba; int dd; struct pending_auth_info *auth; uint16_t dev_id = adapter_get_dev_id(adapter); struct bonding_request_info *bonding = adapter_get_bonding_info(adapter); /* No need to reply anything if the authentication already failed */ if (bonding && bonding->hci_status) return; dd = hci_open_dev(dev_id); if (dd < 0) { error("Unable to open hci%d", dev_id); return; } device_get_address(device, &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); if (dev_id < 0) return dev_id; dd = hci_open_dev(dev_id); if (dd < 0) return dd; memset(&req, 0, sizeof(req)); bacpy(&req.bdaddr, remote); err = ioctl(dd, HCIGETAUTHINFO, (unsigned long) &req); if (err < 0) { debug("HCIGETAUTHINFO failed: %s (%d)", strerror(errno), errno); hci_close_dev(dd); return err; } hci_close_dev(dd); if (auth) *auth = req.type; return 0;}int hcid_dbus_user_confirm(bdaddr_t *sba, bdaddr_t *dba, uint32_t passkey){ struct btd_adapter *adapter; struct btd_device *device; struct agent *agent; char addr[18]; uint8_t type; struct pending_auth_info *auth; uint16_t dev_id; adapter = manager_find_adapter(sba); if (!adapter) { error("No matching adapter found"); return -1; } dev_id = adapter_get_dev_id(adapter); if (get_auth_requirements(sba, dba, &type) < 0) { int dd; dd = hci_open_dev(dev_id); if (dd < 0) { error("Unable to open hci%d", dev_id); return -1; } hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_CONFIRM_NEG_REPLY, 6, dba); hci_close_dev(dd); return 0; } ba2str(dba, addr); device = adapter_get_device(connection, adapter, addr); if (!device) { error("Device creation failed"); return -1; } /* If no MITM protection required, auto-accept */ if (!(device_get_auth(device) & 0x01) && !(type & 0x01)) { int dd; dd = hci_open_dev(dev_id); if (dd < 0) { error("Unable to open hci%d", dev_id); return -1; } hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_CONFIRM_REPLY, 6, dba); hci_close_dev(dd); auth = adapter_new_auth_request(adapter, dba, AUTH_TYPE_CONFIRM); auth->replied = TRUE; return 0; } agent = device_get_agent(device); if (!agent) agent = adapter_get_agent(adapter); if (!agent) { error("No agent available for user confirm request"); return -1; } if (agent_request_confirmation(agent, device, passkey, confirm_cb, device) < 0) { error("Requesting passkey failed"); return -1; } auth = adapter_new_auth_request(adapter, dba, AUTH_TYPE_CONFIRM); auth->agent = agent; return 0;}int hcid_dbus_user_passkey(bdaddr_t *sba, bdaddr_t *dba){ struct btd_adapter *adapter; struct btd_device *device; struct agent *agent = NULL; char addr[18]; struct pending_auth_info *auth; adapter = manager_find_adapter(sba); if (!adapter) { error("No matching adapter found"); return -1; } ba2str(dba, addr); device = adapter_get_device(connection, adapter, addr); if (device) agent = device_get_agent(device); if (!agent) agent = adapter_get_agent(adapter); if (!agent) { error("No agent available for user confirm request"); return -1; } if (agent_request_passkey(agent, device, passkey_cb, device) < 0) { error("Requesting passkey failed"); return -1; } auth = adapter_new_auth_request(adapter, dba, AUTH_TYPE_PASSKEY); auth->agent = agent; return 0;}int hcid_dbus_user_notify(bdaddr_t *sba, bdaddr_t *dba, uint32_t passkey){ struct btd_adapter *adapter; struct btd_device *device; struct agent *agent = NULL; char addr[18]; struct pending_auth_info *auth; adapter = manager_find_adapter(sba); if (!adapter) { error("No matching adapter found"); return -1; } ba2str(dba, addr); device = adapter_get_device(connection, adapter, addr); if (device) agent = device_get_agent(device); if (!agent) agent = adapter_get_agent(adapter); if (!agent) { error("No agent available for user confirm request"); return -1; } if (agent_display_passkey(agent, device, passkey) < 0) { error("Displaying passkey failed"); return -1; } auth = adapter_new_auth_request(adapter, dba, AUTH_TYPE_NOTIFY); auth->agent = agent; return 0;}void hcid_dbus_bonding_process_complete(bdaddr_t *local, bdaddr_t *peer, uint8_t status){ struct btd_adapter *adapter; char peer_addr[18]; DBusMessage *reply;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -