2014-11-06 12:47:06

by Marcin Kraglak

[permalink] [raw]
Subject: [PATCH 1/9] unit/test-gatt: Use one generic search callback

In these callbacks only success is verified, so there is no need to
duplicate them.
---
unit/test-gatt.c | 34 +++++++---------------------------
1 file changed, 7 insertions(+), 27 deletions(-)

diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index 27471ea..f343fe6 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -259,29 +259,7 @@ static struct context *create_context(uint16_t mtu, gconstpointer data)
return context;
}

-static void primary_cb(bool success, uint8_t att_ecode,
- struct bt_gatt_result *result,
- void *user_data)
-{
- struct context *context = user_data;
-
- g_assert(success);
-
- context_quit(context);
-}
-
-static void characteristic_cb(bool success, uint8_t att_ecode,
- struct bt_gatt_result *result,
- void *user_data)
-{
- struct context *context = user_data;
-
- g_assert(success);
-
- context_quit(context);
-}
-
-static void included_cb(bool success, uint8_t att_ecode,
+static void generic_search_cb(bool success, uint8_t att_ecode,
struct bt_gatt_result *result,
void *user_data)
{
@@ -328,7 +306,8 @@ static void test_search_primary(gconstpointer data)
const struct test_data *test_data = data;

bt_gatt_discover_all_primary_services(context->att, test_data->uuid,
- primary_cb, context, NULL);
+ generic_search_cb,
+ context, NULL);

execute_context(context);
}
@@ -338,7 +317,8 @@ static void test_search_included(gconstpointer data)
struct context *context = create_context(512, data);

bt_gatt_discover_included_services(context->att, 0x0001, 0xffff,
- included_cb, context, NULL);
+ generic_search_cb,
+ context, NULL);

execute_context(context);
}
@@ -348,8 +328,8 @@ static void test_search_chars(gconstpointer data)
struct context *context = create_context(512, data);

g_assert(bt_gatt_discover_characteristics(context->att, 0x0010, 0x0020,
- characteristic_cb, context,
- NULL));
+ generic_search_cb,
+ context, NULL));

execute_context(context);
}
--
1.9.3



2014-11-06 15:43:37

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH 1/9] unit/test-gatt: Use one generic search callback

Hi Marcin,

On Thu, Nov 6, 2014 at 2:47 PM, Marcin Kraglak <[email protected]> wrote:
> In these callbacks only success is verified, so there is no need to
> duplicate them.
> ---
> unit/test-gatt.c | 34 +++++++---------------------------
> 1 file changed, 7 insertions(+), 27 deletions(-)
>
> diff --git a/unit/test-gatt.c b/unit/test-gatt.c
> index 27471ea..f343fe6 100644
> --- a/unit/test-gatt.c
> +++ b/unit/test-gatt.c
> @@ -259,29 +259,7 @@ static struct context *create_context(uint16_t mtu, gconstpointer data)
> return context;
> }
>
> -static void primary_cb(bool success, uint8_t att_ecode,
> - struct bt_gatt_result *result,
> - void *user_data)
> -{
> - struct context *context = user_data;
> -
> - g_assert(success);
> -
> - context_quit(context);
> -}
> -
> -static void characteristic_cb(bool success, uint8_t att_ecode,
> - struct bt_gatt_result *result,
> - void *user_data)
> -{
> - struct context *context = user_data;
> -
> - g_assert(success);
> -
> - context_quit(context);
> -}
> -
> -static void included_cb(bool success, uint8_t att_ecode,
> +static void generic_search_cb(bool success, uint8_t att_ecode,
> struct bt_gatt_result *result,
> void *user_data)
> {
> @@ -328,7 +306,8 @@ static void test_search_primary(gconstpointer data)
> const struct test_data *test_data = data;
>
> bt_gatt_discover_all_primary_services(context->att, test_data->uuid,
> - primary_cb, context, NULL);
> + generic_search_cb,
> + context, NULL);
>
> execute_context(context);
> }
> @@ -338,7 +317,8 @@ static void test_search_included(gconstpointer data)
> struct context *context = create_context(512, data);
>
> bt_gatt_discover_included_services(context->att, 0x0001, 0xffff,
> - included_cb, context, NULL);
> + generic_search_cb,
> + context, NULL);
>
> execute_context(context);
> }
> @@ -348,8 +328,8 @@ static void test_search_chars(gconstpointer data)
> struct context *context = create_context(512, data);
>
> g_assert(bt_gatt_discover_characteristics(context->att, 0x0010, 0x0020,
> - characteristic_cb, context,
> - NULL));
> + generic_search_cb,
> + context, NULL));
>
> execute_context(context);
> }
> --
> 1.9.3

Applied, thanks.


--
Luiz Augusto von Dentz

2014-11-06 13:45:50

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH 3/9] shared/gatt: Fix memory leak in discovery_op_unref

Hi Marcin,

On Thu, Nov 6, 2014 at 2:47 PM, Marcin Kraglak <[email protected]> wrote:
> Free services list in discovery_op_unref. If discovery has been
> interrupted, services from discovery_op were not pushed to
> gatt_client service list, and it caused memory leak.
> ---

Please add the backtrace if you have it.

> src/shared/gatt-client.c | 10 +++++++---
> 1 file changed, 7 insertions(+), 3 deletions(-)
>
> diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
> index 8689368..b4f28b2 100644
> --- a/src/shared/gatt-client.c
> +++ b/src/shared/gatt-client.c
> @@ -411,6 +411,8 @@ static void discovery_op_unref(void *data)
> if (__sync_sub_and_fetch(&op->ref_count, 1))
> return;
>
> + service_list_clear(&op->result_head, &op->result_tail);
> +
> free(data);
> }
>
> @@ -1140,6 +1142,10 @@ static void init_complete(struct discovery_op *op, bool success,
> client->svc_head = op->result_head;
> client->svc_tail = op->result_tail;
>
> + /* Change owner of service list */
> + op->result_head = NULL;
> + op->result_tail = NULL;
> +
> if (!client->svc_chngd_val_handle) {
> client->ready = true;
> goto done;
> @@ -1164,12 +1170,10 @@ static void init_complete(struct discovery_op *op, bool success,
> util_debug(client->debug_callback, client->debug_data,
> "Failed to register handler for \"Service Changed\"");
>
> - client->svc_head = client->svc_tail = NULL;
> -
> fail:
> util_debug(client->debug_callback, client->debug_data,
> "Failed to initialize gatt-client");
> - service_list_clear(&op->result_head, &op->result_tail);
> + service_list_clear(&client->svc_head, &client->svc_head);
>
> done:
> if (client->ready_callback)
> --
> 1.9.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html



--
Luiz Augusto von Dentz

2014-11-06 12:47:14

by Marcin Kraglak

[permalink] [raw]
Subject: [PATCH 9/9] unit/test-gatt: Add TP/GAR/CL/BI-03-C test

Verify Generic Attribute Profile client behavior when
the Read Characteristic Value procedure fails due to
insufficient authorization.
---
unit/test-gatt.c | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)

diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index 6208192..39cdda3 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -510,6 +510,12 @@ const struct test_step test_read_3 = {
.expected_att_ecode = 0x02,
};

+const struct test_step test_read_4 = {
+ .handle = 0x0003,
+ .func = test_read,
+ .expected_att_ecode = 0x08,
+};
+
static void test_client(gconstpointer data)
{
struct context *context = create_context(512, data);
@@ -767,5 +773,38 @@ int main(int argc, char *argv[])
raw_pdu(0x0a, 0x03, 0x00),
raw_pdu(0x01, 0x0a, 0x03, 0x00, 0x02));

+ define_test_client("/TP/GAR/CL/BI-03-C", test_client, service_data_1,
+ &test_read_4,
+ raw_pdu(0x02, 0x00, 0x02),
+ raw_pdu(0x03, 0x00, 0x02),
+ raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
+ raw_pdu(0x11, 0x06, 0x01, 0x00, 0x04, 0x00, 0x01, 0x18),
+ raw_pdu(0x10, 0x05, 0x00, 0xff, 0xff, 0x00, 0x28),
+ raw_pdu(0x11, 0x06, 0x05, 0x00, 0x08, 0x00, 0x0d, 0x18),
+ raw_pdu(0x10, 0x09, 0x00, 0xff, 0xff, 0x00, 0x28),
+ raw_pdu(0x01, 0x10, 0x09, 0x00, 0x0a),
+ raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x01, 0x28),
+ raw_pdu(0x01, 0x10, 0x01, 0x00, 0x0a),
+ raw_pdu(0x08, 0x01, 0x00, 0x04, 0x00, 0x02, 0x28),
+ raw_pdu(0x01, 0x08, 0x01, 0x00, 0x0a),
+ raw_pdu(0x08, 0x05, 0x00, 0x08, 0x00, 0x02, 0x28),
+ raw_pdu(0x01, 0x08, 0x05, 0x00, 0x0a),
+ raw_pdu(0x08, 0x01, 0x00, 0x04, 0x00, 0x03, 0x28),
+ raw_pdu(0x09, 0x07, 0x02, 0x00, 0x02, 0x03, 0x00, 0x00,
+ 0x2a),
+ raw_pdu(0x08, 0x03, 0x00, 0x04, 0x00, 0x03, 0x28),
+ raw_pdu(0x01, 0x08, 0x03, 0x00, 0x0a),
+ raw_pdu(0x04, 0x04, 0x00, 0x04, 0x00),
+ raw_pdu(0x05, 0x01, 0x04, 0x00, 0x01, 0x29),
+ raw_pdu(0x08, 0x05, 0x00, 0x08, 0x00, 0x03, 0x28),
+ raw_pdu(0x09, 0x07, 0x06, 0x00, 0x02, 0x07, 0x00, 0x29,
+ 0x2a),
+ raw_pdu(0x08, 0x07, 0x00, 0x08, 0x00, 0x03, 0x28),
+ raw_pdu(0x01, 0x08, 0x07, 0x00, 0x0a),
+ raw_pdu(0x04, 0x08, 0x00, 0x08, 0x00),
+ raw_pdu(0x05, 0x01, 0x08, 0x00, 0x01, 0x29),
+ raw_pdu(0x0a, 0x03, 0x00),
+ raw_pdu(0x01, 0x0a, 0x03, 0x00, 0x08));
+
return g_test_run();
}
--
1.9.3


2014-11-06 12:47:12

by Marcin Kraglak

[permalink] [raw]
Subject: [PATCH 7/9] unit/test-gatt: Add TP/GAR/CL/BI-01-C test

Verify Generic Attribute Profile client behavior when the
Read Characteristic Value procedure fails due to invalid handle.
---
unit/test-gatt.c | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)

diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index 861740b..d91fd41 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -498,6 +498,12 @@ const struct test_step test_read_1 = {
.length = 0x03
};

+const struct test_step test_read_2 = {
+ .handle = 0x0000,
+ .func = test_read,
+ .expected_att_ecode = 0x01,
+};
+
static void test_client(gconstpointer data)
{
struct context *context = create_context(512, data);
@@ -689,5 +695,38 @@ int main(int argc, char *argv[])
raw_pdu(0x0a, 0x03, 0x00),
raw_pdu(0x0b, 0x01, 0x02, 0x03));

+ define_test_client("/TP/GAR/CL/BI-01-C", test_client, service_data_1,
+ &test_read_2,
+ raw_pdu(0x02, 0x00, 0x02),
+ raw_pdu(0x03, 0x00, 0x02),
+ raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
+ raw_pdu(0x11, 0x06, 0x01, 0x00, 0x04, 0x00, 0x01, 0x18),
+ raw_pdu(0x10, 0x05, 0x00, 0xff, 0xff, 0x00, 0x28),
+ raw_pdu(0x11, 0x06, 0x05, 0x00, 0x08, 0x00, 0x0d, 0x18),
+ raw_pdu(0x10, 0x09, 0x00, 0xff, 0xff, 0x00, 0x28),
+ raw_pdu(0x01, 0x10, 0x09, 0x00, 0x0a),
+ raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x01, 0x28),
+ raw_pdu(0x01, 0x10, 0x01, 0x00, 0x0a),
+ raw_pdu(0x08, 0x01, 0x00, 0x04, 0x00, 0x02, 0x28),
+ raw_pdu(0x01, 0x08, 0x01, 0x00, 0x0a),
+ raw_pdu(0x08, 0x05, 0x00, 0x08, 0x00, 0x02, 0x28),
+ raw_pdu(0x01, 0x08, 0x05, 0x00, 0x0a),
+ raw_pdu(0x08, 0x01, 0x00, 0x04, 0x00, 0x03, 0x28),
+ raw_pdu(0x09, 0x07, 0x02, 0x00, 0x02, 0x03, 0x00, 0x00,
+ 0x2a),
+ raw_pdu(0x08, 0x03, 0x00, 0x04, 0x00, 0x03, 0x28),
+ raw_pdu(0x01, 0x08, 0x03, 0x00, 0x0a),
+ raw_pdu(0x04, 0x04, 0x00, 0x04, 0x00),
+ raw_pdu(0x05, 0x01, 0x04, 0x00, 0x01, 0x29),
+ raw_pdu(0x08, 0x05, 0x00, 0x08, 0x00, 0x03, 0x28),
+ raw_pdu(0x09, 0x07, 0x06, 0x00, 0x02, 0x07, 0x00, 0x29,
+ 0x2a),
+ raw_pdu(0x08, 0x07, 0x00, 0x08, 0x00, 0x03, 0x28),
+ raw_pdu(0x01, 0x08, 0x07, 0x00, 0x0a),
+ raw_pdu(0x04, 0x08, 0x00, 0x08, 0x00),
+ raw_pdu(0x05, 0x01, 0x08, 0x00, 0x01, 0x29),
+ raw_pdu(0x0a, 0x00, 0x00),
+ raw_pdu(0x01, 0x0a, 0x00, 0x00, 0x01));
+
return g_test_run();
}
--
1.9.3


2014-11-06 12:47:13

by Marcin Kraglak

[permalink] [raw]
Subject: [PATCH 8/9] unit/test-gatt: Add TP/GAR/CL/BI-02-C test

Verify Generic Attribute Profile client behavior when
the Read Characteristic Value procedure fails due to
read not permitted.
---
unit/test-gatt.c | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)

diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index d91fd41..6208192 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -504,6 +504,12 @@ const struct test_step test_read_2 = {
.expected_att_ecode = 0x01,
};

+const struct test_step test_read_3 = {
+ .handle = 0x0003,
+ .func = test_read,
+ .expected_att_ecode = 0x02,
+};
+
static void test_client(gconstpointer data)
{
struct context *context = create_context(512, data);
@@ -728,5 +734,38 @@ int main(int argc, char *argv[])
raw_pdu(0x0a, 0x00, 0x00),
raw_pdu(0x01, 0x0a, 0x00, 0x00, 0x01));

