📄 adapter.c
字号:
bdaddr_t bdaddr; int sk; str2ba(address, &bdaddr); /* check if there is a pending discover: requested by D-Bus/non clients */ if (adapter->discov_active) 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, &bdaddr)) return in_progress(msg, "Bonding in progress"); /* check if a link key already exists */ create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "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->address, &bdaddr); 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;}static void periodic_discover_req_exit(void *user_data){ struct adapter *adapter = user_data; debug("PeriodicDiscovery requestor exited"); /* Cleanup the discovered devices list and send the cmd to exit from * periodic inquiry or cancel remote name request. The return value can * be ignored. */ cancel_periodic_discovery(adapter);}static DBusMessage *adapter_start_periodic(DBusConnection *conn, DBusMessage *msg, void *data){ periodic_inquiry_cp cp; struct hci_request rq; struct adapter *adapter = data; uint8_t lap[3] = { 0x33, 0x8b, 0x9e }; uint8_t status; int dd; if (!adapter->up) return adapter_not_ready(msg); if (dbus_message_is_method_call(msg, ADAPTER_INTERFACE, "StartPeriodicDiscovery")) { if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) return invalid_args(msg); } if (adapter->discov_active || adapter->pdiscov_active) return in_progress(msg, "Discover in progress"); pending_remote_name_cancel(adapter); dd = hci_open_dev(adapter->dev_id); if (dd < 0) return no_such_adapter(msg); 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, 1000) < 0) { int err = errno; error("Unable to start periodic inquiry: %s (%d)", strerror(errno), errno); hci_close_dev(dd); return failed_strerror(msg, err); } if (status) { error("HCI_Periodic_Inquiry_Mode failed with status 0x%02x", status); hci_close_dev(dd); return failed_strerror(msg, bt_error(status)); } adapter->pdiscov_requestor = g_strdup(dbus_message_get_sender(msg)); if (adapter->pdiscov_resolve_names) adapter->discov_type = PERIODIC_INQUIRY | RESOLVE_NAME; else adapter->discov_type = PERIODIC_INQUIRY; hci_close_dev(dd); /* track the request owner to cancel it automatically if the owner * exits */ adapter->pdiscov_listener = g_dbus_add_disconnect_watch(conn, dbus_message_get_sender(msg), periodic_discover_req_exit, adapter, NULL); return dbus_message_new_method_return(msg);}static DBusMessage *adapter_stop_periodic(DBusConnection *conn, DBusMessage *msg, void *data){ struct adapter *adapter = data; int err; if (!adapter->up) return adapter_not_ready(msg); if (!adapter->pdiscov_active) return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAuthorized", "Not authorized"); /* * Cleanup the discovered devices list and send the cmd to exit * from periodic inquiry mode or cancel remote name request. */ err = cancel_periodic_discovery(adapter); if (err < 0) { if (err == -ENODEV) return no_such_adapter(msg); else return failed_strerror(msg, -err); } return dbus_message_new_method_return(msg);}static void discover_devices_req_exit(void *user_data){ struct adapter *adapter = user_data; debug("DiscoverDevices requestor exited"); /* Cleanup the discovered devices list and send the command to cancel * inquiry or cancel remote name request. The return can be ignored. */ cancel_discovery(adapter);}static DBusMessage *adapter_discover_devices(DBusConnection *conn, DBusMessage *msg, void *data){ inquiry_cp cp; evt_cmd_status rp; struct hci_request rq; struct adapter *adapter = data; uint8_t lap[3] = { 0x33, 0x8b, 0x9e }; int dd; if (!adapter->up) return adapter_not_ready(msg); if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) return invalid_args(msg); if (adapter->discov_active) return in_progress(msg, "Discover in progress"); pending_remote_name_cancel(adapter); if (adapter->bonding) return in_progress(msg, "Bonding in progress"); dd = hci_open_dev(adapter->dev_id); if (dd < 0) return no_such_adapter(msg); 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, 500) < 0) { int err = errno; error("Unable to start inquiry: %s (%d)", strerror(errno), errno); hci_close_dev(dd); return failed_strerror(msg, err); } if (rp.status) { error("HCI_Inquiry command failed with status 0x%02x", rp.status); hci_close_dev(dd); return failed_strerror(msg, bt_error(rp.status)); } adapter->discov_type |= (STD_INQUIRY | RESOLVE_NAME); adapter->discov_requestor = g_strdup(dbus_message_get_sender(msg)); hci_close_dev(dd); /* track the request owner to cancel it automatically if the owner * exits */ adapter->discov_listener = g_dbus_add_disconnect_watch(conn, dbus_message_get_sender(msg), discover_devices_req_exit, adapter, NULL); return dbus_message_new_method_return(msg);}static DBusMessage *adapter_cancel_discovery(DBusConnection *conn, DBusMessage *msg, void *data){ struct adapter *adapter = data; int err; if (!adapter->up) return adapter_not_ready(msg); if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) return invalid_args(msg); /* is there discover pending? or discovery cancel was requested * previously */ if (!adapter->discov_active || adapter->discovery_cancel) return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAuthorized", "Not Authorized"); /* only the discover requestor can cancel the inquiry process */ if (!adapter->discov_requestor || strcmp(adapter->discov_requestor, dbus_message_get_sender(msg))) return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAuthorized", "Not Authorized"); /* Cleanup the discovered devices list and send the cmd to cancel * inquiry or cancel remote name request */ err = cancel_discovery(adapter); if (err < 0) { if (err == -ENODEV) return no_such_adapter(msg); else return failed_strerror(msg, -err); } /* Reply before send DiscoveryCompleted */ adapter->discovery_cancel = dbus_message_ref(msg); return NULL;}struct remote_device_list_t { GSList *list; time_t time;};static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg, void *data){ struct adapter *adapter = data; const char *property; DBusMessage *reply; DBusMessageIter iter; DBusMessageIter dict; bdaddr_t ba; char str[249]; if (check_address(adapter->address) < 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 = adapter->address; dbus_message_iter_append_dict_entry(&dict, "Address", DBUS_TYPE_STRING, &property); /* Name */ memset(str, 0, sizeof(str)); property = str; str2ba(adapter->address, &ba); if (!read_local_name(&ba, str)) dbus_message_iter_append_dict_entry(&dict, "Name", DBUS_TYPE_STRING, &property); /* Mode */ property = mode2str(adapter->mode); dbus_message_iter_append_dict_entry(&dict, "Mode", DBUS_TYPE_STRING, &property); /* DiscoverableTimeout */ dbus_message_iter_append_dict_entry(&dict, "DiscoverableTimeout", DBUS_TYPE_UINT32, &adapter->discov_timeout); /* PeriodicDiscovery */ dbus_message_iter_append_dict_entry(&dict, "PeriodicDiscovery", DBUS_TYPE_BOOLEAN, &adapter->pdiscov_active); dbus_message_iter_close_container(&iter, &dict); return reply;}static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg, void *data){ struct adapter *adapter = data; DBusMessageIter iter; DBusMessageIter sub; const char *property; if (!dbus_message_iter_init(msg, &iter)) return invalid_args(msg); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) return invalid_args(msg); dbus_message_iter_get_basic(&iter, &property); dbus_message_iter_next(&iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) return invalid_args(msg); dbus_message_iter_recurse(&iter, &sub); if (g_str_equal("Name", property)) { const char *name; if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) return invalid_args(msg); dbus_message_iter_get_basic(&sub, &name); return set_name(conn, msg, name, data); } else if (g_str_equal("DiscoverableTimeout", property)) { uint32_t timeout; if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT32) return invalid_args(msg); dbus_message_iter_get_basic(&sub, &timeout); return set_discoverable_timeout(conn, msg, timeout, data); } else if (g_str_equal("PeriodicDiscovery", property)) { dbus_bool_t value; if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN) return invalid_args(msg); dbus_message_iter_get_basic(&sub, &value); if (value) return adapter_start_periodic(conn, msg, data); else return adapter_stop_periodic(conn, msg, data); } else if (g_str_equal("Mode", property)) { const char *mode; if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) return invalid_args(msg); dbus_message_iter_get_basic(&sub, &mode); adapter->global_mode = str2mode(adapter->address, mode); if (adapter->global_mode == adapter->mode) return dbus_message_new_method_return(msg); if (adapter->sessions && adapter->global_mode < adapter->mode) return confirm_mode(conn, msg, mode, data); return set_mode(conn, msg, str2mode(adapter->address, mode), data); } return invalid_args(msg);}static void session_exit(void *data){ struct mode_req *req = data; struct adapter *adapter = req->adapter; adapter->sessions = g_slist_remove(adapter->sessions, req); if (!adapter->sessions) { debug("Falling back to '%s' mode", mode2str(adapter->global_mode)); /* FIXME: fallback to previous mode set_mode(req->conn, req->msg, adapter->global_mode, adapter); */ } dbus_connection_unref(req->conn); dbus_message_unref(req->msg); g_free(req);}static DBusMessage *request_mode(DBusConnection *conn, DBusMessage *msg, void *data){ const char *mode; struct adapter *adapter = data; struct mode_req *req; uint8_t new_mode; int ret; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &mode, DBUS_TYPE_INVALID)) return invalid_args(msg); new_mode = str2mode(adapter->address, mode); if (new_mode != MODE_CONNECTABLE && new_mode != MODE_DISCOVERABLE) return invalid_args(msg); if (!adapter->agent) return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", "No agent registered"); if (g_slist_find_custom(adapter->sessions, msg, (GCompareFunc) find_session)) return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", "Mode already requested"); req = g_new0(struct mode_req, 1); req->adapter = adapter; req->conn = dbus_connection_ref(conn); req->msg = dbus_message_ref(msg); req->mode = new_mode; req->id = g_dbus_add_disconnect_watch(conn, dbus_message_get_sender(msg), session_exit, req, NULL); if (!adapter->sessions) adapter->global_mode = adapter->mode; adapter->sessions = g_slist_append(adapter->sessions, req); /* No need to change mode */ if (adapter->mode >= new_mode) return dbus_message_new_method_return(msg); ret = agent_confirm_mode_change(adapter->agent, mode, confirm_mode_cb, req); if (ret < 0) { dbus_message_unref(req->msg); g_dbus_remove_watch(req->conn, req->id); dbus_connection_unref(req->conn); g_free(req); return invalid_args(msg); } return NULL;}static DBusMessage *release_mode(DBusConnection *conn, DBusMessage *msg, void *data){ struct adapter *adapter = data; GSList *l; l = g_slist_find_custom(adapter->sessions, msg, (GCompareFunc) find_session); if (!l) return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", "No Mode to release"); session_exit(l->data); return dbus_message_new_method_return(msg);}static DBusMessage *list_devices(DBusConnection *conn, DBusMessage *msg, void *data){ struct adapter *adapter = data; DBusMessage *reply; GSList *l; DBusMessageIter iter; DBusMessageIter array_iter; const gchar *dev_path; if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING)) return invalid_args(msg);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -