Adds a "large database" as defined by the test spec, and a set of
new tests from the test spec.
To support some tests, find_by_type_value is now supported.
gatt_db_find_by_type shares some code with gatt_db_find_by_type_value, and
callbacks are preferred to queues, so those functions and users have been
reworked to use callbacks instead.
v1 -> v2:
* Rebased to subsume already-commited patches
* Switch find_by_type and find_by_type_value to callbacks
Michael Janssen (12):
gatt_db: use callback for gatt_db_find_by_type
shared/gatt-db: Add gatt_db_find_by_type_value
shared/gatt-server: support Discover by UUID
unit/gatt: Add Test Spec Large Database 1
unit/gatt: Comment cleanup
unit/gatt: Add /TP/GAD/SR/BV-02-C test
unit/gatt: Add /TP/GAD/SR/BV-03-C test
unit/gatt: Add /TP/GAD/SR/BV-04-C test
unit/gatt: Add clarifying note about dup tests.
unit/gatt: Add /TP/GAD/SR/BV-06-C test
unit/gatt: Add /TP/GAR/SR/BV-01-C test
unit/gatt: Add /TP/GAR/SR/BI-02-C test
android/gatt.c | 85 ++++----
src/shared/gatt-client.c | 43 ++--
src/shared/gatt-db.c | 44 +++-
src/shared/gatt-db.h | 21 +-
src/shared/gatt-server.c | 103 +++++++++
unit/test-gatt.c | 529 ++++++++++++++++++++++++++++++++++++++++++++++-
6 files changed, 742 insertions(+), 83 deletions(-)
--
2.2.0.rc0.207.ga3a616c
Hi Michael,
On Mon, Jan 5, 2015 at 7:32 PM, Michael Janssen <[email protected]> wrote:
> Adds a "large database" as defined by the test spec, and a set of
> new tests from the test spec.
>
> To support some tests, find_by_type_value is now supported.
>
> gatt_db_find_by_type shares some code with gatt_db_find_by_type_value, and
> callbacks are preferred to queues, so those functions and users have been
> reworked to use callbacks instead.
>
> v1 -> v2:
> * Rebased to subsume already-commited patches
> * Switch find_by_type and find_by_type_value to callbacks
>
> Michael Janssen (12):
> gatt_db: use callback for gatt_db_find_by_type
> shared/gatt-db: Add gatt_db_find_by_type_value
> shared/gatt-server: support Discover by UUID
> unit/gatt: Add Test Spec Large Database 1
> unit/gatt: Comment cleanup
> unit/gatt: Add /TP/GAD/SR/BV-02-C test
> unit/gatt: Add /TP/GAD/SR/BV-03-C test
> unit/gatt: Add /TP/GAD/SR/BV-04-C test
> unit/gatt: Add clarifying note about dup tests.
> unit/gatt: Add /TP/GAD/SR/BV-06-C test
> unit/gatt: Add /TP/GAR/SR/BV-01-C test
> unit/gatt: Add /TP/GAR/SR/BI-02-C test
>
> android/gatt.c | 85 ++++----
> src/shared/gatt-client.c | 43 ++--
> src/shared/gatt-db.c | 44 +++-
> src/shared/gatt-db.h | 21 +-
> src/shared/gatt-server.c | 103 +++++++++
> unit/test-gatt.c | 529 ++++++++++++++++++++++++++++++++++++++++++++++-
> 6 files changed, 742 insertions(+), 83 deletions(-)
>
> --
> 2.2.0.rc0.207.ga3a616c
Ive applied this set expect for 09/12 since it was not clear which
tests were duplicate to what as you mentioned 4 but I could find only
one being implemented, also please make sure you run the tests with
valgrind, I got the following problem introduced in the very first
patch:
==16068== Conditional jump or move depends on uninitialised value(s)
==16068== at 0x41C618: init_complete (gatt-client.c:1166)
==16068== by 0x419C44: discover_descs_cb (gatt-client.c:628)
==16068== by 0x41658B: discover_descs_cb (gatt-helpers.c:1453)
==16068== by 0x415D2D: can_read_data (att.c:600)
==16068== by 0x421BDA: watch_callback (io-glib.c:170)
==16068== by 0x4E7A2A5: g_main_context_dispatch (in
/usr/lib64/libglib-2.0.so.0.3800.2)
==16068== by 0x4E7A627: ??? (in /usr/lib64/libglib-2.0.so.0.3800.2)
==16068== by 0x4E7AA39: g_main_loop_run (in
/usr/lib64/libglib-2.0.so.0.3800.2)
==16068== by 0x413990: test_client (test-gatt.c:601)
==16068== by 0x4E9E5E0: ??? (in /usr/lib64/libglib-2.0.so.0.3800.2)
==16068== by 0x4E9E7A5: ??? (in /usr/lib64/libglib-2.0.so.0.3800.2)
==16068== by 0x4E9E7A5: ??? (in /usr/lib64/libglib-2.0.so.0.3800.2)
==16068== Uninitialised value was created by a stack allocation
==16068== at 0x41C5A0: init_complete (gatt-client.c:1150)
--
Luiz Augusto von Dentz
Hi Michael,
> BV-05-C tests are identical to the BV-04-C tests, so add a note
> explaining as such.
> ---
> unit/test-gatt.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/unit/test-gatt.c b/unit/test-gatt.c
> index b8815ee..de3fe8b 100644
> --- a/unit/test-gatt.c
> +++ b/unit/test-gatt.c
> @@ -1680,6 +1680,11 @@ int main(int argc, char *argv[])
> raw_pdu(0x08, 0x29, 0x00, 0x29, 0x00, 0x03, 0x28),
> raw_pdu(0x01, 0x08, 0x29, 0x00, 0x0a));
>
> + /*
> + * Note: /TP/GAD/CL/BV-05-C and /TP/GAD/SV/BV-05-C are identical to
> + * /TP/GAD/CL/BV-04-C and /TP/GAD/SV/BV-04-C for BlueZ
> + */
> +
can we just add a copy of the test even while it is the same test. Makes it a lot easier to keep track of since you can list the test cases with -l option.
Regards
Marcel
BV-05-C tests are identical to the BV-04-C tests, so add a note
explaining as such.
---
unit/test-gatt.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index b8815ee..de3fe8b 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -1680,6 +1680,11 @@ int main(int argc, char *argv[])
raw_pdu(0x08, 0x29, 0x00, 0x29, 0x00, 0x03, 0x28),
raw_pdu(0x01, 0x08, 0x29, 0x00, 0x0a));
+ /*
+ * Note: /TP/GAD/CL/BV-05-C and /TP/GAD/SV/BV-05-C are identical to
+ * /TP/GAD/CL/BV-04-C and /TP/GAD/SV/BV-04-C for BlueZ
+ */
+
define_test_att("/TP/GAD/CL/BV-06-C", test_search_descs, NULL, NULL,
MTU_EXCHANGE_CLIENT_PDUS,
raw_pdu(0x04, 0x13, 0x00, 0x16, 0x00),
--
2.2.0.rc0.207.ga3a616c
---
unit/test-gatt.c | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index 9f67239..632609f 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -866,17 +866,16 @@ static struct gatt_db *make_service_data_1_db(void)
/*
* Defined Test database 1:
* Tiny database fits into a single minimum sized-pdu.
- * Satisfies:
- * 3. At least one primary seervice at the MAX handle
- * For each / all databases:
- * X 7. at least one service uuid with multiple instances
- * X 8. Some simple services, some with included services
- * X 9. an instance where handle of included service comes before the including
+ * Satisfies requirements:
+ * 3. At least one primary service at the MAX handle
+ * 7. at least one service uuid with multiple instances
+ * 8. Some simple services, some with included services
+ * 9. an instance where handle of included service comes before the including
* service
- * X 11. Simple characteristics (no desc) and complex characteristics
- * (multiple descriptors)
- * X 12. Instances of complex chars with 16-bit and 128-bit uuids
- * (although not in scrambled order)
+ * 11. Simple characteristics (no desc) and complex characteristics
+ * (multiple descriptors)
+ * 12. Instances of complex chars with 16-bit and 128-bit uuids
+ * (although not in scrambled order)
*/
static struct gatt_db *make_test_spec_small_db(void)
--
2.2.0.rc0.207.ga3a616c
Verify that a Generic Attribute Profile server can detect and reject a
Read Characteristic Value Request with an unsupported Characteristic
Value handle and issue an Invalid Handle Response.
---
unit/test-gatt.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index 582cee9..684c1c8 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -1754,6 +1754,18 @@ int main(int argc, char *argv[])
'4', '4', '5', '5', '5', '5', '5', '6', '6',
'6', '6', '6', '7', '7'));
+ define_test_server("/TP/GAR/SR/BI-02-C/small", test_server,
+ ts_small_db, NULL,
+ raw_pdu(0x03, 0x00, 0x02),
+ raw_pdu(0x0a, 0x00, 0x00),
+ raw_pdu(0x01, 0x0a, 0x00, 0x00, 0x01));
+
+ define_test_server("/TP/GAR/SR/BI-02-C/large", test_server,
+ ts_large_db_1, NULL,
+ raw_pdu(0x03, 0x00, 0x02),
+ raw_pdu(0x0a, 0x0f, 0xf0),
+ raw_pdu(0x01, 0x0a, 0x0f, 0xf0, 0x01));
+
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),
--
2.2.0.rc0.207.ga3a616c
It is preferred to not expose queue, so switch the function to a
callback style instead, and update the uses of it, eliminating a set of
queue uses.
---
android/gatt.c | 85 ++++++++++++++++++++++++++++--------------------
src/shared/gatt-client.c | 43 +++++++++++-------------
src/shared/gatt-db.c | 15 +++++----
src/shared/gatt-db.h | 13 ++++----
4 files changed, 84 insertions(+), 72 deletions(-)
diff --git a/android/gatt.c b/android/gatt.c
index 3a35bd6..b749705 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -6243,15 +6243,53 @@ static uint8_t find_info_handle(const uint8_t *cmd, uint16_t cmd_len,
return ret;
}
+struct find_by_type_request_data {
+ struct gatt_device *device;
+ uint8_t *search_value;
+ size_t search_vlen;
+ uint8_t error;
+};
+
+static void find_by_type_request_cb(struct gatt_db_attribute *attrib,
+ void *user_data)
+{
+ struct find_by_type_request_data *find_data = user_data;
+ struct pending_request *request_data;
+
+ if (find_data->error)
+ return;
+
+ request_data = new0(struct pending_request, 1);
+ if (!request_data) {
+ find_data->error = ATT_ECODE_INSUFF_RESOURCES;
+ return;
+ }
+
+ request_data->filter_value = malloc0(find_data->search_vlen);
+ if (!request_data->filter_value) {
+ destroy_pending_request(request_data);
+ find_data->error = ATT_ECODE_INSUFF_RESOURCES;
+ return;
+ }
+
+ request_data->state = REQUEST_INIT;
+ request_data->attrib = attrib;
+ request_data->filter_vlen = find_data->search_vlen;
+ memcpy(request_data->filter_value, find_data->search_value,
+ find_data->search_vlen);
+
+ queue_push_tail(find_data->device->pending_requests, request_data);
+}
+
static uint8_t find_by_type_request(const uint8_t *cmd, uint16_t cmd_len,
struct gatt_device *device)
{
uint8_t search_value[cmd_len];
size_t search_vlen;
uint16_t start, end;
- struct queue *q;
bt_uuid_t uuid;
uint16_t len;
+ struct find_by_type_request_data data;
DBG("");
@@ -6263,53 +6301,28 @@ static uint8_t find_by_type_request(const uint8_t *cmd, uint16_t cmd_len,
if (start > end || start == 0)
return ATT_ECODE_INVALID_HANDLE;
- q = queue_new();
- if (!q)
- return ATT_ECODE_UNLIKELY;
+ data.error = 0;
+ data.search_vlen = search_vlen;
+ data.search_value = search_value;
+ data.device = device;
- gatt_db_find_by_type(gatt_db, start, end, &uuid, q);
+ gatt_db_find_by_type(gatt_db, start, end, &uuid,
+ find_by_type_request_cb, &data);
- if (queue_isempty(q)) {
+ if (data.error == ATT_ECODE_ATTR_NOT_FOUND) {
size_t mtu;
uint8_t *rsp = g_attrib_get_buffer(device->attrib, &mtu);
len = enc_error_resp(ATT_OP_FIND_BY_TYPE_REQ, start,
ATT_ECODE_ATTR_NOT_FOUND, rsp, mtu);
g_attrib_send(device->attrib, 0, rsp, len, NULL, NULL, NULL);
- queue_destroy(q, NULL);
return 0;
}
- while (queue_peek_head(q)) {
- struct gatt_db_attribute *attrib = queue_pop_head(q);
- struct pending_request *data;
-
- data = new0(struct pending_request, 1);
- if (!data) {
- queue_destroy(q, NULL);
- return ATT_ECODE_INSUFF_RESOURCES;
- }
+ if (!data.error)
+ process_dev_pending_requests(device, ATT_OP_FIND_BY_TYPE_REQ);
- data->filter_value = malloc0(search_vlen);
- if (!data->filter_value) {
- destroy_pending_request(data);
- queue_destroy(q, NULL);
- return ATT_ECODE_INSUFF_RESOURCES;
- }
-
- data->state = REQUEST_INIT;
- data->attrib = attrib;
- data->filter_vlen = search_vlen;
- memcpy(data->filter_value, search_value, search_vlen);
-
- queue_push_tail(device->pending_requests, data);
- }
-
- queue_destroy(q, NULL);
-
- process_dev_pending_requests(device, ATT_OP_FIND_BY_TYPE_REQ);
-
- return 0;
+ return data.error;
}
static void write_confirm(struct gatt_db_attribute *attrib,
diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index 6768892..e9fb852 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
@@ -973,6 +973,17 @@ static void process_service_changed(struct bt_gatt_client *client,
static void service_changed_cb(uint16_t value_handle, const uint8_t *value,
uint16_t length, void *user_data);
+static void get_first_attribute(struct gatt_db_attribute *attrib,
+ void *user_data)
+{
+ struct gatt_db_attribute **stored = user_data;
+
+ if (*stored)
+ return;
+
+ *stored = attrib;
+}
+
static void service_changed_complete(struct discovery_op *op, bool success,
uint8_t att_ecode)
{
@@ -982,7 +993,6 @@ static void service_changed_complete(struct discovery_op *op, bool success,
uint16_t end_handle = op->end;
struct gatt_db_attribute *attr;
bt_uuid_t uuid;
- struct queue *q;
client->in_svc_chngd = false;
@@ -1008,21 +1018,13 @@ static void service_changed_complete(struct discovery_op *op, bool success,
return;
}
- /* Check if the GATT service was among the changed services */
- q = queue_new();
- if (!q)
- return;
-
bt_uuid16_create(&uuid, SVC_CHNGD_UUID);
- gatt_db_find_by_type(client->db, start_handle, end_handle, &uuid, q);
- if (queue_isempty(q)) {
- queue_destroy(q, NULL);
- return;
- }
+ gatt_db_find_by_type(client->db, start_handle, end_handle, &uuid,
+ get_first_attribute, &attr);
- attr = queue_pop_head(q);
- queue_destroy(q, NULL);
+ if (!attr)
+ return;
/* The GATT service was modified. Re-register the handler for
* indications from the "Service Changed" characteristic.
@@ -1150,29 +1152,22 @@ static void init_complete(struct discovery_op *op, bool success,
bool registered;
struct gatt_db_attribute *attr;
bt_uuid_t uuid;
- struct queue *q;
client->in_init = false;
if (!success)
goto fail;
- q = queue_new();
- if (!q)
- goto fail;
-
bt_uuid16_create(&uuid, SVC_CHNGD_UUID);
- gatt_db_find_by_type(client->db, 0x0001, 0xffff, &uuid, q);
- if (queue_isempty(q)) {
- queue_destroy(q, NULL);
+ gatt_db_find_by_type(client->db, 0x0001, 0xffff, &uuid,
+ get_first_attribute, &attr);
+
+ if (!attr) {
client->ready = true;
goto done;
}
- attr = queue_pop_head(q);
- queue_destroy(q, NULL);
-
/* Register an indication handler for the "Service Changed"
* characteristic and report ready only if the handler is registered
* successfully. Temporarily set "ready" to true so that we can register
diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
index d2cdacc..f519bcb 100644
--- a/src/shared/gatt-db.c
+++ b/src/shared/gatt-db.c
@@ -826,10 +826,11 @@ next_service:
}
struct find_by_type_value_data {
- struct queue *queue;
bt_uuid_t uuid;
uint16_t start_handle;
uint16_t end_handle;
+ gatt_db_attribute_cb_t func;
+ void *user_data;
};
static void find_by_type(void *data, void *user_data)
@@ -855,21 +856,23 @@ static void find_by_type(void *data, void *user_data)
if (bt_uuid_cmp(&search_data->uuid, &attribute->uuid))
continue;
- queue_push_tail(search_data->queue, attribute);
+ search_data->func(attribute, search_data->user_data);
}
}
void gatt_db_find_by_type(struct gatt_db *db, uint16_t start_handle,
- uint16_t end_handle,
- const bt_uuid_t *type,
- struct queue *queue)
+ uint16_t end_handle,
+ const bt_uuid_t *type,
+ gatt_db_attribute_cb_t func,
+ void *user_data)
{
struct find_by_type_value_data data;
data.uuid = *type;
data.start_handle = start_handle;
data.end_handle = end_handle;
- data.queue = queue;
+ data.func = func;
+ data.user_data = user_data;
queue_foreach(db->services, find_by_type, &data);
}
diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
index f188944..9fc1b11 100644
--- a/src/shared/gatt-db.h
+++ b/src/shared/gatt-db.h
@@ -83,15 +83,19 @@ gatt_db_service_add_included(struct gatt_db_attribute *attrib,
bool gatt_db_service_set_active(struct gatt_db_attribute *attrib, bool active);
bool gatt_db_service_get_active(struct gatt_db_attribute *attrib);
+typedef void (*gatt_db_attribute_cb_t)(struct gatt_db_attribute *attrib,
+ void *user_data);
+
void gatt_db_read_by_group_type(struct gatt_db *db, uint16_t start_handle,
uint16_t end_handle,
const bt_uuid_t type,
struct queue *queue);
void gatt_db_find_by_type(struct gatt_db *db, uint16_t start_handle,
- uint16_t end_handle,
- const bt_uuid_t *type,
- struct queue *queue);
+ uint16_t end_handle,
+ const bt_uuid_t *type,
+ gatt_db_attribute_cb_t func,
+ void *user_data);
void gatt_db_read_by_type(struct gatt_db *db, uint16_t start_handle,
uint16_t end_handle,
@@ -103,9 +107,6 @@ void gatt_db_find_information(struct gatt_db *db, uint16_t start_handle,
struct queue *queue);
-typedef void (*gatt_db_attribute_cb_t)(struct gatt_db_attribute *attrib,
- void *user_data);
-
void gatt_db_foreach_service(struct gatt_db *db, const bt_uuid_t *uuid,
gatt_db_attribute_cb_t func,
void *user_data);
--
2.2.0.rc0.207.ga3a616c
Verify that a Generic Attribute Profile server can support reading a
Characteristic Value selected by handle.
---
unit/test-gatt.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index 44a10e8..582cee9 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -1736,6 +1736,24 @@ int main(int argc, char *argv[])
raw_pdu(0x0a, 0x03, 0x00),
raw_pdu(0x01, 0x0a, 0x03, 0x00, 0x08));
+ define_test_server("/TP/GAR/SR/BV-01-C/small", test_server,
+ ts_small_db, NULL,
+ raw_pdu(0x03, 0x00, 0x02),
+ raw_pdu(0x0a, 0x03, 0x00),
+ raw_pdu(0x0b, 0x42, 0x6c, 0x75, 0x65, 0x5a));
+
+ define_test_server("/TP/GAR/SR/BV-01-C/large-1", test_server,
+ ts_large_db_1, NULL,
+ raw_pdu(0x03, 0x00, 0x02),
+ raw_pdu(0x0a, 0xc4, 0x00),
+ raw_pdu(0x0b, '1', '1', '1', '1', '1', '2', '2', '2',
+ '2', '2', '3', '3', '3', '3', '3', '4', '4',
+ '4', '4', '4', '5'),
+ raw_pdu(0x0a, 0xca, 0x00),
+ raw_pdu(0x0b, '3', '3', '3', '3', '3', '4', '4', '4',
+ '4', '4', '5', '5', '5', '5', '5', '6', '6',
+ '6', '6', '6', '7', '7'));
+
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),
--
2.2.0.rc0.207.ga3a616c
Verify that a Generic Attribute Profile server can support discovery of
all particular Primary Services selected by service UUID, using 16-bit
UUIDs, and using 128-bit UUIDs where supported.
128-bit tests will be added once the larger databases with 128-bit UUIDs
are added.
---
unit/test-gatt.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 57 insertions(+)
diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index 632609f..12e84da 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -1525,6 +1525,63 @@ int main(int argc, char *argv[])
0x18, 0x00, 0x00),
raw_pdu(0x01, 0x06, 0x18, 0x00, 0x0a));
+ define_test_server("/TP/GAD/SR/BV-02-C/exists-16/small", test_server,
+ ts_small_db, NULL,
+ raw_pdu(0x03, 0x00, 0x02),
+ raw_pdu(0x06, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28, 0x00,
+ 0x18),
+ raw_pdu(0x07, 0x10, 0xf0, 0x17, 0xf0),
+ raw_pdu(0x06, 0x18, 0xf0, 0xff, 0xff, 0x00, 0x28, 0x00,
+ 0x18),
+ raw_pdu(0x01, 0x06, 0x18, 0xf0, 0x0a));
+
+ define_test_server("/TP/GAD/SR/BV-02-C/exists-16/large-1", test_server,
+ ts_large_db_1, NULL,
+ raw_pdu(0x03, 0x00, 0x02),
+ raw_pdu(0x06, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28, 0x0b,
+ 0xa0),
+ raw_pdu(0x07, 0x30, 0x00, 0x32, 0x00, 0x50, 0x00, 0x52,
+ 0x00, 0x60, 0x00, 0x6b, 0x00, 0x70, 0x00, 0x76,
+ 0x00, 0x80, 0x00, 0x85, 0x00),
+ raw_pdu(0x06, 0x86, 0x00, 0xff, 0xff, 0x00, 0x28, 0x0b,
+ 0xa0),
+ raw_pdu(0x01, 0x06, 0x86, 0x00, 0x0a));
+
+ define_test_server("/TP/GAD/SR/BV-02-C/missing-16/small", test_server,
+ ts_small_db, NULL,
+ raw_pdu(0x03, 0x00, 0x02),
+ raw_pdu(0x06, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28, 0x01,
+ 0x18),
+ raw_pdu(0x01, 0x06, 0x01, 0x00, 0x0a));
+
+ define_test_server("/TP/GAD/SR/BV-02-C/missing-16/large-1", test_server,
+ ts_large_db_1, NULL,
+ raw_pdu(0x03, 0x00, 0x02),
+ raw_pdu(0x06, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28, 0x0f,
+ 0xf0),
+ raw_pdu(0x01, 0x06, 0x01, 0x00, 0x0a));
+
+ define_test_server("/TP/GAD/SR/BV-02-C/exists-128/large-1", test_server,
+ ts_large_db_1, NULL,
+ raw_pdu(0x03, 0x00, 0x02),
+ raw_pdu(0x06, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28, 0xef,
+ 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x0c, 0xa0, 0x00, 0x00),
+ raw_pdu(0x07, 0x90, 0x00, 0x96, 0x00, 0xc0, 0x00, 0xdd,
+ 0x00),
+ raw_pdu(0x06, 0xde, 0x00, 0xff, 0xff, 0x00, 0x28, 0xef,
+ 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x0c, 0xa0, 0x00, 0x00),
+ raw_pdu(0x01, 0x06, 0xde, 0x00, 0x0a));
+
+ define_test_server("/TP/GAD/SR/BV-02-C/missing-128/large-1",
+ test_server, ts_large_db_1, NULL,
+ raw_pdu(0x03, 0x00, 0x02),
+ raw_pdu(0x06, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28, 0xff,
+ 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x0c, 0xa0, 0x00, 0x00),
+ raw_pdu(0x01, 0x06, 0x01, 0x00, 0x0a));
+
define_test_att("/TP/GAD/CL/BV-03-C", test_search_included, NULL,
NULL,
MTU_EXCHANGE_CLIENT_PDUS,
--
2.2.0.rc0.207.ga3a616c
Adds a large GATT database definition and initial service discovery test
which satisfies a number of the requirements from the GATT Test Spec
Document.
---
unit/test-gatt.c | 339 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 338 insertions(+), 1 deletion(-)
diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index 169fbd3..9f67239 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -152,6 +152,31 @@ struct context {
raw_pdu(0x11, 0x06, 0x10, 0xF0, 0x17, 0xF0, 0x00, 0x18, \
0xFF, 0xFF, 0xFF, 0xFF, 0x0a, 0x18)
+#define PRIMARY_DISC_LARGE_DB_1 \
+ raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28), \
+ raw_pdu(0x11, 0x06, 0x10, 0x00, 0x13, 0x00, 0x01, 0x18, \
+ 0x20, 0x00, 0x29, 0x00, 0x0A, 0xA0, \
+ 0x30, 0x00, 0x32, 0x00, 0x0B, 0xA0), \
+ raw_pdu(0x10, 0x33, 0x00, 0xff, 0xff, 0x00, 0x28), \
+ raw_pdu(0x11, 0x06, 0x40, 0x00, 0x46, 0x00, 0x00, 0x18, \
+ 0x50, 0x00, 0x52, 0x00, 0x0B, 0xA0, \
+ 0x60, 0x00, 0x6B, 0x00, 0x0B, 0xA0), \
+ raw_pdu(0x10, 0x6C, 0x00, 0xff, 0xff, 0x00, 0x28), \
+ raw_pdu(0x11, 0x06, 0x70, 0x00, 0x76, 0x00, 0x0B, 0xA0, \
+ 0x80, 0x00, 0x85, 0x00, 0x0B, 0xA0), \
+ raw_pdu(0x10, 0x86, 0x00, 0xff, 0xff, 0x00, 0x28), \
+ raw_pdu(0x11, 0x14, 0x90, 0x00, 0x96, 0x00, \
+ 0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01, \
+ 0x00, 0x00, 0x00, 0x00, 0x0C, 0xA0, 0x00, 0x00),\
+ raw_pdu(0x10, 0x97, 0x00, 0xff, 0xff, 0x00, 0x28), \
+ raw_pdu(0x11, 0x06, 0xa0, 0x00, 0xb1, 0x00, 0x0f, 0xa0),\
+ raw_pdu(0x10, 0xb2, 0x00, 0xff, 0xff, 0x00, 0x28), \
+ raw_pdu(0x11, 0x14, 0xC0, 0x00, 0xDD, 0x00, \
+ 0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01, \
+ 0x00, 0x00, 0x00, 0x00, 0x0C, 0xA0, 0x00, 0x00),\
+ raw_pdu(0x10, 0xde, 0x00, 0xff, 0xff, 0x00, 0x28), \
+ raw_pdu(0x01, 0x10, 0xde, 0x00, 0x0a)
+
#define SECONDARY_DISC_SMALL_DB \
raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x01, 0x28), \
raw_pdu(0x11, 0x06, 0x01, 0x00, 0x0F, 0x00, 0x0a, 0x18),\
@@ -883,6 +908,312 @@ static struct gatt_db *make_test_spec_small_db(void)
return make_db(specs);
}
+/*
+ * Defined Test database 2:
+ * Large Database with 128-bit services at the end
+ * Satisfies requirements:
+ * 4. at least one primary service without any include or characteristic
+ * at the max handle.
+ * 6. at least one secondary service
+ * 7. at least one each of 16-bit and 128-bit UUID with multiple instances
+ * 8. some simple services, some some with included services
+ * 9. one instance where an included service comes before the including
+ * 10. one or more services with both 16-bit and 128-bit service UUIDs
+ * 11. simple and complex characteristics
+ * 12. complex chars with 16-bit and 128-bit uuids
+ */
+
+#define STRING_512BYTES "11111222223333344444555556666677777888889999900000" \
+ "11111222223333344444555556666677777888889999900000" \
+ "11111222223333344444555556666677777888889999900000" \
+ "11111222223333344444555556666677777888889999900000" \
+ "11111222223333344444555556666677777888889999900000" \
+ "11111222223333344444555556666677777888889999900000" \
+ "11111222223333344444555556666677777888889999900000" \
+ "11111222223333344444555556666677777888889999900000" \
+ "11111222223333344444555556666677777888889999900000" \
+ "11111222223333344444555556666677777888889999900000" \
+ "111112222233"
+
+static struct gatt_db *make_test_spec_large_db_1(void)
+{
+ const struct att_handle_spec specs[] = {
+ PRIMARY_SERVICE(0x0080, "a00b", 6),
+ CHARACTERISTIC(0xb008, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ BT_GATT_CHRC_PROP_READ |
+ BT_GATT_CHRC_PROP_WRITE,
+ 0x08),
+ DESCRIPTOR(0xb015, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE, 0x01),
+ DESCRIPTOR(0xb016, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE, 0x02),
+ DESCRIPTOR(0xb017, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE |
+ BT_ATT_PERM_ENCRYPT, 0x03),
+
+ SECONDARY_SERVICE(0x0001, "a00d", 6),
+ INCLUDE(0x0080),
+ CHARACTERISTIC(0xb00c, BT_ATT_PERM_READ, BT_GATT_CHRC_PROP_READ,
+ 0x0C),
+ CHARACTERISTIC(0000b00b-0000-0000-0123-456789abcdef,
+ BT_ATT_PERM_READ, BT_GATT_CHRC_PROP_READ, 0x0B),
+
+ PRIMARY_SERVICE(0x0010, GATT_UUID, 4),
+ CHARACTERISTIC(GATT_CHARAC_SERVICE_CHANGED, BT_ATT_PERM_READ,
+ BT_GATT_CHRC_PROP_INDICATE,
+ 0x01, 0x00, 0xFF, 0xFF),
+ DESCRIPTOR(GATT_CLIENT_CHARAC_CFG_UUID,
+ BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ 0x00, 0x00),
+
+ PRIMARY_SERVICE(0x0020, "a00a", 10),
+ INCLUDE(0x0001),
+ CHARACTERISTIC(0xb001, BT_ATT_PERM_READ, BT_GATT_CHRC_PROP_READ,
+ 0x01),
+ CHARACTERISTIC_STR(0xb002, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ BT_GATT_CHRC_PROP_READ |
+ BT_GATT_CHRC_PROP_WRITE,
+ STRING_512BYTES),
+ CHARACTERISTIC_STR(0xb002, BT_ATT_PERM_WRITE,
+ BT_GATT_CHRC_PROP_WRITE,
+ "1111122222333334444455555"
+ "6666677777888889999900000"),
+ CHARACTERISTIC(0xb003, BT_ATT_PERM_WRITE,
+ BT_GATT_CHRC_PROP_WRITE, 0x03),
+
+ PRIMARY_SERVICE(0x0030, "a00b", 3),
+ CHARACTERISTIC(0xb007, BT_ATT_PERM_WRITE,
+ BT_GATT_CHRC_PROP_WRITE, 0x07),
+
+ PRIMARY_SERVICE(0x0040, GAP_UUID, 7),
+ CHARACTERISTIC_STR(GATT_CHARAC_DEVICE_NAME, BT_ATT_PERM_READ,
+ BT_GATT_CHRC_PROP_READ,
+ "Test Database"),
+ CHARACTERISTIC(GATT_CHARAC_APPEARANCE, BT_ATT_PERM_READ,
+ BT_GATT_CHRC_PROP_READ, 17),
+ CHARACTERISTIC(GATT_CHARAC_PERIPHERAL_PREF_CONN,
+ BT_ATT_PERM_READ, BT_GATT_CHRC_PROP_READ,
+ 0x64, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x07, 0xD0),
+
+ PRIMARY_SERVICE(0x0050, "a00b", 3),
+ CHARACTERISTIC(0xb006, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ BT_GATT_CHRC_PROP_READ |
+ BT_GATT_CHRC_PROP_WRITE |
+ BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP |
+ BT_GATT_CHRC_PROP_NOTIFY |
+ BT_GATT_CHRC_PROP_INDICATE, 0x06),
+
+ PRIMARY_SERVICE(0x0060, "a00b", 12),
+ CHARACTERISTIC(0xb004, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ BT_GATT_CHRC_PROP_READ | BT_GATT_CHRC_PROP_WRITE, 0x04),
+ CHARACTERISTIC(0xb004, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ BT_GATT_CHRC_PROP_READ | BT_GATT_CHRC_PROP_WRITE, 0x04),
+ DESCRIPTOR(GATT_SERVER_CHARAC_CFG_UUID,
+ BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ 0x00, 0x00),
+ CHARACTERISTIC(0xb004, 0, 0, 0x04),
+ DESCRIPTOR(0xb012, 0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
+ 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22, 0x33,
+ 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11,
+ 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99,
+ 0x00, 0x11, 0x22, 0x33),
+ CHARACTERISTIC(0xb004, BT_ATT_PERM_READ, BT_GATT_CHRC_PROP_READ,
+ 0x04),
+ DESCRIPTOR(0xb012, BT_ATT_PERM_READ, 0x11, 0x22, 0x33, 0x44,
+ 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22,
+ 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00,
+ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+ 0x99, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
+ 0x77, 0x88, 0x99, 0x00, 0x11, 0x22, 0x33),
+
+ PRIMARY_SERVICE(0x0070, "a00b", 7),
+ CHARACTERISTIC(0xb005, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ BT_GATT_CHRC_PROP_READ |
+ BT_GATT_CHRC_PROP_WRITE |
+ BT_GATT_CHRC_PROP_EXT_PROP,
+ 0x05),
+ DESCRIPTOR(GATT_CHARAC_EXT_PROPER_UUID, BT_ATT_PERM_READ, 0x03,
+ 0x00),
+ DESCRIPTOR_STR(GATT_CHARAC_USER_DESC_UUID,
+ BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"),
+ DESCRIPTOR(GATT_CHARAC_FMT_UUID, 0x04, 0x00, 0x01, 0x30, 0x01,
+ 0x11, 0x31),
+ DESCRIPTOR(0000d5d4-0000-0000-0123-456789abcdef,
+ BT_ATT_PERM_READ, 0x44),
+
+ /* 0x0080 service defined earlier, included in 0x0001 */
+
+ PRIMARY_SERVICE(0x0090, "0000a00c-0000-0000-0123-456789abcdef",
+ 7),
+ INCLUDE(0x0001),
+ CHARACTERISTIC(0000b009-0000-0000-0123-456789abcdef,
+ BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ BT_GATT_CHRC_PROP_READ |
+ BT_GATT_CHRC_PROP_WRITE |
+ BT_GATT_CHRC_PROP_EXT_PROP, 0x09),
+ DESCRIPTOR(GATT_CHARAC_EXT_PROPER_UUID, BT_ATT_PERM_READ, 0x01,
+ 0x00),
+ DESCRIPTOR(0000d9d2-0000-0000-0123-456789abcdef,
+ BT_ATT_PERM_READ | BT_ATT_PERM_WRITE, 0x22),
+ DESCRIPTOR(0000d9d3-0000-0000-0123-456789abcdef,
+ BT_ATT_PERM_WRITE, 0x33),
+
+ PRIMARY_SERVICE(0x00a0, "a00f", 18),
+ CHARACTERISTIC_STR(0xb00e, BT_ATT_PERM_READ,
+ BT_GATT_CHRC_PROP_READ, "Length is "),
+ DESCRIPTOR(GATT_CHARAC_FMT_UUID, BT_ATT_PERM_READ, 0x19, 0x00,
+ 0x00, 0x30, 0x01, 0x00, 0x00),
+ CHARACTERISTIC(0xb00f, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ BT_GATT_CHRC_PROP_READ |
+ BT_GATT_CHRC_PROP_WRITE, 0x65),
+ DESCRIPTOR(GATT_CHARAC_FMT_UUID, BT_ATT_PERM_READ, 0x04, 0x00,
+ 0x01, 0x27, 0x01, 0x01, 0x00),
+ CHARACTERISTIC(0xb006, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ BT_GATT_CHRC_PROP_READ |
+ BT_GATT_CHRC_PROP_WRITE,
+ 0x34, 0x12),
+ DESCRIPTOR(GATT_CHARAC_FMT_UUID, BT_ATT_PERM_READ, 0x06, 0x00,
+ 0x10, 0x27, 0x01, 0x02, 0x00),
+ CHARACTERISTIC(0xb007, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ BT_GATT_CHRC_PROP_READ |
+ BT_GATT_CHRC_PROP_WRITE,
+ 0x04, 0x03, 0x02, 0x01),
+ DESCRIPTOR(GATT_CHARAC_FMT_UUID, BT_ATT_PERM_READ, 0x08, 0x00,
+ 0x17, 0x27, 0x01, 0x03, 0x00),
+ CHARACTERISTIC(0xb010, BT_ATT_PERM_READ, BT_GATT_CHRC_PROP_READ,
+ 0x65, 0x34, 0x12, 0x04, 0x03, 0x02,
+ 0x01),
+ DESCRIPTOR(GATT_CHARAC_AGREG_FMT_UUID, BT_ATT_PERM_READ, 0xA6,
+ 0x00, 0xa9, 0x00, 0xac, 0x00),
+ CHARACTERISTIC(0xb011, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ BT_GATT_CHRC_PROP_READ |
+ BT_GATT_CHRC_PROP_AUTH, 0x012),
+
+ PRIMARY_SERVICE(0x00C0, "0000a00c-0000-0000-0123-456789abcdef",
+ 30),
+ CHARACTERISTIC(0xb00a, BT_ATT_PERM_READ, BT_GATT_CHRC_PROP_READ,
+ 0x0A),
+ CHARACTERISTIC_STR(0xb002, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ BT_GATT_CHRC_PROP_READ |
+ BT_GATT_CHRC_PROP_WRITE,
+ "111112222233333444445"),
+ DESCRIPTOR(0xb012, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+ 0x99, 0x00, 0x12, 0x34, 0x56, 0x78, 0x90, 0x11),
+ CHARACTERISTIC_STR(0xb002, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ BT_GATT_CHRC_PROP_READ |
+ BT_GATT_CHRC_PROP_WRITE,
+ "2222233333444445555566"),
+ DESCRIPTOR(0xb013, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+ 0x99, 0x00, 0x12, 0x34, 0x56, 0x78, 0x90, 0x11,
+ 0x22),
+ CHARACTERISTIC_STR(0xb002, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ BT_GATT_CHRC_PROP_READ |
+ BT_GATT_CHRC_PROP_WRITE,
+ "33333444445555566666777"),
+ DESCRIPTOR(0xb014, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+ 0x99, 0x00, 0x12, 0x34, 0x56, 0x78, 0x90, 0x11,
+ 0x22, 0x33),
+ CHARACTERISTIC(0xb002, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ BT_GATT_CHRC_PROP_READ |
+ BT_GATT_CHRC_PROP_WRITE,
+ 0x11, 0x22, 0x33, 0x44, 0x55,
+ 0x66, 0x77, 0x88, 0x99, 0x00,
+ 0x11, 0x22, 0x33, 0x44, 0x55,
+ 0x66, 0x77, 0x88, 0x99, 0x00,
+ 0x11, 0x22, 0x33, 0x44, 0x55,
+ 0x66, 0x77, 0x88, 0x99, 0x00,
+ 0x11, 0x22, 0x33, 0x44, 0x55,
+ 0x66, 0x77, 0x88, 0x99, 0x00,
+ 0x11, 0x22, 0x33),
+ DESCRIPTOR(0xb012, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+ 0x99, 0x00, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12,
+ 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78,
+ 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x11, 0x22,
+ 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00,
+ 0x11, 0x22, 0x33),
+ CHARACTERISTIC(0xb002, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ BT_GATT_CHRC_PROP_READ |
+ BT_GATT_CHRC_PROP_WRITE,
+ 0x11, 0x22, 0x33, 0x44, 0x55,
+ 0x66, 0x77, 0x88, 0x99, 0x00,
+ 0x11, 0x22, 0x33, 0x44, 0x55,
+ 0x66, 0x77, 0x88, 0x99, 0x00,
+ 0x11, 0x22, 0x33, 0x44, 0x55,
+ 0x66, 0x77, 0x88, 0x99, 0x00,
+ 0x11, 0x22, 0x33, 0x44, 0x55,
+ 0x66, 0x77, 0x88, 0x99, 0x00,
+ 0x11, 0x22, 0x33, 0x44),
+ DESCRIPTOR(0xb013, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+ 0x99, 0x00, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12,
+ 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78,
+ 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x11, 0x22,
+ 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00,
+ 0x11, 0x22, 0x33, 0x44),
+ CHARACTERISTIC(0xb002, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ BT_GATT_CHRC_PROP_READ |
+ BT_GATT_CHRC_PROP_WRITE,
+ 0x11, 0x22, 0x33, 0x44, 0x55,
+ 0x66, 0x77, 0x88, 0x99, 0x00,
+ 0x11, 0x22, 0x33, 0x44, 0x55,
+ 0x66, 0x77, 0x88, 0x99, 0x00,
+ 0x11, 0x22, 0x33, 0x44, 0x55,
+ 0x66, 0x77, 0x88, 0x99, 0x00,
+ 0x11, 0x22, 0x33, 0x44, 0x55,
+ 0x66, 0x77, 0x88, 0x99, 0x00,
+ 0x11, 0x22, 0x33, 0x44, 0x55),
+ DESCRIPTOR(0xb014, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+ 0x99, 0x00, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12,
+ 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78,
+ 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x11, 0x22,
+ 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00,
+ 0x11, 0x22, 0x33, 0x44, 0x55),
+ CHARACTERISTIC_STR(0xb002, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ BT_GATT_CHRC_PROP_READ |
+ BT_GATT_CHRC_PROP_WRITE,
+ "1111122222333334444455555"
+ "666667777788888999"),
+ DESCRIPTOR(0xb012, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+ 0x99, 0x00, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12,
+ 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78,
+ 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x11, 0x22,
+ 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00,
+ 0x11, 0x22, 0x33),
+ CHARACTERISTIC_STR(0xb002, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ BT_GATT_CHRC_PROP_READ |
+ BT_GATT_CHRC_PROP_WRITE,
+ "2222233333444445555566666"
+ "7777788888999990000"),
+ DESCRIPTOR(0xb013, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+ 0x99, 0x00, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12,
+ 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78,
+ 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x11, 0x22,
+ 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00,
+ 0x11, 0x22, 0x33, 0x44),
+ CHARACTERISTIC_STR(0xb002, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ BT_GATT_CHRC_PROP_READ |
+ BT_GATT_CHRC_PROP_WRITE,
+ "3333344444555556666677777"
+ "88888999990000011111"),
+ DESCRIPTOR(0xb014, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+ 0x99, 0x00, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12,
+ 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78,
+ 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x11, 0x22,
+ 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00,
+ 0x11, 0x22, 0x33, 0x44, 0x55),
+ { }
+ };
+
+ return make_db(specs);
+}
+
static void test_client(gconstpointer data)
{
struct context *context = create_context(512, data);
@@ -1104,12 +1435,13 @@ static void test_read_by_type(gconstpointer data)
int main(int argc, char *argv[])
{
- struct gatt_db *service_db_1, *ts_small_db;
+ struct gatt_db *service_db_1, *ts_small_db, *ts_large_db_1;
g_test_init(&argc, &argv, NULL);
service_db_1 = make_service_data_1_db();
ts_small_db = make_test_spec_small_db();
+ ts_large_db_1 = make_test_spec_large_db_1();
/*
* Server Configuration
@@ -1165,6 +1497,11 @@ int main(int argc, char *argv[])
raw_pdu(0x03, 0x00, 0x02),
PRIMARY_DISC_SMALL_DB);
+ define_test_server("/TP/GAD/SR/BV-01-C-large-1", test_server,
+ ts_large_db_1, NULL,
+ raw_pdu(0x03, 0x00, 0x02),
+ PRIMARY_DISC_LARGE_DB_1);
+
define_test_att("/TP/GAD/CL/BV-02-C-1", test_search_primary, &uuid_16,
NULL,
MTU_EXCHANGE_CLIENT_PDUS,
--
2.2.0.rc0.207.ga3a616c
Verify that a Generic Attribute Profile server can support a search for
all characteristics of a specified Service, and report all of those
characteristics.
---
unit/test-gatt.c | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index 2b58db5..b8815ee 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -1641,6 +1641,45 @@ int main(int argc, char *argv[])
raw_pdu(0x08, 0x14, 0x00, 0x20, 0x00, 0x03, 0x28),
raw_pdu(0x01, 0x08, 0x12, 0x00, 0x0a));
+ define_test_server("/TP/GAD/SR/BV-04-C/small/1", test_server,
+ ts_small_db, NULL,
+ raw_pdu(0x03, 0x00, 0x02),
+ raw_pdu(0x08, 0x10, 0xf0, 0x17, 0xf0, 0x03, 0x28),
+ raw_pdu(0x09, 0x07, 0x12, 0xf0, 0x02, 0x13, 0xf0, 0x00,
+ 0x2a),
+ raw_pdu(0x08, 0x13, 0xf0, 0x17, 0xf0, 0x03, 0x28),
+ raw_pdu(0x09, 0x15, 0x14, 0xf0, 0x02, 0x15, 0xf0, 0xef,
+ 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x09,
+ 0xb0, 0x00, 0x00),
+ raw_pdu(0x08, 0x15, 0xf0, 0x17, 0xf0, 0x03, 0x28),
+ raw_pdu(0x09, 0x07, 0x16, 0xf0, 0x02, 0x17, 0xf0, 0x01,
+ 0x2a),
+ raw_pdu(0x08, 0x17, 0xf0, 0x17, 0xf0, 0x03, 0x28),
+ raw_pdu(0x01, 0x08, 0x17, 0xf0, 0x0a));
+
+ define_test_server("/TP/GAD/SR/BV-04-C/small/2", test_server,
+ ts_small_db, NULL,
+ raw_pdu(0x03, 0x00, 0x02),
+ raw_pdu(0x08, 0x01, 0x00, 0x0f, 0x00, 0x03, 0x28),
+ raw_pdu(0x09, 0x07, 0x02, 0x00, 0x02, 0x03, 0x00, 0x29,
+ 0x2a),
+ raw_pdu(0x08, 0x03, 0x00, 0x0f, 0x00, 0x03, 0x28),
+ raw_pdu(0x01, 0x08, 0x03, 0x00, 0x0a));
+
+ define_test_server("/TP/GAD/SR/BV-04-C/large-1", test_server,
+ ts_large_db_1, NULL,
+ raw_pdu(0x03, 0x00, 0x02),
+ raw_pdu(0x08, 0x20, 0x00, 0x29, 0x00, 0x03, 0x28),
+ raw_pdu(0x09, 0x07, 0x22, 0x00, 0x02, 0x23, 0x00, 0x01,
+ 0xb0, 0x24, 0x00, 0x0a, 0x25, 0x00, 0x02, 0xb0,
+ 0x26, 0x00, 0x08, 0x27, 0x00, 0x02, 0xb0),
+ raw_pdu(0x08, 0x27, 0x00, 0x29, 0x00, 0x03, 0x28),
+ raw_pdu(0x09, 0x07, 0x28, 0x00, 0x08, 0x29, 0x00, 0x03,
+ 0xb0),
+ raw_pdu(0x08, 0x29, 0x00, 0x29, 0x00, 0x03, 0x28),
+ raw_pdu(0x01, 0x08, 0x29, 0x00, 0x0a));
+
define_test_att("/TP/GAD/CL/BV-06-C", test_search_descs, NULL, NULL,
MTU_EXCHANGE_CLIENT_PDUS,
raw_pdu(0x04, 0x13, 0x00, 0x16, 0x00),
--
2.2.0.rc0.207.ga3a616c
Verify that a Generic Attribute Profile server can support a search for
all Included Services in a specified handle range.
---
unit/test-gatt.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index 12e84da..2b58db5 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -1605,6 +1605,28 @@ int main(int argc, char *argv[])
raw_pdu(0x08, 0x06, 0x00, 0xff, 0xff, 0x02, 0x28),
raw_pdu(0x01, 0x08, 0x06, 0x00, 0x0a));
+ define_test_server("/TP/GAD/SR/BV-03-C/small", test_server,
+ ts_small_db, NULL,
+ raw_pdu(0x03, 0x00, 0x02),
+ raw_pdu(0x08, 0x01, 0x00, 0xff, 0xff, 0x02, 0x28),
+ raw_pdu(0x09, 0x08, 0x11, 0xf0, 0x01, 0x00, 0x10, 0x00,
+ 0x0a, 0x18),
+ raw_pdu(0x08, 0x12, 0xf0, 0xff, 0xff, 0x02, 0x28),
+ raw_pdu(0x01, 0x08, 0x12, 0xf0, 0x0a));
+
+ define_test_server("/TP/GAD/SR/BV-03-C/large-1", test_server,
+ ts_large_db_1, NULL,
+ raw_pdu(0x03, 0x00, 0x02),
+ raw_pdu(0x08, 0x01, 0x00, 0xff, 0xff, 0x02, 0x28),
+ raw_pdu(0x09, 0x08, 0x02, 0x00, 0x80, 0x00, 0x85, 0x00,
+ 0x0b, 0xa0, 0x21, 0x00, 0x01, 0x00, 0x06, 0x00,
+ 0x0d, 0xa0),
+ raw_pdu(0x08, 0x22, 0x00, 0xff, 0xff, 0x02, 0x28),
+ raw_pdu(0x09, 0x08, 0x91, 0x00, 0x01, 0x00, 0x06, 0x00,
+ 0x0d, 0xa0),
+ raw_pdu(0x08, 0x92, 0x00, 0xff, 0xff, 0x02, 0x28),
+ raw_pdu(0x01, 0x08, 0x92, 0x00, 0x0a));
+
define_test_att("/TP/GAD/CL/BV-04-C", test_search_chars, NULL,
NULL,
MTU_EXCHANGE_CLIENT_PDUS,
--
2.2.0.rc0.207.ga3a616c
Verify that a Generic Attribute Profile server can support a search for
all descriptors of a specified characteristic.
---
unit/test-gatt.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index de3fe8b..44a10e8 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -1694,6 +1694,24 @@ int main(int argc, char *argv[])
raw_pdu(0x05, 0x01, 0x15, 0x00, 0x04, 0x29, 0x16, 0x00,
0x05, 0x29));
+ define_test_server("/TP/GAD/SR/BV-06-C/small", test_server,
+ ts_small_db, NULL,
+ raw_pdu(0x03, 0x00, 0x02),
+ raw_pdu(0x04, 0x04, 0x00, 0x05, 0x00),
+ raw_pdu(0x05, 0x01, 0x04, 0x00, 0x02, 0x29, 0x05, 0x00,
+ 0x01, 0x29));
+
+ define_test_server("/TP/GAD/SR/BV-06-C/large-1", test_server,
+ ts_large_db_1, NULL,
+ raw_pdu(0x03, 0x00, 0x02),
+ raw_pdu(0x04, 0x73, 0x00, 0x76, 0x00),
+ raw_pdu(0x05, 0x01, 0x73, 0x00, 0x00, 0x29, 0x74, 0x00,
+ 0x01, 0x29, 0x75, 0x00, 0x04, 0x29),
+ raw_pdu(0x04, 0x76, 0x00, 0x76, 0x00),
+ raw_pdu(0x05, 0x02, 0x76, 0x00, 0xef, 0xcd, 0xab, 0x89,
+ 0x67, 0x45, 0x23, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0xd4, 0xd5, 0x00, 0x00));
+
define_test_client("/TP/GAR/CL/BV-01-C", test_client, service_db_1,
&test_read_1,
SERVICE_DATA_1_PDUS,
--
2.2.0.rc0.207.ga3a616c
Implements Find By Type Value parsing and response, supporting the
"Discovery Primary Service by UUID" of GATT.
---
src/shared/gatt-server.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 103 insertions(+)
diff --git a/src/shared/gatt-server.c b/src/shared/gatt-server.c
index 00f36fd..ed1b274 100644
--- a/src/shared/gatt-server.c
+++ b/src/shared/gatt-server.c
@@ -87,6 +87,7 @@ struct bt_gatt_server {
unsigned int read_by_grp_type_id;
unsigned int read_by_type_id;
unsigned int find_info_id;
+ unsigned int find_by_type_value_id;
unsigned int write_id;
unsigned int write_cmd_id;
unsigned int read_id;
@@ -114,6 +115,7 @@ static void bt_gatt_server_free(struct bt_gatt_server *server)
bt_att_unregister(server->att, server->read_by_grp_type_id);
bt_att_unregister(server->att, server->read_by_type_id);
bt_att_unregister(server->att, server->find_info_id);
+ bt_att_unregister(server->att, server->find_by_type_value_id);
bt_att_unregister(server->att, server->write_id);
bt_att_unregister(server->att, server->write_cmd_id);
bt_att_unregister(server->att, server->read_id);
@@ -639,6 +641,98 @@ error:
}
+struct find_by_type_val_data {
+ uint8_t *pdu;
+ uint16_t len;
+ uint16_t mtu;
+ uint8_t ecode;
+};
+
+static void find_by_type_val_att_cb(struct gatt_db_attribute *attrib,
+ void *user_data)
+{
+ uint16_t handle, end_handle;
+ struct find_by_type_val_data *data = user_data;
+
+ if (data->ecode)
+ return;
+
+ if (data->len + 4 > data->mtu - 1)
+ return;
+
+ /*
+ * This OP is only valid for Primary Service per the spec
+ * page 562, so this should work.
+ */
+ gatt_db_attribute_get_service_data(attrib, &handle, &end_handle, NULL,
+ NULL);
+
+ if (!handle || !end_handle) {
+ data->ecode = BT_ATT_ERROR_UNLIKELY;
+ return;
+ }
+
+ put_le16(handle, data->pdu + data->len);
+ put_le16(end_handle, data->pdu + data->len + 2);
+
+ data->len += 4;
+}
+
+static void find_by_type_val_cb(uint8_t opcode, const void *pdu,
+ uint16_t length, void *user_data)
+{
+ struct bt_gatt_server *server = user_data;
+ uint16_t start, end, uuid16;
+ struct find_by_type_val_data data;
+ uint16_t mtu = bt_att_get_mtu(server->att);
+ uint8_t rsp_pdu[mtu];
+ uint16_t ehandle = 0;
+ bt_uuid_t uuid;
+
+ if (length < 6) {
+ data.ecode = BT_ATT_ERROR_INVALID_PDU;
+ goto error;
+ }
+
+ data.pdu = rsp_pdu;
+ data.len = 0;
+ data.mtu = mtu;
+ data.ecode = 0;
+
+ start = get_le16(pdu);
+ end = get_le16(pdu + 2);
+ uuid16 = get_le16(pdu + 4);
+
+ util_debug(server->debug_callback, server->debug_data,
+ "Find By Type Value - start: 0x%04x end: 0x%04x uuid: 0x%04x",
+ start, end, uuid16);
+ ehandle = start;
+ if (start > end) {
+ data.ecode = BT_ATT_ERROR_INVALID_HANDLE;
+ goto error;
+ }
+
+ bt_uuid16_create(&uuid, uuid16);
+ gatt_db_find_by_type_value(server->db, start, end, &uuid, pdu + 6,
+ length - 6,
+ find_by_type_val_att_cb,
+ &data);
+
+ if (!data.len)
+ data.ecode = BT_ATT_ERROR_ATTRIBUTE_NOT_FOUND;
+
+ if (data.ecode)
+ goto error;
+
+ bt_att_send(server->att, BT_ATT_OP_FIND_BY_TYPE_VAL_RSP, data.pdu,
+ data.len, NULL, NULL, NULL);
+
+ return;
+
+error:
+ bt_att_send_error_rsp(server->att, opcode, ehandle, data.ecode);
+}
+
static void async_write_op_destroy(struct async_write_op *op)
{
if (op->server)
@@ -1128,6 +1222,15 @@ static bool gatt_server_register_att_handlers(struct bt_gatt_server *server)
if (!server->find_info_id)
return false;
+ /* Find By Type Value */
+ server->find_by_type_value_id = bt_att_register(server->att,
+ BT_ATT_OP_FIND_BY_TYPE_VAL_REQ,
+ find_by_type_val_cb,
+ server, NULL);
+
+ if (!server->find_by_type_value_id)
+ return false;
+
/* Write Request */
server->write_id = bt_att_register(server->att, BT_ATT_OP_WRITE_REQ,
write_cb,
--
2.2.0.rc0.207.ga3a616c
Added to support the GATT discovery of services by UUID.
Currently only works for values which are stored within the attribute
structure (not callback-based).
---
src/shared/gatt-db.c | 29 +++++++++++++++++++++++++++++
src/shared/gatt-db.h | 8 ++++++++
2 files changed, 37 insertions(+)
diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
index f519bcb..e8f78fd 100644
--- a/src/shared/gatt-db.c
+++ b/src/shared/gatt-db.c
@@ -831,6 +831,8 @@ struct find_by_type_value_data {
uint16_t end_handle;
gatt_db_attribute_cb_t func;
void *user_data;
+ const void *value;
+ size_t value_len;
};
static void find_by_type(void *data, void *user_data)
@@ -856,6 +858,12 @@ static void find_by_type(void *data, void *user_data)
if (bt_uuid_cmp(&search_data->uuid, &attribute->uuid))
continue;
+ /* TODO: fix for read-callback based attributes */
+ if (search_data->value && memcmp(attribute->value,
+ search_data->value,
+ search_data->value_len))
+ continue;
+
search_data->func(attribute, search_data->user_data);
}
}
@@ -877,6 +885,27 @@ void gatt_db_find_by_type(struct gatt_db *db, uint16_t start_handle,
queue_foreach(db->services, find_by_type, &data);
}
+void gatt_db_find_by_type_value(struct gatt_db *db, uint16_t start_handle,
+ uint16_t end_handle,
+ const bt_uuid_t *type,
+ const void *value,
+ size_t value_len,
+ gatt_db_attribute_cb_t func,
+ void *user_data)
+{
+ struct find_by_type_value_data data;
+
+ data.uuid = *type;
+ data.start_handle = start_handle;
+ data.end_handle = end_handle;
+ data.func = func;
+ data.user_data = user_data;
+ data.value = value;
+ data.value_len = value_len;
+
+ queue_foreach(db->services, find_by_type, &data);
+}
+
struct read_by_type_data {
struct queue *queue;
bt_uuid_t uuid;
diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
index 9fc1b11..2edd13f 100644
--- a/src/shared/gatt-db.h
+++ b/src/shared/gatt-db.h
@@ -97,6 +97,14 @@ void gatt_db_find_by_type(struct gatt_db *db, uint16_t start_handle,
gatt_db_attribute_cb_t func,
void *user_data);
+void gatt_db_find_by_type_value(struct gatt_db *db, uint16_t start_handle,
+ uint16_t end_handle,
+ const bt_uuid_t *type,
+ const void *value,
+ size_t value_len,
+ gatt_db_attribute_cb_t func,
+ void *user_data);
+
void gatt_db_read_by_type(struct gatt_db *db, uint16_t start_handle,
uint16_t end_handle,
const bt_uuid_t type,
--
2.2.0.rc0.207.ga3a616c