+ define_test_client("/TP/GAR/CL/BI-02-C", test_client, service_data_1,
+ &test_read_3,
+ raw_pdu(0x02, 0x00, 0x02),
+ raw_pdu(0x03, 0x00, 0x02),
+ raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
+ raw_pdu(0x11, 0x06, 0x01, 0x00, 0x04, 0x00, 0x01, 0x18),
+ raw_pdu(0x10, 0x05, 0x00, 0xff, 0xff, 0x00, 0x28),
+ raw_pdu(0x11, 0x06, 0x05, 0x00, 0x08, 0x00, 0x0d, 0x18),
+ raw_pdu(0x10, 0x09, 0x00, 0xff, 0xff, 0x00, 0x28),
+ raw_pdu(0x01, 0x10, 0x09, 0x00, 0x0a),
+ raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x01, 0x28),
+ raw_pdu(0x01, 0x10, 0x01, 0x00, 0x0a),
+ raw_pdu(0x08, 0x01, 0x00, 0x04, 0x00, 0x02, 0x28),
+ raw_pdu(0x01, 0x08, 0x01, 0x00, 0x0a),
+ raw_pdu(0x08, 0x05, 0x00, 0x08, 0x00, 0x02, 0x28),
+ raw_pdu(0x01, 0x08, 0x05, 0x00, 0x0a),
+ raw_pdu(0x08, 0x01, 0x00, 0x04, 0x00, 0x03, 0x28),
+ raw_pdu(0x09, 0x07, 0x02, 0x00, 0x02, 0x03, 0x00, 0x00,
+ 0x2a),
+ raw_pdu(0x08, 0x03, 0x00, 0x04, 0x00, 0x03, 0x28),
+ raw_pdu(0x01, 0x08, 0x03, 0x00, 0x0a),
+ raw_pdu(0x04, 0x04, 0x00, 0x04, 0x00),
+ raw_pdu(0x05, 0x01, 0x04, 0x00, 0x01, 0x29),
+ raw_pdu(0x08, 0x05, 0x00, 0x08, 0x00, 0x03, 0x28),
+ raw_pdu(0x09, 0x07, 0x06, 0x00, 0x02, 0x07, 0x00, 0x29,
+ 0x2a),
+ raw_pdu(0x08, 0x07, 0x00, 0x08, 0x00, 0x03, 0x28),
+ raw_pdu(0x01, 0x08, 0x07, 0x00, 0x0a),
+ raw_pdu(0x04, 0x08, 0x00, 0x08, 0x00),
+ raw_pdu(0x05, 0x01, 0x08, 0x00, 0x01, 0x29),
+ raw_pdu(0x0a, 0x03, 0x00),
+ raw_pdu(0x01, 0x0a, 0x03, 0x00, 0x02));
+
return g_test_run();
}
--
1.9.3


2014-11-06 12:47:11

by Marcin Kraglak

[permalink] [raw]
Subject: [PATCH 6/9] unit/test-gatt: Add /TP/GAR/CL/BV-01-C test

Verify that a Generic Attribute Profile client can read
a Characteristic Value selected by handle.
---
unit/test-gatt.c | 163 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 156 insertions(+), 7 deletions(-)

diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index c2544a5..861740b 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -66,6 +66,7 @@ struct test_data {
bt_uuid_t *uuid;
int num_services;
const struct gatt_service **services;
+ const void *step;
};

