Return-Path: From: Marcin Kraglak To: linux-bluetooth@vger.kernel.org Subject: [PATCHv2 2/6] shared/gatt: Discover included services 128 bit UUIDS Date: Mon, 6 Oct 2014 07:55:40 +0200 Message-Id: <1412574944-5304-2-git-send-email-marcin.kraglak@tieto.com> In-Reply-To: <1412574944-5304-1-git-send-email-marcin.kraglak@tieto.com> References: <1412574944-5304-1-git-send-email-marcin.kraglak@tieto.com> Sender: linux-bluetooth-owner@vger.kernel.org List-ID: 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 d126a55..f4ca97c 100644 --- a/src/shared/gatt-helpers.c +++ b/src/shared/gatt-helpers.c @@ -668,6 +668,160 @@ bool bt_gatt_discover_primary_services(struct bt_att *att, bt_uuid_t *uuid, return result; } +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) { @@ -697,7 +851,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; } @@ -716,6 +871,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