2015-01-14 09:19:36

by Jakub Tyszkowski

[permalink] [raw]
Subject: [PATCHv2 0/5] android/tester: GATT tests for various write scenarios

Those are probably corner cases, but PTS can use Service Change ccc descriptor
for its prepare/execute write tests. We should treat this descriptor like any
other and allow multiple write types and report proper errors.

v2 changes:
* fixed partial ccc value storing in prepare write with offset
* minor fixes mentioned by sjanc

Jakub Tyszkowski (5):
android/tester: Add case for GATT prep. and exec. write on ccc descr.
android/tester: Add GATT Server test for invalid value length for ccc
android/tester: Add case for error passing in GATT server responses
android/tester: Add GATT case for Svc. change invalid offset write
android/gatt: Fix not handling service change ccc write execute

android/gatt.c | 55 ++++++++++++--
android/tester-gatt.c | 196 ++++++++++++++++++++++++++++++++++++++++++++++++++
android/tester-main.c | 10 +++
android/tester-main.h | 9 +++
4 files changed, 265 insertions(+), 5 deletions(-)

--
1.9.1



2015-01-14 09:19:39

by Jakub Tyszkowski

[permalink] [raw]
Subject: [PATCHv2 3/5] android/tester: Add case for error passing in GATT server responses

This is to verify proper error passing from user apps.
---
android/tester-gatt.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)

diff --git a/android/tester-gatt.c b/android/tester-gatt.c
index c98791b..e277f64 100644
--- a/android/tester-gatt.c
+++ b/android/tester-gatt.c
@@ -858,6 +858,13 @@ static struct send_resp_data send_resp_data_2 = {
.response = &response_2,
};

+static struct send_resp_data send_resp_data_2_error = {
+ .conn_id = CONN1_ID,
+ .trans_id = TRANS1_ID,
+ .status = GATT_ERR_INVAL_ATTR_VALUE_LEN,
+ .response = &response_2,
+};
+
#define SEARCH_SERVICE_SINGLE_SUCCESS_PDUS \
raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28), \
raw_pdu(0x11, 0x06, 0x01, 0x00, 0x10, 0x00, 0x00, 0x18), \
@@ -3416,6 +3423,53 @@ 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 Server - Send error resp to write char request",
+ 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_server_register_action, &app1_uuid),
+ CALLBACK_STATUS(CB_GATTS_REGISTER_SERVER, BT_STATUS_SUCCESS),
+ ACTION_SUCCESS(gatt_server_add_service_action,
+ &add_service_data_5),
+ CALLBACK_GATTS_SERVICE_ADDED(GATT_STATUS_SUCCESS, APP1_ID,
+ &service_add_1, NULL,
+ &srvc1_handle),
+ ACTION_SUCCESS(gatt_server_add_char_action, &add_char_data_2),
+ CALLBACK_GATTS_CHARACTERISTIC_ADDED(GATT_STATUS_SUCCESS,
+ APP1_ID, &app1_uuid,
+ &srvc1_handle, NULL,
+ &char1_handle),
+ ACTION_SUCCESS(gatt_server_start_srvc_action,
+ &start_srvc_data_2),
+ CALLBACK_GATTS_SERVICE_STARTED(GATT_STATUS_SUCCESS, APP1_ID,
+ &srvc1_handle),
+ ACTION_SUCCESS(bt_start_discovery_action, NULL),
+ CALLBACK_STATE(CB_BT_DISCOVERY_STATE_CHANGED,
+ BT_DISCOVERY_STARTED),
+ CALLBACK_DEVICE_FOUND(prop_emu_remotes_default_le_set, 2),
+ ACTION_SUCCESS(bt_cancel_discovery_action, NULL),
+ ACTION_SUCCESS(gatt_server_connect_action, &app1_conn_req),
+ CALLBACK_GATTS_CONNECTION(GATT_SERVER_CONNECTED,
+ prop_emu_remotes_default_set,
+ CONN1_ID, APP1_ID),
+ PROCESS_DATA(GATT_STATUS_SUCCESS,
+ gatt_remote_send_raw_pdu_action,
+ &att_write_req_op_v, &char1_handle_v,
+ &att_write_req_value_1_v),
+ CALLBACK_GATTS_REQUEST_WRITE(CONN1_ID, TRANS1_ID,
+ prop_emu_remotes_default_set,
+ &char1_handle, 0,
+ sizeof(att_write_req_value_1),
+ true, false,
+ att_write_req_value_1),
+ ACTION_SUCCESS(gatt_server_send_response_action,
+ &send_resp_data_2_error),
+ CALLBACK_ERROR(CB_EMU_ATT_ERROR, GATT_ERR_INVAL_ATTR_VALUE_LEN),
+ ACTION_SUCCESS(bluetooth_disable_action, NULL),
+ CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_OFF),
+ ),
/* This tests embeded ccc */
TEST_CASE_BREDRLE("Gatt Server - Srvc change write req. success",
ACTION_SUCCESS(bluetooth_enable_action, NULL),
--
1.9.1


2015-01-14 09:19:41

by Jakub Tyszkowski

[permalink] [raw]
Subject: [PATCHv2 5/5] android/gatt: Fix not handling service change ccc write execute

This adds prepare and execute write handling on Service Change CCC
descriptor. It also protect CCC from remote sending invalid prepare
write offset and value with invalid length.

PTS can use this embeded service's ccc descriptor if no such descriptors
are added by the user. It tests descriptor writes for both, invalid
offset and invalid value length errors in TC_GAW_SR_BI_27_C and
TC_GAW_SR_BI_34_C respectively.
---
android/gatt.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 50 insertions(+), 5 deletions(-)

diff --git a/android/gatt.c b/android/gatt.c
index b749705..593e5c1 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -171,6 +171,8 @@ struct gatt_device {
struct queue *autoconnect_apps;

struct queue *pending_requests;
+ bool wait_svc_change_execute_write;
+ uint16_t svc_change_ccc;
};

struct app_connection {
@@ -6599,6 +6601,28 @@ static uint8_t write_execute_request(const uint8_t *cmd, uint16_t cmd_len,
uint8_t value;
struct pending_request *data;

+ /* handle embeded ccc */
+ if (dev->wait_svc_change_execute_write) {
+ dev->wait_svc_change_execute_write = false;
+
+ if (!dec_exec_write_req(cmd, cmd_len, &value))
+ return ATT_ECODE_INVALID_PDU;
+
+ if (value)
+ bt_store_gatt_ccc(&dev->bdaddr, dev->svc_change_ccc);
+
+ if (!pending_execute_write()) {
+ size_t mtu;
+ uint16_t len;
+ uint8_t *rsp = g_attrib_get_buffer(dev->attrib, &mtu);
+
+ len = enc_exec_write_resp(rsp);
+ g_attrib_send(dev->attrib, 0, rsp, len, NULL, NULL,
+ NULL);
+ return 0;
+ }
+ }
+
/*
* Check if there was any write prep before.
* TODO: Try to find better error code if possible
@@ -6992,6 +7016,7 @@ static void gatt_srvc_change_write_cb(struct gatt_db_attribute *attrib,
void *user_data)
{
struct gatt_device *dev;
+ uint8_t *prep_val;

dev = find_device_by_addr(bdaddr);
if (!dev) {
@@ -7005,15 +7030,35 @@ static void gatt_srvc_change_write_cb(struct gatt_db_attribute *attrib,
return;
}

- /* 2 octets are expected as CCC value */
- if (len != 2) {
- gatt_db_attribute_write_result(attrib, id,
+ /* Out of bound sanity check */
+ if (offset + len > 2) {
+ if (offset > 1)
+ gatt_db_attribute_write_result(attrib, id,
+ ATT_ECODE_INVALID_OFFSET);
+ else
+ gatt_db_attribute_write_result(attrib, id,
ATT_ECODE_INVAL_ATTR_VALUE_LEN);
return;
}

- /* Set services changed indication value */
- bt_store_gatt_ccc(bdaddr, get_le16(value));
+ switch (opcode) {
+ case ATT_OP_PREP_WRITE_REQ:
+ dev->wait_svc_change_execute_write = true;
+ prep_val = (uint8_t *) &dev->svc_change_ccc;
+
+ memcpy(prep_val + offset, value, len);
+
+ break;
+ default:
+ /* 2 octets are expected as CCC value */
+ if (len != 2)
+ gatt_db_attribute_write_result(attrib, id,
+ ATT_ECODE_INVAL_ATTR_VALUE_LEN);
+
+ /* Set services changed indication value */
+ bt_store_gatt_ccc(bdaddr, get_le16(value));
+ break;
+ }

gatt_db_attribute_write_result(attrib, id, 0);
}
--
1.9.1


2015-01-14 09:19:40

by Jakub Tyszkowski

[permalink] [raw]
Subject: [PATCHv2 4/5] android/tester: Add GATT case for Svc. change invalid offset write

This is to check whether we allow only values with proper length to be
written to Service Change CCC descriptor.
---
android/tester-gatt.c | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)

diff --git a/android/tester-gatt.c b/android/tester-gatt.c
index e277f64..307edf1 100644
--- a/android/tester-gatt.c
+++ b/android/tester-gatt.c
@@ -44,6 +44,7 @@
#define GATT_STATUS_FAILURE 0x00000101
#define GATT_STATUS_INS_AUTH 0x08

+#define GATT_ERR_INVAL_OFFSET 0x07
#define GATT_ERR_INVAL_ATTR_VALUE_LEN 0x0D

#define GATT_SERVER_DISCONNECTED 0
@@ -1107,6 +1108,8 @@ static struct iovec svc_change_ccc_prep_value_v = raw_pdu(0x00, 0x00,
0x00, 0x01);
static struct iovec svc_change_ccc_prep_value_inv_v = raw_pdu(0x00, 0x00, 0x00,
0x00, 0x01);
+static struct iovec svc_change_ccc_prep_offset_inv_v = raw_pdu(0xff, 0xff,
+ 0x00, 0x01);
static struct iovec att_prep_write_exec_v = raw_pdu(0x01);

static void gatt_client_register_action(void)
@@ -3573,6 +3576,38 @@ TEST_CASE_BREDRLE("Gatt Server - Srvc change prep/exec write inv. len.",
ACTION_SUCCESS(bluetooth_disable_action, NULL),
CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_OFF),
),
+TEST_CASE_BREDRLE("Gatt Server - Srvc change prep/exec write inv. off.",
+ 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_server_register_action, &app1_uuid),
+ CALLBACK_STATUS(CB_GATTS_REGISTER_SERVER, BT_STATUS_SUCCESS),
+ ACTION_SUCCESS(bt_start_discovery_action, NULL),
+ CALLBACK_STATE(CB_BT_DISCOVERY_STATE_CHANGED,
+ BT_DISCOVERY_STARTED),
+ CALLBACK_DEVICE_FOUND(prop_emu_remotes_default_le_set, 2),
+ ACTION_SUCCESS(bt_cancel_discovery_action, NULL),
+ ACTION_SUCCESS(gatt_server_connect_action, &app1_conn_req),
+ CALLBACK_GATTS_CONNECTION(GATT_SERVER_CONNECTED,
+ prop_emu_remotes_default_set,
+ CONN1_ID, APP1_ID),
+ /* For CCC we need to be bonded */
+ ACTION_SUCCESS(bt_create_bond_action,
+ &prop_test_remote_ble_bdaddr_req),
+ CALLBACK_BOND_STATE(BT_BOND_STATE_BONDED,
+ &prop_emu_remotes_default_set[0], 1),
+ PROCESS_DATA(GATT_STATUS_SUCCESS,
+ gatt_remote_send_raw_pdu_action,
+ &att_prep_write_req_op_v,
+ &svc_change_ccc_handle_v,
+ &svc_change_ccc_prep_offset_inv_v),
+ CALLBACK_ERROR(CB_EMU_ATT_ERROR, GATT_ERR_INVAL_OFFSET),
+ /* Shutdown */
+ ACTION_SUCCESS(bluetooth_disable_action, NULL),
+ CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_OFF),
+ ),
};

