📄 adapter.c
字号:
int dd; uint8_t scan_enable; uint16_t dev_id = adapter->dev_id; adapter->discov_timeout_id = 0; dd = hci_open_dev(dev_id); if (dd < 0) { error("HCI device open failed: hci%d", dev_id); return FALSE; } scan_enable = adapter->scan_mode & ~SCAN_INQUIRY; hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE, 1, &scan_enable); hci_close_dev(dd); return FALSE;}static void adapter_set_discov_timeout(struct btd_adapter *adapter, guint interval){ if (adapter->discov_timeout_id) { g_source_remove(adapter->discov_timeout_id); adapter->discov_timeout_id = 0; } if (interval == 0) return; adapter->discov_timeout_id = g_timeout_add_seconds(interval, discov_timeout_handler, adapter);}static uint8_t mode2scan(uint8_t mode){ switch (mode) { case MODE_OFF: return SCAN_DISABLED; case MODE_CONNECTABLE: return SCAN_PAGE; case MODE_DISCOVERABLE: case MODE_LIMITED: return (SCAN_PAGE | SCAN_INQUIRY); default: error("Invalid mode given to mode2scan: %u", mode); return SCAN_PAGE; }}static int set_mode(struct btd_adapter *adapter, uint8_t new_mode){ uint8_t scan_enable; uint8_t current_scan = adapter->scan_mode; int err, dd; const char *modestr; scan_enable = mode2scan(new_mode); dd = hci_open_dev(adapter->dev_id); if (dd < 0) return -EIO; if (!adapter->up && (main_opts.offmode == HCID_OFFMODE_NOSCAN || (main_opts.offmode == HCID_OFFMODE_DEVDOWN && scan_enable != SCAN_DISABLED))) { /* Start HCI device */ if (ioctl(dd, HCIDEVUP, adapter->dev_id) == 0) goto done; /* on success */ if (errno != EALREADY) { err = -errno; error("Can't init device hci%d: %s (%d)\n", adapter->dev_id, strerror(errno), errno); hci_close_dev(dd); return err; } } if (adapter->up && scan_enable == SCAN_DISABLED && main_opts.offmode == HCID_OFFMODE_DEVDOWN) { if (ioctl(dd, HCIDEVDOWN, adapter->dev_id) < 0) { err = -errno; hci_close_dev(dd); return err; } goto done; } if (current_scan != scan_enable) { err = hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE, 1, &scan_enable); if (err < 0) { hci_close_dev(dd); return err; } } else { /* discoverable or limited */ if ((scan_enable & SCAN_INQUIRY) && (new_mode != adapter->mode)) { adapter_remove_discov_timeout(adapter); if (adapter->discov_timeout) adapter_set_discov_timeout(adapter, adapter->discov_timeout); } }done: modestr = mode2str(new_mode); write_device_mode(&adapter->bdaddr, modestr); hci_close_dev(dd); adapter->mode = new_mode; return 0;}static DBusMessage *set_powered(DBusConnection *conn, DBusMessage *msg, gboolean powered, void *data){ struct btd_adapter *adapter = data; uint8_t mode; int err; mode = powered ? get_mode(&adapter->bdaddr, "on") : MODE_OFF; if (mode == adapter->mode) return dbus_message_new_method_return(msg); err = set_mode(adapter, mode); if (err < 0) return failed_strerror(msg, -err); return dbus_message_new_method_return(msg);}static DBusMessage *set_discoverable(DBusConnection *conn, DBusMessage *msg, gboolean discoverable, void *data){ struct btd_adapter *adapter = data; uint8_t mode; int err; mode = discoverable ? MODE_DISCOVERABLE : MODE_CONNECTABLE; if (mode == MODE_DISCOVERABLE && adapter->pairable) mode = MODE_LIMITED; if (mode == adapter->mode) return dbus_message_new_method_return(msg); err = set_mode(adapter, mode); if (err < 0) return failed_strerror(msg, -err); return dbus_message_new_method_return(msg);}static DBusMessage *set_pairable(DBusConnection *conn, DBusMessage *msg, gboolean pairable, void *data){ struct btd_adapter *adapter = data; uint8_t mode; int err; if (adapter->scan_mode == SCAN_DISABLED) return adapter_not_ready(msg); if (pairable == adapter->pairable) goto done; adapter->pairable = pairable; write_device_pairable(&adapter->bdaddr, pairable); emit_property_changed(connection, adapter->path, ADAPTER_INTERFACE, "Pairable", DBUS_TYPE_BOOLEAN, &pairable); if (pairable && adapter->pairable_timeout) adapter_set_pairable_timeout(adapter, adapter->pairable_timeout); if (!(adapter->scan_mode & SCAN_INQUIRY)) goto done; mode = pairable ? MODE_LIMITED : MODE_DISCOVERABLE; err = set_mode(adapter, mode); if (err < 0 && msg) return failed_strerror(msg, -err);done: return msg ? dbus_message_new_method_return(msg) : NULL;}static gboolean pairable_timeout_handler(void *data){ set_pairable(NULL, NULL, FALSE, data); return FALSE;}static void adapter_set_pairable_timeout(struct btd_adapter *adapter, guint interval){ if (adapter->pairable_timeout_id) { g_source_remove(adapter->pairable_timeout_id); adapter->pairable_timeout_id = 0; } if (interval == 0) return; adapter->pairable_timeout_id = g_timeout_add_seconds(interval, pairable_timeout_handler, adapter);}static struct session_req *find_session(GSList *list, const char *sender){ GSList *l; for (l = list; l; l = l->next) { struct session_req *req = l->data; if (g_str_equal(req->owner, sender)) return req; } return NULL;}static uint8_t get_needed_mode(struct btd_adapter *adapter, uint8_t mode){ GSList *l; if (adapter->global_mode > mode) mode = adapter->global_mode; for (l = adapter->mode_sessions; l; l = l->next) { struct session_req *req = l->data; if (req->mode > mode) mode = req->mode; } return mode;}static void session_remove(struct session_req *req){ struct btd_adapter *adapter = req->adapter; if (req->mode) { uint8_t mode; adapter->mode_sessions = g_slist_remove(adapter->mode_sessions, req); mode = get_needed_mode(adapter, adapter->global_mode); if (mode == adapter->mode) return; debug("Switching to '%s' mode", mode2str(mode)); set_mode(adapter, mode); } else { adapter->disc_sessions = g_slist_remove(adapter->disc_sessions, req); if (adapter->disc_sessions) return; debug("Stopping discovery"); if (adapter->state & STD_INQUIRY) cancel_discovery(adapter); else if (adapter->scheduler_id) g_source_remove(adapter->scheduler_id); else cancel_periodic_discovery(adapter); }}static void session_free(struct session_req *req){ debug("%s session %p with %s deactivated", req->mode ? "Mode" : "Discovery", req, req->owner); if (req->id) g_dbus_remove_watch(req->conn, req->id); session_remove(req); if (req->msg) dbus_message_unref(req->msg); if (req->conn) dbus_connection_unref(req->conn); g_free(req->owner); g_free(req);}static void session_owner_exit(DBusConnection *conn, void *user_data){ struct session_req *req = user_data; req->id = 0; session_free(req);}static struct session_req *session_ref(struct session_req *req){ req->refcount++; debug("session_ref(%p): ref=%d", req, req->refcount); return req;}static void session_unref(struct session_req *req){ req->refcount--; debug("session_unref(%p): ref=%d", req, req->refcount); if (req->refcount) return; session_free(req);}static struct session_req *create_session(struct btd_adapter *adapter, DBusConnection *conn, DBusMessage *msg, uint8_t mode, GDBusWatchFunction cb){ struct session_req *req; const char *sender = dbus_message_get_sender(msg); req = g_new0(struct session_req, 1); req->adapter = adapter; req->conn = dbus_connection_ref(conn); req->msg = dbus_message_ref(msg); req->owner = g_strdup(dbus_message_get_sender(msg)); req->mode = mode; if (cb) req->id = g_dbus_add_disconnect_watch(conn, sender, cb, req, NULL); info("%s session %p with %s activated", req->mode ? "Mode" : "Discovery", req, sender); return session_ref(req);}static void confirm_mode_cb(struct agent *agent, DBusError *derr, void *data){ struct session_req *req = data; int err; DBusMessage *reply; if (derr && dbus_error_is_set(derr)) { reply = dbus_message_new_error(req->msg, derr->name, derr->message); g_dbus_send_message(req->conn, reply); session_unref(req); return; } err = set_mode(req->adapter, req->mode); if (err < 0) reply = failed_strerror(req->msg, -err); else reply = dbus_message_new_method_return(req->msg); g_dbus_send_message(req->conn, reply); dbus_message_unref(req->msg); req->msg = NULL; if (!find_session(req->adapter->mode_sessions, req->owner)) session_unref(req);}static DBusMessage *set_discoverable_timeout(DBusConnection *conn, DBusMessage *msg, uint32_t timeout, void *data){ struct btd_adapter *adapter = data; const char *path; if (adapter->discov_timeout == timeout && timeout == 0) return dbus_message_new_method_return(msg); if (adapter->scan_mode & SCAN_INQUIRY) adapter_set_discov_timeout(adapter, timeout); adapter->discov_timeout = timeout; write_discoverable_timeout(&adapter->bdaddr, timeout); path = dbus_message_get_path(msg); emit_property_changed(conn, path, ADAPTER_INTERFACE, "DiscoverableTimeout", DBUS_TYPE_UINT32, &timeout); return dbus_message_new_method_return(msg);}static DBusMessage *set_pairable_timeout(DBusConnection *conn, DBusMessage *msg, uint32_t timeout, void *data){ struct btd_adapter *adapter = data; const char *path; if (adapter->pairable_timeout == timeout && timeout == 0) return dbus_message_new_method_return(msg); if (adapter->pairable) adapter_set_pairable_timeout(adapter, timeout); adapter->pairable_timeout = timeout; write_pairable_timeout(&adapter->bdaddr, timeout); path = dbus_message_get_path(msg); emit_property_changed(conn, path, ADAPTER_INTERFACE, "PairableTimeout", 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, HCI_REQ_TIMEOUT) < 0) error("Can't write extended inquiry response: %s (%d)", strerror(errno), errno);}static int adapter_set_name(struct btd_adapter *adapter, const char *name){ struct hci_dev *dev = &adapter->dev; int dd, err; write_local_name(&adapter->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, HCI_REQ_TIMEOUT) < 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 btd_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); 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) g_dbus_send_message(bonding->conn, reply);}struct btd_device *adapter_find_device(struct btd_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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -