📄 adapter.c
字号:
const char *mode, void *data){ struct adapter *adapter = data; struct mode_req *req; int ret; if (!adapter->agent) return dbus_message_new_method_return(msg); req = g_new0(struct mode_req, 1); req->adapter = adapter; req->conn = dbus_connection_ref(conn); req->msg = dbus_message_ref(msg); req->mode = str2mode(adapter->address, mode); ret = agent_confirm_mode_change(adapter->agent, mode, confirm_mode_cb, req); if (ret < 0) { dbus_connection_unref(req->conn); dbus_message_unref(req->msg); g_free(req); return invalid_args(msg); } return NULL;}static DBusMessage *set_discoverable_timeout(DBusConnection *conn, DBusMessage *msg, uint32_t timeout, void *data){ struct adapter *adapter = data; bdaddr_t bdaddr; const char *path; if (adapter->discov_timeout_id) { g_source_remove(adapter->discov_timeout_id); adapter->discov_timeout_id = 0; } if ((timeout != 0) && (adapter->scan_mode & SCAN_INQUIRY)) adapter->discov_timeout_id = g_timeout_add(timeout * 1000, discov_timeout_handler, adapter); adapter->discov_timeout = timeout; str2ba(adapter->address, &bdaddr); write_discoverable_timeout(&bdaddr, timeout); path = dbus_message_get_path(msg); dbus_connection_emit_property_changed(conn, path, ADAPTER_INTERFACE, "DiscoverableTimeout", DBUS_TYPE_UINT32, &timeout); return dbus_message_new_method_return(msg);}static void update_ext_inquiry_response(int dd, struct hci_dev *dev){ uint8_t fec = 0, data[240]; if (!(dev->features[6] & LMP_EXT_INQ)) return; memset(data, 0, sizeof(data)); if (dev->ssp_mode > 0) create_ext_inquiry_response((char *) dev->name, data); if (hci_write_ext_inquiry_response(dd, fec, data, 2000) < 0) error("Can't write extended inquiry response: %s (%d)", strerror(errno), errno);}static int adapter_set_name(struct adapter *adapter, const char *name){ struct hci_dev *dev = &adapter->dev; int dd, err; bdaddr_t bdaddr; str2ba(adapter->address, &bdaddr); write_local_name(&bdaddr, (char *) name); if (!adapter->up) return 0; dd = hci_open_dev(adapter->dev_id); if (dd < 0) { err = errno; error("Can't open device hci%d: %s (%d)", adapter->dev_id, strerror(err), err); return -err; } if (hci_write_local_name(dd, name, 5000) < 0) { err = errno; error("Can't write name for hci%d: %s (%d)", adapter->dev_id, strerror(err), err); hci_close_dev(dd); return -err; } strncpy((char *) dev->name, name, 248); update_ext_inquiry_response(dd, dev); hci_close_dev(dd); return 0;}static DBusMessage *set_name(DBusConnection *conn, DBusMessage *msg, const char *name, void *data){ struct adapter *adapter = data; int ecode; const char *path; if (!g_utf8_validate(name, -1, NULL)) { error("Name change failed: the supplied name isn't valid UTF-8"); return invalid_args(msg); } ecode = adapter_set_name(adapter, name); if (ecode < 0) return failed_strerror(msg, -ecode); path = dbus_message_get_path(msg); dbus_connection_emit_property_changed(conn, path, ADAPTER_INTERFACE, "Name", DBUS_TYPE_STRING, &name); return dbus_message_new_method_return(msg);}static void reply_authentication_failure(struct bonding_request_info *bonding){ DBusMessage *reply; int status; status = bonding->hci_status ? bonding->hci_status : HCI_AUTHENTICATION_FAILURE; reply = new_authentication_return(bonding->msg, status); if (reply) { dbus_connection_send(bonding->conn, reply, NULL); dbus_message_unref(reply); }}struct btd_device *adapter_find_device(struct adapter *adapter, const char *dest){ struct btd_device *device; GSList *l; if (!adapter) return NULL; l = g_slist_find_custom(adapter->devices, dest, (GCompareFunc) device_address_cmp); if (!l) return NULL; device = l->data; return device;}struct btd_device *adapter_create_device(DBusConnection *conn, struct adapter *adapter, const char *address){ struct btd_device *device; debug("adapter_create_device(%s)", address); device = device_create(conn, adapter, address); if (!device) return NULL; device_set_temporary(device, TRUE); adapter->devices = g_slist_append(adapter->devices, device); return device;}static DBusMessage *remove_bonding(DBusConnection *conn, DBusMessage *msg, const char *address, void *data){ struct adapter *adapter = data; struct btd_device *device; char filename[PATH_MAX + 1]; char *str; bdaddr_t src, dst; GSList *l; int dev, err; gboolean paired; str2ba(adapter->address, &src); str2ba(address, &dst); dev = hci_open_dev(adapter->dev_id); if (dev < 0 && msg) return no_such_adapter(msg); create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "linkkeys"); /* textfile_del doesn't return an error when the key is not found */ str = textfile_caseget(filename, address); paired = str ? TRUE : FALSE; g_free(str); if (!paired && msg) { hci_close_dev(dev); return g_dbus_create_error(msg, ERROR_INTERFACE ".DoesNotExist", "Bonding does not exist"); } /* Delete the link key from storage */ if (textfile_casedel(filename, address) < 0 && msg) { hci_close_dev(dev); err = errno; return failed_strerror(msg, err); } /* Delete the link key from the Bluetooth chip */ hci_delete_stored_link_key(dev, &dst, 0, 1000); /* find the connection */ l = g_slist_find_custom(adapter->active_conn, &dst, active_conn_find_by_bdaddr); if (l) { struct active_conn_info *con = l->data; /* Send the HCI disconnect command */ if ((hci_disconnect(dev, htobs(con->handle), HCI_OE_USER_ENDED_CONNECTION, 500) < 0) && msg){ int err = errno; error("Disconnect failed"); hci_close_dev(dev); return failed_strerror(msg, err); } } hci_close_dev(dev); device = adapter_find_device(adapter, address); if (!device) goto proceed; if (paired) { gboolean paired = FALSE; const gchar *dev_path = device_get_path(device); dbus_connection_emit_property_changed(conn, dev_path, DEVICE_INTERFACE, "Paired", DBUS_TYPE_BOOLEAN, &paired); }proceed: if(!msg) goto done; return dbus_message_new_method_return(msg);done: return NULL;}void adapter_remove_device(DBusConnection *conn, struct adapter *adapter, struct btd_device *device){ bdaddr_t src; const gchar *destination = device_get_address(device); const gchar *dev_path = device_get_path(device); struct agent *agent; str2ba(adapter->address, &src); delete_entry(&src, "profiles", destination); remove_bonding(conn, NULL, destination, adapter); if (!device_is_temporary(device)) { g_dbus_emit_signal(conn, adapter->path, ADAPTER_INTERFACE, "DeviceRemoved", DBUS_TYPE_OBJECT_PATH, &dev_path, DBUS_TYPE_INVALID); } agent = device_get_agent(device); if (agent) { agent_destroy(agent, FALSE); device_set_agent(device, NULL); } adapter->devices = g_slist_remove(adapter->devices, device); device_remove(conn, device);}struct btd_device *adapter_get_device(DBusConnection *conn, struct adapter *adapter, const gchar *address){ struct btd_device *device; debug("adapter_get_device(%s)", address); if (!adapter) return NULL; device = adapter_find_device(adapter, address); if (device) return device; return adapter_create_device(conn, adapter, address);}void remove_pending_device(struct adapter *adapter){ struct btd_device *device; char address[18]; ba2str(&adapter->bonding->bdaddr, address); device = adapter_find_device(adapter, address); if (!device) return; if (device_is_temporary(device)) adapter_remove_device(adapter->bonding->conn, adapter, device);}static gboolean create_bonding_conn_complete(GIOChannel *io, GIOCondition cond, struct adapter *adapter){ struct hci_request rq; auth_requested_cp cp; evt_cmd_status rp; struct l2cap_conninfo cinfo; socklen_t len; int sk, dd, ret; if (!adapter->bonding) { /* If we come here it implies a bug somewhere */ debug("create_bonding_conn_complete: no pending bonding!"); g_io_channel_close(io); g_io_channel_unref(io); return FALSE; } if (cond & G_IO_NVAL) { DBusMessage *reply; reply = new_authentication_return(adapter->bonding->msg, 0x09); g_dbus_send_message(adapter->bonding->conn, reply); goto cleanup; } if (cond & (G_IO_HUP | G_IO_ERR)) { debug("Hangup or error on bonding IO channel"); if (!adapter->bonding->auth_active) error_connection_attempt_failed(adapter->bonding->conn, adapter->bonding->msg, ENETDOWN); else reply_authentication_failure(adapter->bonding); goto failed; } sk = g_io_channel_unix_get_fd(io); len = sizeof(ret); if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { error("Can't get socket error: %s (%d)", strerror(errno), errno); error_failed_errno(adapter->bonding->conn, adapter->bonding->msg, errno); goto failed; } if (ret != 0) { if (adapter->bonding->auth_active) reply_authentication_failure(adapter->bonding); else error_connection_attempt_failed(adapter->bonding->conn, adapter->bonding->msg, ret); goto failed; } len = sizeof(cinfo); if (getsockopt(sk, SOL_L2CAP, L2CAP_CONNINFO, &cinfo, &len) < 0) { error("Can't get connection info: %s (%d)", strerror(errno), errno); error_failed_errno(adapter->bonding->conn, adapter->bonding->msg, errno); goto failed; } dd = hci_open_dev(adapter->dev_id); if (dd < 0) { DBusMessage *reply = no_such_adapter(adapter->bonding->msg); g_dbus_send_message(adapter->bonding->conn, reply); goto failed; } memset(&rp, 0, sizeof(rp)); memset(&cp, 0, sizeof(cp)); cp.handle = htobs(cinfo.hci_handle); memset(&rq, 0, sizeof(rq)); rq.ogf = OGF_LINK_CTL; rq.ocf = OCF_AUTH_REQUESTED; rq.cparam = &cp; rq.clen = AUTH_REQUESTED_CP_SIZE; rq.rparam = &rp; rq.rlen = EVT_CMD_STATUS_SIZE; rq.event = EVT_CMD_STATUS; if (hci_send_req(dd, &rq, 500) < 0) { error("Unable to send HCI request: %s (%d)", strerror(errno), errno); error_failed_errno(adapter->bonding->conn, adapter->bonding->msg, errno); hci_close_dev(dd); goto failed; } if (rp.status) { error("HCI_Authentication_Requested failed with status 0x%02x", rp.status); error_failed_errno(adapter->bonding->conn, adapter->bonding->msg, bt_error(rp.status)); hci_close_dev(dd); goto failed; } hci_close_dev(dd); adapter->bonding->auth_active = 1; adapter->bonding->io_id = g_io_add_watch(io, G_IO_NVAL | G_IO_HUP | G_IO_ERR, (GIOFunc) create_bonding_conn_complete, adapter); return FALSE;failed: g_io_channel_close(io); remove_pending_device(adapter);cleanup: g_dbus_remove_watch(adapter->bonding->conn, adapter->bonding->listener_id); bonding_request_free(adapter->bonding); adapter->bonding = NULL; return FALSE;}static void cancel_auth_request(struct pending_auth_info *auth, int dev_id){ int dd; if (auth->replied) return; dd = hci_open_dev(dev_id); if (dd < 0) { error("hci_open_dev: %s (%d)", strerror(errno), errno); return; } switch (auth->type) { case AUTH_TYPE_PINCODE: hci_send_cmd(dd, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, 6, &auth->bdaddr); break; case AUTH_TYPE_CONFIRM: hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_CONFIRM_NEG_REPLY, 6, &auth->bdaddr); break; case AUTH_TYPE_PASSKEY: hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_PASSKEY_NEG_REPLY, 6, &auth->bdaddr); break; case AUTH_TYPE_NOTIFY: /* User Notify doesn't require any reply */ break; } auth->replied = TRUE; hci_close_dev(dd);}static void create_bond_req_exit(void *user_data){ struct adapter *adapter = user_data; struct pending_auth_info *auth; debug("CreateConnection requestor exited before bonding was completed"); auth = adapter_find_auth_request(adapter, &adapter->bonding->bdaddr); if (auth) { cancel_auth_request(auth, adapter->dev_id); if (auth->agent) agent_cancel(auth->agent); adapter_remove_auth_request(adapter, &adapter->bonding->bdaddr); } remove_pending_device(adapter); g_io_channel_close(adapter->bonding->io); if (adapter->bonding->io_id) g_source_remove(adapter->bonding->io_id); bonding_request_free(adapter->bonding); adapter->bonding = NULL;}static DBusMessage *create_bonding(DBusConnection *conn, DBusMessage *msg, const char *address, const char *agent_path, uint8_t capability, void *data){ char filename[PATH_MAX + 1]; char *str; struct adapter *adapter = data; struct bonding_request_info *bonding;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -