Handles are only 2 bytes in size. We should use uint16_t to be able to
safely cast iovec with such handle to uint16_t and vice versa.
---
android/tester-gatt.c | 28 ++++++++++++++--------------
android/tester-main.h | 16 ++++++++--------
2 files changed, 22 insertions(+), 22 deletions(-)
diff --git a/android/tester-gatt.c b/android/tester-gatt.c
index f6b0492..f4d22fd 100644
--- a/android/tester-gatt.c
+++ b/android/tester-gatt.c
@@ -81,9 +81,9 @@
static struct queue *list; /* List of gatt test cases */
-static int srvc1_handle;
-static int inc_srvc1_handle;
-static int char1_handle;
+static uint16_t srvc1_handle;
+static uint16_t inc_srvc1_handle;
+static uint16_t char1_handle;
struct set_att_data {
char *to;
@@ -92,7 +92,7 @@ struct set_att_data {
};
struct att_write_req_data {
- int *attr_handle;
+ uint16_t *attr_handle;
uint8_t *value;
};
@@ -189,12 +189,12 @@ struct add_service_data {
struct add_included_service_data {
int app_id;
- int *inc_srvc_handle;
- int *srvc_handle;
+ uint16_t *inc_srvc_handle;
+ uint16_t *srvc_handle;
};
struct add_char_data {
int app_id;
- int *srvc_handle;
+ uint16_t *srvc_handle;
bt_uuid_t *uuid;
int properties;
int permissions;
@@ -202,30 +202,30 @@ struct add_char_data {
struct add_desc_data {
int app_id;
- int *srvc_handle;
+ uint16_t *srvc_handle;
bt_uuid_t *uuid;
int permissions;
};
struct start_srvc_data {
int app_id;
- int *srvc_handle;
+ uint16_t *srvc_handle;
int transport;
};
struct stop_srvc_data {
int app_id;
- int *srvc_handle;
+ uint16_t *srvc_handle;
};
struct delete_srvc_data {
int app_id;
- int *srvc_handle;
+ uint16_t *srvc_handle;
};
struct send_indication_data {
int app_id;
- int *attr_handle;
+ uint16_t *attr_handle;
int conn_id;
int len;
int confirm;
@@ -531,7 +531,7 @@ static struct add_service_data add_sec_service_data_1 = {
.num_handles = 1
};
-static int srvc_bad_handle = -1;
+static uint16_t srvc_bad_handle = 0xffff;
static struct add_included_service_data add_inc_service_data_1 = {
.app_id = APP1_ID,
@@ -634,7 +634,7 @@ static struct delete_srvc_data delete_bad_srvc_data_1 = {
.srvc_handle = &srvc_bad_handle
};
-static int srvc_indication_handle_1 = 0x01;
+static uint16_t srvc_indication_handle_1 = 0x01;
static struct send_indication_data send_indication_data_1 = {
.app_id = APP1_ID,
diff --git a/android/tester-main.h b/android/tester-main.h
index dc1a2bb..7fe73fe 100644
--- a/android/tester-main.h
+++ b/android/tester-main.h
@@ -651,11 +651,11 @@ struct bt_callback_data {
int offset;
bool is_long;
int connected;
- int *attr_handle;
- int *srvc_handle;
- int *inc_srvc_handle;
- int *char_handle;
- int *desc_handle;
+ uint16_t *attr_handle;
+ uint16_t *srvc_handle;
+ uint16_t *inc_srvc_handle;
+ uint16_t *char_handle;
+ uint16_t *desc_handle;
btgatt_srvc_id_t *service;
btgatt_gatt_id_t *characteristic;
btgatt_gatt_id_t *descriptor;
@@ -709,9 +709,9 @@ struct step {
void *set_data_to;
int set_data_len;
- int *store_srvc_handle;
- int *store_char_handle;
- int *store_desc_handle;
+ uint16_t *store_srvc_handle;
+ uint16_t *store_char_handle;
+ uint16_t *store_desc_handle;
};
struct test_case {
--
1.9.1
Hi Jakub,
On Thursday 08 of January 2015 10:17:39 Jakub Tyszkowski wrote:
> Handles are only 2 bytes in size. We should use uint16_t to be able to
> safely cast iovec with such handle to uint16_t and vice versa.
> ---
> android/tester-gatt.c | 28 ++++++++++++++--------------
> android/tester-main.h | 16 ++++++++--------
> 2 files changed, 22 insertions(+), 22 deletions(-)
>
> diff --git a/android/tester-gatt.c b/android/tester-gatt.c
> index f6b0492..f4d22fd 100644
> --- a/android/tester-gatt.c
> +++ b/android/tester-gatt.c
> @@ -81,9 +81,9 @@
>
> static struct queue *list; /* List of gatt test cases */
>
> -static int srvc1_handle;
> -static int inc_srvc1_handle;
> -static int char1_handle;
> +static uint16_t srvc1_handle;
> +static uint16_t inc_srvc1_handle;
> +static uint16_t char1_handle;
>
> struct set_att_data {
> char *to;
> @@ -92,7 +92,7 @@ struct set_att_data {
> };
>
> struct att_write_req_data {
> - int *attr_handle;
> + uint16_t *attr_handle;
> uint8_t *value;
> };
>
> @@ -189,12 +189,12 @@ struct add_service_data {
>
> struct add_included_service_data {
> int app_id;
> - int *inc_srvc_handle;
> - int *srvc_handle;
> + uint16_t *inc_srvc_handle;
> + uint16_t *srvc_handle;
> };
> struct add_char_data {
> int app_id;
> - int *srvc_handle;
> + uint16_t *srvc_handle;
> bt_uuid_t *uuid;
> int properties;
> int permissions;
> @@ -202,30 +202,30 @@ struct add_char_data {
>
> struct add_desc_data {
> int app_id;
> - int *srvc_handle;
> + uint16_t *srvc_handle;
> bt_uuid_t *uuid;
> int permissions;
> };
>
> struct start_srvc_data {
> int app_id;
> - int *srvc_handle;
> + uint16_t *srvc_handle;
> int transport;
> };
>
> struct stop_srvc_data {
> int app_id;
> - int *srvc_handle;
> + uint16_t *srvc_handle;
> };
>
> struct delete_srvc_data {
> int app_id;
> - int *srvc_handle;
> + uint16_t *srvc_handle;
> };
>
> struct send_indication_data {
> int app_id;
> - int *attr_handle;
> + uint16_t *attr_handle;
> int conn_id;
> int len;
> int confirm;
> @@ -531,7 +531,7 @@ static struct add_service_data add_sec_service_data_1 = {
> .num_handles = 1
> };
>
> -static int srvc_bad_handle = -1;
> +static uint16_t srvc_bad_handle = 0xffff;
>
> static struct add_included_service_data add_inc_service_data_1 = {
> .app_id = APP1_ID,
> @@ -634,7 +634,7 @@ static struct delete_srvc_data delete_bad_srvc_data_1 = {
> .srvc_handle = &srvc_bad_handle
> };
>
> -static int srvc_indication_handle_1 = 0x01;
> +static uint16_t srvc_indication_handle_1 = 0x01;
>
> static struct send_indication_data send_indication_data_1 = {
> .app_id = APP1_ID,
> diff --git a/android/tester-main.h b/android/tester-main.h
> index dc1a2bb..7fe73fe 100644
> --- a/android/tester-main.h
> +++ b/android/tester-main.h
> @@ -651,11 +651,11 @@ struct bt_callback_data {
> int offset;
> bool is_long;
> int connected;
> - int *attr_handle;
> - int *srvc_handle;
> - int *inc_srvc_handle;
> - int *char_handle;
> - int *desc_handle;
> + uint16_t *attr_handle;
> + uint16_t *srvc_handle;
> + uint16_t *inc_srvc_handle;
> + uint16_t *char_handle;
> + uint16_t *desc_handle;
> btgatt_srvc_id_t *service;
> btgatt_gatt_id_t *characteristic;
> btgatt_gatt_id_t *descriptor;
> @@ -709,9 +709,9 @@ struct step {
> void *set_data_to;
> int set_data_len;
>
> - int *store_srvc_handle;
> - int *store_char_handle;
> - int *store_desc_handle;
> + uint16_t *store_srvc_handle;
> + uint16_t *store_char_handle;
> + uint16_t *store_desc_handle;
> };
>
> struct test_case {
>
Patches 1-5 applied, thanks.
--
Best regards,
Szymon Janc
Hi Jakub,
On Thursday 08 of January 2015 10:17:49 Jakub Tyszkowski wrote:
> Protect CCC from remote sending invalid prepare write offset.
>
> We are not using offset value in the code right now, but there is a test
> case in PTS that expects this error to be send. PTS can use this embeded
> service's ccc descriptor if no such descriptors are added by the user.
Please mention affected PTS test name.
> ---
> android/gatt.c | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/android/gatt.c b/android/gatt.c
> index c00eb9e..70b8a00 100644
> --- a/android/gatt.c
> +++ b/android/gatt.c
> @@ -7029,6 +7029,12 @@ static void gatt_srvc_change_write_cb(struct gatt_db_attribute *attrib,
> return;
> }
>
> + if (offset > 1) {
> + gatt_db_attribute_write_result(attrib, id,
> + ATT_ECODE_INVALID_OFFSET);
> + return;
Indentation is wrong here.
> + }
> +
> /* 2 octets are expected as CCC value */
> if (len != 2) {
> gatt_db_attribute_write_result(attrib, id,
>
--
Best regards,
Szymon Janc
Hi Jakub,
On Thursday 08 of January 2015 10:17:45 Jakub Tyszkowski wrote:
> This adds prepare and execute write handling on Service Change CCC
> descriptor.
> ---
> android/gatt.c | 36 ++++++++++++++++++++++++++++++++++--
> 1 file changed, 34 insertions(+), 2 deletions(-)
>
> diff --git a/android/gatt.c b/android/gatt.c
> index b749705..c00eb9e 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) {
> + uint8_t flags;
> +
> + dec_exec_write_req(cmd, cmd_len, &flags);
This could fail so we should check it, otherwise we might use garbage flags.
> + dev->wait_svc_change_execute_write = false;
> +
> + if (!!flags)
This !! is not needed here.
> + bt_store_gatt_ccc(&dev->bdaddr, dev->svc_change_ccc);
> +
> + if (!pending_execute_write()) {
> + size_t mtu;
> + uint16_t len = 0;
This initialization is not needed.
> + 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
> @@ -7012,8 +7036,16 @@ static void gatt_srvc_change_write_cb(struct gatt_db_attribute *attrib,
> 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;
> + dev->svc_change_ccc = get_le16(value);
> + break;
> + default:
> + /* Set services changed indication value */
> + bt_store_gatt_ccc(bdaddr, get_le16(value));
> + break;
> + }
>
> gatt_db_attribute_write_result(attrib, id, 0);
> }
>
--
Best regards,
Szymon Janc
Hi Jakub,
On Thursday 08 of January 2015 10:17:44 Jakub Tyszkowski wrote:
> 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..ab8497b 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,
Line over 80 characters.
> + 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 {
>
--
Best regards,
Szymon Janc
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 6226018..5c5c8d1 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
Protect CCC from remote sending invalid prepare write offset.
We are not using offset value in the code right now, but there is a test
case in PTS that expects this error to be send. PTS can use this embeded
service's ccc descriptor if no such descriptors are added by the user.
---
android/gatt.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/android/gatt.c b/android/gatt.c
index c00eb9e..70b8a00 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -7029,6 +7029,12 @@ static void gatt_srvc_change_write_cb(struct gatt_db_attribute *attrib,
return;
}
+ if (offset > 1) {
+ gatt_db_attribute_write_result(attrib, id,
+ ATT_ECODE_INVALID_OFFSET);
+ return;
+ }
+
/* 2 octets are expected as CCC value */
if (len != 2) {
gatt_db_attribute_write_result(attrib, id,
--
1.9.1
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 ab8497b..fca9d05 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
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 fca9d05..6226018 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
This adds prepare and execute write handling on Service Change CCC
descriptor.
---
android/gatt.c | 36 ++++++++++++++++++++++++++++++++++--
1 file changed, 34 insertions(+), 2 deletions(-)
diff --git a/android/gatt.c b/android/gatt.c
index b749705..c00eb9e 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) {
+ uint8_t flags;
+
+ dec_exec_write_req(cmd, cmd_len, &flags);
+ dev->wait_svc_change_execute_write = false;
+
+ if (!!flags)
+ bt_store_gatt_ccc(&dev->bdaddr, dev->svc_change_ccc);
+
+ if (!pending_execute_write()) {
+ size_t mtu;
+ uint16_t len = 0;
+ 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
@@ -7012,8 +7036,16 @@ static void gatt_srvc_change_write_cb(struct gatt_db_attribute *attrib,
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;
+ dev->svc_change_ccc = get_le16(value);
+ break;
+ default:
+ /* 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
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..ab8497b 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
This tests if Service Changed CCC descriptor write request is properly
handled.
---
android/tester-gatt.c | 42 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/android/tester-gatt.c b/android/tester-gatt.c
index 644e204..23c6609 100644
--- a/android/tester-gatt.c
+++ b/android/tester-gatt.c
@@ -264,6 +264,12 @@ static bt_property_t prop_emu_remotes_default_le_set[] = {
&emu_remote_ble_device_type },
};
+static struct bt_action_data prop_test_remote_ble_bdaddr_req = {
+ .addr = &emu_remote_bdaddr_val,
+ .prop_type = BT_PROPERTY_BDADDR,
+ .prop = &prop_emu_remotes_default_set[0],
+};
+
static bt_scan_mode_t setprop_scan_mode_conn_val =
BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE;
@@ -1078,6 +1084,9 @@ static struct iovec send_notification_1[] = {
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 svc_change_ccc_handle_v = raw_pdu(0x1a, 0x00);
+static struct iovec svc_change_ccc_value_v = raw_pdu(0x00, 0x01);
+
static void gatt_client_register_action(void)
{
struct test_data *data = tester_get_data();
@@ -3370,6 +3379,39 @@ static struct test_case test_cases[] = {
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),
+ 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_write_req_op_v, &svc_change_ccc_handle_v,
+ &svc_change_ccc_value_v),
+ CALLBACK(CB_EMU_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)
--
1.9.1
This simplifies sending pdus which are made of header ond few other parts
by using multiple iovectors instead of copying buffers and aggregating
data in some additional structures.
---
android/tester-gatt.c | 80 ++++++++++++---------------------------------------
1 file changed, 18 insertions(+), 62 deletions(-)
diff --git a/android/tester-gatt.c b/android/tester-gatt.c
index a8dbd35..644e204 100644
--- a/android/tester-gatt.c
+++ b/android/tester-gatt.c
@@ -85,6 +85,11 @@ static uint16_t srvc1_handle;
static uint16_t inc_srvc1_handle;
static uint16_t char1_handle;
+static struct iovec char1_handle_v = {
+ .iov_base = &char1_handle,
+ .iov_len = sizeof(char1_handle),
+};
+
struct set_att_data {
char *to;
char *from;
@@ -109,6 +114,10 @@ static bt_uuid_t app2_uuid = {
static uint8_t value_1[] = {0x01};
static uint8_t att_write_req_value_1[] = {0x00, 0x01, 0x02, 0x03};
+static struct iovec att_write_req_value_1_v = {
+ .iov_base = att_write_req_value_1,
+ .iov_len = sizeof(att_write_req_value_1),
+};
struct gatt_connect_data {
const int app_id;
@@ -1065,59 +1074,9 @@ static struct iovec send_notification_1[] = {
end_pdu
};
-static struct att_write_req_data att_write_req_data_1 = {
- .attr_handle = &char1_handle,
- .value = att_write_req_value_1,
-};
-
/* att commands define raw pdus */
-static struct iovec att_read_req = raw_pdu(0x0a, 0x00, 0x00);
-static struct iovec att_write_req_1 = raw_pdu(0x12, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00);
-
-static void gatt_att_pdu_modify(void)
-{
- struct test_data *data = tester_get_data();
- struct step *current_data_step = queue_peek_head(data->steps);
- struct iovec *store_pdu = current_data_step->set_data_2;
- struct step *step = g_new0(struct step, 1);
- unsigned char *raw_pdu = store_pdu->iov_base;
- int set_data_len = current_data_step->set_data_len;
-
- switch (raw_pdu[0]) {
- case L2CAP_ATT_READ_REQ: {
- uint16_t handle = *((int *)current_data_step->set_data);
-
- memcpy(raw_pdu + 1, &handle, set_data_len);
- tester_debug("gatt: modify pdu read request handle to 0x%02x",
- handle);
-
- break;
- }
-
- case L2CAP_ATT_WRITE_REQ: {
- struct att_write_req_data *pdu_set_data =
- current_data_step->set_data;
- uint16_t handle = *((int *)(pdu_set_data->attr_handle));
- uint8_t *value = pdu_set_data->value;
-
- memcpy(raw_pdu + 1, &handle, sizeof(handle));
- memcpy(raw_pdu + 3, value, set_data_len - sizeof(handle));
-
- tester_debug("gatt: modify pdu write request handle to 0x%02x",
- handle);
-
- break;
- }
- default:
- tester_debug("modify att pdu with opcode 0x%02x not handled",
- raw_pdu[0]);
-
- break;
- }
-
- schedule_action_verification(step);
-}
+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 void gatt_client_register_action(void)
{
@@ -3352,10 +3311,9 @@ static struct test_case test_cases[] = {
CALLBACK_GATTS_CONNECTION(GATT_SERVER_CONNECTED,
prop_emu_remotes_default_set,
CONN1_ID, APP1_ID),
- MODIFY_DATA(GATT_STATUS_SUCCESS, gatt_att_pdu_modify,
- &char1_handle, &att_read_req,
- ATT_HANDLE_SIZE),
- ACTION_SUCCESS(gatt_remote_send_raw_pdu_action, &att_read_req),
+ PROCESS_DATA(GATT_STATUS_SUCCESS,
+ gatt_remote_send_raw_pdu_action,
+ &att_read_req_op_v, &char1_handle_v, NULL),
CALLBACK_GATTS_REQUEST_READ(CONN1_ID, TRANS1_ID,
prop_emu_remotes_default_set,
&char1_handle, 0, false),
@@ -3396,12 +3354,10 @@ static struct test_case test_cases[] = {
CALLBACK_GATTS_CONNECTION(GATT_SERVER_CONNECTED,
prop_emu_remotes_default_set,
CONN1_ID, APP1_ID),
- MODIFY_DATA(GATT_STATUS_SUCCESS, gatt_att_pdu_modify,
- &att_write_req_data_1, &att_write_req_1,
- sizeof(att_write_req_value_1) +
- ATT_HANDLE_SIZE),
- ACTION_SUCCESS(gatt_remote_send_raw_pdu_action,
- &att_write_req_1),
+ 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,
--
1.9.1
This handles multiple iovectors instead of one assembled pdu.
---
android/tester-gatt.c | 31 +++++++++++++++++++++++++++++--
1 file changed, 29 insertions(+), 2 deletions(-)
diff --git a/android/tester-gatt.c b/android/tester-gatt.c
index 610c1b4..a8dbd35 100644
--- a/android/tester-gatt.c
+++ b/android/tester-gatt.c
@@ -1704,17 +1704,44 @@ static void gatt_remote_send_raw_pdu_action(void)
struct bthost *bthost = hciemu_client_get_host(data->hciemu);
struct step *current_data_step = queue_peek_head(data->steps);
struct iovec *pdu = current_data_step->set_data;
+ struct iovec *pdu2 = current_data_step->set_data_2;
+ struct iovec *pdu3 = current_data_step->set_data_3;
struct step *step = g_new0(struct step, 1);
if (cid_data.handle && cid_data.cid) {
- bthost_send_cid_v(bthost, cid_data.handle, cid_data.cid,
- pdu, 1);
+ struct iovec rsp[3];
+ size_t len = 0;
+
+ if (!pdu) {
+ step->action_status = BT_STATUS_FAIL;
+ goto done;
+ }
+
+ rsp[0].iov_base = pdu->iov_base;
+ rsp[0].iov_len = pdu->iov_len;
+ len++;
+
+ if (pdu2) {
+ rsp[1].iov_base = pdu2->iov_base;
+ rsp[1].iov_len = pdu2->iov_len;
+ len++;
+ }
+
+ if (pdu3) {
+ rsp[2].iov_base = pdu3->iov_base;
+ rsp[2].iov_len = pdu3->iov_len;
+ len++;
+ }
+
+ bthost_send_cid_v(bthost, cid_data.handle, cid_data.cid, rsp,
+ len);
step->action_status = BT_STATUS_SUCCESS;
} else {
tester_debug("No connection set up");
step->action_status = BT_STATUS_FAIL;
}
+done:
schedule_action_verification(step);
}
--
1.9.1
As of now when we want to send response from remote device, we compose
pdu from handle and value, which are then copied into fixed size pdu
with predefined header. With this macro we will be able to pass up to
3 iovectors which are then send without additional copying. It also
quite generic and can be used to any other kind of data processing nad
not only for sending pdus.
---
android/tester-gatt.c | 2 +-
android/tester-main.h | 13 +++++++++++--
2 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/android/tester-gatt.c b/android/tester-gatt.c
index f4d22fd..610c1b4 100644
--- a/android/tester-gatt.c
+++ b/android/tester-gatt.c
@@ -1079,7 +1079,7 @@ static void gatt_att_pdu_modify(void)
{
struct test_data *data = tester_get_data();
struct step *current_data_step = queue_peek_head(data->steps);
- struct iovec *store_pdu = current_data_step->set_data_to;
+ struct iovec *store_pdu = current_data_step->set_data_2;
struct step *step = g_new0(struct step, 1);
unsigned char *raw_pdu = store_pdu->iov_base;
int set_data_len = current_data_step->set_data_len;
diff --git a/android/tester-main.h b/android/tester-main.h
index 7fe73fe..e35feec 100644
--- a/android/tester-main.h
+++ b/android/tester-main.h
@@ -68,10 +68,18 @@ struct pdu_set {
.action_status = status, \
.action = modif_fun, \
.set_data = from, \
- .set_data_to = to, \
+ .set_data_2 = to, \
.set_data_len = len, \
}
+#define PROCESS_DATA(status, proc_fun, data1, data2, data3) { \
+ .action_status = status, \
+ .action = proc_fun, \
+ .set_data = data1, \
+ .set_data_2 = data2, \
+ .set_data_3 = data3, \
+ }
+
#define ACTION(status, act_fun, data_set) { \
.action_status = status, \
.action = act_fun, \
@@ -706,7 +714,8 @@ struct step {
struct bt_callback_data callback_result;
void *set_data;
- void *set_data_to;
+ void *set_data_2;
+ void *set_data_3;
int set_data_len;
uint16_t *store_srvc_handle;
--
1.9.1