destroy, false);
}
+struct read_incl_data {
+ struct discovery_op *op;
+ struct bt_gatt_result *result;
+ int pos;
+ int ref_count;
+};
+
+static struct read_incl_data *new_read_included(struct bt_gatt_result *res)
+{
+ struct read_incl_data *data;
+
+ data = new0(struct read_incl_data, 1);
+ if (!data)
+ return NULL;
+
+ data->op = discovery_op_ref(res->op);
+ data->result = res;
+
+ return data;
+};
+
+static struct read_incl_data *read_included_ref(struct read_incl_data *data)
+{
+ __sync_fetch_and_add(&data->ref_count, 1);
+
+ return data;
+}
+
+static void read_included_unref(void *data)
+{
+ struct read_incl_data *read_data = data;
+
+ if (__sync_sub_and_fetch(&read_data->ref_count, 1))
+ return;
+
+ discovery_op_unref(read_data->op);
+
+ free(read_data);
+}
+
+static void discover_included_cb(uint8_t opcode, const void *pdu,
+ uint16_t length, void *user_data);
+
+static void read_included_cb(uint8_t opcode, const void *pdu,
+ uint16_t length, void *user_data)
+{
+ struct read_incl_data *data = user_data;
+ struct bt_gatt_result *final_result = NULL;
+ struct discovery_op *op = data->op;
+ struct bt_gatt_result *cur_result;
+ uint8_t att_ecode = 0;
+ uint8_t read_pdu[2];
+ bool success;
+
+ if (opcode == BT_ATT_OP_ERROR_RSP) {
+ success = false;
+ att_ecode = process_error(pdu, length);
+ goto done;
+ }
+
+ if (opcode != BT_ATT_OP_READ_RSP || (!pdu && length)) {
+ success = false;
+ goto done;
+ }
+
+ /*
+ * UUID should be in 128 bit format, as it couldn't be read in
+ * READ_BY_TYPE request
+ */
+ if (length != 16) {
+ success = false;
+ goto done;
+ }
+
+ cur_result = result_create(opcode, pdu, length, length, op);
+ if (!cur_result) {
+ success = false;
+ goto done;
+ }
+
+ if (!op->result_head) {
+ op->result_head = op->result_tail = cur_result;
+ } else {
+ op->result_tail->next = cur_result;
+ op->result_tail = cur_result;
+ }
+
+ if (data->pos == data->result->pdu_len) {
+ uint16_t last_handle;
+ uint8_t pdu[6];
+
+ last_handle = get_le16(data->result->pdu + data->pos -
+ data->result->data_len);
+ if (last_handle == op->end_handle) {
+ final_result = op->result_head;
+ success = true;
+ goto done;
+ }
+
+ 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 done;
+ }
+
+ memcpy(read_pdu, data->result->pdu + data->pos + 2, sizeof(uint16_t));
+
+ data->pos += data->result->data_len;
+
+ if (bt_att_send(op->att, BT_ATT_OP_READ_REQ, read_pdu, sizeof(read_pdu),
+ read_included_cb, read_included_ref(data),
+ read_included_unref))
+ return;
+
+ read_included_unref(data);
+ success = false;
+
+done:
+ if (op->callback)
+ op->callback(success, att_ecode, final_result, op->user_data);
+}
+
+static void read_included(struct read_incl_data *data)
+{
+ struct discovery_op *op = data->op;
+ uint8_t pdu[2];
+
+ memcpy(pdu, data->result->pdu + 2, sizeof(uint16_t));
+
+ data->pos += data->result->data_len;
+
+ if (bt_att_send(op->att, BT_ATT_OP_READ_REQ, pdu, sizeof(pdu),
+ read_included_cb,
+ read_included_ref(data),
+ read_included_unref))
+ return;
+
+ read_included_unref(data);
+
+ if (op->callback)
+ op->callback(false, 0, NULL, data->op->user_data);
+}
+
static void discover_included_cb(uint8_t opcode, const void *pdu,
uint16_t length, void *user_data)
{
* 2 octets - end handle of included service
* optional 2 octets - Bluetooth UUID of included service
*/
- if (data_length != 8 || (length - 1) % data_length) {
+ if ((data_length != 8 && data_length != 6) ||
+ (length - 1) % data_length) {
success = false;
goto failed;
}
op->result_tail = cur_result;
}
+ if (data_length == 6) {
+ struct read_incl_data *data;
+
+ data = new_read_included(cur_result);
+ if (!data) {
+ success = false;
+ goto done;
+ }
+
+ read_included(data);
+ return;
+ }
+
last_handle = get_le16(pdu + length - data_length);
if (last_handle != op->end_handle) {
uint8_t pdu[6];