static void handle_notify(struct bt_att *att, uint8_t opcode, uint8_t *pdu, ssize_t pdu_len) { struct notify_data data; bt_att_ref(att); att->in_notify = true; memset(&data, 0, sizeof(data)); data.opcode = opcode; if (pdu_len > 0) { data.pdu = pdu; data.pdu_len = pdu_len; } queue_foreach(att->notify_list, notify_handler, &data); att->in_notify = false; if (att->need_notify_cleanup) { queue_remove_all(att->notify_list, match_notify_removed, NULL, destroy_att_notify); att->need_notify_cleanup = false; } bt_att_unref(att); }
static bool disconnect_cb(struct io *io, void *user_data) { struct bt_att *att = user_data; int err; socklen_t len; len = sizeof(err); if (getsockopt(att->fd, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { util_debug(att->debug_callback, att->debug_data, "Failed to obtain disconnect error: %s", strerror(errno)); err = 0; } util_debug(att->debug_callback, att->debug_data, "Physical link disconnected: %s", strerror(err)); io_destroy(att->io); att->io = NULL; bt_att_cancel_all(att); bt_att_ref(att); queue_foreach(att->disconn_list, disconn_handler, INT_TO_PTR(err)); bt_att_unregister_all(att); bt_att_unref(att); return false; }
static void resume_callback(void) { gboolean suspend = FALSE; DBG("Resuming ..."); queue_foreach(devices, set_suspend, GINT_TO_POINTER(suspend)); }
static void suspend_callback(void) { gboolean suspend = TRUE; DBG("Suspending ..."); queue_foreach(devices, set_suspend, GINT_TO_POINTER(suspend)); }
void bt_dis_detach(struct bt_dis *dis) { if (!dis->attrib) return; queue_foreach(dis->gatt_op, (void *) cancel_gatt_req, NULL); g_attrib_unref(dis->attrib); dis->attrib = NULL; }
void btd_gatt_client_disconnected(struct btd_gatt_client *client) { if (!client || !client->gatt) return; DBG("Device disconnected. Cleaning up."); /* * TODO: Once GATT over BR/EDR is properly supported, we should pass the * correct bdaddr_type based on the transport over which GATT is being * done. */ queue_foreach(client->all_notify_clients, clear_notify_id, NULL); queue_foreach(client->services, cancel_ops, client->gatt); bt_gatt_client_unref(client->gatt); client->gatt = NULL; }
static void app_search_channel(void *data, void *user_data) { struct health_app *app = data; struct channel_search *search = user_data; if (search->channel) return; queue_foreach(app->devices, device_search_channel, search); }
static int register_endpoints(void) { struct register_state state; state.ep = &audio_endpoints[0]; state.error = false; queue_foreach(loaded_codecs, register_endpoint, &state); return state.error ? AUDIO_STATUS_FAILED : AUDIO_STATUS_SUCCESS; }
static struct health_channel *search_channel_by_id(uint16_t id) { struct channel_search search; DBG(""); search.channel_id = id; search.channel = NULL; queue_foreach(apps, app_search_channel, &search); return search.channel; }
void gatt_db_find_information(struct gatt_db *db, uint16_t start_handle, uint16_t end_handle, struct queue *queue) { struct find_information_data data; data.start_handle = start_handle; data.end_handle = end_handle; data.queue = queue; queue_foreach(db->services, find_information, &data); }
static void master_command_callback(uint16_t opcode, const void *data, uint8_t len, btdev_callback callback, void *user_data) { struct hciemu *hciemu = user_data; struct run_data run_data = { .opcode = opcode, .data = data, .len = len }; btdev_command_default(callback); queue_foreach(hciemu->post_command_hooks, run_command_hook, &run_data); }
void gatt_db_read_by_type(struct gatt_db *db, uint16_t start_handle, uint16_t end_handle, const bt_uuid_t type, struct queue *queue) { struct read_by_type_data data; data.uuid = type; data.start_handle = start_handle; data.end_handle = end_handle; data.queue = queue; queue_foreach(db->services, read_by_type, &data); }
static struct health_app *search_app_by_mdepid(uint8_t mdepid) { struct app_search search; DBG(""); search.mdepid = mdepid; search.app = NULL; queue_foreach(apps, app_search_mdep, &search); return search.app; }
void bt_bas_detach(struct bt_bas *bas) { if (!bas || !bas->attrib) return; if (bas->id > 0) { g_attrib_unregister(bas->attrib, bas->id); bas->id = 0; } queue_foreach(bas->gatt_op, (void *) cancel_gatt_req, NULL); g_attrib_unref(bas->attrib); bas->attrib = NULL; }
void bt_scpp_detach(struct bt_scpp *scan) { if (!scan || !scan->attrib) return; if (scan->refresh_cb_id > 0) { g_attrib_unregister(scan->attrib, scan->refresh_cb_id); scan->refresh_cb_id = 0; } queue_foreach(scan->gatt_op, (void *) cancel_gatt_req, NULL); g_attrib_unref(scan->attrib); scan->attrib = NULL; }
bool mgmt_unregister_all(struct mgmt *mgmt) { if (!mgmt) return false; if (mgmt->in_notify) { queue_foreach(mgmt->notify_list, mark_notify_removed, UINT_TO_PTR(MGMT_INDEX_NONE)); mgmt->need_notify_cleanup = true; } else queue_remove_all(mgmt->notify_list, NULL, NULL, destroy_notify); return true; }
void btd_gatt_client_foreach_service(struct btd_gatt_client *client, btd_gatt_client_service_path_t func, void *user_data) { struct foreach_service_data data; if (!client) return; data.func = func; data.user_data = user_data; queue_foreach(client->services, client_service_foreach, &data); }
bool mgmt_unregister_index(struct mgmt *mgmt, uint16_t index) { if (!mgmt) return false; if (mgmt->in_notify) { queue_foreach(mgmt->notify_list, mark_notify_removed, UINT_TO_PTR(index)); mgmt->need_notify_cleanup = true; } else queue_remove_all(mgmt->notify_list, match_notify_index, UINT_TO_PTR(index), destroy_notify); return true; }
static gboolean characteristic_get_descriptors( const GDBusPropertyTable *property, DBusMessageIter *iter, void *data) { struct characteristic *chrc = data; DBusMessageIter array; dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "o", &array); queue_foreach(chrc->descs, append_desc_path, &array); dbus_message_iter_close_container(iter, &array); return TRUE; }
static gboolean service_get_characteristics(const GDBusPropertyTable *property, DBusMessageIter *iter, void *data) { struct service *service = data; DBusMessageIter array; dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "o", &array); if (service->chrcs_ready) queue_foreach(service->chrcs, append_chrc_path, &array); dbus_message_iter_close_container(iter, &array); return TRUE; }
bool bt_att_unregister_all(struct bt_att *att) { if (!att) return false; if (!att->in_notify) { queue_remove_all(att->notify_list, NULL, NULL, destroy_att_notify); return true; } queue_foreach(att->notify_list, mark_notify_removed, NULL); att->need_notify_cleanup = true; return true; }
static void cancel_chrc_ops(void *data, void *user_data) { struct characteristic *chrc = data; struct bt_gatt_client *gatt = user_data; if (chrc->read_id) { bt_gatt_client_cancel(gatt, chrc->read_id); chrc->read_id = 0; } if (chrc->write_id) { bt_gatt_client_cancel(gatt, chrc->write_id); chrc->write_id = 0; } queue_foreach(chrc->descs, cancel_desc_ops, user_data); }
static bool create_characteristics(struct gatt_db_attribute *attr, struct service *service) { struct export_data data; data.root = service; data.failed = false; gatt_db_service_foreach_char(attr, export_char, &data); if (data.failed) return false; /* Obtain extended properties */ queue_foreach(service->pending_ext_props, read_ext_props, NULL); return true; }
static void notify_service_changed(struct gatt_db *db, struct gatt_db_service *service, bool added) { struct notify_data data; if (queue_isempty(db->notify_list)) return; data.attr = service->attributes[0]; data.added = added; gatt_db_ref(db); queue_foreach(db->notify_list, handle_notify, &data); gatt_db_unref(db); }
static void process_notify(struct mgmt *mgmt, uint16_t event, uint16_t index, uint16_t length, const void *param) { struct event_index match = { .event = event, .index = index, .length = length, .param = param }; mgmt->in_notify = true; queue_foreach(mgmt->notify_list, notify_handler, &match); mgmt->in_notify = false; if (mgmt->need_notify_cleanup) { queue_remove_all(mgmt->notify_list, match_notify_removed, NULL, destroy_notify); mgmt->need_notify_cleanup = false; } }
static int register_service_sup_features(sdp_record_t *rec, struct health_app *app) { sdp_list_t *sup_features = NULL; DBG(""); queue_foreach(app->mdeps, register_features, &sup_features); if (!sup_features) return -1; if (sdp_set_supp_feat(rec, sup_features) < 0) { sdp_list_free(sup_features, free_hdp_list); return -1; } sdp_list_free(sup_features, free_hdp_list); return 0; }
void gatt_db_foreach_service_in_range(struct gatt_db *db, const bt_uuid_t *uuid, gatt_db_attribute_cb_t func, void *user_data, uint16_t start_handle, uint16_t end_handle) { struct foreach_data data; if (!db || !func || start_handle > end_handle) return; data.func = func; data.uuid = uuid; data.user_data = user_data; data.start = start_handle; data.end = end_handle; queue_foreach(db->services, foreach_service_in_range, &data); }
unsigned int gatt_db_find_by_type(struct gatt_db *db, uint16_t start_handle, uint16_t end_handle, const bt_uuid_t *type, gatt_db_attribute_cb_t func, void *user_data) { struct find_by_type_value_data data; memset(&data, 0, sizeof(data)); data.uuid = *type; data.start_handle = start_handle; data.end_handle = end_handle; data.func = func; data.user_data = user_data; queue_foreach(db->services, find_by_type, &data); return data.num_of_res; }
void btd_gatt_client_connected(struct btd_gatt_client *client) { struct bt_gatt_client *gatt; gatt = btd_device_get_gatt_client(client->device); if (!gatt) { error("GATT client not initialized"); return; } DBG("Device connected."); bt_gatt_client_unref(client->gatt); client->gatt = bt_gatt_client_ref(gatt); /* * Services have already been created before. Re-enable notifications * for any pre-registered notification sessions. */ queue_foreach(client->all_notify_clients, register_notify, client); }
static void process_event(struct bt_hci *hci, const void *data, size_t size) { const struct bt_hci_evt_hdr *hdr = data; const struct bt_hci_evt_cmd_complete *cc; const struct bt_hci_evt_cmd_status *cs; if (size < sizeof(struct bt_hci_evt_hdr)) return; data += sizeof(struct bt_hci_evt_hdr); size -= sizeof(struct bt_hci_evt_hdr); if (hdr->plen != size) return; switch (hdr->evt) { case BT_HCI_EVT_CMD_COMPLETE: if (size < sizeof(*cc)) return; cc = data; hci->num_cmds = cc->ncmd; process_response(hci, le16_to_cpu(cc->opcode), data + sizeof(*cc), size - sizeof(*cc)); break; case BT_HCI_EVT_CMD_STATUS: if (size < sizeof(*cs)) return; cs = data; hci->num_cmds = cs->ncmd; process_response(hci, le16_to_cpu(cs->opcode), &cs->status, 1); break; default: queue_foreach(hci->evt_list, process_notify, (void *) hdr); break; } }