static void exec_write_cb(uint8_t opcode, const void *pdu, uint16_t length, void *user_data) { struct bt_gatt_server *server = user_data; uint8_t flags; uint8_t ecode; bool write; uint16_t ehandle = 0; if (length != 1) { ecode = BT_ATT_ERROR_INVALID_PDU; goto error; } flags = ((uint8_t *) pdu)[0]; util_debug(server->debug_callback, server->debug_data, "Exec Write Req - flags: 0x%02x", flags); if (flags == 0x00) write = false; else if (flags == 0x01) write = true; else { ecode = BT_ATT_ERROR_INVALID_PDU; goto error; } if (!write) { queue_remove_all(server->prep_queue, NULL, NULL, prep_write_data_destroy); bt_att_send(server->att, BT_ATT_OP_EXEC_WRITE_RSP, NULL, 0, NULL, NULL, NULL); return; } /* If there is more than one prep request, we are in reliable session */ if (queue_length(server->prep_queue) > 1) { struct prep_write_data *prep_data; prep_data = queue_find(server->prep_queue, find_no_reliable_characteristic, NULL); if (prep_data) { ecode = BT_ATT_ERROR_REQUEST_NOT_SUPPORTED; ehandle = prep_data->handle; goto error; } } exec_next_prep_write(server, 0, 0); return; error: queue_remove_all(server->prep_queue, NULL, NULL, prep_write_data_destroy); bt_att_send_error_rsp(server->att, opcode, ehandle, ecode); }
bool bt_att_unregister_all(struct bt_att *att) { if (!att) return false; queue_remove_all(att->notify_list, NULL, NULL, destroy_att_notify); queue_remove_all(att->disconn_list, NULL, NULL, destroy_att_disconn); return true; }
bool mgmt_cancel_all(struct mgmt *mgmt) { if (!mgmt) return false; queue_remove_all(mgmt->pending_list, NULL, NULL, destroy_request); queue_remove_all(mgmt->reply_queue, NULL, NULL, destroy_request); queue_remove_all(mgmt->request_queue, NULL, NULL, destroy_request); return true; }
bool mgmt_cancel_index(struct mgmt *mgmt, uint16_t index) { if (!mgmt) return false; queue_remove_all(mgmt->request_queue, match_request_index, UINT_TO_PTR(index), destroy_request); queue_remove_all(mgmt->reply_queue, match_request_index, UINT_TO_PTR(index), destroy_request); queue_remove_all(mgmt->pending_list, match_request_index, UINT_TO_PTR(index), destroy_request); return true; }
bool bt_hci_flush(struct bt_hci *hci) { if (!hci) return false; if (hci->writer_active) { io_set_write_handler(hci->io, NULL, NULL, NULL); hci->writer_active = false; } queue_remove_all(hci->cmd_queue, NULL, NULL, cmd_free); queue_remove_all(hci->rsp_queue, NULL, NULL, cmd_free); return true; }
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); }
bool bt_att_cancel_all(struct bt_att *att) { if (!att) return false; queue_remove_all(att->req_queue, NULL, NULL, destroy_att_send_op); queue_remove_all(att->ind_queue, NULL, NULL, destroy_att_send_op); queue_remove_all(att->write_queue, NULL, NULL, destroy_att_send_op); if (att->pending_req) destroy_att_send_op(att->pending_req); if (att->pending_ind) destroy_att_send_op(att->pending_ind); return true; }
void queue_destroy(struct queue *queue, queue_destroy_func_t destroy) { if (!queue) return; queue_remove_all(queue, NULL, NULL, destroy); queue_unref(queue); }
static void unregister_characteristic(void *data) { struct characteristic *chrc = data; struct bt_gatt_client *gatt = chrc->service->client->gatt; DBG("Removing GATT characteristic: %s", chrc->path); if (chrc->read_id) bt_gatt_client_cancel(gatt, chrc->read_id); if (chrc->write_id) bt_gatt_client_cancel(gatt, chrc->write_id); queue_remove_all(chrc->notify_clients, NULL, NULL, remove_client); queue_remove_all(chrc->descs, NULL, NULL, unregister_descriptor); g_dbus_unregister_interface(btd_get_dbus_connection(), chrc->path, GATT_CHARACTERISTIC_IFACE); }
bool bt_att_cancel_all(struct bt_att *att) { if (!att) return false; queue_remove_all(att->req_queue, NULL, NULL, destroy_att_send_op); queue_remove_all(att->ind_queue, NULL, NULL, destroy_att_send_op); queue_remove_all(att->write_queue, NULL, NULL, destroy_att_send_op); if (att->pending_req) /* Don't cancel the pending request; remove it's handlers */ cancel_att_send_op(att->pending_req); if (att->pending_ind) /* Don't cancel the pending request; remove it's handlers */ cancel_att_send_op(att->pending_ind); return true; }
bool gatt_db_clear(struct gatt_db *db) { if (!db) return false; queue_remove_all(db->services, NULL, NULL, gatt_db_service_destroy); db->next_handle = 0; return true; }
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; }
static void unregister_service(void *data) { struct service *service = data; DBG("Removing GATT service: %s", service->path); if (service->idle_id) g_source_remove(service->idle_id); queue_remove_all(service->chrcs, NULL, NULL, unregister_characteristic); g_dbus_unregister_interface(btd_get_dbus_connection(), service->path, GATT_SERVICE_IFACE); }
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; }
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; }
bool gatt_db_clear_range(struct gatt_db *db, uint16_t start_handle, uint16_t end_handle) { struct clear_range range; if (!db || start_handle > end_handle) return false; range.start = start_handle; range.end = end_handle; queue_remove_all(db->services, match_range, &range, gatt_db_service_destroy); return true; }
void btd_gatt_client_disconnected(struct btd_gatt_client *client) { if (!client) return; DBG("Device disconnected. Cleaning up"); /* * Remove all services. We'll recreate them when a new bt_gatt_client * becomes ready. */ queue_remove_all(client->services, NULL, NULL, unregister_service); bt_gatt_client_unref(client->gatt); client->gatt = NULL; }
void btd_gatt_client_service_removed(struct btd_gatt_client *client, struct gatt_db_attribute *attrib) { uint16_t start_handle, end_handle; if (!client || !attrib || !client->ready) return; gatt_db_attribute_get_service_handles(attrib, &start_handle, &end_handle); DBG("GATT Services Removed - start: 0x%04x, end: 0x%04x", start_handle, end_handle); queue_remove_all(client->services, match_service_handle, UINT_TO_PTR(start_handle), unregister_service); }
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 void exec_next_prep_write(struct bt_gatt_server *server, uint16_t ehandle, int err) { struct prep_write_data *next = NULL; struct gatt_db_attribute *attr; bool status; if (err) goto error; next = queue_pop_head(server->prep_queue); if (!next) { bt_att_send(server->att, BT_ATT_OP_EXEC_WRITE_RSP, NULL, 0, NULL, NULL, NULL); return; } attr = gatt_db_get_attribute(server->db, next->handle); if (!attr) { err = BT_ATT_ERROR_UNLIKELY; goto error; } status = gatt_db_attribute_write(attr, next->offset, next->value, next->length, BT_ATT_OP_EXEC_WRITE_REQ, server->att, exec_write_complete_cb, server); prep_write_data_destroy(next); if (status) return; err = BT_ATT_ERROR_UNLIKELY; error: queue_remove_all(server->prep_queue, NULL, NULL, prep_write_data_destroy); bt_att_send_error_rsp(server->att, BT_ATT_OP_EXEC_WRITE_REQ, ehandle, err); }
static void exec_write_cb(uint8_t opcode, const void *pdu, uint16_t length, void *user_data) { struct bt_gatt_server *server = user_data; uint8_t flags; uint8_t ecode; bool write; if (length != 1) { ecode = BT_ATT_ERROR_INVALID_PDU; goto error; } flags = ((uint8_t *) pdu)[0]; util_debug(server->debug_callback, server->debug_data, "Exec Write Req - flags: 0x%02x", flags); if (flags == 0x00) write = false; else if (flags == 0x01) write = true; else { ecode = BT_ATT_ERROR_INVALID_PDU; goto error; } if (!write) { queue_remove_all(server->prep_queue, NULL, NULL, prep_write_data_destroy); bt_att_send(server->att, BT_ATT_OP_EXEC_WRITE_RSP, NULL, 0, NULL, NULL, NULL); return; } exec_next_prep_write(server, 0, 0); return; error: bt_att_send_error_rsp(server->att, opcode, 0, ecode); }
static void mcap_mdl_deleted_cb(struct mcap_mdl *mdl, void *data) { struct health_channel *channel = data; struct health_device *dev; if (!channel) return; dev = channel->dev; DBG("device %p channel %p mdl %p", dev, channel, mdl); /* mdl == NULL means, delete all mdls */ if (!mdl) { queue_foreach(dev->channels, notify_channel, NULL); queue_remove_all(dev->channels, NULL, NULL, free_health_channel); return; } destroy_channel(channel); }