📄 dbus-test.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#include <stdio.h>#include <errno.h>#include <stdlib.h>#include <bluetooth/bluetooth.h>#include <bluetooth/l2cap.h>#include <bluetooth/sdp.h>#include <glib.h>#include <dbus/dbus.h>#include "dbus.h"#include "dbus-helper.h"#include "hcid.h"#include "dbus-common.h"#include "adapter.h"#include "dbus-hci.h"#include "dbus-error.h"#include "error.h"#include "dbus-test.h"#define L2INFO_TIMEOUT (2 * 1000)enum { AUDIT_STATE_MTU = 0, AUDIT_STATE_FEATURES};struct audit { bdaddr_t peer; bdaddr_t local; /* We need to store the path instead of a pointer to the data * because by the time the audit is processed the adapter * might have gotten removed. Storing only the path allows us to * detect this scenario */ char adapter_path[PATH_MAX]; char *requestor; DBusConnection *conn; GIOChannel *io; guint io_id; guint timeout; int state; uint16_t mtu_result; uint16_t mtu; uint16_t mask_result; uint32_t mask;};static GSList *audits = NULL;static gboolean l2raw_connect_complete(GIOChannel *io, GIOCondition cond, struct audit *audit);static struct audit *audit_new(DBusConnection *conn, DBusMessage *msg, bdaddr_t *peer, bdaddr_t *local){ struct audit *audit; const char *path; const char *requestor; path = dbus_message_get_path(msg); requestor = dbus_message_get_sender(msg); audit = g_new0(struct audit, 1); audit->requestor = g_strdup(requestor); bacpy(&audit->peer, peer); bacpy(&audit->local, local); strncpy(audit->adapter_path, path, sizeof(audit->adapter_path) - 1); audit->conn = dbus_connection_ref(conn); return audit;}static void audit_free(struct audit *audit){ g_free(audit->requestor); dbus_connection_unref(audit->conn); g_free(audit);}static void send_audit_status(struct audit *audit, const char *name){ char addr[18], *addr_ptr = addr; ba2str(&audit->peer, addr); dbus_connection_emit_signal(audit->conn, audit->adapter_path, TEST_INTERFACE, name, DBUS_TYPE_STRING, &addr_ptr, DBUS_TYPE_INVALID);}static void audit_requestor_exited(const char *name, struct audit *audit){ debug("AuditRemoteDevice requestor %s exited", name); audits = g_slist_remove(audits, audit); if (audit->io) { struct adapter *adapter = NULL; send_audit_status(audit, "AuditRemoteDeviceComplete"); dbus_connection_get_object_user_data(audit->conn, audit->adapter_path, (void *) &adapter); if (adapter) bacpy(&adapter->agents_disabled, BDADDR_ANY); g_io_channel_close(audit->io); } if (audit->timeout) g_source_remove(audit->timeout); audit_free(audit);}int audit_addr_cmp(const void *a, const void *b){ const struct audit *audit = a; const bdaddr_t *addr = b; return bacmp(&audit->peer, addr);}static gboolean audit_in_progress(void){ GSList *l; for (l = audits; l != NULL; l = l->next) { struct audit *audit = l->data; if (audit->io) return TRUE; } return FALSE;}static gboolean l2raw_input_timer(struct audit *audit){ error("l2raw_input_timer: Timed out while waiting for input"); send_audit_status(audit, "AuditRemoteDeviceComplete"); g_io_channel_close(audit->io); audits = g_slist_remove(audits, audit); name_listener_remove(audit->conn, audit->requestor, (name_cb_t) audit_requestor_exited, audit); audit_free(audit); return FALSE;}static void handle_mtu_response(struct audit *audit, const l2cap_info_rsp *rsp){ audit->mtu_result = btohs(rsp->result); switch (audit->mtu_result) { case 0x0000: audit->mtu = btohs(bt_get_unaligned((uint16_t *) rsp->data)); debug("Connectionless MTU size is %d", audit->mtu); break; case 0x0001: debug("Connectionless MTU is not supported"); break; }}static void handle_features_response(struct audit *audit, const l2cap_info_rsp *rsp){ audit->mask_result = btohs(rsp->result); switch (audit->mask_result) { case 0x0000: audit->mask = btohl(bt_get_unaligned((uint32_t *) rsp->data)); debug("Extended feature mask is 0x%04x", audit->mask); if (audit->mask & 0x01) debug(" Flow control mode"); if (audit->mask & 0x02) debug(" Retransmission mode"); if (audit->mask & 0x04) debug(" Bi-directional QoS"); break; case 0x0001: debug("Extended feature mask is not supported"); break; }}static gboolean l2raw_data_callback(GIOChannel *io, GIOCondition cond, struct audit *audit){ unsigned char buf[48]; l2cap_cmd_hdr *cmd = (l2cap_cmd_hdr *) buf; l2cap_info_req *req = (l2cap_info_req *) (buf + L2CAP_CMD_HDR_SIZE); l2cap_info_rsp *rsp = (l2cap_info_rsp *) (buf + L2CAP_CMD_HDR_SIZE); int sk, ret, expected; if (cond & G_IO_NVAL) { g_io_channel_unref(io); return FALSE; } if (cond & (G_IO_ERR | G_IO_HUP)) goto failed; sk = g_io_channel_unix_get_fd(io); memset(buf, 0, sizeof(buf)); if (audit->state == AUDIT_STATE_MTU) expected = L2CAP_CMD_HDR_SIZE + L2CAP_INFO_RSP_SIZE + 2; else expected = L2CAP_CMD_HDR_SIZE + L2CAP_INFO_RSP_SIZE + 4; ret = recv(sk, buf, expected, 0); if (ret < 0) { error("Can't receive info response: %s (%d)", strerror(errno), errno); goto failed; } if (ret < L2CAP_CMD_HDR_SIZE) { error("Too little data for l2cap response"); goto failed; } if (cmd->code != L2CAP_INFO_RSP) return TRUE; if (ret < L2CAP_CMD_HDR_SIZE + L2CAP_INFO_RSP_SIZE) { error("Too little data for l2cap info response"); goto failed; } switch (audit->state) { case AUDIT_STATE_MTU: if (rsp->type != htobs(0x0001)) return TRUE; if (audit->timeout) { g_source_remove(audit->timeout); audit->timeout = 0; } handle_mtu_response(audit, rsp); memset(buf, 0, sizeof(buf)); cmd->code = L2CAP_INFO_REQ; cmd->ident = 43; cmd->len = htobs(2); req->type = htobs(0x0002); if (send(sk, buf, L2CAP_CMD_HDR_SIZE + L2CAP_INFO_REQ_SIZE, 0) < 0) { error("Can't send info request:", strerror(errno), errno); goto failed; } audit->timeout = g_timeout_add(L2INFO_TIMEOUT, (GSourceFunc) l2raw_input_timer, audit); audit->state = AUDIT_STATE_FEATURES; return TRUE; case AUDIT_STATE_FEATURES: if (rsp->type != htobs(0x0002)) return TRUE; if (audit->timeout) { g_source_remove(audit->timeout); audit->timeout = 0; } handle_features_response(audit, rsp); break; } write_l2cap_info(&audit->local, &audit->peer, audit->mtu_result, audit->mtu, audit->mask_result, audit->mask);failed: if (audit->timeout) { g_source_remove(audit->timeout); audit->timeout = 0; } send_audit_status(audit, "AuditRemoteDeviceComplete"); g_io_channel_close(io); g_io_channel_unref(io); audits = g_slist_remove(audits, audit); name_listener_remove(audit->conn, audit->requestor, (name_cb_t) audit_requestor_exited, audit); process_audits_list(audit->adapter_path); audit_free(audit); return FALSE;}static gboolean l2raw_connect_complete(GIOChannel *io, GIOCondition cond, struct audit *audit){ unsigned char buf[48]; l2cap_cmd_hdr *cmd = (l2cap_cmd_hdr *) buf; l2cap_info_req *req = (l2cap_info_req *) (buf + L2CAP_CMD_HDR_SIZE); socklen_t len; int sk, ret; struct adapter *adapter = NULL; if (cond & G_IO_NVAL) { g_io_channel_unref(io); return FALSE; } dbus_connection_get_object_user_data(audit->conn, audit->adapter_path, (void *) &adapter); if (adapter) bacpy(&adapter->agents_disabled, BDADDR_ANY); if (cond & (G_IO_ERR | G_IO_HUP)) { error("Error on raw l2cap socket"); goto failed;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -