adapter.c
来自「LINUX下」· C语言 代码 · 共 2,715 行 · 第 1/5 页
C
2,715 行
limited = (new_mode == MODE_LIMITED ? TRUE : FALSE); err = set_limited_discoverable(dd, adapter->dev.class, limited); if (err < 0) { hci_close_dev(dd); return failed_strerror(msg, -err); } if (current_scan != scan_enable) { struct hci_request rq; uint8_t status = 0; memset(&rq, 0, sizeof(rq)); rq.ogf = OGF_HOST_CTL; rq.ocf = OCF_WRITE_SCAN_ENABLE; rq.cparam = &scan_enable; rq.clen = sizeof(scan_enable); 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("Sending write scan enable command failed: %s (%d)", strerror(errno), errno); hci_close_dev(dd); return failed_strerror(msg, err); } if (status) { error("Setting scan enable failed with status 0x%02x", status); hci_close_dev(dd); return failed_strerror(msg, bt_error(status)); } } else { /* discoverable or limited */ if ((scan_enable & SCAN_INQUIRY) && (new_mode != adapter->mode)) { if (adapter->discov_timeout_id) { g_source_remove(adapter->discov_timeout_id); adapter->discov_timeout_id = 0; } if (!adapter->mode_sessions && !adapter->discov_timeout) adapter_set_discov_timeout(adapter, adapter->discov_timeout * 1000); } }done: write_device_mode(&adapter->bdaddr, mode); hci_close_dev(dd); adapter->mode = new_mode; return dbus_message_new_method_return(msg);}static DBusMessage *set_powered(DBusConnection *conn, DBusMessage *msg, gboolean powered, void *data){ struct btd_adapter *adapter = data; uint8_t mode; mode = powered ? get_mode(&adapter->bdaddr, "on") : MODE_OFF; if (mode == adapter->mode) return dbus_message_new_method_return(msg); return set_mode(conn, msg, mode, data);}static DBusMessage *set_discoverable(DBusConnection *conn, DBusMessage *msg, gboolean discoverable, void *data){ struct btd_adapter *adapter = data; const char *strmode; uint8_t mode; strmode = discoverable ? "discoverable" : "connectable"; mode = get_mode(&adapter->bdaddr, strmode); if (mode == adapter->mode) return dbus_message_new_method_return(msg); return set_mode(conn, msg, mode, data);}static struct session_req *find_session(GSList *list, DBusMessage *msg){ GSList *l; const char *sender = dbus_message_get_sender(msg); for (l = list; l; l = l->next) { struct session_req *req = l->data; const char *name = dbus_message_get_sender(req->msg); if (g_str_equal(name, sender)) return req; } return NULL;}static void session_remove(struct session_req *req){ struct btd_adapter *adapter = req->adapter; if (req->mode) { GSList *l; uint8_t mode = adapter->global_mode; adapter->mode_sessions = g_slist_remove(adapter->mode_sessions, req); for (l = adapter->mode_sessions; l; l = l->next) { struct session_req *req = l->data; if (req->mode > mode) mode = req->mode; } if (mode == adapter->mode) return; debug("Switching to '%s' mode", mode2str(mode)); set_mode(req->conn, req->msg, mode, adapter); } else { adapter->disc_sessions = g_slist_remove(adapter->disc_sessions, req); if (adapter->disc_sessions) return; debug("Stopping discovery", mode2str(adapter->global_mode)); 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){ const char *sender = dbus_message_get_sender(req->msg); info("%s session %p with %s deactivated", req->mode ? "Mode" : "Discovery", req, sender); session_remove(req); dbus_message_unref(req->msg); dbus_connection_unref(req->conn); g_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; if (req->id) g_dbus_remove_watch(req->conn, req->id); 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->mode = mode; if (cb) req->id = g_dbus_add_disconnect_watch(conn, dbus_message_get_sender(msg), 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 *err, void *data){ struct session_req *req = data; DBusMessage *reply; if (err && dbus_error_is_set(err)) { reply = dbus_message_new_error(req->msg, err->name, err->message); dbus_connection_send(req->conn, reply, NULL); dbus_message_unref(reply); goto cleanup; } reply = set_mode(req->conn, req->msg, req->mode, req->adapter); dbus_connection_send(req->conn, reply, NULL); dbus_message_unref(reply); if (!find_session(req->adapter->mode_sessions, req->msg)) goto cleanup; return;cleanup: session_unref(req);}static DBusMessage *confirm_mode(DBusConnection *conn, DBusMessage *msg, const char *mode, void *data){ struct btd_adapter *adapter = data; struct session_req *req; int ret; uint8_t umode; if (!adapter->agent) return dbus_message_new_method_return(msg); umode = get_mode(&adapter->bdaddr, mode); req = create_session(adapter, conn, msg, umode, NULL); ret = agent_confirm_mode_change(adapter->agent, mode, confirm_mode_cb, req); if (ret < 0) { session_unref(req); return invalid_args(msg); } return NULL;}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->discov_timeout_id) { g_source_remove(adapter->discov_timeout_id); adapter->discov_timeout_id = 0; } if ((timeout != 0) && (adapter->scan_mode & SCAN_INQUIRY)) adapter_set_discov_timeout(adapter, timeout * 1000); 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 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) { dbus_connection_send(bonding->conn, reply, NULL); dbus_message_unref(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; device = l->data; return device;}struct btd_device *adapter_create_device(DBusConnection *conn, struct btd_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 btd_adapter *adapter = data; struct btd_device *device; char filename[PATH_MAX + 1]; char *str, srcaddr[18]; bdaddr_t dst; GSList *l; int dev, err; gboolean paired; str2ba(address, &dst); ba2str(&adapter->bdaddr, srcaddr); dev = hci_open_dev(adapter->dev_id); if (dev < 0 && msg) return no_such_adapter(msg); create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "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, HCI_REQ_TIMEOUT); /* 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, HCI_REQ_TIMEOUT) < 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); 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 btd_adapter *adapter, struct btd_device *device){ bdaddr_t dst; const gchar *dev_path = device_get_path(device); struct agent *agent; char dstaddr[18]; device_get_address(device, &dst); ba2str(&dst, dstaddr); delete_entry(&adapter->bdaddr, "profiles", dstaddr); adapter->devices = g_slist_remove(adapter->devices, device); if (!device_is_temporary(device)) { remove_bonding(conn, NULL, dstaddr, adapter); g_dbus_emit_signal(conn, adapter->path, ADAPTER_INTERFACE, "DeviceRemoved", DBUS_TYPE_OBJECT_PATH, &dev_path, DBUS_TYPE_INVALID); adapter_update_devices(adapter); } agent = device_get_agent(device); if (agent) { agent_destroy(agent, FALSE); device_set_agent(device, NULL); } device_remove(conn, device);}struct btd_device *adapter_get_device(DBusConnection *conn, struct btd_adapter *adapter, const gchar *address){
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?