📄 adapter.c
字号:
struct agent *agent; struct btd_adapter *adapter = data; uint8_t cap; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_STRING, &capability, DBUS_TYPE_INVALID)) return NULL; if (adapter->agent) return g_dbus_create_error(msg, ERROR_INTERFACE ".AlreadyExists", "Agent already exists"); cap = parse_io_capability(capability); if (cap == IO_CAPABILITY_INVALID) return invalid_args(msg); name = dbus_message_get_sender(msg); agent = agent_create(adapter, name, path, cap, (agent_remove_cb) agent_removed, adapter); if (!agent) return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", "Failed to create a new agent"); adapter->agent = agent; debug("Agent registered for hci%d at %s:%s", adapter->dev_id, name, path); return dbus_message_new_method_return(msg);}static DBusMessage *unregister_agent(DBusConnection *conn, DBusMessage *msg, void *data){ const char *path, *name; struct btd_adapter *adapter = data; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) return NULL; name = dbus_message_get_sender(msg); if (!adapter->agent || !agent_matches(adapter->agent, name, path)) return g_dbus_create_error(msg, ERROR_INTERFACE ".DoesNotExist", "No such agent"); agent_destroy(adapter->agent, FALSE); adapter->agent = NULL; return dbus_message_new_method_return(msg);}/* BlueZ 4.0 API */static GDBusMethodTable adapter_methods[] = { { "GetProperties", "", "a{sv}",get_properties }, { "SetProperty", "sv", "", set_property, G_DBUS_METHOD_FLAG_ASYNC}, { "RequestSession", "", "", request_session, G_DBUS_METHOD_FLAG_ASYNC}, { "ReleaseSession", "", "", release_session }, { "StartDiscovery", "", "", adapter_start_discovery }, { "StopDiscovery", "", "", adapter_stop_discovery, G_DBUS_METHOD_FLAG_ASYNC}, { "ListDevices", "", "ao", list_devices, G_DBUS_METHOD_FLAG_DEPRECATED}, { "CreateDevice", "s", "o", create_device, G_DBUS_METHOD_FLAG_ASYNC}, { "CreatePairedDevice", "sos", "o", create_paired_device, G_DBUS_METHOD_FLAG_ASYNC}, { "CancelDeviceCreation","s", "", cancel_device_creation }, { "RemoveDevice", "o", "", remove_device }, { "FindDevice", "s", "o", find_device }, { "RegisterAgent", "os", "", register_agent }, { "UnregisterAgent", "o", "", unregister_agent }, { }};static GDBusSignalTable adapter_signals[] = { { "DeviceCreated", "o" }, { "DeviceRemoved", "o" }, { "DeviceFound", "sa{sv}" }, { "PropertyChanged", "sv" }, { "DeviceDisappeared", "s" }, { }};static inline uint8_t get_inquiry_mode(struct hci_dev *dev){ if (dev->features[6] & LMP_EXT_INQ) return 2; if (dev->features[3] & LMP_RSSI_INQ) return 1; if (dev->manufacturer == 11 && dev->hci_rev == 0x00 && dev->lmp_subver == 0x0757) return 1; if (dev->manufacturer == 15) { if (dev->hci_rev == 0x03 && dev->lmp_subver == 0x6963) return 1; if (dev->hci_rev == 0x09 && dev->lmp_subver == 0x6963) return 1; if (dev->hci_rev == 0x00 && dev->lmp_subver == 0x6965) return 1; } if (dev->manufacturer == 31 && dev->hci_rev == 0x2005 && dev->lmp_subver == 0x1805) return 1; return 0;}static int adapter_read_bdaddr(uint16_t dev_id, bdaddr_t *bdaddr){ int dd, err; dd = hci_open_dev(dev_id); if (dd < 0) { err = -errno; error("Can't open device hci%d: %s (%d)", dev_id, strerror(err), err); return err; } if (hci_read_bd_addr(dd, bdaddr, HCI_REQ_TIMEOUT) < 0) { err = -errno; error("Can't read address for hci%d: %s (%d)", dev_id, strerror(err), err); hci_close_dev(dd); return err; } hci_close_dev(dd); return 0;}static int adapter_setup(struct btd_adapter *adapter, int dd){ struct hci_dev *dev = &adapter->dev; uint8_t events[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00 }; uint8_t inqmode; int err; char name[249]; if (dev->hci_rev > 1) { if (dev->features[5] & LMP_SNIFF_SUBR) events[5] |= 0x20; if (dev->features[5] & LMP_PAUSE_ENC) events[5] |= 0x80; if (dev->features[6] & LMP_EXT_INQ) events[5] |= 0x40; if (dev->features[6] & LMP_NFLUSH_PKTS) events[7] |= 0x01; if (dev->features[7] & LMP_LSTO) events[6] |= 0x80; if (dev->features[6] & LMP_SIMPLE_PAIR) { events[6] |= 0x01; /* IO Capability Request */ events[6] |= 0x02; /* IO Capability Response */ events[6] |= 0x04; /* User Confirmation Request */ events[6] |= 0x08; /* User Passkey Request */ events[6] |= 0x10; /* Remote OOB Data Request */ events[6] |= 0x20; /* Simple Pairing Complete */ events[7] |= 0x04; /* User Passkey Notification */ events[7] |= 0x08; /* Keypress Notification */ events[7] |= 0x10; /* Remote Host Supported Features Notification */ } hci_send_cmd(dd, OGF_HOST_CTL, OCF_SET_EVENT_MASK, sizeof(events), events); } if (read_local_name(&adapter->bdaddr, name) == 0) { memcpy(dev->name, name, 248); hci_write_local_name(dd, name, HCI_REQ_TIMEOUT); } update_ext_inquiry_response(dd, dev); inqmode = get_inquiry_mode(dev); if (inqmode < 1) return 0; if (hci_write_inquiry_mode(dd, inqmode, HCI_REQ_TIMEOUT) < 0) { err = -errno; error("Can't write inquiry mode for %s: %s (%d)", adapter->path, strerror(err), err); hci_close_dev(dd); return err; } return 0;}static int active_conn_append(GSList **list, bdaddr_t *bdaddr, uint16_t handle){ struct active_conn_info *dev; dev = g_new0(struct active_conn_info, 1); bacpy(&dev->bdaddr, bdaddr); dev->handle = handle; *list = g_slist_append(*list, dev); return 0;}static void create_stored_device_from_profiles(char *key, char *value, void *user_data){ struct btd_adapter *adapter = user_data; GSList *uuids = bt_string2list(value); struct btd_device *device; bdaddr_t dst; char srcaddr[18], dstaddr[18]; ba2str(&adapter->bdaddr, srcaddr); if (g_slist_find_custom(adapter->devices, key, (GCompareFunc) device_address_cmp)) return; device = device_create(connection, adapter, key); if (!device) return; device_set_temporary(device, FALSE); adapter->devices = g_slist_append(adapter->devices, device); device_get_address(device, &dst); ba2str(&dst, dstaddr); device_probe_drivers(device, uuids); g_slist_foreach(uuids, (GFunc) g_free, NULL); g_slist_free(uuids);}static void create_stored_device_from_linkkeys(char *key, char *value, void *user_data){ struct btd_adapter *adapter = user_data; struct btd_device *device; if (g_slist_find_custom(adapter->devices, key, (GCompareFunc) device_address_cmp)) return; device = device_create(connection, adapter, key); if (device) { device_set_temporary(device, FALSE); adapter->devices = g_slist_append(adapter->devices, device); }}static void load_devices(struct btd_adapter *adapter){ char filename[PATH_MAX + 1]; char srcaddr[18]; ba2str(&adapter->bdaddr, srcaddr); create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "profiles"); textfile_foreach(filename, create_stored_device_from_profiles, adapter); create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "linkkeys"); textfile_foreach(filename, create_stored_device_from_linkkeys, adapter);}static void load_drivers(struct btd_adapter *adapter){ GSList *l; for (l = adapter_drivers; l; l = l->next) { struct btd_adapter_driver *driver = l->data; if (driver->probe) driver->probe(adapter); }}static int get_discoverable_timeout(const char *src){ int timeout; if (read_discoverable_timeout(src, &timeout) == 0) return timeout; return main_opts.discovto;}static int get_pairable_timeout(const char *src){ int timeout; if (read_pairable_timeout(src, &timeout) == 0) return timeout; return main_opts.pairto;}static void adapter_up(struct btd_adapter *adapter, int dd){ char mode[14], srcaddr[18]; int i; uint8_t scan_mode; gboolean powered, first_init; ba2str(&adapter->bdaddr, srcaddr); first_init = adapter->first_init; if (adapter->first_init) adapter->first_init = FALSE; adapter->up = 1; adapter->discov_timeout = get_discoverable_timeout(srcaddr); adapter->pairable_timeout = get_pairable_timeout(srcaddr); adapter->state = DISCOVER_TYPE_NONE; adapter->mode = MODE_CONNECTABLE; scan_mode = SCAN_PAGE; powered = TRUE; /* Set pairable mode */ if (read_device_pairable(&adapter->bdaddr, &adapter->pairable) < 0) adapter->pairable = TRUE; /* Set scan mode */ if (read_device_mode(srcaddr, mode, sizeof(mode)) < 0) goto proceed; if (g_str_equal(mode, "off")) { powered = FALSE; if (main_opts.offmode == HCID_OFFMODE_NOSCAN) { adapter->mode = MODE_OFF; scan_mode = SCAN_DISABLED; } else if (main_opts.offmode == HCID_OFFMODE_DEVDOWN) { if (first_init) { ioctl(dd, HCIDEVDOWN, adapter->dev_id); return; } if (read_on_mode(srcaddr, mode, sizeof(mode)) < 0) write_device_mode(&adapter->bdaddr, "connectable"); else write_device_mode(&adapter->bdaddr, mode); adapter_up(adapter, dd); return; } } else if (!g_str_equal(mode, "connectable") && adapter->discov_timeout == 0) { /* Set discoverable only if timeout is 0 */ adapter->mode = adapter->pairable ? MODE_LIMITED : MODE_DISCOVERABLE; scan_mode = SCAN_PAGE | SCAN_INQUIRY; }proceed: hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE, 1, &scan_mode); /* retrieve the active connections: address the scenario where * the are active connections before the daemon've started */ if (adapter->first_init) { struct hci_conn_list_req *cl = NULL; struct hci_conn_info *ci; cl = g_malloc0(10 * sizeof(*ci) + sizeof(*cl)); cl->dev_id = adapter->dev_id; cl->conn_num = 10; ci = cl->conn_info; if (ioctl(dd, HCIGETCONNLIST, cl) == 0) { for (i = 0; i < cl->conn_num; i++, ci++) active_conn_append(&adapter->active_conn, &ci->bdaddr, ci->handle); } g_free(cl); } if (main_opts.offmode == HCID_OFFMODE_DEVDOWN) emit_property_changed(connection, adapter->path, ADAPTER_INTERFACE, "Powered", DBUS_TYPE_BOOLEAN, &powered); if (adapter->first_init) { load_drivers(adapter); load_devices(adapter); }}int adapter_start(struct btd_adapter *adapter){ struct hci_dev *dev = &adapter->dev; struct hci_dev_info di; struct hci_version ver; uint8_t features[8]; int dd, err; char name[249]; if (hci_devinfo(adapter->dev_id, &di) < 0) return -errno; if (hci_test_bit(HCI_RAW, &di.flags)) { dev->ignore = 1; return -1; } if (!bacmp(&di.bdaddr, BDADDR_ANY)) { int err; debug("Adapter %s without an address", adapter->path); err = adapter_read_bdaddr(adapter->dev_id, &di.bdaddr); if (err < 0) return err; } bacpy(&adapter->bdaddr, &di.bdaddr); memcpy(dev->features, di.features, 8); dd = hci_open_dev(adapter->dev_id); if (dd < 0) { err = -errno; error("Can't open adapter %s: %s (%d)", adapter->path, strerror(err), err); return err; } if (hci_read_local_version(dd, &ver, HCI_REQ_TIMEOUT) < 0) { err = -errno; error("Can't read version info for %s: %s (%d)", adapter->path, strerror(err), err); hci_close_dev(dd); return err; } dev->hci_rev = ver.hci_rev; dev->lmp_ver = ver.lmp_ver; dev->lmp_subver = ver.lmp_subver; dev->manufacturer = ver.manufacturer; if (hci_read_local_features(dd, features, HCI_REQ_TIMEOUT) < 0) { err = -errno; error("Can't read features for %s: %s (%d)", adapter->path, strerror(err), err); hci_close_dev(dd); return err; } memcpy(dev->features, features, 8); if (hci_read_class_of_dev(dd, dev->class, HCI_REQ_TIMEOUT) < 0) { err = -errno; error("Can't read class of adapter on %s: %s (%d)", adapter->path, strerror(err), err); hci_close_dev(dd); return err; } if (hci_read_local_name(dd, sizeof(name), name, HCI_REQ_TIMEOUT) < 0) { err = -errno; error("Can't read local name on %s: %s (%d)", adapter->path, strerror(err), err); hci_close_dev(dd); return err; } memcpy(dev->name, name, 248); if (!(features[6] & LMP_SIMPLE_PAIR)) goto setup; if (ioctl(dd, HCIGETAUTHINFO, NULL) < 0 && errno != EINVAL) hci_write_simple_pairing_mode(dd, 0x01, HCI_REQ_TIMEOUT); if (hci_read_simple_pairing_mode(dd, &dev->ssp_mode, HCI_REQ_TIMEOUT) < 0) { err = -errno; error("Can't read simple pairing mode on %s: %s (%d)", adapter->path, strerror(err), err); hci_close_dev(dd); return err; }setup: hci_send_cmd(dd, OGF_LINK_POLICY, OCF_READ_DEFAULT_LINK_POLICY, 0, NULL); if (hci_test_bit(HCI_INQUIRY, &di.flags)) adapter->state |= STD_INQUIRY; else adapter->state &= ~STD_INQUIRY; adapter_setup(adapter, dd); adapter_up(adapter, dd); hci_close_dev(dd); info("Adapter %s has been enabled", adapter->path); return 0;}static void reply_pending_requests(struct btd_adapter *adapter){ DBusMessage *reply; if (!adapter) return; /* pending bonding */ if (adapter->bonding) { reply = new_authentication_return(adapter->bonding->msg, HCI_OE_USER_ENDED_CONNECTION); g_dbus_send_message(connection, reply); remove_pending_device(adapter); g_dbus_remove_watch(adapter->bonding->conn, adapter->bonding->listener_id); if (adapter->bonding->io_id) g_source_remove(adapter->bonding->io_id); if (adapter->bonding->io) g_io_channel_close(adapter->bonding->io); bonding_request_free(adapter->bonding); adapter->bonding = NULL; } if (adapter->state & STD_INQUIRY) { /* Cancel inquiry initiated by
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -