If included services has 128 bit UUID, it won't be returned in READ_BY_TYPE_RSP. To get UUID READ_REQUEST is used. This procedure is described in CORE SPEC 4.5.1 "Find Included Services". --- src/shared/gatt-helpers.c | 170 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 169 insertions(+), 1 deletion(-) diff --git a/src/shared/gatt-helpers.c b/src/shared/gatt-helpers.c index dcb2a2f..c18f738 100644 --- a/src/shared/gatt-helpers.c +++ b/src/shared/gatt-helpers.c @@ -692,6 +692,160 @@ bool bt_gatt_discover_secondary_services(struct bt_att *att, bt_uuid_t *uuid, 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; + uint16_t handle; + 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; + } + + 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, data_len; + uint8_t pdu[6]; + + data_len = data->result->data_len; + last_handle = get_le16(data->result->pdu + data->pos - + 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; + } + + handle = get_le16(data->result->pdu + data->pos + 2); + put_le16(handle, read_pdu); + + 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; + uint16_t handle; + uint8_t pdu[2]; + + handle = get_le16(data->result->pdu + 2); + put_le16(handle, pdu); + + 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) { @@ -721,7 +875,8 @@ static void discover_included_cb(uint8_t opcode, const void *pdu, data_length = ((uint8_t *) pdu)[0]; - if ((length - 1) % data_length || data_length != 8) { + if (((length - 1) % data_length) || + (data_length != 8 && data_length != 6)) { success = false; goto done; } @@ -740,6 +895,19 @@ static void discover_included_cb(uint8_t opcode, const void *pdu, 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]; -- 1.9.3 -- To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html