Add support for search_result_cb() and search_complete_cb()
in GATT tester.
---
android/tester-main.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++--
android/tester-main.h | 14 +++++++++++++
2 files changed, 68 insertions(+), 2 deletions(-)
diff --git a/android/tester-main.c b/android/tester-main.c
index 369a943..a825035 100644
--- a/android/tester-main.c
+++ b/android/tester-main.c
@@ -395,6 +395,18 @@ static int verify_property(bt_property_t *exp_props, int exp_num_props,
* Check each test case step if test case expected
* data is set and match it with expected result.
*/
+
+static bool verify_services(btgatt_srvc_id_t *a, btgatt_srvc_id_t *b)
+{
+ if (a->is_primary != b->is_primary)
+ return false;
+
+ if (memcmp(&a->id.uuid, &b->id.uuid, sizeof(bt_uuid_t)))
+ return false;
+
+ return true;
+}
+
static bool match_data(struct step *step)
{
struct test_data *data = tester_get_data();
@@ -529,6 +541,13 @@ static bool match_data(struct step *step)
tester_debug("Gatt properties don't match");
return false;
}
+
+ if (exp->callback_result.service &&
+ !verify_services(step->callback_result.service,
+ exp->callback_result.service)) {
+ tester_debug("Gatt service doesn't match");
+ return false;
+ }
}
return true;
@@ -613,6 +632,9 @@ static void destroy_callback_step(void *data)
if (step->callback_result.properties)
free_properties(step);
+ if (step->callback_result.service)
+ free(step->callback_result.service);
+
g_free(step);
g_atomic_int_dec_and_test(&scheduled_cbacks_num);
}
@@ -1030,6 +1052,27 @@ static void gattc_listen_cb(int status, int server_if)
schedule_callback_call(step);
}
+static void gattc_search_result_cb(int conn_id, btgatt_srvc_id_t *srvc_id)
+{
+ struct step *step = g_new0(struct step, 1);
+
+ step->callback = CB_GATTC_SEARCH_RESULT;
+ step->callback_result.conn_id = conn_id;
+ step->callback_result.service = g_memdup(srvc_id, sizeof(*srvc_id));
+
+ schedule_callback_call(step);
+}
+
+static void gattc_search_complete_cb(int conn_id, int status)
+{
+ struct step *step = g_new0(struct step, 1);
+
+ step->callback = CB_GATTC_SEARCH_COMPLETE;
+ step->callback_result.conn_id = conn_id;
+
+ schedule_callback_call(step);
+}
+
static void pan_control_state_cb(btpan_control_state_t state,
bt_status_t error, int local_role,
const char *ifname)
@@ -1130,8 +1173,8 @@ static const btgatt_client_callbacks_t btgatt_client_callbacks = {
.scan_result_cb = gattc_scan_result_cb,
.open_cb = gattc_connect_cb,
.close_cb = gattc_disconnect_cb,
- .search_complete_cb = NULL,
- .search_result_cb = NULL,
+ .search_complete_cb = gattc_search_complete_cb,
+ .search_result_cb = gattc_search_result_cb,
.get_characteristic_cb = NULL,
.get_descriptor_cb = NULL,
.get_included_service_cb = NULL,
@@ -1236,6 +1279,12 @@ static bool setup_base(struct test_data *data)
if (!(data->steps = queue_new()))
return false;
+ data->pdus = queue_new();
+ if (!data->pdus) {
+ queue_destroy(data->steps, NULL);
+ return false;
+ }
+
return true;
}
@@ -1479,6 +1528,9 @@ static void teardown(const void *test_data)
queue_destroy(data->steps, NULL);
data->steps = NULL;
+ queue_destroy(data->pdus, NULL);
+ data->pdus = NULL;
+
if (data->if_gatt) {
data->if_gatt->cleanup();
data->if_gatt = NULL;
diff --git a/android/tester-main.h b/android/tester-main.h
index ad87878..cc96975 100644
--- a/android/tester-main.h
+++ b/android/tester-main.h
@@ -140,6 +140,17 @@
.callback_result.client_id = cb_client_id, \
}
+#define CALLBACK_GATTC_SEARCH_RESULT(cb_conn_id, cb_service) { \
+ .callback = CB_GATTC_SEARCH_RESULT, \
+ .callback_result.conn_id = cb_conn_id, \
+ .callback_result.service = cb_service \
+ }
+
+#define CALLBACK_GATTC_SEARCH_COMPLETE(cb_res, cb_conn_id) { \
+ .callback = CB_GATTC_SEARCH_COMPLETE, \
+ .callback_result.conn_id = cb_conn_id \
+ }
+
#define CALLBACK_GATTC_DISCONNECT(cb_res, cb_prop, cb_conn_id, cb_client_id) { \
.callback = CB_GATTC_CLOSE, \
.callback_result.status = cb_res, \
@@ -315,6 +326,8 @@ struct test_data {
guint signalfd;
uint16_t mgmt_index;
pid_t bluetoothd_pid;
+
+ struct queue *pdus;
};
/*
@@ -372,6 +385,7 @@ struct bt_callback_data {
int client_id;
int conn_id;
+ btgatt_srvc_id_t *service;
btpan_control_state_t ctrl_state;
btpan_connection_state_t conn_state;
--
1.9.3
It tests searching Primary Services.
---
android/tester-gatt.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 122 insertions(+), 1 deletion(-)
diff --git a/android/tester-gatt.c b/android/tester-gatt.c
index 1d66309..5b43a32 100644
--- a/android/tester-gatt.c
+++ b/android/tester-gatt.c
@@ -33,8 +33,23 @@
#define CONN1_ID 1
#define CONN2_ID 2
+#define data(args...) ((const unsigned char[]) { args })
+
+#define raw_pdu(args...) \
+ { \
+ .data = data(args), \
+ .size = sizeof(data(args)), \
+ }
+
+#define end_pdu { .data = NULL }
+
static struct queue *list; /* List of gatt test cases */
+struct pdu {
+ const uint8_t *data;
+ uint16_t size;
+};
+
static bt_uuid_t client_app_uuid = {
.uu = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
@@ -53,6 +68,11 @@ struct gatt_connect_data {
const int conn_id;
};
+struct gatt_search_service_data {
+ const int conn_id;
+ bt_uuid_t *filter_uuid;
+};
+
static bt_uuid_t client2_app_uuid = {
.uu = { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 },
@@ -92,9 +112,28 @@ static struct gatt_connect_data client2_conn_req = {
.conn_id = CONN2_ID,
};
+static struct gatt_search_service_data search_services_1 = {
+ .conn_id = CONN1_ID,
+ .filter_uuid = NULL,
+};
+
static const uint8_t exchange_mtu_req_pdu[] = { 0x02, 0xa0, 0x02 };
static const uint8_t exchange_mtu_resp_pdu[] = { 0x03, 0xa0, 0x02 };
+static btgatt_srvc_id_t service_1 = {
+ .is_primary = true,
+ .id.uuid.uu = {0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00}
+};
+
+static struct pdu search_service[] = {
+ raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
+ raw_pdu(0x11, 0x06, 0x01, 0x00, 0x10, 0x00, 0x00, 0x18),
+ raw_pdu(0x10, 0x11, 0x00, 0xff, 0xff, 0x00, 0x28),
+ raw_pdu(0x01, 0x08, 0x11, 0x00, 0x0a),
+ end_pdu
+};
+
static void gatt_client_register_action(void)
{
struct test_data *data = tester_get_data();
@@ -212,6 +251,7 @@ static void gatt_cid_hook_cb(const void *data, uint16_t len, void *user_data)
struct bthost *bthost = hciemu_client_get_host(t_data->hciemu);
struct emu_cid_data *cid_data = user_data;
const uint8_t *pdu = data;
+ struct pdu *gatt_pdu = queue_peek_head(t_data->pdus);
switch (pdu[0]) {
case L2CAP_ATT_EXCHANGE_MTU_REQ:
@@ -228,7 +268,29 @@ static void gatt_cid_hook_cb(const void *data, uint16_t len, void *user_data)
break;
default:
- tester_print("Unknown ATT packet.");
+ if (!gatt_pdu || !gatt_pdu->data) {
+ tester_print("Unknown ATT packet.");
+ break;
+ }
+
+ if (gatt_pdu->size != len) {
+ tester_print("Size of incoming frame is not valid");
+ tester_print("Expected size = %d incoming size = %d",
+ gatt_pdu->size, len);
+ break;
+ }
+
+ if (memcmp(gatt_pdu->data, data, len)) {
+ tester_print("Incoming data mismatch");
+ break;
+ }
+ queue_pop_head(t_data->pdus);
+ gatt_pdu = queue_pop_head(t_data->pdus);
+ if (!gatt_pdu->data)
+ break;
+
+ bthost_send_cid(bthost, cid_data->handle, cid_data->cid,
+ gatt_pdu->data, gatt_pdu->size);
break;
}
@@ -286,6 +348,23 @@ static void emu_remote_connect_hci_action(void)
schedule_action_verification(step);
}
+static void gatt_client_search_services(void)
+{
+ struct test_data *data = tester_get_data();
+ struct step *current_data_step = queue_peek_head(data->steps);
+ struct step *step = g_new0(struct step, 1);
+ struct gatt_search_service_data *search_data;
+ int status;
+
+ search_data = current_data_step->set_data;
+
+ status = data->if_gatt->client->search_service(search_data->conn_id,
+ search_data->filter_uuid);
+ step->action_status = status;
+
+ schedule_action_verification(step);
+}
+
static void emu_remote_disconnect_hci_action(void)
{
struct test_data *data = tester_get_data();
@@ -299,6 +378,23 @@ static void emu_remote_disconnect_hci_action(void)
schedule_action_verification(step);
}
+static void init_pdus(void)
+{
+ struct test_data *data = tester_get_data();
+ struct step *current_data_step = queue_peek_head(data->steps);
+ struct step *step = g_new0(struct step, 1);
+ struct pdu *pdu = current_data_step->set_data;
+
+ while (pdu->data) {
+ queue_push_tail(data->pdus, pdu);
+ pdu++;
+ }
+
+ step->action_status = BT_STATUS_SUCCESS;
+
+ schedule_action_verification(step);
+}
+
static struct test_case test_cases[] = {
TEST_CASE_BREDRLE("Gatt Init",
ACTION_SUCCESS(dummy_action, NULL),
@@ -487,6 +583,31 @@ static struct test_case test_cases[] = {
ACTION_SUCCESS(bluetooth_disable_action, NULL),
CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_OFF),
),
+ TEST_CASE_BREDRLE("Gatt Client - Search Service",
+ ACTION_SUCCESS(init_pdus, search_service),
+ ACTION_SUCCESS(bluetooth_enable_action, NULL),
+ CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_ON),
+ ACTION_SUCCESS(emu_setup_powered_remote_action, NULL),
+ ACTION_SUCCESS(emu_set_ssp_mode_action, NULL),
+ ACTION_SUCCESS(emu_set_connect_cb_action, gatt_conn_cb),
+ ACTION_SUCCESS(gatt_client_register_action, &client_app_uuid),
+ CALLBACK_STATUS(CB_GATTC_REGISTER_CLIENT, BT_STATUS_SUCCESS),
+ ACTION_SUCCESS(gatt_client_start_scan_action,
+ INT_TO_PTR(CLIENT1_ID)),
+ CLLBACK_GATTC_SCAN_RES(prop_emu_remotes_default_set, 1, TRUE),
+ ACTION_SUCCESS(gatt_client_stop_scan_action,
+ INT_TO_PTR(CLIENT1_ID)),
+ ACTION_SUCCESS(gatt_client_connect_action,
+ &client1_conn_req),
+ CALLBACK_GATTC_CONNECT(GATT_STATUS_SUCCESS,
+ prop_emu_remotes_default_set,
+ CONN1_ID, CLIENT1_ID),
+ ACTION_SUCCESS(gatt_client_search_services, &search_services_1),
+ CALLBACK_GATTC_SEARCH_RESULT(CONN1_ID, &service_1),
+ CALLBACK_GATTC_SEARCH_COMPLETE(GATT_STATUS_SUCCESS, CONN1_ID),
+ ACTION_SUCCESS(bluetooth_disable_action, NULL),
+ CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_OFF),
+ ),
};
struct queue *get_gatt_tests(void)
--
1.9.3