struct context {
@@ -88,7 +89,8 @@ struct context {
.size = sizeof(data(args)), \
}

-#define define_test(name, function, type, bt_uuid, bt_services, args...)\
+#define define_test(name, function, type, bt_uuid, bt_services, \
+ test_step, args...) \
do { \
const struct test_pdu pdus[] = { \
args, { } \
@@ -97,19 +99,20 @@ struct context {
data.test_name = g_strdup(name); \
data.context_type = type; \
data.uuid = bt_uuid; \
- data.pdu_list = g_malloc(sizeof(pdus)); \
+ data.step = test_step; \
data.services = bt_services; \
data.num_services = sizeof(bt_services) / \
sizeof(bt_services[0]); \
+ data.pdu_list = g_malloc(sizeof(pdus)); \
memcpy(data.pdu_list, pdus, sizeof(pdus)); \
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, args)
+#define define_test_att(name, function, bt_uuid, args...) \
+ define_test(name, function, ATT, bt_uuid, NULL, NULL, args)

-#define define_test_client(name, function, bt_services, args...) \
- define_test(name, function, CLIENT, NULL, bt_services, args)
+#define define_test_client(name, function, bt_services, test_step, args...)\
+ define_test(name, function, CLIENT, NULL, bt_services, test_step, args)

static bt_uuid_t uuid_16 = {
.type = BT_UUID16,
@@ -122,6 +125,74 @@ static bt_uuid_t uuid_128 = {
0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb}
};

+const bt_gatt_service_t service_1 = {
+ .primary = true,
+ .start_handle = 0x0001,
+ .end_handle = 0x0004,
+ .uuid = {0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb}
+};
+
+const bt_gatt_descriptor_t descriptor_1 = {
+ .handle = 0x0004,
+ .uuid = {0x00, 0x00, 0x29, 0x01, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb}
+};
+
+const bt_gatt_characteristic_t characteristic_1 = {
+ .start_handle = 0x0002,
+ .end_handle = 0x0004,
+ .value_handle = 0x0003,
+ .properties = 0x02,
+ .uuid = {0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb},
+ .descs = &descriptor_1,
+ .num_descs = 1
+};
+
+const bt_gatt_service_t service_2 = {
+ .primary = true,
+ .start_handle = 0x0005,
+ .end_handle = 0x0008,
+ .uuid = {0x00, 0x00, 0x18, 0x0d, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb}
+};
+
+const bt_gatt_descriptor_t descriptor_2 = {
+ .handle = 0x0008,
+ .uuid = {0x00, 0x00, 0x29, 0x01, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb}
+};
+
+const bt_gatt_characteristic_t characteristic_2 = {
+ .start_handle = 0x0006,
+ .end_handle = 0x0008,
+ .value_handle = 0x0007,
+ .properties = 0x02,
+ .uuid = {0x00, 0x00, 0x2a, 0x29, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb},
+ .descs = &descriptor_2,
+ .num_descs = 1
+};
+
+const bt_gatt_characteristic_t *characteristics_1[] = {&characteristic_1};
+const bt_gatt_characteristic_t *characteristics_2[] = {&characteristic_2};
+
+const struct gatt_service gatt_service_1 = {
+ .service = &service_1,
+ .num_chars = sizeof(characteristics_1) / sizeof(characteristics_1[0]),
+ .chars = characteristics_1
+};
+
+const struct gatt_service gatt_service_2 = {
+ .service = &service_2,
+ .num_chars = sizeof(characteristics_2) / sizeof(characteristics_2[0]),
+ .chars = characteristics_2
+};
+
+const struct gatt_service *service_data_1[] = {&gatt_service_1,
+ &gatt_service_2};
+
static void test_debug(const char *str, void *user_data)
{
const char *prefix = user_data;
@@ -382,6 +453,51 @@ static void execute_context(struct context *context)
destroy_context(context);
}

+typedef void (*test_step_t)(struct context *context);
+
+struct test_step {
+ test_step_t func;
+ uint16_t handle;
+ uint8_t expected_att_ecode;
+ const uint8_t *value;
+ uint16_t length;
+};
+
+static void test_read_cb(bool success, uint8_t att_ecode,
+ const uint8_t *value, uint16_t length,
+ void *user_data)
+{
+ struct context *context = user_data;
+ const struct test_step *step = context->data->step;
+
+ g_assert(att_ecode == step->expected_att_ecode);
+
+ if (success) {
+ g_assert(length == step->length);
+ g_assert(memcmp(value, step->value, length) == 0);
+ }
+
+ context_quit(context);
+}
+
+static void test_read(struct context *context)
+{
+ const struct test_step *step = context->data->step;
+
+ g_assert(bt_gatt_client_read_value(context->client, step->handle,
+ test_read_cb, context, NULL));
+}
+
+const uint8_t read_data_1[] = {0x01, 0x02, 0x03};
+
+const struct test_step test_read_1 = {
+ .handle = 0x0003,
+ .func = test_read,
+ .expected_att_ecode = 0,
+ .value = read_data_1,
+ .length = 0x03
+};
+
static void test_client(gconstpointer data)
{
struct context *context = create_context(512, data);
@@ -445,7 +561,7 @@ int main(int argc, char *argv[])
* Server Configuration.
*/

- define_test_client("/TP/GAC/CL/BV-01-C", test_client, NULL,
+ define_test_client("/TP/GAC/CL/BV-01-C", test_client, NULL, NULL,
raw_pdu(0x02, 0x00, 0x02));

/*
@@ -540,5 +656,38 @@ int main(int argc, char *argv[])
raw_pdu(0x05, 0x01, 0x15, 0x00, 0x04, 0x29, 0x16, 0x00,
0x05, 0x29));

+ define_test_client("/TP/GAR/CL/BV-01-C", test_client, service_data_1,
+ &test_read_1,
+ raw_pdu(0x02, 0x00, 0x02),
+ raw_pdu(0x03, 0x00, 0x02),
+ raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
+ raw_pdu(0x11, 0x06, 0x01, 0x00, 0x04, 0x00, 0x01, 0x18),
+ raw_pdu(0x10, 0x05, 0x00, 0xff, 0xff, 0x00, 0x28),
+ raw_pdu(0x11, 0x06, 0x05, 0x00, 0x08, 0x00, 0x0d, 0x18),
+ raw_pdu(0x10, 0x09, 0x00, 0xff, 0xff, 0x00, 0x28),
+ raw_pdu(0x01, 0x10, 0x09, 0x00, 0x0a),
+ raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x01, 0x28),
+ raw_pdu(0x01, 0x10, 0x01, 0x00, 0x0a),
+ raw_pdu(0x08, 0x01, 0x00, 0x04, 0x00, 0x02, 0x28),
+ raw_pdu(0x01, 0x08, 0x01, 0x00, 0x0a),
+ raw_pdu(0x08, 0x05, 0x00, 0x08, 0x00, 0x02, 0x28),
+ raw_pdu(0x01, 0x08, 0x05, 0x00, 0x0a),
+ raw_pdu(0x08, 0x01, 0x00, 0x04, 0x00, 0x03, 0x28),
+ raw_pdu(0x09, 0x07, 0x02, 0x00, 0x02, 0x03, 0x00, 0x00,
+ 0x2a),
+ raw_pdu(0x08, 0x03, 0x00, 0x04, 0x00, 0x03, 0x28),
+ raw_pdu(0x01, 0x08, 0x03, 0x00, 0x0a),
+ raw_pdu(0x04, 0x04, 0x00, 0x04, 0x00),
+ raw_pdu(0x05, 0x01, 0x04, 0x00, 0x01, 0x29),
+ raw_pdu(0x08, 0x05, 0x00, 0x08, 0x00, 0x03, 0x28),
+ raw_pdu(0x09, 0x07, 0x06, 0x00, 0x02, 0x07, 0x00, 0x29,
+ 0x2a),
+ raw_pdu(0x08, 0x07, 0x00, 0x08, 0x00, 0x03, 0x28),
+ raw_pdu(0x01, 0x08, 0x07, 0x00, 0x0a),
+ raw_pdu(0x04, 0x08, 0x00, 0x08, 0x00),
+ raw_pdu(0x05, 0x01, 0x08, 0x00, 0x01, 0x29),
+ raw_pdu(0x0a, 0x03, 0x00),
+ raw_pdu(0x0b, 0x01, 0x02, 0x03));
+
return g_test_run();
}
--
1.9.3


2014-11-06 12:47:09

by Marcin Kraglak

[permalink] [raw]
Subject: [PATCH 4/9] unit/test-gatt: Add macros defining tests with type

Simplify macros for defining test cases.
---
unit/test-gatt.c | 21 ++++++++++++++-------
1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index a2ca5b6..712b117 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -94,6 +94,12 @@ 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, args)
+
+#define define_test_client(name, function, args...) \
+ define_test(name, function, CLIENT, NULL, args)
+
static bt_uuid_t uuid_16 = {
.type = BT_UUID16,
.value.u16 = 0x1800
@@ -355,7 +361,8 @@ int main(int argc, char *argv[])
* The test group objective is to verify Generic Attribute Profile
* Server Configuration.
*/
- define_test("/TP/GAC/CL/BV-01-C", test_client, CLIENT, NULL,
+
+ define_test_client("/TP/GAC/CL/BV-01-C", test_client,
raw_pdu(0x02, 0x00, 0x02));

/*
@@ -364,7 +371,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("/TP/GAD/CL/BV-01-C", test_search_primary, ATT, NULL,
+ define_test_att("/TP/GAD/CL/BV-01-C", test_search_primary, NULL,
raw_pdu(0x02, 0x00, 0x02),
raw_pdu(0x03, 0x00, 0x02),
raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
@@ -379,7 +386,7 @@ int main(int argc, char *argv[])
raw_pdu(0x10, 0x97, 0x00, 0xff, 0xff, 0x00, 0x28),
raw_pdu(0x01, 0x10, 0x97, 0x00, 0x0a));

- define_test("/TP/GAD/CL/BV-02-C-1", test_search_primary, ATT, &uuid_16,
+ define_test_att("/TP/GAD/CL/BV-02-C-1", test_search_primary, &uuid_16,
raw_pdu(0x02, 0x00, 0x02),
raw_pdu(0x03, 0x00, 0x02),
raw_pdu(0x06, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28, 0x00,
@@ -389,7 +396,7 @@ int main(int argc, char *argv[])
0x18),
raw_pdu(0x01, 0x06, 0x08, 0x00, 0x0a));

- define_test("/TP/GAD/CL/BV-02-C-2", test_search_primary, ATT, &uuid_128,
+ define_test_att("/TP/GAD/CL/BV-02-C-2", test_search_primary, &uuid_128,
raw_pdu(0x02, 0x00, 0x02),
raw_pdu(0x03, 0x00, 0x02),
raw_pdu(06, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28, 0xfb,
@@ -403,7 +410,7 @@ int main(int argc, char *argv[])
0x18, 0x00, 0x00),
raw_pdu(0x01, 0x06, 0x08, 0x00, 0x0a));

- define_test("/TP/GAD/CL/BV-03-C", test_search_included, ATT, NULL,
+ define_test_att("/TP/GAD/CL/BV-03-C", test_search_included, NULL,
raw_pdu(0x02, 0x00, 0x02),
raw_pdu(0x03, 0x00, 0x02),
raw_pdu(0x08, 0x01, 0x00, 0xff, 0xff, 0x02, 0x28),
@@ -426,7 +433,7 @@ int main(int argc, char *argv[])
raw_pdu(0x08, 0x06, 0x00, 0xff, 0xff, 0x02, 0x28),
raw_pdu(0x01, 0x08, 0x06, 0x00, 0x0a));

- define_test("/TP/GAD/CL/BV-04-C", test_search_chars, ATT, NULL,
+ define_test_att("/TP/GAD/CL/BV-04-C", test_search_chars, NULL,
raw_pdu(0x02, 0x00, 0x02),
raw_pdu(0x03, 0x00, 0x02),
raw_pdu(0x08, 0x10, 0x00, 0x20, 0x00, 0x03, 0x28),
@@ -440,7 +447,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("/TP/GAD/CL/BV-06-C", test_search_descs, ATT, NULL,
+ define_test_att("/TP/GAD/CL/BV-06-C", test_search_descs, NULL,
raw_pdu(0x02, 0x00, 0x02),
raw_pdu(0x03, 0x00, 0x02),
raw_pdu(0x04, 0x13, 0x00, 0x16, 0x00),
--
1.9.3


2014-11-06 12:47:10

by Marcin Kraglak

[permalink] [raw]
Subject: [PATCH 5/9] unit/test-gatt: Verify found services

Register ready_callback in bt_gatt_client to verify services,
characteristics and descriptors found during discovery.
---
unit/test-gatt.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 88 insertions(+), 5 deletions(-)

diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index 712b117..c2544a5 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -53,11 +53,19 @@ enum context_type {
SERVER
};

+struct gatt_service {
+ const bt_gatt_service_t *service;
+ int num_chars;
+ const bt_gatt_characteristic_t **chars;
+};
+
struct test_data {
char *test_name;
struct test_pdu *pdu_list;
enum context_type context_type;
bt_uuid_t *uuid;
+ int num_services;
+ const struct gatt_service **services;
};

struct context {
@@ -80,7 +88,7 @@ struct context {
.size = sizeof(data(args)), \
}

-#define define_test(name, function, type, bt_uuid, args...) \
+#define define_test(name, function, type, bt_uuid, bt_services, args...)\
do { \
const struct test_pdu pdus[] = { \
args, { } \
@@ -90,15 +98,18 @@ struct context {
data.context_type = type; \
data.uuid = bt_uuid; \
data.pdu_list = g_malloc(sizeof(pdus)); \
+ data.services = bt_services; \
+ data.num_services = sizeof(bt_services) / \
+ sizeof(bt_services[0]); \
memcpy(data.pdu_list, pdus, sizeof(pdus)); \
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, args)
+ define_test(name, function, ATT, bt_uuid, NULL, args)

-#define define_test_client(name, function, args...) \
- define_test(name, function, CLIENT, NULL, args)
+#define define_test_client(name, function, bt_services, args...) \
+ define_test(name, function, CLIENT, NULL, bt_services, args)

static bt_uuid_t uuid_16 = {
.type = BT_UUID16,
@@ -209,6 +220,75 @@ static void gatt_debug(const char *str, void *user_data)
g_print("%s%s\n", prefix, str);
}

+static void compare_service(const bt_gatt_service_t *a,
+ const bt_gatt_service_t *b)
+{
+ g_assert(a->primary && b->primary);
+ g_assert(a->start_handle == b->start_handle);
+ g_assert(a->end_handle == b->end_handle);
+ g_assert(memcmp(a->uuid, b->uuid, sizeof(a->uuid)) == 0);
+}
+
+static void compare_descs(const bt_gatt_descriptor_t *a,
+ const bt_gatt_descriptor_t *b)
+{
+ g_assert(a->handle == b->handle);
+ g_assert(memcmp(a->uuid, b->uuid, sizeof(a->uuid)) == 0);
+}
+
+static void compare_chars(const bt_gatt_characteristic_t *a,
+ const bt_gatt_characteristic_t *b)
+{
+ unsigned int i;
+
+ g_assert(a->start_handle == b->start_handle);
+ g_assert(a->end_handle == b->end_handle);
+ g_assert(a->properties == b->properties);
+ g_assert(a->value_handle == b->value_handle);
+ g_assert(a->num_descs == b->num_descs);
+ g_assert(memcmp(a->uuid, b->uuid, sizeof(a->uuid)) == 0);
+
+ for (i = 0; i < a->num_descs; i++)
+ compare_descs(&a->descs[i], &b->descs[i]);
+}
+
+static void client_ready_cb(bool success, uint8_t att_ecode, void *user_data)
+{
+ struct context *context = user_data;
+ const struct test_data *data = context->data;
+ struct bt_gatt_characteristic_iter char_iter;
+ const bt_gatt_characteristic_t *charac;
+ const bt_gatt_service_t *service;
+ struct bt_gatt_service_iter iter;
+ int i, j;
+
+ g_assert(success);
+
+ if (!data->services) {
+ context_quit(context);
+ return;
+ }
+
+ g_assert(bt_gatt_service_iter_init(&iter, context->client));
+ for (i = 0; i < data->num_services; i++) {
+ g_assert(bt_gatt_service_iter_next(&iter, &service));
+ compare_service(service, data->services[i]->service);
+ g_assert(bt_gatt_characteristic_iter_init(&char_iter, service));
+
+ for (j = 0; j < data->services[i]->num_chars; j++) {
+ g_assert(bt_gatt_characteristic_iter_next(&char_iter,
+ &charac));
+ compare_chars(charac, data->services[i]->chars[j]);
+ }
+ g_assert(!bt_gatt_characteristic_iter_next(&char_iter,
+ &charac));
+ }
+
+ g_assert(!bt_gatt_service_iter_next(&iter, &service));
+
+ context_quit(context);
+}
+
static struct context *create_context(uint16_t mtu, gconstpointer data)
{
struct context *context = g_new0(struct context, 1);
@@ -240,6 +320,9 @@ static struct context *create_context(uint16_t mtu, gconstpointer data)
bt_gatt_client_set_debug(context->client, gatt_debug,
"gatt:", NULL);

+ bt_gatt_client_set_ready_handler(context->client,
+ client_ready_cb, context, NULL);
+
bt_att_unref(att);
break;
default:
@@ -362,7 +445,7 @@ int main(int argc, char *argv[])
* Server Configuration.
*/

- define_test_client("/TP/GAC/CL/BV-01-C", test_client,
+ define_test_client("/TP/GAC/CL/BV-01-C", test_client, NULL,
raw_pdu(0x02, 0x00, 0x02));

/*
--
1.9.3


2014-11-06 12:47:08

by Marcin Kraglak

[permalink] [raw]
Subject: [PATCH 3/9] shared/gatt: Fix memory leak in discovery_op_unref

Free services list in discovery_op_unref. If discovery has been
interrupted, services from discovery_op were not pushed to
gatt_client service list, and it caused memory leak.
---
src/shared/gatt-client.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index 8689368..b4f28b2 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
@@ -411,6 +411,8 @@ static void discovery_op_unref(void *data)
if (__sync_sub_and_fetch(&op->ref_count, 1))
return;

+ service_list_clear(&op->result_head, &op->result_tail);
+
free(data);
}

@@ -1140,6 +1142,10 @@ static void init_complete(struct discovery_op *op, bool success,
client->svc_head = op->result_head;
client->svc_tail = op->result_tail;

+ /* Change owner of service list */
+ op->result_head = NULL;
+ op->result_tail = NULL;
+
if (!client->svc_chngd_val_handle) {
client->ready = true;
goto done;
@@ -1164,12 +1170,10 @@ static void init_complete(struct discovery_op *op, bool success,
util_debug(client->debug_callback, client->debug_data,
"Failed to register handler for \"Service Changed\"");

- client->svc_head = client->svc_tail = NULL;
-
fail:
util_debug(client->debug_callback, client->debug_data,
"Failed to initialize gatt-client");
- service_list_clear(&op->result_head, &op->result_tail);
+ service_list_clear(&client->svc_head, &client->svc_head);

done:
if (client->ready_callback)
--
1.9.3


2014-11-06 12:47:07

by Marcin Kraglak

[permalink] [raw]
Subject: [PATCH 2/9] unit/test-gatt: Add TP/GAD/CL/BV-06-C test

Verify that a Generic Attribute Profile client can find all
Descriptors of a specified Characteristic.
---
unit/test-gatt.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)

diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index f343fe6..a2ca5b6 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -334,6 +334,17 @@ static void test_search_chars(gconstpointer data)
execute_context(context);
}

+static void test_search_descs(gconstpointer data)
+{
+ struct context *context = create_context(512, data);
+
+ g_assert(bt_gatt_discover_descriptors(context->att, 0x0013, 0x0016,
+ generic_search_cb,
+ context, NULL));
+
+ execute_context(context);
+}
+
int main(int argc, char *argv[])
{
g_test_init(&argc, &argv, NULL);
@@ -429,5 +440,15 @@ int main(int argc, char *argv[])
raw_pdu(0x08, 0x14, 0x00, 0x20, 0x00, 0x03, 0x28),
raw_pdu(0x01, 0x08, 0x12, 0x00, 0x0a));

+ define_test("/TP/GAD/CL/BV-06-C", test_search_descs, ATT, NULL,
+ raw_pdu(0x02, 0x00, 0x02),
+ raw_pdu(0x03, 0x00, 0x02),
+ raw_pdu(0x04, 0x13, 0x00, 0x16, 0x00),
+ raw_pdu(0x05, 0x01, 0x13, 0x00, 0x02, 0x29, 0x14, 0x00,
+ 0x03, 0x29),
+ raw_pdu(0x04, 0x15, 0x00, 0x16, 0x00),
+ raw_pdu(0x05, 0x01, 0x15, 0x00, 0x04, 0x29, 0x16, 0x00,
+ 0x05, 0x29));
+
return g_test_run();
}
--
1.9.3