struct queue *get_gatt_tests(void)
--
1.9.1


2015-01-14 09:19:37

by Jakub Tyszkowski

[permalink] [raw]
Subject: [PATCHv2 1/5] android/tester: Add case for GATT prep. and exec. write on ccc descr.

We should support prepare and execute write also on Service Changed
characteristic.
---
android/tester-gatt.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++
android/tester-main.c | 2 ++
android/tester-main.h | 2 ++
3 files changed, 66 insertions(+)

diff --git a/android/tester-gatt.c b/android/tester-gatt.c
index 23c6609..7cb6629 100644
--- a/android/tester-gatt.c
+++ b/android/tester-gatt.c
@@ -34,6 +34,10 @@
#define L2CAP_ATT_WRITE_RSP 0x13
#define L2CAP_ATT_HANDLE_VALUE_NOTIFY 0x1b
#define L2CAP_ATT_HANDLE_VALUE_IND 0x1d
+#define L2CAP_ATT_PREP_WRITE_REQ 0x16
+#define L2CAP_ATT_PREP_WRITE_RSP 0x17
+#define L2CAP_ATT_EXEC_WRITE_REQ 0x18
+#define L2CAP_ATT_EXEC_WRITE_RSP 0x19

#define GATT_STATUS_SUCCESS 0x00000000
#define GATT_STATUS_FAILURE 0x00000101
@@ -1083,10 +1087,16 @@ static struct iovec send_notification_1[] = {
/* att commands define raw pdus */
static struct iovec att_read_req_op_v = raw_pdu(L2CAP_ATT_READ_REQ);
static struct iovec att_write_req_op_v = raw_pdu(L2CAP_ATT_WRITE_REQ);
+static struct iovec att_prep_write_req_op_v = raw_pdu(L2CAP_ATT_PREP_WRITE_REQ);
+static struct iovec att_exec_write_req_op_v = raw_pdu(L2CAP_ATT_EXEC_WRITE_REQ);

static struct iovec svc_change_ccc_handle_v = raw_pdu(0x1a, 0x00);
static struct iovec svc_change_ccc_value_v = raw_pdu(0x00, 0x01);

+static struct iovec svc_change_ccc_prep_value_v = raw_pdu(0x00, 0x00,
+ 0x00, 0x01);
+static struct iovec att_prep_write_exec_v = raw_pdu(0x01);
+
static void gatt_client_register_action(void)
{
struct test_data *data = tester_get_data();
@@ -1618,6 +1628,20 @@ static void gatt_cid_hook_cb(const void *data, uint16_t len, void *user_data)

schedule_callback_verification(step);
break;
+ case L2CAP_ATT_PREP_WRITE_RSP:
+ step = g_new0(struct step, 1);
+
+ step->callback = CB_EMU_PREP_WRITE_RESPONSE;
+
+ schedule_callback_verification(step);
+ break;
+ case L2CAP_ATT_EXEC_WRITE_RSP:
+ step = g_new0(struct step, 1);
+
+ step->callback = CB_EMU_EXEC_WRITE_RESPONSE;
+
+ schedule_callback_verification(step);
+ break;
default:
if (!gatt_pdu || !gatt_pdu->iov_base) {
tester_print("Unknown ATT packet.");
@@ -3412,6 +3436,44 @@ 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 Server - Srvc change prep/exec write success",
+ 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_server_register_action, &app1_uuid),
+ CALLBACK_STATUS(CB_GATTS_REGISTER_SERVER, BT_STATUS_SUCCESS),
+ ACTION_SUCCESS(bt_start_discovery_action, NULL),
+ CALLBACK_STATE(CB_BT_DISCOVERY_STATE_CHANGED,
+ BT_DISCOVERY_STARTED),
+ CALLBACK_DEVICE_FOUND(prop_emu_remotes_default_le_set, 2),
+ ACTION_SUCCESS(bt_cancel_discovery_action, NULL),
+ ACTION_SUCCESS(gatt_server_connect_action, &app1_conn_req),
+ CALLBACK_GATTS_CONNECTION(GATT_SERVER_CONNECTED,
+ prop_emu_remotes_default_set,
+ CONN1_ID, APP1_ID),
+ /* For CCC we need to be bonded */
+ ACTION_SUCCESS(bt_create_bond_action,
+ &prop_test_remote_ble_bdaddr_req),
+ CALLBACK_BOND_STATE(BT_BOND_STATE_BONDED,
+ &prop_emu_remotes_default_set[0], 1),
+ /* Write and receive confirmation */
+ PROCESS_DATA(GATT_STATUS_SUCCESS,
+ gatt_remote_send_raw_pdu_action,
+ &att_prep_write_req_op_v,
+ &svc_change_ccc_handle_v,
+ &svc_change_ccc_prep_value_v),
+ CALLBACK(CB_EMU_PREP_WRITE_RESPONSE),
+ PROCESS_DATA(GATT_STATUS_SUCCESS,
+ gatt_remote_send_raw_pdu_action,
+ &att_exec_write_req_op_v,
+ &att_prep_write_exec_v, NULL),
+ CALLBACK(CB_EMU_EXEC_WRITE_RESPONSE),
+ /* Shutdown */
+ ACTION_SUCCESS(bluetooth_disable_action, NULL),
+ CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_OFF),
+ ),
};

struct queue *get_gatt_tests(void)
diff --git a/android/tester-main.c b/android/tester-main.c
index 336a9a8..1d61cfb 100644
--- a/android/tester-main.c
+++ b/android/tester-main.c
@@ -134,6 +134,8 @@ static struct {
DBG_CB(CB_EMU_VALUE_NOTIFICATION),
DBG_CB(CB_EMU_READ_RESPONSE),
DBG_CB(CB_EMU_WRITE_RESPONSE),
+ DBG_CB(CB_EMU_PREP_WRITE_RESPONSE),
+ DBG_CB(CB_EMU_EXEC_WRITE_RESPONSE),
};

static gboolean check_callbacks_called(gpointer user_data)
diff --git a/android/tester-main.h b/android/tester-main.h
index e35feec..ec9a20f 100644
--- a/android/tester-main.h
+++ b/android/tester-main.h
@@ -548,6 +548,8 @@ typedef enum {
CB_EMU_VALUE_NOTIFICATION,
CB_EMU_READ_RESPONSE,
CB_EMU_WRITE_RESPONSE,
+ CB_EMU_PREP_WRITE_RESPONSE,
+ CB_EMU_EXEC_WRITE_RESPONSE,
} expected_bt_callback_t;

struct test_data {
--
1.9.1


2015-01-14 09:19:38

by Jakub Tyszkowski

[permalink] [raw]
Subject: [PATCHv2 2/5] android/tester: Add GATT Server test for invalid value length for ccc

This is to verify that we check for the length of value that is to be
written to Service Change CCC descriptor.
---
android/tester-gatt.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
android/tester-main.c | 8 ++++++++
android/tester-main.h | 7 +++++++
3 files changed, 60 insertions(+)

diff --git a/android/tester-gatt.c b/android/tester-gatt.c
index 7cb6629..c98791b 100644
--- a/android/tester-gatt.c
+++ b/android/tester-gatt.c
@@ -26,6 +26,7 @@

#define ATT_HANDLE_SIZE 2

+#define L2CAP_ATT_ERROR 0x01
#define L2CAP_ATT_EXCHANGE_MTU_REQ 0x02
#define L2CAP_ATT_EXCHANGE_MTU_RSP 0x03
#define L2CAP_ATT_READ_REQ 0x0a
@@ -43,6 +44,8 @@
#define GATT_STATUS_FAILURE 0x00000101
#define GATT_STATUS_INS_AUTH 0x08

+#define GATT_ERR_INVAL_ATTR_VALUE_LEN 0x0D
+
#define GATT_SERVER_DISCONNECTED 0
#define GATT_SERVER_CONNECTED 1

@@ -1095,6 +1098,8 @@ static struct iovec svc_change_ccc_value_v = raw_pdu(0x00, 0x01);

static struct iovec svc_change_ccc_prep_value_v = raw_pdu(0x00, 0x00,
0x00, 0x01);
+static struct iovec svc_change_ccc_prep_value_inv_v = raw_pdu(0x00, 0x00, 0x00,
+ 0x00, 0x01);
static struct iovec att_prep_write_exec_v = raw_pdu(0x01);

static void gatt_client_register_action(void)
@@ -1585,6 +1590,14 @@ static void gatt_cid_hook_cb(const void *data, uint16_t len, void *user_data)
tester_debug("Received att pdu with opcode 0x%02x", pdu[0]);

switch (pdu[0]) {
+ case L2CAP_ATT_ERROR:
+ step = g_new0(struct step, 1);
+
+ step->callback = CB_EMU_ATT_ERROR;
+ step->callback_result.error = pdu[4];
+
+ schedule_callback_verification(step);
+ break;
case L2CAP_ATT_EXCHANGE_MTU_REQ:
tester_print("Exchange MTU request received.");

@@ -3474,6 +3487,38 @@ TEST_CASE_BREDRLE("Gatt Server - Srvc change prep/exec write success",
ACTION_SUCCESS(bluetooth_disable_action, NULL),
CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_OFF),
),
+TEST_CASE_BREDRLE("Gatt Server - Srvc change prep/exec write inv. len.",
+ 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_server_register_action, &app1_uuid),
+ CALLBACK_STATUS(CB_GATTS_REGISTER_SERVER, BT_STATUS_SUCCESS),
+ ACTION_SUCCESS(bt_start_discovery_action, NULL),
+ CALLBACK_STATE(CB_BT_DISCOVERY_STATE_CHANGED,
+ BT_DISCOVERY_STARTED),
+ CALLBACK_DEVICE_FOUND(prop_emu_remotes_default_le_set, 2),
+ ACTION_SUCCESS(bt_cancel_discovery_action, NULL),
+ ACTION_SUCCESS(gatt_server_connect_action, &app1_conn_req),
+ CALLBACK_GATTS_CONNECTION(GATT_SERVER_CONNECTED,
+ prop_emu_remotes_default_set,
+ CONN1_ID, APP1_ID),
+ /* For CCC we need to be bonded */
+ ACTION_SUCCESS(bt_create_bond_action,
+ &prop_test_remote_ble_bdaddr_req),
+ CALLBACK_BOND_STATE(BT_BOND_STATE_BONDED,
+ &prop_emu_remotes_default_set[0], 1),
+ PROCESS_DATA(GATT_STATUS_SUCCESS,
+ gatt_remote_send_raw_pdu_action,
+ &att_prep_write_req_op_v,
+ &svc_change_ccc_handle_v,
+ &svc_change_ccc_prep_value_inv_v),
+ CALLBACK_ERROR(CB_EMU_ATT_ERROR, GATT_ERR_INVAL_ATTR_VALUE_LEN),
+ /* Shutdown */
+ ACTION_SUCCESS(bluetooth_disable_action, NULL),
+ CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_OFF),
+ ),
};

struct queue *get_gatt_tests(void)
diff --git a/android/tester-main.c b/android/tester-main.c
index 1d61cfb..2cc0c18 100644
--- a/android/tester-main.c
+++ b/android/tester-main.c
@@ -126,6 +126,7 @@ static struct {
DBG_CB(CB_MAP_CLIENT_REMOTE_MAS_INSTANCES),

/* Emulator callbacks */
+ DBG_CB(CB_EMU_ATT_ERROR),
DBG_CB(CB_EMU_CONFIRM_SEND_DATA),
DBG_CB(CB_EMU_ENCRYPTION_ENABLED),
DBG_CB(CB_EMU_ENCRYPTION_DISABLED),
@@ -1038,6 +1039,13 @@ static bool match_data(struct step *step)
return false;
}

+ if (exp->callback_result.error != step->callback_result.error) {
+ tester_debug("Err mismatch: %d vs %d",
+ exp->callback_result.error,
+ step->callback_result.error);
+ return false;
+ }
+
if (exp->store_srvc_handle)
memcpy(exp->store_srvc_handle,
step->callback_result.srvc_handle,
diff --git a/android/tester-main.h b/android/tester-main.h
index ec9a20f..c266359 100644
--- a/android/tester-main.h
+++ b/android/tester-main.h
@@ -106,6 +106,11 @@ struct pdu_set {
.callback_result.status = cb_res, \
}

+#define CALLBACK_ERROR(cb, cb_err) { \
+ .callback = cb, \
+ .callback_result.error = cb_err, \
+ }
+
#define CALLBACK_ADAPTER_PROPS(props, prop_cnt) { \
.callback = CB_BT_ADAPTER_PROPERTIES, \
.callback_result.properties = props, \
@@ -540,6 +545,7 @@ typedef enum {
CB_MAP_CLIENT_REMOTE_MAS_INSTANCES,

/* Emulator callbacks */
+ CB_EMU_ATT_ERROR,
CB_EMU_CONFIRM_SEND_DATA,
CB_EMU_ENCRYPTION_ENABLED,
CB_EMU_ENCRYPTION_DISABLED,
@@ -679,6 +685,7 @@ struct bt_callback_data {
uint8_t *value;
bool need_rsp;
bool is_prep;
+ uint8_t error;

btpan_control_state_t ctrl_state;
btpan_connection_state_t conn_state;
--
1.9.1