diff --git a/src/shared/gatt-helpers.c b/src/shared/gatt-helpers.c
index 4dc787f..4cc483a 100644
--- a/src/shared/gatt-helpers.c
+++ b/src/shared/gatt-helpers.c
destroy, false);
}
+static void discover_included_cb(uint8_t opcode, const void *pdu,
+ uint16_t length, void *user_data)
+{
+ struct bt_gatt_result *final_result = NULL;
+ struct discovery_op *op = user_data;
+ struct bt_gatt_result *cur_result;
+ uint8_t att_ecode = 0;
+ uint16_t last_handle;
+ size_t data_length;
+ bool success;
+
+ if (opcode == BT_ATT_OP_ERROR_RSP) {
+ att_ecode = process_error(pdu, length);
+
+ if (att_ecode == BT_ATT_ERROR_ATTRIBUTE_NOT_FOUND &&
+ op->result_head)
+ goto done;
+
+ success = false;
+ goto failed;
+ }
+
+ if (opcode != BT_ATT_OP_READ_BY_TYPE_RSP || !pdu || length < 6) {
+ success = false;
+ goto failed;
+ }
+
+ data_length = ((const uint8_t *) pdu)[0];
+
+ /*
+ * Check if PDU contains data sets with length declared in the beginning
+ * of frame and if this length is correct.
+ * Data set length may be 6 or 8 octets:
+ * 2 octets - include service handle
+ * 2 octets - start handle of included service
+ * 2 octets - end handle of included service
+ * optional 2 octets - Bluetooth UUID of included service
+ */
+ if (data_length != 8 || (length - 1) % data_length) {
+ success = false;
+ goto failed;
+ }
+
+ cur_result = result_create(opcode, pdu + 1, length - 1,
+ data_length, op);
+ if (!cur_result) {
+ success = false;
+ goto failed;
+ }
+
+ if (!op->result_head) {
+ op->result_head = op->result_tail = cur_result;
+ } else {
+ op->result_tail->next = cur_result;
+ op->result_tail = cur_result;
+ }
+
+ last_handle = get_le16(pdu + length - data_length);
+ if (last_handle != op->end_handle) {
+ uint8_t pdu[6];
+
+ put_le16(last_handle + 1, pdu);
+ put_le16(op->end_handle, pdu + 2);
+ put_le16(GATT_INCLUDE_UUID, pdu + 4);
+
+ if (bt_att_send(op->att, BT_ATT_OP_READ_BY_TYPE_REQ,
+ pdu, sizeof(pdu),
+ discover_included_cb,
+ discovery_op_ref(op),
+ discovery_op_unref))
+ return;
+
+ discovery_op_unref(op);
+ success = false;
+ goto failed;
+ }
+
+done:
+ success = true;
+ final_result = op->result_head;
+
+failed:
+ if (op->callback)
+ op->callback(success, att_ecode, final_result, op->user_data);
+}
+
bool bt_gatt_discover_included_services(struct bt_att *att,
uint16_t start, uint16_t end,
bt_uuid_t *uuid,
void *user_data,
bt_gatt_destroy_func_t destroy)
{
- /* TODO */
- return false;
+ struct discovery_op *op;
+ uint8_t pdu[6];
+
+ if (!att)
+ return false;
+
+ op = new0(struct discovery_op, 1);
+ if (!op)
+ return false;
+
+ op->att = att;
+ op->callback = callback;
+ op->user_data = user_data;
+ op->destroy = destroy;
+ op->end_handle = end;
+
+ put_le16(start, pdu);
+ put_le16(end, pdu + 2);
+ put_le16(GATT_INCLUDE_UUID, pdu + 4);
+
+ if (!bt_att_send(att, BT_ATT_OP_READ_BY_TYPE_REQ,
+ pdu, sizeof(pdu),
+ discover_included_cb,
+ discovery_op_ref(op),
+ discovery_op_unref)) {
+ free(op);
+ return false;
+ }
+
+ return true;
}
static void discover_chrcs_cb(uint8_t opcode, const void *pdu,