📄 adapter.c
字号:
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 btd_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 btd_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); 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, HCI_REQ_TIMEOUT) < 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 cancel_bonding(struct btd_adapter *adapter, gboolean exited){ struct pending_auth_info *auth; struct bonding_request_info *bonding = adapter->bonding; auth = adapter_find_auth_request(adapter, &adapter->bdaddr); if (auth) { cancel_auth_request(auth, adapter->dev_id); if (auth->agent) agent_cancel(auth->agent); adapter_remove_auth_request(adapter, &bonding->bdaddr); } remove_pending_device(adapter); if (bonding->io) g_io_channel_close(bonding->io); if (exited) { if (bonding->io_id) { g_source_remove(bonding->io_id); bonding->io_id = 0; } bonding_request_free(bonding); adapter->bonding = NULL; } else bonding->cancel = TRUE;}static void create_bond_req_exit(void *user_data){ struct btd_adapter *adapter = user_data; debug("CreateConnection requestor exited before bonding was completed"); cancel_bonding(adapter, TRUE);}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, srcaddr[18]; struct btd_adapter *adapter = data; struct bonding_request_info *bonding; bdaddr_t dst; int sk; str2ba(address, &dst); ba2str(&adapter->bdaddr, srcaddr); /* check if there is a pending discover: requested by D-Bus/non clients */ if (adapter->state & STD_INQUIRY) return in_progress(msg, "Discover in progress"); pending_remote_name_cancel(adapter); if (adapter->bonding) return in_progress(msg, "Bonding in progress"); if (adapter_find_auth_request(adapter, &dst)) return in_progress(msg, "Bonding in progress"); /* check if a link key already exists */ create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "linkkeys"); str = textfile_caseget(filename, address); if (str) { free(str); return g_dbus_create_error(msg, ERROR_INTERFACE ".AlreadyExists", "Bonding already exists"); } sk = l2raw_connect(&adapter->bdaddr, &dst); if (sk < 0) return g_dbus_create_error(msg, ERROR_INTERFACE ".ConnectionAttemptFailed", "Connection attempt failed"); bonding = bonding_request_new(conn, msg, adapter, address, agent_path, capability); if (!bonding) { close(sk); return NULL; } bonding->io = g_io_channel_unix_new(sk); bonding->io_id = g_io_add_watch(bonding->io, G_IO_OUT | G_IO_NVAL | G_IO_HUP | G_IO_ERR, (GIOFunc) create_bonding_conn_complete, adapter); bonding->listener_id = g_dbus_add_disconnect_watch(conn, dbus_message_get_sender(msg), create_bond_req_exit, adapter, NULL); adapter->bonding = bonding; return NULL;}int start_inquiry(struct btd_adapter *adapter){ inquiry_cp cp; evt_cmd_status rp; struct hci_request rq; uint8_t lap[3] = { 0x33, 0x8b, 0x9e }; int dd, err; pending_remote_name_cancel(adapter); dd = hci_open_dev(adapter->dev_id); if (dd < 0) return dd; memset(&cp, 0, sizeof(cp)); memcpy(&cp.lap, lap, 3); cp.length = 0x08; cp.num_rsp = 0x00; memset(&rq, 0, sizeof(rq)); rq.ogf = OGF_LINK_CTL; rq.ocf = OCF_INQUIRY; rq.cparam = &cp; rq.clen = INQUIRY_CP_SIZE; rq.rparam = &rp; rq.rlen = EVT_CMD_STATUS_SIZE; rq.event = EVT_CMD_STATUS; if (hci_send_req(dd, &rq, HCI_REQ_TIMEOUT) < 0) { err = errno; error("Unable to start inquiry: %s (%d)", strerror(err), err); hci_close_dev(dd); return -err; } if (rp.status) { err = bt_error(rp.status); error("HCI_Inquiry command failed with status 0x%02x", rp.status); hci_close_dev(dd); return -err; } hci_close_dev(dd); adapter->state |= RESOLVE_NAME; return 0;}static int start_periodic_inquiry(struct btd_adapter *adapter){ periodic_inquiry_cp cp; struct hci_request rq; uint8_t lap[3] = { 0x33, 0x8b, 0x9e }; uint8_t status; int dd, err; dd = hci_open_dev(adapter->dev_id); if (dd < 0) return dd; memset(&cp, 0, sizeof(cp)); memcpy(&cp.lap, lap, 3); cp.max_period = htobs(24); cp.min_period = htobs(16); cp.length = 0x08; cp.num_rsp = 0x00; memset(&rq, 0, sizeof(rq)); rq.ogf = OGF_LINK_CTL; rq.ocf = OCF_PERIODIC_INQUIRY; rq.cparam = &cp; rq.clen = PERIODIC_INQUIRY_CP_SIZE; rq.rparam = &status; rq.rlen = sizeof(status); rq.event = EVT_CMD_COMPLETE; if (hci_send_req(dd, &rq, HCI_REQ_TIMEOUT) < 0) { err = errno; error("Unable to start periodic inquiry: %s (%d)", strerror(err), err); hci_close_dev(dd); return -err; } if (status) { err = bt_error(status); error("HCI_Periodic_Inquiry_Mode failed with status 0x%02x", status); hci_close_dev(dd); return -err; } hci_close_dev(dd); adapter->state |= RESOLVE_NAME; return 0;}static DBusMessage *adapter_start_discovery(DBusConnection *conn, DBusMessage *msg, void *data){ struct session_req *req; struct btd_adapter *adapter = data; int err; if (!adapter->up) return adapter_not_ready(msg); req = find_session(adapter->disc_sessions, msg); if (req) { session_ref(req); return dbus_message_new_method_return(msg); } if (adapter->disc_sessions) goto done; if (main_opts.inqmode) err = start_inquiry(adapter); else err = start_periodic_inquiry(adapter); if (err < 0) return failed_strerror(msg, -err);done: req = create_session(adapter, conn, msg, 0, (GDBusWatchFunction) session_free); adapter->disc_sessions = g_slist_append(adapter->disc_sessions, req); return dbus_message_new_method_return(msg);}static DBusMessage *adapter_stop_discovery(DBusConnection *conn, DBusMessage *msg, void *data){ struct btd_adapter *adapter = data; struct session_req *req; if (!adapter->up) return adapter_not_ready(msg); req = find_session(adapter->disc_sessions, msg); if (!req) return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", "Invalid discovery session"); session_unref(req); return dbus_message_new_method_return(msg);}struct remote_device_list_t { GSList *list; time_t time;};static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg, void *data){ struct btd_adapter *adapter = data; const char *property; DBusMessage *reply; DBusMessageIter iter; DBusMessageIter dict; char str[249], srcaddr[18]; gboolean value; char **devices; int i; GSList *l; ba2str(&adapter->bdaddr, srcaddr); if (check_address(srcaddr) < 0) return adapter_not_ready(msg); reply = dbus_message_new_method_return(msg); if (!reply) return NULL; dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); /* Address */ property = srcaddr; dict_append_entry(&dict, "Address", DBUS_TYPE_STRING, &property); /* Name */ memset(str, 0, sizeof(str)); strncpy(str, (char *) adapter->dev.name, 248); property = str; dict_append_entry(&dict, "Name", DBUS_TYPE_STRING, &property); /* Mode */ property = mode2str(adapter->mode); dict_append_entry(&dict, "Mode", DBUS_TYPE_STRING, &property); /* Powered */ if (main_opts.offmode == HCID_OFFMODE_DEVDOWN) value = adapter->up ? TRUE : FALSE; else value = adapter->scan_mode == SCAN_DISABLED ? FALSE : TRUE; dict_append_entry(&dict, "Powered", DBUS_TYPE_BOOLEAN, &value); /* Discoverable */ value = adapter->scan_mode & SCAN_INQUIRY ? TRUE : FALSE; dict_append_entry(&dict, "Discoverable", DBUS_TYPE_BOOLEAN, &value); /* DiscoverableTimeout */ dict_append_entry(&dict, "DiscoverableTimeout", DBUS_TYPE_UINT32, &adapter->discov_timeout); if (adapter->state & PERIODIC_INQUIRY || adapter->state & STD_INQUIRY) value = TRUE; else value = FALSE; /* Discovering */ dict_append_entry(&dict, "Discovering", DBUS_TYPE_BOOLEAN, &value); /* Devices */ devices = g_new0(char *, g_slist_length(adapter->devices) + 1); for (i = 0, l = adapter->devices; l; l = l->next, i++) { struct btd_device *dev = l->data; devices[i] = (char *) device_get_path(dev); } dict_append_array(&dict, "Devices", DBUS_TYPE_OBJECT_PATH, &devices, i); g_free(devices); dbus_message_iter_close_container(&iter, &dict); return reply;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -