📄 dbus.c
字号:
/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2006 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#include <stdio.h>#include <errno.h>#include <unistd.h>#include <signal.h>#include <string.h>#include <syslog.h>#include <sys/ioctl.h>#include <sys/socket.h>#include <sys/time.h>#include <bluetooth/bluetooth.h>#include <bluetooth/hci.h>#include <bluetooth/hci_lib.h>#include <dbus/dbus.h>#include "glib-ectomy.h"#include "hcid.h"#include "dbus.h"#ifndef DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT#define DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT 0x00#endifstatic DBusConnection *connection;static int default_dev = -1;#define TIMEOUT (30 * 1000) /* 30 seconds */#define DBUS_RECONNECT_TIMER (5 * 1000 * 1000) /* 5 sec */#define MAX_PATH_LENGTH 64#define MAX_CONN_NUMBER 10#define PINAGENT_SERVICE_NAME BASE_INTERFACE ".PinAgent"#define PINAGENT_INTERFACE PINAGENT_SERVICE_NAME#define PIN_REQUEST "PinRequest"#define PINAGENT_PATH BASE_PATH "/PinAgent"struct pin_request { int dev; bdaddr_t bda;};typedef DBusMessage* (service_handler_func_t) (DBusMessage *, void *);struct service_data { const char *name; service_handler_func_t *handler_func; const char *signature;};struct hci_dbus_data { uint16_t dev_id; uint16_t path_id; uint32_t path_data;};typedef int register_function_t(DBusConnection *conn, uint16_t id);typedef int unregister_function_t(DBusConnection *conn, uint16_t id);const struct service_data *get_hci_table(void);static int hci_dbus_reg_obj_path(DBusConnection *conn, uint16_t id);static int hci_dbus_unreg_obj_path(DBusConnection *conn, uint16_t id);typedef const struct service_data *get_svc_table_func_t(void);struct profile_obj_path_data { uint16_t id; register_function_t *reg_func; unregister_function_t *unreg_func; get_svc_table_func_t *get_svc_table; /* return the service table */};/* * D-Bus error messages functions and declarations. * This section should be moved to a common file * in the future * */typedef struct { uint32_t code; const char *str;} bluez_error_t;typedef struct { char *str; unsigned int val;} hci_map;static hci_map dev_flags_map[] = { { "INIT", HCI_INIT }, { "RUNNING", HCI_RUNNING }, { "RAW", HCI_RAW }, { "PSCAN", HCI_PSCAN }, { "ISCAN", HCI_ISCAN }, { "INQUIRY", HCI_INQUIRY }, { "AUTH", HCI_AUTH }, { "ENCRYPT", HCI_ENCRYPT }, { "SECMGR", HCI_SECMGR }, { NULL }};static const bluez_error_t dbus_error_array[] = { { BLUEZ_EDBUS_UNKNOWN_METHOD, "Method not found" }, { BLUEZ_EDBUS_WRONG_SIGNATURE, "Wrong method signature" }, { BLUEZ_EDBUS_WRONG_PARAM, "Invalid parameters" }, { BLUEZ_EDBUS_RECORD_NOT_FOUND, "No record found" }, { BLUEZ_EDBUS_NO_MEM, "No memory" }, { BLUEZ_EDBUS_CONN_NOT_FOUND, "Connection not found" }, { BLUEZ_EDBUS_UNKNOWN_PATH, "Unknown D-BUS path" }, { BLUEZ_EDBUS_NOT_IMPLEMENTED, "Method not implemented" }, { 0, NULL }};static const bluez_error_t hci_error_array[] = { { HCI_UNKNOWN_COMMAND, "Unknown HCI Command" }, { HCI_NO_CONNECTION, "Unknown Connection Identifier" }, { HCI_HARDWARE_FAILURE, "Hardware Failure" }, { HCI_PAGE_TIMEOUT, "Page Timeout" }, { HCI_AUTHENTICATION_FAILURE, "Authentication Failure" }, { HCI_PIN_OR_KEY_MISSING, "PIN Missing" }, { HCI_MEMORY_FULL, "Memory Capacity Exceeded" }, { HCI_CONNECTION_TIMEOUT, "Connection Timeout" }, { HCI_MAX_NUMBER_OF_CONNECTIONS, "Connection Limit Exceeded" }, { HCI_MAX_NUMBER_OF_SCO_CONNECTIONS, "Synchronous Connection Limit To A Device Exceeded" }, { HCI_ACL_CONNECTION_EXISTS, "ACL Connection Already Exists" }, { HCI_COMMAND_DISALLOWED, "Command Disallowed" }, { HCI_REJECTED_LIMITED_RESOURCES, "Connection Rejected due to Limited Resources" }, { HCI_REJECTED_SECURITY, "Connection Rejected Due To Security Reasons" }, { HCI_REJECTED_PERSONAL, "Connection Rejected due to Unacceptable BD_ADDR" }, { HCI_HOST_TIMEOUT, "Connection Accept Timeout Exceeded" }, { HCI_UNSUPPORTED_FEATURE, "Unsupported Feature or Parameter Value" }, { HCI_INVALID_PARAMETERS, "Invalid HCI Command Parameters" }, { HCI_OE_USER_ENDED_CONNECTION, "Remote User Terminated Connection" }, { HCI_OE_LOW_RESOURCES, "Remote Device Terminated Connection due to Low Resources" }, { HCI_OE_POWER_OFF, "Remote Device Terminated Connection due to Power Off" }, { HCI_CONNECTION_TERMINATED, "Connection Terminated By Local Host" }, { HCI_REPEATED_ATTEMPTS, "Repeated Attempts" }, { HCI_PAIRING_NOT_ALLOWED, "Pairing Not Allowed" }, { HCI_UNKNOWN_LMP_PDU, "Unknown LMP PDU" }, { HCI_UNSUPPORTED_REMOTE_FEATURE, "Unsupported Remote Feature" }, { HCI_SCO_OFFSET_REJECTED, "SCO Offset Rejected" }, { HCI_SCO_INTERVAL_REJECTED, "SCO Interval Rejected" }, { HCI_AIR_MODE_REJECTED, "SCO Air Mode Rejected" }, { HCI_INVALID_LMP_PARAMETERS, "Invalid LMP Parameters" }, { HCI_UNSPECIFIED_ERROR, "Unspecified Error" }, { HCI_UNSUPPORTED_LMP_PARAMETER_VALUE, "Unsupported LMP Parameter Value" }, { HCI_ROLE_CHANGE_NOT_ALLOWED, "Role Change Not Allowed" }, { HCI_LMP_RESPONSE_TIMEOUT, "LMP Response Timeout" }, { HCI_LMP_ERROR_TRANSACTION_COLLISION, "LMP Error Transaction Collision" }, { HCI_LMP_PDU_NOT_ALLOWED, "LMP PDU Not Allowed" }, { HCI_ENCRYPTION_MODE_NOT_ACCEPTED, "Encryption Mode Not Acceptable" }, { HCI_UNIT_LINK_KEY_USED, "Link Key Can Not be Changed" }, { HCI_QOS_NOT_SUPPORTED, "Requested QoS Not Supported" }, { HCI_INSTANT_PASSED, "Instant Passed" }, { HCI_PAIRING_NOT_SUPPORTED, "Pairing With Unit Key Not Supported" }, { HCI_TRANSACTION_COLLISION, "Different Transaction Collision" }, { HCI_QOS_UNACCEPTABLE_PARAMETER, "QoS Unacceptable Parameter" }, { HCI_QOS_REJECTED, "QoS Rejected" }, { HCI_CLASSIFICATION_NOT_SUPPORTED, "Channel Classification Not Supported" }, { HCI_INSUFFICIENT_SECURITY, "Insufficient Security" }, { HCI_PARAMETER_OUT_OF_RANGE, "Parameter Out Of Mandatory Range" }, { HCI_ROLE_SWITCH_PENDING, "Role Switch Pending" }, { HCI_SLOT_VIOLATION, "Reserved Slot Violation" }, { HCI_ROLE_SWITCH_FAILED, "Role Switch Failed" }, { 0, NULL },};static const char *bluez_dbus_error_to_str(const uint32_t ecode) { const bluez_error_t *ptr; uint32_t raw_code = 0; if (ecode & BLUEZ_ESYSTEM_OFFSET) { /* System error */ raw_code = (~BLUEZ_ESYSTEM_OFFSET) & ecode; syslog(LOG_INFO, "%s - msg:%s", __PRETTY_FUNCTION__, strerror(raw_code)); return strerror(raw_code); } else if (ecode & BLUEZ_EDBUS_OFFSET) { /* D-Bus error */ for (ptr = dbus_error_array; ptr->code; ptr++) { if (ptr->code == ecode) { syslog(LOG_INFO, "%s - msg:%s", __PRETTY_FUNCTION__, ptr->str); return ptr->str; } } } else { /* BLUEZ_EBT_OFFSET - Bluetooth HCI errors */ for (ptr = hci_error_array; ptr->code; ptr++) { if (ptr->code == ecode) { syslog(LOG_INFO, "%s - msg:%s", __PRETTY_FUNCTION__, ptr->str); return ptr->str; } } } return NULL;}static DBusMessage *bluez_new_failure_msg(DBusMessage *msg, const uint32_t ecode){ DBusMessageIter iter; DBusMessage *reply; const char *error_msg; error_msg = bluez_dbus_error_to_str(ecode); if (!error_msg) return NULL; reply = dbus_message_new_error(msg, ERROR_INTERFACE, error_msg); dbus_message_iter_init_append(reply, &iter); dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT32 ,&ecode); return reply;}/* * Object path register/unregister functions * */static struct profile_obj_path_data obj_path_table[] = { { HCI_PATH_ID, hci_dbus_reg_obj_path, hci_dbus_unreg_obj_path, get_hci_table }, /* add other profiles here */ { INVALID_PATH_ID, NULL, NULL, NULL }};/* * Virtual table that handle the object path hierarchy */static DBusHandlerResult msg_func_device(DBusConnection *conn, DBusMessage *msg, void *data);static DBusHandlerResult msg_func_manager(DBusConnection *conn, DBusMessage *msg, void *data);static DBusMessage* handle_not_implemented_req(DBusMessage *msg, void *data);static const DBusObjectPathVTable obj_dev_vtable = { .message_function = &msg_func_device, .unregister_function = NULL};static const DBusObjectPathVTable obj_mgr_vtable = { .message_function = &msg_func_manager, .unregister_function = NULL};/* * Services provided under the path DEVICE_PATH */static DBusMessage* handle_device_up_req(DBusMessage *msg, void *data);static DBusMessage* handle_device_down_req(DBusMessage *msg, void *data);static DBusMessage* handle_device_set_property_req(DBusMessage *msg, void *data);static DBusMessage* handle_device_get_property_req(DBusMessage *msg, void *data);static DBusMessage* handle_device_set_property_req_name(DBusMessage *msg, void *data);static DBusMessage* handle_device_get_property_req_name(DBusMessage *msg, void *data);static DBusMessage* handle_device_set_property_req_pscan(DBusMessage *msg, void *data);static DBusMessage* handle_device_set_property_req_iscan(DBusMessage *msg, void *data);static const struct service_data device_services[] = { { DEV_UP, handle_device_up_req, DEV_UP_SIGNATURE }, { DEV_DOWN, handle_device_down_req, DEV_DOWN_SIGNATURE }, { DEV_SET_PROPERTY, handle_device_set_property_req, DEV_SET_PROPERTY_SIGNATURE_BOOL }, { DEV_SET_PROPERTY, handle_device_set_property_req, DEV_SET_PROPERTY_SIGNATURE_STR }, { DEV_SET_PROPERTY, handle_device_set_property_req, DEV_SET_PROPERTY_SIGNATURE_BYTE }, { DEV_GET_PROPERTY, handle_device_get_property_req, DEV_GET_PROPERTY_SIGNATURE }, { NULL, NULL, NULL}};static const struct service_data set_property_services[] = { { DEV_PROPERTY_AUTH, handle_not_implemented_req, DEV_SET_PROPERTY_SIGNATURE_BOOL }, { DEV_PROPERTY_ENCRYPT, handle_not_implemented_req, DEV_SET_PROPERTY_SIGNATURE_BOOL }, { DEV_PROPERTY_PSCAN, handle_device_set_property_req_pscan, DEV_SET_PROPERTY_SIGNATURE_BOOL }, { DEV_PROPERTY_ISCAN, handle_device_set_property_req_iscan, DEV_SET_PROPERTY_SIGNATURE_BOOL }, { DEV_PROPERTY_NAME, handle_device_set_property_req_name, DEV_SET_PROPERTY_SIGNATURE_STR }, { DEV_PROPERTY_INCMODE, handle_not_implemented_req, DEV_SET_PROPERTY_SIGNATURE_BYTE }, { NULL, NULL, NULL}};static const struct service_data get_property_services[] = { { DEV_PROPERTY_DEV_INFO, handle_not_implemented_req, DEV_GET_PROPERTY_SIGNATURE }, { DEV_PROPERTY_NAME, handle_device_get_property_req_name, DEV_GET_PROPERTY_SIGNATURE }, { DEV_PROPERTY_INCMODE, handle_not_implemented_req, DEV_GET_PROPERTY_SIGNATURE }, { NULL, NULL, NULL}};/* * Services provided under the path MANAGER_PATH */static DBusMessage* handle_device_list_req(DBusMessage *msg, void *data);static DBusMessage* handle_default_device_req(DBusMessage *msg, void *data);static const struct service_data manager_services[] = { { MGR_DEVICE_LIST, handle_device_list_req, MGR_GET_DEV_SIGNATURE }, { MGR_DEFAULT_DEVICE, handle_default_device_req, MGR_DEFAULT_DEV_SIGNATURE }, { MGR_INIT, handle_not_implemented_req, NULL }, { MGR_ENABLE, handle_not_implemented_req, NULL }, { MGR_DISABLE, handle_not_implemented_req, NULL }, { NULL, NULL, NULL }};/* * HCI D-Bus services */static DBusHandlerResult hci_signal_filter(DBusConnection *conn, DBusMessage *msg, void *data);static DBusMessage* handle_periodic_inq_req(DBusMessage *msg, void *data);static DBusMessage* handle_cancel_periodic_inq_req(DBusMessage *msg, void *data);static DBusMessage* handle_inq_req(DBusMessage *msg, void *data);static DBusMessage* handle_cancel_inq_req(DBusMessage *msg, void *data);static DBusMessage* handle_role_switch_req(DBusMessage *msg, void *data);static DBusMessage* handle_remote_name_req(DBusMessage *msg, void *data);static DBusMessage* handle_display_conn_req(DBusMessage *msg, void *data);static DBusMessage* handle_auth_req(DBusMessage *msg, void *data);static const struct service_data device_hci_services[] = { { HCI_PERIODIC_INQ, handle_periodic_inq_req, HCI_PERIODIC_INQ_SIGNATURE }, { HCI_PERIODIC_INQ, handle_periodic_inq_req, HCI_PERIODIC_INQ_EXT_SIGNATURE }, { HCI_CANCEL_PERIODIC_INQ, handle_cancel_periodic_inq_req, HCI_CANCEL_PERIODIC_INQ_SIGNATURE }, { HCI_ROLE_SWITCH, handle_role_switch_req, HCI_ROLE_SWITCH_SIGNATURE }, { HCI_INQ, handle_inq_req, HCI_INQ_SIGNATURE }, { HCI_INQ, handle_inq_req, HCI_INQ_EXT_SIGNATURE }, { HCI_CANCEL_INQ, handle_cancel_inq_req, HCI_CANCEL_INQ_SIGNATURE }, { HCI_REMOTE_NAME, handle_remote_name_req, HCI_REMOTE_NAME_SIGNATURE }, { HCI_CONNECTIONS, handle_display_conn_req, HCI_CONNECTIONS_SIGNATURE }, { HCI_AUTHENTICATE, handle_auth_req, HCI_AUTHENTICATE_SIGNATURE }, { NULL, NULL, NULL }};static void reply_handler_function(DBusPendingCall *call, void *user_data){ struct pin_request *req = (struct pin_request *) user_data; pin_code_reply_cp pr; DBusMessage *message; DBusMessageIter iter; int arg_type; int msg_type; size_t len; char *pin; const char *error_msg; message = dbus_pending_call_steal_reply(call); if (!message) goto done; msg_type = dbus_message_get_type(message); dbus_message_iter_init(message, &iter); if (msg_type == DBUS_MESSAGE_TYPE_ERROR) { dbus_message_iter_get_basic(&iter, &error_msg); /* handling WRONG_ARGS_ERROR, DBUS_ERROR_NO_REPLY, DBUS_ERROR_SERVICE_UNKNOWN */ syslog(LOG_ERR, "%s: %s", dbus_message_get_error_name(message), error_msg); hci_send_cmd(req->dev, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, 6, &req->bda); goto done; } /* check signature */ arg_type = dbus_message_iter_get_arg_type(&iter); if (arg_type != DBUS_TYPE_STRING) { syslog(LOG_ERR, "Wrong reply signature: expected PIN"); hci_send_cmd(req->dev, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, 6, &req->bda); } else { dbus_message_iter_get_basic(&iter, &pin); len = strlen(pin); memset(&pr, 0, sizeof(pr)); bacpy(&pr.bdaddr, &req->bda); memcpy(pr.pin_code, pin, len); pr.pin_len = len; hci_send_cmd(req->dev, OGF_LINK_CTL, OCF_PIN_CODE_REPLY, PIN_CODE_REPLY_CP_SIZE, &pr); }done: if (message) dbus_message_unref(message); dbus_pending_call_unref(call);}static void free_pin_req(void *req){ free(req);}static gboolean register_dbus_path(const char *path, uint16_t path_id, uint16_t dev_id, const DBusObjectPathVTable *pvtable, gboolean fallback){ gboolean ret = FALSE; struct hci_dbus_data *data = NULL; data = malloc(sizeof(struct hci_dbus_data)); if (data == NULL) { syslog(LOG_ERR, "Failed to alloc memory to DBUS path register data (%s)", path); goto failed; } data->path_id = path_id; data->dev_id = dev_id; if (fallback) { if (!dbus_connection_register_fallback(connection, path, pvtable, data)) { syslog(LOG_ERR, "DBUS failed to register %s fallback", path); goto failed; } } else { if (!dbus_connection_register_object_path(connection, path, pvtable, data)) { syslog(LOG_ERR, "DBUS failed to register %s object", path); goto failed; } } ret = TRUE;failed: if (!ret && data) free(data); return ret;}static gboolean unregister_dbus_path(const char *path){ void *data; if (dbus_connection_get_object_path_data(connection, path, &data) && data) free(data); if (!dbus_connection_unregister_object_path (connection, path)) { syslog(LOG_ERR, "DBUS failed to unregister %s object", path); return FALSE; } return TRUE;}void hcid_dbus_request_pin(int dev, struct hci_conn_info *ci){ DBusMessage *message = NULL; DBusPendingCall *pending = NULL; struct pin_request *req; uint8_t *addr = (uint8_t *) &ci->bdaddr; dbus_bool_t out = ci->out; if (!connection) { if (!hcid_dbus_init()) goto failed; } message = dbus_message_new_method_call(PINAGENT_SERVICE_NAME, PINAGENT_PATH, PINAGENT_INTERFACE, PIN_REQUEST); if (message == NULL) { syslog(LOG_ERR, "Couldn't allocate D-BUS message"); goto failed; } req = malloc(sizeof(*req)); req->dev = dev; bacpy(&req->bda, &ci->bdaddr);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -