It allows user to perform Read By Type requests with given UUID
v2:
Implementation moved to gatt-helpers instead of gatt-client
after conversation with Arman and Luiz.
Marcin Kraglak (9):
shared/gatt-helpers: Add read-by-type functionality
shared/gatt-helpers: Add iterator to read_by_type results
unit/test-gatt: Add /TP/GAR/CL/BV-03-C-1 test
unit/test-gatt: Add /TP/GAR/CL/BV-03-C-2 test
unit/test-gatt: Add /TP/GAR/CL/BI-06-C test
unit/test-gatt: Add /TP/GAR/CL/BI-07-C test
unit/test-gatt: Add /TP/GAR/CL/BI-09-C test
unit/test-gatt: Add /TP/GAR/CL/BI-10-C test
unit/test-gatt: Add /TP/GAR/CL/BI-11-C test
src/shared/gatt-helpers.c | 152 ++++++++++++++++++++++++++++++++++++++++++-
src/shared/gatt-helpers.h | 9 +++
unit/test-gatt.c | 160 ++++++++++++++++++++++++++++++++++++++++++++--
3 files changed, 316 insertions(+), 5 deletions(-)
--
1.9.3
Hi Marcin,
On Wed, Nov 19, 2014 at 1:26 PM, Marcin Kraglak
<[email protected]> wrote:
> It allows user to perform Read By Type requests with given UUID
>
> v2:
> Implementation moved to gatt-helpers instead of gatt-client
> after conversation with Arman and Luiz.
>
> Marcin Kraglak (9):
> shared/gatt-helpers: Add read-by-type functionality
> shared/gatt-helpers: Add iterator to read_by_type results
> unit/test-gatt: Add /TP/GAR/CL/BV-03-C-1 test
> unit/test-gatt: Add /TP/GAR/CL/BV-03-C-2 test
> unit/test-gatt: Add /TP/GAR/CL/BI-06-C test
> unit/test-gatt: Add /TP/GAR/CL/BI-07-C test
> unit/test-gatt: Add /TP/GAR/CL/BI-09-C test
> unit/test-gatt: Add /TP/GAR/CL/BI-10-C test
> unit/test-gatt: Add /TP/GAR/CL/BI-11-C test
>
> src/shared/gatt-helpers.c | 152 ++++++++++++++++++++++++++++++++++++++++++-
> src/shared/gatt-helpers.h | 9 +++
> unit/test-gatt.c | 160 ++++++++++++++++++++++++++++++++++++++++++++--
> 3 files changed, 316 insertions(+), 5 deletions(-)
>
> --
> 1.9.3
Applied, thanks.
--
Luiz Augusto von Dentz
Verify Generic Attribute Profile client behavior when the Read Using
Characteristic UUID procedure fails due to insufficient encryption
key size.
---
unit/test-gatt.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index 4265de1..9ded1f0 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -654,6 +654,12 @@ const struct test_step test_read_by_type_5 = {
.expected_att_ecode = 0x05,
};
+const struct test_step test_read_by_type_6 = {
+ .handle = 0x0001,
+ .end_handle = 0xffff,
+ .expected_att_ecode = 0x0c,
+};
+
static void read_by_type_cb(bool success, uint8_t att_ecode,
struct bt_gatt_result *result,
void *user_data)
@@ -880,5 +886,12 @@ int main(int argc, char *argv[])
raw_pdu(0x08, 0x01, 0x00, 0xff, 0xff, 0x0d, 0x2a),
raw_pdu(0x01, 0x08, 0x0b, 0x00, 0x05));
+ define_test_att("/TP/GAR/CL/BI-11-C", test_read_by_type, &uuid_char_16,
+ &test_read_by_type_6,
+ raw_pdu(0x02, 0x00, 0x02),
+ raw_pdu(0x03, 0x00, 0x02),
+ raw_pdu(0x08, 0x01, 0x00, 0xff, 0xff, 0x0d, 0x2a),
+ raw_pdu(0x01, 0x08, 0x0b, 0x00, 0x0c));
+
return g_test_run();
}
--
1.9.3
Verify that a Generic Attribute Profile client can read
a Characteristic Value selected by UUID using a 128-bit UUID.
---
unit/test-gatt.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index 72cfbf6..8d5f3b3 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -160,6 +160,12 @@ static bt_uuid_t uuid_128 = {
0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb}
};
+static bt_uuid_t uuid_char_128 = {
+ .type = BT_UUID128,
+ .value.u128.data = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}
+};
+
const bt_gatt_service_t service_1 = {
.primary = true,
.start_handle = 0x0001,
@@ -807,5 +813,20 @@ int main(int argc, char *argv[])
raw_pdu(0x08, 0x0b, 0x00, 0xff, 0xff, 0x0d, 0x2a),
raw_pdu(0x01, 0x08, 0x0b, 0x00, 0x0a));
+ define_test_att("/TP/GAR/CL/BV-03-C-2", test_read_by_type,
+ &uuid_char_128, &test_read_by_type_1,
+ raw_pdu(0x02, 0x00, 0x02),
+ raw_pdu(0x03, 0x00, 0x02),
+ raw_pdu(0x08, 0x01, 0x00, 0xff, 0xff, 0x0f, 0x0e, 0x0d,
+ 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
+ 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,
+ 0x00),
+ raw_pdu(0x09, 0x05, 0x0a, 0x00, 0x01, 0x02, 0x03),
+ raw_pdu(0x08, 0x0b, 0x00, 0xff, 0xff, 0x0f, 0x0e, 0x0d,
+ 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
+ 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,
+ 0x00),
+ raw_pdu(0x01, 0x08, 0x0b, 0x00, 0x0a));
+
return g_test_run();
}
--
1.9.3
Verify Generic Attribute Profile client behavior when the Read Using
Characteristic UUID procedure fails due to insufficient authorization.
---
unit/test-gatt.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index d68c2c7..adcadc5 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -642,6 +642,12 @@ const struct test_step test_read_by_type_3 = {
.expected_att_ecode = 0x0a,
};
+const struct test_step test_read_by_type_4 = {
+ .handle = 0x0001,
+ .end_handle = 0xffff,
+ .expected_att_ecode = 0x08,
+};
+
static void read_by_type_cb(bool success, uint8_t att_ecode,
struct bt_gatt_result *result,
void *user_data)
@@ -854,5 +860,12 @@ int main(int argc, char *argv[])
raw_pdu(0x08, 0x01, 0x00, 0xff, 0xff, 0x0d, 0x2a),
raw_pdu(0x01, 0x08, 0x0b, 0x00, 0x0a));
+ define_test_att("/TP/GAR/CL/BI-09-C", test_read_by_type, &uuid_char_16,
+ &test_read_by_type_4,
+ raw_pdu(0x02, 0x00, 0x02),
+ raw_pdu(0x03, 0x00, 0x02),
+ raw_pdu(0x08, 0x01, 0x00, 0xff, 0xff, 0x0d, 0x2a),
+ raw_pdu(0x01, 0x08, 0x0b, 0x00, 0x08));
+
return g_test_run();
}
--
1.9.3
Verify Generic Attribute Profile client behavior when the Read Using
Characteristic UUID procedure fails due to insufficient authentication
---
unit/test-gatt.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index adcadc5..4265de1 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -648,6 +648,12 @@ const struct test_step test_read_by_type_4 = {
.expected_att_ecode = 0x08,
};
+const struct test_step test_read_by_type_5 = {
+ .handle = 0x0001,
+ .end_handle = 0xffff,
+ .expected_att_ecode = 0x05,
+};
+
static void read_by_type_cb(bool success, uint8_t att_ecode,
struct bt_gatt_result *result,
void *user_data)
@@ -867,5 +873,12 @@ int main(int argc, char *argv[])
raw_pdu(0x08, 0x01, 0x00, 0xff, 0xff, 0x0d, 0x2a),
raw_pdu(0x01, 0x08, 0x0b, 0x00, 0x08));
+ define_test_att("/TP/GAR/CL/BI-10-C", test_read_by_type, &uuid_char_16,
+ &test_read_by_type_5,
+ raw_pdu(0x02, 0x00, 0x02),
+ raw_pdu(0x03, 0x00, 0x02),
+ raw_pdu(0x08, 0x01, 0x00, 0xff, 0xff, 0x0d, 0x2a),
+ raw_pdu(0x01, 0x08, 0x0b, 0x00, 0x05));
+
return g_test_run();
}
--
1.9.3
Verify Generic Attribute Profile client behavior when
the Read Using Characteristic UUID procedure fails due to
attribute not found.
---
unit/test-gatt.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index b90d7be..d68c2c7 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -636,6 +636,12 @@ const struct test_step test_read_by_type_2 = {
.expected_att_ecode = 0x02,
};
+const struct test_step test_read_by_type_3 = {
+ .handle = 0x0001,
+ .end_handle = 0xffff,
+ .expected_att_ecode = 0x0a,
+};
+
static void read_by_type_cb(bool success, uint8_t att_ecode,
struct bt_gatt_result *result,
void *user_data)
@@ -841,5 +847,12 @@ int main(int argc, char *argv[])
raw_pdu(0x08, 0x01, 0x00, 0xff, 0xff, 0x0d, 0x2a),
raw_pdu(0x01, 0x08, 0x0b, 0x00, 0x02));
+ define_test_att("/TP/GAR/CL/BI-07-C", test_read_by_type, &uuid_char_16,
+ &test_read_by_type_3,
+ raw_pdu(0x02, 0x00, 0x02),
+ raw_pdu(0x03, 0x00, 0x02),
+ raw_pdu(0x08, 0x01, 0x00, 0xff, 0xff, 0x0d, 0x2a),
+ raw_pdu(0x01, 0x08, 0x0b, 0x00, 0x0a));
+
return g_test_run();
}
--
1.9.3
Add iterator to get handle and value from read-by-type responses.
Also avoid using other iterator (characteristics and include services
iterators) with read-by-type results.
---
src/shared/gatt-helpers.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++-
src/shared/gatt-helpers.h | 3 +++
2 files changed, 49 insertions(+), 1 deletion(-)
diff --git a/src/shared/gatt-helpers.c b/src/shared/gatt-helpers.c
index 0c3fd34..d0bee3f 100644
--- a/src/shared/gatt-helpers.c
+++ b/src/shared/gatt-helpers.c
@@ -247,6 +247,7 @@ bool bt_gatt_iter_next_included_service(struct bt_gatt_iter *iter,
uint16_t *end_handle, uint8_t uuid[16])
{
struct bt_gatt_result *read_result;
+ struct discovery_op *op;
const void *pdu_ptr;
int i = 0;
@@ -254,9 +255,14 @@ bool bt_gatt_iter_next_included_service(struct bt_gatt_iter *iter,
|| !uuid)
return false;
+
if (iter->result->opcode != BT_ATT_OP_READ_BY_TYPE_RSP)
return false;
+ /* UUID in discovery_op is set in read_by_type and service_discovery */
+ op = iter->result->op;
+ if (op->uuid.type != BT_UUID_UNSPEC)
+ return false;
/*
* iter->result points to READ_BY_TYPE_RSP with data length containing:
* 2 octets - include service handle
@@ -372,6 +378,10 @@ bool bt_gatt_iter_next_characteristic(struct bt_gatt_iter *iter,
if (iter->result->opcode != BT_ATT_OP_READ_BY_TYPE_RSP)
return false;
+ /* UUID in discovery_op is set in read_by_type and service_discovery */
+ op = iter->result->op;
+ if (op->uuid.type != BT_UUID_UNSPEC)
+ return false;
/*
* Data length contains 7 or 21 octets:
* 2 octets: Attribute handle
@@ -382,7 +392,6 @@ bool bt_gatt_iter_next_characteristic(struct bt_gatt_iter *iter,
if (iter->result->data_len != 21 && iter->result->data_len != 7)
return false;
- op = iter->result->op;
pdu_ptr = iter->result->pdu + iter->pos;
*start_handle = get_le16(pdu_ptr);
@@ -431,6 +440,42 @@ bool bt_gatt_iter_next_descriptor(struct bt_gatt_iter *iter, uint16_t *handle,
return true;
}
+bool bt_gatt_iter_next_read_by_type(struct bt_gatt_iter *iter,
+ uint16_t *handle, uint16_t *length,
+ const uint8_t **value)
+{
+ struct discovery_op *op;
+ const void *pdu_ptr;
+
+ if (!iter || !iter->result || !handle || !length || !value)
+ return false;
+
+ if (iter->result->opcode != BT_ATT_OP_READ_BY_TYPE_RSP)
+ return false;
+
+ /*
+ * Check if UUID is set, otherwise results can contain characteristic
+ * discovery service or included service discovery results
+ */
+ op = iter->result->op;
+ if (op->uuid.type == BT_UUID_UNSPEC)
+ return false;
+
+ pdu_ptr = iter->result->pdu + iter->pos;
+
+ *handle = get_le16(pdu_ptr);
+ *length = iter->result->data_len - 2;
+ *value = pdu_ptr + 2;
+
+ iter->pos += iter->result->data_len;
+ if (iter->pos == iter->result->pdu_len) {
+ iter->result = iter->result->next;
+ iter->pos = 0;
+ }
+
+ return true;
+}
+
struct mtu_op {
struct bt_att *att;
uint16_t client_rx_mtu;
diff --git a/src/shared/gatt-helpers.h b/src/shared/gatt-helpers.h
index 2cc37c6..0217e82 100644
--- a/src/shared/gatt-helpers.h
+++ b/src/shared/gatt-helpers.h
@@ -53,6 +53,9 @@ bool bt_gatt_iter_next_descriptor(struct bt_gatt_iter *iter, uint16_t *handle,
bool bt_gatt_iter_next_included_service(struct bt_gatt_iter *iter,
uint16_t *handle, uint16_t *start_handle,
uint16_t *end_handle, uint8_t uuid[16]);
+bool bt_gatt_iter_next_read_by_type(struct bt_gatt_iter *iter,
+ uint16_t *handle, uint16_t *length,
+ const uint8_t **value);
typedef void (*bt_gatt_destroy_func_t)(void *user_data);
--
1.9.3
Verify Generic Attribute Profile client behavior when the Read
Using Characteristic UUID procedure fails due to read not permitted.
---
unit/test-gatt.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index 8d5f3b3..b90d7be 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -630,6 +630,12 @@ const struct test_step test_read_by_type_1 = {
.length = 0x03
};
+const struct test_step test_read_by_type_2 = {
+ .handle = 0x0001,
+ .end_handle = 0xffff,
+ .expected_att_ecode = 0x02,
+};
+
static void read_by_type_cb(bool success, uint8_t att_ecode,
struct bt_gatt_result *result,
void *user_data)
@@ -828,5 +834,12 @@ int main(int argc, char *argv[])
0x00),
raw_pdu(0x01, 0x08, 0x0b, 0x00, 0x0a));
+ define_test_att("/TP/GAR/CL/BI-06-C", test_read_by_type, &uuid_char_16,
+ &test_read_by_type_2,
+ raw_pdu(0x02, 0x00, 0x02),
+ raw_pdu(0x03, 0x00, 0x02),
+ raw_pdu(0x08, 0x01, 0x00, 0xff, 0xff, 0x0d, 0x2a),
+ raw_pdu(0x01, 0x08, 0x0b, 0x00, 0x02));
+
return g_test_run();
}
--
1.9.3
Verify that a Generic Attribute Profile client can read a
Characteristic Value selected by UUID using a 16-bit UUID.
---
unit/test-gatt.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 70 insertions(+), 4 deletions(-)
diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index 9917ec9..72cfbf6 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -108,8 +108,8 @@ struct context {
g_test_add_data_func(name, &data, function); \
} while (0)
-#define define_test_att(name, function, bt_uuid, args...) \
- define_test(name, function, ATT, bt_uuid, NULL, NULL, args)
+#define define_test_att(name, function, bt_uuid, test_step, args...) \
+ define_test(name, function, ATT, bt_uuid, NULL, test_step, args)
#define define_test_client(name, function, bt_services, test_step, args...)\
define_test(name, function, CLIENT, NULL, bt_services, test_step, args)
@@ -149,6 +149,11 @@ static bt_uuid_t uuid_16 = {
.value.u16 = 0x1800
};
+static bt_uuid_t uuid_char_16 = {
+ .type = BT_UUID16,
+ .value.u16 = 0x2a0d
+};
+
static bt_uuid_t uuid_128 = {
.type = BT_UUID128,
.value.u128.data = {0x00, 0x00, 0x18, 0x0d, 0x00, 0x00, 0x10, 0x00,
@@ -611,6 +616,54 @@ static void test_search_descs(gconstpointer data)
execute_context(context);
}
+const struct test_step test_read_by_type_1 = {
+ .handle = 0x0001,
+ .end_handle = 0xffff,
+ .expected_att_ecode = 0x0a,
+ .value = read_data_1,
+ .length = 0x03
+};
+
+static void read_by_type_cb(bool success, uint8_t att_ecode,
+ struct bt_gatt_result *result,
+ void *user_data)
+{
+ struct context *context = user_data;
+ const struct test_step *step = context->data->step;
+ struct bt_gatt_iter iter;
+
+ g_assert(att_ecode == step->expected_att_ecode);
+
+ if (success) {
+ uint16_t length, handle;
+ const uint8_t *value;
+
+ g_assert(bt_gatt_iter_init(&iter, result));
+ g_assert(bt_gatt_iter_next_read_by_type(&iter, &handle, &length,
+ &value));
+ g_assert(length == step->length);
+ g_assert(!memcmp(value, step->value, length));
+
+ g_assert(!bt_gatt_iter_next_read_by_type(&iter, &handle,
+ &length, &value));
+ }
+
+ context_quit(context);
+}
+
+static void test_read_by_type(gconstpointer data)
+{
+ struct context *context = create_context(512, data);
+ const struct test_data *test_data = data;
+ const struct test_step *step = context->data->step;
+
+ g_assert(bt_gatt_read_by_type(context->att, step->handle,
+ step->end_handle, test_data->uuid,
+ read_by_type_cb, context, NULL));
+
+ execute_context(context);
+}
+
int main(int argc, char *argv[])
{
g_test_init(&argc, &argv, NULL);
@@ -631,7 +684,7 @@ int main(int argc, char *argv[])
* The test group objective is to verify Generic Attribute Profile
* Discovery of Services and Service Characteristics.
*/
- define_test_att("/TP/GAD/CL/BV-01-C", test_search_primary, NULL,
+ define_test_att("/TP/GAD/CL/BV-01-C", test_search_primary, NULL, NULL,
raw_pdu(0x02, 0x00, 0x02),
raw_pdu(0x03, 0x00, 0x02),
raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
@@ -647,6 +700,7 @@ int main(int argc, char *argv[])
raw_pdu(0x01, 0x10, 0x97, 0x00, 0x0a));
define_test_att("/TP/GAD/CL/BV-02-C-1", test_search_primary, &uuid_16,
+ NULL,
raw_pdu(0x02, 0x00, 0x02),
raw_pdu(0x03, 0x00, 0x02),
raw_pdu(0x06, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28, 0x00,
@@ -657,6 +711,7 @@ int main(int argc, char *argv[])
raw_pdu(0x01, 0x06, 0x08, 0x00, 0x0a));
define_test_att("/TP/GAD/CL/BV-02-C-2", test_search_primary, &uuid_128,
+ NULL,
raw_pdu(0x02, 0x00, 0x02),
raw_pdu(0x03, 0x00, 0x02),
raw_pdu(06, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28, 0xfb,
@@ -671,6 +726,7 @@ int main(int argc, char *argv[])
raw_pdu(0x01, 0x06, 0x08, 0x00, 0x0a));
define_test_att("/TP/GAD/CL/BV-03-C", test_search_included, NULL,
+ NULL,
raw_pdu(0x02, 0x00, 0x02),
raw_pdu(0x03, 0x00, 0x02),
raw_pdu(0x08, 0x01, 0x00, 0xff, 0xff, 0x02, 0x28),
@@ -694,6 +750,7 @@ int main(int argc, char *argv[])
raw_pdu(0x01, 0x08, 0x06, 0x00, 0x0a));
define_test_att("/TP/GAD/CL/BV-04-C", test_search_chars, NULL,
+ NULL,
raw_pdu(0x02, 0x00, 0x02),
raw_pdu(0x03, 0x00, 0x02),
raw_pdu(0x08, 0x10, 0x00, 0x20, 0x00, 0x03, 0x28),
@@ -707,7 +764,7 @@ int main(int argc, char *argv[])
raw_pdu(0x08, 0x14, 0x00, 0x20, 0x00, 0x03, 0x28),
raw_pdu(0x01, 0x08, 0x12, 0x00, 0x0a));
- define_test_att("/TP/GAD/CL/BV-06-C", test_search_descs, NULL,
+ define_test_att("/TP/GAD/CL/BV-06-C", test_search_descs, NULL, NULL,
raw_pdu(0x02, 0x00, 0x02),
raw_pdu(0x03, 0x00, 0x02),
raw_pdu(0x04, 0x13, 0x00, 0x16, 0x00),
@@ -741,5 +798,14 @@ int main(int argc, char *argv[])
raw_pdu(0x0a, 0x03, 0x00),
raw_pdu(0x01, 0x0a, 0x03, 0x00, 0x08));
+ define_test_att("/TP/GAR/CL/BV-03-C-1", test_read_by_type,
+ &uuid_char_16, &test_read_by_type_1,
+ raw_pdu(0x02, 0x00, 0x02),
+ raw_pdu(0x03, 0x00, 0x02),
+ raw_pdu(0x08, 0x01, 0x00, 0xff, 0xff, 0x0d, 0x2a),
+ raw_pdu(0x09, 0x05, 0x0a, 0x00, 0x01, 0x02, 0x03),
+ raw_pdu(0x08, 0x0b, 0x00, 0xff, 0xff, 0x0d, 0x2a),
+ raw_pdu(0x01, 0x08, 0x0b, 0x00, 0x0a));
+
return g_test_run();
}
--
1.9.3
This is exposed to allow client reading characteristic values
with known uuid.
---
src/shared/gatt-helpers.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++
src/shared/gatt-helpers.h | 6 +++
2 files changed, 111 insertions(+)
diff --git a/src/shared/gatt-helpers.c b/src/shared/gatt-helpers.c
index 97e62fe..0c3fd34 100644
--- a/src/shared/gatt-helpers.c
+++ b/src/shared/gatt-helpers.c
@@ -1217,6 +1217,111 @@ bool bt_gatt_discover_characteristics(struct bt_att *att,
return true;
}
+static void read_by_type_cb(uint8_t opcode, const void *pdu,
+ uint16_t length, void *user_data)
+{
+ struct discovery_op *op = user_data;
+ bool success;
+ uint8_t att_ecode = 0;
+ size_t data_length;
+ uint16_t last_handle;
+
+ 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)
+ success = true;
+ else
+ success = false;
+
+ goto done;
+ }
+
+ if (opcode != BT_ATT_OP_READ_BY_TYPE_RSP || !pdu) {
+ success = false;
+ att_ecode = 0;
+ goto done;
+ }
+
+ data_length = ((uint8_t *) pdu)[0];
+ if (((length - 1) % data_length)) {
+ success = false;
+ att_ecode = 0;
+ goto done;
+ }
+
+ if (!result_append(opcode, pdu + 1, length - 1, data_length, op)) {
+ success = false;
+ att_ecode = 0;
+ goto done;
+ }
+
+ last_handle = get_le16(pdu + length - data_length);
+ if (last_handle != op->end_handle) {
+ uint8_t pdu[4 + get_uuid_len(&op->uuid)];
+
+ put_le16(last_handle + 1, pdu);
+ put_le16(op->end_handle, pdu + 2);
+ put_uuid_le(&op->uuid, pdu + 4);
+
+ if (bt_att_send(op->att, BT_ATT_OP_READ_BY_TYPE_REQ,
+ pdu, sizeof(pdu),
+ read_by_type_cb,
+ discovery_op_ref(op),
+ discovery_op_unref))
+ return;
+
+ discovery_op_unref(op);
+ success = false;
+ goto done;
+ }
+
+ success = true;
+
+done:
+ if (op->callback)
+ op->callback(success, att_ecode, success ? op->result_head :
+ NULL, op->user_data);
+}
+
+bool bt_gatt_read_by_type(struct bt_att *att, uint16_t start, uint16_t end,
+ const bt_uuid_t *uuid,
+ bt_gatt_discovery_callback_t callback,
+ void *user_data,
+ bt_gatt_destroy_func_t destroy)
+{
+ struct discovery_op *op;
+ uint8_t pdu[4 + get_uuid_len(uuid)];
+
+ if (!att || !uuid || uuid->type == BT_UUID_UNSPEC)
+ 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;
+ op->uuid = *uuid;
+
+ put_le16(start, pdu);
+ put_le16(end, pdu + 2);
+ put_uuid_le(uuid, pdu + 4);
+
+ if (!bt_att_send(att, BT_ATT_OP_READ_BY_TYPE_REQ, pdu, sizeof(pdu),
+ read_by_type_cb, discovery_op_ref(op),
+ discovery_op_unref)) {
+ free(op);
+ return false;
+ }
+
+ return true;
+}
+
static void discover_descs_cb(uint8_t opcode, const void *pdu,
uint16_t length, void *user_data)
{
diff --git a/src/shared/gatt-helpers.h b/src/shared/gatt-helpers.h
index 07c145d..2cc37c6 100644
--- a/src/shared/gatt-helpers.h
+++ b/src/shared/gatt-helpers.h
@@ -96,3 +96,9 @@ bool bt_gatt_discover_descriptors(struct bt_att *att,
bt_gatt_discovery_callback_t callback,
void *user_data,
bt_gatt_destroy_func_t destroy);
+
+bool bt_gatt_read_by_type(struct bt_att *att, uint16_t start, uint16_t end,
+ const bt_uuid_t *uuid,
+ bt_gatt_discovery_callback_t callback,
+ void *user_data,
+ bt_gatt_destroy_func_t destroy);
--
1.9.3