From bdc10744fb338ae197692713a0b48a7ccc36f566 Mon Sep 17 00:00:00 2001 From: JF Date: Sun, 26 Apr 2020 10:25:59 +0200 Subject: Add Nimble in libs directory --- src/libs/mynewt-nimble/nimble/host/test/pkg.yml | 34 + .../nimble/host/test/src/ble_att_clt_test.c | 548 +++ .../nimble/host/test/src/ble_att_svr_test.c | 2138 +++++++++ .../nimble/host/test/src/ble_gap_test.c | 3168 +++++++++++++ .../nimble/host/test/src/ble_gatt_conn_test.c | 746 +++ .../nimble/host/test/src/ble_gatt_disc_c_test.c | 722 +++ .../nimble/host/test/src/ble_gatt_disc_d_test.c | 446 ++ .../nimble/host/test/src/ble_gatt_disc_s_test.c | 631 +++ .../nimble/host/test/src/ble_gatt_find_s_test.c | 433 ++ .../nimble/host/test/src/ble_gatt_read_test.c | 923 ++++ .../nimble/host/test/src/ble_gatt_write_test.c | 832 ++++ .../nimble/host/test/src/ble_gatts_notify_test.c | 1090 +++++ .../nimble/host/test/src/ble_gatts_read_test.c | 257 + .../nimble/host/test/src/ble_gatts_reg_test.c | 719 +++ .../nimble/host/test/src/ble_hs_adv_test.c | 1280 +++++ .../nimble/host/test/src/ble_hs_conn_test.c | 224 + .../nimble/host/test/src/ble_hs_hci_test.c | 342 ++ .../nimble/host/test/src/ble_hs_id_test.c | 124 + .../nimble/host/test/src/ble_hs_pvcy_test.c | 509 ++ .../nimble/host/test/src/ble_hs_stop_test.c | 203 + .../nimble/host/test/src/ble_hs_test.c | 83 + .../nimble/host/test/src/ble_hs_test.h | 62 + .../nimble/host/test/src/ble_hs_test_util.c | 2048 ++++++++ .../nimble/host/test/src/ble_hs_test_util.h | 305 ++ .../nimble/host/test/src/ble_hs_test_util_hci.c | 616 +++ .../nimble/host/test/src/ble_hs_test_util_hci.h | 105 + .../nimble/host/test/src/ble_l2cap_test.c | 1500 ++++++ .../nimble/host/test/src/ble_os_test.c | 388 ++ .../nimble/host/test/src/ble_sm_lgcy_test.c | 849 ++++ .../nimble/host/test/src/ble_sm_sc_test.c | 4938 ++++++++++++++++++++ .../nimble/host/test/src/ble_sm_test.c | 414 ++ .../nimble/host/test/src/ble_sm_test_util.c | 2967 ++++++++++++ .../nimble/host/test/src/ble_sm_test_util.h | 128 + .../nimble/host/test/src/ble_store_test.c | 435 ++ .../nimble/host/test/src/ble_uuid_test.c | 76 + src/libs/mynewt-nimble/nimble/host/test/syscfg.yml | 31 + 36 files changed, 30314 insertions(+) create mode 100644 src/libs/mynewt-nimble/nimble/host/test/pkg.yml create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_att_clt_test.c create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_att_svr_test.c create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_gap_test.c create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_gatt_conn_test.c create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_gatt_disc_c_test.c create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_gatt_disc_d_test.c create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_gatt_disc_s_test.c create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_gatt_find_s_test.c create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_gatt_read_test.c create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_gatt_write_test.c create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_gatts_notify_test.c create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_gatts_read_test.c create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_gatts_reg_test.c create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_adv_test.c create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_conn_test.c create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_hci_test.c create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_id_test.c create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_pvcy_test.c create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_stop_test.c create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_test.c create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_test.h create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_test_util.c create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_test_util.h create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_test_util_hci.c create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_test_util_hci.h create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_l2cap_test.c create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_os_test.c create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_sm_lgcy_test.c create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_sm_sc_test.c create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_sm_test.c create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_sm_test_util.c create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_sm_test_util.h create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_store_test.c create mode 100644 src/libs/mynewt-nimble/nimble/host/test/src/ble_uuid_test.c create mode 100644 src/libs/mynewt-nimble/nimble/host/test/syscfg.yml (limited to 'src/libs/mynewt-nimble/nimble/host/test') diff --git a/src/libs/mynewt-nimble/nimble/host/test/pkg.yml b/src/libs/mynewt-nimble/nimble/host/test/pkg.yml new file mode 100644 index 00000000..dd1ad18b --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/pkg.yml @@ -0,0 +1,34 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +pkg.name: nimble/host/test +pkg.type: unittest +pkg.description: "NimBLE host unit tests." +pkg.author: "Apache Mynewt " +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + +pkg.deps: + - "@apache-mynewt-core/test/testutil" + - nimble/host + - nimble/host/store/config + +pkg.deps.SELFTEST: + - "@apache-mynewt-core/sys/console/stub" + - "@apache-mynewt-core/sys/log/full" + - "@apache-mynewt-core/sys/stats/stub" + - nimble/transport/ram diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_att_clt_test.c b/src/libs/mynewt-nimble/nimble/host/test/src/ble_att_clt_test.c new file mode 100644 index 00000000..787d4bca --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_att_clt_test.c @@ -0,0 +1,548 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include "testutil/testutil.h" +#include "nimble/ble.h" +#include "ble_hs_test.h" +#include "ble_hs_test_util.h" + +/** + * @return The handle of the new test connection. + */ +static uint16_t +ble_att_clt_test_misc_init(void) +{ + ble_hs_test_util_init(); + ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), NULL, + NULL); + return 2; +} + +static void +ble_att_clt_test_misc_verify_tx_write(uint16_t handle_id, void *value, + int value_len, int is_req) +{ + struct ble_att_write_req req; + struct os_mbuf *om; + + om = ble_hs_test_util_prev_tx_dequeue_pullup(); + TEST_ASSERT_FATAL(om != NULL); + + if (is_req) { + ble_att_write_req_parse(om->om_data, om->om_len, &req); + } else { + ble_att_write_cmd_parse(om->om_data, om->om_len, &req); + } + + TEST_ASSERT(req.bawq_handle == handle_id); + TEST_ASSERT(om->om_len == BLE_ATT_WRITE_REQ_BASE_SZ + value_len); + TEST_ASSERT(memcmp(om->om_data + BLE_ATT_WRITE_REQ_BASE_SZ, value, + value_len) == 0); +} + +static void +ble_att_clt_test_tx_write_req_or_cmd(uint16_t conn_handle, uint16_t handle, + void *value, int value_len, int is_req) +{ + struct os_mbuf *om; + int rc; + + om = ble_hs_test_util_om_from_flat(value, value_len); + if (is_req) { + rc = ble_att_clt_tx_write_req(conn_handle, handle, om); + } else { + rc = ble_att_clt_tx_write_cmd(conn_handle, handle, om); + } + TEST_ASSERT(rc == 0); +} + +TEST_CASE_SELF(ble_att_clt_test_tx_find_info) +{ + uint16_t conn_handle; + int rc; + + ble_hs_test_util_assert_mbufs_freed(NULL); + + conn_handle = ble_att_clt_test_misc_init(); + + /*** Success. */ + rc = ble_att_clt_tx_find_info(conn_handle, 1, 0xffff); + TEST_ASSERT(rc == 0); + + /*** Error: start handle of 0. */ + rc = ble_att_clt_tx_find_info(conn_handle, 0, 0xffff); + TEST_ASSERT(rc == BLE_HS_EINVAL); + + /*** Error: start handle greater than end handle. */ + rc = ble_att_clt_tx_find_info(conn_handle, 500, 499); + TEST_ASSERT(rc == BLE_HS_EINVAL); + + /*** Success; start and end handles equal. */ + rc = ble_att_clt_tx_find_info(conn_handle, 500, 500); + TEST_ASSERT(rc == 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_att_clt_test_rx_find_info) +{ + struct ble_att_find_info_rsp rsp; + uint16_t conn_handle; + uint8_t buf[1024]; + uint8_t uuid128_1[16] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 }; + int off; + int rc; + + conn_handle = ble_att_clt_test_misc_init(); + + /*** One 128-bit UUID. */ + /* Receive response with attribute mapping. */ + off = 0; + rsp.bafp_format = BLE_ATT_FIND_INFO_RSP_FORMAT_128BIT; + ble_att_find_info_rsp_write(buf + off, sizeof buf - off, &rsp); + off += BLE_ATT_FIND_INFO_RSP_BASE_SZ; + + put_le16(buf + off, 1); + off += 2; + memcpy(buf + off, uuid128_1, 16); + off += 16; + + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, off); + TEST_ASSERT(rc == 0); + + /*** One 16-bit UUID. */ + /* Receive response with attribute mapping. */ + off = 0; + rsp.bafp_format = BLE_ATT_FIND_INFO_RSP_FORMAT_16BIT; + ble_att_find_info_rsp_write(buf + off, sizeof buf - off, &rsp); + off += BLE_ATT_FIND_INFO_RSP_BASE_SZ; + + put_le16(buf + off, 2); + off += 2; + put_le16(buf + off, 0x000f); + off += 2; + + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, off); + TEST_ASSERT(rc == 0); + + /*** Two 16-bit UUIDs. */ + /* Receive response with attribute mappings. */ + off = 0; + rsp.bafp_format = BLE_ATT_FIND_INFO_RSP_FORMAT_16BIT; + ble_att_find_info_rsp_write(buf + off, sizeof buf - off, &rsp); + off += BLE_ATT_FIND_INFO_RSP_BASE_SZ; + + put_le16(buf + off, 3); + off += 2; + put_le16(buf + off, 0x0010); + off += 2; + + put_le16(buf + off, 4); + off += 2; + put_le16(buf + off, 0x0011); + off += 2; + + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, off); + TEST_ASSERT(rc == 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +static void +ble_att_clt_test_case_tx_write_req_or_cmd(int is_req) +{ + uint16_t conn_handle; + uint8_t value300[500] = { 0 }; + uint8_t value5[5] = { 6, 7, 54, 34, 8 }; + + conn_handle = ble_att_clt_test_misc_init(); + + /*** 5-byte write. */ + ble_att_clt_test_tx_write_req_or_cmd(conn_handle, 0x1234, value5, + sizeof value5, is_req); + ble_att_clt_test_misc_verify_tx_write(0x1234, value5, sizeof value5, + is_req); + + /*** Overlong write; verify command truncated to ATT MTU. */ + ble_att_clt_test_tx_write_req_or_cmd(conn_handle, 0xab83, value300, + sizeof value300, is_req); + ble_att_clt_test_misc_verify_tx_write(0xab83, value300, + BLE_ATT_MTU_DFLT - 3, is_req); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +static void +ble_att_clt_test_misc_prep_good(uint16_t handle, uint16_t offset, + uint8_t *attr_data, uint16_t attr_data_len) +{ + struct ble_att_prep_write_cmd req; + struct os_mbuf *om; + uint16_t conn_handle; + int rc; + int i; + + conn_handle = ble_att_clt_test_misc_init(); + + om = ble_hs_test_util_om_from_flat(attr_data, attr_data_len); + rc = ble_att_clt_tx_prep_write(conn_handle, handle, offset, om); + TEST_ASSERT(rc == 0); + + om = ble_hs_test_util_prev_tx_dequeue_pullup(); + TEST_ASSERT_FATAL(om != NULL); + TEST_ASSERT(om->om_len == BLE_ATT_PREP_WRITE_CMD_BASE_SZ + attr_data_len); + + ble_att_prep_write_req_parse(om->om_data, om->om_len, &req); + TEST_ASSERT(req.bapc_handle == handle); + TEST_ASSERT(req.bapc_offset == offset); + for (i = 0; i < attr_data_len; i++) { + TEST_ASSERT(om->om_data[BLE_ATT_PREP_WRITE_CMD_BASE_SZ + i] == + attr_data[i]); + } +} + +static void +ble_att_clt_test_misc_exec_good(uint8_t flags) +{ + struct ble_att_exec_write_req req; + struct os_mbuf *om; + uint16_t conn_handle; + int rc; + + conn_handle = ble_att_clt_test_misc_init(); + + rc = ble_att_clt_tx_exec_write(conn_handle, flags); + TEST_ASSERT(rc == 0); + + om = ble_hs_test_util_prev_tx_dequeue_pullup(); + TEST_ASSERT_FATAL(om != NULL); + TEST_ASSERT(om->om_len == BLE_ATT_EXEC_WRITE_REQ_SZ); + + ble_att_exec_write_req_parse(om->om_data, om->om_len, &req); + TEST_ASSERT(req.baeq_flags == flags); +} + +static void +ble_att_clt_test_misc_prep_bad(uint16_t handle, uint16_t offset, + uint8_t *attr_data, uint16_t attr_data_len, + int status) +{ + struct os_mbuf *om; + uint16_t conn_handle; + int rc; + + conn_handle = ble_att_clt_test_misc_init(); + + om = ble_hs_test_util_om_from_flat(attr_data, attr_data_len); + + rc = ble_att_clt_tx_prep_write(conn_handle, handle, offset, om); + TEST_ASSERT(rc == status); +} + +static void +ble_att_clt_test_misc_tx_mtu(uint16_t conn_handle, uint16_t mtu, int status) +{ + int rc; + + rc = ble_att_clt_tx_mtu(conn_handle, mtu); + TEST_ASSERT(rc == status); + + if (rc == 0) { + ble_hs_test_util_verify_tx_mtu_cmd(1, mtu); + } +} + +TEST_CASE_SELF(ble_att_clt_test_tx_write) +{ + ble_att_clt_test_case_tx_write_req_or_cmd(0); + ble_att_clt_test_case_tx_write_req_or_cmd(1); +} + +TEST_CASE_SELF(ble_att_clt_test_tx_read) +{ + uint16_t conn_handle; + int rc; + + conn_handle = ble_att_clt_test_misc_init(); + + /*** Success. */ + rc = ble_att_clt_tx_read(conn_handle, 1); + TEST_ASSERT(rc == 0); + + /*** Error: handle of 0. */ + rc = ble_att_clt_tx_read(conn_handle, 0); + TEST_ASSERT(rc == BLE_HS_EINVAL); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_att_clt_test_rx_read) +{ + uint16_t conn_handle; + uint8_t buf[1024]; + int rc; + + conn_handle = ble_att_clt_test_misc_init(); + + /*** Basic success. */ + buf[0] = BLE_ATT_OP_READ_RSP; + buf[1] = 0; + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, 2); + TEST_ASSERT(rc == 0); + + /*** Larger response. */ + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, 20); + TEST_ASSERT(rc == 0); + + /*** Zero-length response. */ + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, 1); + TEST_ASSERT(rc == 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_att_clt_test_tx_read_blob) +{ + uint16_t conn_handle; + int rc; + + conn_handle = ble_att_clt_test_misc_init(); + + /*** Success. */ + rc = ble_att_clt_tx_read_blob(conn_handle, 1, 0); + TEST_ASSERT(rc == 0); + + /*** Error: handle of 0. */ + rc = ble_att_clt_tx_read_blob(conn_handle, 0, 0); + TEST_ASSERT(rc == BLE_HS_EINVAL); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_att_clt_test_rx_read_blob) +{ + uint16_t conn_handle; + uint8_t buf[1024]; + int rc; + + conn_handle = ble_att_clt_test_misc_init(); + + /*** Basic success. */ + buf[0] = BLE_ATT_OP_READ_BLOB_RSP; + buf[1] = 0; + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, 2); + TEST_ASSERT(rc == 0); + + /*** Larger response. */ + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, 20); + TEST_ASSERT(rc == 0); + + /*** Zero-length response. */ + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, 1); + TEST_ASSERT(rc == 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_att_clt_test_tx_read_mult) +{ + struct os_mbuf *om; + uint16_t conn_handle; + int rc; + + conn_handle = ble_att_clt_test_misc_init(); + + /*** Success. */ + rc = ble_att_clt_tx_read_mult(conn_handle, ((uint16_t[]){ 1, 2 }), 2); + TEST_ASSERT(rc == 0); + + om = ble_hs_test_util_prev_tx_dequeue_pullup(); + TEST_ASSERT_FATAL(om != NULL); + TEST_ASSERT(om->om_len == BLE_ATT_READ_MULT_REQ_BASE_SZ + 4); + + ble_att_read_mult_req_parse(om->om_data, om->om_len); + TEST_ASSERT(get_le16(om->om_data + BLE_ATT_READ_MULT_REQ_BASE_SZ) == 1); + TEST_ASSERT(get_le16(om->om_data + BLE_ATT_READ_MULT_REQ_BASE_SZ + 2) == 2); + + /*** Error: no handles. */ + rc = ble_att_clt_tx_read_mult(conn_handle, NULL, 0); + TEST_ASSERT(rc == BLE_HS_EINVAL); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_att_clt_test_rx_read_mult) +{ + uint16_t conn_handle; + uint8_t buf[1024]; + int rc; + + conn_handle = ble_att_clt_test_misc_init(); + + /*** Basic success. */ + ble_att_read_mult_rsp_write(buf, sizeof buf); + put_le16(buf + BLE_ATT_READ_MULT_RSP_BASE_SZ + 0, 12); + + rc = ble_hs_test_util_l2cap_rx_payload_flat( + conn_handle, BLE_L2CAP_CID_ATT, buf, + BLE_ATT_READ_MULT_RSP_BASE_SZ + 2); + TEST_ASSERT(rc == 0); + + /*** Larger response. */ + put_le16(buf + BLE_ATT_READ_MULT_RSP_BASE_SZ + 0, 12); + put_le16(buf + BLE_ATT_READ_MULT_RSP_BASE_SZ + 2, 43); + put_le16(buf + BLE_ATT_READ_MULT_RSP_BASE_SZ + 4, 91); + rc = ble_hs_test_util_l2cap_rx_payload_flat( + conn_handle, BLE_L2CAP_CID_ATT, buf, + BLE_ATT_READ_MULT_RSP_BASE_SZ + 6); + TEST_ASSERT(rc == 0); + + /*** Zero-length response. */ + rc = ble_hs_test_util_l2cap_rx_payload_flat( + conn_handle, BLE_L2CAP_CID_ATT, buf, + BLE_ATT_READ_MULT_RSP_BASE_SZ + 0); + TEST_ASSERT(rc == 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_att_clt_test_tx_prep_write) +{ + uint8_t attr_data[512]; + int i; + + for (i = 0; i < sizeof attr_data; i++) { + attr_data[i] = i; + } + + /*** Success. */ + ble_att_clt_test_misc_prep_good(123, 0, attr_data, 16); + ble_att_clt_test_misc_prep_good(5432, 100, attr_data, 2); + ble_att_clt_test_misc_prep_good(0x1234, 400, attr_data, 0); + ble_att_clt_test_misc_prep_good(5432, 0, attr_data, + BLE_ATT_MTU_DFLT - + BLE_ATT_PREP_WRITE_CMD_BASE_SZ); + ble_att_clt_test_misc_prep_good(0x1234, 507, attr_data, 5); + + /*** Error: handle of 0. */ + ble_att_clt_test_misc_prep_bad(0, 0, attr_data, 16, BLE_HS_EINVAL); + + /*** Error: offset + length greater than maximum attribute size. */ + ble_att_clt_test_misc_prep_bad(1, 507, attr_data, 6, BLE_HS_EINVAL); + + /*** Error: packet larger than MTU. */ + ble_att_clt_test_misc_prep_bad(1, 0, attr_data, + BLE_ATT_MTU_DFLT - + BLE_ATT_PREP_WRITE_CMD_BASE_SZ + 1, + BLE_HS_EINVAL); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_att_clt_test_rx_prep_write) +{ + struct ble_att_prep_write_cmd rsp; + uint16_t conn_handle; + uint8_t buf[1024]; + int rc; + + conn_handle = ble_att_clt_test_misc_init(); + + /*** Basic success. */ + rsp.bapc_handle = 0x1234; + rsp.bapc_offset = 0; + ble_att_prep_write_rsp_write(buf, sizeof buf, &rsp); + memset(buf + BLE_ATT_PREP_WRITE_CMD_BASE_SZ, 1, 5); + rc = ble_hs_test_util_l2cap_rx_payload_flat( + conn_handle, BLE_L2CAP_CID_ATT, buf, + BLE_ATT_PREP_WRITE_CMD_BASE_SZ + 5); + TEST_ASSERT(rc == 0); + + /*** 0-length write. */ + rsp.bapc_handle = 0x1234; + rsp.bapc_offset = 0; + ble_att_prep_write_rsp_write(buf, sizeof buf, &rsp); + rc = ble_hs_test_util_l2cap_rx_payload_flat( + conn_handle, BLE_L2CAP_CID_ATT, buf, BLE_ATT_PREP_WRITE_CMD_BASE_SZ); + TEST_ASSERT(rc == 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_att_clt_test_tx_exec_write) +{ + uint16_t conn_handle; + int rc; + + conn_handle = ble_att_clt_test_misc_init(); + + /*** Success. */ + ble_att_clt_test_misc_exec_good(BLE_ATT_EXEC_WRITE_F_CANCEL); + ble_att_clt_test_misc_exec_good(BLE_ATT_EXEC_WRITE_F_EXECUTE); + + /*** Success: nonzero == execute. */ + rc = ble_att_clt_tx_exec_write(conn_handle, 0x02); + TEST_ASSERT(rc == 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_att_clt_test_tx_mtu) +{ + uint16_t conn_handle; + + conn_handle = ble_att_clt_test_misc_init(); + + /*** Success. */ + ble_att_clt_test_misc_tx_mtu(conn_handle, 50, 0); + + /*** Error: repeated sends. */ + ble_att_clt_test_misc_tx_mtu(conn_handle, 50, BLE_HS_EALREADY); + ble_att_clt_test_misc_tx_mtu(conn_handle, 60, BLE_HS_EALREADY); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_att_clt_suite) +{ + ble_att_clt_test_tx_find_info(); + ble_att_clt_test_rx_find_info(); + ble_att_clt_test_tx_read(); + ble_att_clt_test_rx_read(); + ble_att_clt_test_tx_read_blob(); + ble_att_clt_test_rx_read_blob(); + ble_att_clt_test_tx_read_mult(); + ble_att_clt_test_rx_read_mult(); + ble_att_clt_test_tx_write(); + ble_att_clt_test_tx_prep_write(); + ble_att_clt_test_rx_prep_write(); + ble_att_clt_test_tx_exec_write(); + ble_att_clt_test_tx_mtu(); +} diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_att_svr_test.c b/src/libs/mynewt-nimble/nimble/host/test/src/ble_att_svr_test.c new file mode 100644 index 00000000..60ab14b4 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_att_svr_test.c @@ -0,0 +1,2138 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include "testutil/testutil.h" +#include "nimble/hci_common.h" +#include "ble_hs_test.h" +#include "host/ble_uuid.h" +#include "ble_hs_test_util.h" + +static uint8_t *ble_att_svr_test_attr_r_1; +static uint16_t ble_att_svr_test_attr_r_1_len; +static uint8_t *ble_att_svr_test_attr_r_2; +static uint16_t ble_att_svr_test_attr_r_2_len; + +static uint8_t ble_att_svr_test_attr_w_1[1024]; +static uint16_t ble_att_svr_test_attr_w_1_len; +static uint8_t ble_att_svr_test_attr_w_2[1024]; +static uint16_t ble_att_svr_test_attr_w_2_len; + +static uint16_t ble_att_svr_test_n_conn_handle; +static uint16_t ble_att_svr_test_n_attr_handle; +static uint8_t ble_att_svr_test_attr_n[1024]; +static uint16_t ble_att_svr_test_attr_n_len; + +static void +ble_att_svr_test_assert_mbufs_freed(void) +{ + /* When checking for mbuf leaks, ensure no stale prep entries. */ + static const struct ble_hs_test_util_mbuf_params mbuf_params = { + .prev_tx = 1, + .rx_queue = 1, + .prep_list = 0, + }; + + ble_hs_test_util_assert_mbufs_freed(&mbuf_params); +} + +static int +ble_att_svr_test_misc_gap_cb(struct ble_gap_event *event, void *arg) +{ + int rc; + + switch (event->type) { + case BLE_GAP_EVENT_NOTIFY_RX: + ble_att_svr_test_n_conn_handle = event->notify_rx.conn_handle; + ble_att_svr_test_n_attr_handle = event->notify_rx.attr_handle; + TEST_ASSERT_FATAL(OS_MBUF_PKTLEN(event->notify_rx.om) <= + sizeof ble_att_svr_test_attr_n); + ble_att_svr_test_attr_n_len = OS_MBUF_PKTLEN(event->notify_rx.om); + rc = os_mbuf_copydata(event->notify_rx.om, 0, + ble_att_svr_test_attr_n_len, + ble_att_svr_test_attr_n); + TEST_ASSERT_FATAL(rc == 0); + break; + + default: + break; + } + + return 0; +} + +/** + * @return The handle of the new test connection. + */ +static uint16_t +ble_att_svr_test_misc_init(uint16_t mtu) +{ + struct ble_l2cap_chan *chan; + struct ble_hs_conn *conn; + int rc; + + ble_hs_test_util_init(); + + ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), + ble_att_svr_test_misc_gap_cb, NULL); + + ble_hs_lock(); + + rc = ble_hs_misc_conn_chan_find(2, BLE_L2CAP_CID_ATT, &conn, &chan); + TEST_ASSERT_FATAL(rc == 0); + + if (mtu != 0) { + chan->my_mtu = mtu; + chan->peer_mtu = mtu; + chan->flags |= BLE_L2CAP_CHAN_F_TXED_MTU; + } + + ble_hs_unlock(); + + ble_att_svr_test_attr_r_1_len = 0; + ble_att_svr_test_attr_r_2_len = 0; + ble_att_svr_test_attr_w_1_len = 0; + + return 2; +} + +static int +ble_att_svr_test_misc_attr_fn_r_1(uint16_t conn_handle, uint16_t attr_handle, + uint8_t op, uint16_t offset, + struct os_mbuf **om, void *arg) +{ + int rc; + + switch (op) { + case BLE_ATT_ACCESS_OP_READ: + if (offset > ble_att_svr_test_attr_r_1_len) { + return BLE_ATT_ERR_INVALID_OFFSET; + } + + rc = os_mbuf_append(*om, ble_att_svr_test_attr_r_1 + offset, + ble_att_svr_test_attr_r_1_len - offset); + TEST_ASSERT_FATAL(rc == 0); + return 0; + + default: + return BLE_ATT_ERR_UNLIKELY; + } +} + +static int +ble_att_svr_test_misc_attr_fn_r_2(uint16_t conn_handle, uint16_t attr_handle, + uint8_t op, uint16_t offset, + struct os_mbuf **om, void *arg) +{ + int rc; + + switch (op) { + case BLE_ATT_ACCESS_OP_READ: + if (offset > ble_att_svr_test_attr_r_2_len) { + return BLE_ATT_ERR_INVALID_OFFSET; + } + + rc = os_mbuf_append(*om, ble_att_svr_test_attr_r_2 + offset, + ble_att_svr_test_attr_r_2_len - offset); + TEST_ASSERT_FATAL(rc == 0); + return 0; + + default: + return BLE_ATT_ERR_UNLIKELY; + } +} + +static int +ble_att_svr_test_misc_attr_fn_r_err(uint16_t conn_handle, uint16_t attr_handle, + uint8_t op, uint16_t offset, + struct os_mbuf **om, void *arg) +{ + int rc; + + rc = os_mbuf_append(*om, (uint8_t[4]){1,2,3,4}, 4); + TEST_ASSERT_FATAL(rc == 0); + + return BLE_ATT_ERR_UNLIKELY; +} + +#define BLE_ATT_SVR_TEST_LAST_SVC 11 +#define BLE_ATT_SVR_TEST_LAST_ATTR 24 + +static int +ble_att_svr_test_misc_attr_fn_r_group(uint16_t conn_handle, + uint16_t attr_handle, + uint8_t op, + uint16_t offset, + struct os_mbuf **om, + void *arg) +{ + uint8_t *src; + int rc; + + /* Service 0x1122 from 1 to 5 */ + /* Service 0x2233 from 6 to 10 */ + /* Service 010203...0f from 11 to 24 */ + + static uint8_t vals[25][16] = { + [1] = { 0x22, 0x11 }, + [2] = { 0x01, 0x11 }, + [3] = { 0x02, 0x11 }, + [4] = { 0x03, 0x11 }, + [5] = { 0x04, 0x11 }, + [6] = { 0x33, 0x22 }, + [7] = { 0x01, 0x22 }, + [8] = { 0x02, 0x22 }, + [9] = { 0x03, 0x22 }, + [10] = { 0x04, 0x22 }, + [11] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 }, + [12] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }, + [13] = { 0xdd, 0xdd }, + [14] = { 0x55, 0x55 }, + [15] = { 0xdd, 0xdd }, + [16] = { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 }, + [17] = { 0xdd, 0xdd }, + [18] = { 0x66, 0x66 }, + [19] = { 0xdd, 0xdd }, + [20] = { 0x77, 0x77 }, + [21] = { 0xdd, 0xdd }, + [22] = { 0x88, 0x88 }, + [23] = { 0xdd, 0xdd }, + [24] = { 0x99, 0x99 }, + }; + + static uint8_t zeros[14]; + + if (op != BLE_ATT_ACCESS_OP_READ) { + return -1; + } + + TEST_ASSERT_FATAL(attr_handle >= 1 && + attr_handle <= BLE_ATT_SVR_TEST_LAST_ATTR); + + src = &vals[attr_handle][0]; + if (memcmp(src + 2, zeros, 14) == 0) { + rc = os_mbuf_append(*om, src, 2); + } else { + rc = os_mbuf_append(*om, src, 16); + } + if (rc != 0) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + return 0; +} + +static void +ble_att_svr_test_misc_register_uuid(const ble_uuid_t *uuid, uint8_t flags, + uint16_t expected_handle, + ble_att_svr_access_fn *fn) +{ + uint16_t handle; + int rc; + + rc = ble_att_svr_register(uuid, flags, 0, &handle, fn, NULL); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT_FATAL(handle == expected_handle); +} + +static void +ble_att_svr_test_misc_register_group_attrs(void) +{ + /* Service 0x1122 from 1 to 5 */ + /* Service 0x2233 from 6 to 10 */ + /* Service 010203...0f from 11 to 24 */ + + static const ble_uuid16_t uuid_svc = + BLE_UUID16_INIT(BLE_ATT_UUID_PRIMARY_SERVICE); + static const ble_uuid16_t uuid_inc = + BLE_UUID16_INIT(BLE_ATT_UUID_INCLUDE); + static const ble_uuid16_t uuid_chr = + BLE_UUID16_INIT(BLE_ATT_UUID_CHARACTERISTIC); + static ble_uuid16_t uuids[24]; + + int i; + + /* Service 0x1122 from 1 to 5 */ + ble_att_svr_test_misc_register_uuid(&uuid_svc.u, HA_FLAG_PERM_RW, 1, + ble_att_svr_test_misc_attr_fn_r_group); + for (i = 2; i <= 5; i++) { + if ((i - 2) % 2 == 0) { + ble_att_svr_test_misc_register_uuid(&uuid_chr.u, HA_FLAG_PERM_RW, i, + ble_att_svr_test_misc_attr_fn_r_group); + } else { + uuids[i] = *BLE_UUID16(BLE_UUID16_DECLARE(i)); + ble_att_svr_test_misc_register_uuid(&uuids[i].u, HA_FLAG_PERM_RW, i, + ble_att_svr_test_misc_attr_fn_r_group); + } + } + + /* Service 0x2233 from 6 to 10 */ + ble_att_svr_test_misc_register_uuid(&uuid_svc.u, HA_FLAG_PERM_RW, 6, + ble_att_svr_test_misc_attr_fn_r_group); + for (i = 7; i <= 10; i++) { + ble_att_svr_test_misc_register_uuid(&uuid_inc.u, HA_FLAG_PERM_RW, i, + ble_att_svr_test_misc_attr_fn_r_group); + } + + /* Service 010203...0f from 11 to 24 */ + ble_att_svr_test_misc_register_uuid(&uuid_svc.u, HA_FLAG_PERM_RW, 11, + ble_att_svr_test_misc_attr_fn_r_group); + for (i = 12; i <= 24; i++) { + if ((i - 12) % 2 == 0) { + ble_att_svr_test_misc_register_uuid(&uuid_chr.u, HA_FLAG_PERM_RW, i, + ble_att_svr_test_misc_attr_fn_r_group); + } else { + uuids[i] = *BLE_UUID16(BLE_UUID16_DECLARE(i)); + ble_att_svr_test_misc_register_uuid(&uuids[i].u, HA_FLAG_PERM_RW, i, + ble_att_svr_test_misc_attr_fn_r_group); + } + } +} + +static int +ble_att_svr_test_misc_attr_fn_rw_1(uint16_t conn_handle, uint16_t attr_handle, + uint8_t op, uint16_t offset, + struct os_mbuf **om, void *arg) +{ + int rc; + + switch (op) { + case BLE_ATT_ACCESS_OP_READ: + if (offset > ble_att_svr_test_attr_w_1_len) { + return BLE_ATT_ERR_INVALID_OFFSET; + } + + rc = os_mbuf_append(*om, ble_att_svr_test_attr_w_1 + offset, + ble_att_svr_test_attr_w_1_len - offset); + TEST_ASSERT_FATAL(rc == 0); + return 0; + + case BLE_ATT_ACCESS_OP_WRITE: + rc = os_mbuf_copydata(*om, 0, OS_MBUF_PKTLEN(*om), + ble_att_svr_test_attr_w_1); + TEST_ASSERT_FATAL(rc == 0); + ble_att_svr_test_attr_w_1_len = OS_MBUF_PKTLEN(*om); + return 0; + + default: + return BLE_ATT_ERR_UNLIKELY; + } +} + +static int +ble_att_svr_test_misc_attr_fn_w_1(uint16_t conn_handle, uint16_t attr_handle, + uint8_t op, uint16_t offset, + struct os_mbuf **om, void *arg) +{ + int rc; + + switch (op) { + case BLE_ATT_ACCESS_OP_WRITE: + rc = os_mbuf_copydata(*om, 0, OS_MBUF_PKTLEN(*om), + ble_att_svr_test_attr_w_1); + TEST_ASSERT_FATAL(rc == 0); + ble_att_svr_test_attr_w_1_len = OS_MBUF_PKTLEN(*om); + return 0; + + default: + return BLE_ATT_ERR_UNLIKELY; + } +} + +static int +ble_att_svr_test_misc_attr_fn_w_2(uint16_t conn_handle, uint16_t attr_handle, + uint8_t op, uint16_t offset, + struct os_mbuf **om, void *arg) +{ + int rc; + + switch (op) { + case BLE_ATT_ACCESS_OP_WRITE: + rc = os_mbuf_copydata(*om, 0, OS_MBUF_PKTLEN(*om), + ble_att_svr_test_attr_w_2); + TEST_ASSERT_FATAL(rc == 0); + ble_att_svr_test_attr_w_2_len = OS_MBUF_PKTLEN(*om); + return 0; + + default: + return BLE_ATT_ERR_UNLIKELY; + } +} + +static int +ble_att_svr_test_misc_attr_fn_w_fail(uint16_t conn_handle, + uint16_t attr_handle, + uint8_t op, uint16_t offset, + struct os_mbuf **om, void *arg) +{ + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; +} + +static void +ble_att_svr_test_misc_verify_w_1(void *data, int data_len) +{ + TEST_ASSERT(ble_att_svr_test_attr_w_1_len == data_len); + TEST_ASSERT(memcmp(ble_att_svr_test_attr_w_1, data, data_len) == 0); +} + +static void +ble_att_svr_test_misc_verify_w_2(void *data, int data_len) +{ + TEST_ASSERT(ble_att_svr_test_attr_w_2_len == data_len); + TEST_ASSERT(memcmp(ble_att_svr_test_attr_w_2, data, data_len) == 0); +} + +static void +ble_att_svr_test_misc_rx_read_mult_req(uint16_t conn_handle, + uint16_t *handles, int num_handles, + int success) +{ + int rc; + + rc = ble_hs_test_util_rx_att_read_mult_req(conn_handle, handles, + num_handles); + if (success) { + TEST_ASSERT(rc == 0); + } else { + TEST_ASSERT(rc != 0); + } +} + +static void +ble_att_svr_test_misc_verify_tx_read_mult_rsp( + uint16_t conn_handle, struct ble_hs_test_util_flat_attr *attrs, + int num_attrs) +{ + struct ble_l2cap_chan *chan; + struct os_mbuf *om; + uint16_t attr_len; + uint16_t mtu; + uint8_t u8; + int rc; + int off; + int i; + + om = ble_hs_test_util_prev_tx_dequeue(); + + rc = os_mbuf_copydata(om, 0, 1, &u8); + TEST_ASSERT(rc == 0); + TEST_ASSERT(u8 == BLE_ATT_OP_READ_MULT_RSP); + + ble_hs_lock(); + + rc = ble_hs_misc_conn_chan_find(conn_handle, BLE_L2CAP_CID_ATT, + NULL, &chan); + TEST_ASSERT_FATAL(rc == 0); + mtu = ble_att_chan_mtu(chan); + + ble_hs_unlock(); + + off = 1; + for (i = 0; i < num_attrs; i++) { + attr_len = min(attrs[i].value_len, mtu - off); + + rc = os_mbuf_cmpf(om, off, attrs[i].value, attr_len); + TEST_ASSERT(rc == 0); + + off += attr_len; + } + + TEST_ASSERT(OS_MBUF_PKTLEN(om) == off); +} + +static void +ble_att_svr_test_misc_verify_all_read_mult( + uint16_t conn_handle, struct ble_hs_test_util_flat_attr *attrs, + int num_attrs) +{ + uint16_t handles[256]; + int i; + + TEST_ASSERT_FATAL(num_attrs <= sizeof handles / sizeof handles[0]); + + for (i = 0; i < num_attrs; i++) { + handles[i] = attrs[i].handle; + } + + ble_att_svr_test_misc_rx_read_mult_req(conn_handle, handles, num_attrs, 1); + ble_att_svr_test_misc_verify_tx_read_mult_rsp(conn_handle, + attrs, num_attrs); +} + +static void +ble_att_svr_test_misc_verify_tx_mtu_rsp(uint16_t conn_handle) +{ + struct ble_l2cap_chan *chan; + struct ble_hs_conn *conn; + uint16_t my_mtu; + int rc; + + ble_hs_lock(); + + rc = ble_att_conn_chan_find(conn_handle, &conn, &chan); + assert(rc == 0); + my_mtu = chan->my_mtu; + + ble_hs_unlock(); + + ble_hs_test_util_verify_tx_mtu_cmd(0, my_mtu); +} + +struct ble_att_svr_test_type_value_entry { + uint16_t first; /* 0 on last entry */ + uint16_t last; +}; + +static void +ble_att_svr_test_misc_verify_tx_find_type_value_rsp( + struct ble_att_svr_test_type_value_entry *entries) +{ + struct ble_att_svr_test_type_value_entry *entry; + struct os_mbuf *om; + uint16_t u16; + uint8_t op; + int off; + int rc; + + off = 0; + + om = ble_hs_test_util_prev_tx_dequeue_pullup(); + + rc = os_mbuf_copydata(om, off, 1, &op); + TEST_ASSERT(rc == 0); + off += 1; + + TEST_ASSERT(op == BLE_ATT_OP_FIND_TYPE_VALUE_RSP); + + for (entry = entries; entry->first != 0; entry++) { + rc = os_mbuf_copydata(om, off, 2, &u16); + TEST_ASSERT(rc == 0); + put_le16(&u16, u16); + TEST_ASSERT(u16 == entry->first); + off += 2; + + rc = os_mbuf_copydata(om, off, 2, &u16); + TEST_ASSERT(rc == 0); + put_le16(&u16, u16); + TEST_ASSERT(u16 == entry->last); + off += 2; + } + + /* Ensure there is no extra data in the response. */ + TEST_ASSERT(off == OS_MBUF_PKTHDR(om)->omp_len); +} + +/** Returns the number of entries successfully verified. */ + +struct ble_att_svr_test_type_entry { + uint16_t handle; /* 0 on last entry */ + void *value; + int value_len; +}; + +/** Returns the number of entries successfully verified. */ +static void +ble_att_svr_test_misc_verify_tx_read_type_rsp( + struct ble_att_svr_test_type_entry *entries) +{ + struct ble_att_svr_test_type_entry *entry; + struct ble_att_read_type_rsp rsp; + struct os_mbuf *om; + uint16_t handle; + uint8_t buf[512]; + int off; + int rc; + + om = ble_hs_test_util_prev_tx_dequeue_pullup(); + TEST_ASSERT(om); + + ble_att_read_type_rsp_parse(om->om_data, om->om_len, &rsp); + + off = BLE_ATT_READ_TYPE_RSP_BASE_SZ; + for (entry = entries; entry->handle != 0; entry++) { + TEST_ASSERT_FATAL(rsp.batp_length == + BLE_ATT_READ_TYPE_ADATA_BASE_SZ + entry->value_len); + + rc = os_mbuf_copydata(om, off, 2, &handle); + TEST_ASSERT(rc == 0); + handle = get_le16(&handle); + TEST_ASSERT(handle == entry->handle); + off += 2; + + rc = os_mbuf_copydata(om, off, entry->value_len, buf); + TEST_ASSERT(rc == 0); + TEST_ASSERT(memcmp(entry->value, buf, entry->value_len) == 0); + off += entry->value_len; + } + + /* Ensure there is no extra data in the response. */ + TEST_ASSERT(off == OS_MBUF_PKTLEN(om)); +} + +static void +ble_att_svr_test_misc_verify_tx_prep_write_rsp(uint16_t attr_handle, + uint16_t offset, + void *data, int data_len) +{ + struct ble_att_prep_write_cmd rsp; + struct os_mbuf *om; + uint8_t buf[1024]; + int rc; + + om = ble_hs_test_util_prev_tx_dequeue(); + + rc = os_mbuf_copydata(om, 0, OS_MBUF_PKTLEN(om), buf); + TEST_ASSERT_FATAL(rc == 0); + + ble_att_prep_write_rsp_parse(buf, sizeof buf, &rsp); + + TEST_ASSERT(rsp.bapc_handle == attr_handle); + TEST_ASSERT(rsp.bapc_offset == offset); + TEST_ASSERT(memcmp(buf + BLE_ATT_PREP_WRITE_CMD_BASE_SZ, data, + data_len) == 0); + + TEST_ASSERT(OS_MBUF_PKTLEN(om) == + BLE_ATT_PREP_WRITE_CMD_BASE_SZ + data_len); +} + +static void +ble_att_svr_test_misc_verify_tx_exec_write_rsp(void) +{ + struct os_mbuf *om; + + om = ble_hs_test_util_prev_tx_dequeue_pullup(); + TEST_ASSERT(om); + + ble_att_exec_write_rsp_parse(om->om_data, om->om_len); +} + +static void +ble_att_svr_test_misc_mtu_exchange(uint16_t my_mtu, uint16_t peer_sent, + uint16_t peer_actual, uint16_t chan_mtu) +{ + struct ble_att_mtu_cmd req; + struct ble_l2cap_chan *chan; + struct ble_hs_conn *conn; + uint16_t conn_handle; + uint8_t buf[BLE_ATT_MTU_CMD_SZ]; + int rc; + + conn_handle = ble_att_svr_test_misc_init(my_mtu); + + req.bamc_mtu = peer_sent; + ble_att_mtu_req_write(buf, sizeof buf, &req); + + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, sizeof buf); + TEST_ASSERT(rc == 0); + + ble_att_svr_test_misc_verify_tx_mtu_rsp(conn_handle); + + ble_hs_lock(); + rc = ble_hs_misc_conn_chan_find(conn_handle, BLE_L2CAP_CID_ATT, + &conn, &chan); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(chan->peer_mtu == peer_actual); + TEST_ASSERT(ble_att_chan_mtu(chan) == chan_mtu); + ble_hs_unlock(); + +} + +static void +ble_att_svr_test_misc_prep_write(uint16_t conn_handle, uint16_t attr_handle, + uint16_t offset, void *data, + int data_len, uint8_t error_code) +{ + int rc; + + rc = ble_hs_test_util_rx_att_prep_write_req(conn_handle, attr_handle, + offset, data, data_len); + if (error_code == 0) { + TEST_ASSERT(rc == 0); + ble_att_svr_test_misc_verify_tx_prep_write_rsp(attr_handle, offset, + data, data_len); + } else { + TEST_ASSERT(rc != 0); + ble_hs_test_util_verify_tx_err_rsp(BLE_ATT_OP_PREP_WRITE_REQ, + attr_handle, error_code); + } +} + +static void +ble_att_svr_test_misc_exec_write(uint16_t conn_handle, uint8_t flags, + uint8_t error_code, uint16_t error_handle) +{ + int rc; + + rc = ble_hs_test_util_rx_att_exec_write_req(conn_handle, flags); + if (error_code == 0) { + TEST_ASSERT(rc == 0); + ble_att_svr_test_misc_verify_tx_exec_write_rsp(); + } else { + TEST_ASSERT(rc != 0); + ble_hs_test_util_verify_tx_err_rsp(BLE_ATT_OP_EXEC_WRITE_REQ, + error_handle, error_code); + } +} + +static void +ble_att_svr_test_misc_rx_notify(uint16_t conn_handle, uint16_t attr_handle, + void *attr_val, int attr_len, int good) +{ + struct ble_att_notify_req req; + uint8_t buf[1024]; + int off; + int rc; + + req.banq_handle = attr_handle; + ble_att_notify_req_write(buf, sizeof buf, &req); + off = BLE_ATT_NOTIFY_REQ_BASE_SZ; + + memcpy(buf + off, attr_val, attr_len); + off += attr_len; + + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, off); + if (good) { + TEST_ASSERT(rc == 0); + } else { + TEST_ASSERT(rc == BLE_HS_EBADDATA); + } +} + +static void +ble_att_svr_test_misc_verify_notify(uint16_t conn_handle, uint16_t attr_handle, + void *attr_val, int attr_len, int good) +{ + ble_att_svr_test_n_conn_handle = 0xffff; + ble_att_svr_test_n_attr_handle = 0; + ble_att_svr_test_attr_n_len = 0; + + ble_att_svr_test_misc_rx_notify(conn_handle, attr_handle, attr_val, + attr_len, good); + + if (good) { + TEST_ASSERT(ble_att_svr_test_n_conn_handle == conn_handle); + TEST_ASSERT(ble_att_svr_test_n_attr_handle == attr_handle); + TEST_ASSERT(ble_att_svr_test_attr_n_len == attr_len); + TEST_ASSERT(memcmp(ble_att_svr_test_attr_n, attr_val, attr_len) == 0); + } else { + TEST_ASSERT(ble_att_svr_test_n_conn_handle == 0xffff); + TEST_ASSERT(ble_att_svr_test_n_attr_handle == 0); + TEST_ASSERT(ble_att_svr_test_attr_n_len == 0); + } +} + +static void +ble_att_svr_test_misc_verify_tx_indicate_rsp(void) +{ + struct os_mbuf *om; + + om = ble_hs_test_util_prev_tx_dequeue_pullup(); + TEST_ASSERT(om); + + ble_att_indicate_rsp_parse(om->om_data, om->om_len); +} + +static void +ble_att_svr_test_misc_rx_indicate(uint16_t conn_handle, uint16_t attr_handle, + void *attr_val, int attr_len, int good) +{ + int rc; + + rc = ble_hs_test_util_rx_att_indicate_req(conn_handle, attr_handle, + attr_val, attr_len); + if (good) { + TEST_ASSERT(rc == 0); + } else { + TEST_ASSERT(rc == BLE_HS_EBADDATA); + } +} + +static void +ble_att_svr_test_misc_verify_indicate(uint16_t conn_handle, + uint16_t attr_handle, + void *attr_val, int attr_len, int good) +{ + ble_att_svr_test_n_conn_handle = 0xffff; + ble_att_svr_test_n_attr_handle = 0; + ble_att_svr_test_attr_n_len = 0; + + ble_att_svr_test_misc_rx_indicate(conn_handle, attr_handle, attr_val, + attr_len, good); + + if (good) { + TEST_ASSERT(ble_att_svr_test_n_conn_handle == conn_handle); + TEST_ASSERT(ble_att_svr_test_n_attr_handle == attr_handle); + TEST_ASSERT(ble_att_svr_test_attr_n_len == attr_len); + TEST_ASSERT(memcmp(ble_att_svr_test_attr_n, attr_val, attr_len) == 0); + ble_att_svr_test_misc_verify_tx_indicate_rsp(); + } else { + TEST_ASSERT(ble_att_svr_test_n_conn_handle == 0xffff); + TEST_ASSERT(ble_att_svr_test_n_attr_handle == 0); + TEST_ASSERT(ble_att_svr_test_attr_n_len == 0); + TEST_ASSERT(ble_hs_test_util_prev_tx_queue_sz() == 0); + } +} + +TEST_CASE_SELF(ble_att_svr_test_mtu) +{ + /*** MTU too low; should pretend peer sent default value instead. */ + ble_att_svr_test_misc_mtu_exchange(BLE_ATT_MTU_DFLT, 5, + BLE_ATT_MTU_DFLT, BLE_ATT_MTU_DFLT); + + /*** MTUs equal. */ + ble_att_svr_test_misc_mtu_exchange(50, 50, 50, 50); + + /*** Peer's higher than mine. */ + ble_att_svr_test_misc_mtu_exchange(50, 100, 100, 50); + + /*** Mine higher than peer's. */ + ble_att_svr_test_misc_mtu_exchange(100, 50, 50, 50); + + ble_att_svr_test_assert_mbufs_freed(); +} + +TEST_CASE_SELF(ble_att_svr_test_read) +{ + struct ble_hs_conn *conn; + struct os_mbuf *om; + uint16_t attr_handle; + uint16_t conn_handle; + const ble_uuid_t *uuid_sec = BLE_UUID128_DECLARE( \ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + const ble_uuid_t *uuid_bad = BLE_UUID128_DECLARE( \ + 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + const ble_uuid_t *uuid = BLE_UUID128_DECLARE( \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ); + int rc; + + conn_handle = ble_att_svr_test_misc_init(0); + + /*** Nonexistent attribute. */ + attr_handle = 0; + rc = ble_hs_test_util_rx_att_read_req(conn_handle, attr_handle); + TEST_ASSERT(rc != 0); + ble_hs_test_util_verify_tx_err_rsp(BLE_ATT_OP_READ_REQ, 0, + BLE_ATT_ERR_INVALID_HANDLE); + + /*** Application error. */ + rc = ble_att_svr_register(uuid_bad, HA_FLAG_PERM_RW, 0, &attr_handle, + ble_att_svr_test_misc_attr_fn_r_err, NULL); + TEST_ASSERT(rc == 0); + + rc = ble_hs_test_util_rx_att_read_req(conn_handle, attr_handle); + TEST_ASSERT(rc == BLE_HS_EAPP); + ble_hs_test_util_verify_tx_err_rsp(BLE_ATT_OP_READ_REQ, attr_handle, + BLE_ATT_ERR_UNLIKELY); + + /*** Successful read. */ + ble_att_svr_test_attr_r_1 = (uint8_t[]){0,1,2,3,4,5,6,7}; + ble_att_svr_test_attr_r_1_len = 8; + rc = ble_att_svr_register(uuid, HA_FLAG_PERM_RW, 0, &attr_handle, + ble_att_svr_test_misc_attr_fn_r_1, NULL); + TEST_ASSERT(rc == 0); + + rc = ble_hs_test_util_rx_att_read_req(conn_handle, attr_handle); + TEST_ASSERT(rc == 0); + ble_hs_test_util_verify_tx_read_rsp( + ble_att_svr_test_attr_r_1, ble_att_svr_test_attr_r_1_len); + + /*** Partial read. */ + ble_att_svr_test_attr_r_1 = + (uint8_t[]){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21, + 22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39}; + ble_att_svr_test_attr_r_1_len = 40; + + rc = ble_hs_test_util_rx_att_read_req(conn_handle, attr_handle); + TEST_ASSERT(rc == 0); + ble_hs_test_util_verify_tx_read_rsp(ble_att_svr_test_attr_r_1, + BLE_ATT_MTU_DFLT - 1); + + /*** Read requires encryption. */ + /* Insufficient authentication. */ + rc = ble_att_svr_register(uuid_sec, BLE_ATT_F_READ | BLE_ATT_F_READ_ENC, 0, + &attr_handle, + ble_att_svr_test_misc_attr_fn_r_1, NULL); + TEST_ASSERT(rc == 0); + + rc = ble_hs_test_util_rx_att_read_req(conn_handle, attr_handle); + TEST_ASSERT(rc == BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN)); + ble_hs_test_util_verify_tx_err_rsp(BLE_ATT_OP_READ_REQ, attr_handle, + BLE_ATT_ERR_INSUFFICIENT_AUTHEN); + + /* Security check bypassed for local reads. */ + rc = ble_att_svr_read_local(attr_handle, &om); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(OS_MBUF_PKTLEN(om) == ble_att_svr_test_attr_r_1_len); + TEST_ASSERT(os_mbuf_cmpf(om, 0, ble_att_svr_test_attr_r_1, + ble_att_svr_test_attr_r_1_len) == 0); + rc = os_mbuf_free_chain(om); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure no response got sent. */ + TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue() == NULL); + + /* Encrypt link; success. */ + ble_hs_lock(); + conn = ble_hs_conn_find(conn_handle); + conn->bhc_sec_state.encrypted = 1; + ble_hs_unlock(); + + rc = ble_hs_test_util_rx_att_read_req(conn_handle, attr_handle); + TEST_ASSERT(rc == 0); + ble_hs_test_util_verify_tx_read_rsp(ble_att_svr_test_attr_r_1, + BLE_ATT_MTU_DFLT - 1); + + ble_att_svr_test_assert_mbufs_freed(); +} + +TEST_CASE_SELF(ble_att_svr_test_read_blob) +{ + uint16_t attr_handle; + uint16_t conn_handle; + const ble_uuid_t *uuid = BLE_UUID128_DECLARE( \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + int rc; + + conn_handle = ble_att_svr_test_misc_init(0); + + /*** Nonexistent attribute. */ + rc = ble_hs_test_util_rx_att_read_blob_req(conn_handle, 0, 0); + TEST_ASSERT(rc != 0); + ble_hs_test_util_verify_tx_err_rsp(BLE_ATT_OP_READ_BLOB_REQ, 0, + BLE_ATT_ERR_INVALID_HANDLE); + + /*** Successful partial read. */ + ble_att_svr_test_attr_r_1 = + (uint8_t[]){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21, + 22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39}; + ble_att_svr_test_attr_r_1_len = 40; + rc = ble_att_svr_register(uuid, HA_FLAG_PERM_RW, 0, &attr_handle, + ble_att_svr_test_misc_attr_fn_r_1, NULL); + TEST_ASSERT(rc == 0); + + rc = ble_hs_test_util_rx_att_read_blob_req(conn_handle, attr_handle, 0); + TEST_ASSERT(rc == 0); + ble_hs_test_util_verify_tx_read_blob_rsp(ble_att_svr_test_attr_r_1, + BLE_ATT_MTU_DFLT - 1); + + /*** Read remainder of attribute. */ + rc = ble_hs_test_util_rx_att_read_blob_req(conn_handle, attr_handle, + BLE_ATT_MTU_DFLT - 1); + TEST_ASSERT(rc == 0); + ble_hs_test_util_verify_tx_read_blob_rsp( + ble_att_svr_test_attr_r_1 + BLE_ATT_MTU_DFLT - 1, + 40 - (BLE_ATT_MTU_DFLT - 1)); + + /*** Zero-length read. */ + rc = ble_hs_test_util_rx_att_read_blob_req(conn_handle, attr_handle, + ble_att_svr_test_attr_r_1_len); + TEST_ASSERT(rc == 0); + ble_hs_test_util_verify_tx_read_blob_rsp(ble_att_svr_test_attr_r_1, + 0); + + ble_att_svr_test_assert_mbufs_freed(); +} + +TEST_CASE_SELF(ble_att_svr_test_read_mult) +{ + uint16_t conn_handle; + int rc; + + conn_handle = ble_att_svr_test_misc_init(0); + + struct ble_hs_test_util_flat_attr attrs[2] = { + { + .handle = 0, + .offset = 0, + .value = { 1, 2, 3, 4 }, + .value_len = 4, + }, + { + .handle = 0, + .offset = 0, + .value = { 2, 3, 4, 5, 6 }, + .value_len = 5, + }, + }; + + ble_att_svr_test_attr_r_1 = attrs[0].value; + ble_att_svr_test_attr_r_1_len = attrs[0].value_len; + ble_att_svr_test_attr_r_2 = attrs[1].value; + ble_att_svr_test_attr_r_2_len = attrs[1].value_len; + + rc = ble_att_svr_register(BLE_UUID16_DECLARE(0x1111), HA_FLAG_PERM_RW, 0, + &attrs[0].handle, + ble_att_svr_test_misc_attr_fn_r_1, NULL); + TEST_ASSERT(rc == 0); + + rc = ble_att_svr_register(BLE_UUID16_DECLARE(0x2222), HA_FLAG_PERM_RW, 0, + &attrs[1].handle, + ble_att_svr_test_misc_attr_fn_r_2, NULL); + TEST_ASSERT(rc == 0); + + /*** Single nonexistent attribute. */ + ble_att_svr_test_misc_rx_read_mult_req( + conn_handle, ((uint16_t[]){ 100 }), 1, 0); + ble_hs_test_util_verify_tx_err_rsp(BLE_ATT_OP_READ_MULT_REQ, + 100, BLE_ATT_ERR_INVALID_HANDLE); + + /*** Single attribute. */ + ble_att_svr_test_misc_verify_all_read_mult(conn_handle, &attrs[0], 1); + + /*** Two attributes. */ + ble_att_svr_test_misc_verify_all_read_mult(conn_handle, attrs, 2); + + /*** Reverse order. */ + ble_att_svr_test_misc_verify_all_read_mult(conn_handle, attrs, 2); + + /*** Second attribute nonexistent; verify only error txed. */ + ble_att_svr_test_misc_rx_read_mult_req( + conn_handle, ((uint16_t[]){ attrs[0].handle, 100 }), 2, 0); + ble_hs_test_util_verify_tx_err_rsp(BLE_ATT_OP_READ_MULT_REQ, + 100, BLE_ATT_ERR_INVALID_HANDLE); + + /*** Response too long; verify only MTU bytes sent. */ + attrs[0].value_len = 20; + memcpy(attrs[0].value, + ((uint8_t[]){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}), + attrs[0].value_len); + ble_att_svr_test_attr_r_1_len = attrs[0].value_len; + + attrs[1].value_len = 20; + memcpy(attrs[1].value, + ((uint8_t[]){ + 22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39 + }), + attrs[1].value_len); + ble_att_svr_test_attr_r_2_len = attrs[1].value_len; + + ble_att_svr_test_misc_verify_all_read_mult(conn_handle, attrs, 2); + + ble_att_svr_test_assert_mbufs_freed(); +} + +TEST_CASE_SELF(ble_att_svr_test_write) +{ + struct ble_hs_conn *conn; + uint16_t conn_handle; + uint16_t attr_handle; + const ble_uuid_t *uuid_sec = BLE_UUID128_DECLARE( \ + 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + const ble_uuid_t *uuid_rw = BLE_UUID128_DECLARE( \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + const ble_uuid_t *uuid_r = BLE_UUID128_DECLARE( \ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + int rc; + + static const uint8_t attr_val[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; + + conn_handle = ble_att_svr_test_misc_init(0); + + /*** Nonexistent attribute. */ + rc = ble_hs_test_util_rx_att_write_req(conn_handle, 0, + attr_val, sizeof attr_val); + TEST_ASSERT(rc != 0); + ble_hs_test_util_verify_tx_err_rsp( + BLE_ATT_OP_WRITE_REQ, 0, BLE_ATT_ERR_INVALID_HANDLE); + + /*** Write not permitted if non-local. */ + /* Non-local write (fail). */ + rc = ble_att_svr_register(uuid_r, BLE_ATT_F_READ, 0, &attr_handle, + ble_att_svr_test_misc_attr_fn_w_1, NULL); + TEST_ASSERT(rc == 0); + + rc = ble_hs_test_util_rx_att_write_req(conn_handle, attr_handle, + attr_val, sizeof attr_val); + TEST_ASSERT(rc == BLE_HS_EREJECT); + ble_hs_test_util_verify_tx_err_rsp(BLE_ATT_OP_WRITE_REQ, + attr_handle, + BLE_ATT_ERR_WRITE_NOT_PERMITTED); + + /* Local write (success). */ + rc = ble_hs_test_util_write_local_flat(attr_handle, + attr_val, sizeof attr_val); + TEST_ASSERT(rc == 0); + + /* Ensure no response got sent. */ + TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue() == NULL); + + /*** Successful write. */ + rc = ble_att_svr_register(uuid_rw, HA_FLAG_PERM_RW, 0, &attr_handle, + ble_att_svr_test_misc_attr_fn_w_1, NULL); + TEST_ASSERT(rc == 0); + + rc = ble_hs_test_util_rx_att_write_req(conn_handle, attr_handle, + attr_val, sizeof attr_val); + TEST_ASSERT(rc == 0); + ble_hs_test_util_verify_tx_write_rsp(); + + /*** Write requires encryption. */ + /* Insufficient authentication. */ + rc = ble_att_svr_register(uuid_sec, BLE_ATT_F_WRITE | BLE_ATT_F_WRITE_ENC, + 0, &attr_handle, + ble_att_svr_test_misc_attr_fn_w_1, NULL); + TEST_ASSERT(rc == 0); + + rc = ble_hs_test_util_rx_att_write_req(conn_handle, attr_handle, + attr_val, sizeof attr_val); + TEST_ASSERT(rc == BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN)); + ble_hs_test_util_verify_tx_err_rsp(BLE_ATT_OP_WRITE_REQ, + attr_handle, + BLE_ATT_ERR_INSUFFICIENT_AUTHEN); + + /* Security check bypassed for local writes. */ + rc = ble_hs_test_util_write_local_flat(attr_handle, + attr_val, sizeof attr_val); + TEST_ASSERT(rc == 0); + + /* Ensure no response got sent. */ + TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue() == NULL); + + /* Encrypt link; success. */ + ble_hs_lock(); + conn = ble_hs_conn_find(conn_handle); + conn->bhc_sec_state.encrypted = 1; + ble_hs_unlock(); + + rc = ble_hs_test_util_rx_att_write_req(conn_handle, attr_handle, + attr_val, sizeof attr_val); + TEST_ASSERT(rc == 0); + ble_hs_test_util_verify_tx_write_rsp(); + + ble_att_svr_test_assert_mbufs_freed(); +} + +TEST_CASE_SELF(ble_att_svr_test_find_info) +{ + uint16_t conn_handle; + uint16_t handle1; + uint16_t handle2; + uint16_t handle3; + const ble_uuid_t *uuid1 = + BLE_UUID128_DECLARE(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ,11, 12, 13, 14, 15); + const ble_uuid_t *uuid2 = + BLE_UUID128_DECLARE(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + const ble_uuid_t *uuid3 = BLE_UUID16_DECLARE(0x000f); + int rc; + + conn_handle = ble_att_svr_test_misc_init(128); + + /*** Start handle of 0. */ + rc = ble_hs_test_util_rx_att_find_info_req(conn_handle, 0, 0); + TEST_ASSERT(rc != 0); + ble_hs_test_util_verify_tx_err_rsp( + BLE_ATT_OP_FIND_INFO_REQ, 0, BLE_ATT_ERR_INVALID_HANDLE); + + /*** Start handle > end handle. */ + rc = ble_hs_test_util_rx_att_find_info_req(conn_handle, 101, 100); + TEST_ASSERT(rc != 0); + ble_hs_test_util_verify_tx_err_rsp( + BLE_ATT_OP_FIND_INFO_REQ, 101, BLE_ATT_ERR_INVALID_HANDLE); + + /*** No attributes. */ + rc = ble_hs_test_util_rx_att_find_info_req(conn_handle, 200, 300); + TEST_ASSERT(rc != 0); + ble_hs_test_util_verify_tx_err_rsp( + BLE_ATT_OP_FIND_INFO_REQ, 200, BLE_ATT_ERR_ATTR_NOT_FOUND); + + /*** Range too late. */ + rc = ble_att_svr_register(uuid1, HA_FLAG_PERM_RW, 0, &handle1, + ble_att_svr_test_misc_attr_fn_r_1, NULL); + TEST_ASSERT(rc == 0); + + rc = ble_hs_test_util_rx_att_find_info_req(conn_handle, 200, 300); + TEST_ASSERT(rc != 0); + ble_hs_test_util_verify_tx_err_rsp( + BLE_ATT_OP_FIND_INFO_REQ, 200, BLE_ATT_ERR_ATTR_NOT_FOUND); + + /*** One 128-bit entry. */ + rc = ble_hs_test_util_rx_att_find_info_req(conn_handle, handle1, handle1); + TEST_ASSERT(rc == 0); + ble_hs_test_util_verify_tx_find_info_rsp( + ((struct ble_hs_test_util_att_info_entry[]) { { + .handle = handle1, + .uuid = BLE_UUID128_DECLARE(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15), + }, { + .handle = 0, + } })); + + /*** Two 128-bit entries. */ + rc = ble_att_svr_register(uuid2, HA_FLAG_PERM_RW, 0, &handle2, + ble_att_svr_test_misc_attr_fn_r_1, NULL); + TEST_ASSERT(rc == 0); + + rc = ble_hs_test_util_rx_att_find_info_req(conn_handle, handle1, handle2); + TEST_ASSERT(rc == 0); + ble_hs_test_util_verify_tx_find_info_rsp( + ((struct ble_hs_test_util_att_info_entry[]) { { + .handle = handle1, + .uuid = BLE_UUID128_DECLARE(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15), + }, { + .handle = handle2, + .uuid = BLE_UUID128_DECLARE(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16), + }, { + .handle = 0, + } })); + + /*** Two 128-bit entries; 16-bit entry doesn't get sent. */ + rc = ble_att_svr_register(uuid3, HA_FLAG_PERM_RW, 0, &handle3, + ble_att_svr_test_misc_attr_fn_r_1, NULL); + TEST_ASSERT(rc == 0); + + rc = ble_hs_test_util_rx_att_find_info_req(conn_handle, handle1, handle3); + TEST_ASSERT(rc == 0); + ble_hs_test_util_verify_tx_find_info_rsp( + ((struct ble_hs_test_util_att_info_entry[]) { { + .handle = handle1, + .uuid = BLE_UUID128_DECLARE(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15), + }, { + .handle = handle2, + .uuid = BLE_UUID128_DECLARE(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16), + }, { + .handle = 0, + } })); + + /*** Remaining 16-bit entry requested. */ + rc = ble_hs_test_util_rx_att_find_info_req(conn_handle, handle3, handle3); + TEST_ASSERT(rc == 0); + ble_hs_test_util_verify_tx_find_info_rsp( + ((struct ble_hs_test_util_att_info_entry[]) { { + .handle = handle3, + .uuid = BLE_UUID16_DECLARE(0x000f), + }, { + .handle = 0, + } })); + + ble_att_svr_test_assert_mbufs_freed(); +} + +TEST_CASE_SELF(ble_att_svr_test_find_type_value) +{ + uint16_t conn_handle; + uint16_t handle1; + uint16_t handle2; + uint16_t handle3; + uint16_t handle4; + uint16_t handle5; + uint16_t handle_desc; + const ble_uuid_t *uuid1 = BLE_UUID16_DECLARE(0x2800); + const ble_uuid_t *uuid2 = BLE_UUID16_DECLARE(0x2803); + const ble_uuid_t *uuid3 = + BLE_UUID128_DECLARE(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + int rc; + + conn_handle = ble_att_svr_test_misc_init(128); + + ble_att_svr_test_attr_r_1 = (uint8_t[]){0x99, 0x99}; + ble_att_svr_test_attr_r_1_len = 2; + + /*** Start handle of 0. */ + rc = ble_hs_test_util_rx_att_find_type_value_req( + conn_handle, 0, 0, 0x2800, ble_att_svr_test_attr_r_1, + ble_att_svr_test_attr_r_1_len); + TEST_ASSERT(rc != 0); + ble_hs_test_util_verify_tx_err_rsp( + BLE_ATT_OP_FIND_TYPE_VALUE_REQ, 0, + BLE_ATT_ERR_INVALID_HANDLE); + + /*** Start handle > end handle. */ + rc = ble_hs_test_util_rx_att_find_type_value_req( + conn_handle, 101, 100, 0x2800, ble_att_svr_test_attr_r_1, + ble_att_svr_test_attr_r_1_len); + TEST_ASSERT(rc != 0); + ble_hs_test_util_verify_tx_err_rsp( + BLE_ATT_OP_FIND_TYPE_VALUE_REQ, 101, + BLE_ATT_ERR_INVALID_HANDLE); + + /*** No attributes. */ + rc = ble_hs_test_util_rx_att_find_type_value_req( + conn_handle, 200, 300, 0x2800, ble_att_svr_test_attr_r_1, + ble_att_svr_test_attr_r_1_len); + TEST_ASSERT(rc != 0); + ble_hs_test_util_verify_tx_err_rsp( + BLE_ATT_OP_FIND_TYPE_VALUE_REQ, 200, + BLE_ATT_ERR_ATTR_NOT_FOUND); + + /*** Range too late. */ + rc = ble_att_svr_register(uuid1, HA_FLAG_PERM_RW, 0, &handle1, + ble_att_svr_test_misc_attr_fn_r_1, NULL); + TEST_ASSERT(rc == 0); + + rc = ble_hs_test_util_rx_att_find_type_value_req( + conn_handle, 200, 300, 0x2800, ble_att_svr_test_attr_r_1, + ble_att_svr_test_attr_r_1_len); + TEST_ASSERT(rc != 0); + ble_hs_test_util_verify_tx_err_rsp( + BLE_ATT_OP_FIND_TYPE_VALUE_REQ, 200, + BLE_ATT_ERR_ATTR_NOT_FOUND); + + /*** One entry, one attribute. */ + rc = ble_hs_test_util_rx_att_find_type_value_req( + conn_handle, handle1, handle1, 0x2800, ble_att_svr_test_attr_r_1, + ble_att_svr_test_attr_r_1_len); + TEST_ASSERT(rc == 0); + ble_att_svr_test_misc_verify_tx_find_type_value_rsp( + ((struct ble_att_svr_test_type_value_entry[]) { { + .first = handle1, + .last = handle1, + }, { + .first = 0, + } })); + + /*** One entry, two attributes. */ + rc = ble_att_svr_register(uuid2, HA_FLAG_PERM_RW, 0, &handle2, + ble_att_svr_test_misc_attr_fn_r_1, NULL); + TEST_ASSERT(rc == 0); + + rc = ble_hs_test_util_rx_att_find_type_value_req( + conn_handle, handle1, handle2, 0x2800, ble_att_svr_test_attr_r_1, + ble_att_svr_test_attr_r_1_len); + TEST_ASSERT(rc == 0); + ble_att_svr_test_misc_verify_tx_find_type_value_rsp( + ((struct ble_att_svr_test_type_value_entry[]) { { + .first = handle1, + .last = handle2, + }, { + .first = 0, + } })); + + /*** Entry 1: four attributes; entry 2 (invalid value): one attribute; + * entry 3: one attribute; Check that invalid value is not returned. */ + ble_att_svr_test_attr_r_2 = (uint8_t[]){0x00, 0x00}; + ble_att_svr_test_attr_r_2_len = 2; + + rc = ble_att_svr_register(uuid3, HA_FLAG_PERM_RW, 0, &handle_desc, + ble_att_svr_test_misc_attr_fn_r_2, NULL); + TEST_ASSERT(rc == 0); + + rc = ble_att_svr_register(uuid2, HA_FLAG_PERM_RW, 0, &handle3, + ble_att_svr_test_misc_attr_fn_r_2, NULL); + TEST_ASSERT(rc == 0); + + rc = ble_att_svr_register(uuid1, HA_FLAG_PERM_RW, 0, &handle4, + ble_att_svr_test_misc_attr_fn_r_2, NULL); + TEST_ASSERT(rc == 0); + + rc = ble_att_svr_register(uuid1, HA_FLAG_PERM_RW, 0, &handle5, + ble_att_svr_test_misc_attr_fn_r_1, NULL); + TEST_ASSERT(rc == 0); + + rc = ble_hs_test_util_rx_att_find_type_value_req( + conn_handle, 0x0001, 0xffff, 0x2800, ble_att_svr_test_attr_r_1, + ble_att_svr_test_attr_r_1_len); + TEST_ASSERT(rc == 0); + ble_att_svr_test_misc_verify_tx_find_type_value_rsp( + ((struct ble_att_svr_test_type_value_entry[]) { { + .first = handle1, + .last = handle3, + }, { + .first = handle5, + .last = handle5, + }, { + .first = 0, + } })); + + /*** As above, check proper range is returned with smaller search range */ + rc = ble_hs_test_util_rx_att_find_type_value_req( + conn_handle, 0x0001, 0x0001, 0x2800, ble_att_svr_test_attr_r_1, + ble_att_svr_test_attr_r_1_len); + TEST_ASSERT(rc == 0); + ble_att_svr_test_misc_verify_tx_find_type_value_rsp( + ((struct ble_att_svr_test_type_value_entry[]) { { + .first = handle1, + .last = handle3, + }, { + .first = 0, + } })); + + /*** As above, check grouping by Characteristic UUID */ + rc = ble_hs_test_util_rx_att_find_type_value_req( + conn_handle, handle1, handle3, 0x2803, ble_att_svr_test_attr_r_1, + ble_att_svr_test_attr_r_1_len); + TEST_ASSERT(rc == 0); + ble_att_svr_test_misc_verify_tx_find_type_value_rsp( + ((struct ble_att_svr_test_type_value_entry[]) { { + .first = handle2, + .last = handle_desc, + }, { + .first = 0, + } })); + + ble_att_svr_test_assert_mbufs_freed(); +} + +static void +ble_att_svr_test_misc_read_type(uint16_t mtu) +{ + uint16_t conn_handle; + int rc; + + conn_handle = ble_att_svr_test_misc_init(mtu); + + /*** Start handle of 0. */ + rc = ble_hs_test_util_rx_att_read_type_req16(conn_handle, 0, 0, + BLE_ATT_UUID_PRIMARY_SERVICE); + TEST_ASSERT(rc != 0); + ble_hs_test_util_verify_tx_err_rsp( + BLE_ATT_OP_READ_TYPE_REQ, 0, + BLE_ATT_ERR_INVALID_HANDLE); + + /*** Start handle > end handle. */ + rc = ble_hs_test_util_rx_att_read_type_req16(conn_handle, 101, 100, + BLE_ATT_UUID_PRIMARY_SERVICE); + TEST_ASSERT(rc != 0); + ble_hs_test_util_verify_tx_err_rsp( + BLE_ATT_OP_READ_TYPE_REQ, 101, + BLE_ATT_ERR_INVALID_HANDLE); + + /*** No attributes. */ + rc = ble_hs_test_util_rx_att_read_type_req16(conn_handle, 1, 0xffff, + BLE_ATT_UUID_PRIMARY_SERVICE); + TEST_ASSERT(rc != 0); + ble_hs_test_util_verify_tx_err_rsp( + BLE_ATT_OP_READ_TYPE_REQ, 1, + BLE_ATT_ERR_ATTR_NOT_FOUND); + + /*** Range too late. */ + ble_att_svr_test_misc_register_group_attrs(); + rc = ble_hs_test_util_rx_att_read_type_req16(conn_handle, 200, 300, + BLE_ATT_UUID_PRIMARY_SERVICE); + TEST_ASSERT(rc != 0); + ble_hs_test_util_verify_tx_err_rsp( + BLE_ATT_OP_READ_TYPE_REQ, 200, + BLE_ATT_ERR_ATTR_NOT_FOUND); + + /*** One characteristic from one service. */ + rc = ble_hs_test_util_rx_att_read_type_req16(conn_handle, 1, 2, + BLE_ATT_UUID_CHARACTERISTIC); + TEST_ASSERT(rc == 0); + ble_att_svr_test_misc_verify_tx_read_type_rsp( + ((struct ble_att_svr_test_type_entry[]) { { + .handle = 2, + .value = (uint8_t[]){ 0x01, 0x11 }, + .value_len = 2, + }, { + .handle = 0, + } })); + + /*** Both characteristics from one service. */ + rc = ble_hs_test_util_rx_att_read_type_req16(conn_handle, 1, 10, + BLE_ATT_UUID_CHARACTERISTIC); + TEST_ASSERT(rc == 0); + ble_att_svr_test_misc_verify_tx_read_type_rsp( + ((struct ble_att_svr_test_type_entry[]) { { + .handle = 2, + .value = (uint8_t[]){ 0x01, 0x11 }, + .value_len = 2, + }, { + .handle = 4, + .value = (uint8_t[]){ 0x03, 0x11 }, + .value_len = 2, + }, { + .handle = 0, + } })); + + /*** Ensure 16-bit and 128-bit values are retrieved separately. */ + rc = ble_hs_test_util_rx_att_read_type_req16(conn_handle, 11, 0xffff, + BLE_ATT_UUID_CHARACTERISTIC); + TEST_ASSERT(rc == 0); + ble_att_svr_test_misc_verify_tx_read_type_rsp( + ((struct ble_att_svr_test_type_entry[]) { { + .handle = 12, + .value = (uint8_t[]){ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }, + .value_len = 16, + }, { + .handle = 0, + } })); + + rc = ble_hs_test_util_rx_att_read_type_req16(conn_handle, 13, 0xffff, + BLE_ATT_UUID_CHARACTERISTIC); + TEST_ASSERT(rc == 0); + ble_att_svr_test_misc_verify_tx_read_type_rsp( + ((struct ble_att_svr_test_type_entry[]) { { + .handle = 14, + .value = (uint8_t[]){ 0x55, 0x55 }, + .value_len = 2, + }, { + .handle = 0, + } })); + + rc = ble_hs_test_util_rx_att_read_type_req16(conn_handle, 15, 0xffff, + BLE_ATT_UUID_CHARACTERISTIC); + TEST_ASSERT(rc == 0); + ble_att_svr_test_misc_verify_tx_read_type_rsp( + ((struct ble_att_svr_test_type_entry[]) { { + .handle = 16, + .value = (uint8_t[]){ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 }, + .value_len = 16, + }, { + .handle = 0, + } })); + + /*** Read until the end of the attribute list. */ + rc = ble_hs_test_util_rx_att_read_type_req16(conn_handle, 17, 0xffff, + BLE_ATT_UUID_CHARACTERISTIC); + TEST_ASSERT(rc == 0); + ble_att_svr_test_misc_verify_tx_read_type_rsp( + ((struct ble_att_svr_test_type_entry[]) { { + .handle = 18, + .value = (uint8_t[]){ 0x66, 0x66 }, + .value_len = 2, + }, { + .handle = 20, + .value = (uint8_t[]){ 0x77, 0x77 }, + .value_len = 2, + }, { + .handle = 22, + .value = (uint8_t[]){ 0x88, 0x88 }, + .value_len = 2, + }, { + .handle = 24, + .value = (uint8_t[]){ 0x99, 0x99 }, + .value_len = 2, + }, { + .handle = 0, + } })); + + ble_att_svr_test_assert_mbufs_freed(); +} + +TEST_CASE_SELF(ble_att_svr_test_read_type) +{ + ble_att_svr_test_misc_read_type(0); + ble_att_svr_test_misc_read_type(128); + + ble_att_svr_test_assert_mbufs_freed(); +} + +TEST_CASE_SELF(ble_att_svr_test_read_group_type) +{ + uint16_t conn_handle; + int rc; + + conn_handle = ble_att_svr_test_misc_init(128); + + /*** Start handle of 0. */ + rc = ble_hs_test_util_rx_att_read_group_type_req16( + conn_handle, 0, 0, BLE_ATT_UUID_PRIMARY_SERVICE); + TEST_ASSERT(rc != 0); + ble_hs_test_util_verify_tx_err_rsp( + BLE_ATT_OP_READ_GROUP_TYPE_REQ, 0, + BLE_ATT_ERR_INVALID_HANDLE); + + /*** Start handle > end handle. */ + rc = ble_hs_test_util_rx_att_read_group_type_req16( + conn_handle, 101, 100, BLE_ATT_UUID_PRIMARY_SERVICE); + TEST_ASSERT(rc != 0); + ble_hs_test_util_verify_tx_err_rsp( + BLE_ATT_OP_READ_GROUP_TYPE_REQ, 101, + BLE_ATT_ERR_INVALID_HANDLE); + + /*** Invalid group UUID (0x1234). */ + rc = ble_hs_test_util_rx_att_read_group_type_req16( + conn_handle, 110, 150, 0x1234); + TEST_ASSERT(rc != 0); + ble_hs_test_util_verify_tx_err_rsp( + BLE_ATT_OP_READ_GROUP_TYPE_REQ, 110, + BLE_ATT_ERR_UNSUPPORTED_GROUP); + + /*** No attributes. */ + rc = ble_hs_test_util_rx_att_read_group_type_req16( + conn_handle, 1, 0xffff, BLE_ATT_UUID_PRIMARY_SERVICE); + TEST_ASSERT(rc != 0); + ble_hs_test_util_verify_tx_err_rsp( + BLE_ATT_OP_READ_GROUP_TYPE_REQ, 1, + BLE_ATT_ERR_ATTR_NOT_FOUND); + + /*** Range too late. */ + ble_att_svr_test_misc_register_group_attrs(); + + rc = ble_hs_test_util_rx_att_read_group_type_req16( + conn_handle, 200, 300, BLE_ATT_UUID_PRIMARY_SERVICE); + TEST_ASSERT(rc != 0); + ble_hs_test_util_verify_tx_err_rsp( + BLE_ATT_OP_READ_GROUP_TYPE_REQ, 200, + BLE_ATT_ERR_ATTR_NOT_FOUND); + + /*** One 16-bit UUID service. */ + rc = ble_hs_test_util_rx_att_read_group_type_req16( + conn_handle, 1, 5, BLE_ATT_UUID_PRIMARY_SERVICE); + TEST_ASSERT(rc == 0); + ble_hs_test_util_verify_tx_read_group_type_rsp( + ((struct ble_hs_test_util_att_group_type_entry[]) { { + .start_handle = 1, + .end_handle = 5, + .uuid = BLE_UUID16_DECLARE(0x1122), + }, { + .start_handle = 0, + } })); + + /*** Two 16-bit UUID services. */ + rc = ble_hs_test_util_rx_att_read_group_type_req16( + conn_handle, 1, 10, BLE_ATT_UUID_PRIMARY_SERVICE); + TEST_ASSERT(rc == 0); + ble_hs_test_util_verify_tx_read_group_type_rsp( + ((struct ble_hs_test_util_att_group_type_entry[]) { { + .start_handle = 1, + .end_handle = 5, + .uuid = BLE_UUID16_DECLARE(0x1122), + }, { + .start_handle = 6, + .end_handle = 10, + .uuid = BLE_UUID16_DECLARE(0x2233), + }, { + .start_handle = 0, + } })); + + /*** Two 16-bit UUID services; ensure 128-bit service not returned. */ + rc = ble_hs_test_util_rx_att_read_group_type_req16( + conn_handle, 1, 100, BLE_ATT_UUID_PRIMARY_SERVICE); + TEST_ASSERT(rc == 0); + ble_hs_test_util_verify_tx_read_group_type_rsp( + ((struct ble_hs_test_util_att_group_type_entry[]) { { + .start_handle = 1, + .end_handle = 5, + .uuid = BLE_UUID16_DECLARE(0x1122), + }, { + .start_handle = 6, + .end_handle = 10, + .uuid = BLE_UUID16_DECLARE(0x2233), + }, { + .start_handle = 0, + } })); + + /*** One 128-bit service. */ + rc = ble_hs_test_util_rx_att_read_group_type_req16( + conn_handle, 11, 100, BLE_ATT_UUID_PRIMARY_SERVICE); + TEST_ASSERT(rc == 0); + ble_hs_test_util_verify_tx_read_group_type_rsp( + ((struct ble_hs_test_util_att_group_type_entry[]) { { + .start_handle = 11, + .end_handle = 0xffff, + .uuid = BLE_UUID128_DECLARE(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16), + }, { + .start_handle = 0, + } })); + + ble_att_svr_test_assert_mbufs_freed(); +} + +TEST_CASE_SELF(ble_att_svr_test_prep_write) +{ + struct ble_hs_conn *conn; + uint16_t conn_handle; + int i; + + static uint8_t data[1024]; + + conn_handle = ble_att_svr_test_misc_init(205); + + /* Initialize some attribute data. */ + for (i = 0; i < sizeof data; i++) { + data[i] = i; + } + + /* Register two writable attributes. */ + ble_att_svr_test_misc_register_uuid(BLE_UUID16_DECLARE(0x1234), + HA_FLAG_PERM_RW, 1, + ble_att_svr_test_misc_attr_fn_w_1); + ble_att_svr_test_misc_register_uuid(BLE_UUID16_DECLARE(0x8989), + HA_FLAG_PERM_RW, 2, + ble_att_svr_test_misc_attr_fn_w_2); + + /* 3: not writable. */ + ble_att_svr_test_misc_register_uuid(BLE_UUID16_DECLARE(0xabab), + BLE_ATT_F_READ, 3, + ble_att_svr_test_misc_attr_fn_r_1); + /* 4: Encryption required. */ + ble_att_svr_test_misc_register_uuid( + BLE_UUID16_DECLARE(0xabac), BLE_ATT_F_WRITE | BLE_ATT_F_WRITE_ENC, 4, + ble_att_svr_test_misc_attr_fn_w_1); + + /* 5: Encryption+authentication required. */ + ble_att_svr_test_misc_register_uuid( + BLE_UUID16_DECLARE(0xabad), + BLE_ATT_F_WRITE | BLE_ATT_F_WRITE_ENC | BLE_ATT_F_WRITE_AUTHEN, + 5, ble_att_svr_test_misc_attr_fn_w_1); + + /* 6: Write callback always fails. */ + ble_att_svr_test_misc_register_uuid( + BLE_UUID16_DECLARE(0xabae), BLE_ATT_F_WRITE, 6, + ble_att_svr_test_misc_attr_fn_w_fail); + + /*** Empty write succeeds. */ + ble_att_svr_test_misc_exec_write(conn_handle, BLE_ATT_EXEC_WRITE_F_EXECUTE, + 0, 0); + + /*** Empty cancel succeeds. */ + ble_att_svr_test_misc_exec_write(conn_handle, 0, 0, 0); + + /*** Failure for prep write to nonexistent attribute. */ + ble_att_svr_test_misc_prep_write(conn_handle, 53525, 0, data, 10, + BLE_ATT_ERR_INVALID_HANDLE); + + /*** Failure due to write-not-permitted. */ + ble_att_svr_test_misc_prep_write(conn_handle, 3, 0, data, 35, + BLE_ATT_ERR_WRITE_NOT_PERMITTED); + + /*** Failure due to insufficient authentication (encryption required). */ + ble_att_svr_test_misc_prep_write(conn_handle, 4, 0, data, 1, + BLE_ATT_ERR_INSUFFICIENT_AUTHEN); + + /*** Encrypt connection; ensure previous prep write now succeeds. */ + ble_hs_lock(); + conn = ble_hs_conn_find(2); + TEST_ASSERT_FATAL(conn != NULL); + conn->bhc_sec_state.encrypted = 1; + ble_hs_unlock(); + + ble_att_svr_test_misc_prep_write(conn_handle, 4, 0, data, 1, 0); + ble_att_svr_test_misc_exec_write(conn_handle, 0, 0, 0); + + /*** Failure due to insufficient authentication (not authenticated). */ + ble_att_svr_test_misc_prep_write(conn_handle, 5, 0, data, 35, + BLE_ATT_ERR_INSUFFICIENT_AUTHEN); + + /*** Failure for write starting at nonzero offset. */ + ble_att_svr_test_misc_prep_write(conn_handle, 1, 1, data, 10, 0); + ble_att_svr_test_misc_exec_write(conn_handle, BLE_ATT_EXEC_WRITE_F_EXECUTE, + BLE_ATT_ERR_INVALID_OFFSET, 1); + ble_att_svr_test_misc_verify_w_1(NULL, 0); + + /*** Success for clear starting at nonzero offset. */ + ble_att_svr_test_misc_prep_write(conn_handle, 1, 1, data, 10, 0); + ble_att_svr_test_misc_exec_write(conn_handle, 0, 0, 0); + ble_att_svr_test_misc_verify_w_1(NULL, 0); + + /*** Failure for write with gap. */ + ble_att_svr_test_misc_prep_write(conn_handle, 1, 0, data, 10, 0); + ble_att_svr_test_misc_prep_write(conn_handle, 1, 11, data, 10, 0); + ble_att_svr_test_misc_exec_write(conn_handle, BLE_ATT_EXEC_WRITE_F_EXECUTE, + BLE_ATT_ERR_INVALID_OFFSET, 1); + ble_att_svr_test_misc_verify_w_1(NULL, 0); + + /*** Success for clear with gap. */ + ble_att_svr_test_misc_prep_write(conn_handle, 1, 0, data, 10, 0); + ble_att_svr_test_misc_prep_write(conn_handle, 1, 11, data, 10, 0); + ble_att_svr_test_misc_exec_write(conn_handle, 0, 0, 0); + ble_att_svr_test_misc_verify_w_1(NULL, 0); + + /*** Failure for overlong write. */ + ble_att_svr_test_misc_prep_write(conn_handle, 1, 0, data, 200, 0); + ble_att_svr_test_misc_prep_write(conn_handle, 1, 200, data + 200, 200, 0); + ble_att_svr_test_misc_prep_write(conn_handle, 1, 400, data + 400, 200, 0); + ble_att_svr_test_misc_exec_write(conn_handle, BLE_ATT_EXEC_WRITE_F_EXECUTE, + BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN, 1); + ble_att_svr_test_misc_verify_w_1(NULL, 0); + + /*** Successful two part write. */ + ble_att_svr_test_misc_prep_write(conn_handle, 1, 0, data, 20, 0); + ble_att_svr_test_misc_prep_write(conn_handle, 1, 20, data + 20, 20, 0); + ble_att_svr_test_misc_exec_write(conn_handle, BLE_ATT_EXEC_WRITE_F_EXECUTE, + 0, 0); + ble_att_svr_test_misc_verify_w_1(data, 40); + + /*** Successful three part write. */ + ble_att_svr_test_misc_prep_write(conn_handle, 1, 0, data, 35, 0); + ble_att_svr_test_misc_prep_write(conn_handle, 1, 35, data + 35, 43, 0); + ble_att_svr_test_misc_prep_write(conn_handle, 1, 78, data + 78, 1, 0); + ble_att_svr_test_misc_exec_write(conn_handle, BLE_ATT_EXEC_WRITE_F_EXECUTE, + 0, 0); + ble_att_svr_test_misc_verify_w_1(data, 79); + + /*** Successful two part write to two attributes. */ + ble_att_svr_test_misc_prep_write(conn_handle, 1, 0, data, 7, 0); + ble_att_svr_test_misc_prep_write(conn_handle, 1, 7, data + 7, 10, 0); + ble_att_svr_test_misc_prep_write(conn_handle, 2, 0, data, 20, 0); + ble_att_svr_test_misc_prep_write(conn_handle, 2, 20, data + 20, 10, 0); + ble_att_svr_test_misc_exec_write(conn_handle, BLE_ATT_EXEC_WRITE_F_EXECUTE, + 0, 0); + ble_att_svr_test_misc_verify_w_1(data, 17); + ble_att_svr_test_misc_verify_w_2(data, 30); + + /*** Fail write to second attribute; ensure first write doesn't occur. */ + ble_att_svr_test_misc_prep_write(conn_handle, 1, 0, data, 5, 0); + ble_att_svr_test_misc_prep_write(conn_handle, 1, 5, data + 5, 2, 0); + ble_att_svr_test_misc_prep_write(conn_handle, 2, 0, data, 11, 0); + ble_att_svr_test_misc_prep_write(conn_handle, 2, 12, data + 11, 19, 0); + ble_att_svr_test_misc_exec_write(conn_handle, BLE_ATT_EXEC_WRITE_F_EXECUTE, + BLE_ATT_ERR_INVALID_OFFSET, 2); + ble_att_svr_test_misc_verify_w_1(data, 17); + ble_att_svr_test_misc_verify_w_2(data, 30); + + /*** Successful out of order write to two attributes. */ + ble_att_svr_test_misc_prep_write(conn_handle, 1, 0, data, 9, 0); + ble_att_svr_test_misc_prep_write(conn_handle, 2, 0, data, 18, 0); + ble_att_svr_test_misc_prep_write(conn_handle, 1, 9, data + 9, 3, 0); + ble_att_svr_test_misc_prep_write(conn_handle, 2, 18, data + 18, 43, 0); + ble_att_svr_test_misc_exec_write(conn_handle, BLE_ATT_EXEC_WRITE_F_EXECUTE, + 0, 0); + ble_att_svr_test_misc_verify_w_1(data, 12); + ble_att_svr_test_misc_verify_w_2(data, 61); + + /*** Fail due to attribute callback error. */ + ble_att_svr_test_misc_prep_write(conn_handle, 6, 0, data, 35, 0); + ble_att_svr_test_misc_prep_write(conn_handle, 6, 35, data + 35, 43, 0); + ble_att_svr_test_misc_prep_write(conn_handle, 6, 78, data + 78, 1, 0); + ble_att_svr_test_misc_exec_write(conn_handle, BLE_ATT_EXEC_WRITE_F_EXECUTE, + BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN, 6); + + ble_att_svr_test_assert_mbufs_freed(); +} + +TEST_CASE_SELF(ble_att_svr_test_notify) +{ + uint16_t conn_handle; + + conn_handle = ble_att_svr_test_misc_init(0); + + /*** Successful notifies; verify callback is executed. */ + /* 3-length attribute. */ + ble_att_svr_test_misc_verify_notify(conn_handle, 10, + (uint8_t[]) { 1, 2, 3 }, 3, 1); + /* 1-length attribute. */ + ble_att_svr_test_misc_verify_notify(conn_handle, 1, + (uint8_t[]) { 0xff }, 1, 1); + /* 0-length attribute. */ + ble_att_svr_test_misc_verify_notify(conn_handle, 43, NULL, 0, 1); + + /*** Bad notifies; verify callback is not executed. */ + /* Attribute handle of 0. */ + ble_att_svr_test_misc_verify_notify(conn_handle, 0, + (uint8_t[]) { 1, 2, 3 }, 3, 0); + + ble_att_svr_test_assert_mbufs_freed(); +} + +TEST_CASE_SELF(ble_att_svr_test_prep_write_tmo) +{ + int32_t ticks_from_now; + uint16_t conn_handle; + int rc; + int i; + + static uint8_t data[1024]; + + conn_handle = ble_att_svr_test_misc_init(205); + + /* Initialize some attribute data. */ + for (i = 0; i < sizeof data; i++) { + data[i] = i; + } + + /* Register a writable attribute. */ + ble_att_svr_test_misc_register_uuid(BLE_UUID16_DECLARE(0x1234), + HA_FLAG_PERM_RW, 1, + ble_att_svr_test_misc_attr_fn_w_1); + + /* Ensure timer is not set. */ + ticks_from_now = ble_hs_conn_timer(); + TEST_ASSERT_FATAL(ticks_from_now == BLE_HS_FOREVER); + + /* Receive a prepare write request. */ + ble_att_svr_test_misc_prep_write(conn_handle, 1, 0, data, 7, 0); + + /* Ensure timer will expire in 30 seconds. */ + ticks_from_now = ble_hs_conn_timer(); + TEST_ASSERT(ticks_from_now == BLE_HS_ATT_SVR_QUEUED_WRITE_TMO); + + /* Almost let the timer expire. */ + os_time_advance(BLE_HS_ATT_SVR_QUEUED_WRITE_TMO - 1); + ticks_from_now = ble_hs_conn_timer(); + TEST_ASSERT(ticks_from_now == 1); + + /* Receive a second prepare write request. */ + ble_att_svr_test_misc_prep_write(conn_handle, 1, 7, data + 7, 10, 0); + + /* Ensure timer got reset. */ + ticks_from_now = ble_hs_conn_timer(); + TEST_ASSERT(ticks_from_now == BLE_HS_ATT_SVR_QUEUED_WRITE_TMO); + + /* Allow the timer to expire. */ + ble_hs_test_util_hci_ack_set_disconnect(0); + os_time_advance(BLE_HS_ATT_SVR_QUEUED_WRITE_TMO); + ticks_from_now = ble_hs_conn_timer(); + TEST_ASSERT(ticks_from_now == BLE_HS_FOREVER); + + /* Ensure connection was terminated. */ + ble_hs_test_util_hci_verify_tx_disconnect(2, BLE_ERR_REM_USER_CONN_TERM); + + /* Free connection. This is needed so that the prep write mbufs get + * freed and no mbuf leak gets reported. + */ + rc = ble_hs_atomic_conn_delete(conn_handle); + TEST_ASSERT_FATAL(rc == 0); + + ble_att_svr_test_assert_mbufs_freed(); +} + +TEST_CASE_SELF(ble_att_svr_test_indicate) +{ + uint16_t conn_handle; + + conn_handle = ble_att_svr_test_misc_init(0); + + /*** Successful indicates; verify callback is executed. */ + /* 3-length attribute. */ + ble_att_svr_test_misc_verify_indicate(conn_handle, 10, + (uint8_t[]) { 1, 2, 3 }, 3, 1); + /* 1-length attribute. */ + ble_att_svr_test_misc_verify_indicate(conn_handle, 1, + (uint8_t[]) { 0xff }, 1, 1); + /* 0-length attribute. */ + ble_att_svr_test_misc_verify_indicate(conn_handle, 43, NULL, 0, 1); + + /*** Bad indicates; verify callback is not executed. */ + /* Attribute handle of 0. */ + ble_att_svr_test_misc_verify_indicate(conn_handle, 0, + (uint8_t[]) { 1, 2, 3 }, 3, 0); + + ble_att_svr_test_assert_mbufs_freed(); +} + +TEST_CASE_SELF(ble_att_svr_test_oom) +{ + struct os_mbuf *oms; + uint16_t conn_handle; + int rc; + + conn_handle = ble_att_svr_test_misc_init(0); + + /* Register an attribute (primary service) for incoming read commands. */ + ble_att_svr_test_misc_register_uuid( + BLE_UUID16_DECLARE(BLE_ATT_UUID_PRIMARY_SERVICE), + HA_FLAG_PERM_RW, 1, ble_att_svr_test_misc_attr_fn_rw_1); + ble_att_svr_test_attr_w_1_len = 2; + ble_att_svr_test_attr_w_1[0] = 0x12; + ble_att_svr_test_attr_w_1[1] = 0x34; + + /* Exhaust the msys pool. Leave one mbuf for the forthcoming request. */ + oms = ble_hs_test_util_mbuf_alloc_all_but(1); + + /*** MTU; always respond affirmatively, even when no mbufs. */ + + /* Receive a request. */ + rc = ble_hs_test_util_rx_att_mtu_cmd(conn_handle, 1, 100); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure we were able to send a real response. */ + ble_att_svr_test_misc_verify_tx_mtu_rsp(conn_handle); + + /*** Find information; always respond affirmatively, even when no mbufs. */ + ble_hs_test_util_prev_tx_dequeue(); + + /* Receive a request. */ + rc = ble_hs_test_util_rx_att_find_info_req(conn_handle, 1, 100); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure we were able to send a real response. */ + ble_hs_test_util_verify_tx_find_info_rsp( + (struct ble_hs_test_util_att_info_entry[]) { + { .handle = 1, .uuid = BLE_UUID16_DECLARE(BLE_ATT_UUID_PRIMARY_SERVICE) }, + { 0 }, + }); + + /*** Find by type value. */ + ble_hs_test_util_prev_tx_dequeue(); + + /* Receive a request. */ + rc = ble_hs_test_util_rx_att_find_type_value_req( + conn_handle, 1, 100, 0x0001, ((uint8_t[2]){0x99, 0x99}), 2); + TEST_ASSERT_FATAL(rc == BLE_HS_ENOMEM); + + /* Ensure we were able to send an error response. */ + ble_hs_test_util_verify_tx_err_rsp(BLE_ATT_OP_FIND_TYPE_VALUE_REQ, 1, + BLE_ATT_ERR_INSUFFICIENT_RES); + + /*** Read by type; always respond affirmatively, even when no mbufs. */ + ble_hs_test_util_prev_tx_dequeue(); + + /* Receive a request. */ + rc = ble_hs_test_util_rx_att_read_type_req16(conn_handle, 100, 0xffff, + BLE_ATT_UUID_PRIMARY_SERVICE); + TEST_ASSERT_FATAL(rc == BLE_HS_ENOENT); + + /* Ensure we were able to send a non-OOM error response. */ + ble_hs_test_util_verify_tx_err_rsp(BLE_ATT_OP_READ_TYPE_REQ, 100, + BLE_ATT_ERR_ATTR_NOT_FOUND); + + /*** Read; always respond affirmatively, even when no mbufs. */ + ble_hs_test_util_prev_tx_dequeue(); + + /* Receive a request. */ + rc = ble_hs_test_util_rx_att_read_req(conn_handle, 1); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure we were able to send a real response. */ + ble_hs_test_util_verify_tx_read_rsp(ble_att_svr_test_attr_w_1, + ble_att_svr_test_attr_w_1_len); + + /*** Read blob; always respond affirmatively, even when no mbufs. */ + ble_hs_test_util_prev_tx_dequeue(); + + /* Receive a request. */ + rc = ble_hs_test_util_rx_att_read_blob_req(conn_handle, 1, 0); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure we were able to send a real response. */ + ble_hs_test_util_verify_tx_read_blob_rsp(ble_att_svr_test_attr_w_1, + ble_att_svr_test_attr_w_1_len); + + /*** Read multiple. */ + ble_hs_test_util_prev_tx_dequeue(); + + /* Receive a request. */ + rc = ble_hs_test_util_rx_att_read_mult_req(conn_handle, + ((uint16_t[2]){0x0001, 0x0002}), + 2); + TEST_ASSERT_FATAL(rc == BLE_HS_ENOMEM); + + /* Ensure we were able to send an error response. */ + ble_hs_test_util_verify_tx_err_rsp(BLE_ATT_OP_READ_MULT_REQ, 0, + BLE_ATT_ERR_INSUFFICIENT_RES); + + /*** + * Read by group type; always respond affirmatively, even when no + * mbufs. + */ + ble_hs_test_util_prev_tx_dequeue(); + + /* Receive a request. */ + rc = ble_hs_test_util_rx_att_read_group_type_req16( + conn_handle, 11, 100, BLE_ATT_UUID_PRIMARY_SERVICE); + TEST_ASSERT_FATAL(rc == BLE_HS_ENOENT); + + /* Ensure we were able to send a non-OOM error response. */ + ble_hs_test_util_verify_tx_err_rsp(BLE_ATT_OP_READ_GROUP_TYPE_REQ, 11, + BLE_ATT_ERR_ATTR_NOT_FOUND); + + /*** Write. */ + ble_hs_test_util_prev_tx_dequeue(); + + /* Receive a request. */ + rc = ble_hs_test_util_rx_att_write_req(conn_handle, 1, + ((uint8_t[1]){1}), 1); + TEST_ASSERT_FATAL(rc == BLE_HS_ENOMEM); + + /* Ensure we were able to send an error response. */ + ble_hs_test_util_verify_tx_err_rsp(BLE_ATT_OP_WRITE_REQ, 1, + BLE_ATT_ERR_INSUFFICIENT_RES); + + /*** Write command; no response. */ + ble_hs_test_util_prev_tx_dequeue(); + + /* Receive a request. */ + rc = ble_hs_test_util_rx_att_write_cmd(conn_handle, 1, + ((uint8_t[1]){1}), 1); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure no response sent. */ + TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue() == NULL); + + /*** Prepare write. */ + ble_hs_test_util_prev_tx_dequeue(); + + /* Receive a request. */ + rc = ble_hs_test_util_rx_att_prep_write_req(conn_handle, 1, 0, + ((uint8_t[1]){1}), 1); + TEST_ASSERT_FATAL(rc == BLE_HS_ENOMEM); + + /* Ensure we were able to send an error response. */ + ble_hs_test_util_verify_tx_err_rsp(BLE_ATT_OP_PREP_WRITE_REQ, 1, + BLE_ATT_ERR_INSUFFICIENT_RES); + + /*** Notify; no response. */ + ble_hs_test_util_prev_tx_dequeue(); + + /* Receive a request. */ + rc = ble_hs_test_util_rx_att_notify_req(conn_handle, 1, + ((uint8_t[1]){1}), 1); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure no response sent. */ + TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue() == NULL); + + /*** Indicate. */ + ble_hs_test_util_prev_tx_dequeue(); + + /* Receive a request. */ + rc = ble_hs_test_util_rx_att_indicate_req(conn_handle, 1, + ((uint8_t[1]){1}), 1); + TEST_ASSERT_FATAL(rc == BLE_HS_ENOMEM); + + /* Ensure we were able to send a real response. */ + ble_hs_test_util_verify_tx_err_rsp(BLE_ATT_OP_INDICATE_REQ, 1, + BLE_ATT_ERR_INSUFFICIENT_RES); + + rc = os_mbuf_free_chain(oms); + TEST_ASSERT_FATAL(rc == 0); + + ble_att_svr_test_assert_mbufs_freed(); +} + +TEST_CASE_SELF(ble_att_svr_test_unsupported_req) +{ + uint16_t conn_handle; + int rc; + uint8_t buf[] = {0x3f, 0x00, 0x00, 0x01, 0x02, 0x03}; + + conn_handle = ble_att_svr_test_misc_init(0); + + /* Put handle into buf */ + (*(uint16_t *)&buf[1]) = htole16(conn_handle); + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, sizeof buf); + TEST_ASSERT(rc != 0); + ble_hs_test_util_verify_tx_err_rsp(0x3f, 0, + BLE_ATT_ERR_REQ_NOT_SUPPORTED); + + /* Check for no response when unknown command is sent */ + buf[0] = 0x4f; + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, sizeof buf); + TEST_ASSERT(rc != 0); + + /* Ensure no response sent. */ + TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue() == NULL); + + ble_att_svr_test_assert_mbufs_freed(); +} + +TEST_SUITE(ble_att_svr_suite) +{ + ble_att_svr_test_mtu(); + ble_att_svr_test_read(); + ble_att_svr_test_read_blob(); + ble_att_svr_test_read_mult(); + ble_att_svr_test_write(); + ble_att_svr_test_find_info(); + ble_att_svr_test_find_type_value(); + ble_att_svr_test_read_type(); + ble_att_svr_test_read_group_type(); + ble_att_svr_test_prep_write(); + ble_att_svr_test_prep_write_tmo(); + ble_att_svr_test_notify(); + ble_att_svr_test_indicate(); + ble_att_svr_test_oom(); + ble_att_svr_test_unsupported_req(); +} diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_gap_test.c b/src/libs/mynewt-nimble/nimble/host/test/src/ble_gap_test.c new file mode 100644 index 00000000..7496e316 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_gap_test.c @@ -0,0 +1,3168 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include "testutil/testutil.h" +#include "nimble/ble.h" +#include "nimble/hci_common.h" +#include "host/ble_hs_adv.h" +#include "ble_hs_test.h" +#include "ble_hs_test_util.h" + +#define BLE_HCI_SET_SCAN_PARAM_LEN (7) +#define BLE_HCI_SET_SCAN_ENABLE_LEN (2) +#define BLE_HCI_DISCONNECT_CMD_LEN (3) +#define BLE_HCI_SET_ADV_PARAM_LEN (15) +#define BLE_HCI_SET_ADV_ENABLE_LEN (1) +#define BLE_HCI_CONN_UPDATE_LEN (14) +#define BLE_HCI_CONN_PARAM_REPLY_LEN (14) +#define BLE_HCI_CONN_PARAM_NEG_REPLY_LEN (3) + +static struct ble_gap_event ble_gap_test_event; +static int ble_gap_test_conn_status; +static struct ble_gap_conn_desc ble_gap_test_conn_desc; +static void *ble_gap_test_conn_arg; +static struct ble_gap_upd_params ble_gap_test_conn_peer_params; +static struct ble_gap_upd_params ble_gap_test_conn_self_params; + +static int ble_gap_test_disc_event_type; +static struct ble_gap_disc_desc ble_gap_test_disc_desc; +static void *ble_gap_test_disc_arg; + +/***************************************************************************** + * $misc * + *****************************************************************************/ + +static void +ble_gap_test_util_reset_cb_info(void) +{ + memset(&ble_gap_test_event, 0xff, sizeof ble_gap_test_event); + ble_gap_test_conn_status = -1; + memset(&ble_gap_test_conn_desc, 0xff, sizeof ble_gap_test_conn_desc); + ble_gap_test_conn_arg = (void *)-1; + + ble_gap_test_disc_event_type = -1; + memset(&ble_gap_test_disc_desc, 0xff, sizeof ble_gap_test_disc_desc); + ble_gap_test_disc_arg = (void *)-1; +} + +static void +ble_gap_test_util_init(void) +{ + ble_hs_test_util_init(); + ble_hs_test_util_set_static_rnd_addr((uint8_t[6]){ 1, 2, 3, 4, 5, 0xc0 }); + ble_gap_test_util_reset_cb_info(); +} + +static int +ble_gap_test_util_disc_cb(struct ble_gap_event *event, void *arg) +{ + ble_gap_test_disc_event_type = event->type; + ble_gap_test_disc_arg = arg; + + if (event->type == BLE_GAP_EVENT_DISC) { + ble_gap_test_disc_desc = event->disc; + } + + return 0; +} + +static int +ble_gap_test_util_connect_cb(struct ble_gap_event *event, void *arg) +{ + int *fail_reason; + int ret; + + ble_gap_test_event = *event; + ble_gap_test_conn_arg = arg; + + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + ble_gap_test_conn_status = event->connect.status; + ret = ble_gap_conn_find(event->connect.conn_handle, + &ble_gap_test_conn_desc); + TEST_ASSERT_FATAL(ble_gap_test_conn_status || ret == 0); + break; + + case BLE_GAP_EVENT_DISCONNECT: + ble_gap_test_conn_status = event->disconnect.reason; + ble_gap_test_conn_desc = event->disconnect.conn; + break; + + case BLE_GAP_EVENT_CONN_UPDATE: + ble_gap_test_conn_status = event->conn_update.status; + ret = ble_gap_conn_find(event->conn_update.conn_handle, + &ble_gap_test_conn_desc); + TEST_ASSERT_FATAL(ret == 0); + break; + + case BLE_GAP_EVENT_TERM_FAILURE: + ble_gap_test_conn_status = event->term_failure.status; + ret = ble_gap_conn_find(event->term_failure.conn_handle, + &ble_gap_test_conn_desc); + TEST_ASSERT_FATAL(ret == 0); + break; + + case BLE_GAP_EVENT_ADV_COMPLETE: + ble_gap_test_conn_arg = arg; + break; + + case BLE_GAP_EVENT_CONN_UPDATE_REQ: + ble_gap_test_conn_peer_params = *event->conn_update_req.peer_params; + *event->conn_update_req.self_params = ble_gap_test_conn_self_params; + ret = ble_gap_conn_find(event->conn_update_req.conn_handle, + &ble_gap_test_conn_desc); + TEST_ASSERT_FATAL(ret == 0); + + fail_reason = arg; + if (fail_reason == NULL) { + return 0; + } else { + return *fail_reason; + } + break; + + case BLE_GAP_EVENT_MTU: + break; + + default: + TEST_ASSERT_FATAL(0); + break; + } + + return 0; +} + +static int +ble_gap_test_util_copy_cb(struct ble_gap_event *event, void *arg) +{ + ble_gap_test_event = *event; + ble_gap_test_conn_arg = arg; + + return 0; +} + +static void +ble_gap_test_util_verify_tx_clear_wl(void) +{ + uint8_t param_len; + + ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_CLEAR_WHITE_LIST, + ¶m_len); + TEST_ASSERT(param_len == 0); +} + +static void +ble_gap_test_util_verify_tx_add_wl(ble_addr_t *addr) +{ + uint8_t param_len; + uint8_t *param; + int i; + + param = ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_ADD_WHITE_LIST, + ¶m_len); + TEST_ASSERT(param_len == 7); + TEST_ASSERT(param[0] == addr->type); + for (i = 0; i < 6; i++) { + TEST_ASSERT(param[1 + i] == addr->val[i]); + } +} + +static void +ble_gap_test_util_verify_tx_set_scan_params(uint8_t own_addr_type, + uint8_t scan_type, + uint16_t itvl, + uint16_t scan_window, + uint8_t filter_policy) +{ + uint8_t param_len; + uint8_t *param; + + param = ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_SET_SCAN_PARAMS, + ¶m_len); + TEST_ASSERT(param_len == BLE_HCI_SET_SCAN_PARAM_LEN); + TEST_ASSERT(param[0] == scan_type); + TEST_ASSERT(get_le16(param + 1) == itvl); + TEST_ASSERT(get_le16(param + 3) == scan_window); + TEST_ASSERT(param[5] == own_addr_type); + TEST_ASSERT(param[6] == filter_policy); +} + +static void +ble_gap_test_util_verify_tx_scan_enable(uint8_t enable, + uint8_t filter_duplicates) +{ + uint8_t param_len; + uint8_t *param; + + param = ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_SET_SCAN_ENABLE, + ¶m_len); + TEST_ASSERT(param_len == BLE_HCI_SET_SCAN_ENABLE_LEN); + TEST_ASSERT(param[0] == enable); + TEST_ASSERT(param[1] == filter_duplicates); +} + +static void +ble_hs_test_util_hci_verify_tx_create_conn_cancel(void) +{ + uint8_t param_len; + + ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_CREATE_CONN_CANCEL, + ¶m_len); + TEST_ASSERT(param_len == 0); +} + +static void +ble_gap_test_util_verify_tx_disconnect(void) +{ + uint8_t param_len; + uint8_t *param; + + param = ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LINK_CTRL, + BLE_HCI_OCF_DISCONNECT_CMD, + ¶m_len); + TEST_ASSERT(param_len == BLE_HCI_DISCONNECT_CMD_LEN); + TEST_ASSERT(get_le16(param + 0) == 2); + TEST_ASSERT(param[2] == BLE_ERR_REM_USER_CONN_TERM); +} + +static void +ble_gap_test_util_verify_tx_adv_params(void) +{ + uint8_t param_len; + + ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_SET_ADV_PARAMS, + ¶m_len); + TEST_ASSERT(param_len == BLE_HCI_SET_ADV_PARAM_LEN); + + /* Note: Content of message verified in ble_hs_adv_test.c. */ +} + +static void +ble_gap_test_util_verify_tx_adv_data(void) +{ + uint8_t param_len; + + ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_SET_ADV_DATA, + ¶m_len); + /* Note: Content of message verified in ble_hs_adv_test.c. */ +} + +#if 0 +static void +ble_gap_test_util_verify_tx_rsp_data(void) +{ + uint8_t param_len; + uint8_t *param; + + param = ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_SET_SCAN_RSP_DATA, + ¶m_len); + (void)param; /* XXX: Verify other fields. */ +} +#endif + +static void +ble_gap_test_util_verify_tx_adv_enable(int enabled) +{ + uint8_t param_len; + uint8_t *param; + + param = ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_SET_ADV_ENABLE, + ¶m_len); + TEST_ASSERT(param_len == BLE_HCI_SET_ADV_ENABLE_LEN); + TEST_ASSERT(param[0] == !!enabled); +} + +static void +ble_gap_test_util_verify_tx_update_conn(struct ble_gap_upd_params *params) +{ + uint8_t param_len; + uint8_t *param; + + param = ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_CONN_UPDATE, + ¶m_len); + TEST_ASSERT(param_len == BLE_HCI_CONN_UPDATE_LEN); + TEST_ASSERT(get_le16(param + 0) == 2); + TEST_ASSERT(get_le16(param + 2) == params->itvl_min); + TEST_ASSERT(get_le16(param + 4) == params->itvl_max); + TEST_ASSERT(get_le16(param + 6) == params->latency); + TEST_ASSERT(get_le16(param + 8) == params->supervision_timeout); + TEST_ASSERT(get_le16(param + 10) == params->min_ce_len); + TEST_ASSERT(get_le16(param + 12) == params->max_ce_len); +} + +static void +ble_gap_test_util_verify_tx_params_reply_pos(void) +{ + uint8_t param_len; + uint8_t *param; + + param = ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_REM_CONN_PARAM_RR, + ¶m_len); + TEST_ASSERT(param_len == BLE_HCI_CONN_PARAM_REPLY_LEN); + TEST_ASSERT(get_le16(param + 0) == 2); + TEST_ASSERT(get_le16(param + 2) == ble_gap_test_conn_self_params.itvl_min); + TEST_ASSERT(get_le16(param + 4) == ble_gap_test_conn_self_params.itvl_max); + TEST_ASSERT(get_le16(param + 6) == ble_gap_test_conn_self_params.latency); + TEST_ASSERT(get_le16(param + 8) == + ble_gap_test_conn_self_params.supervision_timeout); + TEST_ASSERT(get_le16(param + 10) == + ble_gap_test_conn_self_params.min_ce_len); + TEST_ASSERT(get_le16(param + 12) == + ble_gap_test_conn_self_params.max_ce_len); +} + +static void +ble_gap_test_util_verify_tx_params_reply_neg(uint8_t reason) +{ + uint8_t param_len; + uint8_t *param; + + param = ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_REM_CONN_PARAM_NRR, + ¶m_len); + TEST_ASSERT(param_len == BLE_HCI_CONN_PARAM_NEG_REPLY_LEN); + TEST_ASSERT(get_le16(param + 0) == 2); + TEST_ASSERT(param[2] == reason); +} + +static void +ble_gap_test_util_rx_update_complete( + uint8_t status, + const struct ble_gap_upd_params *params) +{ + struct ble_hci_ev_le_subev_conn_upd_complete evt; + + evt.subev_code = BLE_HCI_LE_SUBEV_CONN_UPD_COMPLETE; + evt.status = status; + evt.conn_handle = htole16(2); + evt.conn_itvl = htole16(params->itvl_max); + evt.conn_latency = htole16(params->latency); + evt.supervision_timeout = htole16(params->supervision_timeout); + + ble_gap_rx_update_complete(&evt); +} + +static int +ble_gap_test_util_rx_param_req(struct ble_gap_upd_params *params, int pos, + int *cmd_idx, int cmd_fail_idx, + uint8_t fail_status) +{ + struct ble_hci_ev_le_subev_rem_conn_param_req evt; + uint16_t opcode; + uint8_t hci_status; + + evt.subev_code = BLE_HCI_LE_SUBEV_REM_CONN_PARM_REQ; + evt.conn_handle = htole16(2); + evt.min_interval = htole16(params->itvl_min); + evt.max_interval = htole16(params->itvl_max); + evt.latency = htole16(params->latency); + evt.timeout = params->supervision_timeout; + + if (pos) { + opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_REM_CONN_PARAM_RR); + } else { + opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_REM_CONN_PARAM_NRR); + } + if (*cmd_idx == cmd_fail_idx) { + hci_status = fail_status; + } else { + hci_status = 0; + } + (*cmd_idx)++; + + ble_hs_test_util_hci_ack_set(opcode, hci_status); + ble_gap_rx_param_req(&evt); + + return hci_status; +} + +/***************************************************************************** + * $white list * + *****************************************************************************/ + +static void +ble_gap_test_util_wl_set(ble_addr_t *addrs, int addrs_count, int cmd_fail_idx, + uint8_t fail_status) +{ + int cmd_idx; + int rc; + int i; + + ble_gap_test_util_init(); + cmd_idx = 0; + + rc = ble_hs_test_util_wl_set(addrs, addrs_count, cmd_fail_idx, + fail_status); + TEST_ASSERT(rc == BLE_HS_HCI_ERR(fail_status)); + + /* Verify tx of clear white list command. */ + ble_gap_test_util_verify_tx_clear_wl(); + if (cmd_idx >= cmd_fail_idx) { + return; + } + cmd_idx++; + + /* Verify tx of add white list commands. */ + for (i = 0; i < addrs_count; i++) { + ble_gap_test_util_verify_tx_add_wl(addrs + i); + if (cmd_idx >= cmd_fail_idx) { + return; + } + cmd_idx++; + } +} + +TEST_CASE_SELF(ble_gap_test_case_wl_bad_args) +{ + int rc; + + ble_gap_test_util_init(); + + /*** 0 white list entries. */ + rc = ble_hs_test_util_wl_set(NULL, 0, 0, 0); + TEST_ASSERT(rc == BLE_HS_EINVAL); + + /*** Invalid address type. */ + rc = ble_hs_test_util_wl_set( + ((ble_addr_t[]) { { + 5, { 1, 2, 3, 4, 5, 6 } + }, }), + 1, 0, 0); + TEST_ASSERT(rc == BLE_HS_EINVAL); + + /*** White-list-using connection in progress. */ + rc = ble_hs_test_util_connect(BLE_OWN_ADDR_PUBLIC, NULL, 0, NULL, + ble_gap_test_util_connect_cb, NULL, 0); + TEST_ASSERT(rc == 0); + + rc = ble_hs_test_util_wl_set( + ((ble_addr_t[]) { { + BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 } + }, }), + 1, 0, 0); + TEST_ASSERT(rc == BLE_HS_EBUSY); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_wl_ctlr_fail) +{ + int i; + + ble_addr_t addrs[] = { + { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 } }, + { BLE_ADDR_PUBLIC, { 2, 3, 4, 5, 6, 7 } }, + { BLE_ADDR_PUBLIC, { 3, 4, 5, 6, 7, 8 } }, + { BLE_ADDR_PUBLIC, { 4, 5, 6, 7, 8, 9 } }, + }; + int addrs_count = sizeof addrs / sizeof addrs[0]; + + for (i = 0; i < 5; i++) { + ble_gap_test_util_wl_set(addrs, addrs_count, i, + BLE_ERR_UNSPECIFIED); + } + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_wl_good) +{ + ble_addr_t addrs[] = { + { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 } }, + { BLE_ADDR_PUBLIC, { 2, 3, 4, 5, 6, 7 } }, + { BLE_ADDR_PUBLIC, { 3, 4, 5, 6, 7, 8 } }, + { BLE_ADDR_PUBLIC, { 4, 5, 6, 7, 8, 9 } }, + }; + int addrs_count = sizeof addrs / sizeof addrs[0]; + + ble_gap_test_util_wl_set(addrs, addrs_count, 0, 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_gap_test_suite_wl) +{ + ble_gap_test_case_wl_good(); + ble_gap_test_case_wl_bad_args(); + ble_gap_test_case_wl_ctlr_fail(); +} + +/***************************************************************************** + * $discovery * + *****************************************************************************/ + +static int +ble_gap_test_util_disc(uint8_t own_addr_type, + const struct ble_gap_disc_params *disc_params, + struct ble_gap_disc_desc *desc, int cmd_fail_idx, + uint8_t fail_status) +{ + int rc; + + ble_gap_test_util_init(); + + TEST_ASSERT(!ble_gap_disc_active()); + + /* Begin the discovery procedure. */ + rc = ble_hs_test_util_disc(own_addr_type, BLE_HS_FOREVER, disc_params, + ble_gap_test_util_disc_cb, NULL, cmd_fail_idx, + fail_status); + TEST_ASSERT(rc == BLE_HS_HCI_ERR(fail_status)); + if (rc == 0) { + TEST_ASSERT(ble_gap_master_in_progress()); + ble_gap_rx_adv_report(desc); + } else { + TEST_ASSERT(ble_gap_test_disc_event_type == -1); + } + + if (cmd_fail_idx > 0) { + /* Verify tx of set scan parameters command. */ + ble_gap_test_util_verify_tx_set_scan_params( + own_addr_type, + disc_params->passive ? + BLE_HCI_SCAN_TYPE_PASSIVE : + BLE_HCI_SCAN_TYPE_ACTIVE, + disc_params->itvl, + disc_params->window, + disc_params->filter_policy); + } + + if (cmd_fail_idx > 1) { + /* Verify tx of scan enable command. */ + ble_gap_test_util_verify_tx_scan_enable( + 1, disc_params->filter_duplicates); + } + + if (rc == 0) { + TEST_ASSERT(ble_gap_disc_active()); + } + + return rc; +} + +TEST_CASE_SELF(ble_gap_test_case_disc_bad_args) +{ + struct ble_gap_disc_params params; + int rc; + + params.itvl = 0; + params.window = 0; + params.filter_policy = BLE_HCI_SCAN_FILT_NO_WL; + params.limited = 0; + params.passive = 0; + params.filter_duplicates = 0; + + ble_gap_test_util_init(); + + /*** Invalid filter policy. */ + params.filter_policy = 6; + rc = ble_gap_disc(BLE_OWN_ADDR_PUBLIC, 0, ¶ms, + ble_gap_test_util_disc_cb, NULL); + TEST_ASSERT(rc == BLE_HS_EINVAL); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_disc_good) +{ + uint8_t adv_data[32]; + uint8_t flags; + uint8_t own_addr_type; + int passive; + int limited; + int rc; + + struct ble_gap_disc_desc desc = { + .event_type = BLE_HCI_ADV_TYPE_ADV_IND, + .addr = { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 } }, + .length_data = 0, + .rssi = 0, + .data = adv_data, + }; + struct ble_gap_disc_params disc_params = { + .itvl = BLE_GAP_SCAN_SLOW_INTERVAL1, + .window = BLE_GAP_SCAN_SLOW_WINDOW1, + .filter_policy = BLE_HCI_CONN_FILT_NO_WL, + .limited = 0, + .passive = 0, + .filter_duplicates = 0, + }; + + flags = BLE_HS_ADV_F_DISC_LTD; + rc = ble_hs_adv_set_flat(BLE_HS_ADV_TYPE_FLAGS, 1, &flags, + adv_data, &desc.length_data, + sizeof adv_data); + TEST_ASSERT_FATAL(rc == 0); + + for (own_addr_type = 0; + own_addr_type <= BLE_OWN_ADDR_RPA_RANDOM_DEFAULT; + own_addr_type++) + for (passive = 0; passive <= 1; passive++) + for (limited = 0; limited <= 1; limited++) { + disc_params.passive = passive; + disc_params.limited = limited; + ble_gap_test_util_disc(own_addr_type, &disc_params, &desc, -1, 0); + + TEST_ASSERT(ble_gap_master_in_progress()); + TEST_ASSERT(ble_gap_test_disc_event_type == BLE_GAP_EVENT_DISC); + TEST_ASSERT(ble_gap_test_disc_desc.event_type == + BLE_HCI_ADV_TYPE_ADV_IND); + TEST_ASSERT(ble_gap_test_disc_desc.addr.type == + BLE_ADDR_PUBLIC); + TEST_ASSERT(ble_gap_test_disc_desc.length_data == 3); + TEST_ASSERT(ble_gap_test_disc_desc.rssi == 0); + TEST_ASSERT(memcmp(ble_gap_test_disc_desc.addr.val, desc.addr.val, + 6) == 0); + TEST_ASSERT(ble_gap_test_disc_arg == NULL); + + } + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_disc_ltd_mismatch) +{ + int rc; + struct ble_gap_disc_desc desc_gen = { + .event_type = BLE_HCI_ADV_TYPE_ADV_IND, + .length_data = 3, + .rssi = 0, + .addr = { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 } }, + .data = (uint8_t[BLE_HS_ADV_MAX_SZ]){ + 2, + BLE_HS_ADV_TYPE_FLAGS, + BLE_HS_ADV_F_DISC_GEN, + }, + }; + + struct ble_gap_disc_desc desc_lim = { + .event_type = BLE_HCI_ADV_TYPE_ADV_IND, + .length_data = 3, + .rssi = 0, + .addr = { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 } }, + .data = (uint8_t[BLE_HS_ADV_MAX_SZ]){ + 2, + BLE_HS_ADV_TYPE_FLAGS, + BLE_HS_ADV_F_DISC_LTD, + }, + }; + + struct ble_gap_disc_params disc_params = { + .itvl = BLE_GAP_SCAN_SLOW_INTERVAL1, + .window = BLE_GAP_SCAN_SLOW_WINDOW1, + .filter_policy = BLE_HCI_CONN_FILT_NO_WL, + .limited = 1, + .passive = 0, + .filter_duplicates = 0, + }; + + rc = ble_gap_test_util_disc(BLE_OWN_ADDR_PUBLIC, &disc_params, &desc_gen, + -1, 0); + TEST_ASSERT(rc == 0); + TEST_ASSERT(ble_gap_master_in_progress()); + + /* Verify that the report was ignored because of a mismatched LTD flag. */ + TEST_ASSERT(ble_gap_test_disc_event_type == -1); + + /* Stop the scan and swap the flags. */ + rc = ble_hs_test_util_disc_cancel(0); + TEST_ASSERT(rc == 0); + + disc_params.limited = 0; + rc = ble_gap_test_util_disc(BLE_OWN_ADDR_PUBLIC, &disc_params, &desc_lim, + -1, 0); + TEST_ASSERT(rc == 0); + TEST_ASSERT(ble_gap_master_in_progress()); + + /* This time we should have reported the advertisement; general discovery + * hears everything. + */ + TEST_ASSERT(ble_gap_test_disc_event_type == BLE_GAP_EVENT_DISC); + +} + +TEST_CASE_SELF(ble_gap_test_case_disc_hci_fail) +{ + int fail_idx; + int limited; + int rc; + + struct ble_gap_disc_desc desc = { + .event_type = BLE_HCI_ADV_TYPE_ADV_IND, + .length_data = 0, + .rssi = 0, + .addr = { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 } }, + .data = NULL, + }; + struct ble_gap_disc_params disc_params = { + .itvl = BLE_GAP_SCAN_SLOW_INTERVAL1, + .window = BLE_GAP_SCAN_SLOW_WINDOW1, + .filter_policy = BLE_HCI_CONN_FILT_NO_WL, + .limited = 0, + .passive = 0, + .filter_duplicates = 0, + }; + + for (limited = 0; limited <= 1; limited++) { + disc_params.limited = limited; + + for (fail_idx = 0; fail_idx < 2; fail_idx++) { + rc = ble_gap_test_util_disc(BLE_OWN_ADDR_PUBLIC, &disc_params, + &desc, fail_idx, BLE_ERR_UNSUPPORTED); + TEST_ASSERT(rc == BLE_HS_HCI_ERR(BLE_ERR_UNSUPPORTED)); + TEST_ASSERT(!ble_gap_master_in_progress()); + } + } + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +static void +ble_gap_test_util_disc_dflts_once(int limited) +{ + struct ble_gap_disc_params params; + uint16_t exp_window; + uint16_t exp_itvl; + int rc; + + ble_gap_test_util_init(); + + memset(¶ms, 0, sizeof params); + params.limited = limited; + + rc = ble_hs_test_util_disc(BLE_OWN_ADDR_PUBLIC, 0, ¶ms, + ble_gap_test_util_disc_cb, NULL, -1, 0); + TEST_ASSERT_FATAL(rc == 0); + + if (limited) { + exp_itvl = BLE_GAP_LIM_DISC_SCAN_INT; + exp_window = BLE_GAP_LIM_DISC_SCAN_WINDOW; + } else { + exp_itvl = BLE_GAP_SCAN_FAST_INTERVAL_MIN; + exp_window = BLE_GAP_SCAN_FAST_WINDOW; + } + ble_gap_test_util_verify_tx_set_scan_params( + BLE_OWN_ADDR_PUBLIC, + BLE_HCI_SCAN_TYPE_ACTIVE, + exp_itvl, + exp_window, + BLE_HCI_SCAN_FILT_NO_WL); + + ble_gap_test_util_verify_tx_scan_enable(1, 0); +} + +TEST_CASE_SELF(ble_gap_test_case_disc_dflts) +{ + ble_gap_test_util_disc_dflts_once(0); + ble_gap_test_util_disc_dflts_once(1); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_disc_already) +{ + static const struct ble_gap_disc_params disc_params = { 0 }; + int rc; + + ble_gap_test_util_init(); + + /* Start a discovery procedure. */ + rc = ble_hs_test_util_disc(BLE_OWN_ADDR_PUBLIC, BLE_HS_FOREVER, + &disc_params, ble_gap_test_util_disc_cb, + NULL, -1, 0); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure host indicates BLE_HS_EALREADY if we try to discover. */ + rc = ble_gap_disc(BLE_OWN_ADDR_PUBLIC, BLE_HS_FOREVER, &disc_params, + ble_gap_test_util_disc_cb, NULL); + TEST_ASSERT(rc == BLE_HS_EALREADY); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_disc_busy) +{ + static const struct ble_gap_disc_params disc_params = { 0 }; + static const ble_addr_t peer_addr = { + BLE_ADDR_PUBLIC, + { 1, 2, 3, 4, 5, 6 } + }; + int rc; + + ble_gap_test_util_init(); + + /* Start a connect procedure. */ + rc = ble_hs_test_util_connect(BLE_OWN_ADDR_PUBLIC, &peer_addr, 0, NULL, + ble_gap_test_util_connect_cb, NULL, 0); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure host indicates BLE_HS_EBUSY if we try to discover. */ + rc = ble_gap_disc(BLE_OWN_ADDR_PUBLIC, BLE_HS_FOREVER, &disc_params, + ble_gap_test_util_disc_cb, NULL); + TEST_ASSERT(rc == BLE_HS_EBUSY); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_gap_test_suite_disc) +{ + ble_gap_test_case_disc_bad_args(); + ble_gap_test_case_disc_good(); + ble_gap_test_case_disc_ltd_mismatch(); + ble_gap_test_case_disc_hci_fail(); + ble_gap_test_case_disc_dflts(); + ble_gap_test_case_disc_already(); + ble_gap_test_case_disc_busy(); +} + +/***************************************************************************** + * $direct connect * + *****************************************************************************/ + +TEST_CASE_SELF(ble_gap_test_case_conn_gen_good) +{ + struct ble_gap_conn_complete evt; + struct ble_gap_conn_params params; + int rc; + + ble_addr_t peer_addr = { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 }}; + + ble_gap_test_util_init(); + + TEST_ASSERT(!ble_gap_master_in_progress()); + TEST_ASSERT(!ble_gap_conn_active()); + + params.scan_itvl = 0x12; + params.scan_window = 0x11; + params.itvl_min = 25; + params.itvl_max = 26; + params.latency = 1; + params.supervision_timeout = 20; + params.min_ce_len = 3; + params.max_ce_len = 4; + + rc = ble_hs_test_util_connect(BLE_OWN_ADDR_PUBLIC, + &peer_addr, 0, ¶ms, + ble_gap_test_util_connect_cb, NULL, 0); + TEST_ASSERT(rc == 0); + + TEST_ASSERT(ble_gap_master_in_progress()); + TEST_ASSERT(ble_gap_conn_active()); + + TEST_ASSERT(ble_gap_master_in_progress()); + TEST_ASSERT(ble_hs_atomic_conn_flags(2, NULL) == BLE_HS_ENOTCONN); + + /* ble_gap_rx_conn_complete() will send extra HCI command, need phony + * ack */ + ble_hs_test_util_hci_ack_set(ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_RD_REM_FEAT), 0); + + /* Receive connection complete event. */ + memset(&evt, 0, sizeof evt); + evt.status = BLE_ERR_SUCCESS; + evt.connection_handle = 2; + evt.role = BLE_HCI_LE_CONN_COMPLETE_ROLE_MASTER; + memcpy(evt.peer_addr, peer_addr.val, 6); + rc = ble_gap_rx_conn_complete(&evt, 0); + TEST_ASSERT(rc == 0); + + TEST_ASSERT(!ble_gap_master_in_progress()); + + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONNECT); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr.val, + peer_addr.val, 6) == 0); + + TEST_ASSERT(ble_hs_atomic_conn_flags(2, NULL) == 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_conn_gen_bad_args) +{ + int rc; + + ble_gap_test_util_init(); + + TEST_ASSERT(!ble_gap_master_in_progress()); + + /*** Invalid address type. */ + rc = ble_gap_connect(BLE_OWN_ADDR_PUBLIC, + &((ble_addr_t) { 5, { 1, 2, 3, 4, 5, 6 }}), 0, NULL, + ble_gap_test_util_connect_cb, NULL); + TEST_ASSERT(rc == BLE_HS_EINVAL); + TEST_ASSERT(!ble_gap_master_in_progress()); + + /*** Connection already in progress. */ + rc = ble_hs_test_util_connect( + BLE_OWN_ADDR_PUBLIC, + &((ble_addr_t) { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 }}), + 0, NULL, ble_gap_test_util_connect_cb, + NULL, 0); + TEST_ASSERT(rc == 0); + TEST_ASSERT(ble_gap_master_in_progress()); + + rc = ble_gap_connect( + BLE_OWN_ADDR_PUBLIC, + &((ble_addr_t) { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 }}), + 0, NULL, ble_gap_test_util_connect_cb, NULL); + TEST_ASSERT(rc == BLE_HS_EALREADY); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_conn_gen_dflt_params) +{ + static const ble_addr_t peer_addr = { + BLE_ADDR_PUBLIC, + { 2, 3, 8, 6, 6, 1 } + }; + int rc; + + ble_gap_test_util_init(); + + rc = ble_hs_test_util_connect(BLE_OWN_ADDR_PUBLIC, + &peer_addr, 0, NULL, + ble_gap_test_util_connect_cb, NULL, 0); + TEST_ASSERT(rc == 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_conn_gen_already) +{ + static const struct ble_gap_conn_params conn_params = { 0 }; + static const ble_addr_t peer_addr = { + BLE_ADDR_PUBLIC, + { 1, 2, 3, 4, 5, 6 } + }; + int rc; + + ble_gap_test_util_init(); + + /* Start a connect procedure. */ + rc = ble_hs_test_util_connect(BLE_OWN_ADDR_PUBLIC, &peer_addr, 0, NULL, + ble_gap_test_util_connect_cb, NULL, 0); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure host indicates BLE_HS_EALREADY if we try to connect. */ + rc = ble_gap_connect(BLE_OWN_ADDR_PUBLIC, &peer_addr, BLE_HS_FOREVER, + &conn_params, ble_gap_test_util_connect_cb, NULL); + TEST_ASSERT(rc == BLE_HS_EALREADY); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_conn_gen_done) +{ + static const struct ble_gap_conn_params conn_params = { 0 }; + static const ble_addr_t peer_addr = { + BLE_ADDR_PUBLIC, + { 1, 2, 3, 4, 5, 6 } + }; + int rc; + + ble_gap_test_util_init(); + + /* Successfully connect to the peer. */ + ble_hs_test_util_create_conn(2, peer_addr.val, + ble_gap_test_util_connect_cb, NULL); + + /* Ensure host indicates BLE_HS_EDONE if we try to connect to the same + * peer. + */ + rc = ble_gap_connect(BLE_OWN_ADDR_PUBLIC, &peer_addr, BLE_HS_FOREVER, + &conn_params, ble_gap_test_util_connect_cb, NULL); + TEST_ASSERT(rc == BLE_HS_EDONE); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_conn_gen_busy) +{ + static const struct ble_gap_disc_params disc_params = { 0 }; + static const struct ble_gap_conn_params conn_params = { 0 }; + static const ble_addr_t peer_addr = { + BLE_ADDR_PUBLIC, + { 1, 2, 3, 4, 5, 6 } + }; + int rc; + + ble_gap_test_util_init(); + + /* Start a discovery procedure. */ + rc = ble_hs_test_util_disc(BLE_OWN_ADDR_PUBLIC, BLE_HS_FOREVER, + &disc_params, ble_gap_test_util_disc_cb, + NULL, -1, 0); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure host indicates BLE_HS_EBUSY if we try to connect. */ + rc = ble_gap_connect(BLE_OWN_ADDR_PUBLIC, &peer_addr, BLE_HS_FOREVER, + &conn_params, ble_gap_test_util_connect_cb, NULL); + TEST_ASSERT(rc == BLE_HS_EBUSY); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_conn_gen_fail_evt) +{ + static const ble_addr_t peer_addr = {BLE_ADDR_PUBLIC, {1, 2, 3, 4, 5, 6}}; + struct ble_gap_conn_complete evt; + struct ble_hci_ev_disconn_cmp disc_evt; + int rc; + + ble_gap_test_util_init(); + + /* Start a connect procedure. */ + rc = ble_hs_test_util_connect(BLE_OWN_ADDR_PUBLIC, &peer_addr, 0, NULL, + ble_gap_test_util_copy_cb, NULL, 0); + TEST_ASSERT_FATAL(rc == 0); + + /* Controller indicates failure via connect complete event. */ + memset(&evt, 0, sizeof evt); + evt.status = BLE_ERR_SUCCESS; + evt.connection_handle = 6; + evt.role = BLE_HCI_LE_CONN_COMPLETE_ROLE_MASTER; + evt.peer_addr_type = BLE_ADDR_PUBLIC; + memcpy(evt.peer_addr, peer_addr.val, 6); + + rc = ble_gap_rx_conn_complete(&evt, 0); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure failed connect was reported to application. */ + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONNECT); + TEST_ASSERT(ble_gap_test_event.connect.status == + BLE_HS_HCI_ERR(BLE_ERR_SUCCESS)); + + memset(&disc_evt, 0, sizeof disc_evt); + disc_evt.conn_handle = htole16(6); + disc_evt.status = BLE_ERR_SUCCESS; + disc_evt.reason = BLE_ERR_CONN_ESTABLISHMENT; + + ble_gap_rx_disconn_complete(&disc_evt); + + /* Ensure failed connect was reported to application. */ + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_DISCONNECT); + TEST_ASSERT(ble_gap_test_event.disconnect.reason == + BLE_HS_HCI_ERR(BLE_ERR_CONN_ESTABLISHMENT)); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_gap_test_suite_conn_gen) +{ + ble_gap_test_case_conn_gen_good(); + ble_gap_test_case_conn_gen_bad_args(); + ble_gap_test_case_conn_gen_dflt_params(); + ble_gap_test_case_conn_gen_already(); + ble_gap_test_case_conn_gen_done(); + ble_gap_test_case_conn_gen_busy(); + ble_gap_test_case_conn_gen_fail_evt(); +} + +/***************************************************************************** + * $cancel * + *****************************************************************************/ + +static void +ble_gap_test_util_conn_cancel(uint8_t hci_status) +{ + struct ble_gap_conn_complete evt; + int rc; + + /* Initiate cancel procedure. */ + rc = ble_hs_test_util_conn_cancel(hci_status); + TEST_ASSERT(rc == BLE_HS_HCI_ERR(hci_status)); + + /* Verify tx of cancel create connection command. */ + ble_hs_test_util_hci_verify_tx_create_conn_cancel(); + if (rc != 0) { + return; + } + TEST_ASSERT(ble_gap_master_in_progress()); + + /* Receive connection complete event. */ + memset(&evt, 0, sizeof evt); + evt.status = BLE_ERR_UNK_CONN_ID; + /* test if host correctly ignores other fields if status is error */ + evt.connection_handle = 0x0fff; + + rc = ble_gap_rx_conn_complete(&evt, 0); + TEST_ASSERT(rc == 0); + TEST_ASSERT(!ble_gap_master_in_progress()); + + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONNECT); + TEST_ASSERT(ble_gap_test_event.connect.status == BLE_HS_EAPP); +} + +static void +ble_gap_test_util_conn_and_cancel(uint8_t *peer_addr, uint8_t hci_status) +{ + ble_addr_t addr = { BLE_ADDR_PUBLIC }; + int rc; + + ble_gap_test_util_init(); + + memcpy(addr.val, peer_addr, 6); + + /* Begin creating a connection. */ + rc = ble_hs_test_util_connect(BLE_OWN_ADDR_PUBLIC, &addr, 0, NULL, + ble_gap_test_util_connect_cb, NULL, 0); + TEST_ASSERT(rc == 0); + TEST_ASSERT(ble_gap_master_in_progress()); + + /* Initiate cancel procedure. */ + ble_gap_test_util_conn_cancel(hci_status); + TEST_ASSERT(ble_hs_atomic_conn_flags(2, NULL) == BLE_HS_ENOTCONN); +} + +TEST_CASE_SELF(ble_gap_test_case_conn_cancel_bad_args) +{ + int rc; + + ble_gap_test_util_init(); + + /* Initiate cancel procedure with no connection in progress. */ + TEST_ASSERT(!ble_gap_master_in_progress()); + rc = ble_hs_test_util_conn_cancel(0); + TEST_ASSERT(rc == BLE_HS_EALREADY); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_conn_cancel_good) +{ + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + + ble_gap_test_util_conn_and_cancel(peer_addr, 0); + + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONNECT); + TEST_ASSERT(ble_gap_test_event.connect.status == BLE_HS_EAPP); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == BLE_HS_CONN_HANDLE_NONE); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_conn_cancel_ctlr_fail) +{ + struct ble_gap_conn_complete evt; + int rc; + + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + + ble_gap_test_util_conn_and_cancel(peer_addr, BLE_ERR_REPEATED_ATTEMPTS); + + /* Make sure the host didn't invoke the application callback. The cancel + * failure was indicated via the return code from the gap call. + */ + TEST_ASSERT(ble_gap_test_event.type == 0xff); + + /* ble_gap_rx_conn_complete() will send extra HCI command, need phony + * ack + */ + ble_hs_test_util_hci_ack_set(ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_RD_REM_FEAT), 0); + + /* Allow connection complete to succeed. */ + memset(&evt, 0, sizeof evt); + evt.status = BLE_ERR_SUCCESS; + evt.connection_handle = 2; + evt.role = BLE_HCI_LE_CONN_COMPLETE_ROLE_MASTER; + memcpy(evt.peer_addr, peer_addr, 6); + rc = ble_gap_rx_conn_complete(&evt, 0); + TEST_ASSERT(rc == 0); + + TEST_ASSERT(!ble_gap_master_in_progress()); + + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONNECT); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr.val, + peer_addr, 6) == 0); + + TEST_ASSERT(ble_hs_atomic_conn_flags(2, NULL) == 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_gap_test_suite_conn_cancel) +{ + ble_gap_test_case_conn_cancel_good(); + ble_gap_test_case_conn_cancel_bad_args(); + ble_gap_test_case_conn_cancel_ctlr_fail(); +} + +/***************************************************************************** + * $terminate * + *****************************************************************************/ + +static void +ble_gap_test_util_terminate(uint8_t *peer_addr, uint8_t hci_status) +{ + struct ble_hci_ev_disconn_cmp evt; + int rc; + + ble_gap_test_util_init(); + + /* Create a connection. */ + ble_hs_test_util_create_conn(2, peer_addr, ble_gap_test_util_connect_cb, + NULL); + + /* Reset the callback event code; we don't care about the successful + * connection in this test. + */ + ble_gap_test_event.type = -1; + + /* Terminate the connection. */ + rc = ble_hs_test_util_conn_terminate(2, hci_status); + TEST_ASSERT(rc == BLE_HS_HCI_ERR(hci_status)); + TEST_ASSERT(!ble_gap_master_in_progress()); + + /* Verify tx of disconnect command. */ + ble_gap_test_util_verify_tx_disconnect(); + + if (hci_status == 0) { + /* Receive disconnection complete event. */ + evt.conn_handle = htole16(2); + evt.status = 0; + evt.reason = BLE_ERR_CONN_TERM_LOCAL; + ble_gap_rx_disconn_complete(&evt); + } +} + +TEST_CASE_SELF(ble_gap_test_case_conn_terminate_bad_args) +{ + int rc; + + ble_gap_test_util_init(); + + /*** Nonexistent connection. */ + rc = ble_hs_test_util_conn_terminate(2, 0); + TEST_ASSERT(rc == BLE_HS_ENOTCONN); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_conn_terminate_good) +{ + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + + ble_gap_test_util_terminate(peer_addr, 0); + + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_DISCONNECT); + TEST_ASSERT(ble_gap_test_conn_status == + BLE_HS_HCI_ERR(BLE_ERR_CONN_TERM_LOCAL)); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); + TEST_ASSERT(ble_gap_test_conn_desc.peer_id_addr.type == + BLE_ADDR_PUBLIC); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr.val, + peer_addr, 6) == 0); + TEST_ASSERT(ble_gap_test_conn_arg == NULL); + + TEST_ASSERT(ble_hs_atomic_conn_flags(2, NULL) == BLE_HS_ENOTCONN); + TEST_ASSERT(!ble_gap_master_in_progress()); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_conn_terminate_ctlr_fail) +{ + struct ble_hci_ev_disconn_cmp evt; + int rc; + + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + + ble_gap_test_util_init(); + + /* Create a connection. */ + ble_hs_test_util_create_conn(2, peer_addr, ble_gap_test_util_connect_cb, + NULL); + + /* Terminate the connection. */ + rc = ble_hs_test_util_conn_terminate(2, 0); + TEST_ASSERT(rc == 0); + TEST_ASSERT(!ble_gap_master_in_progress()); + + /* Verify tx of disconnect command. */ + ble_gap_test_util_verify_tx_disconnect(); + + /* Receive failed disconnection complete event. */ + evt.conn_handle = htole16(2); + evt.status = BLE_ERR_UNSUPPORTED; + evt.reason = 0; + ble_gap_rx_disconn_complete(&evt); + + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_TERM_FAILURE); + TEST_ASSERT(ble_gap_test_conn_status == + BLE_HS_HCI_ERR(BLE_ERR_UNSUPPORTED)); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); + TEST_ASSERT(ble_gap_test_conn_desc.peer_id_addr.type == + BLE_ADDR_PUBLIC); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr.val, + peer_addr, 6) == 0); + TEST_ASSERT(ble_gap_test_conn_arg == NULL); + + TEST_ASSERT(ble_hs_atomic_conn_flags(2, NULL) == 0); + TEST_ASSERT(!ble_gap_master_in_progress()); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_conn_terminate_hci_fail) +{ + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + + ble_gap_test_util_terminate(peer_addr, BLE_ERR_REPEATED_ATTEMPTS); + + TEST_ASSERT(ble_gap_test_event.type == 0xff); + TEST_ASSERT(ble_hs_atomic_conn_flags(2, NULL) == 0); + TEST_ASSERT(!ble_gap_master_in_progress()); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_gap_test_suite_conn_terminate) +{ + ble_gap_test_case_conn_terminate_bad_args(); + ble_gap_test_case_conn_terminate_good(); + ble_gap_test_case_conn_terminate_ctlr_fail(); + ble_gap_test_case_conn_terminate_hci_fail(); +} + +/***************************************************************************** + * $conn find * + *****************************************************************************/ + +TEST_CASE_SELF(ble_gap_test_case_conn_find) +{ + + struct ble_gap_conn_desc desc; + struct ble_hs_conn *conn; + uint8_t pub_addr[6]; + int rc; + + /*** We are master; public addresses. */ + ble_gap_test_util_init(); + + rc = ble_hs_id_copy_addr(BLE_ADDR_PUBLIC, pub_addr, NULL); + TEST_ASSERT_FATAL(rc == 0); + + ble_hs_test_util_create_rpa_conn(8, + BLE_OWN_ADDR_PUBLIC, + ((uint8_t[6]){0,0,0,0,0,0}), + BLE_ADDR_PUBLIC, + ((uint8_t[6]){2,3,4,5,6,7}), + ((uint8_t[6]){0,0,0,0,0,0}), + BLE_HS_TEST_CONN_FEAT_ALL, + ble_gap_test_util_connect_cb, + NULL); + + rc = ble_gap_conn_find(8, &desc); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(desc.conn_handle == 8); + TEST_ASSERT(desc.our_id_addr.type == BLE_ADDR_PUBLIC); + TEST_ASSERT(desc.our_ota_addr.type == BLE_ADDR_PUBLIC); + TEST_ASSERT(desc.peer_ota_addr.type == BLE_ADDR_PUBLIC); + TEST_ASSERT(desc.role == BLE_GAP_ROLE_MASTER); + TEST_ASSERT(memcmp(desc.our_ota_addr.val, pub_addr, 6) == 0); + TEST_ASSERT(memcmp(desc.our_id_addr.val, pub_addr, 6) == 0); + TEST_ASSERT(memcmp(desc.peer_ota_addr.val, + ((uint8_t[6]){2,3,4,5,6,7}), 6) == 0); + TEST_ASSERT(memcmp(desc.peer_id_addr.val, + ((uint8_t[6]){2,3,4,5,6,7}), 6) == 0); + TEST_ASSERT(desc.conn_itvl == BLE_GAP_INITIAL_CONN_ITVL_MAX); + TEST_ASSERT(desc.conn_latency == BLE_GAP_INITIAL_CONN_LATENCY); + TEST_ASSERT(desc.supervision_timeout == + BLE_GAP_INITIAL_SUPERVISION_TIMEOUT); + TEST_ASSERT(desc.master_clock_accuracy == 0); + TEST_ASSERT(!desc.sec_state.encrypted); + TEST_ASSERT(!desc.sec_state.authenticated); + TEST_ASSERT(!desc.sec_state.bonded); + + /*** Swap roles. */ + ble_hs_lock(); + conn = ble_hs_conn_find(8); + conn->bhc_flags &= ~BLE_HS_CONN_F_MASTER; + ble_hs_unlock(); + + rc = ble_gap_conn_find(8, &desc); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(desc.role == BLE_GAP_ROLE_SLAVE); + + /*** We are master; RPAs. */ + ble_gap_test_util_init(); + + rc = ble_hs_id_copy_addr(BLE_ADDR_PUBLIC, pub_addr, NULL); + TEST_ASSERT_FATAL(rc == 0); + + ble_hs_test_util_create_rpa_conn(54, + BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT, + ((uint8_t[6]){0x40,1,2,3,4,5}), + BLE_ADDR_RANDOM_ID, + ((uint8_t[6]){3,4,5,6,7,8}), + ((uint8_t[6]){0x50,1,2,3,4,5}), + BLE_HS_TEST_CONN_FEAT_ALL, + ble_gap_test_util_connect_cb, + NULL); + + rc = ble_gap_conn_find(54, &desc); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(desc.conn_handle == 54); + TEST_ASSERT(desc.our_id_addr.type == BLE_ADDR_PUBLIC); + TEST_ASSERT(desc.our_ota_addr.type == BLE_ADDR_RANDOM); + TEST_ASSERT(desc.peer_ota_addr.type == BLE_ADDR_RANDOM); + TEST_ASSERT(desc.role == BLE_GAP_ROLE_MASTER); + TEST_ASSERT(memcmp(desc.our_ota_addr.val, + ((uint8_t[6]){0x40,1,2,3,4,5}), 6) == 0); + TEST_ASSERT(memcmp(desc.our_id_addr.val, pub_addr, 6) == 0); + TEST_ASSERT(memcmp(desc.peer_ota_addr.val, + ((uint8_t[6]){0x50,1,2,3,4,5}), 6) == 0); + TEST_ASSERT(memcmp(desc.peer_id_addr.val, + ((uint8_t[6]){3,4,5,6,7,8}), 6) == 0); + TEST_ASSERT(desc.conn_itvl == BLE_GAP_INITIAL_CONN_ITVL_MAX); + TEST_ASSERT(desc.conn_latency == BLE_GAP_INITIAL_CONN_LATENCY); + TEST_ASSERT(desc.supervision_timeout == + BLE_GAP_INITIAL_SUPERVISION_TIMEOUT); + TEST_ASSERT(desc.master_clock_accuracy == 0); + TEST_ASSERT(!desc.sec_state.encrypted); + TEST_ASSERT(!desc.sec_state.authenticated); + TEST_ASSERT(!desc.sec_state.bonded); + + /*** Swap roles. */ + ble_hs_lock(); + conn = ble_hs_conn_find(54); + conn->bhc_flags &= ~BLE_HS_CONN_F_MASTER; + ble_hs_unlock(); + + rc = ble_gap_conn_find(54, &desc); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(desc.role == BLE_GAP_ROLE_SLAVE); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_gap_test_suite_conn_find) +{ + ble_gap_test_case_conn_find(); +} + +/***************************************************************************** + * $advertise * + *****************************************************************************/ + +static void +ble_gap_test_util_adv(uint8_t own_addr_type, + const ble_addr_t *peer_addr, uint8_t conn_mode, + uint8_t disc_mode, int connect_status, + int cmd_fail_idx, uint8_t fail_status) +{ + struct ble_gap_conn_complete evt; + struct ble_gap_adv_params adv_params; + struct ble_hs_adv_fields adv_fields; + uint8_t hci_status; + int cmd_idx; + int rc; + + ble_gap_test_util_init(); + + adv_params = ble_hs_test_util_adv_params; + adv_params.conn_mode = conn_mode; + adv_params.disc_mode = disc_mode; + + TEST_ASSERT(!ble_gap_adv_active()); + + cmd_idx = 0; + + memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.tx_pwr_lvl_is_present = 1; + adv_fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO; + + rc = ble_hs_test_util_adv_set_fields(&adv_fields, cmd_fail_idx, + fail_status); + if (cmd_fail_idx < 2) { + hci_status = fail_status; + } else { + hci_status = 0; + } + TEST_ASSERT_FATAL(rc == BLE_HS_HCI_ERR(hci_status)); + cmd_idx += 2; + + if (rc == 0) { + ble_gap_test_util_verify_tx_adv_data(); + } + + if (fail_status == 0 || cmd_fail_idx >= cmd_idx) { + rc = ble_hs_test_util_adv_start(own_addr_type, + peer_addr, &adv_params, BLE_HS_FOREVER, + ble_gap_test_util_connect_cb, NULL, + cmd_fail_idx - cmd_idx, fail_status); + + TEST_ASSERT(rc == BLE_HS_HCI_ERR(fail_status)); + cmd_idx++; + } + + if (fail_status == 0 || cmd_fail_idx >= cmd_idx) { + /* Verify tx of set advertising params command. */ + ble_gap_test_util_verify_tx_adv_params(); + } + cmd_idx++; + + if (fail_status == 0 || cmd_fail_idx >= cmd_idx) { + /* Verify tx of set advertise enable command. */ + ble_gap_test_util_verify_tx_adv_enable(1); + } + cmd_idx++; + + if (connect_status != -1 && + (fail_status == 0 || cmd_fail_idx >= cmd_idx)) { + + TEST_ASSERT(ble_gap_adv_active()); + + /* Receive a connection complete event. */ + if (conn_mode != BLE_GAP_CONN_MODE_NON) { + if (connect_status == BLE_ERR_SUCCESS) { + /* + * ble_gap_rx_conn_complete() will send extra HCI command, need + * phony ack + */ + ble_hs_test_util_hci_ack_set( + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_RD_REM_FEAT), + 0); + } + + memset(&evt, 0, sizeof evt); + evt.status = connect_status; + + if (connect_status == BLE_ERR_SUCCESS) { + evt.connection_handle = 2; + evt.role = BLE_HCI_LE_CONN_COMPLETE_ROLE_SLAVE; + memcpy(evt.peer_addr, peer_addr->val, 6); + } else { + /* test if host correctly ignores other fields if status is + * error + */ + evt.connection_handle = 0x0fff; + } + + rc = ble_gap_rx_conn_complete(&evt, 0); + TEST_ASSERT(rc == 0); + + if (connect_status == 0 || + connect_status == BLE_ERR_DIR_ADV_TMO) { + + TEST_ASSERT(!ble_gap_adv_active()); + } else { + TEST_ASSERT(ble_gap_adv_active()); + } + } + } +} + +TEST_CASE_SELF(ble_gap_test_case_adv_bad_args) +{ + struct ble_gap_adv_params adv_params; + ble_addr_t peer_addr = { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 }}; + ble_addr_t peer_addr_inv = { 12, { 1, 2, 3, 4, 5, 6 }}; + int rc; + + ble_gap_test_util_init(); + + TEST_ASSERT(!ble_gap_adv_active()); + + /*** Invalid discoverable mode. */ + adv_params = ble_hs_test_util_adv_params; + adv_params.disc_mode = 43; + rc = ble_hs_test_util_adv_start(BLE_OWN_ADDR_PUBLIC, + &peer_addr, &adv_params, BLE_HS_FOREVER, + ble_gap_test_util_connect_cb, NULL, 0, 0); + TEST_ASSERT(rc == BLE_HS_EINVAL); + TEST_ASSERT(!ble_gap_adv_active()); + + /*** Invalid connectable mode. */ + adv_params = ble_hs_test_util_adv_params; + adv_params.conn_mode = 27; + rc = ble_hs_test_util_adv_start(BLE_OWN_ADDR_PUBLIC, + &peer_addr, &adv_params, BLE_HS_FOREVER, + ble_gap_test_util_connect_cb, NULL, 0, 0); + TEST_ASSERT(rc == BLE_HS_EINVAL); + TEST_ASSERT(!ble_gap_adv_active()); + + /*** Invalid peer address type with directed advertisable mode. */ + adv_params = ble_hs_test_util_adv_params; + adv_params.conn_mode = BLE_GAP_CONN_MODE_DIR; + rc = ble_hs_test_util_adv_start( + BLE_OWN_ADDR_PUBLIC, + &peer_addr_inv, &adv_params, BLE_HS_FOREVER, + ble_gap_test_util_connect_cb, NULL, 0, 0); + TEST_ASSERT(rc == BLE_HS_EINVAL); + TEST_ASSERT(!ble_gap_adv_active()); + + /*** Advertising already in progress. */ + adv_params = ble_hs_test_util_adv_params; + rc = ble_hs_test_util_adv_start(BLE_OWN_ADDR_PUBLIC, + &peer_addr, &adv_params, BLE_HS_FOREVER, + ble_gap_test_util_connect_cb, NULL, 0, 0); + TEST_ASSERT(rc == 0); + TEST_ASSERT(ble_gap_adv_active()); + + rc = ble_hs_test_util_adv_start(BLE_OWN_ADDR_PUBLIC, + &peer_addr, &adv_params, BLE_HS_FOREVER, + ble_gap_test_util_connect_cb, NULL, 0, 0); + TEST_ASSERT(rc == BLE_HS_EALREADY); + TEST_ASSERT(ble_gap_adv_active()); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +static void +ble_gap_test_util_adv_verify_dflt_params(uint8_t own_addr_type, + const ble_addr_t *peer_addr, + uint8_t conn_mode, + uint8_t disc_mode) +{ + struct ble_hci_le_set_adv_params_cp hci_cmd; + struct ble_gap_adv_params adv_params; + uint8_t *hci_buf; + uint8_t hci_param_len; + int rc; + + ble_gap_test_util_init(); + + TEST_ASSERT(!ble_gap_adv_active()); + + adv_params = ble_hs_test_util_adv_params; + adv_params.conn_mode = conn_mode; + adv_params.disc_mode = disc_mode; + + /* Let stack calculate all default parameters. */ + adv_params.itvl_min = 0; + adv_params.itvl_max = 0; + adv_params.channel_map = 0; + adv_params.filter_policy = 0; + adv_params.high_duty_cycle = 0; + + rc = ble_hs_test_util_adv_start(BLE_OWN_ADDR_PUBLIC, peer_addr, + &adv_params, BLE_HS_FOREVER, + ble_gap_test_util_connect_cb, NULL, 0, 0); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure default parameters properly filled in. */ + hci_buf = ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_SET_ADV_PARAMS, + &hci_param_len); + TEST_ASSERT_FATAL(hci_buf != NULL); + TEST_ASSERT_FATAL(hci_param_len == BLE_HCI_SET_ADV_PARAM_LEN); + + hci_cmd.min_interval = get_le16(hci_buf + 0); + hci_cmd.max_interval = get_le16(hci_buf + 2); + hci_cmd.type = hci_buf[4]; + hci_cmd.own_addr_type = hci_buf[5]; + hci_cmd.peer_addr_type = hci_buf[6]; + memcpy(hci_cmd.peer_addr, hci_buf + 7, 6); + hci_cmd.chan_map = hci_buf[13]; + hci_cmd.filter_policy = hci_buf[14]; + + if (conn_mode == BLE_GAP_CONN_MODE_NON) { + TEST_ASSERT(hci_cmd.min_interval == BLE_GAP_ADV_FAST_INTERVAL2_MIN); + TEST_ASSERT(hci_cmd.max_interval == BLE_GAP_ADV_FAST_INTERVAL2_MAX); + } else { + TEST_ASSERT(hci_cmd.min_interval == BLE_GAP_ADV_FAST_INTERVAL1_MIN); + TEST_ASSERT(hci_cmd.max_interval == BLE_GAP_ADV_FAST_INTERVAL1_MAX); + } + + if (conn_mode == BLE_GAP_CONN_MODE_NON) { + if (disc_mode == BLE_GAP_DISC_MODE_NON) { + TEST_ASSERT(hci_cmd.type == BLE_HCI_ADV_TYPE_ADV_NONCONN_IND); + } else { + TEST_ASSERT(hci_cmd.type == BLE_HCI_ADV_TYPE_ADV_SCAN_IND); + } + } else if (conn_mode == BLE_GAP_CONN_MODE_UND) { + TEST_ASSERT(hci_cmd.type == BLE_HCI_ADV_TYPE_ADV_IND); + } else { + TEST_ASSERT(hci_cmd.type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD); + } +} + +TEST_CASE_SELF(ble_gap_test_case_adv_dflt_params) +{ + ble_addr_t peer_addr = { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 }}; + + int d; + int c; + + for (c = BLE_GAP_CONN_MODE_NON; c < BLE_GAP_CONN_MODE_MAX; c++) { + for (d = BLE_GAP_DISC_MODE_NON; d < BLE_GAP_DISC_MODE_MAX; d++) { + ble_gap_test_util_adv_verify_dflt_params( + BLE_OWN_ADDR_PUBLIC, &peer_addr, c, d); + } + } + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_adv_good) +{ + ble_addr_t peer_addr = { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 }}; + int d; + int c; + + for (c = BLE_GAP_CONN_MODE_NON; c < BLE_GAP_CONN_MODE_MAX; c++) { + for (d = BLE_GAP_DISC_MODE_NON; d < BLE_GAP_DISC_MODE_MAX; d++) { + ble_gap_test_util_adv(BLE_OWN_ADDR_PUBLIC, + &peer_addr, c, d, BLE_ERR_SUCCESS, -1, 0); + + if (c != BLE_GAP_CONN_MODE_NON) { + TEST_ASSERT(!ble_gap_adv_active()); + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONNECT); + TEST_ASSERT(ble_gap_test_conn_status == 0); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr.val, + peer_addr.val, 6) == 0); + TEST_ASSERT(ble_gap_test_conn_arg == NULL); + } + } + } + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_adv_ctlr_fail) +{ + ble_addr_t peer_addr = { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 }}; + int d; + int c; + + for (c = BLE_GAP_CONN_MODE_NON + 1; c < BLE_GAP_CONN_MODE_MAX; c++) { + for (d = BLE_GAP_DISC_MODE_NON; d < BLE_GAP_DISC_MODE_MAX; d++) { + ble_gap_test_util_adv(BLE_OWN_ADDR_PUBLIC, + &peer_addr, c, d, BLE_ERR_DIR_ADV_TMO, + -1, 0); + + TEST_ASSERT(!ble_gap_adv_active()); + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_ADV_COMPLETE); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == + BLE_HS_CONN_HANDLE_NONE); + TEST_ASSERT(ble_gap_test_conn_arg == NULL); + } + } + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_adv_hci_fail) +{ + ble_addr_t peer_addr = { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 }}; + int fail_idx; + int d; + int c; + + for (c = BLE_GAP_CONN_MODE_NON; c < BLE_GAP_CONN_MODE_MAX; c++) { + for (d = BLE_GAP_DISC_MODE_NON; d < BLE_GAP_DISC_MODE_MAX; d++) { + for (fail_idx = 0; fail_idx < 4; fail_idx++) { + ble_gap_test_util_adv(BLE_OWN_ADDR_PUBLIC, + &peer_addr, + c, d, 0, fail_idx, BLE_ERR_UNSUPPORTED); + + TEST_ASSERT(!ble_gap_adv_active()); + TEST_ASSERT(ble_gap_test_event.type == 0xff); + } + } + } + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_gap_test_suite_adv) +{ + ble_gap_test_case_adv_bad_args(); + ble_gap_test_case_adv_dflt_params(); + ble_gap_test_case_adv_good(); + ble_gap_test_case_adv_ctlr_fail(); + ble_gap_test_case_adv_hci_fail(); +} + +/***************************************************************************** + * $stop advertise * + *****************************************************************************/ + +static void +ble_gap_test_util_stop_adv(const ble_addr_t *peer_addr, + uint8_t conn_mode, uint8_t disc_mode, + int cmd_fail_idx, uint8_t fail_status) +{ + uint8_t hci_status; + int rc; + + ble_gap_test_util_init(); + + /* Start advertising; don't rx a successful connection event. */ + ble_gap_test_util_adv(BLE_OWN_ADDR_PUBLIC, peer_addr, + conn_mode, disc_mode, -1, -1, 0); + + TEST_ASSERT(ble_gap_adv_active()); + + /* Stop advertising. */ + hci_status = cmd_fail_idx == 0 ? fail_status : 0; + + rc = ble_hs_test_util_adv_stop(hci_status); + TEST_ASSERT(rc == BLE_HS_HCI_ERR(hci_status)); + + /* Verify tx of advertising enable command. */ + ble_gap_test_util_verify_tx_adv_enable(0); +} + +TEST_CASE_SELF(ble_gap_test_case_stop_adv_good) +{ + ble_addr_t peer_addr = { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 }}; + int d; + int c; + + for (c = BLE_GAP_CONN_MODE_NON; c < BLE_GAP_CONN_MODE_MAX; c++) { + for (d = BLE_GAP_DISC_MODE_NON; d < BLE_GAP_DISC_MODE_MAX; d++) { + ble_gap_test_util_stop_adv(&peer_addr, c, d, -1, 0); + TEST_ASSERT(!ble_gap_adv_active()); + TEST_ASSERT(ble_gap_test_event.type == 0xff); + TEST_ASSERT(ble_gap_test_conn_status == -1); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == (uint16_t)-1); + TEST_ASSERT(ble_gap_test_conn_arg == (void *)-1); + } + } + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_stop_adv_hci_fail) +{ + ble_addr_t peer_addr = { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 }}; + int d; + int c; + + for (c = BLE_GAP_CONN_MODE_NON; c < BLE_GAP_CONN_MODE_MAX; c++) { + for (d = BLE_GAP_DISC_MODE_NON; d < BLE_GAP_DISC_MODE_MAX; d++) { + ble_gap_test_util_stop_adv(&peer_addr, c, d, + 0, BLE_ERR_UNSUPPORTED); + TEST_ASSERT(ble_gap_adv_active()); + TEST_ASSERT(ble_gap_test_event.type == 0xff); + TEST_ASSERT(ble_gap_test_conn_status == -1); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == (uint16_t)-1); + TEST_ASSERT(ble_gap_test_conn_arg == (void *)-1); + } + } + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_gap_test_suite_stop_adv) +{ + ble_gap_test_case_stop_adv_good(); + ble_gap_test_case_stop_adv_hci_fail(); +} + +/***************************************************************************** + * $update connection * + *****************************************************************************/ + +static void +ble_gap_test_util_update_verify_params(struct ble_gap_upd_params *params, + uint8_t ble_hs_err) +{ + int rc; + + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + + ble_gap_test_util_init(); + + ble_hs_test_util_create_conn(2, peer_addr, ble_gap_test_util_connect_cb, + NULL); + + rc = ble_hs_test_util_conn_update(2, params, 0); + TEST_ASSERT(rc == ble_hs_err); +} + +static void +ble_gap_test_util_update_no_l2cap(struct ble_gap_upd_params *params, + int master, + uint8_t hci_status, int event_status) +{ + struct ble_hs_conn *conn; + int rc; + + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + + ble_gap_test_util_init(); + + ble_hs_test_util_create_conn(2, peer_addr, ble_gap_test_util_connect_cb, + NULL); + + if (!master) { + ble_hs_lock(); + conn = ble_hs_conn_find(2); + TEST_ASSERT_FATAL(conn != NULL); + conn->bhc_flags &= ~BLE_HS_CONN_F_MASTER; + ble_hs_unlock(); + } + + /* Erase callback info reported during connection establishment; we only + * care about updates. + */ + ble_gap_test_util_reset_cb_info(); + + TEST_ASSERT(!ble_gap_master_in_progress()); + + rc = ble_hs_test_util_conn_update(2, params, hci_status); + TEST_ASSERT(rc == BLE_HS_HCI_ERR(hci_status)); + TEST_ASSERT(!ble_gap_master_in_progress()); + + /* Verify tx of connection update command. */ + ble_gap_test_util_verify_tx_update_conn(params); + + if (rc == 0) { + TEST_ASSERT(ble_gap_dbg_update_active(2)); + + /* Attempt two duplicate updates; ensure BLE_HS_EALREADY gets returned + * both times. Make sure initial update still completes successfully + * (MYNEWT-702). + */ + rc = ble_hs_test_util_conn_update(2, params, 0); + TEST_ASSERT(rc == BLE_HS_EALREADY); + rc = ble_hs_test_util_conn_update(2, params, 0); + TEST_ASSERT(rc == BLE_HS_EALREADY); + + /* Receive connection update complete event. */ + ble_gap_test_util_rx_update_complete(event_status, params); + + TEST_ASSERT(!ble_gap_master_in_progress()); + TEST_ASSERT(!ble_gap_dbg_update_active(2)); + + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONN_UPDATE); + TEST_ASSERT(ble_gap_test_conn_status == BLE_HS_HCI_ERR(event_status)); + if (event_status == 0) { + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr.val, + peer_addr, 6) == 0); + TEST_ASSERT(ble_gap_test_conn_desc.conn_itvl == params->itvl_max); + TEST_ASSERT(ble_gap_test_conn_desc.conn_latency == + params->latency); + TEST_ASSERT(ble_gap_test_conn_desc.supervision_timeout == + params->supervision_timeout); + } + } else { + TEST_ASSERT(!ble_gap_master_in_progress()); + TEST_ASSERT(!ble_gap_dbg_update_active(2)); + + TEST_ASSERT(ble_gap_test_event.type == 0xff); + } +} + +static void +ble_gap_test_util_update_l2cap(struct ble_gap_upd_params *params, + uint16_t l2cap_result) +{ + struct ble_l2cap_sig_update_params l2cap_params; + struct ble_hs_conn *conn; + uint8_t id; + int rc; + + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + + ble_gap_test_util_init(); + + ble_hs_test_util_create_conn_feat(2, peer_addr, + BLE_HS_TEST_CONN_FEAT_NO_CONN_PARAM, + ble_gap_test_util_connect_cb, NULL); + + ble_hs_lock(); + conn = ble_hs_conn_find(2); + TEST_ASSERT_FATAL(conn != NULL); + conn->bhc_flags &= ~BLE_HS_CONN_F_MASTER; + ble_hs_unlock(); + + /* Erase callback info reported during connection establishment; we only + * care about updates. + */ + ble_gap_test_util_reset_cb_info(); + + rc = ble_hs_test_util_conn_update(2, params, 0xFF); + TEST_ASSERT(rc == 0); + + TEST_ASSERT(ble_gap_dbg_update_active(2)); + + l2cap_params.itvl_min = params->itvl_min; + l2cap_params.itvl_max = params->itvl_max; + l2cap_params.slave_latency = params->latency; + l2cap_params.timeout_multiplier = params->supervision_timeout; + id = ble_hs_test_util_verify_tx_l2cap_update_req(&l2cap_params); + + /* Receive l2cap connection parameter update response. */ + ble_hs_test_util_rx_l2cap_update_rsp(2, id, l2cap_result); + TEST_ASSERT(!ble_gap_dbg_update_active(2)); + + if (l2cap_result == BLE_L2CAP_SIG_UPDATE_RSP_RESULT_ACCEPT) { + /* Receive connection update complete event. */ + ble_gap_test_util_rx_update_complete(0, params); + } + + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONN_UPDATE); + if (l2cap_result != BLE_L2CAP_SIG_UPDATE_RSP_RESULT_ACCEPT) { + TEST_ASSERT(ble_gap_test_conn_status == BLE_HS_EREJECT); + } else { + TEST_ASSERT(ble_gap_test_conn_status == 0); + TEST_ASSERT(ble_gap_test_conn_desc.conn_itvl == params->itvl_max); + TEST_ASSERT(ble_gap_test_conn_desc.conn_latency == params->latency); + TEST_ASSERT(ble_gap_test_conn_desc.supervision_timeout == + params->supervision_timeout); + } + + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr.val, + peer_addr, 6) == 0); +} + +static void +ble_gap_test_util_update_l2cap_tmo(struct ble_gap_upd_params *params, + uint8_t hci_status, uint8_t event_status, + int rx_l2cap) +{ + struct ble_l2cap_sig_update_params l2cap_params; + struct ble_hs_conn *conn; + uint8_t id; + int rc; + + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + + ble_gap_test_util_init(); + + ble_hs_test_util_create_conn_feat(2, peer_addr, + BLE_HS_TEST_CONN_FEAT_NO_CONN_PARAM, + ble_gap_test_util_connect_cb, NULL); + + ble_hs_lock(); + conn = ble_hs_conn_find(2); + TEST_ASSERT_FATAL(conn != NULL); + conn->bhc_flags &= ~BLE_HS_CONN_F_MASTER; + ble_hs_unlock(); + + /* Erase callback info reported during connection establishment; we only + * care about updates. + */ + ble_gap_test_util_reset_cb_info(); + + rc = ble_hs_test_util_conn_update(2, params, 0xFF); + TEST_ASSERT(rc == 0); + + TEST_ASSERT(ble_gap_dbg_update_active(2)); + + if (rx_l2cap) { + l2cap_params.itvl_min = params->itvl_min; + l2cap_params.itvl_max = params->itvl_max; + l2cap_params.slave_latency = params->latency; + l2cap_params.timeout_multiplier = params->supervision_timeout; + id = ble_hs_test_util_verify_tx_l2cap_update_req(&l2cap_params); + + /* Receive l2cap connection parameter update response. */ + ble_hs_test_util_rx_l2cap_update_rsp( + 2, id, BLE_L2CAP_SIG_UPDATE_RSP_RESULT_ACCEPT); + + TEST_ASSERT(!ble_gap_dbg_update_active(2)); + } else { + TEST_ASSERT(ble_gap_dbg_update_active(2)); + } + + /* Ensure no update event reported. */ + TEST_ASSERT(ble_gap_test_event.type == 0xff); + + /* Advance 29 seconds; ensure no timeout reported. + * Note: L2CAP signaling timeout is 30 sec, GAP update timeout is 40 sec + */ + os_time_advance(29 * OS_TICKS_PER_SEC); + ble_gap_timer(); + ble_l2cap_sig_timer(); + TEST_ASSERT(ble_gap_test_event.type == 0xff); + + /* Advance 30th second; ensure timeout reported. */ + os_time_advance(1 * OS_TICKS_PER_SEC); + + /* If L2CAP response has been received, GAP Timer is removed */ + if (!rx_l2cap) { + + /* Timeout will result in a terminate HCI command being sent; schedule ack + * from controller. + */ + ble_hs_test_util_hci_ack_set_disconnect(0); + + ble_gap_timer(); + ble_l2cap_sig_timer(); + + /* Verify terminate was sent. */ + ble_gap_test_util_verify_tx_disconnect(); + + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONN_UPDATE); + TEST_ASSERT(ble_gap_test_conn_status == BLE_HS_ETIMEOUT); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr.val, + peer_addr, 6) == 0); + } else { + ble_gap_timer(); + ble_l2cap_sig_timer(); + + TEST_ASSERT(ble_gap_test_event.type == 0xff); + } +} + +static void +ble_gap_test_util_update_peer(uint8_t status, + struct ble_gap_upd_params *params) +{ + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + + ble_gap_test_util_init(); + + ble_hs_test_util_create_conn(2, peer_addr, ble_gap_test_util_connect_cb, + NULL); + + TEST_ASSERT(!ble_gap_master_in_progress()); + + /* Receive connection update complete event. */ + ble_gap_test_util_rx_update_complete(status, params); + + TEST_ASSERT(!ble_gap_master_in_progress()); + + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONN_UPDATE); + TEST_ASSERT(ble_gap_test_conn_status == BLE_HS_HCI_ERR(status)); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr.val, + peer_addr, 6) == 0); + + if (status == 0) { + TEST_ASSERT(ble_gap_test_conn_desc.conn_itvl == params->itvl_max); + TEST_ASSERT(ble_gap_test_conn_desc.conn_latency == params->latency); + TEST_ASSERT(ble_gap_test_conn_desc.supervision_timeout == + params->supervision_timeout); + } + + TEST_ASSERT(!ble_gap_dbg_update_active(2)); +} + +static void +ble_gap_test_util_update_req_pos(struct ble_gap_upd_params *peer_params, + struct ble_gap_upd_params *self_params, + int cmd_fail_idx, uint8_t hci_status) +{ + int cmd_idx; + int rc; + + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + + ble_gap_test_util_init(); + cmd_idx = 0; + + ble_hs_test_util_create_conn(2, peer_addr, ble_gap_test_util_connect_cb, + NULL); + + TEST_ASSERT(!ble_gap_master_in_progress()); + + ble_gap_test_conn_self_params = *self_params; + rc = ble_gap_test_util_rx_param_req(peer_params, 1, &cmd_idx, cmd_fail_idx, + hci_status); + if (rc != 0) { + goto hci_fail; + } + TEST_ASSERT(!ble_gap_master_in_progress()); + + /* We don't maintain an update entry when the peer initiates. */ + TEST_ASSERT(!ble_gap_dbg_update_active(2)); + + /* Verify tx of connection parameters reply command. */ + ble_gap_test_util_verify_tx_params_reply_pos(); + + TEST_ASSERT(!ble_gap_master_in_progress()); + TEST_ASSERT(!ble_gap_dbg_update_active(2)); + + /* Receive connection update complete event. */ + ble_gap_test_util_rx_update_complete(0, self_params); + + TEST_ASSERT(!ble_gap_master_in_progress()); + TEST_ASSERT(!ble_gap_dbg_update_active(2)); + + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONN_UPDATE); + TEST_ASSERT(ble_gap_test_conn_status == 0); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr.val, + peer_addr, 6) == 0); + TEST_ASSERT(ble_gap_test_conn_desc.conn_itvl == self_params->itvl_max); + TEST_ASSERT(ble_gap_test_conn_desc.conn_latency == self_params->latency); + TEST_ASSERT(ble_gap_test_conn_desc.supervision_timeout == + self_params->supervision_timeout); + + return; + +hci_fail: + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONN_UPDATE); + TEST_ASSERT(ble_gap_test_conn_status == BLE_HS_HCI_ERR(hci_status)); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr.val, + peer_addr, 6) == 0); + TEST_ASSERT(ble_gap_test_conn_desc.conn_itvl == + BLE_GAP_INITIAL_CONN_ITVL_MAX); + TEST_ASSERT(ble_gap_test_conn_desc.conn_latency == + BLE_GAP_INITIAL_CONN_LATENCY); + TEST_ASSERT(ble_gap_test_conn_desc.supervision_timeout == + BLE_GAP_INITIAL_SUPERVISION_TIMEOUT); +} + +static void +ble_gap_test_util_update_req_neg(struct ble_gap_upd_params *peer_params, + int cmd_fail_idx, uint8_t hci_status) +{ + int cmd_idx; + int reason; + int rc; + + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + + ble_gap_test_util_init(); + cmd_idx = 0; + + reason = BLE_ERR_UNSPECIFIED; + ble_hs_test_util_create_conn(2, peer_addr, ble_gap_test_util_connect_cb, + &reason); + + TEST_ASSERT(!ble_gap_master_in_progress()); + TEST_ASSERT(!ble_gap_dbg_update_active(2)); + + rc = ble_gap_test_util_rx_param_req(peer_params, 0, &cmd_idx, cmd_fail_idx, + hci_status); + if (rc != 0) { + goto hci_fail; + } + TEST_ASSERT(!ble_gap_master_in_progress()); + TEST_ASSERT(!ble_gap_dbg_update_active(2)); + + /* Verify tx of connection parameters negative reply command. */ + ble_gap_test_util_verify_tx_params_reply_neg(reason); + + TEST_ASSERT(!ble_gap_master_in_progress()); + TEST_ASSERT(!ble_gap_dbg_update_active(2)); + + return; + +hci_fail: + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONN_UPDATE); + TEST_ASSERT(ble_gap_test_conn_status == BLE_HS_HCI_ERR(hci_status)); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr.val, + peer_addr, 6) == 0); + TEST_ASSERT(ble_gap_test_conn_desc.conn_itvl == + BLE_GAP_INITIAL_CONN_ITVL_MAX); + TEST_ASSERT(ble_gap_test_conn_desc.conn_latency == + BLE_GAP_INITIAL_CONN_LATENCY); + TEST_ASSERT(ble_gap_test_conn_desc.supervision_timeout == + BLE_GAP_INITIAL_SUPERVISION_TIMEOUT); +} + +static void +ble_gap_test_util_update_req_concurrent( + struct ble_gap_upd_params *init_params, + struct ble_gap_upd_params *peer_params, + struct ble_gap_upd_params *self_params, + int cmd_fail_idx, + uint8_t fail_status) +{ + uint8_t hci_status; + int cmd_idx; + int rc; + + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + + ble_gap_test_util_init(); + + ble_hs_test_util_create_conn(2, peer_addr, ble_gap_test_util_connect_cb, + NULL); + + TEST_ASSERT(!ble_gap_master_in_progress()); + TEST_ASSERT(!ble_gap_dbg_update_active(2)); + + hci_status = cmd_fail_idx == 0 ? fail_status : 0; + rc = ble_hs_test_util_conn_update(2, init_params, hci_status); + TEST_ASSERT(rc == BLE_HS_HCI_ERR(hci_status)); + + TEST_ASSERT(!ble_gap_master_in_progress()); + + /* Verify tx of connection update command. */ + ble_gap_test_util_verify_tx_update_conn(init_params); + + if (rc == 0) { + TEST_ASSERT(ble_gap_dbg_update_active(2)); + } else { + TEST_ASSERT(!ble_gap_dbg_update_active(2)); + return; + } + + TEST_ASSERT(!ble_gap_master_in_progress()); + TEST_ASSERT(ble_gap_dbg_update_active(2)); + + /* Receive connection parameter update request from peer. */ + ble_gap_test_conn_self_params = *self_params; + rc = ble_gap_test_util_rx_param_req(peer_params, 1, &cmd_idx, cmd_fail_idx, + hci_status); + if (rc != 0) { + goto hci_fail; + } + TEST_ASSERT(!ble_gap_master_in_progress()); + TEST_ASSERT(ble_gap_dbg_update_active(2)); + + /* Verify tx of connection parameters reply command. */ + ble_gap_test_util_verify_tx_params_reply_pos(); + + TEST_ASSERT(!ble_gap_master_in_progress()); + TEST_ASSERT(ble_gap_dbg_update_active(2)); + + /* Receive connection update complete event. */ + ble_gap_test_util_rx_update_complete(0, self_params); + + TEST_ASSERT(!ble_gap_master_in_progress()); + TEST_ASSERT(!ble_gap_dbg_update_active(2)); + + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONN_UPDATE); + TEST_ASSERT(ble_gap_test_conn_status == 0); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr.val, + peer_addr, 6) == 0); + TEST_ASSERT(ble_gap_test_conn_desc.conn_itvl == self_params->itvl_max); + TEST_ASSERT(ble_gap_test_conn_desc.conn_latency == self_params->latency); + TEST_ASSERT(ble_gap_test_conn_desc.supervision_timeout == + self_params->supervision_timeout); + + return; + +hci_fail: + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONN_UPDATE); + TEST_ASSERT(ble_gap_test_conn_status == BLE_HS_HCI_ERR(fail_status)); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr.val, + peer_addr, 6) == 0); + TEST_ASSERT(ble_gap_test_conn_desc.conn_itvl == + BLE_GAP_INITIAL_CONN_ITVL_MAX); + TEST_ASSERT(ble_gap_test_conn_desc.conn_latency == + BLE_GAP_INITIAL_CONN_LATENCY); + TEST_ASSERT(ble_gap_test_conn_desc.supervision_timeout == + BLE_GAP_INITIAL_SUPERVISION_TIMEOUT); +} + +TEST_CASE_SELF(ble_gap_test_case_update_conn_good) +{ + ble_gap_test_util_update_no_l2cap( + ((struct ble_gap_upd_params[]) { { + .itvl_min = 10, + .itvl_max = 100, + .supervision_timeout = 200, + .min_ce_len = 123, + .max_ce_len = 456, + }}), + 1, 0, 0); + + ble_gap_test_util_update_no_l2cap( + ((struct ble_gap_upd_params[]) { { + .itvl_min = 100, + .itvl_max = 100, + .supervision_timeout = 200, + .min_ce_len = 554, + .max_ce_len = 554, + }}), + 1, 0, 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_update_conn_verify_params) +{ + /* GOOD */ + ble_gap_test_util_update_verify_params( + ((struct ble_gap_upd_params[]) { { + .itvl_min = 100, + .itvl_max = 100, + .supervision_timeout = 200, + .min_ce_len = 554, + .max_ce_len = 554, + }}), + 0); + + /* BAD */ + ble_gap_test_util_update_verify_params( + ((struct ble_gap_upd_params[]) { { + .itvl_min = 1, + .itvl_max = 100, + .supervision_timeout = 200, + .min_ce_len = 554, + .max_ce_len = 554, + }}), + BLE_HS_EINVAL); + + ble_gap_test_util_update_verify_params( + ((struct ble_gap_upd_params[]) { { + .itvl_min = 0x0C80 + 1, + .itvl_max = 100, + .supervision_timeout = 200, + .min_ce_len = 554, + .max_ce_len = 554, + }}), + BLE_HS_EINVAL); + + ble_gap_test_util_update_verify_params( + ((struct ble_gap_upd_params[]) { { + .itvl_min = 100, + .itvl_max = 50, + .supervision_timeout = 200, + .min_ce_len = 554, + .max_ce_len = 554, + }}), + BLE_HS_EINVAL); + + ble_gap_test_util_update_verify_params( + ((struct ble_gap_upd_params[]) { { + .itvl_min = 100, + .itvl_max = 100, + .supervision_timeout = 200, + .latency = 0x01F4, + .min_ce_len = 554, + .max_ce_len = 554, + }}), + BLE_HS_EINVAL); + + ble_gap_test_util_update_verify_params( + ((struct ble_gap_upd_params[]) { { + .itvl_min = 100, + .itvl_max = 600, + .supervision_timeout = 300, + .latency = 1, + .min_ce_len = 554, + .max_ce_len = 554, + }}), + BLE_HS_EINVAL); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_update_conn_bad) +{ + ble_gap_test_util_update_no_l2cap( + ((struct ble_gap_upd_params[]) { { + .itvl_min = 10, + .itvl_max = 100, + .supervision_timeout = 200, + .min_ce_len = 123, + .max_ce_len = 456, + }}), + 1, 0, BLE_ERR_LMP_COLLISION); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_update_conn_hci_fail) +{ + ble_gap_test_util_update_no_l2cap( + ((struct ble_gap_upd_params[]) { { + .itvl_min = 10, + .itvl_max = 100, + .supervision_timeout = 200, + .min_ce_len = 123, + .max_ce_len = 456, + }}), + 1, BLE_ERR_UNSUPPORTED, 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_update_conn_l2cap) +{ + struct ble_gap_upd_params params = { + .itvl_min = 10, + .itvl_max = 100, + .supervision_timeout = 200, + .min_ce_len = 123, + .max_ce_len = 456, + }; + + /* Accepted L2CAP. */ + ble_gap_test_util_update_l2cap(¶ms, + BLE_L2CAP_SIG_UPDATE_RSP_RESULT_ACCEPT); + + /* Rejected L2CAP. */ + ble_gap_test_util_update_l2cap(¶ms, + BLE_L2CAP_SIG_UPDATE_RSP_RESULT_REJECT); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_update_peer_good) +{ + ble_gap_test_util_update_peer(0, + ((struct ble_gap_upd_params[]) { { + .itvl_min = 10, + .itvl_max = 100, + .supervision_timeout = 0, + .min_ce_len = 123, + .max_ce_len = 456, + }})); + + ble_gap_test_util_update_peer(0, + ((struct ble_gap_upd_params[]) { { + .itvl_min = 100, + .itvl_max = 100, + .supervision_timeout = 100, + .min_ce_len = 554, + .max_ce_len = 554, + }})); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_update_req_good) +{ + ble_gap_test_util_update_req_pos( + ((struct ble_gap_upd_params[]) { { + .itvl_min = 50, + .itvl_max = 500, + .supervision_timeout = 800, + .min_ce_len = 555, + .max_ce_len = 888, + }}), + ((struct ble_gap_upd_params[]) { { + .itvl_min = 10, + .itvl_max = 100, + .supervision_timeout = 200, + .min_ce_len = 123, + .max_ce_len = 456, + }}), + -1, 0); + + ble_gap_test_util_update_req_pos( + ((struct ble_gap_upd_params[]) { { + .itvl_min = 50, + .itvl_max = 500, + .supervision_timeout = 800, + .min_ce_len = 555, + .max_ce_len = 888, + }}), + ((struct ble_gap_upd_params[]) { { + .itvl_min = 100, + .itvl_max = 100, + .supervision_timeout = 200, + .min_ce_len = 554, + .max_ce_len = 554, + }}), + -1, 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_update_req_hci_fail) +{ + ble_gap_test_util_update_req_pos( + ((struct ble_gap_upd_params[]) { { + .itvl_min = 50, + .itvl_max = 500, + .supervision_timeout = 800, + .min_ce_len = 555, + .max_ce_len = 888, + }}), + ((struct ble_gap_upd_params[]) { { + .itvl_min = 10, + .itvl_max = 100, + .supervision_timeout = 200, + .min_ce_len = 123, + .max_ce_len = 456, + }}), + 0, BLE_ERR_UNSUPPORTED); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_update_req_reject) +{ + ble_gap_test_util_update_req_neg( + ((struct ble_gap_upd_params[]) { { + .itvl_min = 50, + .itvl_max = 500, + .supervision_timeout = 800, + .min_ce_len = 555, + .max_ce_len = 888, + }}), + -1, 0); + + ble_gap_test_util_update_req_neg( + ((struct ble_gap_upd_params[]) { { + .itvl_min = 50, + .itvl_max = 500, + .supervision_timeout = 800, + .min_ce_len = 555, + .max_ce_len = 888, + }}), + -1, 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_update_concurrent_good) +{ + ble_gap_test_util_update_req_concurrent( + ((struct ble_gap_upd_params[]) { { + .itvl_min = 10, + .itvl_max = 100, + .supervision_timeout = 200, + .min_ce_len = 123, + .max_ce_len = 456, + }}), + ((struct ble_gap_upd_params[]) { { + .itvl_min = 50, + .itvl_max = 500, + .supervision_timeout = 800, + .min_ce_len = 555, + .max_ce_len = 888, + }}), + ((struct ble_gap_upd_params[]) { { + .itvl_min = 10, + .itvl_max = 100, + .supervision_timeout = 200, + .min_ce_len = 123, + .max_ce_len = 456, + }}), + -1, 0); + + ble_gap_test_util_update_req_concurrent( + ((struct ble_gap_upd_params[]) { { + .itvl_min = 10, + .itvl_max = 100, + .supervision_timeout = 200, + .min_ce_len = 123, + .max_ce_len = 456, + }}), + ((struct ble_gap_upd_params[]) { { + .itvl_min = 50, + .itvl_max = 500, + .supervision_timeout = 800, + .min_ce_len = 555, + .max_ce_len = 888, + }}), + ((struct ble_gap_upd_params[]) { { + .itvl_min = 20, + .itvl_max = 200, + .supervision_timeout = 350, + .min_ce_len = 111, + .max_ce_len = 222, + }}), + -1, 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_update_concurrent_hci_fail) +{ + ble_gap_test_util_update_req_concurrent( + ((struct ble_gap_upd_params[]) { { + .itvl_min = 10, + .itvl_max = 100, + .supervision_timeout = 200, + .min_ce_len = 123, + .max_ce_len = 456, + }}), + ((struct ble_gap_upd_params[]) { { + .itvl_min = 50, + .itvl_max = 500, + .supervision_timeout = 800, + .min_ce_len = 555, + .max_ce_len = 888, + }}), + ((struct ble_gap_upd_params[]) { { + .itvl_min = 20, + .itvl_max = 200, + .supervision_timeout = 350, + .min_ce_len = 111, + .max_ce_len = 222, + }}), + 0, BLE_ERR_UNSUPPORTED); + + ble_gap_test_util_update_req_concurrent( + ((struct ble_gap_upd_params[]) { { + .itvl_min = 10, + .itvl_max = 100, + .supervision_timeout = 200, + .min_ce_len = 123, + .max_ce_len = 456, + }}), + ((struct ble_gap_upd_params[]) { { + .itvl_min = 50, + .itvl_max = 500, + .supervision_timeout = 800, + .min_ce_len = 555, + .max_ce_len = 888, + }}), + ((struct ble_gap_upd_params[]) { { + .itvl_min = 20, + .itvl_max = 200, + .supervision_timeout = 350, + .min_ce_len = 111, + .max_ce_len = 222, + }}), + 1, BLE_ERR_UNSUPPORTED); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_gap_test_suite_update_conn) +{ + ble_gap_test_case_update_conn_good(); + ble_gap_test_case_update_conn_bad(); + ble_gap_test_case_update_conn_hci_fail(); + ble_gap_test_case_update_conn_l2cap(); + ble_gap_test_case_update_peer_good(); + ble_gap_test_case_update_req_good(); + ble_gap_test_case_update_req_hci_fail(); + ble_gap_test_case_update_req_reject(); + ble_gap_test_case_update_concurrent_good(); + ble_gap_test_case_update_concurrent_hci_fail(); + ble_gap_test_case_update_conn_verify_params(); +} + +/***************************************************************************** + * $timeout * + *****************************************************************************/ + +static void +ble_gap_test_util_conn_forever(void) +{ + int32_t ticks_from_now; + + /* Initiate a connect procedure with no timeout. */ + ble_hs_test_util_connect( + BLE_OWN_ADDR_PUBLIC, + &((ble_addr_t) { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 }}), + BLE_HS_FOREVER, + NULL, ble_gap_test_util_connect_cb, + NULL, 0); + + /* Ensure no pending GAP event. */ + ticks_from_now = ble_gap_timer(); + TEST_ASSERT(ticks_from_now == BLE_HS_FOREVER); + + /* Advance 100 seconds; ensure no timeout reported. */ + os_time_advance(100 * OS_TICKS_PER_SEC); + ble_gap_timer(); + TEST_ASSERT(ble_gap_test_event.type == 0xff); + TEST_ASSERT(ble_gap_conn_active()); +} + +static void +ble_gap_test_util_conn_timeout(int32_t duration_ms) +{ + struct ble_gap_conn_complete evt; + uint32_t duration_ticks; + int32_t ticks_from_now; + int rc; + + TEST_ASSERT_FATAL(duration_ms != BLE_HS_FOREVER); + + /* Initiate a connect procedure with the specified timeout. */ + ble_hs_test_util_connect( + BLE_OWN_ADDR_PUBLIC, + &((ble_addr_t) { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 }}), + duration_ms, + NULL, ble_gap_test_util_connect_cb, + NULL, 0); + + /* Ensure next GAP event is at the expected time. */ + rc = os_time_ms_to_ticks(duration_ms, &duration_ticks); + TEST_ASSERT_FATAL(rc == 0); + ticks_from_now = ble_gap_timer(); + TEST_ASSERT(ticks_from_now == duration_ticks); + + /* Advance duration ms; ensure timeout event does not get reported before + * connection complete event rxed. + */ + os_time_advance(duration_ms); + + ble_hs_test_util_hci_ack_set( + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_CREATE_CONN_CANCEL), + 0); + + TEST_ASSERT(ble_gap_test_event.type == 0xff); + + ticks_from_now = ble_gap_timer(); + TEST_ASSERT(ticks_from_now == BLE_HS_FOREVER); + + /* Ensure cancel create connection command was sent. */ + ble_hs_test_util_hci_verify_tx_create_conn_cancel(); + + /* Ensure timer has been stopped. */ + ticks_from_now = ble_gap_timer(); + TEST_ASSERT(ticks_from_now == BLE_HS_FOREVER); + + /* Receive the connection complete event indicating a successful cancel. */ + memset(&evt, 0, sizeof evt); + evt.status = BLE_ERR_UNK_CONN_ID; + /* test if host correctly ignores other fields if status is error */ + evt.connection_handle = 0x0fff; + + rc = ble_gap_rx_conn_complete(&evt, 0); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure the GAP event was triggered. */ + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONNECT); + TEST_ASSERT(ble_gap_test_conn_status == BLE_HS_ETIMEOUT); + + /* Clear GAP event for remainder of test. */ + ble_gap_test_util_reset_cb_info(); +} + +static void +ble_gap_test_util_disc_forever(void) +{ + struct ble_gap_disc_params params; + int32_t ticks_from_now; + + memset(¶ms, 0, sizeof params); + + /* Initiate a discovery procedure with no timeout. */ + ble_hs_test_util_disc(BLE_OWN_ADDR_PUBLIC, + BLE_HS_FOREVER, ¶ms, ble_gap_test_util_disc_cb, + NULL, -1, 0); + + /* Ensure no pending GAP event. */ + ticks_from_now = ble_gap_timer(); + TEST_ASSERT(ticks_from_now == BLE_HS_FOREVER); + + /* Advance 100 seconds; ensure no timeout reported. */ + os_time_advance(100 * OS_TICKS_PER_SEC); + TEST_ASSERT(ble_gap_test_disc_event_type == -1); + TEST_ASSERT(ble_gap_disc_active()); +} + +static void +ble_gap_test_util_disc_timeout(int32_t duration_ms) +{ + struct ble_gap_disc_params params; + uint32_t duration_ticks; + int32_t ticks_from_now; + int rc; + + TEST_ASSERT_FATAL(duration_ms != BLE_HS_FOREVER); + + memset(¶ms, 0, sizeof params); + + /* Initiate a discovery procedure with the specified timeout. */ + ble_hs_test_util_disc(BLE_OWN_ADDR_PUBLIC, + duration_ms, ¶ms, ble_gap_test_util_disc_cb, + NULL, -1, 0); + + /* Ensure next GAP event is at the expected time. */ + rc = os_time_ms_to_ticks(duration_ms, &duration_ticks); + TEST_ASSERT_FATAL(rc == 0); + ticks_from_now = ble_gap_timer(); + TEST_ASSERT(ticks_from_now == duration_ticks); + + /* Advance duration ms; ensure timeout event was reported. */ + os_time_advance(duration_ms); + + ble_hs_test_util_hci_ack_set( + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_SET_SCAN_ENABLE), + 0); + ticks_from_now = ble_gap_timer(); + TEST_ASSERT(ticks_from_now == BLE_HS_FOREVER); + + TEST_ASSERT(ble_gap_test_disc_event_type == BLE_GAP_EVENT_DISC_COMPLETE); + + /* Clear GAP event for remainder of test. */ + ble_gap_test_util_reset_cb_info(); +} + +TEST_CASE_SELF(ble_gap_test_case_update_timeout) +{ + struct ble_gap_upd_params params = { + .itvl_min = 10, + .itvl_max = 100, + .supervision_timeout = 200, + .min_ce_len = 123, + .max_ce_len = 456, + }; + + /* L2CAP - Local unsupported; L2CAP timeout. */ + ble_gap_test_util_update_l2cap_tmo(¶ms, BLE_ERR_UNKNOWN_HCI_CMD, 0, 0); + + /* L2CAP - Remote unsupported; L2CAP timeout. */ + ble_gap_test_util_update_l2cap_tmo(¶ms, 0, BLE_ERR_UNSUPP_REM_FEATURE, + 0); + + /* L2CAP - Remote unsupported; LL timeout. */ + ble_gap_test_util_update_l2cap_tmo(¶ms, 0, BLE_ERR_UNSUPP_REM_FEATURE, + 1); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_conn_timeout_conn_forever) +{ + ble_gap_test_util_init(); + + /* 30 ms. */ + ble_gap_test_util_conn_timeout(30); + + /* No timeout. */ + ble_gap_test_util_conn_forever(); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_conn_timeout_conn_timeout) +{ + ble_gap_test_util_init(); + + /* 30 ms. */ + ble_gap_test_util_conn_timeout(30); + + /* 20 ms. */ + ble_gap_test_util_conn_timeout(20); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_conn_forever_conn_timeout) +{ + ble_gap_test_util_init(); + + /* No timeout. */ + ble_gap_test_util_conn_forever(); + + /* Cancel connect procedure manually. */ + ble_gap_test_util_conn_cancel(0); + + /* Clear GAP event for remainder of test. */ + ble_gap_test_util_reset_cb_info(); + + /* 30 ms. */ + ble_gap_test_util_conn_timeout(30); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_disc_timeout_disc_forever) +{ + ble_gap_test_util_init(); + + /* 30 ms. */ + ble_gap_test_util_disc_timeout(30); + + /* No timeout. */ + ble_gap_test_util_disc_forever(); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_disc_timeout_disc_timeout) +{ + ble_gap_test_util_init(); + + /* 30 ms. */ + ble_gap_test_util_disc_timeout(30); + + /* 20 ms. */ + ble_gap_test_util_disc_timeout(20); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_disc_forever_disc_timeout) +{ + ble_gap_test_util_init(); + + /* No timeout. */ + ble_gap_test_util_disc_forever(); + + /* Cancel discovery procedure manually. */ + ble_hs_test_util_disc_cancel(0); + + /* 30 ms. */ + ble_gap_test_util_disc_timeout(30); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_conn_timeout_disc_timeout) +{ + ble_gap_test_util_init(); + + /* 15 seconds. */ + ble_gap_test_util_conn_timeout(15000); + + /* 1280 ms. */ + ble_gap_test_util_disc_timeout(1280); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_gap_test_suite_timeout) +{ + ble_gap_test_case_conn_timeout_conn_forever(); + ble_gap_test_case_conn_timeout_conn_timeout(); + ble_gap_test_case_conn_forever_conn_timeout(); + + ble_gap_test_case_disc_timeout_disc_forever(); + ble_gap_test_case_disc_timeout_disc_timeout(); + ble_gap_test_case_disc_forever_disc_timeout(); + + ble_gap_test_case_conn_timeout_disc_timeout(); + + ble_gap_test_case_update_timeout(); +} + +TEST_CASE_SELF(ble_gap_test_case_mtu_us) +{ + const uint8_t peer_addr[6] = { 1,2,3,4,5,6 }; + int rc; + + ble_gap_test_util_init(); + + ble_hs_test_util_create_conn(2, peer_addr, ble_gap_test_util_connect_cb, + NULL); + + ble_att_set_preferred_mtu(200); + + rc = ble_gattc_exchange_mtu(2, NULL, NULL); + TEST_ASSERT_FATAL(rc == 0); + ble_hs_test_util_verify_tx_mtu_cmd(1, 200); + + rc = ble_hs_test_util_rx_att_mtu_cmd(2, 0, 123); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_MTU); + TEST_ASSERT(ble_gap_test_event.mtu.conn_handle == 2); + TEST_ASSERT(ble_gap_test_event.mtu.channel_id == BLE_L2CAP_CID_ATT); + TEST_ASSERT(ble_gap_test_event.mtu.value == 123); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_mtu_peer) +{ + const uint8_t peer_addr[6] = { 1,2,3,4,5,6 }; + int rc; + + ble_gap_test_util_init(); + + ble_hs_test_util_create_conn(2, peer_addr, ble_gap_test_util_connect_cb, + NULL); + + ble_att_set_preferred_mtu(200); + + rc = ble_hs_test_util_rx_att_mtu_cmd(2, 1, 123); + TEST_ASSERT_FATAL(rc == 0); + ble_hs_test_util_verify_tx_mtu_cmd(0, 200); + + TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_MTU); + TEST_ASSERT(ble_gap_test_event.mtu.conn_handle == 2); + TEST_ASSERT(ble_gap_test_event.mtu.channel_id == BLE_L2CAP_CID_ATT); + TEST_ASSERT(ble_gap_test_event.mtu.value == 123); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_gap_test_suite_mtu) +{ + ble_gap_test_case_mtu_us(); + ble_gap_test_case_mtu_peer(); +} + +/***************************************************************************** + * $set cb * + *****************************************************************************/ + +static int +ble_gap_test_util_set_cb_event(struct ble_gap_event *event, void *arg) +{ + struct ble_gap_event *event_arg; + + event_arg = arg; + + *event_arg = *event; + + return 0; +} + +TEST_CASE_SELF(ble_gap_test_case_set_cb_good) +{ + const uint8_t peer_addr[6] = { 1,2,3,4,5,6 }; + struct ble_gap_event event; + int rc; + + ble_gap_test_util_init(); + + ble_hs_test_util_create_conn(2, peer_addr, ble_gap_test_util_connect_cb, + NULL); + + /* Reconfigure the callback. */ + rc = ble_gap_set_event_cb(2, ble_gap_test_util_set_cb_event, &event); + TEST_ASSERT_FATAL(rc == 0); + + /* Terminate the connection and ensure the new callback gets called. */ + rc = ble_hs_test_util_conn_terminate(2, 0); + TEST_ASSERT_FATAL(rc == 0); + + ble_hs_test_util_hci_rx_disconn_complete_event(2, 0, BLE_ERR_REM_USER_CONN_TERM); + + TEST_ASSERT(event.type == BLE_GAP_EVENT_DISCONNECT); + TEST_ASSERT(event.disconnect.reason == + BLE_HS_HCI_ERR(BLE_ERR_REM_USER_CONN_TERM)); + TEST_ASSERT(event.disconnect.conn.conn_handle == 2); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gap_test_case_set_cb_bad) +{ + int rc; + + ble_gap_test_util_init(); + + /* Ensure error is reported when specified connection doesn't exist. */ + rc = ble_gap_set_event_cb(123, ble_gap_test_util_set_cb_event, NULL); + TEST_ASSERT(rc == BLE_HS_ENOTCONN); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_gap_test_suite_set_cb) +{ + ble_gap_test_case_set_cb_good(); + ble_gap_test_case_set_cb_bad(); +} diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_gatt_conn_test.c b/src/libs/mynewt-nimble/nimble/host/test/src/ble_gatt_conn_test.c new file mode 100644 index 00000000..8d95f743 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_gatt_conn_test.c @@ -0,0 +1,746 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include "testutil/testutil.h" +#include "nimble/ble.h" +#include "ble_hs_test.h" +#include "ble_hs_test_util.h" + +#define BLE_GATT_BREAK_TEST_READ_ATTR_HANDLE 0x9383 +#define BLE_GATT_BREAK_TEST_WRITE_ATTR_HANDLE 0x1234 + +static uint8_t ble_gatt_conn_test_write_value[] = { 1, 3, 64, 21, 6 }; + +struct ble_gatt_conn_test_arg { + uint16_t exp_conn_handle; + int exp_status; + int called; +}; + +static struct ble_gap_event ble_gatt_conn_test_gap_event; + +static void +ble_gatt_conn_test_util_init(void) +{ + ble_hs_test_util_init(); + memset(&ble_gatt_conn_test_gap_event, -1, + sizeof ble_gatt_conn_test_gap_event); +} + +static int +ble_gatt_conn_test_indicate_cb(struct ble_gap_event *event, void *arg) +{ + /* Only record indication failures. */ + if (event->type == BLE_GAP_EVENT_NOTIFY_TX && + event->notify_tx.status != 0) { + + ble_gatt_conn_test_gap_event = *event; + } + return 0; +} + +static int +ble_gatt_conn_test_attr_cb(uint16_t conn_handle, uint16_t attr_handle, + uint8_t op, uint16_t offset, struct os_mbuf **om, + void *arg) +{ + uint8_t *buf; + + switch (op) { + case BLE_ATT_ACCESS_OP_READ: + buf = os_mbuf_extend(*om, 1); + TEST_ASSERT_FATAL(buf != NULL); + *buf = 1; + return 0; + + default: + return -1; + } +} + +static int +ble_gatt_conn_test_mtu_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + uint16_t mtu, void *arg) +{ + struct ble_gatt_conn_test_arg *cb_arg; + + cb_arg = arg; + + TEST_ASSERT(cb_arg->exp_conn_handle == conn_handle); + TEST_ASSERT(!cb_arg->called); + TEST_ASSERT_FATAL(error != NULL); + TEST_ASSERT(error->status == cb_arg->exp_status); + TEST_ASSERT(mtu == 0); + + cb_arg->called++; + + return 0; +} + +static int +ble_gatt_conn_test_disc_all_svcs_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_svc *service, + void *arg) +{ + struct ble_gatt_conn_test_arg *cb_arg; + + cb_arg = arg; + + TEST_ASSERT(cb_arg->exp_conn_handle == conn_handle); + TEST_ASSERT(!cb_arg->called); + TEST_ASSERT_FATAL(error != NULL); + TEST_ASSERT(error->status == cb_arg->exp_status); + TEST_ASSERT(service == NULL); + + cb_arg->called++; + + return 0; +} + +static int +ble_gatt_conn_test_disc_svc_uuid_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_svc *service, + void *arg) +{ + struct ble_gatt_conn_test_arg *cb_arg; + + cb_arg = arg; + + TEST_ASSERT(cb_arg->exp_conn_handle == conn_handle); + TEST_ASSERT(!cb_arg->called); + TEST_ASSERT_FATAL(error != NULL); + TEST_ASSERT(error->status == cb_arg->exp_status); + TEST_ASSERT(service == NULL); + + cb_arg->called++; + + return 0; +} + +static int +ble_gatt_conn_test_find_inc_svcs_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_svc *service, + void *arg) +{ + struct ble_gatt_conn_test_arg *cb_arg; + + cb_arg = arg; + + TEST_ASSERT(cb_arg->exp_conn_handle == conn_handle); + TEST_ASSERT(!cb_arg->called); + TEST_ASSERT_FATAL(error != NULL); + TEST_ASSERT(error->status == cb_arg->exp_status); + TEST_ASSERT(service == NULL); + + cb_arg->called++; + + return 0; +} + +static int +ble_gatt_conn_test_disc_all_chrs_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_chr *chr, void *arg) +{ + struct ble_gatt_conn_test_arg *cb_arg; + + cb_arg = arg; + + TEST_ASSERT(cb_arg->exp_conn_handle == conn_handle); + TEST_ASSERT(!cb_arg->called); + TEST_ASSERT_FATAL(error != NULL); + TEST_ASSERT(error->status == cb_arg->exp_status); + TEST_ASSERT(chr == NULL); + + cb_arg->called++; + + return 0; +} + +static int +ble_gatt_conn_test_disc_chr_uuid_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_chr *chr, void *arg) +{ + struct ble_gatt_conn_test_arg *cb_arg; + + cb_arg = arg; + + TEST_ASSERT(cb_arg->exp_conn_handle == conn_handle); + TEST_ASSERT(!cb_arg->called); + TEST_ASSERT_FATAL(error != NULL); + TEST_ASSERT(error->status == cb_arg->exp_status); + TEST_ASSERT(chr == NULL); + + cb_arg->called++; + + return 0; +} + +static int +ble_gatt_conn_test_disc_all_dscs_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + uint16_t chr_val_handle, + const struct ble_gatt_dsc *dsc, + void *arg) +{ + struct ble_gatt_conn_test_arg *cb_arg; + + cb_arg = arg; + + TEST_ASSERT(cb_arg->exp_conn_handle == conn_handle); + TEST_ASSERT(!cb_arg->called); + TEST_ASSERT_FATAL(error != NULL); + TEST_ASSERT(error->status == cb_arg->exp_status); + TEST_ASSERT(dsc == NULL); + + cb_arg->called++; + + return 0; +} + +static int +ble_gatt_conn_test_read_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, void *arg) +{ + struct ble_gatt_conn_test_arg *cb_arg; + + cb_arg = arg; + + TEST_ASSERT(cb_arg->exp_conn_handle == conn_handle); + TEST_ASSERT(!cb_arg->called); + TEST_ASSERT_FATAL(error != NULL); + TEST_ASSERT(error->status == cb_arg->exp_status); + TEST_ASSERT(attr == NULL); + + cb_arg->called++; + + return 0; +} + +static int +ble_gatt_conn_test_read_uuid_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, void *arg) +{ + struct ble_gatt_conn_test_arg *cb_arg; + + cb_arg = arg; + + TEST_ASSERT(cb_arg->exp_conn_handle == conn_handle); + TEST_ASSERT(!cb_arg->called); + TEST_ASSERT_FATAL(error != NULL); + TEST_ASSERT(error->status == cb_arg->exp_status); + TEST_ASSERT(attr == NULL); + + cb_arg->called++; + + return 0; +} + +static int +ble_gatt_conn_test_read_long_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, void *arg) +{ + struct ble_gatt_conn_test_arg *cb_arg; + + cb_arg = arg; + + TEST_ASSERT(cb_arg->exp_conn_handle == conn_handle); + TEST_ASSERT(!cb_arg->called); + TEST_ASSERT_FATAL(error != NULL); + TEST_ASSERT(error->status == cb_arg->exp_status); + TEST_ASSERT(attr == NULL); + + cb_arg->called++; + + return 0; +} +static int +ble_gatt_conn_test_read_mult_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, void *arg) +{ + struct ble_gatt_conn_test_arg *cb_arg; + + cb_arg = arg; + + TEST_ASSERT(cb_arg->exp_conn_handle == conn_handle); + TEST_ASSERT(!cb_arg->called); + TEST_ASSERT_FATAL(error != NULL); + TEST_ASSERT(error->status == cb_arg->exp_status); + TEST_ASSERT(attr->om == NULL); + + cb_arg->called++; + + return 0; +} + +static int +ble_gatt_conn_test_write_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + void *arg) +{ + struct ble_gatt_conn_test_arg *cb_arg; + + cb_arg = arg; + + TEST_ASSERT(cb_arg->exp_conn_handle == conn_handle); + TEST_ASSERT(!cb_arg->called); + TEST_ASSERT_FATAL(error != NULL); + TEST_ASSERT(error->status == cb_arg->exp_status); + TEST_ASSERT(attr != NULL); + TEST_ASSERT(attr->handle == BLE_GATT_BREAK_TEST_WRITE_ATTR_HANDLE); + + cb_arg->called++; + + return 0; +} + +static int +ble_gatt_conn_test_write_long_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, void *arg) +{ + struct ble_gatt_conn_test_arg *cb_arg; + + cb_arg = arg; + + TEST_ASSERT(cb_arg->exp_conn_handle == conn_handle); + TEST_ASSERT(!cb_arg->called); + TEST_ASSERT_FATAL(error != NULL); + TEST_ASSERT(error->status == cb_arg->exp_status); + TEST_ASSERT(attr != NULL); + TEST_ASSERT(attr->handle == BLE_GATT_BREAK_TEST_WRITE_ATTR_HANDLE); + + cb_arg->called++; + + return 0; +} + +static int +ble_gatt_conn_test_write_rel_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attrs, + uint8_t num_attrs, + void *arg) +{ + struct ble_gatt_conn_test_arg *cb_arg; + + cb_arg = arg; + + TEST_ASSERT(cb_arg->exp_conn_handle == conn_handle); + TEST_ASSERT(!cb_arg->called); + TEST_ASSERT_FATAL(error != NULL); + TEST_ASSERT(error->status == cb_arg->exp_status); + TEST_ASSERT(attrs != NULL); + + cb_arg->called++; + + return 0; +} + +TEST_CASE_SELF(ble_gatt_conn_test_disconnect) +{ + struct ble_gatt_conn_test_arg mtu_arg = { 0, BLE_HS_ENOTCONN }; + struct ble_gatt_conn_test_arg disc_all_svcs_arg = { 0, BLE_HS_ENOTCONN }; + struct ble_gatt_conn_test_arg disc_svc_uuid_arg = { 0, BLE_HS_ENOTCONN }; + struct ble_gatt_conn_test_arg find_inc_svcs_arg = { 0, BLE_HS_ENOTCONN }; + struct ble_gatt_conn_test_arg disc_all_chrs_arg = { 0, BLE_HS_ENOTCONN }; + struct ble_gatt_conn_test_arg disc_chr_uuid_arg = { 0, BLE_HS_ENOTCONN }; + struct ble_gatt_conn_test_arg disc_all_dscs_arg = { 0, BLE_HS_ENOTCONN }; + struct ble_gatt_conn_test_arg read_arg = { 0, BLE_HS_ENOTCONN }; + struct ble_gatt_conn_test_arg read_uuid_arg = { 0, BLE_HS_ENOTCONN }; + struct ble_gatt_conn_test_arg read_long_arg = { 0, BLE_HS_ENOTCONN }; + struct ble_gatt_conn_test_arg read_mult_arg = { 0, BLE_HS_ENOTCONN }; + struct ble_gatt_conn_test_arg write_arg = { 0, BLE_HS_ENOTCONN }; + struct ble_gatt_conn_test_arg write_long_arg = { 0, BLE_HS_ENOTCONN }; + struct ble_gatt_conn_test_arg write_rel_arg = { 0, BLE_HS_ENOTCONN }; + struct ble_gatt_attr attr; + uint16_t attr_handle; + uint16_t offset = 0; + int rc; + + ble_gatt_conn_test_util_init(); + + /*** Register an attribute to allow indicatations to be sent. */ + rc = ble_att_svr_register(BLE_UUID16_DECLARE(0x1212), BLE_ATT_F_READ, 0, + &attr_handle, + ble_gatt_conn_test_attr_cb, NULL); + TEST_ASSERT(rc == 0); + + /* Create three connections. */ + ble_hs_test_util_create_conn(1, ((uint8_t[]){1,2,3,4,5,6,7,8}), + ble_gatt_conn_test_indicate_cb, NULL); + ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), + ble_gatt_conn_test_indicate_cb, NULL); + ble_hs_test_util_create_conn(3, ((uint8_t[]){3,4,5,6,7,8,9,10}), + ble_gatt_conn_test_indicate_cb, NULL); + + /*** Schedule some GATT procedures. */ + /* Connection 1. */ + mtu_arg.exp_conn_handle = 1; + ble_gattc_exchange_mtu(1, ble_gatt_conn_test_mtu_cb, &mtu_arg); + + disc_all_svcs_arg.exp_conn_handle = 1; + rc = ble_gattc_disc_all_svcs(1, ble_gatt_conn_test_disc_all_svcs_cb, + &disc_all_svcs_arg); + TEST_ASSERT_FATAL(rc == 0); + + disc_svc_uuid_arg.exp_conn_handle = 1; + rc = ble_gattc_disc_svc_by_uuid(1, BLE_UUID16_DECLARE(0x1111), + ble_gatt_conn_test_disc_svc_uuid_cb, + &disc_svc_uuid_arg); + TEST_ASSERT_FATAL(rc == 0); + + find_inc_svcs_arg.exp_conn_handle = 1; + rc = ble_gattc_find_inc_svcs(1, 1, 0xffff, + ble_gatt_conn_test_find_inc_svcs_cb, + &find_inc_svcs_arg); + TEST_ASSERT_FATAL(rc == 0); + + disc_all_chrs_arg.exp_conn_handle = 1; + rc = ble_gattc_disc_all_chrs(1, 1, 0xffff, + ble_gatt_conn_test_disc_all_chrs_cb, + &disc_all_chrs_arg); + TEST_ASSERT_FATAL(rc == 0); + + /* Connection 2. */ + disc_all_dscs_arg.exp_conn_handle = 2; + rc = ble_gattc_disc_all_dscs(2, 3, 0xffff, + ble_gatt_conn_test_disc_all_dscs_cb, + &disc_all_dscs_arg); + + disc_chr_uuid_arg.exp_conn_handle = 2; + rc = ble_gattc_disc_chrs_by_uuid(2, 2, 0xffff, BLE_UUID16_DECLARE(0x2222), + ble_gatt_conn_test_disc_chr_uuid_cb, + &disc_chr_uuid_arg); + + read_arg.exp_conn_handle = 2; + rc = ble_gattc_read(2, BLE_GATT_BREAK_TEST_READ_ATTR_HANDLE, + ble_gatt_conn_test_read_cb, &read_arg); + TEST_ASSERT_FATAL(rc == 0); + + read_uuid_arg.exp_conn_handle = 2; + rc = ble_gattc_read_by_uuid(2, 1, 0xffff, BLE_UUID16_DECLARE(0x3333), + ble_gatt_conn_test_read_uuid_cb, + &read_uuid_arg); + TEST_ASSERT_FATAL(rc == 0); + + read_long_arg.exp_conn_handle = 2; + rc = ble_gattc_read_long(2, BLE_GATT_BREAK_TEST_READ_ATTR_HANDLE, offset, + ble_gatt_conn_test_read_long_cb, &read_long_arg); + TEST_ASSERT_FATAL(rc == 0); + + /* Connection 3. */ + read_mult_arg.exp_conn_handle = 3; + rc = ble_gattc_read_mult(3, ((uint16_t[3]){5,6,7}), 3, + ble_gatt_conn_test_read_mult_cb, &read_mult_arg); + TEST_ASSERT_FATAL(rc == 0); + + write_arg.exp_conn_handle = 3; + rc = ble_hs_test_util_gatt_write_flat( + 3, BLE_GATT_BREAK_TEST_WRITE_ATTR_HANDLE, + ble_gatt_conn_test_write_value, sizeof ble_gatt_conn_test_write_value, + ble_gatt_conn_test_write_cb, &write_arg); + TEST_ASSERT_FATAL(rc == 0); + + write_long_arg.exp_conn_handle = 3; + rc = ble_hs_test_util_gatt_write_long_flat( + 3, BLE_GATT_BREAK_TEST_WRITE_ATTR_HANDLE, + ble_gatt_conn_test_write_value, sizeof ble_gatt_conn_test_write_value, + ble_gatt_conn_test_write_long_cb, &write_long_arg); + TEST_ASSERT_FATAL(rc == 0); + + attr.handle = 8; + attr.offset = 0; + attr.om = os_msys_get_pkthdr(0, 0); + write_rel_arg.exp_conn_handle = 3; + rc = ble_gattc_write_reliable( + 3, &attr, 1, ble_gatt_conn_test_write_rel_cb, &write_rel_arg); + TEST_ASSERT_FATAL(rc == 0); + + rc = ble_gattc_indicate(3, attr_handle); + TEST_ASSERT_FATAL(rc == 0); + + /*** Start the procedures. */ + + /*** Break the connections; verify proper callbacks got called. */ + /* Connection 1. */ + ble_gattc_connection_broken(1); + TEST_ASSERT(mtu_arg.called == 1); + TEST_ASSERT(disc_all_svcs_arg.called == 1); + TEST_ASSERT(disc_svc_uuid_arg.called == 1); + TEST_ASSERT(find_inc_svcs_arg.called == 1); + TEST_ASSERT(disc_all_chrs_arg.called == 1); + TEST_ASSERT(disc_chr_uuid_arg.called == 0); + TEST_ASSERT(disc_all_dscs_arg.called == 0); + TEST_ASSERT(read_arg.called == 0); + TEST_ASSERT(read_uuid_arg.called == 0); + TEST_ASSERT(read_long_arg.called == 0); + TEST_ASSERT(read_mult_arg.called == 0); + TEST_ASSERT(write_arg.called == 0); + TEST_ASSERT(write_long_arg.called == 0); + TEST_ASSERT(write_rel_arg.called == 0); + TEST_ASSERT(ble_gatt_conn_test_gap_event.type == 255); + + /* Connection 2. */ + ble_gattc_connection_broken(2); + TEST_ASSERT(mtu_arg.called == 1); + TEST_ASSERT(disc_all_svcs_arg.called == 1); + TEST_ASSERT(disc_svc_uuid_arg.called == 1); + TEST_ASSERT(find_inc_svcs_arg.called == 1); + TEST_ASSERT(disc_all_chrs_arg.called == 1); + TEST_ASSERT(disc_chr_uuid_arg.called == 1); + TEST_ASSERT(disc_all_dscs_arg.called == 1); + TEST_ASSERT(read_arg.called == 1); + TEST_ASSERT(read_uuid_arg.called == 1); + TEST_ASSERT(read_long_arg.called == 1); + TEST_ASSERT(read_mult_arg.called == 0); + TEST_ASSERT(write_arg.called == 0); + TEST_ASSERT(write_long_arg.called == 0); + TEST_ASSERT(write_rel_arg.called == 0); + TEST_ASSERT(ble_gatt_conn_test_gap_event.type == 255); + + /* Connection 3. */ + ble_gattc_connection_broken(3); + TEST_ASSERT(mtu_arg.called == 1); + TEST_ASSERT(disc_all_svcs_arg.called == 1); + TEST_ASSERT(disc_svc_uuid_arg.called == 1); + TEST_ASSERT(find_inc_svcs_arg.called == 1); + TEST_ASSERT(disc_all_chrs_arg.called == 1); + TEST_ASSERT(disc_chr_uuid_arg.called == 1); + TEST_ASSERT(disc_all_dscs_arg.called == 1); + TEST_ASSERT(read_arg.called == 1); + TEST_ASSERT(read_uuid_arg.called == 1); + TEST_ASSERT(read_long_arg.called == 1); + TEST_ASSERT(read_mult_arg.called == 1); + TEST_ASSERT(write_arg.called == 1); + TEST_ASSERT(write_long_arg.called == 1); + TEST_ASSERT(write_rel_arg.called == 1); + TEST_ASSERT(ble_gatt_conn_test_gap_event.type == BLE_GAP_EVENT_NOTIFY_TX); + TEST_ASSERT(ble_gatt_conn_test_gap_event.notify_tx.status == + BLE_HS_ENOTCONN); + TEST_ASSERT(ble_gatt_conn_test_gap_event.notify_tx.conn_handle == 3); + TEST_ASSERT(ble_gatt_conn_test_gap_event.notify_tx.attr_handle == + attr_handle); + TEST_ASSERT(ble_gatt_conn_test_gap_event.notify_tx.indication); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +static void +ble_gatt_conn_test_util_timeout(uint16_t conn_handle, + struct ble_gatt_conn_test_arg *arg) +{ + int32_t ticks_from_now; + + ticks_from_now = ble_gattc_timer(); + TEST_ASSERT(ticks_from_now == 30 * OS_TICKS_PER_SEC); + + os_time_advance(29 * OS_TICKS_PER_SEC); + ticks_from_now = ble_gattc_timer(); + TEST_ASSERT(ticks_from_now == 1 * OS_TICKS_PER_SEC); + + ble_hs_test_util_hci_ack_set_disconnect(0); + os_time_advance(1 * OS_TICKS_PER_SEC); + ticks_from_now = ble_gattc_timer(); + TEST_ASSERT(ticks_from_now == BLE_HS_FOREVER); + + /* Ensure connection was terminated due to proecedure timeout. */ + ble_hs_test_util_hci_rx_disconn_complete_event(conn_handle, 0, + BLE_ERR_REM_USER_CONN_TERM); + + /* Ensure GATT callback was called with timeout status. */ + if (arg != NULL) { + TEST_ASSERT(arg->called == 1); + } +} + +TEST_CASE_SELF(ble_gatt_conn_test_timeout) +{ + static const uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + + struct ble_gatt_conn_test_arg mtu_arg = { 1, BLE_HS_ETIMEOUT }; + struct ble_gatt_conn_test_arg disc_all_svcs_arg = { 1, BLE_HS_ETIMEOUT }; + struct ble_gatt_conn_test_arg disc_svc_uuid_arg = { 1, BLE_HS_ETIMEOUT }; + struct ble_gatt_conn_test_arg find_inc_svcs_arg = { 1, BLE_HS_ETIMEOUT }; + struct ble_gatt_conn_test_arg disc_all_chrs_arg = { 1, BLE_HS_ETIMEOUT }; + struct ble_gatt_conn_test_arg disc_chr_uuid_arg = { 1, BLE_HS_ETIMEOUT }; + struct ble_gatt_conn_test_arg disc_all_dscs_arg = { 1, BLE_HS_ETIMEOUT }; + struct ble_gatt_conn_test_arg read_arg = { 1, BLE_HS_ETIMEOUT }; + struct ble_gatt_conn_test_arg read_uuid_arg = { 1, BLE_HS_ETIMEOUT }; + struct ble_gatt_conn_test_arg read_long_arg = { 1, BLE_HS_ETIMEOUT }; + struct ble_gatt_conn_test_arg read_mult_arg = { 1, BLE_HS_ETIMEOUT }; + struct ble_gatt_conn_test_arg write_arg = { 1, BLE_HS_ETIMEOUT }; + struct ble_gatt_conn_test_arg write_long_arg = { 1, BLE_HS_ETIMEOUT }; + struct ble_gatt_conn_test_arg write_rel_arg = { 1, BLE_HS_ETIMEOUT }; + + struct ble_gatt_attr attr; + int32_t ticks_from_now; + uint16_t attr_handle; + uint16_t offset = 0; + int rc; + + ble_gatt_conn_test_util_init(); + + ticks_from_now = ble_gattc_timer(); + TEST_ASSERT(ticks_from_now == BLE_HS_FOREVER); + + /*** Register an attribute to allow indicatations to be sent. */ + rc = ble_att_svr_register(BLE_UUID16_DECLARE(0x1212), BLE_ATT_F_READ, 0, + &attr_handle, + ble_gatt_conn_test_attr_cb, NULL); + TEST_ASSERT(rc == 0); + + /*** MTU. */ + ble_hs_test_util_create_conn(1, peer_addr, NULL, NULL); + rc = ble_gattc_exchange_mtu(1, ble_gatt_conn_test_mtu_cb, &mtu_arg); + TEST_ASSERT_FATAL(rc == 0); + ble_gatt_conn_test_util_timeout(1, &mtu_arg); + + /*** Discover all services. */ + ble_hs_test_util_create_conn(1, peer_addr, NULL, NULL); + rc = ble_gattc_disc_all_svcs(1, ble_gatt_conn_test_disc_all_svcs_cb, + &disc_all_svcs_arg); + TEST_ASSERT_FATAL(rc == 0); + ble_gatt_conn_test_util_timeout(1, &disc_all_svcs_arg); + + /*** Discover services by UUID. */ + ble_hs_test_util_create_conn(1, peer_addr, NULL, NULL); + rc = ble_gattc_disc_svc_by_uuid(1, BLE_UUID16_DECLARE(0x1111), + ble_gatt_conn_test_disc_svc_uuid_cb, + &disc_svc_uuid_arg); + TEST_ASSERT_FATAL(rc == 0); + ble_gatt_conn_test_util_timeout(1, &disc_svc_uuid_arg); + + /*** Find included services. */ + ble_hs_test_util_create_conn(1, peer_addr, NULL, NULL); + rc = ble_gattc_find_inc_svcs(1, 1, 0xffff, + ble_gatt_conn_test_find_inc_svcs_cb, + &find_inc_svcs_arg); + TEST_ASSERT_FATAL(rc == 0); + ble_gatt_conn_test_util_timeout(1, &find_inc_svcs_arg); + + /*** Discover all characteristics. */ + ble_hs_test_util_create_conn(1, peer_addr, NULL, NULL); + rc = ble_gattc_disc_all_chrs(1, 1, 0xffff, + ble_gatt_conn_test_disc_all_chrs_cb, + &disc_all_chrs_arg); + TEST_ASSERT_FATAL(rc == 0); + ble_gatt_conn_test_util_timeout(1, &disc_all_chrs_arg); + + /*** Discover all descriptors. */ + ble_hs_test_util_create_conn(1, peer_addr, NULL, NULL); + rc = ble_gattc_disc_all_dscs(1, 3, 0xffff, + ble_gatt_conn_test_disc_all_dscs_cb, + &disc_chr_uuid_arg); + TEST_ASSERT_FATAL(rc == 0); + ble_gatt_conn_test_util_timeout(1, &disc_chr_uuid_arg); + + /*** Discover characteristics by UUID. */ + ble_hs_test_util_create_conn(1, peer_addr, NULL, NULL); + rc = ble_gattc_disc_chrs_by_uuid(1, 2, 0xffff, BLE_UUID16_DECLARE(0x2222), + ble_gatt_conn_test_disc_chr_uuid_cb, + &disc_all_dscs_arg); + TEST_ASSERT_FATAL(rc == 0); + ble_gatt_conn_test_util_timeout(1, &disc_all_dscs_arg); + + /*** Read. */ + ble_hs_test_util_create_conn(1, peer_addr, NULL, NULL); + rc = ble_gattc_read(1, BLE_GATT_BREAK_TEST_READ_ATTR_HANDLE, + ble_gatt_conn_test_read_cb, &read_arg); + TEST_ASSERT_FATAL(rc == 0); + ble_gatt_conn_test_util_timeout(1, &read_arg); + + /*** Read by UUID. */ + ble_hs_test_util_create_conn(1, peer_addr, NULL, NULL); + rc = ble_gattc_read_by_uuid(1, 1, 0xffff, BLE_UUID16_DECLARE(0x3333), + ble_gatt_conn_test_read_uuid_cb, + &read_uuid_arg); + TEST_ASSERT_FATAL(rc == 0); + ble_gatt_conn_test_util_timeout(1, &read_uuid_arg); + + /*** Read long. */ + ble_hs_test_util_create_conn(1, peer_addr, NULL, NULL); + rc = ble_gattc_read_long(1, BLE_GATT_BREAK_TEST_READ_ATTR_HANDLE, offset, + ble_gatt_conn_test_read_long_cb, + &read_long_arg); + TEST_ASSERT_FATAL(rc == 0); + ble_gatt_conn_test_util_timeout(1, &read_long_arg); + + /*** Read multiple. */ + ble_hs_test_util_create_conn(1, peer_addr, NULL, NULL); + rc = ble_gattc_read_mult(1, ((uint16_t[3]){5,6,7}), 3, + ble_gatt_conn_test_read_mult_cb, + &read_mult_arg); + TEST_ASSERT_FATAL(rc == 0); + ble_gatt_conn_test_util_timeout(1, &read_mult_arg); + + /*** Write. */ + ble_hs_test_util_create_conn(1, peer_addr, NULL, NULL); + rc = ble_hs_test_util_gatt_write_flat( + 1, BLE_GATT_BREAK_TEST_WRITE_ATTR_HANDLE, + ble_gatt_conn_test_write_value, sizeof ble_gatt_conn_test_write_value, + ble_gatt_conn_test_write_cb, &write_arg); + TEST_ASSERT_FATAL(rc == 0); + ble_gatt_conn_test_util_timeout(1, &write_arg); + + /*** Write long. */ + ble_hs_test_util_create_conn(1, peer_addr, NULL, NULL); + rc = ble_hs_test_util_gatt_write_long_flat( + 1, BLE_GATT_BREAK_TEST_WRITE_ATTR_HANDLE, + ble_gatt_conn_test_write_value, sizeof ble_gatt_conn_test_write_value, + ble_gatt_conn_test_write_long_cb, &write_long_arg); + TEST_ASSERT_FATAL(rc == 0); + ble_gatt_conn_test_util_timeout(1, &write_long_arg); + + /*** Write reliable. */ + ble_hs_test_util_create_conn(1, peer_addr, NULL, NULL); + attr.handle = 8; + attr.offset = 0; + attr.om = os_msys_get_pkthdr(0, 0); + rc = ble_gattc_write_reliable( + 1, &attr, 1, ble_gatt_conn_test_write_rel_cb, &write_rel_arg); + TEST_ASSERT_FATAL(rc == 0); + ble_gatt_conn_test_util_timeout(1, &write_rel_arg); + + /*** Indication. */ + ble_hs_test_util_create_conn(1, peer_addr, NULL, NULL); + rc = ble_gattc_indicate(1, attr_handle); + TEST_ASSERT_FATAL(rc == 0); + ble_gatt_conn_test_util_timeout(1, NULL); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_gatt_conn_suite) +{ + ble_gatt_conn_test_disconnect(); + ble_gatt_conn_test_timeout(); +} diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_gatt_disc_c_test.c b/src/libs/mynewt-nimble/nimble/host/test/src/ble_gatt_disc_c_test.c new file mode 100644 index 00000000..e19db341 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_gatt_disc_c_test.c @@ -0,0 +1,722 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include "testutil/testutil.h" +#include "nimble/ble.h" +#include "ble_hs_test.h" +#include "host/ble_gatt.h" +#include "host/ble_uuid.h" +#include "ble_hs_test_util.h" + +struct ble_gatt_disc_c_test_char { + uint16_t def_handle; + uint16_t val_handle; + uint8_t properties; + const ble_uuid_t *uuid; +}; + +#define BLE_GATT_DISC_C_TEST_MAX_CHARS 256 +static struct ble_gatt_chr + ble_gatt_disc_c_test_chars[BLE_GATT_DISC_C_TEST_MAX_CHARS]; +static int ble_gatt_disc_c_test_num_chars; +static int ble_gatt_disc_c_test_rx_complete; + +static void +ble_gatt_disc_c_test_init(void) +{ + ble_hs_test_util_init(); + + ble_gatt_disc_c_test_num_chars = 0; + ble_gatt_disc_c_test_rx_complete = 0; +} + +static int +ble_gatt_disc_c_test_misc_rx_rsp_once( + uint16_t conn_handle, struct ble_gatt_disc_c_test_char *chars) +{ + struct ble_att_read_type_rsp rsp; + uint8_t buf[1024]; + int off; + int rc; + int i; + + /* Send the pending ATT Read By Type Request. */ + + if (chars[0].uuid->type == BLE_UUID_TYPE_16) { + rsp.batp_length = BLE_ATT_READ_TYPE_ADATA_BASE_SZ + + BLE_GATT_CHR_DECL_SZ_16; + } else { + rsp.batp_length = BLE_ATT_READ_TYPE_ADATA_BASE_SZ + + BLE_GATT_CHR_DECL_SZ_128; + } + + ble_att_read_type_rsp_write(buf, BLE_ATT_READ_TYPE_RSP_BASE_SZ, &rsp); + + off = BLE_ATT_READ_TYPE_RSP_BASE_SZ; + for (i = 0; ; i++) { + if (chars[i].def_handle == 0) { + /* No more services. */ + break; + } + + /* If the value length is changing, we need a separate response. */ + if (((chars[i].uuid->type == BLE_UUID_TYPE_16) ^ + (chars[0].uuid->type == BLE_UUID_TYPE_16)) != 0) { + break; + } + + if (chars[i].uuid->type == BLE_UUID_TYPE_16) { + if (off + BLE_ATT_READ_TYPE_ADATA_SZ_16 > + ble_att_mtu(conn_handle)) { + + /* Can't fit any more entries. */ + break; + } + } else { + if (off + BLE_ATT_READ_TYPE_ADATA_SZ_128 > + ble_att_mtu(conn_handle)) { + + /* Can't fit any more entries. */ + break; + } + } + + put_le16(buf + off, chars[i].def_handle); + off += 2; + + buf[off] = chars[i].properties; + off++; + + put_le16(buf + off, chars[i].val_handle); + off += 2; + + ble_uuid_flat(chars[i].uuid, buf + off); + off += ble_uuid_length(chars[i].uuid); + } + + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, off); + TEST_ASSERT(rc == 0); + + return i; +} + +static void +ble_gatt_disc_c_test_misc_rx_rsp(uint16_t conn_handle, + uint16_t end_handle, + struct ble_gatt_disc_c_test_char *chars) +{ + int count; + int idx; + + idx = 0; + while (chars[idx].def_handle != 0) { + count = ble_gatt_disc_c_test_misc_rx_rsp_once(conn_handle, + chars + idx); + if (count == 0) { + break; + } + idx += count; + } + + if (chars[idx - 1].def_handle != end_handle) { + /* Send the pending ATT Request. */ + ble_hs_test_util_rx_att_err_rsp(conn_handle, BLE_ATT_OP_READ_TYPE_REQ, + BLE_ATT_ERR_ATTR_NOT_FOUND, + chars[idx - 1].def_handle); + } +} + +static void +ble_gatt_disc_c_test_misc_verify_chars(struct ble_gatt_disc_c_test_char *chars, + int stop_after) +{ + int i; + + if (stop_after == 0) { + stop_after = BLE_GATT_DISC_C_TEST_MAX_CHARS; + } + + for (i = 0; i < stop_after && chars[i].def_handle != 0; i++) { + TEST_ASSERT(chars[i].def_handle == + ble_gatt_disc_c_test_chars[i].def_handle); + TEST_ASSERT(chars[i].val_handle == + ble_gatt_disc_c_test_chars[i].val_handle); + TEST_ASSERT(ble_uuid_cmp(chars[i].uuid, + &ble_gatt_disc_c_test_chars[i].uuid.u) == 0); + } + + TEST_ASSERT(i == ble_gatt_disc_c_test_num_chars); + TEST_ASSERT(ble_gatt_disc_c_test_rx_complete); +} + +static int +ble_gatt_disc_c_test_misc_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_chr *chr, void *arg) +{ + struct ble_gatt_chr *dst; + int *stop_after; + + TEST_ASSERT(error != NULL); + TEST_ASSERT(!ble_gatt_disc_c_test_rx_complete); + + stop_after = arg; + + switch (error->status) { + case 0: + TEST_ASSERT_FATAL(ble_gatt_disc_c_test_num_chars < + BLE_GATT_DISC_C_TEST_MAX_CHARS); + + dst = ble_gatt_disc_c_test_chars + ble_gatt_disc_c_test_num_chars++; + *dst = *chr; + break; + + case BLE_HS_EDONE: + ble_gatt_disc_c_test_rx_complete = 1; + break; + + default: + TEST_ASSERT(0); + break; + } + + if (*stop_after > 0) { + (*stop_after)--; + if (*stop_after == 0) { + ble_gatt_disc_c_test_rx_complete = 1; + return 1; + } + } + + return 0; +} + +static void +ble_gatt_disc_c_test_misc_all(uint16_t start_handle, uint16_t end_handle, + int stop_after, + struct ble_gatt_disc_c_test_char *chars) +{ + int num_left; + int rc; + + ble_gatt_disc_c_test_init(); + + ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + + num_left = stop_after; + rc = ble_gattc_disc_all_chrs(2, start_handle, end_handle, + ble_gatt_disc_c_test_misc_cb, &num_left); + TEST_ASSERT(rc == 0); + + ble_gatt_disc_c_test_misc_rx_rsp(2, end_handle, chars); + ble_gatt_disc_c_test_misc_verify_chars(chars, stop_after); +} + +static void +ble_gatt_disc_c_test_misc_uuid(uint16_t start_handle, uint16_t end_handle, + int stop_after, const ble_uuid_t *uuid, + struct ble_gatt_disc_c_test_char *rsp_chars, + struct ble_gatt_disc_c_test_char *ret_chars) +{ + int rc; + + ble_gatt_disc_c_test_init(); + + ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + + rc = ble_gattc_disc_chrs_by_uuid(2, start_handle, end_handle, + uuid, + ble_gatt_disc_c_test_misc_cb, + &stop_after); + TEST_ASSERT(rc == 0); + + ble_gatt_disc_c_test_misc_rx_rsp(2, end_handle, rsp_chars); + ble_gatt_disc_c_test_misc_verify_chars(ret_chars, 0); +} + +TEST_CASE_SELF(ble_gatt_disc_c_test_disc_all) +{ + /*** One 16-bit characteristic. */ + ble_gatt_disc_c_test_misc_all(50, 100, 0, + (struct ble_gatt_disc_c_test_char[]) { + { + .def_handle = 55, + .val_handle = 56, + .uuid = BLE_UUID16_DECLARE(0x2010), + }, { 0 } + }); + + /*** Two 16-bit characteristics. */ + ble_gatt_disc_c_test_misc_all(50, 100, 0, + (struct ble_gatt_disc_c_test_char[]) { + { + .def_handle = 55, + .val_handle = 56, + .uuid = BLE_UUID16_DECLARE(0x2010), + }, { + .def_handle = 57, + .val_handle = 58, + .uuid = BLE_UUID16_DECLARE(0x64ba), + }, { 0 } + }); + + /*** Five 16-bit characteristics. */ + ble_gatt_disc_c_test_misc_all(50, 100, 0, + (struct ble_gatt_disc_c_test_char[]) { + { + .def_handle = 55, + .val_handle = 56, + .uuid = BLE_UUID16_DECLARE(0x2010), + }, { + .def_handle = 57, + .val_handle = 58, + .uuid = BLE_UUID16_DECLARE(0x64ba), + }, { + .def_handle = 59, + .val_handle = 60, + .uuid = BLE_UUID16_DECLARE(0x5372), + }, { + .def_handle = 61, + .val_handle = 62, + .uuid = BLE_UUID16_DECLARE(0xab93), + }, { + .def_handle = 63, + .val_handle = 64, + .uuid = BLE_UUID16_DECLARE(0x0023), + }, { 0 } + }); + + /*** Interleaved 16-bit and 128-bit characteristics. */ + ble_gatt_disc_c_test_misc_all(50, 100, 0, + (struct ble_gatt_disc_c_test_char[]) { + { + .def_handle = 83, + .val_handle = 84, + .uuid = BLE_UUID16_DECLARE(0x2010), + }, { + .def_handle = 87, + .val_handle = 88, + .uuid = BLE_UUID128_DECLARE(0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15), + }, { + .def_handle = 91, + .val_handle = 92, + .uuid = BLE_UUID16_DECLARE(0x0003), + }, { + .def_handle = 93, + .val_handle = 94, + .uuid = BLE_UUID128_DECLARE(1, 0, 4, 0, 6, 9, 17, 7, + 8, 43, 7, 4, 12, 43, 19, 35), + }, { + .def_handle = 98, + .val_handle = 99, + .uuid = BLE_UUID16_DECLARE(0xabfa), + }, { 0 } + }); + + /*** Ends with final handle ID. */ + ble_gatt_disc_c_test_misc_all(50, 100, 0, + (struct ble_gatt_disc_c_test_char[]) { + { + .def_handle = 55, + .val_handle = 56, + .uuid = BLE_UUID16_DECLARE(0x2010), + }, { + .def_handle = 99, + .val_handle = 100, + .uuid = BLE_UUID16_DECLARE(0x64ba), + }, { 0 } + }); + + /*** Stop after two characteristics. */ + ble_gatt_disc_c_test_misc_all(50, 100, 2, + (struct ble_gatt_disc_c_test_char[]) { + { + .def_handle = 55, + .val_handle = 56, + .uuid = BLE_UUID16_DECLARE(0x2010), + }, { + .def_handle = 57, + .val_handle = 58, + .uuid = BLE_UUID16_DECLARE(0x64ba), + }, { + .def_handle = 59, + .val_handle = 60, + .uuid = BLE_UUID16_DECLARE(0x5372), + }, { + .def_handle = 61, + .val_handle = 62, + .uuid = BLE_UUID16_DECLARE(0xab93), + }, { + .def_handle = 63, + .val_handle = 64, + .uuid = BLE_UUID16_DECLARE(0x0023), + }, { 0 } + }); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatt_disc_c_test_disc_uuid) +{ + /*** One 16-bit characteristic. */ + ble_gatt_disc_c_test_misc_uuid(50, 100, 0, BLE_UUID16_DECLARE(0x2010), + (struct ble_gatt_disc_c_test_char[]) { + { + .def_handle = 55, + .val_handle = 56, + .uuid = BLE_UUID16_DECLARE(0x2010), + }, { 0 } }, + (struct ble_gatt_disc_c_test_char[]) { + { + .def_handle = 55, + .val_handle = 56, + .uuid = BLE_UUID16_DECLARE(0x2010), + }, { 0 } } + ); + + /*** No matching characteristics. */ + ble_gatt_disc_c_test_misc_uuid(50, 100, 0, BLE_UUID16_DECLARE(0x2010), + (struct ble_gatt_disc_c_test_char[]) { + { + .def_handle = 55, + .val_handle = 56, + .uuid = BLE_UUID16_DECLARE(0x1234), + }, { 0 } }, + (struct ble_gatt_disc_c_test_char[]) { + { 0 } } + ); + + /*** 2/5 16-bit characteristics. */ + ble_gatt_disc_c_test_misc_uuid(50, 100, 0, BLE_UUID16_DECLARE(0x2010), + (struct ble_gatt_disc_c_test_char[]) { + { + .def_handle = 55, + .val_handle = 56, + .uuid = BLE_UUID16_DECLARE(0x2010), + }, { + .def_handle = 57, + .val_handle = 58, + .uuid = BLE_UUID16_DECLARE(0x64ba), + }, { + .def_handle = 59, + .val_handle = 60, + .uuid = BLE_UUID16_DECLARE(0x5372), + }, { + .def_handle = 61, + .val_handle = 62, + .uuid = BLE_UUID16_DECLARE(0x2010), + }, { + .def_handle = 63, + .val_handle = 64, + .uuid = BLE_UUID16_DECLARE(0x0023), + }, { 0 } }, + (struct ble_gatt_disc_c_test_char[]) { + { + .def_handle = 55, + .val_handle = 56, + .uuid = BLE_UUID16_DECLARE(0x2010), + }, { + .def_handle = 61, + .val_handle = 62, + .uuid = BLE_UUID16_DECLARE(0x2010), + }, { 0 } } + ); + + /*** Interleaved 16-bit and 128-bit characteristics. */ + ble_gatt_disc_c_test_misc_uuid( + 50, 100, 0, + BLE_UUID128_DECLARE(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15), + (struct ble_gatt_disc_c_test_char[]) { + { + .def_handle = 83, + .val_handle = 84, + .uuid = BLE_UUID16_DECLARE(0x2010), + }, { + .def_handle = 87, + .val_handle = 88, + .uuid = BLE_UUID128_DECLARE(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15), + }, { + .def_handle = 91, + .val_handle = 92, + .uuid = BLE_UUID16_DECLARE(0x0003), + }, { + .def_handle = 93, + .val_handle = 94, + .uuid = BLE_UUID128_DECLARE(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15), + }, { + .def_handle = 98, + .val_handle = 99, + .uuid = BLE_UUID16_DECLARE(0xabfa), + }, { 0 } }, + (struct ble_gatt_disc_c_test_char[]) { + { + .def_handle = 87, + .val_handle = 88, + .uuid = BLE_UUID128_DECLARE(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15), + }, { + .def_handle = 93, + .val_handle = 94, + .uuid = BLE_UUID128_DECLARE(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15), + }, { 0 } } + ); + + /*** Ends with final handle ID. */ + ble_gatt_disc_c_test_misc_uuid(50, 100, 0, BLE_UUID16_DECLARE(0x64ba), + (struct ble_gatt_disc_c_test_char[]) { + { + .def_handle = 55, + .val_handle = 56, + .uuid = BLE_UUID16_DECLARE(0x2010), + }, { + .def_handle = 99, + .val_handle = 100, + .uuid = BLE_UUID16_DECLARE(0x64ba), + }, { 0 } }, + (struct ble_gatt_disc_c_test_char[]) { + { + .def_handle = 99, + .val_handle = 100, + .uuid = BLE_UUID16_DECLARE(0x64ba), + }, { 0 } } + ); + + /*** Stop after first characteristic. */ + ble_gatt_disc_c_test_misc_uuid(50, 100, 1, BLE_UUID16_DECLARE(0x2010), + (struct ble_gatt_disc_c_test_char[]) { + { + .def_handle = 55, + .val_handle = 56, + .uuid = BLE_UUID16_DECLARE(0x2010), + }, { + .def_handle = 57, + .val_handle = 58, + .uuid = BLE_UUID16_DECLARE(0x64ba), + }, { + .def_handle = 59, + .val_handle = 60, + .uuid = BLE_UUID16_DECLARE(0x5372), + }, { + .def_handle = 61, + .val_handle = 62, + .uuid = BLE_UUID16_DECLARE(0x2010), + }, { + .def_handle = 63, + .val_handle = 64, + .uuid = BLE_UUID16_DECLARE(0x0023), + }, { 0 } }, + (struct ble_gatt_disc_c_test_char[]) { + { + .def_handle = 55, + .val_handle = 56, + .uuid = BLE_UUID16_DECLARE(0x2010), + }, { 0 } } + ); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatt_disc_c_test_oom_all) +{ + /* Retrieve enough characteristics to require two transactions. */ + struct ble_gatt_disc_c_test_char chrs[] = { + { + .def_handle = 93, + .val_handle = 94, + .uuid = BLE_UUID128_DECLARE(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15), + }, + { + .def_handle = 95, + .val_handle = 96, + .uuid = BLE_UUID128_DECLARE(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16), + }, + { 0 } + }; + + struct os_mbuf *oms; + int32_t ticks_until; + int stop_after; + int num_chrs; + int rc; + + ble_gatt_disc_c_test_init(); + + ble_hs_test_util_create_conn(1, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + + /* Initiate a discover all characteristics procedure. */ + stop_after = 0; + rc = ble_gattc_disc_all_chrs(1, 1, 0xffff, + ble_gatt_disc_c_test_misc_cb, &stop_after); + TEST_ASSERT_FATAL(rc == 0); + + /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ + oms = ble_hs_test_util_mbuf_alloc_all_but(1); + num_chrs = ble_gatt_disc_c_test_misc_rx_rsp_once(1, chrs); + + /* Make sure there are still undiscovered characteristics. */ + TEST_ASSERT_FATAL(num_chrs < sizeof chrs / sizeof chrs[0] - 1); + + /* Ensure no follow-up request got sent. It should not have gotten sent + * due to mbuf exhaustion. + */ + ble_hs_test_util_prev_tx_queue_clear(); + TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL); + + /* Verify that we will resume the stalled GATT procedure in one second. */ + ticks_until = ble_gattc_timer(); + TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE))); + + /* Verify the procedure proceeds after mbufs become available. */ + rc = os_mbuf_free_chain(oms); + TEST_ASSERT_FATAL(rc == 0); + + os_time_advance(ticks_until); + ble_gattc_timer(); + + /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ + oms = ble_hs_test_util_mbuf_alloc_all_but(1); + ble_gatt_disc_c_test_misc_rx_rsp_once(1, chrs + num_chrs); + + /* Ensure no follow-up request got sent. It should not have gotten sent + * due to mbuf exhaustion. + */ + ble_hs_test_util_prev_tx_queue_clear(); + TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL); + + /* Verify that we will resume the stalled GATT procedure in one second. */ + ticks_until = ble_gattc_timer(); + TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE))); + + /* Verify that procedure completes when mbufs are available. */ + rc = os_mbuf_free_chain(oms); + TEST_ASSERT_FATAL(rc == 0); + + os_time_advance(ticks_until); + ble_gattc_timer(); + + ble_hs_test_util_rx_att_err_rsp(1, + BLE_ATT_OP_READ_TYPE_REQ, + BLE_ATT_ERR_ATTR_NOT_FOUND, + 1); + ble_gatt_disc_c_test_misc_verify_chars(chrs, 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatt_disc_c_test_oom_uuid) +{ + /* Retrieve enough characteristics to require two transactions. */ + struct ble_gatt_disc_c_test_char chrs[] = { + { + .def_handle = 93, + .val_handle = 94, + .uuid = BLE_UUID128_DECLARE(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15), + }, + { + .def_handle = 95, + .val_handle = 96, + .uuid = BLE_UUID128_DECLARE(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15), + }, + { 0 } + }; + + struct os_mbuf *oms; + int32_t ticks_until; + int stop_after; + int num_chrs; + int rc; + + ble_gatt_disc_c_test_init(); + + ble_hs_test_util_create_conn(1, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + + /* Initiate a discover characteristics by UUID procedure. */ + stop_after = 0; + rc = ble_gattc_disc_chrs_by_uuid(1, 1, 0xffff, chrs[0].uuid, + ble_gatt_disc_c_test_misc_cb, + &stop_after); + TEST_ASSERT_FATAL(rc == 0); + + /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ + oms = ble_hs_test_util_mbuf_alloc_all_but(1); + num_chrs = ble_gatt_disc_c_test_misc_rx_rsp_once(1, chrs); + + /* Make sure there are still undiscovered characteristics. */ + TEST_ASSERT_FATAL(num_chrs < sizeof chrs / sizeof chrs[0] - 1); + + /* Ensure no follow-up request got sent. It should not have gotten sent + * due to mbuf exhaustion. + */ + ble_hs_test_util_prev_tx_queue_clear(); + TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL); + + /* Verify that we will resume the stalled GATT procedure in one second. */ + ticks_until = ble_gattc_timer(); + TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE))); + + /* Verify the procedure proceeds after mbufs become available. */ + rc = os_mbuf_free_chain(oms); + TEST_ASSERT_FATAL(rc == 0); + os_time_advance(ticks_until); + ble_gattc_timer(); + + /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ + oms = ble_hs_test_util_mbuf_alloc_all_but(1); + ble_gatt_disc_c_test_misc_rx_rsp_once(1, chrs + num_chrs); + + /* Ensure no follow-up request got sent. It should not have gotten sent + * due to mbuf exhaustion. + */ + ble_hs_test_util_prev_tx_queue_clear(); + TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL); + + /* Verify that we will resume the stalled GATT procedure in one second. */ + ticks_until = ble_gattc_timer(); + TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE))); + + /* Verify that procedure completes when mbufs are available. */ + rc = os_mbuf_free_chain(oms); + TEST_ASSERT_FATAL(rc == 0); + os_time_advance(ticks_until); + ble_gattc_timer(); + + ble_hs_test_util_rx_att_err_rsp(1, + BLE_ATT_OP_READ_TYPE_REQ, + BLE_ATT_ERR_ATTR_NOT_FOUND, + 1); + ble_gatt_disc_c_test_misc_verify_chars(chrs, 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_gatt_disc_c_test_suite) +{ + ble_gatt_disc_c_test_disc_all(); + ble_gatt_disc_c_test_disc_uuid(); + ble_gatt_disc_c_test_oom_all(); + ble_gatt_disc_c_test_oom_uuid(); +} diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_gatt_disc_d_test.c b/src/libs/mynewt-nimble/nimble/host/test/src/ble_gatt_disc_d_test.c new file mode 100644 index 00000000..e405c86f --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_gatt_disc_d_test.c @@ -0,0 +1,446 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include "testutil/testutil.h" +#include "nimble/ble.h" +#include "ble_hs_test.h" +#include "host/ble_gatt.h" +#include "host/ble_uuid.h" +#include "ble_hs_test_util.h" + +struct ble_gatt_disc_d_test_dsc { + uint16_t chr_val_handle; /* 0 if last entry. */ + uint16_t dsc_handle; + ble_uuid_any_t dsc_uuid; +}; + +#define BLE_GATT_DISC_D_TEST_MAX_DSCS 256 +static struct ble_gatt_disc_d_test_dsc + ble_gatt_disc_d_test_dscs[BLE_GATT_DISC_D_TEST_MAX_DSCS]; +static int ble_gatt_disc_d_test_num_dscs; +static int ble_gatt_disc_d_test_rx_complete; + +static void +ble_gatt_disc_d_test_init(void) +{ + ble_hs_test_util_init(); + + ble_gatt_disc_d_test_num_dscs = 0; + ble_gatt_disc_d_test_rx_complete = 0; +} + +static int +ble_gatt_disc_d_test_misc_rx_rsp_once( + uint16_t conn_handle, struct ble_gatt_disc_d_test_dsc *dscs) +{ + struct ble_att_find_info_rsp rsp; + uint8_t buf[1024]; + int off; + int rc; + int i; + + /* Send the pending ATT Read By Type Request. */ + + if (dscs[0].dsc_uuid.u.type == BLE_UUID_TYPE_16) { + rsp.bafp_format = BLE_ATT_FIND_INFO_RSP_FORMAT_16BIT; + } else { + rsp.bafp_format = BLE_ATT_FIND_INFO_RSP_FORMAT_128BIT; + } + + ble_att_find_info_rsp_write(buf, BLE_ATT_FIND_INFO_RSP_BASE_SZ, &rsp); + + off = BLE_ATT_FIND_INFO_RSP_BASE_SZ; + for (i = 0; ; i++) { + if (dscs[i].chr_val_handle == 0) { + /* No more descriptors. */ + break; + } + + if (dscs[i].dsc_uuid.u.type == BLE_UUID_TYPE_16) { + if (off + BLE_ATT_FIND_INFO_IDATA_16_SZ > + ble_att_mtu(conn_handle)) { + + /* Can't fit any more entries. */ + break; + } + } else { + if (off + BLE_ATT_FIND_INFO_IDATA_128_SZ > + ble_att_mtu(conn_handle)) { + + /* Can't fit any more entries. */ + break; + } + } + + /* If the value length is changing, we need a separate response. */ + if (((dscs[0].dsc_uuid.u.type == BLE_UUID_TYPE_16) ^ + (dscs[i].dsc_uuid.u.type == BLE_UUID_TYPE_16)) != 0) { + break; + } + + put_le16(buf + off, dscs[i].dsc_handle); + off += 2; + + ble_uuid_flat(&dscs[i].dsc_uuid.u, buf + off); + off += ble_uuid_length(&dscs[i].dsc_uuid.u); + } + + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, off); + TEST_ASSERT(rc == 0); + + return i; +} + +static void +ble_gatt_disc_d_test_misc_rx_rsp(uint16_t conn_handle, + uint16_t end_handle, + struct ble_gatt_disc_d_test_dsc *dscs) +{ + int count; + int idx; + + idx = 0; + while (dscs[idx].chr_val_handle != 0) { + count = ble_gatt_disc_d_test_misc_rx_rsp_once(conn_handle, dscs + idx); + if (count == 0) { + break; + } + idx += count; + } + + if (dscs[idx - 1].dsc_handle != end_handle) { + /* Send the pending ATT Request. */ + ble_hs_test_util_rx_att_err_rsp(conn_handle, BLE_ATT_OP_FIND_INFO_REQ, + BLE_ATT_ERR_ATTR_NOT_FOUND, + end_handle); + } +} + +static void +ble_gatt_disc_d_test_misc_verify_dscs(struct ble_gatt_disc_d_test_dsc *dscs, + int stop_after) +{ + int i; + + if (stop_after == 0) { + stop_after = BLE_GATT_DISC_D_TEST_MAX_DSCS; + } + + for (i = 0; i < stop_after && dscs[i].chr_val_handle != 0; i++) { + TEST_ASSERT(dscs[i].chr_val_handle == + ble_gatt_disc_d_test_dscs[i].chr_val_handle); + TEST_ASSERT(dscs[i].dsc_handle == + ble_gatt_disc_d_test_dscs[i].dsc_handle); + TEST_ASSERT(ble_uuid_cmp(&dscs[i].dsc_uuid.u, + &ble_gatt_disc_d_test_dscs[i].dsc_uuid.u) == 0); + } + + TEST_ASSERT(i == ble_gatt_disc_d_test_num_dscs); + TEST_ASSERT(ble_gatt_disc_d_test_rx_complete); +} + +static int +ble_gatt_disc_d_test_misc_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + uint16_t chr_val_handle, + const struct ble_gatt_dsc *dsc, + void *arg) +{ + struct ble_gatt_disc_d_test_dsc *dst; + int *stop_after; + + TEST_ASSERT(error != NULL); + TEST_ASSERT(!ble_gatt_disc_d_test_rx_complete); + + stop_after = arg; + + switch (error->status) { + case 0: + TEST_ASSERT_FATAL(ble_gatt_disc_d_test_num_dscs < + BLE_GATT_DISC_D_TEST_MAX_DSCS); + + dst = ble_gatt_disc_d_test_dscs + ble_gatt_disc_d_test_num_dscs++; + dst->chr_val_handle = chr_val_handle; + dst->dsc_handle = dsc->handle; + dst->dsc_uuid = dsc->uuid; + break; + + case BLE_HS_EDONE: + ble_gatt_disc_d_test_rx_complete = 1; + break; + + default: + TEST_ASSERT(0); + break; + } + + if (*stop_after > 0) { + (*stop_after)--; + if (*stop_after == 0) { + ble_gatt_disc_d_test_rx_complete = 1; + return 1; + } + } + + return 0; +} + +static void +ble_gatt_disc_d_test_misc_all(uint16_t chr_val_handle, uint16_t end_handle, + int stop_after, + struct ble_gatt_disc_d_test_dsc *dscs) +{ + int num_left; + int rc; + + ble_gatt_disc_d_test_init(); + + ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + + num_left = stop_after; + rc = ble_gattc_disc_all_dscs(2, chr_val_handle, end_handle, + ble_gatt_disc_d_test_misc_cb, &num_left); + TEST_ASSERT(rc == 0); + + ble_gatt_disc_d_test_misc_rx_rsp(2, end_handle, dscs); + ble_gatt_disc_d_test_misc_verify_dscs(dscs, stop_after); +} + +TEST_CASE_SELF(ble_gatt_disc_d_test_1) +{ + /*** One 16-bit descriptor. */ + ble_gatt_disc_d_test_misc_all(5, 10, 0, + ((struct ble_gatt_disc_d_test_dsc[]) { { + .chr_val_handle = 5, + .dsc_handle = 6, + .dsc_uuid.u16 = BLE_UUID16_INIT(0x1234), + }, { + 0 + } }) + ); + + /*** Two 16-bit descriptors. */ + ble_gatt_disc_d_test_misc_all(50, 100, 0, + ((struct ble_gatt_disc_d_test_dsc[]) { { + .chr_val_handle = 50, + .dsc_handle = 51, + .dsc_uuid.u16 = BLE_UUID16_INIT(0x1111), + }, { + .chr_val_handle = 50, + .dsc_handle = 52, + .dsc_uuid.u16 = BLE_UUID16_INIT(0x2222), + }, { + 0 + } }) + ); + + /*** Five 16-bit descriptors. */ + ble_gatt_disc_d_test_misc_all(50, 100, 0, + ((struct ble_gatt_disc_d_test_dsc[]) { { + .chr_val_handle = 50, + .dsc_handle = 51, + .dsc_uuid.u16 = BLE_UUID16_INIT(0x1111), + }, { + .chr_val_handle = 50, + .dsc_handle = 52, + .dsc_uuid.u16 = BLE_UUID16_INIT(0x2222), + }, { + .chr_val_handle = 50, + .dsc_handle = 53, + .dsc_uuid.u16 = BLE_UUID16_INIT(0x3333), + }, { + .chr_val_handle = 50, + .dsc_handle = 54, + .dsc_uuid.u16 = BLE_UUID16_INIT(0x4444), + }, { + .chr_val_handle = 50, + .dsc_handle = 55, + .dsc_uuid.u16 = BLE_UUID16_INIT(0x5555), + }, { + 0 + } }) + ); + + /*** Interleaved 16-bit and 128-bit descriptors. */ + ble_gatt_disc_d_test_misc_all(50, 100, 0, + ((struct ble_gatt_disc_d_test_dsc[]) { { + .chr_val_handle = 50, + .dsc_handle = 51, + .dsc_uuid.u16 = BLE_UUID16_INIT(0x1111), + }, { + .chr_val_handle = 50, + .dsc_handle = 52, + .dsc_uuid.u128 = BLE_UUID128_INIT( 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15), + }, { + .chr_val_handle = 50, + .dsc_handle = 53, + .dsc_uuid.u16 = BLE_UUID16_INIT(0x3333), + }, { + .chr_val_handle = 50, + .dsc_handle = 54, + .dsc_uuid.u128 = BLE_UUID128_INIT(1,0,4,0,6,9,17,7,8,43,7,4,12,43,19,35), + }, { + .chr_val_handle = 50, + .dsc_handle = 55, + .dsc_uuid.u16 = BLE_UUID16_INIT(0x5555), + }, { + 0 + } }) + ); + + /*** Ends with final handle ID. */ + ble_gatt_disc_d_test_misc_all(50, 52, 0, + ((struct ble_gatt_disc_d_test_dsc[]) { { + .chr_val_handle = 50, + .dsc_handle = 51, + .dsc_uuid.u16 = BLE_UUID16_INIT(0x1111), + }, { + .chr_val_handle = 50, + .dsc_handle = 52, + .dsc_uuid.u16 = BLE_UUID16_INIT(0x2222), + }, { + 0 + } }) + ); + + /*** Stop after two descriptors. */ + ble_gatt_disc_d_test_misc_all(50, 100, 2, + ((struct ble_gatt_disc_d_test_dsc[]) { { + .chr_val_handle = 50, + .dsc_handle = 51, + .dsc_uuid.u16 = BLE_UUID16_INIT(0x1111), + }, { + .chr_val_handle = 50, + .dsc_handle = 52, + .dsc_uuid.u16 = BLE_UUID16_INIT(0x2222), + }, { + .chr_val_handle = 50, + .dsc_handle = 53, + .dsc_uuid.u16 = BLE_UUID16_INIT(0x3333), + }, { + .chr_val_handle = 50, + .dsc_handle = 54, + .dsc_uuid.u16 = BLE_UUID16_INIT(0x4444), + }, { + .chr_val_handle = 50, + .dsc_handle = 55, + .dsc_uuid.u16 = BLE_UUID16_INIT(0x5555), + }, { + 0 + } }) + ); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatt_disc_d_test_oom_all) +{ + struct ble_gatt_disc_d_test_dsc dscs[] = { + { + .chr_val_handle = 543, + .dsc_handle = 548, + .dsc_uuid.u128 = BLE_UUID128_INIT(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15), + }, + { + .chr_val_handle = 543, + .dsc_handle = 549, + .dsc_uuid.u128 = BLE_UUID128_INIT(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16), + }, + { 0 } + }; + + struct os_mbuf *oms; + int32_t ticks_until; + int stop_after; + int num_dscs; + int rc; + + ble_gatt_disc_d_test_init(); + + ble_hs_test_util_create_conn(1, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + + /* Initiate a discover all characteristics procedure. */ + stop_after = 0; + rc = ble_gattc_disc_all_dscs(1, 543, 560, + ble_gatt_disc_d_test_misc_cb, &stop_after); + TEST_ASSERT_FATAL(rc == 0); + + /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ + oms = ble_hs_test_util_mbuf_alloc_all_but(1); + num_dscs = ble_gatt_disc_d_test_misc_rx_rsp_once(1, dscs); + + /* Make sure there are still undiscovered services. */ + TEST_ASSERT_FATAL(num_dscs < sizeof dscs / sizeof dscs[0] - 1); + + /* Ensure no follow-up request got sent. It should not have gotten sent + * due to mbuf exhaustion. + */ + ble_hs_test_util_prev_tx_queue_clear(); + TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL); + + /* Verify that we will resume the stalled GATT procedure in one second. */ + ticks_until = ble_gattc_timer(); + TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE))); + + /* Verify the procedure proceeds after mbufs become available. */ + rc = os_mbuf_free_chain(oms); + TEST_ASSERT_FATAL(rc == 0); + os_time_advance(ticks_until); + ble_gattc_timer(); + + /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ + oms = ble_hs_test_util_mbuf_alloc_all_but(1); + ble_gatt_disc_d_test_misc_rx_rsp_once(1, dscs + num_dscs); + + /* Ensure no follow-up request got sent. It should not have gotten sent + * due to mbuf exhaustion. + */ + ble_hs_test_util_prev_tx_queue_clear(); + TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL); + + /* Verify that we will resume the stalled GATT procedure in one second. */ + ticks_until = ble_gattc_timer(); + TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE))); + + /* Verify the procedure succeeds after mbufs become available. */ + rc = os_mbuf_free_chain(oms); + TEST_ASSERT_FATAL(rc == 0); + os_time_advance(ticks_until); + ble_gattc_timer(); + + ble_hs_test_util_rx_att_err_rsp(1, + BLE_ATT_OP_READ_TYPE_REQ, + BLE_ATT_ERR_ATTR_NOT_FOUND, + 1); + ble_gatt_disc_d_test_misc_verify_dscs(dscs, 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_gatt_disc_d_test_suite) +{ + ble_gatt_disc_d_test_1(); + ble_gatt_disc_d_test_oom_all(); +} diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_gatt_disc_s_test.c b/src/libs/mynewt-nimble/nimble/host/test/src/ble_gatt_disc_s_test.c new file mode 100644 index 00000000..3e7a3026 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_gatt_disc_s_test.c @@ -0,0 +1,631 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include "testutil/testutil.h" +#include "nimble/ble.h" +#include "ble_hs_test.h" +#include "host/ble_uuid.h" +#include "ble_hs_test_util.h" + +struct ble_gatt_disc_s_test_svc { + uint16_t start_handle; + uint16_t end_handle; + const ble_uuid_t *uuid; +}; + +#define BLE_GATT_DISC_S_TEST_MAX_SERVICES 256 +static struct ble_gatt_svc + ble_gatt_disc_s_test_svcs[BLE_GATT_DISC_S_TEST_MAX_SERVICES]; +static int ble_gatt_disc_s_test_num_svcs; +static int ble_gatt_disc_s_test_rx_complete; + +static void +ble_gatt_disc_s_test_init(void) +{ + ble_hs_test_util_init(); + ble_gatt_disc_s_test_num_svcs = 0; + ble_gatt_disc_s_test_rx_complete = 0; +} + +static int +ble_gatt_disc_s_test_misc_svc_length(struct ble_gatt_disc_s_test_svc *service) +{ + if (service->uuid->type == BLE_UUID_TYPE_16) { + return 6; + } else { + return 20; + } +} + +static int +ble_gatt_disc_s_test_misc_rx_all_rsp_once( + uint16_t conn_handle, struct ble_gatt_disc_s_test_svc *services) +{ + struct ble_att_read_group_type_rsp rsp; + uint8_t buf[1024]; + int off; + int rc; + int i; + + /* Send the pending ATT Read By Group Type Request. */ + + rsp.bagp_length = ble_gatt_disc_s_test_misc_svc_length(services); + ble_att_read_group_type_rsp_write(buf, BLE_ATT_READ_GROUP_TYPE_RSP_BASE_SZ, + &rsp); + + off = BLE_ATT_READ_GROUP_TYPE_RSP_BASE_SZ; + for (i = 0; ; i++) { + if (services[i].start_handle == 0) { + /* No more services. */ + break; + } + + rc = ble_gatt_disc_s_test_misc_svc_length(services + i); + if (rc != rsp.bagp_length) { + /* UUID length is changing; Need a separate response. */ + break; + } + + if (services[i].uuid->type == BLE_UUID_TYPE_16) { + if (off + BLE_ATT_READ_GROUP_TYPE_ADATA_SZ_16 > + ble_att_mtu(conn_handle)) { + + /* Can't fit any more entries. */ + break; + } + } else { + if (off + BLE_ATT_READ_GROUP_TYPE_ADATA_SZ_128 > + ble_att_mtu(conn_handle)) { + + /* Can't fit any more entries. */ + break; + } + } + + put_le16(buf + off, services[i].start_handle); + off += 2; + + put_le16(buf + off, services[i].end_handle); + off += 2; + + ble_uuid_flat(services[i].uuid, buf + off); + off += ble_uuid_length(services[i].uuid); + } + + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, off); + TEST_ASSERT(rc == 0); + + return i; +} + +static void +ble_gatt_disc_s_test_misc_rx_all_rsp( + uint16_t conn_handle, struct ble_gatt_disc_s_test_svc *services) +{ + int count; + int idx; + + idx = 0; + while (services[idx].start_handle != 0) { + count = ble_gatt_disc_s_test_misc_rx_all_rsp_once(conn_handle, + services + idx); + idx += count; + } + + if (services[idx - 1].end_handle != 0xffff) { + /* Send the pending ATT Request. */ + ble_hs_test_util_rx_att_err_rsp(conn_handle, + BLE_ATT_OP_READ_GROUP_TYPE_REQ, + BLE_ATT_ERR_ATTR_NOT_FOUND, + services[idx - 1].start_handle); + } +} + +static int +ble_gatt_disc_s_test_misc_rx_uuid_rsp_once( + uint16_t conn_handle, struct ble_gatt_disc_s_test_svc *services) +{ + uint8_t buf[1024]; + int off; + int rc; + int i; + + /* Send the pending ATT Find By Type Value Request. */ + + buf[0] = BLE_ATT_OP_FIND_TYPE_VALUE_RSP; + off = BLE_ATT_FIND_TYPE_VALUE_RSP_BASE_SZ; + for (i = 0; ; i++) { + if (services[i].start_handle == 0) { + /* No more services. */ + break; + } + + if (off + BLE_ATT_FIND_TYPE_VALUE_HINFO_BASE_SZ > + ble_att_mtu(conn_handle)) { + + /* Can't fit any more entries. */ + break; + } + + put_le16(buf + off, services[i].start_handle); + off += 2; + + put_le16(buf + off, services[i].end_handle); + off += 2; + } + + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, off); + TEST_ASSERT(rc == 0); + + return i; +} + +static void +ble_gatt_disc_s_test_misc_rx_uuid_rsp( + uint16_t conn_handle, struct ble_gatt_disc_s_test_svc *services) +{ + int count; + int idx; + + idx = 0; + while (services[idx].start_handle != 0) { + count = ble_gatt_disc_s_test_misc_rx_uuid_rsp_once(conn_handle, + services + idx); + idx += count; + } + + if (services[idx - 1].end_handle != 0xffff) { + /* Send the pending ATT Request. */ + ble_hs_test_util_rx_att_err_rsp(conn_handle, + BLE_ATT_OP_FIND_TYPE_VALUE_REQ, + BLE_ATT_ERR_ATTR_NOT_FOUND, + services[idx - 1].start_handle); + } +} + +static void +ble_gatt_disc_s_test_misc_verify_services( + struct ble_gatt_disc_s_test_svc *services) +{ + int i; + + for (i = 0; services[i].start_handle != 0; i++) { + TEST_ASSERT(services[i].start_handle == + ble_gatt_disc_s_test_svcs[i].start_handle); + TEST_ASSERT(services[i].end_handle == + ble_gatt_disc_s_test_svcs[i].end_handle); + + TEST_ASSERT(ble_uuid_cmp(services[i].uuid, + &ble_gatt_disc_s_test_svcs[i].uuid.u) == 0); + } + + TEST_ASSERT(i == ble_gatt_disc_s_test_num_svcs); + TEST_ASSERT(ble_gatt_disc_s_test_rx_complete); +} + +static int +ble_gatt_disc_s_test_misc_disc_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_svc *service, + void *arg) +{ + TEST_ASSERT(error != NULL); + TEST_ASSERT(!ble_gatt_disc_s_test_rx_complete); + + switch (error->status) { + case 0: + TEST_ASSERT(service != NULL); + TEST_ASSERT_FATAL(ble_gatt_disc_s_test_num_svcs < + BLE_GATT_DISC_S_TEST_MAX_SERVICES); + ble_gatt_disc_s_test_svcs[ble_gatt_disc_s_test_num_svcs++] = *service; + break; + + case BLE_HS_EDONE: + TEST_ASSERT(service == NULL); + ble_gatt_disc_s_test_rx_complete = 1; + break; + + case BLE_HS_ETIMEOUT: + ble_gatt_disc_s_test_rx_complete = 1; + break; + + default: + TEST_ASSERT(0); + } + + return 0; +} + +static void +ble_gatt_disc_s_test_misc_good_all(struct ble_gatt_disc_s_test_svc *services) +{ + int rc; + + ble_gatt_disc_s_test_init(); + + ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + + rc = ble_gattc_disc_all_svcs(2, ble_gatt_disc_s_test_misc_disc_cb, NULL); + TEST_ASSERT(rc == 0); + + ble_gatt_disc_s_test_misc_rx_all_rsp(2, services); + ble_gatt_disc_s_test_misc_verify_services(services); +} + +static void +ble_gatt_disc_s_test_misc_good_uuid( + struct ble_gatt_disc_s_test_svc *services) +{ + int rc; + + ble_gatt_disc_s_test_init(); + + ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + + rc = ble_gattc_disc_svc_by_uuid(2, services[0].uuid, + ble_gatt_disc_s_test_misc_disc_cb, NULL); + TEST_ASSERT(rc == 0); + + ble_hs_test_util_verify_tx_disc_svc_uuid(services[0].uuid); + + ble_gatt_disc_s_test_misc_rx_uuid_rsp(2, services); + ble_gatt_disc_s_test_misc_verify_services(services); +} + +TEST_CASE_SELF(ble_gatt_disc_s_test_disc_all) +{ + /*** One 128-bit service. */ + ble_gatt_disc_s_test_misc_good_all((struct ble_gatt_disc_s_test_svc[]) { + { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, + { 0 } + }); + + /*** Two 128-bit services. */ + ble_gatt_disc_s_test_misc_good_all((struct ble_gatt_disc_s_test_svc[]) { + { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, + { 10, 50, BLE_UUID128_DECLARE(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ), }, + { 0 } + }); + + /*** Five 128-bit services. */ + ble_gatt_disc_s_test_misc_good_all((struct ble_gatt_disc_s_test_svc[]) { + { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, + { 10, 50, BLE_UUID128_DECLARE(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ), }, + { 80, 120, BLE_UUID128_DECLARE(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 ), }, + { 123, 678, BLE_UUID128_DECLARE(4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 ), }, + { 751, 999, BLE_UUID128_DECLARE(5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 ), }, + { 0 } + }); + + /*** One 128-bit service, one 16-bit-service. */ + ble_gatt_disc_s_test_misc_good_all((struct ble_gatt_disc_s_test_svc[]) { + { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, + { 6, 7, BLE_UUID16_DECLARE(0x1234) }, + { 0 } + }); + + /*** End with handle 0xffff. */ + ble_gatt_disc_s_test_misc_good_all((struct ble_gatt_disc_s_test_svc[]) { + { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, + { 7, 0xffff,BLE_UUID128_DECLARE(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ), }, + { 0 } + }); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatt_disc_s_test_disc_uuid) +{ + /*** 128-bit service; one entry. */ + ble_gatt_disc_s_test_misc_good_uuid((struct ble_gatt_disc_s_test_svc[]) { + { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, + { 0 } + }); + + /*** 128-bit service; two entries. */ + ble_gatt_disc_s_test_misc_good_uuid((struct ble_gatt_disc_s_test_svc[]) { + { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, + { 8, 43, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, + { 0 } + }); + + /*** 128-bit service; five entries. */ + ble_gatt_disc_s_test_misc_good_uuid((struct ble_gatt_disc_s_test_svc[]) { + { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, + { 8, 43, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, + { 67, 100, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, + { 102, 103, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, + { 262, 900, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, + { 0 } + }); + + /*** 128-bit service; end with handle 0xffff. */ + ble_gatt_disc_s_test_misc_good_uuid((struct ble_gatt_disc_s_test_svc[]) { + { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, + { 7, 0xffff,BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, + { 0 } + }); + + /*** 16-bit service; one entry. */ + ble_gatt_disc_s_test_misc_good_uuid((struct ble_gatt_disc_s_test_svc[]) { + { 1, 5, BLE_UUID16_DECLARE(0x1234) }, + { 0 } + }); + + /*** 16-bit service; two entries. */ + ble_gatt_disc_s_test_misc_good_uuid((struct ble_gatt_disc_s_test_svc[]) { + { 1, 5, BLE_UUID16_DECLARE(0x1234) }, + { 85, 243, BLE_UUID16_DECLARE(0x1234) }, + { 0 } + }); + + /*** 16-bit service; five entries. */ + ble_gatt_disc_s_test_misc_good_uuid((struct ble_gatt_disc_s_test_svc[]) { + { 1, 5, BLE_UUID16_DECLARE(0x1234) }, + { 85, 243, BLE_UUID16_DECLARE(0x1234) }, + { 382, 383, BLE_UUID16_DECLARE(0x1234) }, + { 562, 898, BLE_UUID16_DECLARE(0x1234) }, + { 902, 984, BLE_UUID16_DECLARE(0x1234) }, + { 0 } + }); + + /*** 16-bit service; end with handle 0xffff. */ + ble_gatt_disc_s_test_misc_good_uuid((struct ble_gatt_disc_s_test_svc[]) { + { 1, 5, BLE_UUID16_DECLARE(0x1234) }, + { 9, 0xffff,BLE_UUID16_DECLARE(0x1234) }, + { 0 } + }); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatt_disc_s_test_oom_all) +{ + struct ble_gatt_disc_s_test_svc svcs[] = { + { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, + { 6, 10, BLE_UUID128_DECLARE(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ), }, + { 0 }, + }; + + struct os_mbuf *oms; + int32_t ticks_until; + int num_svcs; + int rc; + + ble_gatt_disc_s_test_init(); + + ble_hs_test_util_create_conn(1, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + + /* Initiate a discover all services procedure. */ + rc = ble_gattc_disc_all_svcs(1, ble_gatt_disc_s_test_misc_disc_cb, NULL); + TEST_ASSERT_FATAL(rc == 0); + + /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ + oms = ble_hs_test_util_mbuf_alloc_all_but(1); + num_svcs = ble_gatt_disc_s_test_misc_rx_all_rsp_once(1, svcs); + + /* Make sure there are still undiscovered services. */ + TEST_ASSERT_FATAL(num_svcs < sizeof svcs / sizeof svcs[0] - 1); + + /* Ensure no follow-up request got sent. It should not have gotten sent + * due to mbuf exhaustion. + */ + ble_hs_test_util_prev_tx_queue_clear(); + TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL); + + /* Verify that we will resume the stalled GATT procedure in one second. */ + ticks_until = ble_gattc_timer(); + TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE))); + + /* Verify the procedure proceeds after mbufs become available. */ + rc = os_mbuf_free_chain(oms); + TEST_ASSERT_FATAL(rc == 0); + os_time_advance(ticks_until); + ble_gattc_timer(); + + /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ + oms = ble_hs_test_util_mbuf_alloc_all_but(1); + ble_gatt_disc_s_test_misc_rx_all_rsp_once(1, svcs + num_svcs); + + /* Ensure no follow-up request got sent. It should not have gotten sent + * due to mbuf exhaustion. + */ + ble_hs_test_util_prev_tx_queue_clear(); + TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL); + + /* Verify that we will resume the stalled GATT procedure in one second. */ + ticks_until = ble_gattc_timer(); + TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE))); + + rc = os_mbuf_free_chain(oms); + TEST_ASSERT_FATAL(rc == 0); + os_time_advance(ticks_until); + ble_gattc_timer(); + + ble_hs_test_util_rx_att_err_rsp(1, + BLE_ATT_OP_READ_GROUP_TYPE_REQ, + BLE_ATT_ERR_ATTR_NOT_FOUND, + 1); + ble_gatt_disc_s_test_misc_verify_services(svcs); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatt_disc_s_test_oom_uuid) +{ + /* Retrieve enough services to require two transactions. */ + struct ble_gatt_disc_s_test_svc svcs[] = { + { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, + { 6, 10, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, + { 11, 15, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, + { 16, 20, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, + { 21, 25, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, + { 26, 30, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, + { 0 }, + }; + + struct os_mbuf *oms; + int32_t ticks_until; + int num_svcs; + int rc; + + ble_gatt_disc_s_test_init(); + + ble_hs_test_util_create_conn(1, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + + /* Initiate a discover all services procedure. */ + rc = ble_gattc_disc_svc_by_uuid(1, svcs[0].uuid, + ble_gatt_disc_s_test_misc_disc_cb, NULL); + TEST_ASSERT_FATAL(rc == 0); + + /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ + oms = ble_hs_test_util_mbuf_alloc_all_but(1); + num_svcs = ble_gatt_disc_s_test_misc_rx_uuid_rsp_once(1, svcs); + + /* Make sure there are still undiscovered services. */ + TEST_ASSERT_FATAL(num_svcs < sizeof svcs / sizeof svcs[0] - 1); + + /* Ensure no follow-up request got sent. It should not have gotten sent + * due to mbuf exhaustion. + */ + ble_hs_test_util_prev_tx_queue_clear(); + TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL); + + /* Verify that we will resume the stalled GATT procedure in one second. */ + ticks_until = ble_gattc_timer(); + TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE))); + + /* Verify the procedure proceeds after mbufs become available. */ + rc = os_mbuf_free_chain(oms); + TEST_ASSERT_FATAL(rc == 0); + os_time_advance(ticks_until); + ble_gattc_timer(); + + /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ + oms = ble_hs_test_util_mbuf_alloc_all_but(1); + ble_gatt_disc_s_test_misc_rx_uuid_rsp_once(1, svcs + num_svcs); + + /* Ensure no follow-up request got sent. It should not have gotten sent + * due to mbuf exhaustion. + */ + ble_hs_test_util_prev_tx_queue_clear(); + TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL); + + /* Verify that we will resume the stalled GATT procedure in one second. */ + ticks_until = ble_gattc_timer(); + TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE))); + + /* Verify that procedure completes when mbufs are available. */ + rc = os_mbuf_free_chain(oms); + TEST_ASSERT_FATAL(rc == 0); + os_time_advance(ticks_until); + ble_gattc_timer(); + + ble_hs_test_util_rx_att_err_rsp(1, + BLE_ATT_OP_READ_GROUP_TYPE_REQ, + BLE_ATT_ERR_ATTR_NOT_FOUND, + 1); + ble_gatt_disc_s_test_misc_verify_services(svcs); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatt_disc_s_test_oom_timeout) +{ + struct ble_gatt_disc_s_test_svc svcs[] = { + { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), }, + { 6, 10, BLE_UUID128_DECLARE(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ), }, + { 0 }, + }; + + struct os_mbuf *oms_temp; + struct os_mbuf *oms; + int32_t ticks_until; + int rc; + int i; + + ble_gatt_disc_s_test_init(); + + ble_hs_test_util_create_conn(1, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + + /* Initiate a discover all services procedure. */ + rc = ble_gattc_disc_all_svcs(1, ble_gatt_disc_s_test_misc_disc_cb, NULL); + TEST_ASSERT_FATAL(rc == 0); + + /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ + oms = ble_hs_test_util_mbuf_alloc_all_but(1); + ble_gatt_disc_s_test_misc_rx_all_rsp_once(1, svcs); + + /* Keep trying to resume for 30 seconds, but never free any mbufs. Verify + * procedure eventually times out. + */ + for (i = 0; i < 30; i++) { + /* Ensure no follow-up request got sent. It should not have gotten + * sent due to mbuf exhaustion. + */ + ble_hs_test_util_prev_tx_queue_clear(); + TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL); + + oms_temp = ble_hs_test_util_mbuf_alloc_all_but(0); + if (oms_temp != NULL) { + os_mbuf_concat(oms, oms_temp); + } + + /* Verify that we will resume the stalled GATT procedure in one + * second. + */ + ticks_until = ble_gattc_timer(); + TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE))); + + os_time_advance(ticks_until); + } + + /* Verify the procedure has timed out. The connection should now be + * in the process of being terminated. XXX: Check this. + */ + ble_hs_test_util_hci_ack_set_disconnect(0); + ble_gattc_timer(); + + ticks_until = ble_gattc_timer(); + TEST_ASSERT(ticks_until == BLE_HS_FOREVER); + TEST_ASSERT(!ble_gattc_any_jobs()); + + rc = os_mbuf_free_chain(oms); + TEST_ASSERT_FATAL(rc == 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_gatt_disc_s_test_suite) +{ + ble_gatt_disc_s_test_disc_all(); + ble_gatt_disc_s_test_disc_uuid(); + ble_gatt_disc_s_test_oom_all(); + ble_gatt_disc_s_test_oom_uuid(); + ble_gatt_disc_s_test_oom_timeout(); +} diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_gatt_find_s_test.c b/src/libs/mynewt-nimble/nimble/host/test/src/ble_gatt_find_s_test.c new file mode 100644 index 00000000..172bdd33 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_gatt_find_s_test.c @@ -0,0 +1,433 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include "testutil/testutil.h" +#include "nimble/ble.h" +#include "ble_hs_test.h" +#include "host/ble_uuid.h" +#include "ble_hs_test_util.h" + +static struct ble_gatt_svc ble_gatt_find_s_test_svcs[256]; +static int ble_gatt_find_s_test_num_svcs; +static int ble_gatt_find_s_test_proc_complete; + +struct ble_gatt_find_s_test_entry { + uint16_t inc_handle; /* 0 indicates no more entries. */ + uint16_t start_handle; + uint16_t end_handle; + const ble_uuid_t *uuid; +}; + +static void +ble_gatt_find_s_test_misc_init(void) +{ + ble_hs_test_util_init(); + ble_gatt_find_s_test_num_svcs = 0; + ble_gatt_find_s_test_proc_complete = 0; +} + +static int +ble_gatt_find_s_test_misc_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_svc *service, + void *arg) +{ + TEST_ASSERT(!ble_gatt_find_s_test_proc_complete); + TEST_ASSERT(error != NULL); + + switch (error->status) { + case 0: + ble_gatt_find_s_test_svcs[ble_gatt_find_s_test_num_svcs++] = *service; + break; + + case BLE_HS_EDONE: + ble_gatt_find_s_test_proc_complete = 1; + break; + + default: + TEST_ASSERT(0); + break; + } + + return 0; +} + +static void +ble_gatt_find_s_test_misc_verify_incs( + struct ble_gatt_find_s_test_entry *entries) +{ + int i; + + for (i = 0; entries[i].inc_handle != 0; i++) { + TEST_ASSERT(ble_gatt_find_s_test_svcs[i].start_handle == + entries[i].start_handle); + TEST_ASSERT(ble_gatt_find_s_test_svcs[i].end_handle == + entries[i].end_handle); + TEST_ASSERT(ble_uuid_cmp(&ble_gatt_find_s_test_svcs[i].uuid.u, + entries[i].uuid) == 0); + } + + TEST_ASSERT(i == ble_gatt_find_s_test_num_svcs); + TEST_ASSERT(ble_gatt_find_s_test_proc_complete); +} + +static int +ble_gatt_find_s_test_misc_rx_read_type( + uint16_t conn_handle, struct ble_gatt_find_s_test_entry *entries) +{ + struct ble_att_read_type_rsp rsp; + uint8_t buf[1024]; + int off; + int rc; + int i; + + memset(&rsp, 0, sizeof rsp); + + off = BLE_ATT_READ_TYPE_RSP_BASE_SZ; + for (i = 0; entries[i].inc_handle != 0; i++) { + if (rsp.batp_length == BLE_GATTS_INC_SVC_LEN_NO_UUID + 2) { + break; + } + + if (entries[i].uuid->type != BLE_UUID_TYPE_16) { + if (rsp.batp_length != 0) { + break; + } + rsp.batp_length = BLE_GATTS_INC_SVC_LEN_NO_UUID + 2; + } else { + rsp.batp_length = BLE_GATTS_INC_SVC_LEN_UUID + 2; + } + + TEST_ASSERT_FATAL(off + rsp.batp_length <= sizeof buf); + + put_le16(buf + off, entries[i].inc_handle); + off += 2; + + put_le16(buf + off, entries[i].start_handle); + off += 2; + + put_le16(buf + off, entries[i].end_handle); + off += 2; + + if (entries[i].uuid->type == BLE_UUID_TYPE_16) { + put_le16(buf + off, ble_uuid_u16(entries[i].uuid)); + off += 2; + } + } + + if (i == 0) { + ble_hs_test_util_rx_att_err_rsp(conn_handle, BLE_ATT_OP_READ_TYPE_REQ, + BLE_ATT_ERR_ATTR_NOT_FOUND, 0); + return 0; + } + + ble_att_read_type_rsp_write(buf + 0, BLE_ATT_READ_TYPE_RSP_BASE_SZ, &rsp); + + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, off); + TEST_ASSERT(rc == 0); + + return i; +} + +static void +ble_gatt_find_s_test_misc_rx_read(uint16_t conn_handle, const ble_uuid_t *uuid) +{ + uint8_t buf[17]; + int rc; + + TEST_ASSERT(uuid->type == BLE_UUID_TYPE_128); + + buf[0] = BLE_ATT_OP_READ_RSP; + ble_uuid_flat(uuid, buf + 1); + + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, 17); + TEST_ASSERT(rc == 0); +} + +static void +ble_gatt_find_s_test_misc_verify_tx_read_type(uint16_t start_handle, + uint16_t end_handle) +{ + struct ble_att_read_type_req req; + struct os_mbuf *om; + uint16_t uuid16; + + om = ble_hs_test_util_prev_tx_dequeue_pullup(); + TEST_ASSERT_FATAL(om != NULL); + + ble_att_read_type_req_parse(om->om_data, om->om_len, &req); + + TEST_ASSERT(req.batq_start_handle == start_handle); + TEST_ASSERT(req.batq_end_handle == end_handle); + TEST_ASSERT(om->om_len == BLE_ATT_READ_TYPE_REQ_BASE_SZ + 2); + uuid16 = get_le16(om->om_data + BLE_ATT_READ_TYPE_REQ_BASE_SZ); + TEST_ASSERT(uuid16 == BLE_ATT_UUID_INCLUDE); +} + +static void +ble_gatt_find_s_test_misc_verify_tx_read(uint16_t handle) +{ + struct ble_att_read_req req; + struct os_mbuf *om; + + om = ble_hs_test_util_prev_tx_dequeue_pullup(); + TEST_ASSERT_FATAL(om != NULL); + + ble_att_read_req_parse(om->om_data, om->om_len, &req); + + TEST_ASSERT(req.barq_handle == handle); + TEST_ASSERT(om->om_len == BLE_ATT_READ_REQ_SZ); +} + +static void +ble_gatt_find_s_test_misc_find_inc(uint16_t conn_handle, + uint16_t start_handle, uint16_t end_handle, + struct ble_gatt_find_s_test_entry *entries) +{ + struct ble_gatt_svc service; + int cur_start; + int num_found; + int idx; + int rc; + int i; + + rc = ble_gattc_find_inc_svcs(conn_handle, start_handle, end_handle, + ble_gatt_find_s_test_misc_cb, &service); + TEST_ASSERT(rc == 0); + + cur_start = start_handle; + idx = 0; + while (1) { + ble_gatt_find_s_test_misc_verify_tx_read_type(cur_start, end_handle); + num_found = ble_gatt_find_s_test_misc_rx_read_type(conn_handle, + entries + idx); + if (num_found == 0) { + break; + } + + if (entries[idx].uuid->type == BLE_UUID_TYPE_128) { + TEST_ASSERT(num_found == 1); + ble_gatt_find_s_test_misc_verify_tx_read( + entries[idx].start_handle); + ble_gatt_find_s_test_misc_rx_read(conn_handle, + entries[idx].uuid); + } + + idx += num_found; + cur_start = entries[idx - 1].inc_handle + 1; + } + TEST_ASSERT(idx == ble_gatt_find_s_test_num_svcs); + TEST_ASSERT(ble_gatt_find_s_test_proc_complete); + + for (i = 0; i < ble_gatt_find_s_test_num_svcs; i++) { + TEST_ASSERT(ble_gatt_find_s_test_svcs[i].start_handle == + entries[i].start_handle); + TEST_ASSERT(ble_gatt_find_s_test_svcs[i].end_handle == + entries[i].end_handle); + TEST_ASSERT(ble_uuid_cmp(&ble_gatt_find_s_test_svcs[i].uuid.u, + entries[i].uuid) == 0); + } +} + +TEST_CASE_SELF(ble_gatt_find_s_test_1) +{ + /* Two 16-bit UUID services; one response. */ + ble_gatt_find_s_test_misc_init(); + ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + ble_gatt_find_s_test_misc_find_inc(2, 5, 10, + ((struct ble_gatt_find_s_test_entry[]) { { + .inc_handle = 6, + .start_handle = 35, + .end_handle = 49, + .uuid = BLE_UUID16_DECLARE(0x5155), + }, { + .inc_handle = 9, + .start_handle = 543, + .end_handle = 870, + .uuid = BLE_UUID16_DECLARE(0x1122), + }, { + 0, + } }) + ); + + /* One 128-bit UUID service; two responses. */ + ble_gatt_find_s_test_misc_init(); + ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + ble_gatt_find_s_test_misc_find_inc(2, 34, 100, + ((struct ble_gatt_find_s_test_entry[]) { { + .inc_handle = 36, + .start_handle = 403, + .end_handle = 859, + .uuid = BLE_UUID128_DECLARE(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16), + }, { + 0, + } }) + ); + + /* Two 128-bit UUID service; four responses. */ + ble_gatt_find_s_test_misc_init(); + ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + ble_gatt_find_s_test_misc_find_inc(2, 34, 100, + ((struct ble_gatt_find_s_test_entry[]) { { + .inc_handle = 36, + .start_handle = 403, + .end_handle = 859, + .uuid = BLE_UUID128_DECLARE(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16), + }, { + .inc_handle = 39, + .start_handle = 900, + .end_handle = 932, + .uuid = BLE_UUID128_DECLARE(2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17), + }, { + 0, + } }) + ); + + /* Two 16-bit UUID; three 128-bit UUID; seven responses. */ + ble_gatt_find_s_test_misc_init(); + ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + ble_gatt_find_s_test_misc_find_inc(2, 1, 100, + ((struct ble_gatt_find_s_test_entry[]) { { + .inc_handle = 36, + .start_handle = 403, + .end_handle = 859, + .uuid = BLE_UUID128_DECLARE(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16), + }, { + .inc_handle = 37, + .start_handle = 35, + .end_handle = 49, + .uuid = BLE_UUID16_DECLARE(0x5155), + }, { + .inc_handle = 38, + .start_handle = 543, + .end_handle = 870, + .uuid = BLE_UUID16_DECLARE(0x1122), + }, { + .inc_handle = 39, + .start_handle = 900, + .end_handle = 932, + .uuid = BLE_UUID128_DECLARE(2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17), + }, { + .inc_handle = 40, + .start_handle = 940, + .end_handle = 950, + .uuid = BLE_UUID128_DECLARE(3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18), + }, { + 0, + } }) + ); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatt_find_s_test_oom) +{ + + struct ble_gatt_find_s_test_entry incs[] = { + { + .inc_handle = 21, + .start_handle = 800, + .end_handle = 899, + .uuid = BLE_UUID128_DECLARE(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15), + }, + { + .inc_handle = 22, + .start_handle = 900, + .end_handle = 999, + .uuid = BLE_UUID128_DECLARE(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16), + }, + { 0 } + }; + + struct os_mbuf *oms; + int32_t ticks_until; + int rc; + + ble_gatt_find_s_test_misc_init(); + + ble_hs_test_util_create_conn(1, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + + /* Initiate a discover all characteristics procedure. */ + rc = ble_gattc_find_inc_svcs(1, 20, 30, + ble_gatt_find_s_test_misc_cb, NULL); + TEST_ASSERT_FATAL(rc == 0); + + /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ + oms = ble_hs_test_util_mbuf_alloc_all_but(1); + ble_gatt_find_s_test_misc_rx_read_type(1, incs); + + /* Ensure no follow-up request got sent. It should not have gotten sent + * due to mbuf exhaustion. + */ + ble_hs_test_util_prev_tx_queue_clear(); + TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL); + + /* Verify that we will resume the stalled GATT procedure in one second. */ + ticks_until = ble_gattc_timer(); + TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE))); + + /* Verify the procedure succeeds after mbufs become available. */ + rc = os_mbuf_free_chain(oms); + TEST_ASSERT_FATAL(rc == 0); + os_time_advance(ticks_until); + ble_gattc_timer(); + + /* We can't cause a memory exhaustion error on the follow up request. The + * GATT client frees the read response immediately before sending the + * follow-up request, so there is always an mbuf available. + */ + /* XXX: Find a way to test this. */ + ble_gatt_find_s_test_misc_rx_read(1, incs[0].uuid); + + /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ + oms = ble_hs_test_util_mbuf_alloc_all_but(1); + ble_gatt_find_s_test_misc_rx_read_type(1, incs + 1); + + /* Verify the procedure succeeds after mbufs become available. */ + rc = os_mbuf_free_chain(oms); + TEST_ASSERT_FATAL(rc == 0); + os_time_advance(ticks_until); + ble_gattc_timer(); + + ble_gatt_find_s_test_misc_rx_read(1, incs[1].uuid); + + ble_hs_test_util_rx_att_err_rsp(1, + BLE_ATT_OP_READ_TYPE_REQ, + BLE_ATT_ERR_ATTR_NOT_FOUND, + 1); + + ble_gatt_find_s_test_misc_verify_incs(incs); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_gatt_find_s_test_suite) +{ + ble_gatt_find_s_test_1(); + ble_gatt_find_s_test_oom(); +} diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_gatt_read_test.c b/src/libs/mynewt-nimble/nimble/host/test/src/ble_gatt_read_test.c new file mode 100644 index 00000000..572b0bf1 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_gatt_read_test.c @@ -0,0 +1,923 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include "testutil/testutil.h" +#include "nimble/ble.h" +#include "ble_hs_test.h" +#include "host/ble_uuid.h" +#include "ble_hs_test_util.h" + +struct ble_gatt_read_test_attr { + uint16_t conn_handle; + uint16_t handle; + uint8_t value_len; + uint8_t value[BLE_ATT_ATTR_MAX_LEN]; +}; + +#define BLE_GATT_READ_TEST_MAX_ATTRS 256 + +struct ble_gatt_read_test_attr + ble_gatt_read_test_attrs[BLE_GATT_READ_TEST_MAX_ATTRS]; +int ble_gatt_read_test_num_attrs; +int ble_gatt_read_test_complete; + +uint16_t ble_gatt_read_test_bad_conn_handle; +int ble_gatt_read_test_bad_status; + +static void +ble_gatt_read_test_misc_init(void) +{ + ble_hs_test_util_init(); + ble_gatt_read_test_num_attrs = 0; + ble_gatt_read_test_complete = 0; + ble_gatt_read_test_bad_conn_handle = 0; + ble_gatt_read_test_bad_status = 0; + + memset(&ble_gatt_read_test_attrs[0], 0, + sizeof ble_gatt_read_test_attrs[0]); +} + +static int +ble_gatt_read_test_cb(uint16_t conn_handle, const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, void *arg) +{ + struct ble_gatt_read_test_attr *dst; + int *stop_after; + int rc; + + stop_after = arg; + + TEST_ASSERT_FATAL(error != NULL); + + if (error->status != 0) { + ble_gatt_read_test_bad_conn_handle = conn_handle; + ble_gatt_read_test_bad_status = error->status; + ble_gatt_read_test_complete = 1; + return 0; + } + + if (attr == NULL) { + ble_gatt_read_test_complete = 1; + return 0; + } + + TEST_ASSERT_FATAL(ble_gatt_read_test_num_attrs < + BLE_GATT_READ_TEST_MAX_ATTRS); + dst = ble_gatt_read_test_attrs + ble_gatt_read_test_num_attrs++; + + TEST_ASSERT_FATAL(OS_MBUF_PKTLEN(attr->om) <= sizeof dst->value); + + dst->conn_handle = conn_handle; + dst->handle = attr->handle; + dst->value_len = OS_MBUF_PKTLEN(attr->om); + rc = os_mbuf_copydata(attr->om, 0, OS_MBUF_PKTLEN(attr->om), dst->value); + TEST_ASSERT_FATAL(rc == 0); + + if (stop_after != NULL && *stop_after > 0) { + (*stop_after)--; + if (*stop_after == 0) { + ble_gatt_read_test_complete = 1; + return 1; + } + } else { + ble_gatt_read_test_complete = 1; + } + + return 0; +} + +static int +ble_gatt_read_test_long_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, void *arg) +{ + struct ble_gatt_read_test_attr *dst; + int *reads_left; + int rc; + + reads_left = arg; + + TEST_ASSERT_FATAL(error != NULL); + + if (error->status != 0) { + ble_gatt_read_test_bad_conn_handle = conn_handle; + ble_gatt_read_test_bad_status = error->status; + ble_gatt_read_test_complete = 1; + return 0; + } + + if (attr == NULL) { + ble_gatt_read_test_complete = 1; + return 0; + } + + dst = ble_gatt_read_test_attrs + 0; + + TEST_ASSERT_FATAL(OS_MBUF_PKTLEN(attr->om) <= + dst->value_len + sizeof dst->value); + TEST_ASSERT(attr->offset == dst->value_len); + + if (attr->offset == 0) { + dst->conn_handle = conn_handle; + dst->handle = attr->handle; + } else { + TEST_ASSERT(conn_handle == dst->conn_handle); + TEST_ASSERT(attr->handle == dst->handle); + } + rc = os_mbuf_copydata(attr->om, 0, OS_MBUF_PKTLEN(attr->om), + dst->value + dst->value_len); + TEST_ASSERT_FATAL(rc == 0); + dst->value_len += OS_MBUF_PKTLEN(attr->om); + + if (reads_left != NULL && *reads_left > 0) { + (*reads_left)--; + if (*reads_left == 0) { + ble_gatt_read_test_complete = 1; + return 1; + } + } + + return 0; +} + +static void +ble_gatt_read_test_misc_rx_rsp_good_raw(uint16_t conn_handle, + uint8_t att_op, + const void *data, int data_len) +{ + uint8_t buf[1024]; + int rc; + + TEST_ASSERT_FATAL(data_len <= sizeof buf); + + /* Send the pending ATT Read Request. */ + + buf[0] = att_op; + memcpy(buf + 1, data, data_len); + + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, 1 + data_len); + TEST_ASSERT(rc == 0); +} + +static void +ble_gatt_read_test_misc_rx_rsp_good(uint16_t conn_handle, + struct ble_hs_test_util_flat_attr *attr) +{ + ble_gatt_read_test_misc_rx_rsp_good_raw(conn_handle, BLE_ATT_OP_READ_RSP, + attr->value, + attr->value_len); +} + +static void +ble_gatt_read_test_misc_rx_rsp_bad(uint16_t conn_handle, + uint8_t att_error, uint16_t err_handle) +{ + /* Send the pending ATT Read Request. */ + + ble_hs_test_util_rx_att_err_rsp(conn_handle, BLE_ATT_OP_READ_REQ, + att_error, err_handle); +} + +static int +ble_gatt_read_test_misc_uuid_rx_rsp_good( + uint16_t conn_handle, struct ble_hs_test_util_flat_attr *attrs) +{ + struct ble_att_read_type_rsp rsp; + uint8_t buf[1024]; + int prev_len; + int off; + int rc; + int i; + + if (ble_gatt_read_test_complete || attrs[0].handle == 0) { + return 0; + } + + /* Send the pending ATT Read By Type Request. */ + + rsp.batp_length = 2 + attrs[0].value_len; + ble_att_read_type_rsp_write(buf, sizeof buf, &rsp); + + prev_len = 0; + off = BLE_ATT_READ_TYPE_RSP_BASE_SZ; + for (i = 0; attrs[i].handle != 0; i++) { + if (prev_len != 0 && prev_len != attrs[i].value_len) { + break; + } + prev_len = attrs[i].value_len; + + put_le16(buf + off, attrs[i].handle); + off += 2; + + memcpy(buf + off, attrs[i].value, attrs[i].value_len); + off += attrs[i].value_len; + } + + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, off); + TEST_ASSERT(rc == 0); + + return i; +} + +static void +ble_gatt_read_test_misc_verify_good(struct ble_hs_test_util_flat_attr *attr) +{ + int rc; + + ble_gatt_read_test_misc_init(); + ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + + /* Exchange MTU: We need plus 1 for the read response opcode */ + ble_hs_test_util_set_att_mtu(2, attr->value_len + 1); + + rc = ble_gattc_read(2, attr->handle, ble_gatt_read_test_cb, NULL); + TEST_ASSERT_FATAL(rc == 0); + + ble_gatt_read_test_misc_rx_rsp_good(2, attr); + + TEST_ASSERT(ble_gatt_read_test_num_attrs == 1); + TEST_ASSERT(ble_gatt_read_test_attrs[0].conn_handle == 2); + TEST_ASSERT(ble_gatt_read_test_attrs[0].handle == attr->handle); + TEST_ASSERT(ble_gatt_read_test_attrs[0].value_len == attr->value_len); + TEST_ASSERT(memcmp(ble_gatt_read_test_attrs[0].value, attr->value, + attr->value_len) == 0); +} + +static void +ble_gatt_read_test_misc_verify_bad(uint8_t att_status, + struct ble_hs_test_util_flat_attr *attr) +{ + int rc; + + ble_gatt_read_test_misc_init(); + ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + + rc = ble_gattc_read(2, attr->handle, ble_gatt_read_test_cb, NULL); + TEST_ASSERT_FATAL(rc == 0); + + ble_gatt_read_test_misc_rx_rsp_bad(2, att_status, attr->handle); + + TEST_ASSERT(ble_gatt_read_test_num_attrs == 0); + TEST_ASSERT(ble_gatt_read_test_bad_conn_handle == 2); + TEST_ASSERT(ble_gatt_read_test_bad_status == + BLE_HS_ERR_ATT_BASE + att_status); + TEST_ASSERT(!ble_gattc_any_jobs()); +} + +static void +ble_gatt_read_test_misc_uuid_verify_good( + uint16_t start_handle, uint16_t end_handle, const ble_uuid_t *uuid, + int stop_after, struct ble_hs_test_util_flat_attr *attrs) +{ + int num_read; + int idx; + int rc; + int i; + + ble_gatt_read_test_misc_init(); + ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + + rc = ble_gattc_read_by_uuid(2, start_handle, end_handle, uuid, + ble_gatt_read_test_cb, &stop_after); + TEST_ASSERT_FATAL(rc == 0); + + idx = 0; + while (1) { + num_read = ble_gatt_read_test_misc_uuid_rx_rsp_good(2, attrs + idx); + if (num_read == 0) { + ble_hs_test_util_rx_att_err_rsp(2, BLE_ATT_OP_READ_TYPE_REQ, + BLE_ATT_ERR_ATTR_NOT_FOUND, + start_handle); + break; + } + + idx += num_read; + } + + TEST_ASSERT(ble_gatt_read_test_complete); + TEST_ASSERT(idx == ble_gatt_read_test_num_attrs); + + for (i = 0; i < idx; i++) { + TEST_ASSERT(ble_gatt_read_test_attrs[i].conn_handle == 2); + TEST_ASSERT(ble_gatt_read_test_attrs[i].handle == attrs[i].handle); + TEST_ASSERT(ble_gatt_read_test_attrs[i].value_len == + attrs[i].value_len); + TEST_ASSERT(memcmp(ble_gatt_read_test_attrs[i].value, attrs[i].value, + attrs[i].value_len) == 0); + } + TEST_ASSERT(!ble_gattc_any_jobs()); +} + +static void +ble_gatt_read_test_misc_long_verify_good( + int max_reads, struct ble_hs_test_util_flat_attr *attr) +{ + int reads_left; + int chunk_sz; + int rem_len; + int att_op; + uint16_t offset = 0; + int off; + int rc; + + ble_gatt_read_test_misc_init(); + ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + + if (max_reads == 0) { + max_reads = INT_MAX; + } + reads_left = max_reads; + rc = ble_gattc_read_long(2, attr->handle, offset, + ble_gatt_read_test_long_cb, &reads_left); + TEST_ASSERT_FATAL(rc == 0); + + off = 0; + rem_len = attr->value_len; + do { + if (rem_len > BLE_ATT_MTU_DFLT - 1) { + chunk_sz = BLE_ATT_MTU_DFLT - 1; + } else { + chunk_sz = rem_len; + } + if (off == 0) { + att_op = BLE_ATT_OP_READ_RSP; + } else { + att_op = BLE_ATT_OP_READ_BLOB_RSP; + } + ble_gatt_read_test_misc_rx_rsp_good_raw(2, att_op, + attr->value + off, chunk_sz); + rem_len -= chunk_sz; + off += chunk_sz; + } while (rem_len > 0 && reads_left > 0); + + TEST_ASSERT(ble_gatt_read_test_complete); + TEST_ASSERT(!ble_gattc_any_jobs()); + TEST_ASSERT(ble_gatt_read_test_attrs[0].conn_handle == 2); + TEST_ASSERT(ble_gatt_read_test_attrs[0].handle == attr->handle); + if (reads_left > 0) { + TEST_ASSERT(ble_gatt_read_test_attrs[0].value_len == attr->value_len); + } + TEST_ASSERT(memcmp(ble_gatt_read_test_attrs[0].value, attr->value, + ble_gatt_read_test_attrs[0].value_len) == 0); +} + +static void +ble_gatt_read_test_misc_long_verify_bad( + uint8_t att_status, struct ble_hs_test_util_flat_attr *attr) +{ + uint16_t offset = 0; + int rc; + + ble_gatt_read_test_misc_init(); + ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + + rc = ble_gattc_read_long(2, attr->handle, offset, + ble_gatt_read_test_long_cb, NULL); + TEST_ASSERT_FATAL(rc == 0); + + ble_gatt_read_test_misc_rx_rsp_bad(2, att_status, attr->handle); + + TEST_ASSERT(ble_gatt_read_test_num_attrs == 0); + TEST_ASSERT(ble_gatt_read_test_bad_conn_handle == 2); + TEST_ASSERT(ble_gatt_read_test_bad_status == + BLE_HS_ERR_ATT_BASE + att_status); + TEST_ASSERT(!ble_gattc_any_jobs()); +} + +static int +ble_gatt_read_test_misc_extract_handles( + struct ble_hs_test_util_flat_attr *attrs, uint16_t *handles) +{ + int i; + + for (i = 0; attrs[i].handle != 0; i++) { + handles[i] = attrs[i].handle; + } + return i; +} + +static void +ble_gatt_read_test_misc_mult_verify_good( + struct ble_hs_test_util_flat_attr *attrs) +{ + uint8_t expected_value[512]; + uint16_t handles[256]; + int num_attrs; + int chunk_sz; + int off; + int rc; + int i; + + ble_gatt_read_test_misc_init(); + ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + + num_attrs = ble_gatt_read_test_misc_extract_handles(attrs, handles); + + off = 0; + for (i = 0; i < num_attrs; i++) { + if (attrs[i].value_len > BLE_ATT_MTU_DFLT - 1 - off) { + chunk_sz = BLE_ATT_MTU_DFLT - 1 - off; + } else { + chunk_sz = attrs[i].value_len; + } + + if (chunk_sz > 0) { + memcpy(expected_value + off, attrs[i].value, chunk_sz); + off += chunk_sz; + } + } + + rc = ble_gattc_read_mult(2, handles, num_attrs, + ble_gatt_read_test_cb, NULL); + TEST_ASSERT_FATAL(rc == 0); + + ble_gatt_read_test_misc_rx_rsp_good_raw(2, BLE_ATT_OP_READ_MULT_RSP, + expected_value, off); + + TEST_ASSERT(ble_gatt_read_test_complete); + TEST_ASSERT(!ble_gattc_any_jobs()); + TEST_ASSERT(ble_gatt_read_test_attrs[0].conn_handle == 2); + TEST_ASSERT(ble_gatt_read_test_attrs[0].value_len == off); + TEST_ASSERT(memcmp(ble_gatt_read_test_attrs[0].value, expected_value, + off) == 0); +} + +static void +ble_gatt_read_test_misc_mult_verify_bad( + uint8_t att_status, uint16_t err_handle, + struct ble_hs_test_util_flat_attr *attrs) +{ + uint16_t handles[256]; + int num_attrs; + int rc; + + ble_gatt_read_test_misc_init(); + ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + + num_attrs = ble_gatt_read_test_misc_extract_handles(attrs, handles); + + rc = ble_gattc_read_mult(2, handles, num_attrs, + ble_gatt_read_test_cb, NULL); + TEST_ASSERT_FATAL(rc == 0); + + ble_gatt_read_test_misc_rx_rsp_bad(2, att_status, err_handle); + + TEST_ASSERT(ble_gatt_read_test_num_attrs == 0); + TEST_ASSERT(ble_gatt_read_test_bad_conn_handle == 2); + TEST_ASSERT(ble_gatt_read_test_bad_status == + BLE_HS_ERR_ATT_BASE + att_status); + TEST_ASSERT(!ble_gattc_any_jobs()); +} + +TEST_CASE_SELF(ble_gatt_read_test_by_handle) +{ + /* Read a seven-byte attribute. */ + ble_gatt_read_test_misc_verify_good( + (struct ble_hs_test_util_flat_attr[]) { { + .handle = 43, + .value = { 1,2,3,4,5,6,7 }, + .value_len = 7 + } }); + + /* Read a one-byte attribute. */ + ble_gatt_read_test_misc_verify_good( + (struct ble_hs_test_util_flat_attr[]) { { + .handle = 0x5432, + .value = { 0xff }, + .value_len = 1 + } }); + + /* Read a 200-byte attribute. */ + ble_gatt_read_test_misc_verify_good( + (struct ble_hs_test_util_flat_attr[]) { { + .handle = 815, + .value = { 0 }, + .value_len = 200, + } }); + + /* Fail due to attribute not found. */ + ble_gatt_read_test_misc_verify_bad(BLE_ATT_ERR_ATTR_NOT_FOUND, + (struct ble_hs_test_util_flat_attr[]) { { + .handle = 719, + .value = { 1,2,3,4,5,6,7 }, + .value_len = 7 + } }); + + /* Fail due to invalid PDU. */ + ble_gatt_read_test_misc_verify_bad(BLE_ATT_ERR_INVALID_PDU, + (struct ble_hs_test_util_flat_attr[]) { { + .handle = 65, + .value = { 0xfa, 0x4c }, + .value_len = 2 + } }); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatt_read_test_by_uuid) +{ + /* Read a single seven-byte attribute. */ + ble_gatt_read_test_misc_uuid_verify_good(1, 100, BLE_UUID16_DECLARE(0x1234), 0, + (struct ble_hs_test_util_flat_attr[]) { { + .handle = 43, + .value = { 1,2,3,4,5,6,7 }, + .value_len = 7 + }, { + 0, + } }); + + /* Read two seven-byte attributes; one response. */ + ble_gatt_read_test_misc_uuid_verify_good(1, 100, BLE_UUID16_DECLARE(0x1234), 0, + (struct ble_hs_test_util_flat_attr[]) { { + .handle = 43, + .value = { 1,2,3,4,5,6,7 }, + .value_len = 7 + }, { + .handle = 44, + .value = { 2,3,4,5,6,7,8 }, + .value_len = 7 + }, { + 0, + } }); + + /* Read two attributes; two responses. */ + ble_gatt_read_test_misc_uuid_verify_good(1, 100, BLE_UUID16_DECLARE(0x1234), 0, + (struct ble_hs_test_util_flat_attr[]) { { + .handle = 43, + .value = { 1,2,3,4,5,6,7 }, + .value_len = 7 + }, { + .handle = 44, + .value = { 2,3,4 }, + .value_len = 3 + }, { + 0, + } }); + + /* Stop after three reads. */ + ble_gatt_read_test_misc_uuid_verify_good(1, 100, BLE_UUID16_DECLARE(0x1234), 3, + (struct ble_hs_test_util_flat_attr[]) { { + .handle = 43, + .value = { 1,2,3,4,5,6,7 }, + .value_len = 7 + }, { + .handle = 44, + .value = { 2,3,4 }, + .value_len = 3 + }, { + .handle = 45, + .value = { 2,3,4 }, + .value_len = 3 + }, { + .handle = 46, + .value = { 3,4,5,6 }, + .value_len = 4 + }, { + .handle = 47, + .value = { 2,3,4 }, + .value_len = 3 + }, { + 0, + } }); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatt_read_test_long) +{ + uint8_t data512[512]; + int i; + + for (i = 0; i < sizeof data512; i++) { + data512[i] = i; + } + + /* Read a seven-byte attribute. */ + ble_gatt_read_test_misc_long_verify_good(0, + (struct ble_hs_test_util_flat_attr[]) { { + .handle = 43, + .value = { 1,2,3,4,5,6,7 }, + .value_len = 7 + } }); + + /* Read a zero-byte attribute. */ + ble_gatt_read_test_misc_long_verify_good(0, + (struct ble_hs_test_util_flat_attr[]) { { + .handle = 43, + .value = { 0 }, + .value_len = 0 + } }); + + /* Read a 60-byte attribute; three requests. */ + ble_gatt_read_test_misc_long_verify_good(0, + (struct ble_hs_test_util_flat_attr[]) { { + .handle = 34, + .value = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60 + }, + .value_len = 60 + } }); + + /* Stop after two reads. */ + ble_gatt_read_test_misc_long_verify_good(2, + (struct ble_hs_test_util_flat_attr[]) { { + .handle = 34, + .value = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60 + }, + .value_len = 60 + } }); + + /* Fail due to attribute not found. */ + ble_gatt_read_test_misc_long_verify_bad(BLE_ATT_ERR_ATTR_NOT_FOUND, + (struct ble_hs_test_util_flat_attr[]) { { + .handle = 719, + .value = { 1, 2, 3, 4, 5, 6, 7 }, + .value_len = 7 + } }); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatt_read_test_mult) +{ + uint8_t data512[512]; + int i; + + for (i = 0; i < sizeof data512; i++) { + data512[i] = i; + } + + /* Read one attribute. */ + ble_gatt_read_test_misc_mult_verify_good( + (struct ble_hs_test_util_flat_attr[]) { { + .handle = 43, + .value = { 0, 1, 2, 3, 4, 5, 6, 7 }, + .value_len = 7 + }, { + 0 + } }); + + /* Read two attributes. */ + ble_gatt_read_test_misc_mult_verify_good( + (struct ble_hs_test_util_flat_attr[]) { { + .handle = 43, + .value = { 0, 1, 2, 3, 4, 5, 6, 7 }, + .value_len = 7, + }, { + .handle = 44, + .value = { 8, 9, 10, 11 }, + .value_len = 4, + }, { + 0 + } }); + + /* Read two attributes (swap order). */ + ble_gatt_read_test_misc_mult_verify_good( + (struct ble_hs_test_util_flat_attr[]) { { + .handle = 44, + .value = { 8, 9, 10, 11 }, + .value_len = 4, + }, { + .handle = 43, + .value = { 0, 1, 2, 3, 4, 5, 6, 7 }, + .value_len = 7, + }, { + 0 + } }); + + /* Read five attributes. */ + ble_gatt_read_test_misc_mult_verify_good( + (struct ble_hs_test_util_flat_attr[]) { { + .handle = 43, + .value = { 0, 1, 2, 3, 4, 5, 6, 7 }, + .value_len = 7, + }, { + .handle = 44, + .value = { 8, 9, 10, 11 }, + .value_len = 4, + }, { + .handle = 145, + .value = { 12, 13 }, + .value_len = 2, + }, { + .handle = 191, + .value = { 14, 15, 16 }, + .value_len = 3, + }, { + .handle = 352, + .value = { 17, 18, 19, 20 }, + .value_len = 4, + }, { + 0 + } }); + + /* Fail due to attribute not found. */ + ble_gatt_read_test_misc_mult_verify_bad(BLE_ATT_ERR_ATTR_NOT_FOUND, 719, + (struct ble_hs_test_util_flat_attr[]) { { + .handle = 719, + .value = { 1,2,3,4,5,6,7 }, + .value_len = 7 + }, { + 0 + } }); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatt_read_test_concurrent) +{ + int rc; + int i; + + ble_gatt_read_test_misc_init(); + ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + + /*** + * Perform three concurrent reads. Assert that each response is correctly + * matched up with its corresponding GATT procedure. + */ + + struct ble_hs_test_util_flat_attr attrs[3] = { + { + .handle = 1, + .offset = 0, + .value_len = 3, + .value = { 1, 2, 3 }, + }, + { + .handle = 2, + .offset = 0, + .value_len = 4, + .value = { 2, 3, 4, 5 }, + }, + { + .handle = 3, + .offset = 0, + .value_len = 5, + .value = { 3, 4, 5, 6, 7 }, + }, + }; + + rc = ble_gattc_read(2, attrs[0].handle, ble_gatt_read_test_cb, NULL); + TEST_ASSERT_FATAL(rc == 0); + rc = ble_gattc_read(2, attrs[1].handle, ble_gatt_read_test_cb, NULL); + TEST_ASSERT_FATAL(rc == 0); + rc = ble_gattc_read(2, attrs[2].handle, ble_gatt_read_test_cb, NULL); + TEST_ASSERT_FATAL(rc == 0); + + ble_gatt_read_test_misc_rx_rsp_good(2, attrs + 0); + ble_gatt_read_test_misc_rx_rsp_good(2, attrs + 1); + ble_gatt_read_test_misc_rx_rsp_good(2, attrs + 2); + + TEST_ASSERT(ble_gatt_read_test_num_attrs == 3); + + for (i = 0; i < 3; i++) { + TEST_ASSERT(ble_gatt_read_test_attrs[i].handle == attrs[i].handle); + TEST_ASSERT(ble_gatt_read_test_attrs[i].value_len == + attrs[i].value_len); + TEST_ASSERT(memcmp(ble_gatt_read_test_attrs[i].value, attrs[i].value, + attrs[i].value_len) == 0); + } + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatt_read_test_long_oom) +{ + static const struct ble_hs_test_util_flat_attr attr = { + .handle = 34, + .value = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60 + }, + .value_len = 60, + }; + + struct os_mbuf *oms; + int32_t ticks_until; + int reads_left; + int chunk_sz; + uint16_t offset = 0; + int off; + int rc; + + ble_gatt_read_test_misc_init(); + ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + + /* Initiate a read long procedure. */ + off = 0; + reads_left = 0; + rc = ble_gattc_read_long(2, attr.handle, offset, ble_gatt_read_test_long_cb, + &reads_left); + TEST_ASSERT_FATAL(rc == 0); + + /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ + oms = ble_hs_test_util_mbuf_alloc_all_but(1); + chunk_sz = ble_att_mtu(2) - BLE_ATT_READ_RSP_BASE_SZ; + ble_gatt_read_test_misc_rx_rsp_good_raw(2, BLE_ATT_OP_READ_RSP, + attr.value + off, chunk_sz); + off += chunk_sz; + + /* Ensure no follow-up request got sent. It should not have gotten sent + * due to mbuf exhaustion. + */ + ble_hs_test_util_prev_tx_queue_clear(); + TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL); + + /* Verify that we will resume the stalled GATT procedure in one second. */ + ticks_until = ble_gattc_timer(); + TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE))); + + /* Verify the procedure proceeds after mbufs become available. */ + rc = os_mbuf_free_chain(oms); + TEST_ASSERT_FATAL(rc == 0); + os_time_advance(ticks_until); + ble_gattc_timer(); + + /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ + oms = ble_hs_test_util_mbuf_alloc_all_but(1); + chunk_sz = ble_att_mtu(2) - BLE_ATT_READ_RSP_BASE_SZ; + ble_gatt_read_test_misc_rx_rsp_good_raw(2, BLE_ATT_OP_READ_RSP, + attr.value + off, chunk_sz); + off += chunk_sz; + + /* Ensure no follow-up request got sent. It should not have gotten sent + * due to mbuf exhaustion. + */ + ble_hs_test_util_prev_tx_queue_clear(); + TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL); + + /* Verify that we will resume the stalled GATT procedure in one second. */ + ticks_until = ble_gattc_timer(); + TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE))); + + /* Verify that procedure completes when mbufs are available. */ + rc = os_mbuf_free_chain(oms); + TEST_ASSERT_FATAL(rc == 0); + os_time_advance(ticks_until); + ble_gattc_timer(); + + chunk_sz = attr.value_len - off; + ble_gatt_read_test_misc_rx_rsp_good_raw(2, BLE_ATT_OP_READ_RSP, + attr.value + off, chunk_sz); + off += chunk_sz; + + TEST_ASSERT(ble_gatt_read_test_complete); + TEST_ASSERT(!ble_gattc_any_jobs()); + TEST_ASSERT(ble_gatt_read_test_attrs[0].conn_handle == 2); + TEST_ASSERT(ble_gatt_read_test_attrs[0].handle == attr.handle); + TEST_ASSERT(ble_gatt_read_test_attrs[0].value_len == attr.value_len); + TEST_ASSERT(memcmp(ble_gatt_read_test_attrs[0].value, attr.value, + ble_gatt_read_test_attrs[0].value_len) == 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_gatt_read_test_suite) +{ + ble_gatt_read_test_by_handle(); + ble_gatt_read_test_by_uuid(); + ble_gatt_read_test_long(); + ble_gatt_read_test_mult(); + ble_gatt_read_test_concurrent(); + ble_gatt_read_test_long_oom(); +} diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_gatt_write_test.c b/src/libs/mynewt-nimble/nimble/host/test/src/ble_gatt_write_test.c new file mode 100644 index 00000000..caa8e565 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_gatt_write_test.c @@ -0,0 +1,832 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include "testutil/testutil.h" +#include "nimble/ble.h" +#include "ble_hs_test.h" +#include "host/ble_gatt.h" +#include "ble_hs_test_util.h" + +#define BLE_GATT_WRITE_TEST_MAX_ATTRS 128 + +static int ble_gatt_write_test_cb_called; + +static uint8_t ble_gatt_write_test_attr_value[BLE_ATT_ATTR_MAX_LEN]; +static struct ble_gatt_error ble_gatt_write_test_error; + +static struct ble_hs_test_util_flat_attr +ble_gatt_write_test_attrs[BLE_GATT_WRITE_TEST_MAX_ATTRS]; +static int ble_gatt_write_test_num_attrs; + +static void +ble_gatt_write_test_init(void) +{ + int i; + + ble_hs_test_util_init(); + ble_gatt_write_test_cb_called = 0; + ble_gatt_write_test_num_attrs = 0; + + for (i = 0; i < sizeof ble_gatt_write_test_attr_value; i++) { + ble_gatt_write_test_attr_value[i] = i; + } +} + +static int +ble_gatt_write_test_cb_good(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, void *arg) +{ + int *attr_len; + + attr_len = arg; + + TEST_ASSERT(error != NULL); + TEST_ASSERT(conn_handle == 2); + + ble_gatt_write_test_error = *error; + + if (attr_len != NULL) { + TEST_ASSERT(error->status == 0); + TEST_ASSERT(attr->handle == 100); + } + + ble_gatt_write_test_cb_called = 1; + + return 0; +} + +static void +ble_gatt_write_test_rx_rsp(uint16_t conn_handle) +{ + uint8_t op; + int rc; + + op = BLE_ATT_OP_WRITE_RSP; + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + &op, 1); + TEST_ASSERT(rc == 0); +} + +static void +ble_gatt_write_test_rx_prep_rsp(uint16_t conn_handle, uint16_t attr_handle, + uint16_t offset, + const void *attr_data, uint16_t attr_data_len) +{ + struct ble_att_prep_write_cmd rsp; + uint8_t buf[512]; + int rc; + + rsp.bapc_handle = attr_handle; + rsp.bapc_offset = offset; + ble_att_prep_write_rsp_write(buf, sizeof buf, &rsp); + + memcpy(buf + BLE_ATT_PREP_WRITE_CMD_BASE_SZ, attr_data, attr_data_len); + + rc = ble_hs_test_util_l2cap_rx_payload_flat( + conn_handle, BLE_L2CAP_CID_ATT, buf, + BLE_ATT_PREP_WRITE_CMD_BASE_SZ + attr_data_len); + TEST_ASSERT(rc == 0); +} + +static void +ble_gatt_write_test_rx_exec_rsp(uint16_t conn_handle) +{ + uint8_t op; + int rc; + + op = BLE_ATT_OP_EXEC_WRITE_RSP; + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + &op, 1); + TEST_ASSERT(rc == 0); +} + +static void +ble_gatt_write_test_misc_long_good(int attr_len) +{ + uint16_t mtu; + int off; + int len; + int rc; + + ble_gatt_write_test_init(); + + ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + + mtu = ble_att_mtu(2); + + rc = ble_hs_test_util_gatt_write_long_flat( + 2, 100, ble_gatt_write_test_attr_value, attr_len, + ble_gatt_write_test_cb_good, &attr_len); + TEST_ASSERT(rc == 0); + + off = 0; + while (off < attr_len) { + len = mtu - BLE_ATT_PREP_WRITE_CMD_BASE_SZ; + if (off + len > attr_len) { + len = attr_len - off; + } + + /* Send the pending ATT Prep Write Command. */ + ble_hs_test_util_verify_tx_prep_write( + 100, off, ble_gatt_write_test_attr_value + off, len); + + /* Receive Prep Write response. */ + ble_gatt_write_test_rx_prep_rsp( + 2, 100, off, ble_gatt_write_test_attr_value + off, len); + + /* Verify callback hasn't gotten called. */ + TEST_ASSERT(!ble_gatt_write_test_cb_called); + + off += len; + } + + /* Verify execute write request sent. */ + ble_hs_test_util_verify_tx_exec_write(BLE_ATT_EXEC_WRITE_F_EXECUTE); + + /* Receive Exec Write response. */ + ble_gatt_write_test_rx_exec_rsp(2); + + /* Verify callback got called. */ + TEST_ASSERT(ble_gatt_write_test_cb_called); +} + +typedef void ble_gatt_write_test_long_fail_fn(uint16_t conn_handle, + int off, int len); + +static void +ble_gatt_write_test_misc_long_bad(int attr_len, + ble_gatt_write_test_long_fail_fn *cb) +{ + uint16_t mtu; + int fail_now; + int off; + int len; + int rc; + + ble_gatt_write_test_init(); + + ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + mtu = ble_att_mtu(2); + + rc = ble_hs_test_util_gatt_write_long_flat( + 2, 100, ble_gatt_write_test_attr_value, attr_len, + ble_gatt_write_test_cb_good, NULL); + TEST_ASSERT(rc == 0); + + fail_now = 0; + off = 0; + while (off < attr_len) { + len = mtu - BLE_ATT_PREP_WRITE_CMD_BASE_SZ; + if (off + len > attr_len) { + len = attr_len - off; + } + + /* Send the pending ATT Prep Write Command. */ + ble_hs_test_util_verify_tx_prep_write( + 100, off, ble_gatt_write_test_attr_value + off, len); + + /* Receive Prep Write response. */ + len = BLE_ATT_MTU_DFLT - BLE_ATT_PREP_WRITE_CMD_BASE_SZ; + if (off + len >= attr_len) { + len = attr_len - off; + fail_now = 1; + } + if (!fail_now) { + ble_gatt_write_test_rx_prep_rsp( + 2, 100, off, ble_gatt_write_test_attr_value + off, len); + } else { + cb(2, off, len); + break; + } + + /* Verify callback hasn't gotten called. */ + TEST_ASSERT(!ble_gatt_write_test_cb_called); + + off += len; + } + + /* Verify callback was called. */ + TEST_ASSERT(ble_gatt_write_test_cb_called); + TEST_ASSERT(ble_gatt_write_test_error.status == BLE_HS_EBADDATA); + TEST_ASSERT(ble_gatt_write_test_error.att_handle == 0); +} + +static void +ble_gatt_write_test_misc_long_fail_handle(uint16_t conn_handle, + int off, int len) +{ + ble_gatt_write_test_rx_prep_rsp( + conn_handle, 99, off, ble_gatt_write_test_attr_value + off, + len); +} + +static void +ble_gatt_write_test_misc_long_fail_offset(uint16_t conn_handle, + int off, int len) +{ + ble_gatt_write_test_rx_prep_rsp( + conn_handle, 100, off + 1, ble_gatt_write_test_attr_value + off, + len); +} + +static void +ble_gatt_write_test_misc_long_fail_value(uint16_t conn_handle, + int off, int len) +{ + ble_gatt_write_test_rx_prep_rsp( + conn_handle, 100, off, ble_gatt_write_test_attr_value + off + 1, + len); +} + +static void +ble_gatt_write_test_misc_long_fail_length(uint16_t conn_handle, + int off, int len) +{ + ble_gatt_write_test_rx_prep_rsp( + conn_handle, 100, off, ble_gatt_write_test_attr_value + off, + len - 1); +} + +static int +ble_gatt_write_test_reliable_cb_good(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attrs, + uint8_t num_attrs, void *arg) +{ + int i; + + TEST_ASSERT_FATAL(num_attrs <= BLE_GATT_WRITE_TEST_MAX_ATTRS); + + TEST_ASSERT(conn_handle == 2); + + ble_gatt_write_test_num_attrs = num_attrs; + for (i = 0; i < num_attrs; i++) { + ble_hs_test_util_attr_to_flat(ble_gatt_write_test_attrs + i, + attrs + i); + } + + ble_gatt_write_test_cb_called = 1; + + return 0; +} + +static void +ble_gatt_write_test_misc_reliable_good( + struct ble_hs_test_util_flat_attr *flat_attrs) +{ + const struct ble_hs_test_util_flat_attr *attr; + struct ble_gatt_attr attrs[16]; + uint16_t mtu; + int num_attrs; + int attr_idx; + int len; + int off; + int rc; + int i; + + ble_gatt_write_test_init(); + + for (num_attrs = 0; flat_attrs[num_attrs].handle != 0; num_attrs++) { + TEST_ASSERT_FATAL(num_attrs < sizeof attrs / sizeof attrs[0]); + ble_hs_test_util_attr_from_flat(attrs + num_attrs, + flat_attrs + num_attrs); + } + + ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + mtu = ble_att_mtu(2); + + rc = ble_gattc_write_reliable(2, attrs, num_attrs, + ble_gatt_write_test_reliable_cb_good, NULL); + TEST_ASSERT(rc == 0); + + attr_idx = 0; + off = 0; + while (attr_idx < num_attrs) { + attr = flat_attrs + attr_idx; + + len = mtu - BLE_ATT_PREP_WRITE_CMD_BASE_SZ; + if (off + len > attr->value_len) { + len = attr->value_len - off; + } + + /* Send the pending ATT Prep Write Command. */ + ble_hs_test_util_verify_tx_prep_write(attr->handle, off, + attr->value + off, len); + + /* Receive Prep Write response. */ + ble_gatt_write_test_rx_prep_rsp(2, attr->handle, off, + attr->value + off, len); + + /* Verify callback hasn't gotten called. */ + TEST_ASSERT(!ble_gatt_write_test_cb_called); + + off += len; + if (off >= attr->value_len) { + attr_idx++; + off = 0; + } + } + + /* Verify execute write request sent. */ + ble_hs_test_util_verify_tx_exec_write(BLE_ATT_EXEC_WRITE_F_EXECUTE); + + /* Receive Exec Write response. */ + ble_gatt_write_test_rx_exec_rsp(2); + + /* Verify callback got called. */ + TEST_ASSERT(ble_gatt_write_test_cb_called); + TEST_ASSERT(ble_gatt_write_test_num_attrs == num_attrs); + for (i = 0; i < num_attrs; i++) { + rc = ble_hs_test_util_flat_attr_cmp( + ble_gatt_write_test_attrs + i, flat_attrs + i); + TEST_ASSERT(rc == 0); + } +} + +TEST_CASE_SELF(ble_gatt_write_test_no_rsp) +{ + int attr_len; + int rc; + + ble_gatt_write_test_init(); + + ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + + attr_len = 4; + rc = ble_hs_test_util_gatt_write_no_rsp_flat( + 2, 100, ble_gatt_write_test_attr_value, attr_len); + TEST_ASSERT(rc == 0); + + /* Send the pending ATT Write Command. */ + + /* No response expected; verify callback not called. */ + TEST_ASSERT(!ble_gatt_write_test_cb_called); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatt_write_test_rsp) +{ + int attr_len; + + ble_gatt_write_test_init(); + + ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + + attr_len = 4; + ble_hs_test_util_gatt_write_flat(2, 100, ble_gatt_write_test_attr_value, + attr_len, ble_gatt_write_test_cb_good, + &attr_len); + + /* Send the pending ATT Write Command. */ + + /* Response not received yet; verify callback not called. */ + TEST_ASSERT(!ble_gatt_write_test_cb_called); + + /* Receive write response. */ + ble_gatt_write_test_rx_rsp(2); + + /* Verify callback got called. */ + TEST_ASSERT(ble_gatt_write_test_cb_called); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatt_write_test_long_good) +{ + /*** 1 prep write req/rsp. */ + ble_gatt_write_test_misc_long_good( + BLE_ATT_MTU_DFLT - BLE_ATT_PREP_WRITE_CMD_BASE_SZ); + + /*** 2 prep write reqs/rsps. */ + ble_gatt_write_test_misc_long_good( + BLE_ATT_MTU_DFLT - BLE_ATT_PREP_WRITE_CMD_BASE_SZ + 1); + + /*** Maximum reqs/rsps. */ + ble_gatt_write_test_misc_long_good(BLE_ATT_ATTR_MAX_LEN); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatt_write_test_long_bad_handle) +{ + /*** 1 prep write req/rsp. */ + ble_gatt_write_test_misc_long_bad( + BLE_ATT_MTU_DFLT - BLE_ATT_PREP_WRITE_CMD_BASE_SZ, + ble_gatt_write_test_misc_long_fail_handle); + + /*** 2 prep write reqs/rsps. */ + ble_gatt_write_test_misc_long_bad( + BLE_ATT_MTU_DFLT - BLE_ATT_PREP_WRITE_CMD_BASE_SZ + 1, + ble_gatt_write_test_misc_long_fail_handle); + + /*** Maximum reqs/rsps. */ + ble_gatt_write_test_misc_long_bad( + BLE_ATT_ATTR_MAX_LEN, + ble_gatt_write_test_misc_long_fail_handle); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatt_write_test_long_bad_offset) +{ + /*** 1 prep write req/rsp. */ + ble_gatt_write_test_misc_long_bad( + BLE_ATT_MTU_DFLT - BLE_ATT_PREP_WRITE_CMD_BASE_SZ, + ble_gatt_write_test_misc_long_fail_offset); + + /*** 2 prep write reqs/rsps. */ + ble_gatt_write_test_misc_long_bad( + BLE_ATT_MTU_DFLT - BLE_ATT_PREP_WRITE_CMD_BASE_SZ + 1, + ble_gatt_write_test_misc_long_fail_offset); + + /*** Maximum reqs/rsps. */ + ble_gatt_write_test_misc_long_bad( + BLE_ATT_ATTR_MAX_LEN, + ble_gatt_write_test_misc_long_fail_offset); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatt_write_test_long_bad_value) +{ + /*** 1 prep write req/rsp. */ + ble_gatt_write_test_misc_long_bad( + BLE_ATT_MTU_DFLT - BLE_ATT_PREP_WRITE_CMD_BASE_SZ, + ble_gatt_write_test_misc_long_fail_value); + + /*** 2 prep write reqs/rsps. */ + ble_gatt_write_test_misc_long_bad( + BLE_ATT_MTU_DFLT - BLE_ATT_PREP_WRITE_CMD_BASE_SZ + 1, + ble_gatt_write_test_misc_long_fail_value); + + /*** Maximum reqs/rsps. */ + ble_gatt_write_test_misc_long_bad( + BLE_ATT_ATTR_MAX_LEN, + ble_gatt_write_test_misc_long_fail_value); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatt_write_test_long_bad_length) +{ + /*** 1 prep write req/rsp. */ + ble_gatt_write_test_misc_long_bad( + BLE_ATT_MTU_DFLT - BLE_ATT_PREP_WRITE_CMD_BASE_SZ, + ble_gatt_write_test_misc_long_fail_length); + + /*** 2 prep write reqs/rsps. */ + ble_gatt_write_test_misc_long_bad( + BLE_ATT_MTU_DFLT - BLE_ATT_PREP_WRITE_CMD_BASE_SZ + 1, + ble_gatt_write_test_misc_long_fail_length); + + /*** Maximum reqs/rsps. */ + ble_gatt_write_test_misc_long_bad( + BLE_ATT_ATTR_MAX_LEN, + ble_gatt_write_test_misc_long_fail_length); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatt_write_test_reliable_good) +{ + /*** 1 attribute. */ + ble_gatt_write_test_misc_reliable_good( + ((struct ble_hs_test_util_flat_attr[]) { { + .handle = 100, + .value_len = 2, + .value = { 1, 2 }, + }, { + 0 + } })); + + /*** 2 attributes. */ + ble_gatt_write_test_misc_reliable_good( + ((struct ble_hs_test_util_flat_attr[]) { { + .handle = 100, + .value_len = 2, + .value = { 1,2 }, + }, { + .handle = 113, + .value_len = 6, + .value = { 5,6,7,8,9,10 }, + }, { + 0 + } })); + + /*** 3 attributes. */ + ble_gatt_write_test_misc_reliable_good( + ((struct ble_hs_test_util_flat_attr[]) { { + .handle = 100, + .value_len = 2, + .value = { 1,2 }, + }, { + .handle = 113, + .value_len = 6, + .value = { 5,6,7,8,9,10 }, + }, { + .handle = 144, + .value_len = 1, + .value = { 0xff }, + }, { + 0 + } })); + + /*** Long attributes. */ + ble_gatt_write_test_misc_reliable_good( + ((struct ble_hs_test_util_flat_attr[]) { { + .handle = 100, + .value_len = 20, + .value = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 }, + }, { + .handle = 144, + .value_len = 20, + .value = { 11,12,13,14,15,16,17,18,19,110, + 111,112,113,114,115,116,117,118,119,120 }, + }, { + 0 + } })); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatt_write_test_long_queue_full) +{ + int off; + int len; + int rc; + int i; + + ble_gatt_write_test_init(); + + ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + + rc = ble_hs_test_util_gatt_write_long_flat( + 2, 100, ble_gatt_write_test_attr_value, 128, + ble_gatt_write_test_cb_good, NULL); + TEST_ASSERT(rc == 0); + + off = 0; + for (i = 0; i < 2; i++) { + /* Verify prep write request was sent. */ + TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue() != NULL); + + /* Receive Prep Write response. */ + len = BLE_ATT_MTU_DFLT - BLE_ATT_PREP_WRITE_CMD_BASE_SZ; + ble_gatt_write_test_rx_prep_rsp( + 2, 100, off, ble_gatt_write_test_attr_value + off, len); + + /* Verify callback hasn't gotten called. */ + TEST_ASSERT(!ble_gatt_write_test_cb_called); + + off += len; + } + + /* Verify prep write request was sent. */ + TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue() != NULL); + + /* Receive queue full error. */ + ble_hs_test_util_rx_att_err_rsp(2, BLE_ATT_OP_PREP_WRITE_REQ, + BLE_ATT_ERR_PREPARE_QUEUE_FULL, 100); + + /* Verify callback was called. */ + TEST_ASSERT(ble_gatt_write_test_cb_called); + TEST_ASSERT(ble_gatt_write_test_error.status == + BLE_HS_ATT_ERR(BLE_ATT_ERR_PREPARE_QUEUE_FULL)); + TEST_ASSERT(ble_gatt_write_test_error.att_handle == 100); + + /* Verify clear queue command got sent. */ + ble_hs_test_util_verify_tx_exec_write(BLE_ATT_EXEC_WRITE_F_CANCEL); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatt_write_test_long_oom) +{ + static const struct ble_hs_test_util_flat_attr attr = { + .handle = 34, + .value = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, + }, + .value_len = 20, + }; + + struct os_mbuf *oms; + int32_t ticks_until; + int chunk_sz; + int off; + int rc; + + ble_gatt_write_test_init(); + ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + + /* Initiate a write long procedure. */ + off = 0; + rc = ble_hs_test_util_gatt_write_long_flat( + 2, attr.handle, attr.value, attr.value_len, + ble_gatt_write_test_cb_good, NULL); + TEST_ASSERT_FATAL(rc == 0); + + chunk_sz = ble_att_mtu(2) - BLE_ATT_PREP_WRITE_CMD_BASE_SZ; + + ble_hs_test_util_verify_tx_prep_write(attr.handle, off, + attr.value + off, chunk_sz); + + /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ + oms = ble_hs_test_util_mbuf_alloc_all_but(1); + ble_gatt_write_test_rx_prep_rsp(2, attr.handle, off, attr.value + off, + chunk_sz); + off += chunk_sz; + + /* Ensure no follow-up request got sent. It should not have gotten sent + * due to mbuf exhaustion. + */ + ble_hs_test_util_prev_tx_queue_clear(); + TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL); + + /* Verify that we will resume the stalled GATT procedure in one second. */ + ticks_until = ble_gattc_timer(); + TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE))); + + /* Verify the procedure proceeds after mbufs become available. */ + rc = os_mbuf_free_chain(oms); + TEST_ASSERT_FATAL(rc == 0); + os_time_advance(ticks_until); + ble_gattc_timer(); + + chunk_sz = attr.value_len - off; + ble_hs_test_util_verify_tx_prep_write(attr.handle, off, + attr.value + off, chunk_sz); + + /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ + oms = ble_hs_test_util_mbuf_alloc_all_but(1); + ble_gatt_write_test_rx_prep_rsp( + 2, attr.handle, off, attr.value + off, chunk_sz); + off += chunk_sz; + + /* Ensure no follow-up request got sent. It should not have gotten sent + * due to mbuf exhaustion. + */ + ble_hs_test_util_prev_tx_queue_clear(); + TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL); + + /* Verify that we will resume the stalled GATT procedure in one second. */ + ticks_until = ble_gattc_timer(); + TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE))); + + /* Verify that procedure completes when mbufs are available. */ + rc = os_mbuf_free_chain(oms); + TEST_ASSERT_FATAL(rc == 0); + os_time_advance(ticks_until); + ble_gattc_timer(); + + /* Verify execute write request sent. */ + ble_hs_test_util_verify_tx_exec_write(BLE_ATT_EXEC_WRITE_F_EXECUTE); + + /* Receive Exec Write response. */ + ble_gatt_write_test_rx_exec_rsp(2); + + /* Verify callback got called. */ + TEST_ASSERT(ble_gatt_write_test_cb_called); + TEST_ASSERT(!ble_gattc_any_jobs()); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatt_write_test_reliable_oom) +{ + static const struct ble_hs_test_util_flat_attr attr = { + .handle = 34, + .value = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, + }, + .value_len = 20, + }; + + struct ble_gatt_attr mattr; + struct os_mbuf *oms; + int32_t ticks_until; + int chunk_sz; + int off; + int rc; + + ble_gatt_write_test_init(); + ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), + NULL, NULL); + + /* Initiate a write reliable procedure. */ + ble_hs_test_util_attr_from_flat(&mattr, &attr); + + off = 0; + rc = ble_gattc_write_reliable(2, &mattr, 1, + ble_gatt_write_test_reliable_cb_good, NULL); + TEST_ASSERT_FATAL(rc == 0); + + chunk_sz = ble_att_mtu(2) - BLE_ATT_PREP_WRITE_CMD_BASE_SZ; + + ble_hs_test_util_verify_tx_prep_write(attr.handle, off, + attr.value + off, chunk_sz); + + /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ + oms = ble_hs_test_util_mbuf_alloc_all_but(1); + ble_gatt_write_test_rx_prep_rsp(2, attr.handle, off, attr.value + off, + chunk_sz); + off += chunk_sz; + + /* Ensure no follow-up request got sent. It should not have gotten sent + * due to mbuf exhaustion. + */ + ble_hs_test_util_prev_tx_queue_clear(); + TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL); + + /* Verify that we will resume the stalled GATT procedure in one second. */ + ticks_until = ble_gattc_timer(); + TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE))); + + /* Verify the procedure proceeds after mbufs become available. */ + rc = os_mbuf_free_chain(oms); + TEST_ASSERT_FATAL(rc == 0); + os_time_advance(ticks_until); + ble_gattc_timer(); + + chunk_sz = attr.value_len - off; + ble_hs_test_util_verify_tx_prep_write(attr.handle, off, + attr.value + off, chunk_sz); + + /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ + oms = ble_hs_test_util_mbuf_alloc_all_but(1); + ble_gatt_write_test_rx_prep_rsp( + 2, attr.handle, off, attr.value + off, chunk_sz); + off += chunk_sz; + + /* Ensure no follow-up request got sent. It should not have gotten sent + * due to mbuf exhaustion. + */ + ble_hs_test_util_prev_tx_queue_clear(); + TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL); + + /* Verify that we will resume the stalled GATT procedure in one second. */ + ticks_until = ble_gattc_timer(); + TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE))); + + /* Verify that procedure completes when mbufs are available. */ + rc = os_mbuf_free_chain(oms); + TEST_ASSERT_FATAL(rc == 0); + os_time_advance(ticks_until); + ble_gattc_timer(); + + /* Verify execute write request sent. */ + ble_hs_test_util_verify_tx_exec_write(BLE_ATT_EXEC_WRITE_F_EXECUTE); + + /* Receive Exec Write response. */ + ble_gatt_write_test_rx_exec_rsp(2); + + /* Verify callback got called. */ + TEST_ASSERT(ble_gatt_write_test_cb_called); + TEST_ASSERT(!ble_gattc_any_jobs()); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_gatt_write_test_suite) +{ + ble_gatt_write_test_no_rsp(); + ble_gatt_write_test_rsp(); + ble_gatt_write_test_long_good(); + ble_gatt_write_test_long_bad_handle(); + ble_gatt_write_test_long_bad_offset(); + ble_gatt_write_test_long_bad_value(); + ble_gatt_write_test_long_bad_length(); + ble_gatt_write_test_long_queue_full(); + ble_gatt_write_test_reliable_good(); + ble_gatt_write_test_long_oom(); + ble_gatt_write_test_reliable_oom(); +} diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_gatts_notify_test.c b/src/libs/mynewt-nimble/nimble/host/test/src/ble_gatts_notify_test.c new file mode 100644 index 00000000..6e04ac36 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_gatts_notify_test.c @@ -0,0 +1,1090 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include "testutil/testutil.h" +#include "nimble/ble.h" +#include "host/ble_uuid.h" +#include "ble_hs_test.h" +#include "ble_hs_test_util.h" + +#define BLE_GATTS_NOTIFY_TEST_CHR_1_UUID 0x1111 +#define BLE_GATTS_NOTIFY_TEST_CHR_2_UUID 0x2222 + +#define BLE_GATTS_NOTIFY_TEST_MAX_EVENTS 16 + +static uint8_t ble_gatts_notify_test_peer_addr[6] = {2,3,4,5,6,7}; + +static int +ble_gatts_notify_test_misc_access(uint16_t conn_handle, + uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg); +static void +ble_gatts_notify_test_misc_reg_cb(struct ble_gatt_register_ctxt *ctxt, + void *arg); + +static const struct ble_gatt_svc_def ble_gatts_notify_test_svcs[] = { { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(0x1234), + .characteristics = (struct ble_gatt_chr_def[]) { { + .uuid = BLE_UUID16_DECLARE(BLE_GATTS_NOTIFY_TEST_CHR_1_UUID), + .access_cb = ble_gatts_notify_test_misc_access, + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | + BLE_GATT_CHR_F_INDICATE, + }, { + .uuid = BLE_UUID16_DECLARE(BLE_GATTS_NOTIFY_TEST_CHR_2_UUID), + .access_cb = ble_gatts_notify_test_misc_access, + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | + BLE_GATT_CHR_F_INDICATE, + }, { + 0 + } }, +}, { + 0 +} }; + +static uint16_t ble_gatts_notify_test_chr_1_def_handle; +static uint8_t ble_gatts_notify_test_chr_1_val[1024]; +static int ble_gatts_notify_test_chr_1_len; +static uint16_t ble_gatts_notify_test_chr_2_def_handle; +static uint8_t ble_gatts_notify_test_chr_2_val[1024]; +static int ble_gatts_notify_test_chr_2_len; + +static struct ble_gap_event +ble_gatts_notify_test_events[BLE_GATTS_NOTIFY_TEST_MAX_EVENTS]; + +static int ble_gatts_notify_test_num_events; + +typedef int ble_store_write_fn(int obj_type, const union ble_store_value *val); + +typedef int ble_store_delete_fn(int obj_type, const union ble_store_key *key); + +static int +ble_gatts_notify_test_util_gap_event(struct ble_gap_event *event, void *arg) +{ + switch (event->type) { + case BLE_GAP_EVENT_NOTIFY_TX: + case BLE_GAP_EVENT_SUBSCRIBE: + TEST_ASSERT_FATAL(ble_gatts_notify_test_num_events < + BLE_GATTS_NOTIFY_TEST_MAX_EVENTS); + + ble_gatts_notify_test_events[ble_gatts_notify_test_num_events++] = + *event; + + default: + break; + } + + return 0; +} + +static uint16_t +ble_gatts_notify_test_misc_read_notify(uint16_t conn_handle, + uint16_t chr_def_handle) +{ + struct ble_att_read_req req; + struct os_mbuf *om; + uint8_t buf[BLE_ATT_READ_REQ_SZ]; + uint16_t flags; + int rc; + + req.barq_handle = chr_def_handle + 2; + ble_att_read_req_write(buf, sizeof buf, &req); + + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, sizeof buf); + TEST_ASSERT(rc == 0); + + om = ble_hs_test_util_prev_tx_dequeue_pullup(); + TEST_ASSERT_FATAL(om != NULL); + TEST_ASSERT_FATAL(om->om_len == 3); + TEST_ASSERT_FATAL(om->om_data[0] == BLE_ATT_OP_READ_RSP); + + flags = get_le16(om->om_data + 1); + return flags; +} + +static void +ble_gatts_notify_test_misc_try_enable_notify(uint16_t conn_handle, + uint16_t chr_def_handle, + uint16_t flags, int fail) +{ + struct ble_att_write_req req; + uint8_t buf[BLE_ATT_WRITE_REQ_BASE_SZ + 2]; + int rc; + + req.bawq_handle = chr_def_handle + 2; + ble_att_write_req_write(buf, sizeof buf, &req); + + put_le16(buf + BLE_ATT_WRITE_REQ_BASE_SZ, flags); + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, sizeof buf); + if (fail) { + TEST_ASSERT_FATAL(rc != 0); + ble_hs_test_util_verify_tx_err_rsp(BLE_ATT_OP_WRITE_REQ, + req.bawq_handle, + BLE_ATT_ERR_REQ_NOT_SUPPORTED); + } else { + TEST_ASSERT_FATAL(rc == 0); + ble_hs_test_util_verify_tx_write_rsp(); + } +} + +static void +ble_gatts_notify_test_misc_enable_notify(uint16_t conn_handle, + uint16_t chr_def_handle, + uint16_t flags) +{ + ble_gatts_notify_test_misc_try_enable_notify(conn_handle, + chr_def_handle, + flags, 0); +} + +static void +ble_gatts_notify_test_util_next_event(struct ble_gap_event *event) +{ + TEST_ASSERT_FATAL(ble_gatts_notify_test_num_events > 0); + + *event = *ble_gatts_notify_test_events; + + ble_gatts_notify_test_num_events--; + if (ble_gatts_notify_test_num_events > 0) { + memmove(ble_gatts_notify_test_events + 0, + ble_gatts_notify_test_events + 1, + ble_gatts_notify_test_num_events * sizeof *event); + } +} + +static void +ble_gatts_notify_test_util_verify_sub_event(uint16_t conn_handle, + uint8_t attr_handle, + uint8_t reason, + uint8_t prevn, uint8_t curn, + uint8_t previ, uint8_t curi) +{ + struct ble_gap_event event; + + ble_gatts_notify_test_util_next_event(&event); + + TEST_ASSERT(event.type == BLE_GAP_EVENT_SUBSCRIBE); + TEST_ASSERT(event.subscribe.conn_handle == conn_handle); + TEST_ASSERT(event.subscribe.attr_handle == attr_handle); + TEST_ASSERT(event.subscribe.reason == reason); + TEST_ASSERT(event.subscribe.prev_notify == prevn); + TEST_ASSERT(event.subscribe.cur_notify == curn); + TEST_ASSERT(event.subscribe.prev_indicate == previ); + TEST_ASSERT(event.subscribe.cur_indicate == curi); +} + +static void +ble_gatts_notify_test_util_verify_tx_event(uint16_t conn_handle, + uint8_t attr_handle, + int status, + int indication) +{ + struct ble_gap_event event; + + ble_gatts_notify_test_util_next_event(&event); + + TEST_ASSERT(event.type == BLE_GAP_EVENT_NOTIFY_TX); + TEST_ASSERT(event.notify_tx.status == status); + TEST_ASSERT(event.notify_tx.conn_handle == conn_handle); + TEST_ASSERT(event.notify_tx.attr_handle == attr_handle); + TEST_ASSERT(event.notify_tx.indication == indication); +} + +static void +ble_gatts_notify_test_util_verify_ack_event(uint16_t conn_handle, + uint8_t attr_handle) +{ + ble_gatts_notify_test_util_verify_tx_event(conn_handle, attr_handle, + BLE_HS_EDONE, 1); +} + +static void +ble_gatts_notify_test_misc_init(uint16_t *out_conn_handle, int bonding, + uint16_t chr1_flags, uint16_t chr2_flags) +{ + struct ble_hs_conn *conn; + uint16_t flags; + int exp_num_cccds; + + ble_hs_test_util_init(); + ble_gatts_notify_test_num_events = 0; + + ble_hs_test_util_reg_svcs(ble_gatts_notify_test_svcs, + ble_gatts_notify_test_misc_reg_cb, + NULL); + TEST_ASSERT_FATAL(ble_gatts_notify_test_chr_1_def_handle != 0); + TEST_ASSERT_FATAL(ble_gatts_notify_test_chr_2_def_handle != 0); + + ble_hs_test_util_create_conn(2, ble_gatts_notify_test_peer_addr, + ble_gatts_notify_test_util_gap_event, NULL); + *out_conn_handle = 2; + + if (bonding) { + ble_hs_lock(); + conn = ble_hs_conn_find(2); + TEST_ASSERT_FATAL(conn != NULL); + conn->bhc_sec_state.encrypted = 1; + conn->bhc_sec_state.authenticated = 1; + conn->bhc_sec_state.bonded = 1; + ble_hs_unlock(); + } + + /* Ensure notifications disabled on new connection. */ + flags = ble_gatts_notify_test_misc_read_notify( + 2, ble_gatts_notify_test_chr_1_def_handle); + TEST_ASSERT(flags == 0); + flags = ble_gatts_notify_test_misc_read_notify( + 2, ble_gatts_notify_test_chr_2_def_handle); + TEST_ASSERT(flags == 0); + + /* Set initial notification / indication state and verify that subscription + * callback gets executed. + */ + if (chr1_flags != 0) { + ble_gatts_notify_test_misc_enable_notify( + 2, ble_gatts_notify_test_chr_1_def_handle, chr1_flags); + + ble_gatts_notify_test_util_verify_sub_event( + *out_conn_handle, + ble_gatts_notify_test_chr_1_def_handle + 1, + BLE_GAP_SUBSCRIBE_REASON_WRITE, + 0, chr1_flags == BLE_GATTS_CLT_CFG_F_NOTIFY, + 0, chr1_flags == BLE_GATTS_CLT_CFG_F_INDICATE); + } + if (chr2_flags != 0) { + ble_gatts_notify_test_misc_enable_notify( + 2, ble_gatts_notify_test_chr_2_def_handle, chr2_flags); + + ble_gatts_notify_test_util_verify_sub_event( + *out_conn_handle, + ble_gatts_notify_test_chr_2_def_handle + 1, + BLE_GAP_SUBSCRIBE_REASON_WRITE, + 0, chr2_flags == BLE_GATTS_CLT_CFG_F_NOTIFY, + 0, chr2_flags == BLE_GATTS_CLT_CFG_F_INDICATE); + } + + /* Ensure no extraneous subscription callbacks were executed. */ + TEST_ASSERT(ble_gatts_notify_test_num_events == 0); + + /* Toss both write responses. */ + ble_hs_test_util_prev_tx_queue_clear(); + + /* Ensure notification / indication state reads back correctly. */ + flags = ble_gatts_notify_test_misc_read_notify( + 2, ble_gatts_notify_test_chr_1_def_handle); + TEST_ASSERT(flags == chr1_flags); + flags = ble_gatts_notify_test_misc_read_notify( + 2, ble_gatts_notify_test_chr_2_def_handle); + TEST_ASSERT(flags == chr2_flags); + + /* Ensure both CCCDs still persisted. */ + if (bonding) { + exp_num_cccds = (chr1_flags != 0) + (chr2_flags != 0); + } else { + exp_num_cccds = 0; + } + TEST_ASSERT(ble_hs_test_util_num_cccds() == exp_num_cccds); +} + +static void +ble_gatts_notify_test_disconnect(uint16_t conn_handle, + uint8_t chr1_flags, + uint8_t chr1_indicate_in_progress, + uint8_t chr2_flags, + uint8_t chr2_indicate_in_progress) +{ + ble_hs_test_util_conn_disconnect(conn_handle); + + if (chr1_indicate_in_progress) { + ble_gatts_notify_test_util_verify_tx_event( + conn_handle, + ble_gatts_notify_test_chr_1_def_handle + 1, + BLE_HS_ENOTCONN, + 1); + } + + /* Verify subscription callback executed for each subscribed + * characteristic. + */ + if (chr1_flags != 0) { + ble_gatts_notify_test_util_verify_sub_event( + conn_handle, + ble_gatts_notify_test_chr_1_def_handle + 1, + BLE_GAP_SUBSCRIBE_REASON_TERM, + chr1_flags == BLE_GATTS_CLT_CFG_F_NOTIFY, 0, + chr1_flags == BLE_GATTS_CLT_CFG_F_INDICATE, 0); + } + + if (chr2_indicate_in_progress) { + ble_gatts_notify_test_util_verify_tx_event( + conn_handle, + ble_gatts_notify_test_chr_2_def_handle + 1, + BLE_HS_ENOTCONN, + 1); + } + + if (chr2_flags != 0) { + ble_gatts_notify_test_util_verify_sub_event( + conn_handle, + ble_gatts_notify_test_chr_2_def_handle + 1, + BLE_GAP_SUBSCRIBE_REASON_TERM, + chr2_flags == BLE_GATTS_CLT_CFG_F_NOTIFY, 0, + chr2_flags == BLE_GATTS_CLT_CFG_F_INDICATE, 0); + } +} + +static void +ble_gatts_notify_test_misc_reg_cb(struct ble_gatt_register_ctxt *ctxt, + void *arg) +{ + uint16_t uuid16; + + if (ctxt->op == BLE_GATT_REGISTER_OP_CHR) { + uuid16 = ble_uuid_u16(ctxt->chr.chr_def->uuid); + switch (uuid16) { + case BLE_GATTS_NOTIFY_TEST_CHR_1_UUID: + ble_gatts_notify_test_chr_1_def_handle = ctxt->chr.def_handle; + break; + + case BLE_GATTS_NOTIFY_TEST_CHR_2_UUID: + ble_gatts_notify_test_chr_2_def_handle = ctxt->chr.def_handle; + break; + + default: + TEST_ASSERT_FATAL(0); + break; + } + } +} + +static int +ble_gatts_notify_test_misc_access(uint16_t conn_handle, + uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg) +{ + int rc; + + TEST_ASSERT_FATAL(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR); + TEST_ASSERT(conn_handle == 0xffff); + + if (attr_handle == ble_gatts_notify_test_chr_1_def_handle + 1) { + TEST_ASSERT(ctxt->chr == + &ble_gatts_notify_test_svcs[0].characteristics[0]); + rc = os_mbuf_copyinto(ctxt->om, 0, ble_gatts_notify_test_chr_1_val, + ble_gatts_notify_test_chr_1_len); + TEST_ASSERT_FATAL(rc == 0); + } else if (attr_handle == ble_gatts_notify_test_chr_2_def_handle + 1) { + TEST_ASSERT(ctxt->chr == + &ble_gatts_notify_test_svcs[0].characteristics[1]); + rc = os_mbuf_copyinto(ctxt->om, 0, ble_gatts_notify_test_chr_2_val, + ble_gatts_notify_test_chr_2_len); + TEST_ASSERT_FATAL(rc == 0); + } else { + TEST_ASSERT_FATAL(0); + } + + return 0; +} + +static void +ble_gatts_notify_test_misc_rx_indicate_rsp(uint16_t conn_handle, + uint16_t attr_handle) +{ + uint8_t buf[BLE_ATT_INDICATE_RSP_SZ]; + int rc; + + ble_att_indicate_rsp_write(buf, sizeof buf); + + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, sizeof buf); + TEST_ASSERT(rc == 0); + + ble_gatts_notify_test_util_verify_ack_event(conn_handle, attr_handle); +} + +static void +ble_gatts_notify_test_misc_verify_tx_n(uint16_t conn_handle, + uint16_t attr_handle, + const uint8_t *attr_data, int attr_len) +{ + struct ble_att_notify_req req; + struct os_mbuf *om; + int i; + + om = ble_hs_test_util_prev_tx_dequeue_pullup(); + TEST_ASSERT_FATAL(om != NULL); + + ble_att_notify_req_parse(om->om_data, om->om_len, &req); + TEST_ASSERT(req.banq_handle == attr_handle); + + for (i = 0; i < attr_len; i++) { + TEST_ASSERT(om->om_data[BLE_ATT_NOTIFY_REQ_BASE_SZ + i] == + attr_data[i]); + } + + ble_gatts_notify_test_util_verify_tx_event(conn_handle, attr_handle, 0, 0); +} + +static void +ble_gatts_notify_test_misc_verify_tx_i(uint16_t conn_handle, + uint16_t attr_handle, + const uint8_t *attr_data, int attr_len) +{ + struct ble_att_indicate_req req; + struct os_mbuf *om; + int i; + + om = ble_hs_test_util_prev_tx_dequeue_pullup(); + TEST_ASSERT_FATAL(om != NULL); + + ble_att_indicate_req_parse(om->om_data, om->om_len, &req); + TEST_ASSERT(req.baiq_handle == attr_handle); + + for (i = 0; i < attr_len; i++) { + TEST_ASSERT(om->om_data[BLE_ATT_INDICATE_REQ_BASE_SZ + i] == + attr_data[i]); + } + + ble_gatts_notify_test_util_verify_tx_event(conn_handle, attr_handle, 0, 1); +} + +static void +ble_gatts_notify_test_misc_verify_tx_gen(uint16_t conn_handle, int attr_idx, + uint8_t chr_flags) +{ + uint16_t attr_handle; + uint16_t attr_len; + void *attr_val; + + switch (attr_idx) { + case 1: + attr_handle = ble_gatts_notify_test_chr_1_def_handle + 1; + attr_len = ble_gatts_notify_test_chr_1_len; + attr_val = ble_gatts_notify_test_chr_1_val; + break; + + case 2: + attr_handle = ble_gatts_notify_test_chr_2_def_handle + 1; + attr_len = ble_gatts_notify_test_chr_2_len; + attr_val = ble_gatts_notify_test_chr_2_val; + break; + + default: + TEST_ASSERT_FATAL(0); + break; + } + + switch (chr_flags) { + case 0: + break; + + case BLE_GATTS_CLT_CFG_F_NOTIFY: + ble_gatts_notify_test_misc_verify_tx_n(conn_handle, attr_handle, + attr_val, attr_len); + break; + + case BLE_GATTS_CLT_CFG_F_INDICATE: + ble_gatts_notify_test_misc_verify_tx_i(conn_handle, attr_handle, + attr_val, attr_len); + break; + + default: + TEST_ASSERT_FATAL(0); + break; + } +} + +static void +ble_gatts_notify_test_restore_bonding(uint16_t conn_handle, + uint8_t chr1_flags, uint8_t chr1_tx, + uint8_t chr2_flags, uint8_t chr2_tx) +{ + struct ble_hs_conn *conn; + + ble_hs_lock(); + conn = ble_hs_conn_find(conn_handle); + TEST_ASSERT_FATAL(conn != NULL); + conn->bhc_sec_state.encrypted = 1; + conn->bhc_sec_state.authenticated = 1; + conn->bhc_sec_state.bonded = 1; + ble_hs_unlock(); + + ble_gatts_bonding_restored(conn_handle); + + /* Verify subscription callback executed for each subscribed + * characteristic. + */ + if (chr1_flags != 0) { + ble_gatts_notify_test_util_verify_sub_event( + conn_handle, + ble_gatts_notify_test_chr_1_def_handle + 1, + BLE_GAP_SUBSCRIBE_REASON_RESTORE, + 0, chr1_flags == BLE_GATTS_CLT_CFG_F_NOTIFY, + 0, chr1_flags == BLE_GATTS_CLT_CFG_F_INDICATE); + + } + if (chr1_tx) { + ble_gatts_notify_test_misc_verify_tx_gen(conn_handle, 1, chr1_flags); + } + + if (chr2_flags != 0) { + ble_gatts_notify_test_util_verify_sub_event( + conn_handle, + ble_gatts_notify_test_chr_2_def_handle + 1, + BLE_GAP_SUBSCRIBE_REASON_RESTORE, + 0, chr2_flags == BLE_GATTS_CLT_CFG_F_NOTIFY, + 0, chr2_flags == BLE_GATTS_CLT_CFG_F_INDICATE); + } + if (chr2_tx) { + ble_gatts_notify_test_misc_verify_tx_gen(conn_handle, 2, chr2_flags); + } +} + +TEST_CASE_SELF(ble_gatts_notify_test_n) +{ + static const uint8_t fourbytes[] = { 1, 2, 3, 4 }; + struct os_mbuf *om; + uint16_t conn_handle; + uint16_t flags; + int rc; + + ble_gatts_notify_test_misc_init(&conn_handle, 0, + BLE_GATTS_CLT_CFG_F_NOTIFY, + BLE_GATTS_CLT_CFG_F_NOTIFY); + + /* Ensure notifications read back as enabled. */ + flags = ble_gatts_notify_test_misc_read_notify( + conn_handle, ble_gatts_notify_test_chr_1_def_handle); + TEST_ASSERT(flags == BLE_GATTS_CLT_CFG_F_NOTIFY); + flags = ble_gatts_notify_test_misc_read_notify( + conn_handle, ble_gatts_notify_test_chr_2_def_handle); + TEST_ASSERT(flags == BLE_GATTS_CLT_CFG_F_NOTIFY); + + /* Verify custom notification data. */ + om = ble_hs_mbuf_from_flat(fourbytes, sizeof fourbytes); + TEST_ASSERT_FATAL(om != NULL); + + rc = ble_gattc_notify_custom(conn_handle, + ble_gatts_notify_test_chr_1_def_handle + 1, + om); + TEST_ASSERT_FATAL(rc == 0); + + ble_gatts_notify_test_misc_verify_tx_n( + conn_handle, + ble_gatts_notify_test_chr_1_def_handle + 1, + fourbytes, + sizeof fourbytes); + + /* Update characteristic 1's value. */ + ble_gatts_notify_test_chr_1_len = 1; + ble_gatts_notify_test_chr_1_val[0] = 0xab; + ble_gatts_chr_updated(ble_gatts_notify_test_chr_1_def_handle + 1); + + /* Verify notification sent properly. */ + ble_gatts_notify_test_misc_verify_tx_n( + conn_handle, + ble_gatts_notify_test_chr_1_def_handle + 1, + ble_gatts_notify_test_chr_1_val, + ble_gatts_notify_test_chr_1_len); + + /* Update characteristic 2's value. */ + ble_gatts_notify_test_chr_2_len = 16; + memcpy(ble_gatts_notify_test_chr_2_val, + ((uint8_t[]){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}), 16); + ble_gatts_chr_updated(ble_gatts_notify_test_chr_2_def_handle + 1); + + /* Verify notification sent properly. */ + ble_gatts_notify_test_misc_verify_tx_n( + conn_handle, + ble_gatts_notify_test_chr_2_def_handle + 1, + ble_gatts_notify_test_chr_2_val, + ble_gatts_notify_test_chr_2_len); + + /*** + * Disconnect, modify characteristic values, and reconnect. Ensure + * notifications are not sent and are no longer enabled. + */ + + ble_gatts_notify_test_disconnect(conn_handle, + BLE_GATTS_CLT_CFG_F_NOTIFY, 0, + BLE_GATTS_CLT_CFG_F_NOTIFY, 0); + + /* Update characteristic 1's value. */ + ble_gatts_notify_test_chr_1_len = 1; + ble_gatts_notify_test_chr_1_val[0] = 0xdd; + ble_gatts_chr_updated(ble_gatts_notify_test_chr_1_def_handle + 1); + + /* Update characteristic 2's value. */ + ble_gatts_notify_test_chr_2_len = 16; + memcpy(ble_gatts_notify_test_chr_2_val, + ((uint8_t[]){1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}), 16); + ble_gatts_chr_updated(ble_gatts_notify_test_chr_2_def_handle + 1); + + ble_hs_test_util_create_conn(conn_handle, ((uint8_t[]){2,3,4,5,6,7,8,9}), + ble_gatts_notify_test_util_gap_event, NULL); + + /* Ensure no notifications sent. */ + TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue() == NULL); + + /* Ensure notifications disabled. */ + flags = ble_gatts_notify_test_misc_read_notify( + conn_handle, ble_gatts_notify_test_chr_1_def_handle); + TEST_ASSERT(flags == 0); + flags = ble_gatts_notify_test_misc_read_notify( + conn_handle, ble_gatts_notify_test_chr_2_def_handle); + TEST_ASSERT(flags == 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatts_notify_test_i) +{ + static const uint8_t fourbytes[] = { 1, 2, 3, 4 }; + struct os_mbuf *om; + uint16_t conn_handle; + uint16_t flags; + int rc; + + ble_gatts_notify_test_misc_init(&conn_handle, 0, + BLE_GATTS_CLT_CFG_F_INDICATE, + BLE_GATTS_CLT_CFG_F_INDICATE); + + /* Verify custom indication data. */ + om = ble_hs_mbuf_from_flat(fourbytes, sizeof fourbytes); + TEST_ASSERT_FATAL(om != NULL); + + rc = ble_gattc_indicate_custom(conn_handle, + ble_gatts_notify_test_chr_1_def_handle + 1, + om); + TEST_ASSERT_FATAL(rc == 0); + + ble_gatts_notify_test_misc_verify_tx_i( + conn_handle, + ble_gatts_notify_test_chr_1_def_handle + 1, + fourbytes, + sizeof fourbytes); + + /* Receive the confirmation for the indication. */ + ble_gatts_notify_test_misc_rx_indicate_rsp( + conn_handle, + ble_gatts_notify_test_chr_1_def_handle + 1); + + /* Update characteristic 1's value. */ + ble_gatts_notify_test_chr_1_len = 1; + ble_gatts_notify_test_chr_1_val[0] = 0xab; + ble_gatts_chr_updated(ble_gatts_notify_test_chr_1_def_handle + 1); + + /* Verify indication sent properly. */ + ble_gatts_notify_test_misc_verify_tx_i( + conn_handle, + ble_gatts_notify_test_chr_1_def_handle + 1, + ble_gatts_notify_test_chr_1_val, + ble_gatts_notify_test_chr_1_len); + + /* Update characteristic 2's value. */ + ble_gatts_notify_test_chr_2_len = 16; + memcpy(ble_gatts_notify_test_chr_2_val, + ((uint8_t[]){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}), 16); + ble_gatts_chr_updated(ble_gatts_notify_test_chr_2_def_handle + 1); + + /* Verify the second indication doesn't get sent until the first is + * confirmed. + */ + TEST_ASSERT(ble_hs_test_util_prev_tx_queue_sz() == 0); + + /* Receive the confirmation for the first indication. */ + ble_gatts_notify_test_misc_rx_indicate_rsp( + conn_handle, + ble_gatts_notify_test_chr_1_def_handle + 1); + + /* Verify indication sent properly. */ + ble_gatts_notify_test_misc_verify_tx_i( + conn_handle, + ble_gatts_notify_test_chr_2_def_handle + 1, + ble_gatts_notify_test_chr_2_val, + ble_gatts_notify_test_chr_2_len); + + /* Receive the confirmation for the second indication. */ + ble_gatts_notify_test_misc_rx_indicate_rsp( + conn_handle, + ble_gatts_notify_test_chr_2_def_handle + 1); + + /* Verify no pending GATT jobs. */ + TEST_ASSERT(!ble_gattc_any_jobs()); + + /*** + * Disconnect, modify characteristic values, and reconnect. Ensure + * indications are not sent and are no longer enabled. + */ + + ble_gatts_notify_test_disconnect(conn_handle, + BLE_GATTS_CLT_CFG_F_INDICATE, 0, + BLE_GATTS_CLT_CFG_F_INDICATE, 0); + + /* Update characteristic 1's value. */ + ble_gatts_notify_test_chr_1_len = 1; + ble_gatts_notify_test_chr_1_val[0] = 0xdd; + ble_gatts_chr_updated(ble_gatts_notify_test_chr_1_def_handle + 1); + + /* Update characteristic 2's value. */ + ble_gatts_notify_test_chr_2_len = 16; + memcpy(ble_gatts_notify_test_chr_2_val, + ((uint8_t[]){1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}), 16); + ble_gatts_chr_updated(ble_gatts_notify_test_chr_2_def_handle + 1); + + ble_hs_test_util_create_conn(conn_handle, ((uint8_t[]){2,3,4,5,6,7,8,9}), + ble_gatts_notify_test_util_gap_event, NULL); + + /* Ensure no indications sent. */ + TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue() == NULL); + + /* Ensure indications disabled. */ + flags = ble_gatts_notify_test_misc_read_notify( + conn_handle, ble_gatts_notify_test_chr_1_def_handle); + TEST_ASSERT(flags == 0); + flags = ble_gatts_notify_test_misc_read_notify( + conn_handle, ble_gatts_notify_test_chr_2_def_handle); + TEST_ASSERT(flags == 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatts_notify_test_bonded_n) +{ + uint16_t conn_handle; + uint16_t flags; + + ble_gatts_notify_test_misc_init(&conn_handle, 1, + BLE_GATTS_CLT_CFG_F_NOTIFY, + BLE_GATTS_CLT_CFG_F_NOTIFY); + + /* Disconnect. */ + ble_gatts_notify_test_disconnect(conn_handle, + BLE_GATTS_CLT_CFG_F_NOTIFY, 0, + BLE_GATTS_CLT_CFG_F_NOTIFY, 0); + + /* Ensure both CCCDs still persisted. */ + TEST_ASSERT(ble_hs_test_util_num_cccds() == 2); + + /* Update characteristic 1's value. */ + ble_gatts_notify_test_chr_1_len = 1; + ble_gatts_notify_test_chr_1_val[0] = 0xdd; + ble_gatts_chr_updated(ble_gatts_notify_test_chr_1_def_handle + 1); + + /* Update characteristic 2's value. */ + ble_gatts_notify_test_chr_2_len = 16; + memcpy(ble_gatts_notify_test_chr_2_val, + ((uint8_t[]){1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}), 16); + ble_gatts_chr_updated(ble_gatts_notify_test_chr_2_def_handle + 1); + + /* Reconnect; ensure notifications don't get sent while unbonded and that + * notifications appear disabled. + */ + + ble_hs_test_util_create_conn(conn_handle, ((uint8_t[]){2,3,4,5,6,7,8,9}), + ble_gatts_notify_test_util_gap_event, NULL); + + ble_gatts_notify_test_num_events = 0; + /* Ensure no notifications sent. */ + TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue() == NULL); + + /* Ensure notifications disabled. */ + flags = ble_gatts_notify_test_misc_read_notify( + conn_handle, ble_gatts_notify_test_chr_1_def_handle); + TEST_ASSERT(flags == 0); + flags = ble_gatts_notify_test_misc_read_notify( + conn_handle, ble_gatts_notify_test_chr_2_def_handle); + TEST_ASSERT(flags == 0); + + /* Simulate a successful encryption procedure (bonding restoration). */ + ble_gatts_notify_test_restore_bonding(conn_handle, + BLE_GATTS_CLT_CFG_F_NOTIFY, 1, + BLE_GATTS_CLT_CFG_F_NOTIFY, 1); + + /* Ensure notifications enabled. */ + flags = ble_gatts_notify_test_misc_read_notify( + conn_handle, ble_gatts_notify_test_chr_1_def_handle); + TEST_ASSERT(flags == BLE_GATTS_CLT_CFG_F_NOTIFY); + flags = ble_gatts_notify_test_misc_read_notify( + conn_handle, ble_gatts_notify_test_chr_2_def_handle); + TEST_ASSERT(flags == BLE_GATTS_CLT_CFG_F_NOTIFY); + + /* Ensure both CCCDs still persisted. */ + TEST_ASSERT(ble_hs_test_util_num_cccds() == 2); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatts_notify_test_bonded_i) +{ + uint16_t conn_handle; + uint16_t flags; + + ble_gatts_notify_test_misc_init(&conn_handle, 1, + BLE_GATTS_CLT_CFG_F_INDICATE, + BLE_GATTS_CLT_CFG_F_INDICATE); + + /* Disconnect. */ + ble_gatts_notify_test_disconnect(conn_handle, + BLE_GATTS_CLT_CFG_F_INDICATE, 0, + BLE_GATTS_CLT_CFG_F_INDICATE, 0); + + /* Ensure both CCCDs still persisted. */ + TEST_ASSERT(ble_hs_test_util_num_cccds() == 2); + + /* Update characteristic 1's value. */ + ble_gatts_notify_test_chr_1_len = 1; + ble_gatts_notify_test_chr_1_val[0] = 0xab; + ble_gatts_chr_updated(ble_gatts_notify_test_chr_1_def_handle + 1); + + /* Update characteristic 2's value. */ + ble_gatts_notify_test_chr_2_len = 16; + memcpy(ble_gatts_notify_test_chr_2_val, + ((uint8_t[]){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}), 16); + ble_gatts_chr_updated(ble_gatts_notify_test_chr_2_def_handle + 1); + + /* Reconnect; ensure notifications don't get sent while unbonded and that + * notifications appear disabled. + */ + + ble_hs_test_util_create_conn(conn_handle, ((uint8_t[]){2,3,4,5,6,7,8,9}), + ble_gatts_notify_test_util_gap_event, NULL); + + /* Ensure no indications sent. */ + TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue() == NULL); + + /* Ensure notifications disabled. */ + flags = ble_gatts_notify_test_misc_read_notify( + conn_handle, ble_gatts_notify_test_chr_1_def_handle); + TEST_ASSERT(flags == 0); + flags = ble_gatts_notify_test_misc_read_notify( + conn_handle, ble_gatts_notify_test_chr_2_def_handle); + TEST_ASSERT(flags == 0); + + /* Simulate a successful encryption procedure (bonding restoration). */ + ble_gatts_notify_test_restore_bonding(conn_handle, + BLE_GATTS_CLT_CFG_F_INDICATE, 1, + BLE_GATTS_CLT_CFG_F_INDICATE, 0); + + /* Verify the second indication doesn't get sent until the first is + * confirmed. + */ + TEST_ASSERT(ble_hs_test_util_prev_tx_queue_sz() == 0); + + /* Receive the confirmation for the first indication. */ + ble_gatts_notify_test_misc_rx_indicate_rsp( + conn_handle, + ble_gatts_notify_test_chr_1_def_handle + 1); + + /* Verify indication sent properly. */ + ble_gatts_notify_test_misc_verify_tx_i( + conn_handle, + ble_gatts_notify_test_chr_2_def_handle + 1, + ble_gatts_notify_test_chr_2_val, + ble_gatts_notify_test_chr_2_len); + + /* Receive the confirmation for the second indication. */ + ble_gatts_notify_test_misc_rx_indicate_rsp( + conn_handle, + ble_gatts_notify_test_chr_2_def_handle + 1); + + /* Verify no pending GATT jobs. */ + TEST_ASSERT(!ble_gattc_any_jobs()); + + /* Ensure notifications enabled. */ + flags = ble_gatts_notify_test_misc_read_notify( + conn_handle, ble_gatts_notify_test_chr_1_def_handle); + TEST_ASSERT(flags == BLE_GATTS_CLT_CFG_F_INDICATE); + flags = ble_gatts_notify_test_misc_read_notify( + conn_handle, ble_gatts_notify_test_chr_2_def_handle); + TEST_ASSERT(flags == BLE_GATTS_CLT_CFG_F_INDICATE); + + /* Ensure both CCCDs still persisted. */ + TEST_ASSERT(ble_hs_test_util_num_cccds() == 2); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatts_notify_test_bonded_i_no_ack) +{ + struct ble_store_value_cccd value_cccd; + struct ble_store_key_cccd key_cccd; + uint16_t conn_handle; + uint16_t flags; + int rc; + + ble_gatts_notify_test_misc_init(&conn_handle, 1, + BLE_GATTS_CLT_CFG_F_INDICATE, 0); + + /* Update characteristic 1's value. */ + ble_gatts_notify_test_chr_1_len = 1; + ble_gatts_notify_test_chr_1_val[0] = 0xab; + ble_gatts_chr_updated(ble_gatts_notify_test_chr_1_def_handle + 1); + + /* Verify indication sent properly. */ + ble_gatts_notify_test_misc_verify_tx_i( + conn_handle, + ble_gatts_notify_test_chr_1_def_handle + 1, + ble_gatts_notify_test_chr_1_val, + ble_gatts_notify_test_chr_1_len); + + /* Verify 'updated' state is still persisted. */ + key_cccd.peer_addr = *BLE_ADDR_ANY; + key_cccd.chr_val_handle = ble_gatts_notify_test_chr_1_def_handle + 1; + key_cccd.idx = 0; + + rc = ble_store_read_cccd(&key_cccd, &value_cccd); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(value_cccd.value_changed); + + /* Disconnect. */ + ble_gatts_notify_test_disconnect(conn_handle, + BLE_GATTS_CLT_CFG_F_INDICATE, 1, 0, 0); + + /* Ensure CCCD still persisted. */ + TEST_ASSERT(ble_hs_test_util_num_cccds() == 1); + + /* Reconnect. */ + ble_hs_test_util_create_conn(conn_handle, ((uint8_t[]){2,3,4,5,6,7,8,9}), + ble_gatts_notify_test_util_gap_event, NULL); + + /* Simulate a successful encryption procedure (bonding restoration). */ + ble_gatts_notify_test_restore_bonding(conn_handle, + BLE_GATTS_CLT_CFG_F_INDICATE, 1, + 0, 0); + + /* Receive the confirmation for the indication. */ + ble_gatts_notify_test_misc_rx_indicate_rsp( + conn_handle, + ble_gatts_notify_test_chr_1_def_handle + 1); + + /* Verify no pending GATT jobs. */ + TEST_ASSERT(!ble_gattc_any_jobs()); + + /* Ensure indication enabled. */ + flags = ble_gatts_notify_test_misc_read_notify( + conn_handle, ble_gatts_notify_test_chr_1_def_handle); + TEST_ASSERT(flags == BLE_GATTS_CLT_CFG_F_INDICATE); + flags = ble_gatts_notify_test_misc_read_notify( + conn_handle, ble_gatts_notify_test_chr_2_def_handle); + TEST_ASSERT(flags == 0); + + /* Ensure CCCD still persisted. */ + TEST_ASSERT(ble_hs_test_util_num_cccds() == 1); + + /* Verify 'updated' state is no longer persisted. */ + rc = ble_store_read_cccd(&key_cccd, &value_cccd); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(!value_cccd.value_changed); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatts_notify_test_disallowed) +{ + uint16_t chr1_val_handle; + uint16_t chr2_val_handle; + uint16_t chr3_val_handle; + + const struct ble_gatt_svc_def svcs[] = { { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(0x1234), + .characteristics = (struct ble_gatt_chr_def[]) { { + .uuid = BLE_UUID16_DECLARE(1), + .access_cb = ble_gatts_notify_test_misc_access, + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY, + .val_handle = &chr1_val_handle, + }, { + .uuid = BLE_UUID16_DECLARE(2), + .access_cb = ble_gatts_notify_test_misc_access, + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_INDICATE, + .val_handle = &chr2_val_handle, + }, { + .uuid = BLE_UUID16_DECLARE(3), + .access_cb = ble_gatts_notify_test_misc_access, + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | + BLE_GATT_CHR_F_INDICATE, + .val_handle = &chr3_val_handle, + }, { + 0 + } }, + }, { + 0 + } }; + + ble_hs_test_util_init(); + + ble_hs_test_util_reg_svcs(svcs, NULL, NULL); + TEST_ASSERT_FATAL(chr1_val_handle != 0); + TEST_ASSERT_FATAL(chr2_val_handle != 0); + TEST_ASSERT_FATAL(chr3_val_handle != 0); + + ble_hs_test_util_create_conn(2, ble_gatts_notify_test_peer_addr, + ble_gatts_notify_test_util_gap_event, NULL); + + /* Attempt to enable notifications on chr1 should succeed. */ + ble_gatts_notify_test_misc_try_enable_notify( + 2, chr1_val_handle - 1, BLE_GATTS_CLT_CFG_F_NOTIFY, 0); + + /* Attempt to enable indications on chr1 should fail. */ + ble_gatts_notify_test_misc_try_enable_notify( + 2, chr1_val_handle - 1, BLE_GATTS_CLT_CFG_F_INDICATE, 1); + + /* Attempt to enable notifications on chr2 should fail. */ + ble_gatts_notify_test_misc_try_enable_notify( + 2, chr2_val_handle - 1, BLE_GATTS_CLT_CFG_F_NOTIFY, 1); + + /* Attempt to enable indications on chr2 should succeed. */ + ble_gatts_notify_test_misc_try_enable_notify( + 2, chr2_val_handle - 1, BLE_GATTS_CLT_CFG_F_INDICATE, 0); + + /* Attempt to enable notifications on chr3 should succeed. */ + ble_gatts_notify_test_misc_try_enable_notify( + 2, chr3_val_handle - 1, BLE_GATTS_CLT_CFG_F_NOTIFY, 0); + + /* Attempt to enable indications on chr3 should succeed. */ + ble_gatts_notify_test_misc_try_enable_notify( + 2, chr3_val_handle - 1, BLE_GATTS_CLT_CFG_F_INDICATE, 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_gatts_notify_suite) +{ + ble_gatts_notify_test_n(); + ble_gatts_notify_test_i(); + + ble_gatts_notify_test_bonded_n(); + ble_gatts_notify_test_bonded_i(); + + ble_gatts_notify_test_bonded_i_no_ack(); + + ble_gatts_notify_test_disallowed(); + + /* XXX: Test corner cases: + * o Bonding after CCCD configuration. + * o Disconnect prior to rx of indicate ack. + */ +} diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_gatts_read_test.c b/src/libs/mynewt-nimble/nimble/host/test/src/ble_gatts_read_test.c new file mode 100644 index 00000000..381b39ad --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_gatts_read_test.c @@ -0,0 +1,257 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include "testutil/testutil.h" +#include "host/ble_uuid.h" +#include "ble_hs_test.h" +#include "ble_hs_test_util.h" + +#define BLE_GATTS_READ_TEST_CHR_1_UUID 0x1111 +#define BLE_GATTS_READ_TEST_CHR_2_UUID 0x2222 + +static uint8_t ble_gatts_read_test_peer_addr[6] = {2,3,4,5,6,7}; + +static int +ble_gatts_read_test_util_access_1(uint16_t conn_handle, + uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg); + +static int +ble_gatts_read_test_util_access_2(uint16_t conn_handle, + uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg); +static void +ble_gatts_read_test_misc_reg_cb(struct ble_gatt_register_ctxt *ctxt, + void *arg); + +static const struct ble_gatt_svc_def ble_gatts_read_test_svcs[] = { { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(0x1234), + .characteristics = (struct ble_gatt_chr_def[]) { { + .uuid = BLE_UUID16_DECLARE(BLE_GATTS_READ_TEST_CHR_1_UUID), + .access_cb = ble_gatts_read_test_util_access_1, + .flags = BLE_GATT_CHR_F_READ + }, { + .uuid = BLE_UUID16_DECLARE(BLE_GATTS_READ_TEST_CHR_2_UUID), + .access_cb = ble_gatts_read_test_util_access_2, + .flags = BLE_GATT_CHR_F_READ + }, { + 0 + } }, +}, { + 0 +} }; + +static uint16_t ble_gatts_read_test_chr_1_def_handle; +static uint16_t ble_gatts_read_test_chr_1_val_handle; +static uint8_t ble_gatts_read_test_chr_1_val[1024]; +static int ble_gatts_read_test_chr_1_len; +static uint16_t ble_gatts_read_test_chr_2_def_handle; +static uint16_t ble_gatts_read_test_chr_2_val_handle; + +static void +ble_gatts_read_test_misc_init(uint16_t *out_conn_handle) +{ + ble_hs_test_util_init(); + + ble_hs_test_util_reg_svcs(ble_gatts_read_test_svcs, + ble_gatts_read_test_misc_reg_cb, + NULL); + TEST_ASSERT_FATAL(ble_gatts_read_test_chr_1_def_handle != 0); + TEST_ASSERT_FATAL(ble_gatts_read_test_chr_1_val_handle == + ble_gatts_read_test_chr_1_def_handle + 1); + TEST_ASSERT_FATAL(ble_gatts_read_test_chr_2_def_handle != 0); + TEST_ASSERT_FATAL(ble_gatts_read_test_chr_2_val_handle == + ble_gatts_read_test_chr_2_def_handle + 1); + + ble_hs_test_util_create_conn(2, ble_gatts_read_test_peer_addr, NULL, NULL); + + if (out_conn_handle != NULL) { + *out_conn_handle = 2; + } +} + +static void +ble_gatts_read_test_misc_reg_cb(struct ble_gatt_register_ctxt *ctxt, + void *arg) +{ + uint16_t uuid16; + + if (ctxt->op == BLE_GATT_REGISTER_OP_CHR) { + uuid16 = ble_uuid_u16(ctxt->chr.chr_def->uuid); + switch (uuid16) { + case BLE_GATTS_READ_TEST_CHR_1_UUID: + ble_gatts_read_test_chr_1_def_handle = ctxt->chr.def_handle; + ble_gatts_read_test_chr_1_val_handle = ctxt->chr.val_handle; + break; + + case BLE_GATTS_READ_TEST_CHR_2_UUID: + ble_gatts_read_test_chr_2_def_handle = ctxt->chr.def_handle; + ble_gatts_read_test_chr_2_val_handle = ctxt->chr.val_handle; + break; + + default: + TEST_ASSERT_FATAL(0); + break; + } + } +} + +static int +ble_gatts_read_test_util_access_1(uint16_t conn_handle, + uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg) +{ + int rc; + + TEST_ASSERT_FATAL(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR); + TEST_ASSERT_FATAL(attr_handle == ble_gatts_read_test_chr_1_val_handle); + + TEST_ASSERT(ctxt->chr == + &ble_gatts_read_test_svcs[0].characteristics[0]); + + rc = os_mbuf_append(ctxt->om, ble_gatts_read_test_chr_1_val, + ble_gatts_read_test_chr_1_len); + TEST_ASSERT(rc == 0); + + return 0; +} + +static int +ble_gatts_read_test_util_access_2(uint16_t conn_handle, + uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg) +{ + uint8_t *buf; + + TEST_ASSERT_FATAL(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR); + TEST_ASSERT_FATAL(attr_handle == ble_gatts_read_test_chr_2_def_handle + 1); + + TEST_ASSERT(ctxt->chr == + &ble_gatts_read_test_svcs[0].characteristics[1]); + + buf = os_mbuf_extend(ctxt->om, 6); + TEST_ASSERT_FATAL(buf != NULL); + + buf[0] = 0; + buf[1] = 10; + buf[2] = 20; + buf[3] = 30; + buf[4] = 40; + buf[5] = 50; + + return 0; +} + +static void +ble_gatts_read_test_once(uint16_t conn_handle, uint16_t attr_id, + void *expected_value, uint16_t expected_len) +{ + struct ble_att_read_req read_req; + uint8_t buf[BLE_ATT_READ_REQ_SZ]; + int rc; + + read_req.barq_handle = attr_id; + ble_att_read_req_write(buf, sizeof buf, &read_req); + + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, sizeof buf); + TEST_ASSERT(rc == 0); + + ble_hs_test_util_verify_tx_read_rsp(expected_value, expected_len); +} + +TEST_CASE_SELF(ble_gatts_read_test_case_basic) +{ + uint16_t conn_handle; + + ble_gatts_read_test_misc_init(&conn_handle); + + /*** Application points attribute at static data. */ + ble_gatts_read_test_chr_1_val[0] = 1; + ble_gatts_read_test_chr_1_val[1] = 2; + ble_gatts_read_test_chr_1_val[2] = 3; + ble_gatts_read_test_chr_1_len = 3; + ble_gatts_read_test_once(conn_handle, + ble_gatts_read_test_chr_1_val_handle, + ble_gatts_read_test_chr_1_val, + ble_gatts_read_test_chr_1_len); + + /*** Application uses stack-provided buffer for dynamic attribute. */ + ble_gatts_read_test_once(conn_handle, + ble_gatts_read_test_chr_2_def_handle + 1, + ((uint8_t[6]){0,10,20,30,40,50}), 6); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatts_read_test_case_long) +{ + struct ble_att_read_blob_req read_blob_req; + struct ble_att_read_req read_req; + uint8_t buf[max(BLE_ATT_READ_REQ_SZ, BLE_ATT_READ_BLOB_REQ_SZ)]; + uint16_t conn_handle; + int rc; + int i; + + ble_gatts_read_test_misc_init(&conn_handle); + + /*** Prepare characteristic value. */ + ble_gatts_read_test_chr_1_len = 40; + for (i = 0; i < ble_gatts_read_test_chr_1_len; i++) { + ble_gatts_read_test_chr_1_val[i] = i; + } + + /* Receive first read request. */ + read_req.barq_handle = ble_gatts_read_test_chr_1_val_handle; + ble_att_read_req_write(buf, sizeof buf, &read_req); + + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, sizeof buf); + TEST_ASSERT(rc == 0); + + ble_hs_test_util_verify_tx_read_rsp(ble_gatts_read_test_chr_1_val, 22); + + /* Receive follow-up read blob request. */ + read_blob_req.babq_handle = ble_gatts_read_test_chr_1_val_handle; + read_blob_req.babq_offset = 22; + ble_att_read_blob_req_write(buf, sizeof buf, &read_blob_req); + + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, sizeof buf); + TEST_ASSERT(rc == 0); + + /* Ensure response starts at appropriate offset (22). */ + ble_hs_test_util_verify_tx_read_blob_rsp( + ble_gatts_read_test_chr_1_val + 22, 18); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_gatts_read_test_suite) +{ + ble_gatts_read_test_case_basic(); + ble_gatts_read_test_case_long(); +} diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_gatts_reg_test.c b/src/libs/mynewt-nimble/nimble/host/test/src/ble_gatts_reg_test.c new file mode 100644 index 00000000..ea69028e --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_gatts_reg_test.c @@ -0,0 +1,719 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include "testutil/testutil.h" +#include "nimble/ble.h" +#include "host/ble_uuid.h" +#include "ble_hs_test.h" +#include "ble_hs_test_util.h" + +#define BLE_GATTS_REG_TEST_MAX_ENTRIES 256 + +struct ble_gatts_reg_test_entry { + uint8_t op; + ble_uuid_any_t uuid; + uint16_t handle; + uint16_t val_handle; /* If a characteristic. */ + + const struct ble_gatt_svc_def *svc; + const struct ble_gatt_chr_def *chr; + const struct ble_gatt_dsc_def *dsc; +}; + +static struct ble_gatts_reg_test_entry +ble_gatts_reg_test_entries[BLE_GATTS_REG_TEST_MAX_ENTRIES]; + +static int ble_gatts_reg_test_num_entries; + +static void +ble_gatts_reg_test_init(void) +{ + ble_hs_test_util_init(); + ble_gatts_reg_test_num_entries = 0; +} + +static void +ble_gatts_reg_test_misc_reg_cb(struct ble_gatt_register_ctxt *ctxt, void *arg) +{ + struct ble_gatts_reg_test_entry *entry; + + TEST_ASSERT_FATAL(ble_gatts_reg_test_num_entries < + BLE_GATTS_REG_TEST_MAX_ENTRIES); + + entry = ble_gatts_reg_test_entries + ble_gatts_reg_test_num_entries++; + memset(entry, 0, sizeof *entry); + + entry->op = ctxt->op; + switch (ctxt->op) { + case BLE_GATT_REGISTER_OP_SVC: + ble_uuid_to_any(ctxt->svc.svc_def->uuid, &entry->uuid); + entry->handle = ctxt->svc.handle; + entry->svc = ctxt->svc.svc_def; + break; + + case BLE_GATT_REGISTER_OP_CHR: + ble_uuid_to_any(ctxt->chr.chr_def->uuid, &entry->uuid); + entry->handle = ctxt->chr.def_handle; + entry->val_handle = ctxt->chr.val_handle; + entry->svc = ctxt->chr.svc_def; + entry->chr = ctxt->chr.chr_def; + break; + + case BLE_GATT_REGISTER_OP_DSC: + ble_uuid_to_any(ctxt->dsc.dsc_def->uuid, &entry->uuid); + entry->handle = ctxt->dsc.handle; + entry->svc = ctxt->dsc.svc_def; + entry->chr = ctxt->dsc.chr_def; + entry->dsc = ctxt->dsc.dsc_def; + break; + + default: + TEST_ASSERT(0); + break; + } +} + +static void +ble_gatts_reg_test_misc_lookup_good(struct ble_gatts_reg_test_entry *entry) +{ + uint16_t chr_def_handle; + uint16_t chr_val_handle; + uint16_t svc_handle; + uint16_t dsc_handle; + int rc; + + switch (entry->op) { + case BLE_GATT_REGISTER_OP_SVC: + rc = ble_gatts_find_svc(&entry->uuid.u, &svc_handle); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(svc_handle == entry->handle); + break; + + case BLE_GATT_REGISTER_OP_CHR: + rc = ble_gatts_find_chr(entry->svc->uuid, entry->chr->uuid, + &chr_def_handle, &chr_val_handle); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(chr_def_handle == entry->handle); + TEST_ASSERT(chr_val_handle == entry->val_handle); + break; + + case BLE_GATT_REGISTER_OP_DSC: + rc = ble_gatts_find_dsc(entry->svc->uuid, entry->chr->uuid, + entry->dsc->uuid, &dsc_handle); + break; + + default: + TEST_ASSERT(0); + break; + } +} + +static void +ble_gatts_reg_test_misc_lookup_bad(struct ble_gatts_reg_test_entry *entry) +{ + struct ble_gatts_reg_test_entry *cur; + ble_uuid_any_t wrong_uuid; + int rc; + int i; + + switch (entry->op) { + case BLE_GATT_REGISTER_OP_SVC: + /* Wrong service UUID. */ + ble_uuid_to_any(entry->svc->uuid, &wrong_uuid); + wrong_uuid.u16.value++; + rc = ble_gatts_find_svc(&wrong_uuid.u, NULL); + TEST_ASSERT(rc == BLE_HS_ENOENT); + break; + + case BLE_GATT_REGISTER_OP_CHR: + /* Correct service UUID, wrong characteristic UUID. */ + ble_uuid_to_any(entry->chr->uuid, &wrong_uuid); + wrong_uuid.u16.value++; + rc = ble_gatts_find_chr(entry->svc->uuid, &wrong_uuid.u, NULL, NULL); + TEST_ASSERT(rc == BLE_HS_ENOENT); + + /* Incorrect service UUID, correct characteristic UUID. */ + ble_uuid_to_any(entry->svc->uuid, &wrong_uuid); + wrong_uuid.u16.value++; + rc = ble_gatts_find_chr(&wrong_uuid.u, entry->chr->uuid, NULL, NULL); + TEST_ASSERT(rc == BLE_HS_ENOENT); + + /* Existing (but wrong) service, correct characteristic UUID. */ + for (i = 0; i < ble_gatts_reg_test_num_entries; i++) { + cur = ble_gatts_reg_test_entries + i; + switch (cur->op) { + case BLE_GATT_REGISTER_OP_SVC: + if (cur->svc != entry->svc) { + rc = ble_gatts_find_chr(cur->svc->uuid, + entry->chr->uuid, + NULL, NULL); + TEST_ASSERT(rc == BLE_HS_ENOENT); + } + break; + + case BLE_GATT_REGISTER_OP_CHR: + /* Characteristic that isn't in this service. */ + if (cur->svc != entry->svc) { + rc = ble_gatts_find_chr(entry->svc->uuid, + cur->chr->uuid, + NULL, NULL); + TEST_ASSERT(rc == BLE_HS_ENOENT); + } + break; + + case BLE_GATT_REGISTER_OP_DSC: + /* Use descriptor UUID instead of characteristic UUID. */ + rc = ble_gatts_find_chr(entry->svc->uuid, + cur->dsc->uuid, + NULL, NULL); + TEST_ASSERT(rc == BLE_HS_ENOENT); + break; + + default: + TEST_ASSERT(0); + break; + } + } + break; + + case BLE_GATT_REGISTER_OP_DSC: + /* Correct svc/chr UUID, wrong dsc UUID. */ + ble_uuid_to_any(entry->dsc->uuid, &wrong_uuid); + wrong_uuid.u128.value[15]++; + rc = ble_gatts_find_dsc(entry->svc->uuid, entry->chr->uuid, + &wrong_uuid.u, NULL); + TEST_ASSERT(rc == BLE_HS_ENOENT); + + /* Incorrect svc UUID, correct chr/dsc UUID. */ + ble_uuid_to_any(entry->svc->uuid, &wrong_uuid); + wrong_uuid.u128.value[15]++; + rc = ble_gatts_find_dsc(&wrong_uuid.u, entry->chr->uuid, + entry->dsc->uuid, NULL); + TEST_ASSERT(rc == BLE_HS_ENOENT); + + for (i = 0; i < ble_gatts_reg_test_num_entries; i++) { + cur = ble_gatts_reg_test_entries + i; + switch (cur->op) { + case BLE_GATT_REGISTER_OP_SVC: + /* Existing (but wrong) svc, correct chr/dsc UUID. */ + if (cur->svc != entry->svc) { + rc = ble_gatts_find_dsc(cur->svc->uuid, + entry->chr->uuid, + entry->dsc->uuid, + NULL); + TEST_ASSERT(rc == BLE_HS_ENOENT); + } + break; + + case BLE_GATT_REGISTER_OP_CHR: + /* Existing (but wrong) svc/chr, correct dsc UUID. */ + if (cur->chr != entry->chr) { + rc = ble_gatts_find_dsc(cur->svc->uuid, + cur->chr->uuid, + entry->dsc->uuid, + NULL); + TEST_ASSERT(rc == BLE_HS_ENOENT); + } + break; + + case BLE_GATT_REGISTER_OP_DSC: + /* Descriptor that isn't in this characteristic. */ + if (cur->chr != entry->chr) { + rc = ble_gatts_find_dsc(cur->svc->uuid, + cur->chr->uuid, + entry->dsc->uuid, + NULL); + TEST_ASSERT(rc == BLE_HS_ENOENT); + } + break; + + default: + TEST_ASSERT(0); + break; + } + } + break; + + default: + TEST_ASSERT(0); + break; + } +} + +static void +ble_gatts_reg_test_misc_verify_entry(uint8_t op, const ble_uuid_t *uuid) +{ + struct ble_gatts_reg_test_entry *entry; + int i; + + for (i = 0; i < ble_gatts_reg_test_num_entries; i++) { + entry = ble_gatts_reg_test_entries + i; + if (entry->op == op && ble_uuid_cmp(&entry->uuid.u, uuid) == 0) { + break; + } + } + TEST_ASSERT_FATAL(entry != NULL); + + /* Verify that characteristic value handle was properly assigned at + * registration. + */ + if (op == BLE_GATT_REGISTER_OP_CHR) { + TEST_ASSERT(*entry->chr->val_handle == entry->val_handle); + } + + /* Verify that the entry can be looked up. */ + ble_gatts_reg_test_misc_lookup_good(entry); + + /* Verify that "barely incorrect" UUID information doesn't retrieve any + * handles. + */ + ble_gatts_reg_test_misc_lookup_bad(entry); +} + +static int +ble_gatts_reg_test_misc_dummy_access(uint16_t conn_handle, + uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg) +{ + return 0; +} + +TEST_CASE_SELF(ble_gatts_reg_test_svc_return) +{ + int rc; + + /*** Missing UUID. */ + ble_gatts_reg_test_init(); + struct ble_gatt_svc_def svcs_no_uuid[] = { { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + }, { + 0 + } }; + + rc = ble_gatts_register_svcs(svcs_no_uuid, NULL, NULL); + TEST_ASSERT(rc == BLE_HS_EINVAL); + + /*** Circular dependency. */ + ble_gatts_reg_test_init(); + struct ble_gatt_svc_def svcs_circ[] = { { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(0x1234), + .includes = (const struct ble_gatt_svc_def*[]) { svcs_circ + 1, NULL }, + }, { + .type = BLE_GATT_SVC_TYPE_SECONDARY, + .uuid = BLE_UUID16_DECLARE(0x1234), + .includes = (const struct ble_gatt_svc_def*[]) { svcs_circ + 0, NULL }, + }, { + 0 + } }; + + rc = ble_gatts_register_svcs(svcs_circ, NULL, NULL); + TEST_ASSERT(rc == BLE_HS_EINVAL); + + /*** Success. */ + ble_gatts_reg_test_init(); + struct ble_gatt_svc_def svcs_good[] = { { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(0x1234), + .includes = (const struct ble_gatt_svc_def*[]) { svcs_good + 1, NULL }, + }, { + .type = BLE_GATT_SVC_TYPE_SECONDARY, + .uuid = BLE_UUID16_DECLARE(0x1234), + }, { + 0 + } }; + + rc = ble_gatts_register_svcs(svcs_good, NULL, NULL); + TEST_ASSERT(rc == 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatts_reg_test_chr_return) +{ + int rc; + + /*** Missing callback. */ + ble_gatts_reg_test_init(); + struct ble_gatt_svc_def svcs_no_chr_cb[] = { { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(0x1234), + .characteristics = (struct ble_gatt_chr_def[]) { { + .uuid = BLE_UUID16_DECLARE(0x1111), + .flags = BLE_GATT_CHR_F_READ, + }, { + 0 + } }, + }, { + 0 + } }; + + rc = ble_gatts_register_svcs(svcs_no_chr_cb, NULL, NULL); + TEST_ASSERT(rc == BLE_HS_EINVAL); + + /*** Success. */ + ble_gatts_reg_test_init(); + struct ble_gatt_svc_def svcs_good[] = { { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(0x1234), + .characteristics = (struct ble_gatt_chr_def[]) { { + .uuid = BLE_UUID16_DECLARE(0x1111), + .access_cb = ble_gatts_reg_test_misc_dummy_access, + .flags = BLE_GATT_CHR_F_READ, + }, { + 0 + } }, + }, { + 0 + } }; + + rc = ble_gatts_register_svcs(svcs_good, NULL, NULL); + TEST_ASSERT(rc == 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatts_reg_test_dsc_return) +{ + int rc; + + /*** Missing callback. */ + ble_gatts_reg_test_init(); + struct ble_gatt_svc_def svcs_no_dsc_cb[] = { { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(0x1234), + .characteristics = (struct ble_gatt_chr_def[]) { { + .uuid = BLE_UUID16_DECLARE(0x1111), + .access_cb = ble_gatts_reg_test_misc_dummy_access, + .flags = BLE_GATT_CHR_F_READ, + .descriptors = (struct ble_gatt_dsc_def[]) { { + .uuid = BLE_UUID16_DECLARE(0x8888), + .att_flags = 5, + }, { + 0 + } }, + }, { + 0 + } }, + }, { + 0 + } }; + + rc = ble_gatts_register_svcs(svcs_no_dsc_cb, NULL, NULL); + TEST_ASSERT(rc == BLE_HS_EINVAL); + + /*** Success. */ + ble_gatts_reg_test_init(); + struct ble_gatt_svc_def svcs_good[] = { { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(0x1234), + .characteristics = (struct ble_gatt_chr_def[]) { { + .uuid = BLE_UUID16_DECLARE(0x1111), + .access_cb = ble_gatts_reg_test_misc_dummy_access, + .flags = BLE_GATT_CHR_F_READ, + .descriptors = (struct ble_gatt_dsc_def[]) { { + .uuid = BLE_UUID16_DECLARE(0x8888), + .access_cb = ble_gatts_reg_test_misc_dummy_access, + .att_flags = 5, + }, { + 0 + } }, + }, { + 0 + } }, + }, { + 0 + } }; + + rc = ble_gatts_register_svcs(svcs_good, NULL, NULL); + TEST_ASSERT(rc == 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +static void +ble_gatts_reg_test_misc_svcs(struct ble_gatt_svc_def *svcs) +{ + const struct ble_gatt_svc_def *svc; + const struct ble_gatt_chr_def *chr; + const struct ble_gatt_dsc_def *dsc; + int rc; + + ble_gatts_reg_test_init(); + + /* Register all the attributes. */ + rc = ble_gatts_register_svcs(svcs, ble_gatts_reg_test_misc_reg_cb, + NULL); + TEST_ASSERT_FATAL(rc == 0); + + /* Verify that the appropriate callbacks were executed. */ + for (svc = svcs; svc->type != BLE_GATT_SVC_TYPE_END; svc++) { + ble_gatts_reg_test_misc_verify_entry(BLE_GATT_REGISTER_OP_SVC, + svc->uuid); + + if (svc->characteristics != NULL) { + for (chr = svc->characteristics; chr->uuid != NULL; chr++) { + ble_gatts_reg_test_misc_verify_entry(BLE_GATT_REGISTER_OP_CHR, + chr->uuid); + + if (chr->descriptors != NULL) { + for (dsc = chr->descriptors; dsc->uuid != NULL; dsc++) { + ble_gatts_reg_test_misc_verify_entry( + BLE_GATT_REGISTER_OP_DSC, dsc->uuid); + } + } + } + } + } +} + +TEST_CASE_SELF(ble_gatts_reg_test_svc_cb) +{ + /*** 1 primary. */ + ble_gatts_reg_test_misc_svcs((struct ble_gatt_svc_def[]) { { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(0x1234), + }, { + 0 + } }); + + /*** 3 primary. */ + ble_gatts_reg_test_misc_svcs((struct ble_gatt_svc_def[]) { { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(0x1234), + }, { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(0x2234), + }, { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(0x3234), + }, { + 0 + } }); + + /*** 1 primary, 1 secondary. */ + ble_gatts_reg_test_misc_svcs((struct ble_gatt_svc_def[]) { { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(0x1234), + }, { + .type = BLE_GATT_SVC_TYPE_SECONDARY, + .uuid = BLE_UUID16_DECLARE(0x2222), + }, { + 0 + } }); + + /*** 1 primary, 1 secondary, 1 include. */ + struct ble_gatt_svc_def svcs[] = { + [0] = { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(0x1234), + .includes = (const struct ble_gatt_svc_def*[]) { svcs + 1, NULL, }, + }, + [1] = { + .type = BLE_GATT_SVC_TYPE_SECONDARY, + .uuid = BLE_UUID16_DECLARE(0x2222), + }, { + 0 + } + }; + ble_gatts_reg_test_misc_svcs(svcs); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatts_reg_test_chr_cb) +{ + uint16_t val_handles[16]; + + /*** 1 characteristic. */ + ble_gatts_reg_test_misc_svcs((struct ble_gatt_svc_def[]) { { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(0x1234), + .characteristics = (struct ble_gatt_chr_def[]) { { + .uuid = BLE_UUID16_DECLARE(0x1111), + .access_cb = ble_gatts_reg_test_misc_dummy_access, + .flags = BLE_GATT_CHR_F_READ, + .val_handle = val_handles + 0, + }, { + 0 + } }, + }, { + 0 + } }); + + /*** 3 characteristics. */ + ble_gatts_reg_test_misc_svcs((struct ble_gatt_svc_def[]) { { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(0x1234), + .characteristics = (struct ble_gatt_chr_def[]) { { + .uuid = BLE_UUID16_DECLARE(0x1111), + .access_cb = ble_gatts_reg_test_misc_dummy_access, + .flags = BLE_GATT_CHR_F_READ, + .val_handle = val_handles + 0, + }, { + .uuid = BLE_UUID16_DECLARE(0x2222), + .access_cb = ble_gatts_reg_test_misc_dummy_access, + .flags = BLE_GATT_CHR_F_WRITE, + .val_handle = val_handles + 1, + }, { + 0 + } }, + }, { + .type = BLE_GATT_SVC_TYPE_SECONDARY, + .uuid = BLE_UUID16_DECLARE(0x5678), + .characteristics = (struct ble_gatt_chr_def[]) { { + .uuid = BLE_UUID16_DECLARE(0x3333), + .access_cb = ble_gatts_reg_test_misc_dummy_access, + .flags = BLE_GATT_CHR_F_READ, + .val_handle = val_handles + 2, + }, { + 0 + } }, + }, { + 0 + } }); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_gatts_reg_test_dsc_cb) +{ + uint16_t val_handles[16]; + + /*** 1 descriptor. */ + ble_gatts_reg_test_misc_svcs((struct ble_gatt_svc_def[]) { { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(0x1234), + .characteristics = (struct ble_gatt_chr_def[]) { { + .uuid = BLE_UUID16_DECLARE(0x1111), + .access_cb = ble_gatts_reg_test_misc_dummy_access, + .flags = BLE_GATT_CHR_F_READ, + .val_handle = val_handles + 0, + .descriptors = (struct ble_gatt_dsc_def[]) { { + .uuid = BLE_UUID16_DECLARE(0x111a), + .att_flags = 5, + .access_cb = ble_gatts_reg_test_misc_dummy_access, + }, { + 0 + } }, + }, { + 0 + } }, + }, { + 0 + } }); + + /*** 5+ descriptors. */ + ble_gatts_reg_test_misc_svcs((struct ble_gatt_svc_def[]) { { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(0x1234), + .characteristics = (struct ble_gatt_chr_def[]) { { + .uuid = BLE_UUID16_DECLARE(0x1111), + .access_cb = ble_gatts_reg_test_misc_dummy_access, + .flags = BLE_GATT_CHR_F_READ, + .val_handle = val_handles + 0, + .descriptors = (struct ble_gatt_dsc_def[]) { { + .uuid = BLE_UUID16_DECLARE(0x111a), + .att_flags = 5, + .access_cb = ble_gatts_reg_test_misc_dummy_access, + }, { + 0 + } }, + }, { + .uuid = BLE_UUID16_DECLARE(0x2222), + .access_cb = ble_gatts_reg_test_misc_dummy_access, + .flags = BLE_GATT_CHR_F_WRITE, + .val_handle = val_handles + 1, + }, { + 0 + } }, + }, { + .type = BLE_GATT_SVC_TYPE_SECONDARY, + .uuid = BLE_UUID16_DECLARE(0x5678), + .characteristics = (struct ble_gatt_chr_def[]) { { + .uuid = BLE_UUID16_DECLARE(0x3333), + .access_cb = ble_gatts_reg_test_misc_dummy_access, + .flags = BLE_GATT_CHR_F_READ, + .val_handle = val_handles + 2, + .descriptors = (struct ble_gatt_dsc_def[]) { { + .uuid = BLE_UUID16_DECLARE(0x333a), + .att_flags = 5, + .access_cb = ble_gatts_reg_test_misc_dummy_access, + }, { + .uuid = BLE_UUID16_DECLARE(0x333b), + .att_flags = 5, + .access_cb = ble_gatts_reg_test_misc_dummy_access, + }, { + .uuid = BLE_UUID16_DECLARE(0x333c), + .att_flags = 5, + .access_cb = ble_gatts_reg_test_misc_dummy_access, + }, { + .uuid = BLE_UUID16_DECLARE(0x333e), + .att_flags = 5, + .access_cb = ble_gatts_reg_test_misc_dummy_access, + }, { + 0 + } }, + }, { + .uuid = BLE_UUID16_DECLARE(0x4444), + .access_cb = ble_gatts_reg_test_misc_dummy_access, + .flags = BLE_GATT_CHR_F_READ, + .val_handle = val_handles + 3, + .descriptors = (struct ble_gatt_dsc_def[]) { { + .uuid = BLE_UUID16_DECLARE(0x444a), + .att_flags = 5, + .access_cb = ble_gatts_reg_test_misc_dummy_access, + }, { + .uuid = BLE_UUID16_DECLARE(0x444b), + .att_flags = 5, + .access_cb = ble_gatts_reg_test_misc_dummy_access, + }, { + .uuid = BLE_UUID16_DECLARE(0x444c), + .att_flags = 5, + .access_cb = ble_gatts_reg_test_misc_dummy_access, + }, { + .uuid = BLE_UUID16_DECLARE(0x444e), + .att_flags = 5, + .access_cb = ble_gatts_reg_test_misc_dummy_access, + }, { + 0 + } }, + }, { + 0 + } }, + }, { + 0 + } }); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_gatts_reg_suite) +{ + ble_gatts_reg_test_svc_return(); + ble_gatts_reg_test_chr_return(); + ble_gatts_reg_test_dsc_return(); + + ble_gatts_reg_test_svc_cb(); + ble_gatts_reg_test_chr_cb(); + ble_gatts_reg_test_dsc_cb(); +} diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_adv_test.c b/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_adv_test.c new file mode 100644 index 00000000..b267dc2a --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_adv_test.c @@ -0,0 +1,1280 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include "testutil/testutil.h" +#include "nimble/hci_common.h" +#include "host/ble_hs_adv.h" +#include "ble_hs_test.h" +#include "ble_hs_test_util.h" + +#define BLE_ADV_TEST_DATA_OFF 4 + +#define BLE_HCI_SET_ADV_DATA_LEN (32) +#define BLE_HCI_SET_SCAN_RSP_DATA_LEN (32) + +static void +ble_hs_adv_test_misc_verify_tx_adv_data_hdr(uint8_t *cmd, int data_len) +{ + uint16_t opcode; + + opcode = get_le16(cmd + 0); + TEST_ASSERT(BLE_HCI_OGF(opcode) == BLE_HCI_OGF_LE); + TEST_ASSERT(BLE_HCI_OCF(opcode) == BLE_HCI_OCF_LE_SET_ADV_DATA); + + TEST_ASSERT(cmd[2] == BLE_HCI_SET_ADV_DATA_LEN); + TEST_ASSERT(cmd[3] == data_len); +} + +static void +ble_hs_adv_test_misc_verify_tx_rsp_data_hdr(uint8_t *cmd, int data_len) +{ + uint16_t opcode; + + opcode = get_le16(cmd + 0); + TEST_ASSERT(BLE_HCI_OGF(opcode) == BLE_HCI_OGF_LE); + TEST_ASSERT(BLE_HCI_OCF(opcode) == BLE_HCI_OCF_LE_SET_SCAN_RSP_DATA); + + TEST_ASSERT(cmd[2] == BLE_HCI_SET_SCAN_RSP_DATA_LEN); + TEST_ASSERT(cmd[3] == data_len); +} + +static void +ble_hs_adv_test_misc_verify_tx_field(uint8_t *cmd, uint8_t type, + uint8_t val_len, void *val) +{ + TEST_ASSERT(cmd[0] == val_len + 1); + TEST_ASSERT(cmd[1] == type); + TEST_ASSERT(memcmp(cmd + 2, val, val_len) == 0); +} + +struct ble_hs_adv_test_field { + uint8_t type; /* 0 indicates end of array. */ + uint8_t *val; + uint8_t val_len; +}; + +static int +ble_hs_adv_test_misc_calc_data_len(struct ble_hs_adv_test_field *fields) +{ + struct ble_hs_adv_test_field *field; + int len; + + len = 0; + if (fields != NULL) { + for (field = fields; field->type != 0; field++) { + len += 2 + field->val_len; + } + } + + return len; +} + +static void +ble_hs_adv_test_misc_verify_tx_fields(uint8_t *cmd, + struct ble_hs_adv_test_field *fields) +{ + struct ble_hs_adv_test_field *field; + + for (field = fields; field->type != 0; field++) { + ble_hs_adv_test_misc_verify_tx_field(cmd, field->type, field->val_len, + field->val); + cmd += 2 + field->val_len; + } +} + +static void +ble_hs_adv_test_misc_verify_tx_adv_data(struct ble_hs_adv_test_field *fields) +{ + int data_len; + uint8_t *cmd; + + cmd = ble_hs_test_util_hci_out_last(); + TEST_ASSERT_FATAL(cmd != NULL); + + data_len = ble_hs_adv_test_misc_calc_data_len(fields); + ble_hs_adv_test_misc_verify_tx_adv_data_hdr(cmd, data_len); + if (fields != NULL) { + ble_hs_adv_test_misc_verify_tx_fields(cmd + BLE_ADV_TEST_DATA_OFF, + fields); + } +} + +static void +ble_hs_adv_test_misc_verify_tx_rsp_data(struct ble_hs_adv_test_field *fields) +{ + int data_len; + uint8_t *cmd; + + cmd = ble_hs_test_util_hci_out_last(); + TEST_ASSERT_FATAL(cmd != NULL); + + data_len = ble_hs_adv_test_misc_calc_data_len(fields); + ble_hs_adv_test_misc_verify_tx_rsp_data_hdr(cmd, data_len); + if (fields != NULL) { + ble_hs_adv_test_misc_verify_tx_fields(cmd + BLE_ADV_TEST_DATA_OFF, + fields); + } +} + +static void +ble_hs_adv_test_misc_tx_and_verify_data( + uint8_t disc_mode, + struct ble_hs_adv_fields *adv_fields, + struct ble_hs_adv_test_field *test_adv_fields, + struct ble_hs_adv_fields *rsp_fields, + struct ble_hs_adv_test_field *test_rsp_fields) +{ + struct ble_gap_adv_params adv_params; + int rc; + + ble_hs_test_util_init(); + + adv_params = ble_hs_test_util_adv_params; + adv_params.disc_mode = disc_mode; + + rc = ble_hs_test_util_adv_set_fields(adv_fields, 0, 0); + TEST_ASSERT_FATAL(rc == 0); + ble_hs_adv_test_misc_verify_tx_adv_data(test_adv_fields); + + if (test_rsp_fields != NULL) { + rc = ble_hs_test_util_adv_rsp_set_fields(rsp_fields, 0, 0); + TEST_ASSERT_FATAL(rc == 0); + ble_hs_adv_test_misc_verify_tx_rsp_data(test_rsp_fields); + } + + rc = ble_hs_test_util_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, &adv_params, + BLE_HS_FOREVER, NULL, NULL, 0, 0); + TEST_ASSERT_FATAL(rc == 0); + + /* Discard the adv-enable command. */ + ble_hs_test_util_hci_out_last(); + + /* Ensure the same data gets sent on repeated advertise procedures. */ + rc = ble_hs_test_util_adv_stop(0); + TEST_ASSERT_FATAL(rc == 0); + + rc = ble_hs_test_util_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, &adv_params, + BLE_HS_FOREVER, NULL, NULL, 0, 0); + TEST_ASSERT_FATAL(rc == 0); + + /* Discard the adv-enable command. */ + ble_hs_test_util_hci_out_last(); +} + +TEST_CASE_SELF(ble_hs_adv_test_case_user) +{ + struct ble_hs_adv_fields adv_fields; + struct ble_hs_adv_fields rsp_fields; + + memset(&rsp_fields, 0, sizeof rsp_fields); + + /*** Complete 16-bit service class UUIDs. */ + memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags = BLE_HS_ADV_F_BREDR_UNSUP; + adv_fields.tx_pwr_lvl_is_present = 1; + adv_fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO; + adv_fields.uuids16 = (ble_uuid16_t[]) { + BLE_UUID16_INIT(0x0001), + BLE_UUID16_INIT(0x1234), + BLE_UUID16_INIT(0x54ab) + }; + adv_fields.num_uuids16 = 3; + adv_fields.uuids16_is_complete = 1; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_COMP_UUIDS16, + .val = (uint8_t[]) { 0x01, 0x00, 0x34, 0x12, 0xab, 0x54 }, + .val_len = 6, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { 0 }, + }, &rsp_fields, NULL); + + /*** Incomplete 16-bit service class UUIDs. */ + memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags = BLE_HS_ADV_F_BREDR_UNSUP; + adv_fields.tx_pwr_lvl_is_present = 1; + adv_fields.uuids16 = (ble_uuid16_t[]) { + BLE_UUID16_INIT(0x0001), + BLE_UUID16_INIT(0x1234), + BLE_UUID16_INIT(0x54ab) + }; + adv_fields.num_uuids16 = 3; + adv_fields.uuids16_is_complete = 0; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_INCOMP_UUIDS16, + .val = (uint8_t[]) { 0x01, 0x00, 0x34, 0x12, 0xab, 0x54 }, + .val_len = 6, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { 0 }, + }, &rsp_fields, NULL); + + /*** Complete 32-bit service class UUIDs. */ + memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags = BLE_HS_ADV_F_BREDR_UNSUP; + adv_fields.tx_pwr_lvl_is_present = 1; + adv_fields.uuids32 = (ble_uuid32_t[]) { + BLE_UUID32_INIT(0x12345678), + BLE_UUID32_INIT(0xabacadae) + }; + adv_fields.num_uuids32 = 2; + adv_fields.uuids32_is_complete = 1; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_COMP_UUIDS32, + .val = (uint8_t[]) { 0x78,0x56,0x34,0x12,0xae,0xad,0xac,0xab }, + .val_len = 8, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { 0 }, + }, &rsp_fields, NULL); + + /*** Incomplete 32-bit service class UUIDs. */ + memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags = BLE_HS_ADV_F_BREDR_UNSUP; + adv_fields.tx_pwr_lvl_is_present = 1; + adv_fields.uuids32 = (ble_uuid32_t[]) { + BLE_UUID32_INIT(0x12345678), + BLE_UUID32_INIT(0xabacadae) + }; + adv_fields.num_uuids32 = 2; + adv_fields.uuids32_is_complete = 0; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_INCOMP_UUIDS32, + .val = (uint8_t[]) { 0x78,0x56,0x34,0x12,0xae,0xad,0xac,0xab }, + .val_len = 8, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { 0 }, + }, &rsp_fields, NULL); + + /*** Complete 128-bit service class UUIDs. */ + memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags = BLE_HS_ADV_F_BREDR_UNSUP; + adv_fields.tx_pwr_lvl_is_present = 1; + adv_fields.uuids128 = (ble_uuid128_t[]) { + BLE_UUID128_INIT(0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff) + }; + adv_fields.num_uuids128 = 1; + adv_fields.uuids128_is_complete = 1; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_COMP_UUIDS128, + .val = (uint8_t[]) { + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, + }, + .val_len = 16, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { 0 }, + }, &rsp_fields, NULL); + + /*** Incomplete 128-bit service class UUIDs. */ + memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags = BLE_HS_ADV_F_BREDR_UNSUP; + adv_fields.tx_pwr_lvl_is_present = 1; + adv_fields.uuids128 = BLE_UUID128(BLE_UUID128_DECLARE( + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, + )); + adv_fields.num_uuids128 = 1; + adv_fields.uuids128_is_complete = 0; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_INCOMP_UUIDS128, + .val = (uint8_t[]) { + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, + }, + .val_len = 16, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { 0 }, + }, &rsp_fields, NULL); + + /*** Complete name. */ + memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags = BLE_HS_ADV_F_BREDR_UNSUP; + adv_fields.tx_pwr_lvl_is_present = 1; + adv_fields.name = (uint8_t *)"myname"; + adv_fields.name_len = 6; + adv_fields.name_is_complete = 1; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_COMP_NAME, + .val = (uint8_t*)"myname", + .val_len = 6, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { 0 }, + }, &rsp_fields, NULL); + + /*** Incomplete name. */ + memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags = BLE_HS_ADV_F_BREDR_UNSUP; + adv_fields.tx_pwr_lvl_is_present = 1; + adv_fields.name = (uint8_t *)"myname"; + adv_fields.name_len = 6; + adv_fields.name_is_complete = 0; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_INCOMP_NAME, + .val = (uint8_t*)"myname", + .val_len = 6, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { 0 }, + }, &rsp_fields, NULL); + + /*** Slave interval range. */ + memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags = BLE_HS_ADV_F_BREDR_UNSUP; + adv_fields.tx_pwr_lvl_is_present = 1; + adv_fields.slave_itvl_range = (uint8_t[]){ 1,2,3,4 }; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE, + .val = (uint8_t[]) { 1,2,3,4 }, + .val_len = BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN, + }, + { 0 }, + }, &rsp_fields, NULL); + + /*** 0x16 - Service data - 16-bit UUID. */ + memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags = BLE_HS_ADV_F_BREDR_UNSUP; + adv_fields.tx_pwr_lvl_is_present = 1; + adv_fields.svc_data_uuid16 = (uint8_t[]){ 1,2,3,4 }; + adv_fields.svc_data_uuid16_len = 4; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_SVC_DATA_UUID16, + .val = (uint8_t[]) { 1,2,3,4 }, + .val_len = 4, + }, + { 0 }, + }, &rsp_fields, NULL); + + /*** 0x17 - Public target address. */ + memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags = BLE_HS_ADV_F_BREDR_UNSUP; + adv_fields.tx_pwr_lvl_is_present = 1; + adv_fields.public_tgt_addr = (uint8_t[]){ 1,2,3,4,5,6, 6,5,4,3,2,1 }; + adv_fields.num_public_tgt_addrs = 2; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR, + .val = (uint8_t[]){ 1,2,3,4,5,6, 6,5,4,3,2,1 }, + .val_len = 2 * BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN, + }, + { 0 }, + }, &rsp_fields, NULL); + + /*** 0x19 - Appearance. */ + memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags = BLE_HS_ADV_F_BREDR_UNSUP; + adv_fields.tx_pwr_lvl_is_present = 1; + adv_fields.appearance = 0x1234; + adv_fields.appearance_is_present = 1; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_APPEARANCE, + .val = (uint8_t[]){ 0x34, 0x12 }, + .val_len = BLE_HS_ADV_APPEARANCE_LEN, + }, + { 0 }, + }, &rsp_fields, NULL); + + /*** 0x1a - Advertising interval. */ + memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags = BLE_HS_ADV_F_BREDR_UNSUP; + adv_fields.tx_pwr_lvl_is_present = 1; + adv_fields.adv_itvl = 0x1234; + adv_fields.adv_itvl_is_present = 1; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_ADV_ITVL, + .val = (uint8_t[]){ 0x34, 0x12 }, + .val_len = BLE_HS_ADV_ADV_ITVL_LEN, + }, + { 0 }, + }, &rsp_fields, NULL); + + /*** 0x20 - Service data - 32-bit UUID. */ + memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags = BLE_HS_ADV_F_BREDR_UNSUP; + adv_fields.tx_pwr_lvl_is_present = 1; + adv_fields.svc_data_uuid32 = (uint8_t[]){ 1,2,3,4,5 }; + adv_fields.svc_data_uuid32_len = 5; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_SVC_DATA_UUID32, + .val = (uint8_t[]) { 1,2,3,4,5 }, + .val_len = 5, + }, + { 0 }, + }, &rsp_fields, NULL); + + /*** 0x21 - Service data - 128-bit UUID. */ + memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags = BLE_HS_ADV_F_BREDR_UNSUP; + adv_fields.tx_pwr_lvl_is_present = 1; + adv_fields.svc_data_uuid128 = + (uint8_t[]){ 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18 }; + adv_fields.svc_data_uuid128_len = 18; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_SVC_DATA_UUID128, + .val = (uint8_t[]){ 1,2,3,4,5,6,7,8,9,10, + 11,12,13,14,15,16,17,18 }, + .val_len = 18, + }, + { 0 }, + }, &rsp_fields, NULL); + + /*** 0x24 - URI. */ + memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags = BLE_HS_ADV_F_BREDR_UNSUP; + adv_fields.tx_pwr_lvl_is_present = 1; + adv_fields.uri = (uint8_t[]){ 1,2,3,4 }; + adv_fields.uri_len = 4; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_URI, + .val = (uint8_t[]) { 1,2,3,4 }, + .val_len = 4, + }, + { 0 }, + }, &rsp_fields, NULL); + + /*** 0xff - Manufacturer specific data. */ + memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags = BLE_HS_ADV_F_BREDR_UNSUP; + adv_fields.tx_pwr_lvl_is_present = 1; + adv_fields.mfg_data = (uint8_t[]){ 1,2,3,4 }; + adv_fields.mfg_data_len = 4; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_MFG_DATA, + .val = (uint8_t[]) { 1,2,3,4 }, + .val_len = 4, + }, + { 0 }, + }, &rsp_fields, NULL); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_hs_adv_test_case_user_rsp) +{ + struct ble_hs_adv_fields rsp_fields; + struct ble_hs_adv_fields adv_fields; + + memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.flags = BLE_HS_ADV_F_BREDR_UNSUP; + adv_fields.tx_pwr_lvl_is_present = 1; + + /*** Complete 16-bit service class UUIDs. */ + memset(&rsp_fields, 0, sizeof rsp_fields); + rsp_fields.uuids16 = (ble_uuid16_t[]) { + BLE_UUID16_INIT(0x0001), + BLE_UUID16_INIT(0x1234), + BLE_UUID16_INIT(0x54ab) + }; + rsp_fields.num_uuids16 = 3; + rsp_fields.uuids16_is_complete = 1; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { 0 }, + }, + &rsp_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_COMP_UUIDS16, + .val = (uint8_t[]) { 0x01, 0x00, 0x34, 0x12, 0xab, 0x54 }, + .val_len = 6, + }, + { 0 }, + }); + + /*** Incomplete 16-bit service class UUIDs. */ + memset(&rsp_fields, 0, sizeof rsp_fields); + rsp_fields.uuids16 = (ble_uuid16_t[]) { + BLE_UUID16_INIT(0x0001), + BLE_UUID16_INIT(0x1234), + BLE_UUID16_INIT(0x54ab) + }; + rsp_fields.num_uuids16 = 3; + rsp_fields.uuids16_is_complete = 0; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { 0 }, + }, + &rsp_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_INCOMP_UUIDS16, + .val = (uint8_t[]) { 0x01, 0x00, 0x34, 0x12, 0xab, 0x54 }, + .val_len = 6, + }, + { 0 }, + }); + + /*** Complete 32-bit service class UUIDs. */ + memset(&rsp_fields, 0, sizeof rsp_fields); + rsp_fields.uuids32 = (ble_uuid32_t[]) { + BLE_UUID32_INIT(0x12345678), + BLE_UUID32_INIT(0xabacadae) + }; + rsp_fields.num_uuids32 = 2; + rsp_fields.uuids32_is_complete = 1; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { 0 }, + }, + &rsp_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_COMP_UUIDS32, + .val = (uint8_t[]) { 0x78,0x56,0x34,0x12,0xae,0xad,0xac,0xab }, + .val_len = 8, + }, + { 0 }, + }); + + /*** Incomplete 32-bit service class UUIDs. */ + memset(&rsp_fields, 0, sizeof rsp_fields); + rsp_fields.uuids32 = (ble_uuid32_t[]) { + BLE_UUID32_INIT(0x12345678), + BLE_UUID32_INIT(0xabacadae) + }; + rsp_fields.num_uuids32 = 2; + rsp_fields.uuids32_is_complete = 0; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { 0 }, + }, + &rsp_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_INCOMP_UUIDS32, + .val = (uint8_t[]) { 0x78,0x56,0x34,0x12,0xae,0xad,0xac,0xab }, + .val_len = 8, + }, + { 0 }, + }); + + /*** Complete 128-bit service class UUIDs. */ + memset(&rsp_fields, 0, sizeof rsp_fields); + rsp_fields.uuids128 = (ble_uuid128_t[]) { + BLE_UUID128_INIT(0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff) + }; + rsp_fields.num_uuids128 = 1; + rsp_fields.uuids128_is_complete = 1; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { 0 }, + }, + &rsp_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_COMP_UUIDS128, + .val = (uint8_t[]) { + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, + }, + .val_len = 16, + }, + { 0 }, + }); + + /*** Incomplete 128-bit service class UUIDs. */ + memset(&rsp_fields, 0, sizeof rsp_fields); + rsp_fields.uuids128 = (ble_uuid128_t[]) { + BLE_UUID128_INIT(0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff) + }; + rsp_fields.num_uuids128 = 1; + rsp_fields.uuids128_is_complete = 0; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { 0 }, + }, + &rsp_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_INCOMP_UUIDS128, + .val = (uint8_t[]) { + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, + }, + .val_len = 16, + }, + { 0 }, + }); + + /*** Complete name. */ + memset(&rsp_fields, 0, sizeof rsp_fields); + rsp_fields.name = (uint8_t *)"myname"; + rsp_fields.name_len = 6; + rsp_fields.name_is_complete = 1; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { 0 }, + }, + &rsp_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_COMP_NAME, + .val = (uint8_t*)"myname", + .val_len = 6, + }, + { 0 }, + }); + + /*** Incomplete name. */ + memset(&rsp_fields, 0, sizeof rsp_fields); + rsp_fields.name = (uint8_t *)"myname"; + rsp_fields.name_len = 6; + rsp_fields.name_is_complete = 0; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { 0 }, + }, + &rsp_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_INCOMP_NAME, + .val = (uint8_t*)"myname", + .val_len = 6, + }, + { 0 }, + }); + + /*** Slave interval range. */ + memset(&rsp_fields, 0, sizeof rsp_fields); + rsp_fields.slave_itvl_range = (uint8_t[]){ 1,2,3,4 }; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { 0 }, + }, + &rsp_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE, + .val = (uint8_t[]) { 1,2,3,4 }, + .val_len = BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN, + }, + { 0 }, + }); + + /*** 0x16 - Service data - 16-bit UUID. */ + memset(&rsp_fields, 0, sizeof rsp_fields); + rsp_fields.svc_data_uuid16 = (uint8_t[]){ 1,2,3,4 }; + rsp_fields.svc_data_uuid16_len = 4; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { 0 }, + }, + &rsp_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_SVC_DATA_UUID16, + .val = (uint8_t[]) { 1,2,3,4 }, + .val_len = 4, + }, + { 0 }, + }); + + /*** 0x17 - Public target address. */ + memset(&rsp_fields, 0, sizeof rsp_fields); + rsp_fields.public_tgt_addr = (uint8_t[]){ 1,2,3,4,5,6, 6,5,4,3,2,1 }; + rsp_fields.num_public_tgt_addrs = 2; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { 0 }, + }, + &rsp_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR, + .val = (uint8_t[]){ 1,2,3,4,5,6, 6,5,4,3,2,1 }, + .val_len = 2 * BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN, + }, + { 0 }, + }); + + /*** 0x19 - Appearance. */ + memset(&rsp_fields, 0, sizeof rsp_fields); + rsp_fields.appearance = 0x1234; + rsp_fields.appearance_is_present = 1; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { 0 }, + }, + &rsp_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_APPEARANCE, + .val = (uint8_t[]){ 0x34, 0x12 }, + .val_len = BLE_HS_ADV_APPEARANCE_LEN, + }, + { 0 }, + }); + + /*** 0x1a - Advertising interval. */ + memset(&rsp_fields, 0, sizeof rsp_fields); + rsp_fields.adv_itvl = 0x1234; + rsp_fields.adv_itvl_is_present = 1; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { 0 }, + }, + &rsp_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_ADV_ITVL, + .val = (uint8_t[]){ 0x34, 0x12 }, + .val_len = BLE_HS_ADV_ADV_ITVL_LEN, + }, + { 0 }, + }); + + /*** 0x20 - Service data - 32-bit UUID. */ + memset(&rsp_fields, 0, sizeof rsp_fields); + rsp_fields.svc_data_uuid32 = (uint8_t[]){ 1,2,3,4,5 }; + rsp_fields.svc_data_uuid32_len = 5; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { 0 }, + }, + &rsp_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_SVC_DATA_UUID32, + .val = (uint8_t[]) { 1,2,3,4,5 }, + .val_len = 5, + }, + { 0 }, + }); + + /*** 0x21 - Service data - 128-bit UUID. */ + memset(&rsp_fields, 0, sizeof rsp_fields); + rsp_fields.svc_data_uuid128 = + (uint8_t[]){ 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18 }; + rsp_fields.svc_data_uuid128_len = 18; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { 0 }, + }, + &rsp_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_SVC_DATA_UUID128, + .val = (uint8_t[]){ 1,2,3,4,5,6,7,8,9,10, + 11,12,13,14,15,16,17,18 }, + .val_len = 18, + }, + { 0 }, + }); + + /*** 0x24 - URI. */ + memset(&rsp_fields, 0, sizeof rsp_fields); + rsp_fields.uri = (uint8_t[]){ 1,2,3,4 }; + rsp_fields.uri_len = 4; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { 0 }, + }, + &rsp_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_URI, + .val = (uint8_t[]) { 1,2,3,4 }, + .val_len = 4, + }, + { 0 }, + }); + + /*** 0xff - Manufacturer specific data. */ + memset(&rsp_fields, 0, sizeof rsp_fields); + rsp_fields.mfg_data = (uint8_t[]){ 1,2,3,4 }; + rsp_fields.mfg_data_len = 4; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_FLAGS, + .val = (uint8_t[]){ BLE_HS_ADV_F_BREDR_UNSUP }, + .val_len = 1, + }, + { + .type = BLE_HS_ADV_TYPE_TX_PWR_LVL, + .val = (uint8_t[]){ 0 }, + .val_len = 1, + }, + { 0 }, + }, + &rsp_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_MFG_DATA, + .val = (uint8_t[]) { 1,2,3,4 }, + .val_len = 4, + }, + { 0 }, + }); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_hs_adv_test_case_user_full_payload) +{ + /* Intentionally allocate an extra byte. */ + static const uint8_t mfg_data[30] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, + }; + + struct ble_hs_adv_fields adv_fields; + struct ble_hs_adv_fields rsp_fields; + int rc; + + ble_hs_test_util_init(); + + memset(&rsp_fields, 0, sizeof rsp_fields); + + /*** + * An advertisement should allow 31 bytes of user data. Each field has a + * two-byte header, leaving 29 bytes of payload. + */ + memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.mfg_data = (void *)mfg_data; + adv_fields.mfg_data_len = 29; + + ble_hs_adv_test_misc_tx_and_verify_data(BLE_GAP_DISC_MODE_NON, &adv_fields, + (struct ble_hs_adv_test_field[]) { + { + .type = BLE_HS_ADV_TYPE_MFG_DATA, + .val = (void *)mfg_data, + .val_len = 29, + }, + { 0 }, + }, &rsp_fields, NULL); + + /*** Fail with 30 bytes. */ + rc = ble_hs_test_util_adv_stop(0); + TEST_ASSERT_FATAL(rc == 0); + + adv_fields.mfg_data_len = 30; + rc = ble_gap_adv_set_fields(&adv_fields); + TEST_ASSERT(rc == BLE_HS_EMSGSIZE); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_hs_adv_test_suite) +{ + ble_hs_adv_test_case_user(); + ble_hs_adv_test_case_user_rsp(); + ble_hs_adv_test_case_user_full_payload(); +} diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_conn_test.c b/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_conn_test.c new file mode 100644 index 00000000..04137d4f --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_conn_test.c @@ -0,0 +1,224 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include "testutil/testutil.h" +#include "nimble/hci_common.h" +#include "host/ble_hs_adv.h" +#include "ble_hs_test.h" +#include "ble_hs_test_util.h" +#include "../src/ble_gap_priv.h" + +static int +ble_hs_conn_test_util_any(void) +{ + struct ble_hs_conn *conn; + + ble_hs_lock(); + conn = ble_hs_conn_first(); + ble_hs_unlock(); + + return conn != NULL; +} + +TEST_CASE_SELF(ble_hs_conn_test_direct_connect_success) +{ + struct ble_gap_conn_complete evt; + struct ble_l2cap_chan *chan; + struct ble_hs_conn *conn; + ble_addr_t addr = { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 }}; + int rc; + + ble_hs_test_util_init(); + + /* Ensure no current or pending connections. */ + TEST_ASSERT(!ble_gap_master_in_progress()); + TEST_ASSERT(!ble_hs_conn_test_util_any()); + + /* Initiate connection. */ + rc = ble_hs_test_util_connect(BLE_OWN_ADDR_PUBLIC, + &addr, 0, NULL, NULL, NULL, 0); + TEST_ASSERT(rc == 0); + + TEST_ASSERT(ble_gap_master_in_progress()); + + /* ble_gap_rx_conn_complete() will send extra HCI command, need phony ack */ + ble_hs_test_util_hci_ack_set(ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_RD_REM_FEAT), 0); + + /* Receive successful connection complete event. */ + memset(&evt, 0, sizeof evt); + evt.status = BLE_ERR_SUCCESS; + evt.connection_handle = 2; + evt.role = BLE_HCI_LE_CONN_COMPLETE_ROLE_MASTER; + memcpy(evt.peer_addr, addr.val, 6); + rc = ble_gap_rx_conn_complete(&evt, 0); + TEST_ASSERT(rc == 0); + TEST_ASSERT(!ble_gap_master_in_progress()); + + ble_hs_lock(); + + conn = ble_hs_conn_first(); + TEST_ASSERT_FATAL(conn != NULL); + TEST_ASSERT(conn->bhc_handle == 2); + TEST_ASSERT(memcmp(conn->bhc_peer_addr.val, addr.val, 6) == 0); + + chan = ble_hs_conn_chan_find_by_scid(conn, BLE_L2CAP_CID_ATT); + TEST_ASSERT_FATAL(chan != NULL); + TEST_ASSERT(chan->my_mtu == MYNEWT_VAL(BLE_ATT_PREFERRED_MTU)); + TEST_ASSERT(chan->peer_mtu == 0); + + ble_hs_unlock(); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_hs_conn_test_direct_connectable_success) +{ + struct ble_gap_conn_complete evt; + struct ble_gap_adv_params adv_params; + struct ble_l2cap_chan *chan; + struct ble_hs_conn *conn; + ble_addr_t addr = { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 }}; + int rc; + + ble_hs_test_util_init(); + + /* Ensure no current or pending connections. */ + TEST_ASSERT(!ble_gap_master_in_progress()); + TEST_ASSERT(!ble_gap_adv_active()); + TEST_ASSERT(!ble_hs_conn_test_util_any()); + + /* Initiate advertising. */ + adv_params = ble_hs_test_util_adv_params; + adv_params.conn_mode = BLE_GAP_CONN_MODE_DIR; + rc = ble_hs_test_util_adv_start(BLE_OWN_ADDR_PUBLIC, + &addr, &adv_params, BLE_HS_FOREVER, + NULL, NULL, 0, 0); + TEST_ASSERT(rc == 0); + + TEST_ASSERT(!ble_gap_master_in_progress()); + TEST_ASSERT(ble_gap_adv_active()); + + /* ble_gap_rx_conn_complete() will send extra HCI command, need phony ack */ + ble_hs_test_util_hci_ack_set(ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_RD_REM_FEAT), 0); + + /* Receive successful connection complete event. */ + memset(&evt, 0, sizeof evt); + evt.status = BLE_ERR_SUCCESS; + evt.connection_handle = 2; + evt.role = BLE_HCI_LE_CONN_COMPLETE_ROLE_SLAVE; + memcpy(evt.peer_addr, addr.val, 6); + rc = ble_gap_rx_conn_complete(&evt, 0); + TEST_ASSERT(rc == 0); + TEST_ASSERT(!ble_gap_master_in_progress()); + TEST_ASSERT(!ble_gap_adv_active()); + + ble_hs_lock(); + + conn = ble_hs_conn_first(); + TEST_ASSERT_FATAL(conn != NULL); + TEST_ASSERT(conn->bhc_handle == 2); + TEST_ASSERT(memcmp(conn->bhc_peer_addr.val, addr.val, 6) == 0); + + chan = ble_hs_conn_chan_find_by_scid(conn, BLE_L2CAP_CID_ATT); + TEST_ASSERT_FATAL(chan != NULL); + TEST_ASSERT(chan->my_mtu == MYNEWT_VAL(BLE_ATT_PREFERRED_MTU)); + TEST_ASSERT(chan->peer_mtu == 0); + + ble_hs_unlock(); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_hs_conn_test_undirect_connectable_success) +{ + struct ble_hs_adv_fields adv_fields; + struct ble_gap_conn_complete evt; + struct ble_gap_adv_params adv_params; + struct ble_l2cap_chan *chan; + struct ble_hs_conn *conn; + ble_addr_t addr = { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 }}; + int rc; + + ble_hs_test_util_init(); + + /* Ensure no current or pending connections. */ + TEST_ASSERT(!ble_gap_master_in_progress()); + TEST_ASSERT(!ble_gap_adv_active()); + TEST_ASSERT(!ble_hs_conn_test_util_any()); + + /* Initiate advertising. */ + memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.tx_pwr_lvl_is_present = 1; + rc = ble_hs_test_util_adv_set_fields(&adv_fields, 0, 0); + TEST_ASSERT_FATAL(rc == 0); + + adv_params = ble_hs_test_util_adv_params; + adv_params.conn_mode = BLE_GAP_CONN_MODE_UND; + rc = ble_hs_test_util_adv_start(BLE_OWN_ADDR_PUBLIC, + &addr, &adv_params, + BLE_HS_FOREVER, + NULL, NULL, 0, 0); + TEST_ASSERT(rc == 0); + + TEST_ASSERT(!ble_gap_master_in_progress()); + TEST_ASSERT(ble_gap_adv_active()); + + /* ble_gap_rx_conn_complete() will send extra HCI command, need phony ack */ + ble_hs_test_util_hci_ack_set(ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_RD_REM_FEAT), 0); + + /* Receive successful connection complete event. */ + memset(&evt, 0, sizeof evt); + evt.status = BLE_ERR_SUCCESS; + evt.connection_handle = 2; + evt.role = BLE_HCI_LE_CONN_COMPLETE_ROLE_SLAVE; + memcpy(evt.peer_addr, addr.val, 6); + rc = ble_gap_rx_conn_complete(&evt, 0); + TEST_ASSERT(rc == 0); + TEST_ASSERT(!ble_gap_master_in_progress()); + TEST_ASSERT(!ble_gap_adv_active()); + + ble_hs_lock(); + + conn = ble_hs_conn_first(); + TEST_ASSERT_FATAL(conn != NULL); + TEST_ASSERT(conn->bhc_handle == 2); + TEST_ASSERT(memcmp(conn->bhc_peer_addr.val, addr.val, 6) == 0); + + chan = ble_hs_conn_chan_find_by_scid(conn, BLE_L2CAP_CID_ATT); + TEST_ASSERT_FATAL(chan != NULL); + TEST_ASSERT(chan->my_mtu == MYNEWT_VAL(BLE_ATT_PREFERRED_MTU)); + TEST_ASSERT(chan->peer_mtu == 0); + + ble_hs_unlock(); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_hs_conn_suite) +{ + ble_hs_conn_test_direct_connect_success(); + ble_hs_conn_test_direct_connectable_success(); + ble_hs_conn_test_undirect_connectable_success(); +} diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_hci_test.c b/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_hci_test.c new file mode 100644 index 00000000..5f72742c --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_hci_test.c @@ -0,0 +1,342 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include "nimble/hci_common.h" +#include "nimble/ble_hci_trans.h" +#include "ble_hs_test.h" +#include "testutil/testutil.h" +#include "ble_hs_test_util.h" + +#define BLE_HCI_READ_RSSI_ACK_PARAM_LEN (3) /* No status byte. */ + +TEST_CASE_SELF(ble_hs_hci_test_event_bad) +{ + uint8_t *buf; + int rc; + + /*** Invalid event code. */ + buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + TEST_ASSERT_FATAL(buf != NULL); + + buf[0] = 0xff; + buf[1] = 0; + rc = ble_hs_hci_evt_process((void*)buf); + TEST_ASSERT(rc == BLE_HS_ENOTSUP); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_hs_hci_test_rssi) +{ + uint8_t params[BLE_HCI_READ_RSSI_ACK_PARAM_LEN]; + uint16_t opcode; + int8_t rssi; + int rc; + + opcode = ble_hs_hci_util_opcode_join(BLE_HCI_OGF_STATUS_PARAMS, + BLE_HCI_OCF_RD_RSSI); + + /*** Success. */ + /* Connection handle. */ + put_le16(params + 0, 1); + + /* RSSI. */ + params[2] = -8; + + ble_hs_test_util_hci_ack_set_params(opcode, 0, params, sizeof params); + + rc = ble_hs_hci_util_read_rssi(1, &rssi); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(rssi == -8); + + /*** Failure: incorrect connection handle. */ + put_le16(params + 0, 99); + + ble_hs_test_util_hci_ack_set_params(opcode, 0, params, sizeof params); + + rc = ble_hs_hci_util_read_rssi(1, &rssi); + TEST_ASSERT(rc == BLE_HS_ECONTROLLER); + + /*** Failure: params too short. */ + ble_hs_test_util_hci_ack_set_params(opcode, 0, params, sizeof params - 1); + rc = ble_hs_hci_util_read_rssi(1, &rssi); + TEST_ASSERT(rc == BLE_HS_ECONTROLLER); + + /*** Failure: params too long. */ + ble_hs_test_util_hci_ack_set_params(opcode, 0, params, sizeof params + 1); + rc = ble_hs_hci_util_read_rssi(1, &rssi); + TEST_ASSERT(rc == BLE_HS_ECONTROLLER); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_hs_hci_acl_one_conn) +{ + struct ble_hs_test_util_hci_num_completed_pkts_entry ncpe[2]; + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + uint8_t data[256]; + int rc; + int i; + + memset(ncpe, 0, sizeof(ncpe)); + for (i = 0; i < sizeof data; i++) { + data[i] = i; + } + + ble_hs_test_util_init(); + + /* The controller has room for five 20-byte payloads. */ + rc = ble_hs_hci_set_buf_sz(20, 5); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT_FATAL(ble_hs_hci_avail_pkts == 5); + + ble_hs_test_util_create_conn(1, peer_addr, NULL, NULL); + + /* Ensure the ATT doesn't truncate our data packets. */ + ble_hs_test_util_set_att_mtu(1, 256); + + /* Send two 3-byte data packets. */ + rc = ble_hs_test_util_gatt_write_no_rsp_flat(1, 100, data, 3); + TEST_ASSERT_FATAL(rc == 0); + rc = ble_hs_test_util_gatt_write_no_rsp_flat(1, 100, data, 3); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT_FATAL(ble_hs_hci_avail_pkts == 3); + + /* Send fragmented packet (two fragments). */ + rc = ble_hs_test_util_gatt_write_no_rsp_flat(1, 100, data, 25); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT_FATAL(ble_hs_hci_avail_pkts == 1); + + ble_hs_test_util_prev_tx_queue_clear(); + + /* Receive a number-of-completed-packets event. Ensure available buffer + * count increases. + */ + ncpe[0].handle_id = 1; + ncpe[0].num_pkts = 3; + ble_hs_test_util_hci_rx_num_completed_pkts_event(ncpe); + TEST_ASSERT_FATAL(ble_hs_hci_avail_pkts == 4); + + /* Use all remaining buffers (four fragments). */ + rc = ble_hs_test_util_gatt_write_no_rsp_flat(1, 100, data, 70); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT_FATAL(ble_hs_hci_avail_pkts == 0); + + /* Attempt to transmit eight more fragments. */ + rc = ble_hs_test_util_gatt_write_no_rsp_flat(1, 100, data, 160); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT_FATAL(ble_hs_hci_avail_pkts == 0); + + /* Receive number-of-completed-packets: 5. */ + ncpe[0].handle_id = 1; + ncpe[0].num_pkts = 5; + ble_hs_test_util_hci_rx_num_completed_pkts_event(ncpe); + TEST_ASSERT_FATAL(ble_hs_hci_avail_pkts == 0); + + /* Receive number-of-completed-packets: 4. */ + ncpe[0].handle_id = 1; + ncpe[0].num_pkts = 5; + ble_hs_test_util_hci_rx_num_completed_pkts_event(ncpe); + TEST_ASSERT_FATAL(ble_hs_hci_avail_pkts == 1); + + /* Ensure the stalled fragments were sent in the expected order. */ + ble_hs_test_util_verify_tx_write_cmd(100, data, 70); + ble_hs_test_util_verify_tx_write_cmd(100, data, 160); + + /* Receive a disconnection-complete event. Ensure available buffer count + * increases. + */ + ble_hs_test_util_hci_rx_disconn_complete_event(1, 0, BLE_ERR_CONN_TERM_LOCAL); + TEST_ASSERT_FATAL(ble_hs_hci_avail_pkts == 5); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_hs_hci_acl_two_conn) +{ + struct ble_hs_test_util_hci_num_completed_pkts_entry ncpe[2]; + const struct ble_hs_conn *conn1; + const struct ble_hs_conn *conn2; + uint8_t peer_addr1[6] = { 1, 2, 3, 4, 5, 6 }; + uint8_t peer_addr2[6] = { 2, 3, 4, 5, 6, 7 }; + uint8_t data[256]; + int rc; + int i; + + memset(ncpe, 0, sizeof(ncpe)); + for (i = 0; i < sizeof data; i++) { + data[i] = i; + } + + ble_hs_test_util_init(); + + /* The controller has room for five 20-byte payloads*/ + rc = ble_hs_hci_set_buf_sz(20, 5); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT_FATAL(ble_hs_hci_avail_pkts == 5); + + ble_hs_test_util_create_conn(1, peer_addr1, NULL, NULL); + ble_hs_test_util_create_conn(2, peer_addr2, NULL, NULL); + + /* This test inspects the connection objects after unlocking the host + * mutex. It is not OK for real code to do this, but this test can assume + * the connection list is unchanging. + */ + ble_hs_lock(); + conn1 = ble_hs_conn_find_assert(1); + conn2 = ble_hs_conn_find_assert(2); + ble_hs_unlock(); + + /* Ensure the ATT doesn't truncate our data packets. */ + ble_hs_test_util_set_att_mtu(1, 256); + ble_hs_test_util_set_att_mtu(2, 256); + + /* Tx two fragments over connection 1. */ + rc = ble_hs_test_util_gatt_write_no_rsp_flat(1, 100, data, 25); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT_FATAL(ble_hs_hci_avail_pkts == 3); + TEST_ASSERT_FATAL(!(conn1->bhc_flags & BLE_HS_CONN_F_TX_FRAG)); + + /* Tx two fragments over connection 2. */ + rc = ble_hs_test_util_gatt_write_no_rsp_flat(2, 100, data + 10, 25); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT_FATAL(ble_hs_hci_avail_pkts == 1); + TEST_ASSERT_FATAL(!(conn1->bhc_flags & BLE_HS_CONN_F_TX_FRAG)); + + /* Tx four fragments over connection 2. */ + rc = ble_hs_test_util_gatt_write_no_rsp_flat(2, 100, data + 20, 70); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT_FATAL(ble_hs_hci_avail_pkts == 0); + TEST_ASSERT_FATAL(conn2->bhc_flags & BLE_HS_CONN_F_TX_FRAG); + + /* Tx four fragments over connection 1. */ + rc = ble_hs_test_util_gatt_write_no_rsp_flat(1, 100, data + 30, 70); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT_FATAL(ble_hs_hci_avail_pkts == 0); + TEST_ASSERT_FATAL(!(conn1->bhc_flags & BLE_HS_CONN_F_TX_FRAG)); + + /** + * controller: (11 222) + * conn 1: 1111 + * conn 2: 222 + */ + + /* Receive number-of-completed-packets: conn=2, num-pkts=1. */ + ncpe[0].handle_id = 2; + ncpe[0].num_pkts = 1; + ble_hs_test_util_hci_rx_num_completed_pkts_event(ncpe); + + /** + * controller: (11 222) + * conn 1: 1111 + * conn 2: 22 + */ + TEST_ASSERT_FATAL(ble_hs_hci_avail_pkts == 0); + TEST_ASSERT_FATAL(!(conn1->bhc_flags & BLE_HS_CONN_F_TX_FRAG)); + TEST_ASSERT_FATAL(conn2->bhc_flags & BLE_HS_CONN_F_TX_FRAG); + + /* Receive number-of-completed-packets: conn=1, num-pkts=1. */ + ncpe[0].handle_id = 1; + ncpe[0].num_pkts = 1; + ble_hs_test_util_hci_rx_num_completed_pkts_event(ncpe); + + /** + * controller: (1 2222) + * conn 1: 1111 + * conn 2: 2 + */ + TEST_ASSERT_FATAL(ble_hs_hci_avail_pkts == 0); + TEST_ASSERT_FATAL(!(conn1->bhc_flags & BLE_HS_CONN_F_TX_FRAG)); + TEST_ASSERT_FATAL(conn2->bhc_flags & BLE_HS_CONN_F_TX_FRAG); + + /* Receive number-of-completed-packets: conn=1, num-pkts=1. */ + ncpe[0].handle_id = 1; + ncpe[0].num_pkts = 1; + ble_hs_test_util_hci_rx_num_completed_pkts_event(ncpe); + + /** + * controller: (22222) + * conn 1: 1111 + * conn 2: - + */ + TEST_ASSERT_FATAL(ble_hs_hci_avail_pkts == 0); + TEST_ASSERT_FATAL(!(conn1->bhc_flags & BLE_HS_CONN_F_TX_FRAG)); + TEST_ASSERT_FATAL(!(conn2->bhc_flags & BLE_HS_CONN_F_TX_FRAG)); + + /* Receive number-of-completed-packets: conn=2, num-pkts=3. */ + ncpe[0].handle_id = 2; + ncpe[0].num_pkts = 3; + ble_hs_test_util_hci_rx_num_completed_pkts_event(ncpe); + + /** + * controller: (11122) + * conn 1: 1 + * conn 2: - + */ + TEST_ASSERT_FATAL(ble_hs_hci_avail_pkts == 0); + TEST_ASSERT_FATAL(conn1->bhc_flags & BLE_HS_CONN_F_TX_FRAG); + TEST_ASSERT_FATAL(!(conn2->bhc_flags & BLE_HS_CONN_F_TX_FRAG)); + + /* Receive number-of-completed-packets: conn=2, num-pkts=2. */ + ncpe[0].handle_id = 2; + ncpe[0].num_pkts = 2; + ble_hs_test_util_hci_rx_num_completed_pkts_event(ncpe); + + /** + * controller: (1111) + * conn 1: - + * conn 2: - + */ + TEST_ASSERT_FATAL(ble_hs_hci_avail_pkts == 1); + TEST_ASSERT_FATAL(!(conn1->bhc_flags & BLE_HS_CONN_F_TX_FRAG)); + TEST_ASSERT_FATAL(!(conn2->bhc_flags & BLE_HS_CONN_F_TX_FRAG)); + + /* Receive number-of-completed-packets: conn=1, num-pkts=4. */ + ncpe[0].handle_id = 1; + ncpe[0].num_pkts = 4; + ble_hs_test_util_hci_rx_num_completed_pkts_event(ncpe); + + /** + * controller: () + * conn 1: - + * conn 2: - + */ + TEST_ASSERT_FATAL(ble_hs_hci_avail_pkts == 5); + TEST_ASSERT_FATAL(!(conn1->bhc_flags & BLE_HS_CONN_F_TX_FRAG)); + TEST_ASSERT_FATAL(!(conn2->bhc_flags & BLE_HS_CONN_F_TX_FRAG)); + + /*** Verify payloads. */ + ble_hs_test_util_verify_tx_write_cmd(100, data, 25); + ble_hs_test_util_verify_tx_write_cmd(100, data + 10, 25); + ble_hs_test_util_verify_tx_write_cmd(100, data + 20, 70); + ble_hs_test_util_verify_tx_write_cmd(100, data + 30, 70); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_hs_hci_suite) +{ + ble_hs_hci_test_event_bad(); + ble_hs_hci_test_rssi(); + ble_hs_hci_acl_one_conn(); + ble_hs_hci_acl_two_conn(); +} diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_id_test.c b/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_id_test.c new file mode 100644 index 00000000..c5fe6ce2 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_id_test.c @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include "testutil/testutil.h" +#include "nimble/hci_common.h" +#include "host/ble_hs_adv.h" +#include "ble_hs_test.h" +#include "ble_hs_test_util.h" + +static int +ble_hs_id_test_util_infer_auto(int privacy, uint8_t *own_addr_type) +{ + int rc; + + rc = ble_hs_id_infer_auto(privacy, own_addr_type); + + return rc; +} + +TEST_CASE_SELF(ble_hs_id_test_case_auto_none) +{ + uint8_t own_addr_type; + int rc; + + ble_hs_test_util_init(); + + /* Clear public address. */ + ble_hs_id_set_pub((uint8_t[6]){ 0, 0, 0, 0, 0, 0 }); + + rc = ble_hs_id_test_util_infer_auto(0, &own_addr_type); + TEST_ASSERT_FATAL(rc == BLE_HS_ENOADDR); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_hs_id_test_case_auto_public) +{ + uint8_t own_addr_type; + int rc; + + ble_hs_test_util_init(); + + rc = ble_hs_id_test_util_infer_auto(0, &own_addr_type); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(own_addr_type == BLE_OWN_ADDR_PUBLIC); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_hs_id_test_case_auto_random) +{ + uint8_t own_addr_type; + int rc; + + ble_hs_test_util_init(); + + /* Configure a random address. */ + ble_hs_test_util_set_static_rnd_addr((uint8_t[6]){ 1, 2, 3, 4, 5, 0xc0 }); + + rc = ble_hs_id_test_util_infer_auto(0, &own_addr_type); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(own_addr_type == BLE_OWN_ADDR_RANDOM); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_hs_id_test_case_auto_rpa_pub) +{ + uint8_t own_addr_type; + int rc; + + ble_hs_test_util_init(); + + rc = ble_hs_id_test_util_infer_auto(1, &own_addr_type); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(own_addr_type == BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_hs_id_test_case_auto_rpa_rnd) +{ + uint8_t own_addr_type; + int rc; + + ble_hs_test_util_init(); + + /* Configure a random address. */ + ble_hs_test_util_set_static_rnd_addr((uint8_t[6]){ 1, 2, 3, 4, 5, 0xc0 }); + + rc = ble_hs_id_test_util_infer_auto(1, &own_addr_type); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(own_addr_type == BLE_OWN_ADDR_RPA_RANDOM_DEFAULT); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_hs_id_test_suite_auto) +{ + ble_hs_id_test_case_auto_none(); + ble_hs_id_test_case_auto_public(); + ble_hs_id_test_case_auto_random(); + ble_hs_id_test_case_auto_rpa_pub(); + ble_hs_id_test_case_auto_rpa_rnd(); +} diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_pvcy_test.c b/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_pvcy_test.c new file mode 100644 index 00000000..79b93b83 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_pvcy_test.c @@ -0,0 +1,509 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include "testutil/testutil.h" +#include "ble_hs_test.h" +#include "ble_hs_test_util.h" + +#define BLE_HS_PVCY_TEST_MAX_GAP_EVENTS 256 +static struct ble_gap_event +ble_hs_pvcy_test_gap_events[BLE_HS_PVCY_TEST_MAX_GAP_EVENTS]; +static int ble_hs_pvcy_test_num_gap_events; + +static void +ble_hs_pvcy_test_util_init(void) +{ + ble_hs_test_util_init(); + ble_hs_pvcy_test_num_gap_events = 0; +} + +static int +ble_hs_pvcy_test_util_gap_event(struct ble_gap_event *event, void *arg) +{ + TEST_ASSERT_FATAL(ble_hs_pvcy_test_num_gap_events < + BLE_HS_PVCY_TEST_MAX_GAP_EVENTS); + ble_hs_pvcy_test_gap_events[ble_hs_pvcy_test_num_gap_events++] = *event; + + return 0; +} + +static void +ble_hs_pvcy_test_util_all_gap_procs(int adv_status, + int conn_status, + int disc_status) +{ + struct ble_gap_disc_params disc_params; + ble_addr_t peer_addr; + int rc; + + /* Advertise. */ + rc = ble_hs_test_util_adv_start(BLE_OWN_ADDR_PUBLIC, + NULL, &ble_hs_test_util_adv_params, + BLE_HS_FOREVER, + ble_hs_pvcy_test_util_gap_event, + NULL, 0, 0); + TEST_ASSERT_FATAL(rc == adv_status); + + if (rc == 0) { + rc = ble_hs_test_util_adv_stop(0); + TEST_ASSERT_FATAL(rc == 0); + } + + /* Connect. */ + peer_addr = (ble_addr_t){ BLE_ADDR_PUBLIC, {1,2,3,4,5,6} }; + rc = ble_hs_test_util_connect(BLE_ADDR_PUBLIC, &peer_addr, + BLE_HS_FOREVER, NULL, + ble_hs_pvcy_test_util_gap_event, NULL, 0); + TEST_ASSERT_FATAL(rc == conn_status); + + if (rc == 0) { + ble_hs_test_util_conn_cancel_full(); + } + + /* Discover. */ + disc_params = (struct ble_gap_disc_params){ 0 }; + rc = ble_hs_test_util_disc(BLE_OWN_ADDR_PUBLIC, BLE_HS_FOREVER, + &disc_params, ble_hs_pvcy_test_util_gap_event, + NULL, -1, 0); + TEST_ASSERT_FATAL(rc == disc_status); + + if (rc == 0) { + rc = ble_hs_test_util_disc_cancel(0); + TEST_ASSERT_FATAL(rc == 0); + } +} + +static void +ble_hs_pvcy_test_util_add_irk_set_acks(bool scanning, bool connecting) +{ + ble_hs_test_util_hci_ack_append( + BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_ADV_ENABLE), 0); + + if (connecting) { + ble_hs_test_util_hci_ack_append( + BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_CREATE_CONN_CANCEL), + 0); + } + + if (scanning) { + ble_hs_test_util_hci_ack_append( + BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_SET_SCAN_ENABLE), + 0); + } + + ble_hs_test_util_hci_ack_append( + BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_ADD_RESOLV_LIST), 0); + ble_hs_test_util_hci_ack_append( + BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_PRIVACY_MODE), 0); +} + +static void +ble_hs_pvcy_test_util_start_host(int num_expected_irks) +{ + int rc; + int i; + + /* Clear our IRK. This ensures the full startup sequence, including + * setting the default IRK, takes place. We need this so that we can plan + * which HCI acks to fake. + */ + rc = ble_hs_test_util_set_our_irk((uint8_t[16]){0}, -1, 0); + TEST_ASSERT_FATAL(rc == 0); + ble_hs_test_util_hci_out_clear(); + + ble_hs_test_util_hci_ack_set_startup(); + + for (i = 0; i < num_expected_irks; i++) { + ble_hs_pvcy_test_util_add_irk_set_acks(false, false); + } + + ble_hs_enabled_state = BLE_HS_ENABLED_STATE_OFF; + rc = ble_hs_start(); + TEST_ASSERT_FATAL(rc == 0); + + /* Discard startup HCI commands. */ + ble_hs_test_util_hci_out_adj(ble_hs_test_util_hci_startup_seq_cnt()); +} + +static void +ble_hs_pvcy_test_util_add_irk_verify_tx(const ble_addr_t *peer_addr, + const uint8_t *peer_irk, + const uint8_t *local_irk, + bool scanning, + bool connecting) +{ + ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_SET_ADV_ENABLE, + NULL); + + if (connecting) { + ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_CREATE_CONN_CANCEL, + NULL); + } + + if (scanning) { + ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_SET_SCAN_ENABLE, + NULL); + } + + ble_hs_test_util_hci_verify_tx_add_irk(peer_addr->type, + peer_addr->val, + peer_irk, + local_irk); + + ble_hs_test_util_hci_verify_tx_set_priv_mode(peer_addr->type, + peer_addr->val, + BLE_GAP_PRIVATE_MODE_DEVICE); +} + +static void +ble_hs_pvcy_test_util_add_irk(const ble_addr_t *peer_addr, + const uint8_t *peer_irk, + const uint8_t *local_irk, + bool scanning, + bool connecting) +{ + int num_acks; + int rc; + + ble_hs_pvcy_test_util_add_irk_set_acks(scanning, connecting); + + rc = ble_hs_pvcy_add_entry(peer_addr->val, peer_addr->type, peer_irk); + TEST_ASSERT_FATAL(rc == 0); + + num_acks = 3; + if (scanning) { + num_acks++; + } + if (connecting) { + num_acks++; + } + ble_hs_test_util_hci_out_adj(-num_acks); + ble_hs_pvcy_test_util_add_irk_verify_tx(peer_addr, peer_irk, local_irk, + scanning, connecting); +} + +static void +ble_hs_pvcy_test_util_add_arbitrary_irk(bool scanning, bool connecting) +{ + ble_addr_t peer_addr; + + peer_addr = (ble_addr_t) { + .type = BLE_ADDR_PUBLIC, + .val = {1,2,3,4,5,6}, + }; + ble_hs_pvcy_test_util_add_irk( + &peer_addr, + (uint8_t[16]){1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}, + ble_hs_pvcy_default_irk, + scanning, + connecting); +} + +static void +ble_hs_pvcy_test_util_restore_irk(const struct ble_store_value_sec *value_sec, + bool scanning, + bool connecting) +{ + int rc; + + ble_hs_pvcy_test_util_add_irk_set_acks(scanning, connecting); + + rc = ble_store_write_peer_sec(value_sec); + TEST_ASSERT_FATAL(rc == 0); + + ble_hs_pvcy_test_util_add_irk_verify_tx(&value_sec->peer_addr, + value_sec->irk, + ble_hs_pvcy_default_irk, + scanning, + connecting); +} + +TEST_CASE_SELF(ble_hs_pvcy_test_case_restore_irks) +{ + struct ble_store_value_sec value_sec1; + struct ble_store_value_sec value_sec2; + + ble_hs_pvcy_test_util_init(); + + /*** No persisted IRKs. */ + ble_hs_pvcy_test_util_start_host(0); + + /*** One persisted IRK. */ + + /* Persist IRK; ensure it automatically gets added to the list. */ + value_sec1 = (struct ble_store_value_sec) { + .peer_addr = { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 } }, + .key_size = 16, + .ediv = 1, + .rand_num = 2, + .irk = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }, + .irk_present = 1, + }; + ble_hs_pvcy_test_util_restore_irk(&value_sec1, false, false); + + /* Ensure it gets added to list on startup. */ + ble_hs_pvcy_test_util_start_host(1); + ble_hs_pvcy_test_util_add_irk_verify_tx(&value_sec1.peer_addr, + value_sec1.irk, + ble_hs_pvcy_default_irk, + false, false); + + /* Two persisted IRKs. */ + value_sec2 = (struct ble_store_value_sec) { + .peer_addr = { BLE_ADDR_PUBLIC, { 2, 3, 4, 5, 6, 7 } }, + .key_size = 16, + .ediv = 12, + .rand_num = 20, + .irk = { 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 9, 9, 9, 9, 9, 10 }, + .irk_present = 1, + }; + ble_hs_pvcy_test_util_restore_irk(&value_sec2, false, false); + + /* Ensure both get added to list on startup. */ + ble_hs_pvcy_test_util_start_host(2); + ble_hs_pvcy_test_util_add_irk_verify_tx(&value_sec1.peer_addr, + value_sec1.irk, + ble_hs_pvcy_default_irk, + false, false); + ble_hs_pvcy_test_util_add_irk_verify_tx(&value_sec2.peer_addr, + value_sec2.irk, + ble_hs_pvcy_default_irk, + false, false); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +/** No active GAP procedures. */ +TEST_CASE_SELF(ble_hs_pvcy_test_case_add_irk_idle) +{ + ble_hs_pvcy_test_util_init(); + + ble_hs_pvcy_test_util_add_arbitrary_irk(false, false); + TEST_ASSERT(ble_hs_pvcy_test_num_gap_events == 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +/*** Advertising active. */ +TEST_CASE_SELF(ble_hs_pvcy_test_case_add_irk_adv) +{ + int rc; + + ble_hs_pvcy_test_util_init(); + + /* Start an advertising procedure. */ + rc = ble_hs_test_util_adv_start(BLE_OWN_ADDR_PUBLIC, + NULL, &ble_hs_test_util_adv_params, + BLE_HS_FOREVER, + ble_hs_pvcy_test_util_gap_event, + NULL, 0, 0); + TEST_ASSERT_FATAL(rc == 0); + + ble_hs_pvcy_test_util_add_arbitrary_irk(false, false); + + TEST_ASSERT(ble_hs_pvcy_test_num_gap_events == 1); + TEST_ASSERT(ble_hs_pvcy_test_gap_events[0].type == + BLE_GAP_EVENT_ADV_COMPLETE); + TEST_ASSERT(ble_hs_pvcy_test_gap_events[0].adv_complete.reason == + BLE_HS_EPREEMPTED); + + /* Ensure GAP procedures are no longer preempted. */ + ble_hs_pvcy_test_util_all_gap_procs(0, 0, 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +/*** Discovery active. */ +TEST_CASE_SELF(ble_hs_pvcy_test_case_add_irk_disc) +{ + struct ble_gap_disc_params disc_params; + int rc; + + ble_hs_pvcy_test_util_init(); + + /* Start an advertising procedure. */ + disc_params = (struct ble_gap_disc_params){ 0 }; + rc = ble_hs_test_util_disc(BLE_OWN_ADDR_PUBLIC, BLE_HS_FOREVER, + &disc_params, ble_hs_pvcy_test_util_gap_event, + NULL, -1, 0); + TEST_ASSERT_FATAL(rc == 0); + + ble_hs_pvcy_test_util_add_arbitrary_irk(true, false); + + TEST_ASSERT(ble_hs_pvcy_test_num_gap_events == 1); + TEST_ASSERT(ble_hs_pvcy_test_gap_events[0].type == + BLE_GAP_EVENT_DISC_COMPLETE); + TEST_ASSERT(ble_hs_pvcy_test_gap_events[0].disc_complete.reason == + BLE_HS_EPREEMPTED); + + /* Ensure GAP procedures are no longer preempted. */ + ble_hs_pvcy_test_util_all_gap_procs(0, 0, 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +/*** Connect active. */ +TEST_CASE_SELF(ble_hs_pvcy_test_case_add_irk_conn) +{ + ble_addr_t peer_addr; + int rc; + + ble_hs_pvcy_test_util_init(); + + /* Start a connect procedure. */ + peer_addr = (ble_addr_t){ BLE_ADDR_PUBLIC, {1,2,3,4,5,6} }; + rc = ble_hs_test_util_connect(BLE_ADDR_PUBLIC, &peer_addr, + BLE_HS_FOREVER, NULL, + ble_hs_pvcy_test_util_gap_event, NULL, 0); + TEST_ASSERT_FATAL(rc == 0); + + ble_hs_pvcy_test_util_add_arbitrary_irk(false, true); + + /* Cancel is now in progress. */ + TEST_ASSERT(ble_hs_pvcy_test_num_gap_events == 0); + + /* Ensure no GAP procedures are allowed. */ + ble_hs_pvcy_test_util_all_gap_procs(BLE_HS_EPREEMPTED, + BLE_HS_EALREADY, + BLE_HS_EBUSY); + + /* Receive cancel event. */ + ble_hs_test_util_rx_conn_cancel_evt(); + + TEST_ASSERT(ble_hs_pvcy_test_num_gap_events == 1); + TEST_ASSERT(ble_hs_pvcy_test_gap_events[0].type == + BLE_GAP_EVENT_CONNECT); + TEST_ASSERT(ble_hs_pvcy_test_gap_events[0].connect.status == + BLE_HS_EPREEMPTED); + + /* Ensure GAP procedures are no longer preempted. */ + ble_hs_pvcy_test_util_all_gap_procs(0, 0, 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +/*** Advertising and discovery active. */ +TEST_CASE_SELF(ble_hs_pvcy_test_case_add_irk_adv_disc) +{ + struct ble_gap_disc_params disc_params; + int rc; + + ble_hs_pvcy_test_util_init(); + + /* Start an advertising procedure. */ + rc = ble_hs_test_util_adv_start(BLE_OWN_ADDR_PUBLIC, + NULL, &ble_hs_test_util_adv_params, + BLE_HS_FOREVER, + ble_hs_pvcy_test_util_gap_event, + NULL, 0, 0); + TEST_ASSERT_FATAL(rc == 0); + + /* Start a discovery procedure. */ + disc_params = (struct ble_gap_disc_params){ 0 }; + rc = ble_hs_test_util_disc(BLE_OWN_ADDR_PUBLIC, BLE_HS_FOREVER, + &disc_params, ble_hs_pvcy_test_util_gap_event, + NULL, -1, 0); + TEST_ASSERT_FATAL(rc == 0); + + ble_hs_pvcy_test_util_add_arbitrary_irk(true, false); + + TEST_ASSERT(ble_hs_pvcy_test_num_gap_events == 2); + TEST_ASSERT(ble_hs_pvcy_test_gap_events[0].type == + BLE_GAP_EVENT_ADV_COMPLETE); + TEST_ASSERT(ble_hs_pvcy_test_gap_events[0].adv_complete.reason == + BLE_HS_EPREEMPTED); + TEST_ASSERT(ble_hs_pvcy_test_gap_events[1].type == + BLE_GAP_EVENT_DISC_COMPLETE); + TEST_ASSERT(ble_hs_pvcy_test_gap_events[1].disc_complete.reason == + BLE_HS_EPREEMPTED); + + /* Ensure GAP procedures are no longer preempted. */ + ble_hs_pvcy_test_util_all_gap_procs(0, 0, 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +/*** Advertising and connecting active. */ +TEST_CASE_SELF(ble_hs_pvcy_test_case_add_irk_adv_conn) +{ + ble_addr_t peer_addr; + int rc; + + ble_hs_pvcy_test_util_init(); + + /* Start an advertising procedure. */ + rc = ble_hs_test_util_adv_start(BLE_OWN_ADDR_PUBLIC, + NULL, &ble_hs_test_util_adv_params, + BLE_HS_FOREVER, + ble_hs_pvcy_test_util_gap_event, + NULL, 0, 0); + TEST_ASSERT_FATAL(rc == 0); + + /* Start a connect procedure. */ + peer_addr = (ble_addr_t){ BLE_ADDR_PUBLIC, {1,2,3,4,5,6} }; + rc = ble_hs_test_util_connect(BLE_ADDR_PUBLIC, &peer_addr, + BLE_HS_FOREVER, NULL, + ble_hs_pvcy_test_util_gap_event, NULL, 0); + TEST_ASSERT_FATAL(rc == 0); + + ble_hs_pvcy_test_util_add_arbitrary_irk(false, true); + + /* Cancel is now in progress. */ + TEST_ASSERT(ble_hs_pvcy_test_num_gap_events == 1); + TEST_ASSERT(ble_hs_pvcy_test_gap_events[0].type == + BLE_GAP_EVENT_ADV_COMPLETE); + TEST_ASSERT(ble_hs_pvcy_test_gap_events[0].adv_complete.reason == + BLE_HS_EPREEMPTED); + + /* Ensure no GAP procedures are allowed. */ + ble_hs_pvcy_test_util_all_gap_procs(BLE_HS_EPREEMPTED, + BLE_HS_EALREADY, + BLE_HS_EBUSY); + + /* Receive cancel event. */ + ble_hs_test_util_rx_conn_cancel_evt(); + + TEST_ASSERT(ble_hs_pvcy_test_num_gap_events == 2); + TEST_ASSERT(ble_hs_pvcy_test_gap_events[1].type == + BLE_GAP_EVENT_CONNECT); + TEST_ASSERT(ble_hs_pvcy_test_gap_events[1].connect.status == + BLE_HS_EPREEMPTED); + + /* Ensure GAP procedures are no longer preempted. */ + ble_hs_pvcy_test_util_all_gap_procs(0, 0, 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_hs_pvcy_test_suite_irk) +{ + ble_hs_pvcy_test_case_restore_irks(); + ble_hs_pvcy_test_case_add_irk_idle(); + ble_hs_pvcy_test_case_add_irk_adv(); + ble_hs_pvcy_test_case_add_irk_disc(); + ble_hs_pvcy_test_case_add_irk_conn(); + ble_hs_pvcy_test_case_add_irk_adv_disc(); + ble_hs_pvcy_test_case_add_irk_adv_conn(); +} diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_stop_test.c b/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_stop_test.c new file mode 100644 index 00000000..526d5f5a --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_stop_test.c @@ -0,0 +1,203 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include "testutil/testutil.h" +#include "host/ble_hs.h" +#include "ble_hs_test.h" +#include "ble_hs_test_util.h" + +#define BHST_MAX_EVENTS 32 + +static struct ble_gap_event bhst_events[BHST_MAX_EVENTS]; +static int bhst_num_events; + +static struct ble_hs_stop_listener bhst_listener; +static struct os_sem bhst_sem; + +static int +bhst_gap_event(struct ble_gap_event *event, void *arg) +{ + TEST_ASSERT_FATAL(bhst_num_events < BHST_MAX_EVENTS); + + bhst_events[bhst_num_events++] = *event; + return 0; +} + +static void +bhst_stop_cb(int status, void *arg) +{ + int rc; + + rc = os_sem_release(&bhst_sem); + TEST_ASSERT_FATAL(rc == 0); +} + +TEST_CASE_TASK(ble_hs_stop_test_new_procs) +{ + static const struct ble_gap_disc_params disc_params; + static const struct ble_gap_adv_params adv_params; + + static const ble_addr_t peer_addr = { + BLE_ADDR_PUBLIC, + { 1, 2, 3, 4, 5, 6 } + }; + + int rc; + + rc = os_sem_init(&bhst_sem, 0); + TEST_ASSERT_FATAL(rc == 0); + + /* Stop the host and wait for the stop procedure to complete. */ + ble_hs_test_util_hci_ack_set( + BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_ADV_ENABLE), 0); + + rc = ble_hs_stop(&bhst_listener, bhst_stop_cb, NULL); + TEST_ASSERT_FATAL(rc == 0); + rc = os_sem_pend(&bhst_sem, OS_TIMEOUT_NEVER); + TEST_ASSERT_FATAL(rc == 0); + + /*** Ensure all GAP procedures fail. */ + + /* Advertise. */ + rc = ble_hs_test_util_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, &adv_params, + BLE_HS_FOREVER, bhst_gap_event, NULL, + 0, 0); + TEST_ASSERT(rc == BLE_HS_EDISABLED); + + /* Discover. */ + rc = ble_hs_test_util_disc(BLE_OWN_ADDR_PUBLIC, BLE_HS_FOREVER, + &disc_params, bhst_gap_event, NULL, 0, 0); + TEST_ASSERT(rc == BLE_HS_EDISABLED); + + /* Connect. */ + rc = ble_hs_test_util_connect(BLE_OWN_ADDR_PUBLIC, &peer_addr, + BLE_HS_FOREVER, NULL, + bhst_gap_event, NULL, 0); + TEST_ASSERT(rc == BLE_HS_EDISABLED); + + /*** Restart stack; ensure GAP procedures succeed. */ + + ble_hs_test_util_hci_ack_set_startup(); + ble_hs_sched_start(); + + /* Advertise. */ + rc = ble_hs_test_util_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, &adv_params, + BLE_HS_FOREVER, bhst_gap_event, NULL, + 0, 0); + TEST_ASSERT(rc == 0); + + rc = ble_hs_test_util_adv_stop(0); + TEST_ASSERT(rc == 0); + + /* Discover. */ + rc = ble_hs_test_util_disc(BLE_OWN_ADDR_PUBLIC, BLE_HS_FOREVER, + &disc_params, bhst_gap_event, NULL, 0, 0); + TEST_ASSERT(rc == 0); + + rc = ble_hs_test_util_disc_cancel(0); + TEST_ASSERT(rc == 0); + + /* Connect. */ + rc = ble_hs_test_util_connect(BLE_OWN_ADDR_PUBLIC, &peer_addr, + BLE_HS_FOREVER, NULL, + bhst_gap_event, NULL, 0); + TEST_ASSERT(rc == 0); + + rc = ble_hs_test_util_conn_cancel(0); + TEST_ASSERT(rc == 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_TASK(ble_hs_stop_test_cur_procs) +{ + static const struct ble_gap_disc_params disc_params; + static const struct ble_gap_adv_params adv_params; + + int rc; + + rc = os_sem_init(&bhst_sem, 0); + TEST_ASSERT_FATAL(rc == 0); + + /* Advertise. */ + rc = ble_hs_test_util_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, &adv_params, + BLE_HS_FOREVER, bhst_gap_event, NULL, + 0, 0); + TEST_ASSERT(rc == 0); + + /* Discover. */ + rc = ble_hs_test_util_disc(BLE_OWN_ADDR_PUBLIC, BLE_HS_FOREVER, + &disc_params, bhst_gap_event, NULL, 0, 0); + TEST_ASSERT(rc == 0); + + /* Preload the host with HCI acks for the cancel commands that will be sent + * automatically when the host stops. + */ + ble_hs_test_util_hci_ack_set( + BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_SET_ADV_ENABLE), + 0); + ble_hs_test_util_hci_ack_append( + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_SET_SCAN_ENABLE), + 0); + + /* Stop the host and wait for the stop procedure to complete. */ + bhst_num_events = 0; + rc = ble_hs_stop(&bhst_listener, bhst_stop_cb, NULL); + TEST_ASSERT_FATAL(rc == 0); + rc = os_sem_pend(&bhst_sem, OS_TIMEOUT_NEVER); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure the GAP procedure cancellations were reported. */ + TEST_ASSERT_FATAL(bhst_num_events == 2); + TEST_ASSERT(bhst_events[0].type == BLE_GAP_EVENT_ADV_COMPLETE); + TEST_ASSERT(bhst_events[0].adv_complete.reason == BLE_HS_EPREEMPTED); + TEST_ASSERT(bhst_events[1].type == BLE_GAP_EVENT_DISC_COMPLETE); + TEST_ASSERT(bhst_events[1].disc_complete.reason == BLE_HS_EPREEMPTED); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +static void +bhst_pre_test(void *arg) +{ + ble_hs_test_util_init_no_sysinit_no_start(); + + /* Preload the host with HCI acks for the startup sequence. */ + ble_hs_test_util_hci_ack_set_startup(); +} + +TEST_SUITE(ble_hs_stop_test_suite) +{ + tu_suite_set_pre_test_cb(bhst_pre_test, NULL); + + ble_hs_stop_test_new_procs(); + ble_hs_stop_test_cur_procs(); +} + +int +ble_stop_test_all(void) +{ + ble_hs_stop_test_suite(); + + return tu_any_failed; +} diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_test.c b/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_test.c new file mode 100644 index 00000000..adf99423 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_test.c @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "sysinit/sysinit.h" +#include "syscfg/syscfg.h" +#include "os/os.h" +#include "nimble/hci_common.h" +#include "testutil/testutil.h" +#include "ble_hs_test_util.h" +#include "ble_hs_test.h" + +#if MYNEWT_VAL(SELFTEST) + +int +main(int argc, char **argv) +{ + /* XXX: This test must come before the others; it causes privacy to be + * enabled. Subsequent tests depend on this. This is wrong - each test + * should enable privacy as needed, but the test util functions are so low + * level that they make this very difficult to arrange (individual HCI + * commands and responses). + * + * To fix this, we should implement a set of higher level BLE test + * functions that don't require individual HCI commands to be specified. + */ + ble_gap_test_suite_disc(); + + ble_att_clt_suite(); + ble_att_svr_suite(); + ble_gap_test_suite_adv(); + ble_gap_test_suite_conn_cancel(); + ble_gap_test_suite_conn_find(); + ble_gap_test_suite_conn_gen(); + ble_gap_test_suite_conn_terminate(); + ble_gap_test_suite_mtu(); + ble_gap_test_suite_set_cb(); + ble_gap_test_suite_stop_adv(); + ble_gap_test_suite_timeout(); + ble_gap_test_suite_update_conn(); + ble_gap_test_suite_wl(); + ble_gatt_conn_suite(); + ble_gatt_disc_c_test_suite(); + ble_gatt_disc_d_test_suite(); + ble_gatt_disc_s_test_suite(); + ble_gatt_find_s_test_suite(); + ble_gatt_read_test_suite(); + ble_gatt_write_test_suite(); + ble_gatts_notify_suite(); + ble_gatts_read_test_suite(); + ble_gatts_reg_suite(); + ble_hs_adv_test_suite(); + ble_hs_conn_suite(); + ble_hs_hci_suite(); + ble_hs_id_test_suite_auto(); + ble_hs_pvcy_test_suite_irk(); + ble_l2cap_test_suite(); + ble_os_test_suite(); + ble_sm_gen_test_suite(); + ble_sm_lgcy_test_suite(); + ble_sm_sc_test_suite(); + ble_store_suite(); + ble_uuid_test_suite(); + + return tu_any_failed; +} + +#endif diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_test.h b/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_test.h new file mode 100644 index 00000000..3fb1454e --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_test.h @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_HS_TEST_ +#define H_BLE_HS_TEST_ + +#include "testutil/testutil.h" + +TEST_SUITE_DECL(ble_att_clt_suite); +TEST_SUITE_DECL(ble_att_svr_suite); +TEST_SUITE_DECL(ble_gap_test_suite_adv); +TEST_SUITE_DECL(ble_gap_test_suite_conn_cancel); +TEST_SUITE_DECL(ble_gap_test_suite_conn_find); +TEST_SUITE_DECL(ble_gap_test_suite_conn_gen); +TEST_SUITE_DECL(ble_gap_test_suite_conn_terminate); +TEST_SUITE_DECL(ble_gap_test_suite_disc); +TEST_SUITE_DECL(ble_gap_test_suite_mtu); +TEST_SUITE_DECL(ble_gap_test_suite_set_cb); +TEST_SUITE_DECL(ble_gap_test_suite_stop_adv); +TEST_SUITE_DECL(ble_gap_test_suite_timeout); +TEST_SUITE_DECL(ble_gap_test_suite_update_conn); +TEST_SUITE_DECL(ble_gap_test_suite_wl); +TEST_SUITE_DECL(ble_gatt_conn_suite); +TEST_SUITE_DECL(ble_gatt_disc_c_test_suite); +TEST_SUITE_DECL(ble_gatt_disc_d_test_suite); +TEST_SUITE_DECL(ble_gatt_disc_s_test_suite); +TEST_SUITE_DECL(ble_gatt_find_s_test_suite); +TEST_SUITE_DECL(ble_gatt_read_test_suite); +TEST_SUITE_DECL(ble_gatt_write_test_suite); +TEST_SUITE_DECL(ble_gatts_notify_suite); +TEST_SUITE_DECL(ble_gatts_read_test_suite); +TEST_SUITE_DECL(ble_gatts_reg_suite); +TEST_SUITE_DECL(ble_hs_adv_test_suite); +TEST_SUITE_DECL(ble_hs_conn_suite); +TEST_SUITE_DECL(ble_hs_hci_suite); +TEST_SUITE_DECL(ble_hs_id_test_suite_auto); +TEST_SUITE_DECL(ble_hs_pvcy_test_suite_irk); +TEST_SUITE_DECL(ble_l2cap_test_suite); +TEST_SUITE_DECL(ble_os_test_suite); +TEST_SUITE_DECL(ble_sm_gen_test_suite); +TEST_SUITE_DECL(ble_sm_lgcy_test_suite); +TEST_SUITE_DECL(ble_sm_sc_test_suite); +TEST_SUITE_DECL(ble_store_suite); +TEST_SUITE_DECL(ble_uuid_test_suite); + +#endif diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_test_util.c b/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_test_util.c new file mode 100644 index 00000000..5ee17e76 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_test_util.c @@ -0,0 +1,2048 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include "sysinit/sysinit.h" +#include "stats/stats.h" +#include "testutil/testutil.h" +#include "nimble/ble.h" +#include "nimble/hci_common.h" +#include "nimble/ble_hci_trans.h" +#include "host/ble_hs_adv.h" +#include "host/ble_hs_id.h" +#include "store/config/ble_store_config.h" +#include "transport/ram/ble_hci_ram.h" +#include "ble_hs_test_util.h" + +/* Our global device address. */ +uint8_t g_dev_addr[BLE_DEV_ADDR_LEN]; + +static STAILQ_HEAD(, os_mbuf_pkthdr) ble_hs_test_util_prev_tx_queue; +struct os_mbuf *ble_hs_test_util_prev_tx_cur; + +int ble_sm_test_store_obj_type; +union ble_store_key ble_sm_test_store_key; +union ble_store_value ble_sm_test_store_value; + +const struct ble_gap_adv_params ble_hs_test_util_adv_params = { + .conn_mode = BLE_GAP_CONN_MODE_UND, + .disc_mode = BLE_GAP_DISC_MODE_GEN, + + .itvl_min = 0, + .itvl_max = 0, + .channel_map = 0, + .filter_policy = 0, + .high_duty_cycle = 0, +}; + +void +ble_hs_test_util_prev_tx_enqueue(struct os_mbuf *om) +{ + struct os_mbuf_pkthdr *omp; + + assert(OS_MBUF_IS_PKTHDR(om)); + + omp = OS_MBUF_PKTHDR(om); + if (STAILQ_EMPTY(&ble_hs_test_util_prev_tx_queue)) { + STAILQ_INSERT_HEAD(&ble_hs_test_util_prev_tx_queue, omp, omp_next); + } else { + STAILQ_INSERT_TAIL(&ble_hs_test_util_prev_tx_queue, omp, omp_next); + } +} + +static struct os_mbuf * +ble_hs_test_util_prev_tx_dequeue_once(struct hci_data_hdr *out_hci_hdr) +{ + struct os_mbuf_pkthdr *omp; + struct os_mbuf *om; + int rc; + + omp = STAILQ_FIRST(&ble_hs_test_util_prev_tx_queue); + if (omp == NULL) { + return NULL; + } + STAILQ_REMOVE_HEAD(&ble_hs_test_util_prev_tx_queue, omp_next); + + om = OS_MBUF_PKTHDR_TO_MBUF(omp); + + rc = ble_hs_hci_util_data_hdr_strip(om, out_hci_hdr); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT_FATAL(out_hci_hdr->hdh_len == OS_MBUF_PKTLEN(om)); + + return om; +} + +struct os_mbuf * +ble_hs_test_util_prev_tx_dequeue(void) +{ + struct ble_l2cap_hdr l2cap_hdr; + struct hci_data_hdr hci_hdr; + struct os_mbuf *om; + uint8_t pb; + int rc; + + rc = os_mbuf_free_chain(ble_hs_test_util_prev_tx_cur); + TEST_ASSERT_FATAL(rc == 0); + + om = ble_hs_test_util_prev_tx_dequeue_once(&hci_hdr); + if (om != NULL) { + pb = BLE_HCI_DATA_PB(hci_hdr.hdh_handle_pb_bc); + TEST_ASSERT_FATAL(pb == BLE_HCI_PB_FIRST_NON_FLUSH); + + rc = ble_l2cap_parse_hdr(om, 0, &l2cap_hdr); + TEST_ASSERT_FATAL(rc == 0); + + os_mbuf_adj(om, BLE_L2CAP_HDR_SZ); + + ble_hs_test_util_prev_tx_cur = om; + while (OS_MBUF_PKTLEN(ble_hs_test_util_prev_tx_cur) < + l2cap_hdr.len) { + + om = ble_hs_test_util_prev_tx_dequeue_once(&hci_hdr); + TEST_ASSERT_FATAL(om != NULL); + + pb = BLE_HCI_DATA_PB(hci_hdr.hdh_handle_pb_bc); + TEST_ASSERT_FATAL(pb == BLE_HCI_PB_MIDDLE); + + os_mbuf_concat(ble_hs_test_util_prev_tx_cur, om); + } + } else { + ble_hs_test_util_prev_tx_cur = NULL; + } + + return ble_hs_test_util_prev_tx_cur; +} + +struct os_mbuf * +ble_hs_test_util_prev_tx_dequeue_pullup(void) +{ + struct os_mbuf *om; + + om = ble_hs_test_util_prev_tx_dequeue(); + if (om != NULL) { + om = os_mbuf_pullup(om, OS_MBUF_PKTLEN(om)); + TEST_ASSERT_FATAL(om != NULL); + ble_hs_test_util_prev_tx_cur = om; + } + + return om; +} + +int +ble_hs_test_util_prev_tx_queue_sz(void) +{ + struct os_mbuf_pkthdr *omp; + int cnt; + + cnt = 0; + STAILQ_FOREACH(omp, &ble_hs_test_util_prev_tx_queue, omp_next) { + cnt++; + } + + return cnt; +} + +void +ble_hs_test_util_prev_tx_queue_clear(void) +{ + while (!STAILQ_EMPTY(&ble_hs_test_util_prev_tx_queue)) { + ble_hs_test_util_prev_tx_dequeue(); + } +} + +static void +ble_hs_test_util_conn_params_dflt(struct ble_gap_conn_params *conn_params) +{ + conn_params->scan_itvl = 0x0010; + conn_params->scan_window = 0x0010; + conn_params->itvl_min = BLE_GAP_INITIAL_CONN_ITVL_MIN; + conn_params->itvl_max = BLE_GAP_INITIAL_CONN_ITVL_MAX; + conn_params->latency = BLE_GAP_INITIAL_CONN_LATENCY; + conn_params->supervision_timeout = BLE_GAP_INITIAL_SUPERVISION_TIMEOUT; + conn_params->min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN; + conn_params->max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN; +} + +static void +ble_hs_test_util_hcc_from_conn_params( + struct hci_create_conn *hcc, uint8_t own_addr_type, + const ble_addr_t *peer_addr, const struct ble_gap_conn_params *conn_params) +{ + hcc->scan_itvl = conn_params->scan_itvl; + hcc->scan_window = conn_params->scan_window; + + if (peer_addr == NULL) { + hcc->filter_policy = BLE_HCI_CONN_FILT_USE_WL; + hcc->peer_addr_type = 0; + memset(hcc->peer_addr, 0, 6); + } else { + hcc->filter_policy = BLE_HCI_CONN_FILT_NO_WL; + hcc->peer_addr_type = peer_addr->type; + memcpy(hcc->peer_addr, peer_addr->val, 6); + } + hcc->own_addr_type = own_addr_type; + hcc->conn_itvl_min = conn_params->itvl_min; + hcc->conn_itvl_max = conn_params->itvl_max; + hcc->conn_latency = conn_params->latency; + hcc->supervision_timeout = conn_params->supervision_timeout; + hcc->min_ce_len = conn_params->min_ce_len; + hcc->max_ce_len = conn_params->max_ce_len; +} + +void +ble_hs_test_util_create_rpa_conn(uint16_t handle, uint8_t own_addr_type, + const uint8_t *our_rpa, + uint8_t peer_addr_type, + const uint8_t *peer_id_addr, + const uint8_t *peer_rpa, + uint8_t conn_features, + ble_gap_event_fn *cb, void *cb_arg) +{ + ble_addr_t addr; + struct ble_gap_conn_complete evt; + struct ble_hci_ev_le_subev_rd_rem_used_feat evt2; + int rc; + + addr.type = peer_addr_type; + memcpy(addr.val, peer_id_addr, 6); + + rc = ble_hs_test_util_connect(own_addr_type, &addr, 0, NULL, cb, cb_arg, + 0); + TEST_ASSERT_FATAL(rc == 0); + + /* ble_gap_rx_conn_complete() will send extra HCI command, need phony ack */ + ble_hs_test_util_hci_ack_set(ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_RD_REM_FEAT), 0); + + memset(&evt, 0, sizeof evt); + evt.status = BLE_ERR_SUCCESS; + evt.connection_handle = handle; + evt.role = BLE_HCI_LE_CONN_COMPLETE_ROLE_MASTER; + evt.peer_addr_type = peer_addr_type; + memcpy(evt.peer_addr, peer_id_addr, 6); + evt.conn_itvl = BLE_GAP_INITIAL_CONN_ITVL_MAX; + evt.conn_latency = BLE_GAP_INITIAL_CONN_LATENCY; + evt.supervision_timeout = BLE_GAP_INITIAL_SUPERVISION_TIMEOUT; + memcpy(evt.local_rpa, our_rpa, 6); + memcpy(evt.peer_rpa, peer_rpa, 6); + + rc = ble_gap_rx_conn_complete(&evt, 0); + TEST_ASSERT(rc == 0); + + evt2.subev_code = BLE_HCI_LE_SUBEV_RD_REM_USED_FEAT; + evt2.status = BLE_ERR_SUCCESS; + evt2.conn_handle = htole16(handle); + memcpy(evt2.features, ((uint8_t[]){ conn_features, 0, 0, 0, 0, 0, 0, 0 }), + 8); + + ble_gap_rx_rd_rem_sup_feat_complete(&evt2); + + ble_hs_test_util_hci_out_clear(); +} + +void +ble_hs_test_util_create_conn(uint16_t handle, const uint8_t *peer_id_addr, + ble_gap_event_fn *cb, void *cb_arg) +{ + static uint8_t null_addr[6]; + + ble_hs_test_util_create_rpa_conn(handle, BLE_OWN_ADDR_PUBLIC, null_addr, + BLE_ADDR_PUBLIC, peer_id_addr, + null_addr, BLE_HS_TEST_CONN_FEAT_ALL, + cb, cb_arg); +} + +void +ble_hs_test_util_create_conn_feat(uint16_t handle, const uint8_t *peer_id_addr, + uint8_t conn_features, ble_gap_event_fn *cb, + void *cb_arg) +{ + static uint8_t null_addr[6]; + + ble_hs_test_util_create_rpa_conn(handle, BLE_OWN_ADDR_PUBLIC, null_addr, + BLE_ADDR_PUBLIC, peer_id_addr, + null_addr, conn_features, cb, cb_arg); +} + +int +ble_hs_test_util_connect(uint8_t own_addr_type, const ble_addr_t *peer_addr, + int32_t duration_ms, + const struct ble_gap_conn_params *params, + ble_gap_event_fn *cb, void *cb_arg, + uint8_t ack_status) +{ + struct ble_gap_conn_params dflt_params; + struct hci_create_conn hcc; + int rc; + + /* This function ensures the most recently sent HCI command is the expected + * create connection command. If the current test case has unverified HCI + * commands, assume we are not interested in them and clear the queue. + */ + ble_hs_test_util_hci_out_clear(); + + ble_hs_test_util_hci_ack_set( + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_CREATE_CONN), + ack_status); + + rc = ble_gap_connect(own_addr_type, peer_addr, duration_ms, params, cb, + cb_arg); + if (ack_status != 0) { + TEST_ASSERT(rc == BLE_HS_HCI_ERR(ack_status)); + } else if (rc != 0) { + return rc; + } + + if (params == NULL) { + ble_hs_test_util_conn_params_dflt(&dflt_params); + params = &dflt_params; + } + + ble_hs_test_util_hcc_from_conn_params(&hcc, own_addr_type, peer_addr, + params); + ble_hs_test_util_hci_verify_tx_create_conn(&hcc); + + return rc; +} + +int +ble_hs_test_util_conn_cancel(uint8_t ack_status) +{ + int rc; + + ble_hs_test_util_hci_ack_set( + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_CREATE_CONN_CANCEL), + ack_status); + + rc = ble_gap_conn_cancel(); + return rc; +} + +void +ble_hs_test_util_rx_conn_cancel_evt(void) +{ + ble_hs_test_util_conn_cancel(0); + ble_hs_test_util_hci_rx_conn_cancel_evt(); +} + +void +ble_hs_test_util_conn_cancel_full(void) +{ + ble_hs_test_util_conn_cancel(0); + ble_hs_test_util_rx_conn_cancel_evt(); +} + +int +ble_hs_test_util_conn_terminate(uint16_t conn_handle, uint8_t hci_status) +{ + int rc; + + ble_hs_test_util_hci_ack_set_disconnect(hci_status); + rc = ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM); + return rc; +} + +void +ble_hs_test_util_conn_disconnect(uint16_t conn_handle) +{ + int rc; + + rc = ble_hs_test_util_conn_terminate(conn_handle, 0); + TEST_ASSERT_FATAL(rc == 0); + + /* Receive disconnection complete event. */ + ble_hs_test_util_hci_rx_disconn_complete_event(conn_handle, 0, + BLE_ERR_CONN_TERM_LOCAL); +} + +int +ble_hs_test_util_disc(uint8_t own_addr_type, int32_t duration_ms, + const struct ble_gap_disc_params *disc_params, + ble_gap_event_fn *cb, void *cb_arg, int fail_idx, + uint8_t fail_status) +{ + int rc; + + ble_hs_test_util_hci_ack_set_disc(own_addr_type, fail_idx, fail_status); + rc = ble_gap_disc(own_addr_type, duration_ms, disc_params, + cb, cb_arg); + return rc; +} + +int +ble_hs_test_util_disc_cancel(uint8_t ack_status) +{ + int rc; + + ble_hs_test_util_hci_ack_set( + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_SET_SCAN_ENABLE), + ack_status); + + rc = ble_gap_disc_cancel(); + return rc; +} + +static void +ble_hs_test_util_verify_tx_rd_pwr(void) +{ + uint8_t param_len; + + ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_RD_ADV_CHAN_TXPWR, + ¶m_len); + TEST_ASSERT(param_len == 0); +} + +int +ble_hs_test_util_adv_set_fields(const struct ble_hs_adv_fields *adv_fields, + int cmd_fail_idx, uint8_t hci_status) +{ + struct ble_hs_test_util_hci_ack acks[3]; + int auto_pwr; + int rc; + int i; + + auto_pwr = adv_fields->tx_pwr_lvl_is_present && + adv_fields->tx_pwr_lvl == BLE_HS_ADV_TX_PWR_LVL_AUTO; + + i = 0; + if (auto_pwr) { + acks[i] = (struct ble_hs_test_util_hci_ack) { + BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_RD_ADV_CHAN_TXPWR), + ble_hs_test_util_hci_misc_exp_status(i, cmd_fail_idx, hci_status), + {0}, + 1, + }; + i++; + } + + acks[i] = (struct ble_hs_test_util_hci_ack) { + BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_SET_ADV_DATA), + ble_hs_test_util_hci_misc_exp_status(i, cmd_fail_idx, hci_status), + }; + i++; + + memset(acks + i, 0, sizeof acks[i]); + ble_hs_test_util_hci_ack_set_seq(acks); + + rc = ble_gap_adv_set_fields(adv_fields); + if (rc == 0 && auto_pwr) { + /* Verify tx of set advertising params command. */ + ble_hs_test_util_verify_tx_rd_pwr(); + } + + return rc; +} + +int +ble_hs_test_util_adv_rsp_set_fields(const struct ble_hs_adv_fields *adv_fields, + int cmd_fail_idx, uint8_t hci_status) +{ + struct ble_hs_test_util_hci_ack acks[3]; + int auto_pwr; + int rc; + int i; + + auto_pwr = adv_fields->tx_pwr_lvl_is_present && + adv_fields->tx_pwr_lvl == BLE_HS_ADV_TX_PWR_LVL_AUTO; + + i = 0; + if (auto_pwr) { + acks[i] = (struct ble_hs_test_util_hci_ack) { + BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_RD_ADV_CHAN_TXPWR), + ble_hs_test_util_hci_misc_exp_status(i, cmd_fail_idx, hci_status), + {0}, + 1, + }; + i++; + } + + acks[i] = (struct ble_hs_test_util_hci_ack) { + BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_SET_SCAN_RSP_DATA), + ble_hs_test_util_hci_misc_exp_status(i, cmd_fail_idx, hci_status), + }; + i++; + + memset(acks + i, 0, sizeof acks[i]); + ble_hs_test_util_hci_ack_set_seq(acks); + + rc = ble_gap_adv_rsp_set_fields(adv_fields); + if (rc == 0 && auto_pwr) { + /* Verify tx of set advertising params command. */ + ble_hs_test_util_verify_tx_rd_pwr(); + } + + return rc; +} + +int +ble_hs_test_util_adv_start(uint8_t own_addr_type, const ble_addr_t *peer_addr, + const struct ble_gap_adv_params *adv_params, + int32_t duration_ms, + ble_gap_event_fn *cb, void *cb_arg, + int fail_idx, uint8_t fail_status) +{ + struct ble_hs_test_util_hci_ack acks[6]; + int rc; + int i; + + i = 0; + + acks[i] = (struct ble_hs_test_util_hci_ack) { + BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_SET_ADV_PARAMS), + fail_idx == i ? fail_status : 0, + }; + i++; + + acks[i] = (struct ble_hs_test_util_hci_ack) { + BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_SET_ADV_ENABLE), + ble_hs_test_util_hci_misc_exp_status(i, fail_idx, fail_status), + }; + i++; + + memset(acks + i, 0, sizeof acks[i]); + + ble_hs_test_util_hci_ack_set_seq(acks); + + rc = ble_gap_adv_start(own_addr_type, peer_addr, + duration_ms, adv_params, cb, cb_arg); + + return rc; +} + +int +ble_hs_test_util_adv_stop(uint8_t hci_status) +{ + int rc; + + ble_hs_test_util_hci_ack_set( + BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_SET_ADV_ENABLE), + hci_status); + + rc = ble_gap_adv_stop(); + return rc; +} + +int +ble_hs_test_util_wl_set(ble_addr_t *addrs, uint8_t addrs_count, + int fail_idx, uint8_t fail_status) +{ + struct ble_hs_test_util_hci_ack acks[64]; + int cmd_idx; + int rc; + int i; + + TEST_ASSERT_FATAL(addrs_count < 63); + + cmd_idx = 0; + acks[cmd_idx] = (struct ble_hs_test_util_hci_ack) { + BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_CLEAR_WHITE_LIST), + ble_hs_test_util_hci_misc_exp_status(cmd_idx, fail_idx, fail_status), + }; + cmd_idx++; + + for (i = 0; i < addrs_count; i++) { + acks[cmd_idx] = (struct ble_hs_test_util_hci_ack) { + BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_ADD_WHITE_LIST), + ble_hs_test_util_hci_misc_exp_status(cmd_idx, fail_idx, fail_status), + }; + + cmd_idx++; + } + memset(acks + cmd_idx, 0, sizeof acks[cmd_idx]); + + ble_hs_test_util_hci_ack_set_seq(acks); + rc = ble_gap_wl_set(addrs, addrs_count); + return rc; +} + +int +ble_hs_test_util_conn_update(uint16_t conn_handle, + struct ble_gap_upd_params *params, + uint8_t hci_status) +{ + int rc; + + /* + * 0xFF is magic value used for cases where we expect update over L2CAP to + * be triggered - in this case we don't need phony ack. + */ + if (hci_status != 0xFF) { + ble_hs_test_util_hci_ack_set( + BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_CONN_UPDATE), + hci_status); + } + + rc = ble_gap_update_params(conn_handle, params); + return rc; +} + +int +ble_hs_test_util_set_our_irk(const uint8_t *irk, int fail_idx, + uint8_t hci_status) +{ + int rc; + + ble_hs_test_util_hci_ack_set_seq(((struct ble_hs_test_util_hci_ack[]) { + { + BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_SET_ADDR_RES_EN), + ble_hs_test_util_hci_misc_exp_status(0, fail_idx, hci_status), + }, + { + BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_CLR_RESOLV_LIST), + ble_hs_test_util_hci_misc_exp_status(1, fail_idx, hci_status), + }, + { + BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_SET_ADDR_RES_EN), + ble_hs_test_util_hci_misc_exp_status(2, fail_idx, hci_status), + }, + { + BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_SET_ADV_ENABLE), + ble_hs_test_util_hci_misc_exp_status(3, fail_idx, hci_status), + }, + { + BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_ADD_RESOLV_LIST), + ble_hs_test_util_hci_misc_exp_status(4, fail_idx, hci_status), + }, + { + BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_SET_PRIVACY_MODE), + ble_hs_test_util_hci_misc_exp_status(5, fail_idx, hci_status), + }, + { + BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_SET_PRIVACY_MODE), + ble_hs_test_util_hci_misc_exp_status(6, fail_idx, hci_status), + }, + { + 0 + } + })); + + rc = ble_hs_pvcy_set_our_irk(irk); + return rc; +} + +int +ble_hs_test_util_security_initiate(uint16_t conn_handle, uint8_t hci_status) +{ + int rc; + + ble_hs_test_util_hci_ack_set( + BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_START_ENCRYPT), hci_status); + + rc = ble_gap_security_initiate(conn_handle); + return rc; +} + +int +ble_hs_test_util_l2cap_rx_first_frag(uint16_t conn_handle, uint16_t cid, + struct hci_data_hdr *hci_hdr, + struct os_mbuf *om) +{ + int rc; + + om = ble_l2cap_prepend_hdr(om, cid, OS_MBUF_PKTLEN(om)); + TEST_ASSERT_FATAL(om != NULL); + + rc = ble_hs_test_util_l2cap_rx(conn_handle, hci_hdr, om); + return rc; +} + +int +ble_hs_test_util_l2cap_rx(uint16_t conn_handle, + struct hci_data_hdr *hci_hdr, + struct os_mbuf *om) +{ + struct ble_hs_conn *conn; + ble_l2cap_rx_fn *rx_cb; + int reject_cid; + int rc; + + ble_hs_lock(); + + conn = ble_hs_conn_find(conn_handle); + if (conn != NULL) { + rc = ble_l2cap_rx(conn, hci_hdr, om, &rx_cb, &reject_cid); + } else { + rc = os_mbuf_free_chain(om); + TEST_ASSERT_FATAL(rc == 0); + } + + ble_hs_unlock(); + + if (conn == NULL) { + rc = BLE_HS_ENOTCONN; + } else if (rc == 0) { + TEST_ASSERT_FATAL(rx_cb != NULL); + rc = rx_cb(conn->bhc_rx_chan); + ble_l2cap_remove_rx(conn, conn->bhc_rx_chan); + } else if (rc == BLE_HS_EAGAIN) { + /* More fragments on the way. */ + rc = 0; + } else { + if (reject_cid != -1) { + ble_l2cap_sig_reject_invalid_cid_tx(conn_handle, 0, 0, reject_cid); + } + } + + return rc; +} + +int +ble_hs_test_util_l2cap_rx_payload_flat(uint16_t conn_handle, uint16_t cid, + const void *data, int len) +{ + struct hci_data_hdr hci_hdr; + struct os_mbuf *om; + int rc; + + om = ble_hs_mbuf_l2cap_pkt(); + TEST_ASSERT_FATAL(om != NULL); + + rc = os_mbuf_append(om, data, len); + TEST_ASSERT_FATAL(rc == 0); + + hci_hdr.hdh_handle_pb_bc = + ble_hs_hci_util_handle_pb_bc_join(conn_handle, + BLE_HCI_PB_FIRST_FLUSH, 0); + hci_hdr.hdh_len = OS_MBUF_PKTHDR(om)->omp_len; + + rc = ble_hs_test_util_l2cap_rx_first_frag(conn_handle, cid, &hci_hdr, om); + return rc; +} + +void +ble_hs_test_util_set_att_mtu(uint16_t conn_handle, uint16_t mtu) +{ + struct ble_l2cap_chan *chan; + struct ble_hs_conn *conn; + int rc; + + if (mtu <= BLE_ATT_MTU_DFLT) { + return; + } + + ble_hs_lock(); + + rc = ble_att_conn_chan_find(conn_handle, &conn, &chan); + assert(rc == 0); + chan->my_mtu = mtu; + chan->peer_mtu = mtu; + chan->flags |= BLE_L2CAP_CHAN_F_TXED_MTU; + + ble_hs_unlock(); +} + +int +ble_hs_test_util_rx_att_mtu_cmd(uint16_t conn_handle, int is_req, uint16_t mtu) +{ + struct ble_att_mtu_cmd cmd; + uint8_t buf[BLE_ATT_MTU_CMD_SZ]; + int rc; + + cmd.bamc_mtu = mtu; + + if (is_req) { + ble_att_mtu_req_write(buf, sizeof buf, &cmd); + } else { + ble_att_mtu_rsp_write(buf, sizeof buf, &cmd); + } + + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, sizeof buf); + return rc; +} + +int +ble_hs_test_util_rx_att_find_info_req(uint16_t conn_handle, + uint16_t start_handle, + uint16_t end_handle) +{ + struct ble_att_find_info_req req; + uint8_t buf[BLE_ATT_FIND_INFO_REQ_SZ]; + int rc; + + req.bafq_start_handle = start_handle; + req.bafq_end_handle = end_handle; + + ble_att_find_info_req_write(buf, sizeof buf, &req); + + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, sizeof buf); + + return rc; +} + +int +ble_hs_test_util_rx_att_find_type_value_req(uint16_t conn_handle, + uint16_t start_handle, + uint16_t end_handle, + uint16_t attr_type, + const void *attr_val, + uint16_t attr_len) +{ + struct ble_att_find_type_value_req req; + uint8_t buf[BLE_ATT_FIND_TYPE_VALUE_REQ_BASE_SZ + 16]; + int rc; + + TEST_ASSERT(attr_len <= 16); + + req.bavq_start_handle = start_handle; + req.bavq_end_handle = end_handle; + req.bavq_attr_type = attr_type; + + ble_att_find_type_value_req_write(buf, sizeof buf, &req); + memcpy(buf + BLE_ATT_FIND_TYPE_VALUE_REQ_BASE_SZ, attr_val, attr_len); + + rc = ble_hs_test_util_l2cap_rx_payload_flat( + conn_handle, BLE_L2CAP_CID_ATT, buf, + BLE_ATT_FIND_TYPE_VALUE_REQ_BASE_SZ + attr_len); + + return rc; +} + +int +ble_hs_test_util_rx_att_read_type_req(uint16_t conn_handle, + uint16_t start_handle, + uint16_t end_handle, + const ble_uuid_t *uuid) +{ + struct ble_att_read_type_req req; + uint8_t buf[BLE_ATT_READ_TYPE_REQ_SZ_128]; + int req_len; + int rc; + + req.batq_start_handle = start_handle; + req.batq_end_handle = end_handle; + + ble_att_read_type_req_write(buf, sizeof buf, &req); + + ble_uuid_flat(uuid, buf + BLE_ATT_READ_TYPE_REQ_BASE_SZ); + req_len = BLE_ATT_READ_TYPE_REQ_BASE_SZ + ble_uuid_length(uuid); + + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, req_len); + return rc; +} + +int +ble_hs_test_util_rx_att_read_type_req16(uint16_t conn_handle, + uint16_t start_handle, + uint16_t end_handle, + uint16_t uuid16) +{ + int rc; + + rc = ble_hs_test_util_rx_att_read_type_req(conn_handle, start_handle, + end_handle, + BLE_UUID16_DECLARE(uuid16)); + return rc; +} + +int +ble_hs_test_util_rx_att_read_req(uint16_t conn_handle, uint16_t attr_handle) +{ + struct ble_att_read_req req; + uint8_t buf[BLE_ATT_READ_REQ_SZ]; + int rc; + + req.barq_handle = attr_handle; + ble_att_read_req_write(buf, sizeof buf, &req); + + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, sizeof buf); + return rc; +} + +int +ble_hs_test_util_rx_att_read_blob_req(uint16_t conn_handle, + uint16_t attr_handle, + uint16_t offset) +{ + struct ble_att_read_blob_req req; + uint8_t buf[BLE_ATT_READ_BLOB_REQ_SZ]; + int rc; + + req.babq_handle = attr_handle; + req.babq_offset = offset; + ble_att_read_blob_req_write(buf, sizeof buf, &req); + + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, sizeof buf); + return rc; +} + +int +ble_hs_test_util_rx_att_read_mult_req(uint16_t conn_handle, + const uint16_t *handles, + int num_handles) +{ + uint8_t buf[256]; + int off; + int rc; + int i; + + ble_att_read_mult_req_write(buf, sizeof buf); + + off = BLE_ATT_READ_MULT_REQ_BASE_SZ; + for (i = 0; i < num_handles; i++) { + put_le16(buf + off, handles[i]); + off += 2; + } + + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, off); + return rc; +} + +int +ble_hs_test_util_rx_att_read_group_type_req(uint16_t conn_handle, + uint16_t start_handle, + uint16_t end_handle, + const ble_uuid_t *uuid) +{ + struct ble_att_read_group_type_req req; + uint8_t buf[BLE_ATT_READ_GROUP_TYPE_REQ_SZ_128]; + int req_len; + int rc; + + req.bagq_start_handle = start_handle; + req.bagq_end_handle = end_handle; + + ble_uuid_flat(uuid, buf + BLE_ATT_READ_TYPE_REQ_BASE_SZ); + req_len = BLE_ATT_READ_GROUP_TYPE_REQ_BASE_SZ + ble_uuid_length(uuid); + + ble_att_read_group_type_req_write(buf, sizeof buf, &req); + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, req_len); + return rc; +} + +int +ble_hs_test_util_rx_att_read_group_type_req16(uint16_t conn_handle, + uint16_t start_handle, + uint16_t end_handle, + uint16_t uuid16) +{ + int rc; + + rc = ble_hs_test_util_rx_att_read_group_type_req(conn_handle, start_handle, + end_handle, + BLE_UUID16_DECLARE(uuid16)); + return rc; +} + +int +ble_hs_test_util_rx_att_write_req(uint16_t conn_handle, uint16_t attr_handle, + const void *attr_val, uint16_t attr_len) +{ + struct ble_att_write_req req; + uint8_t buf[BLE_ATT_WRITE_REQ_BASE_SZ + BLE_ATT_ATTR_MAX_LEN]; + int rc; + + req.bawq_handle = attr_handle; + ble_att_write_req_write(buf, sizeof buf, &req); + + memcpy(buf + BLE_ATT_WRITE_REQ_BASE_SZ, attr_val, attr_len); + + rc = ble_hs_test_util_l2cap_rx_payload_flat( + conn_handle, BLE_L2CAP_CID_ATT, buf, + BLE_ATT_WRITE_REQ_BASE_SZ + attr_len); + + return rc; +} + +int +ble_hs_test_util_rx_att_write_cmd(uint16_t conn_handle, uint16_t attr_handle, + const void *attr_val, uint16_t attr_len) +{ + struct ble_att_write_req req; + uint8_t buf[BLE_ATT_WRITE_REQ_BASE_SZ + BLE_ATT_ATTR_MAX_LEN]; + int rc; + + req.bawq_handle = attr_handle; + ble_att_write_cmd_write(buf, sizeof buf, &req); + + memcpy(buf + BLE_ATT_WRITE_REQ_BASE_SZ, attr_val, attr_len); + + rc = ble_hs_test_util_l2cap_rx_payload_flat( + conn_handle, BLE_L2CAP_CID_ATT, buf, + BLE_ATT_WRITE_REQ_BASE_SZ + attr_len); + + return rc; +} + +int +ble_hs_test_util_rx_att_prep_write_req(uint16_t conn_handle, + uint16_t attr_handle, + uint16_t offset, + const void *attr_val, + uint16_t attr_len) +{ + struct ble_att_prep_write_cmd prep_req; + uint8_t buf[BLE_ATT_PREP_WRITE_CMD_BASE_SZ + BLE_ATT_ATTR_MAX_LEN]; + int rc; + + prep_req.bapc_handle = attr_handle; + prep_req.bapc_offset = offset; + ble_att_prep_write_req_write(buf, sizeof buf, &prep_req); + memcpy(buf + BLE_ATT_PREP_WRITE_CMD_BASE_SZ, attr_val, attr_len); + + rc = ble_hs_test_util_l2cap_rx_payload_flat( + conn_handle, BLE_L2CAP_CID_ATT, buf, + BLE_ATT_PREP_WRITE_CMD_BASE_SZ + attr_len); + + return rc; +} + +int +ble_hs_test_util_rx_att_exec_write_req(uint16_t conn_handle, uint8_t flags) +{ + struct ble_att_exec_write_req exec_req; + uint8_t buf[BLE_ATT_EXEC_WRITE_REQ_SZ]; + int rc; + + exec_req.baeq_flags = flags; + ble_att_exec_write_req_write(buf, sizeof buf, &exec_req); + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, + BLE_ATT_EXEC_WRITE_REQ_SZ); + return rc; +} + +int +ble_hs_test_util_rx_att_notify_req(uint16_t conn_handle, + uint16_t attr_handle, + void *attr_val, + uint16_t attr_len) +{ + struct ble_att_notify_req req; + uint8_t buf[BLE_ATT_NOTIFY_REQ_BASE_SZ + BLE_ATT_ATTR_MAX_LEN]; + int rc; + + req.banq_handle = attr_handle; + ble_att_notify_req_write(buf, sizeof buf, &req); + memcpy(buf + BLE_ATT_NOTIFY_REQ_BASE_SZ, attr_val, attr_len); + + rc = ble_hs_test_util_l2cap_rx_payload_flat( + conn_handle, BLE_L2CAP_CID_ATT, buf, + BLE_ATT_NOTIFY_REQ_BASE_SZ + attr_len); + + return rc; +} + +int +ble_hs_test_util_rx_att_indicate_req(uint16_t conn_handle, + uint16_t attr_handle, + void *attr_val, + uint16_t attr_len) +{ + struct ble_att_indicate_req req; + uint8_t buf[BLE_ATT_INDICATE_REQ_BASE_SZ + BLE_ATT_ATTR_MAX_LEN]; + int rc; + + req.baiq_handle = attr_handle; + ble_att_indicate_req_write(buf, sizeof buf, &req); + memcpy(buf + BLE_ATT_INDICATE_REQ_BASE_SZ, attr_val, attr_len); + + rc = ble_hs_test_util_l2cap_rx_payload_flat( + conn_handle, BLE_L2CAP_CID_ATT, buf, + BLE_ATT_INDICATE_REQ_BASE_SZ + attr_len); + + return rc; +} + +void +ble_hs_test_util_rx_att_err_rsp(uint16_t conn_handle, uint8_t req_op, + uint8_t error_code, uint16_t err_handle) +{ + struct ble_att_error_rsp rsp; + uint8_t buf[BLE_ATT_ERROR_RSP_SZ]; + int rc; + + rsp.baep_req_op = req_op; + rsp.baep_handle = err_handle; + rsp.baep_error_code = error_code; + + ble_att_error_rsp_write(buf, sizeof buf, &rsp); + + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + buf, sizeof buf); + TEST_ASSERT(rc == 0); +} + +void +ble_hs_test_util_verify_tx_prep_write(uint16_t attr_handle, uint16_t offset, + const void *data, int data_len) +{ + struct ble_att_prep_write_cmd req; + struct os_mbuf *om; + + om = ble_hs_test_util_prev_tx_dequeue(); + TEST_ASSERT_FATAL(om != NULL); + TEST_ASSERT(OS_MBUF_PKTLEN(om) == + BLE_ATT_PREP_WRITE_CMD_BASE_SZ + data_len); + + om = os_mbuf_pullup(om, BLE_ATT_PREP_WRITE_CMD_BASE_SZ); + TEST_ASSERT_FATAL(om != NULL); + + ble_att_prep_write_req_parse(om->om_data, om->om_len, &req); + TEST_ASSERT(req.bapc_handle == attr_handle); + TEST_ASSERT(req.bapc_offset == offset); + TEST_ASSERT(os_mbuf_cmpf(om, BLE_ATT_PREP_WRITE_CMD_BASE_SZ, + data, data_len) == 0); +} + +void +ble_hs_test_util_verify_tx_exec_write(uint8_t expected_flags) +{ + struct ble_att_exec_write_req req; + struct os_mbuf *om; + + om = ble_hs_test_util_prev_tx_dequeue_pullup(); + TEST_ASSERT_FATAL(om != NULL); + TEST_ASSERT(om->om_len == BLE_ATT_EXEC_WRITE_REQ_SZ); + + ble_att_exec_write_req_parse(om->om_data, om->om_len, &req); + TEST_ASSERT(req.baeq_flags == expected_flags); +} + +void +ble_hs_test_util_verify_tx_find_type_value(uint16_t start_handle, + uint16_t end_handle, + uint16_t attr_type, + const void *value, + uint16_t value_len) +{ + struct ble_att_find_type_value_req req; + struct os_mbuf *om; + + om = ble_hs_test_util_prev_tx_dequeue_pullup(); + TEST_ASSERT_FATAL(om != NULL); + TEST_ASSERT(om->om_len == BLE_ATT_FIND_TYPE_VALUE_REQ_BASE_SZ + value_len); + + ble_att_find_type_value_req_parse(om->om_data, om->om_len, &req); + TEST_ASSERT(req.bavq_start_handle == start_handle); + TEST_ASSERT(req.bavq_end_handle == end_handle); + TEST_ASSERT(req.bavq_attr_type == attr_type); + TEST_ASSERT(memcmp(om->om_data + BLE_ATT_FIND_TYPE_VALUE_REQ_BASE_SZ, + value, + value_len) == 0); +} + +void +ble_hs_test_util_verify_tx_disc_svc_uuid(const ble_uuid_t *uuid) +{ + uint8_t uuid_buf[16]; + + ble_uuid_flat(uuid, uuid_buf); + ble_hs_test_util_verify_tx_find_type_value( + 1, 0xffff, BLE_ATT_UUID_PRIMARY_SERVICE, + uuid_buf, ble_uuid_length(uuid)); +} + +void +ble_hs_test_util_verify_tx_read_rsp_gen(uint8_t att_op, + uint8_t *attr_data, int attr_len) +{ + struct os_mbuf *om; + uint8_t u8; + int rc; + int i; + + om = ble_hs_test_util_prev_tx_dequeue(); + + rc = os_mbuf_copydata(om, 0, 1, &u8); + TEST_ASSERT(rc == 0); + TEST_ASSERT(u8 == att_op); + + for (i = 0; i < attr_len; i++) { + rc = os_mbuf_copydata(om, i + 1, 1, &u8); + TEST_ASSERT(rc == 0); + TEST_ASSERT(u8 == attr_data[i]); + } + + rc = os_mbuf_copydata(om, i + 1, 1, &u8); + TEST_ASSERT(rc != 0); +} + +void +ble_hs_test_util_verify_tx_read_rsp(uint8_t *attr_data, int attr_len) +{ + ble_hs_test_util_verify_tx_read_rsp_gen(BLE_ATT_OP_READ_RSP, + attr_data, attr_len); +} + +void +ble_hs_test_util_verify_tx_read_blob_rsp(uint8_t *attr_data, int attr_len) +{ + ble_hs_test_util_verify_tx_read_rsp_gen(BLE_ATT_OP_READ_BLOB_RSP, + attr_data, attr_len); +} + +void +ble_hs_test_util_verify_tx_write_rsp(void) +{ + struct os_mbuf *om; + uint8_t u8; + int rc; + + om = ble_hs_test_util_prev_tx_dequeue(); + + rc = os_mbuf_copydata(om, 0, 1, &u8); + TEST_ASSERT(rc == 0); + TEST_ASSERT(u8 == BLE_ATT_OP_WRITE_RSP); +} + +void +ble_hs_test_util_verify_tx_mtu_cmd(int is_req, uint16_t mtu) +{ + struct ble_att_mtu_cmd cmd; + struct os_mbuf *om; + + om = ble_hs_test_util_prev_tx_dequeue_pullup(); + TEST_ASSERT_FATAL(om != NULL); + + if (is_req) { + ble_att_mtu_req_parse(om->om_data, om->om_len, &cmd); + } else { + ble_att_mtu_rsp_parse(om->om_data, om->om_len, &cmd); + } + + TEST_ASSERT(cmd.bamc_mtu == mtu); +} + +void +ble_hs_test_util_verify_tx_find_info_rsp( + struct ble_hs_test_util_att_info_entry *entries) +{ + struct ble_hs_test_util_att_info_entry *entry; + struct ble_att_find_info_rsp rsp; + struct os_mbuf *om; + uint16_t handle; + uint8_t buf[BLE_ATT_FIND_INFO_RSP_BASE_SZ]; + ble_uuid_any_t uuid; + int off; + int rc; + + off = 0; + + om = ble_hs_test_util_prev_tx_dequeue_pullup(); + TEST_ASSERT_FATAL(om); + + rc = os_mbuf_copydata(om, off, sizeof buf, buf); + TEST_ASSERT(rc == 0); + off += sizeof buf; + + ble_att_find_info_rsp_parse(buf, sizeof buf, &rsp); + + for (entry = entries; entry->handle != 0; entry++) { + rc = os_mbuf_copydata(om, off, 2, &handle); + TEST_ASSERT(rc == 0); + off += 2; + + handle = get_le16((void *)&handle); + TEST_ASSERT(handle == entry->handle); + + if (entry->uuid->type == BLE_UUID_TYPE_16) { + TEST_ASSERT(rsp.bafp_format == + BLE_ATT_FIND_INFO_RSP_FORMAT_16BIT); + + ble_uuid_init_from_att_mbuf(&uuid, om, off, 2); + TEST_ASSERT(rc == 0); + off += 2; + } else { + TEST_ASSERT(rsp.bafp_format == + BLE_ATT_FIND_INFO_RSP_FORMAT_128BIT); + + rc = ble_uuid_init_from_att_mbuf(&uuid, om, off, 16); + TEST_ASSERT(rc == 0); + off += 16; + } + + TEST_ASSERT(ble_uuid_cmp(entry->uuid, &uuid.u) == 0); + } + + /* Ensure there is no extra data in the response. */ + TEST_ASSERT(off == OS_MBUF_PKTHDR(om)->omp_len); +} + +void +ble_hs_test_util_verify_tx_read_group_type_rsp( + struct ble_hs_test_util_att_group_type_entry *entries) +{ + struct ble_hs_test_util_att_group_type_entry *entry; + struct ble_att_read_group_type_rsp rsp; + struct os_mbuf *om; + uint16_t u16; + ble_uuid_any_t uuid; + int off; + int rc; + + om = ble_hs_test_util_prev_tx_dequeue_pullup(); + TEST_ASSERT_FATAL(om); + + ble_att_read_group_type_rsp_parse(om->om_data, om->om_len, &rsp); + + off = BLE_ATT_READ_GROUP_TYPE_RSP_BASE_SZ; + for (entry = entries; entry->start_handle != 0; entry++) { + if (entry->uuid->type == BLE_UUID_TYPE_16) { + TEST_ASSERT(rsp.bagp_length == + BLE_ATT_READ_GROUP_TYPE_ADATA_SZ_16); + } else { + TEST_ASSERT(rsp.bagp_length == + BLE_ATT_READ_GROUP_TYPE_ADATA_SZ_128); + } + + rc = os_mbuf_copydata(om, off, 2, &u16); + TEST_ASSERT(rc == 0); + put_le16(&u16, u16); + TEST_ASSERT(u16 == entry->start_handle); + off += 2; + + rc = os_mbuf_copydata(om, off, 2, &u16); + TEST_ASSERT(rc == 0); + put_le16(&u16, u16); + TEST_ASSERT(u16 == entry->end_handle); + off += 2; + + if (entry->uuid->type == BLE_UUID_TYPE_16) { + rc = ble_uuid_init_from_att_mbuf(&uuid, om, off, 2); + TEST_ASSERT(rc == 0); + } else { + rc = ble_uuid_init_from_att_mbuf(&uuid, om, off, 16); + TEST_ASSERT(rc == 0); + } + + TEST_ASSERT(ble_uuid_cmp(&uuid.u, entry->uuid) == 0); + off += ble_uuid_length(&uuid.u); + } + + /* Ensure there is no extra data in the response. */ + TEST_ASSERT(off == OS_MBUF_PKTLEN(om)); +} + +void +ble_hs_test_util_verify_tx_err_rsp(uint8_t req_op, uint16_t handle, + uint8_t error_code) +{ + struct ble_att_error_rsp rsp; + struct os_mbuf *om; + uint8_t buf[BLE_ATT_ERROR_RSP_SZ]; + int rc; + + om = ble_hs_test_util_prev_tx_dequeue(); + + rc = os_mbuf_copydata(om, 0, sizeof buf, buf); + TEST_ASSERT(rc == 0); + + ble_att_error_rsp_parse(buf, sizeof buf, &rsp); + + TEST_ASSERT(rsp.baep_req_op == req_op); + TEST_ASSERT(rsp.baep_handle == handle); + TEST_ASSERT(rsp.baep_error_code == error_code); +} + +void +ble_hs_test_util_verify_tx_write_cmd(uint16_t handle, const void *data, + uint16_t data_len) +{ + struct ble_att_write_req req; + struct os_mbuf *om; + uint8_t buf[BLE_ATT_WRITE_CMD_BASE_SZ]; + int rc; + + om = ble_hs_test_util_prev_tx_dequeue(); + + rc = os_mbuf_copydata(om, 0, sizeof buf, buf); + TEST_ASSERT(rc == 0); + + ble_att_write_cmd_parse(buf, sizeof buf, &req); + + TEST_ASSERT(req.bawq_handle == handle); + + os_mbuf_adj(om, sizeof buf); + TEST_ASSERT(OS_MBUF_PKTLEN(om) == data_len); + TEST_ASSERT(os_mbuf_cmpf(om, 0, data, data_len) == 0); +} + +static struct os_mbuf * +ble_hs_test_util_verify_tx_l2cap_sig_hdr(uint8_t op, uint8_t id, + uint16_t payload_len, + struct ble_l2cap_sig_hdr *out_hdr) +{ + struct ble_l2cap_sig_hdr hdr; + struct os_mbuf *om; + + om = ble_hs_test_util_prev_tx_dequeue(); + TEST_ASSERT_FATAL(om != NULL); + + TEST_ASSERT(OS_MBUF_PKTLEN(om) == BLE_L2CAP_SIG_HDR_SZ + payload_len); + ble_l2cap_sig_hdr_parse(om->om_data, om->om_len, &hdr); + TEST_ASSERT(hdr.op == op); + if (id != 0) { + TEST_ASSERT(hdr.identifier == id); + } + TEST_ASSERT(hdr.length == payload_len); + + om->om_data += BLE_L2CAP_SIG_HDR_SZ; + om->om_len -= BLE_L2CAP_SIG_HDR_SZ; + + if (out_hdr != NULL) { + *out_hdr = hdr; + } + + return om; +} + +int +ble_hs_test_util_inject_rx_l2cap_sig(uint16_t conn_handle, uint8_t opcode, + uint8_t id, void *cmd, uint16_t cmd_size) +{ + void *r; + struct hci_data_hdr hci_hdr; + struct os_mbuf *om; + int rc; + + hci_hdr = BLE_HS_TEST_UTIL_L2CAP_HCI_HDR(2, BLE_HCI_PB_FIRST_FLUSH, + BLE_L2CAP_HDR_SZ + BLE_L2CAP_SIG_HDR_SZ + cmd_size); + + r = ble_l2cap_sig_cmd_get(opcode, id, cmd_size, &om); + TEST_ASSERT_FATAL(r != NULL); + + memcpy(r, cmd, cmd_size); + + rc = ble_hs_test_util_l2cap_rx_first_frag(conn_handle, BLE_L2CAP_CID_SIG, + &hci_hdr, om); + return rc; +} + +/** + * @return The L2CAP sig identifier in the request/response. + */ +uint8_t +ble_hs_test_util_verify_tx_l2cap_sig(uint16_t opcode, void *cmd, + uint16_t cmd_size) +{ + struct ble_l2cap_sig_hdr hdr; + struct os_mbuf *om; + + om = ble_hs_test_util_verify_tx_l2cap_sig_hdr(opcode, 0, cmd_size, &hdr); + om = os_mbuf_pullup(om, cmd_size); + + /* Verify payload. */ + TEST_ASSERT(memcmp(om->om_data, cmd, cmd_size) == 0); + + return hdr.identifier; +} + +void +ble_hs_test_util_verify_tx_l2cap(struct os_mbuf *txom) +{ + struct os_mbuf *om; + + om = ble_hs_test_util_prev_tx_dequeue(); + TEST_ASSERT_FATAL(om != NULL); + + /* TODO Handle fragmentation */ + TEST_ASSERT_FATAL(os_mbuf_cmpm(om, 0, txom, 0, OS_MBUF_PKTLEN(om)) == 0); +} + +void +ble_hs_test_util_inject_rx_l2cap(uint16_t conn_handle, uint16_t cid, + struct os_mbuf *rxom) +{ + struct hci_data_hdr hci_hdr; + int rc; + + hci_hdr = BLE_HS_TEST_UTIL_L2CAP_HCI_HDR(2, BLE_HCI_PB_FIRST_FLUSH, + BLE_L2CAP_HDR_SZ + + BLE_L2CAP_SIG_HDR_SZ + + OS_MBUF_PKTLEN(rxom)); + + rc = ble_hs_test_util_l2cap_rx_first_frag(conn_handle, cid, &hci_hdr, rxom); + TEST_ASSERT(rc == 0); +} + +static void +ble_l2cap_test_update_req_swap(struct ble_l2cap_sig_update_req *dst, + struct ble_l2cap_sig_update_req *src) +{ + dst->itvl_min = le16toh(src->itvl_min); + dst->itvl_max = le16toh(src->itvl_max); + dst->slave_latency = le16toh(src->slave_latency); + dst->timeout_multiplier = le16toh(src->timeout_multiplier); +} + +static void +ble_l2cap_test_update_req_parse(void *payload, int len, + struct ble_l2cap_sig_update_req *dst) +{ + BLE_HS_DBG_ASSERT(len >= BLE_L2CAP_SIG_UPDATE_REQ_SZ); + ble_l2cap_test_update_req_swap(dst, payload); +} + +/** + * @return The L2CAP sig identifier in the request. + */ +uint8_t +ble_hs_test_util_verify_tx_l2cap_update_req( + struct ble_l2cap_sig_update_params *params) +{ + struct ble_l2cap_sig_update_req req; + struct ble_l2cap_sig_hdr hdr; + struct os_mbuf *om; + + om = ble_hs_test_util_verify_tx_l2cap_sig_hdr(BLE_L2CAP_SIG_OP_UPDATE_REQ, + 0, + BLE_L2CAP_SIG_UPDATE_REQ_SZ, + &hdr); + + /* Verify payload. */ + ble_l2cap_test_update_req_parse(om->om_data, om->om_len, &req); + TEST_ASSERT(req.itvl_min == params->itvl_min); + TEST_ASSERT(req.itvl_max == params->itvl_max); + TEST_ASSERT(req.slave_latency == params->slave_latency); + TEST_ASSERT(req.timeout_multiplier == params->timeout_multiplier); + + return hdr.identifier; +} + +static void +ble_l2cap_sig_update_rsp_parse(void *payload, int len, + struct ble_l2cap_sig_update_rsp *dst) +{ + struct ble_l2cap_sig_update_rsp *src = payload; + + BLE_HS_DBG_ASSERT(len >= BLE_L2CAP_SIG_UPDATE_RSP_SZ); + dst->result = le16toh(src->result); +} + +int +ble_hs_test_util_rx_l2cap_update_rsp(uint16_t conn_handle, + uint8_t id, uint16_t result) +{ + struct ble_l2cap_sig_update_rsp *rsp; + struct hci_data_hdr hci_hdr; + struct os_mbuf *om; + int rc; + + hci_hdr = BLE_HS_TEST_UTIL_L2CAP_HCI_HDR( + 2, BLE_HCI_PB_FIRST_FLUSH, + BLE_L2CAP_HDR_SZ + BLE_L2CAP_SIG_HDR_SZ + BLE_L2CAP_SIG_UPDATE_RSP_SZ); + + rsp = ble_l2cap_sig_cmd_get(BLE_L2CAP_SIG_OP_UPDATE_RSP, id, + BLE_L2CAP_SIG_UPDATE_RSP_SZ, &om); + TEST_ASSERT_FATAL(rsp != NULL); + + rsp->result = htole16(result); + + rc = ble_hs_test_util_l2cap_rx_first_frag(conn_handle, BLE_L2CAP_CID_SIG, + &hci_hdr, om); + return rc; +} + +void +ble_hs_test_util_verify_tx_l2cap_update_rsp(uint8_t exp_id, + uint16_t exp_result) +{ + struct ble_l2cap_sig_update_rsp rsp; + struct os_mbuf *om; + + om = ble_hs_test_util_verify_tx_l2cap_sig_hdr(BLE_L2CAP_SIG_OP_UPDATE_RSP, + exp_id, + BLE_L2CAP_SIG_UPDATE_RSP_SZ, + NULL); + + ble_l2cap_sig_update_rsp_parse(om->om_data, om->om_len, &rsp); + TEST_ASSERT(rsp.result == exp_result); +} + +void +ble_hs_test_util_set_static_rnd_addr(const uint8_t *addr) +{ + int rc; + + ble_hs_test_util_hci_ack_set( + BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_SET_RAND_ADDR), 0); + + rc = ble_hs_id_set_rnd(addr); + + TEST_ASSERT_FATAL(rc == 0); + + ble_hs_test_util_hci_out_first(); +} + +struct os_mbuf * +ble_hs_test_util_om_from_flat(const void *buf, uint16_t len) +{ + struct os_mbuf *om; + + om = ble_hs_mbuf_from_flat(buf, len); + TEST_ASSERT_FATAL(om != NULL); + + return om; +} + +int +ble_hs_test_util_flat_attr_cmp(const struct ble_hs_test_util_flat_attr *a, + const struct ble_hs_test_util_flat_attr *b) +{ + if (a->handle != b->handle) { + return -1; + } + if (a->offset != b->offset) { + return -1; + } + if (a->value_len != b->value_len) { + return -1; + } + return memcmp(a->value, b->value, a->value_len); +} + +void +ble_hs_test_util_attr_to_flat(struct ble_hs_test_util_flat_attr *flat, + const struct ble_gatt_attr *attr) +{ + int rc; + + flat->handle = attr->handle; + flat->offset = attr->offset; + rc = ble_hs_mbuf_to_flat(attr->om, flat->value, sizeof flat->value, + &flat->value_len); + TEST_ASSERT_FATAL(rc == 0); +} + +void +ble_hs_test_util_attr_from_flat(struct ble_gatt_attr *attr, + const struct ble_hs_test_util_flat_attr *flat) +{ + attr->handle = flat->handle; + attr->offset = flat->offset; + attr->om = ble_hs_test_util_om_from_flat(flat->value, flat->value_len); +} + +int +ble_hs_test_util_read_local_flat(uint16_t attr_handle, uint16_t max_len, + void *buf, uint16_t *out_len) +{ + struct os_mbuf *om; + int rc; + + rc = ble_att_svr_read_local(attr_handle, &om); + if (rc != 0) { + return rc; + } + + TEST_ASSERT_FATAL(OS_MBUF_PKTLEN(om) <= max_len); + + rc = os_mbuf_copydata(om, 0, OS_MBUF_PKTLEN(om), buf); + TEST_ASSERT_FATAL(rc == 0); + + *out_len = OS_MBUF_PKTLEN(om); + + rc = os_mbuf_free_chain(om); + TEST_ASSERT_FATAL(rc == 0); + return 0; +} + +int +ble_hs_test_util_write_local_flat(uint16_t attr_handle, + const void *buf, uint16_t buf_len) +{ + struct os_mbuf *om; + int rc; + + om = ble_hs_test_util_om_from_flat(buf, buf_len); + rc = ble_att_svr_write_local(attr_handle, om); + return rc; +} + +int +ble_hs_test_util_gatt_write_flat(uint16_t conn_handle, uint16_t attr_handle, + const void *data, uint16_t data_len, + ble_gatt_attr_fn *cb, void *cb_arg) +{ + struct os_mbuf *om; + int rc; + + om = ble_hs_test_util_om_from_flat(data, data_len); + rc = ble_gattc_write(conn_handle, attr_handle, om, cb, cb_arg); + + return rc; +} + +int +ble_hs_test_util_gatt_write_no_rsp_flat(uint16_t conn_handle, + uint16_t attr_handle, + const void *data, uint16_t data_len) +{ + struct os_mbuf *om; + int rc; + + om = ble_hs_test_util_om_from_flat(data, data_len); + rc = ble_gattc_write_no_rsp(conn_handle, attr_handle, om); + + return rc; +} + +int +ble_hs_test_util_gatt_write_long_flat(uint16_t conn_handle, + uint16_t attr_handle, + const void *data, uint16_t data_len, + ble_gatt_attr_fn *cb, void *cb_arg) +{ + struct os_mbuf *om; + uint16_t offset = 0; + int rc; + + om = ble_hs_test_util_om_from_flat(data, data_len); + rc = ble_gattc_write_long(conn_handle, attr_handle, offset, om, cb, cb_arg); + + return rc; +} + +static int +ble_hs_test_util_mbuf_chain_len(const struct os_mbuf *om) +{ + int count; + + count = 0; + while (om != NULL) { + count++; + om = SLIST_NEXT(om, om_next); + } + + return count; +} + +static int +ble_hs_test_util_num_mbufs(void) +{ + return os_msys_count() + ble_hs_hci_frag_num_mbufs(); +} + +static int +ble_hs_test_util_num_mbufs_free(void) +{ + return os_msys_num_free() + ble_hs_hci_frag_num_mbufs_free(); +} + +struct os_mbuf * +ble_hs_test_util_mbuf_alloc_all_but(int count) +{ + struct os_mbuf *prev; + struct os_mbuf *om; + int rc; + int i; + + /* Allocate all available mbufs and put them in a single chain. */ + prev = NULL; + while (1) { + om = os_msys_get(0, 0); + if (om == NULL) { + break; + } + + if (prev != NULL) { + SLIST_NEXT(om, om_next) = prev; + } + + prev = om; + } + + /* Now free 'count' mbufs. */ + for (i = 0; i < count; i++) { + TEST_ASSERT_FATAL(prev != NULL); + om = SLIST_NEXT(prev, om_next); + rc = os_mbuf_free(prev); + TEST_ASSERT_FATAL(rc == 0); + + prev = om; + } + + return prev; +} + +int +ble_hs_test_util_mbuf_count(const struct ble_hs_test_util_mbuf_params *params) +{ + const struct ble_att_prep_entry *prep; + const struct os_mbuf_pkthdr *omp; + const struct ble_l2cap_chan *chan; + const struct ble_hs_conn *conn; + const struct os_mbuf *om; + int count; + int i; + + ble_hs_process_rx_data_queue(); + + count = ble_hs_test_util_num_mbufs_free(); + + if (params->prev_tx) { + count += ble_hs_test_util_mbuf_chain_len(ble_hs_test_util_prev_tx_cur); + STAILQ_FOREACH(omp, &ble_hs_test_util_prev_tx_queue, omp_next) { + om = OS_MBUF_PKTHDR_TO_MBUF(omp); + count += ble_hs_test_util_mbuf_chain_len(om); + } + } + + ble_hs_lock(); + for (i = 0; ; i++) { + conn = ble_hs_conn_find_by_idx(i); + if (conn == NULL) { + break; + } + + if (params->rx_queue) { + SLIST_FOREACH(chan, &conn->bhc_channels, next) { + count += ble_hs_test_util_mbuf_chain_len(chan->rx_buf); + } + } + + if (params->prep_list) { + SLIST_FOREACH(prep, &conn->bhc_att_svr.basc_prep_list, bape_next) { + count += ble_hs_test_util_mbuf_chain_len(prep->bape_value); + } + } + } + ble_hs_unlock(); + + return count; +} + +void +ble_hs_test_util_assert_mbufs_freed( + const struct ble_hs_test_util_mbuf_params *params) +{ + static const struct ble_hs_test_util_mbuf_params dflt = { + .prev_tx = 1, + .rx_queue = 1, + .prep_list = 1, + }; + + int count; + + if (params == NULL) { + params = &dflt; + } + + count = ble_hs_test_util_mbuf_count(params); + TEST_ASSERT(count == ble_hs_test_util_num_mbufs()); +} + +static int +ble_hs_test_util_pkt_txed(struct os_mbuf *om, void *arg) +{ + ble_hs_test_util_prev_tx_enqueue(om); + return 0; +} + +static int +ble_hs_test_util_hci_txed(uint8_t *cmdbuf, void *arg) +{ + ble_hs_test_util_hci_out_enqueue(cmdbuf); + ble_hci_trans_buf_free(cmdbuf); + return 0; +} + +int +ble_hs_test_util_num_cccds(void) +{ + struct ble_store_value_cccd val; + struct ble_store_key_cccd key = { }; + int rc; + + key.peer_addr = *BLE_ADDR_ANY; + for (key.idx = 0; ; key.idx++) { + rc = ble_store_read_cccd(&key, &val); + switch (rc) { + case 0: + break; + + case BLE_HS_ENOENT: + return key.idx; + + default: + TEST_ASSERT_FATAL(0); + } + } +} + +int +ble_hs_test_util_num_our_secs(void) +{ + struct ble_store_value_sec val; + struct ble_store_key_sec key = { }; + int rc; + + key.peer_addr = *BLE_ADDR_ANY; + for (key.idx = 0; ; key.idx++) { + rc = ble_store_read_our_sec(&key, &val); + switch (rc) { + case 0: + break; + + case BLE_HS_ENOENT: + return key.idx; + + default: + TEST_ASSERT_FATAL(0); + } + } +} + +int +ble_hs_test_util_num_peer_secs(void) +{ + struct ble_store_value_sec val; + struct ble_store_key_sec key = { }; + int rc; + + key.peer_addr = *BLE_ADDR_ANY; + for (key.idx = 0; ; key.idx++) { + rc = ble_store_read_peer_sec(&key, &val); + switch (rc) { + case 0: + break; + + case BLE_HS_ENOENT: + return key.idx; + + default: + TEST_ASSERT_FATAL(0); + } + } +} + +static int +ble_hs_test_util_store_read(int obj_type, const union ble_store_key *key, + union ble_store_value *value) +{ + int rc; + + ble_sm_test_store_obj_type = obj_type; + ble_sm_test_store_key = *key; + + rc = ble_store_config_read(obj_type, key, value); + ble_sm_test_store_value = *value; + + return rc; +} + +static int +ble_hs_test_util_store_write(int obj_type, const union ble_store_value *value) +{ + int rc; + + ble_sm_test_store_obj_type = obj_type; + + rc = ble_store_config_write(obj_type, value); + ble_sm_test_store_value = *value; + + return rc; +} + +static int +ble_hs_test_util_store_delete(int obj_type, const union ble_store_key *key) +{ + int rc; + + ble_sm_test_store_obj_type = obj_type; + ble_sm_test_store_key = *key; + + rc = ble_store_config_delete(obj_type, key); + return rc; +} + +void +ble_hs_test_util_reg_svcs(const struct ble_gatt_svc_def *svcs, + ble_gatt_register_fn *reg_cb, + void *cb_arg) +{ + int rc; + + ble_hs_cfg.gatts_register_cb = reg_cb; + ble_hs_cfg.gatts_register_arg = cb_arg; + + rc = ble_gatts_reset(); + TEST_ASSERT_FATAL(rc == 0); + + rc = ble_gatts_add_svcs(svcs); + TEST_ASSERT_FATAL(rc == 0); + + rc = ble_gatts_start(); + TEST_ASSERT_FATAL(rc == 0); +} + + +void +ble_hs_test_util_init_no_sysinit_no_start(void) +{ + STAILQ_INIT(&ble_hs_test_util_prev_tx_queue); + ble_hs_test_util_prev_tx_cur = NULL; + + ble_hs_hci_set_phony_ack_cb(NULL); + + ble_hci_trans_cfg_ll(ble_hs_test_util_hci_txed, NULL, + ble_hs_test_util_pkt_txed, NULL); + + ble_hs_test_util_hci_ack_set_startup(); + + ble_hs_enabled_state = BLE_HS_ENABLED_STATE_OFF; + + ble_hs_max_services = 16; + ble_hs_max_client_configs = 32; + ble_hs_max_attrs = 64; + + ble_hs_test_util_hci_out_clear(); + + ble_hs_cfg.store_read_cb = ble_hs_test_util_store_read; + ble_hs_cfg.store_write_cb = ble_hs_test_util_store_write; + ble_hs_cfg.store_delete_cb = ble_hs_test_util_store_delete; + + ble_store_clear(); +} + +void +ble_hs_test_util_init_no_start(void) +{ + sysinit(); + ble_hs_test_util_init_no_sysinit_no_start(); +} + +void +ble_hs_test_util_init(void) +{ + int rc; + + ble_hs_test_util_init_no_start(); + + rc = ble_hs_start(); + TEST_ASSERT_FATAL(rc == 0); + + ble_hs_test_util_hci_out_clear(); + ble_hs_test_util_hci_acks_clear(); + + /* Clear random address. */ + ble_hs_id_rnd_reset(); +} diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_test_util.h b/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_test_util.h new file mode 100644 index 00000000..411443cf --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_test_util.h @@ -0,0 +1,305 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_HS_TEST_UTIL_ +#define H_BLE_HS_TEST_UTIL_ + +#include +#include "host/ble_gap.h" +#include "ble_hs_priv.h" +#include "ble_hs_test_util_hci.h" +#ifdef __cplusplus +extern "C" { +#endif + + +/* TODO this is currently copied from ble_ll_conn_priv.h and eventually + * should not be needed... + */ +struct hci_create_conn +{ + uint16_t scan_itvl; + uint16_t scan_window; + uint8_t filter_policy; + uint8_t peer_addr_type; + uint8_t peer_addr[BLE_DEV_ADDR_LEN]; + uint8_t own_addr_type; + uint16_t conn_itvl_min; + uint16_t conn_itvl_max; + uint16_t conn_latency; + uint16_t supervision_timeout; + uint16_t min_ce_len; + uint16_t max_ce_len; +}; + +struct ble_hs_conn; +struct ble_l2cap_chan; +struct hci_disconn_complete; +struct hci_create_conn; + +#define BLE_HS_TEST_UTIL_LE_OPCODE(ocf) \ + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, (ocf)) + +#define BLE_HS_TEST_UTIL_PUB_ADDR_VAL { 0x0a, 0x54, 0xab, 0x49, 0x7f, 0x06 } + +extern const struct ble_gap_adv_params ble_hs_test_util_adv_params; + +struct ble_hs_test_util_flat_attr { + uint16_t handle; + uint16_t offset; + uint8_t value[BLE_ATT_ATTR_MAX_LEN]; + uint16_t value_len; +}; + +struct ble_hs_test_util_mbuf_params { + unsigned prev_tx:1; + unsigned rx_queue:1; + unsigned prep_list:1; +}; + +struct ble_hs_test_util_att_info_entry { + uint16_t handle; /* 0 on last entry */ + const ble_uuid_t *uuid; +}; + +struct ble_hs_test_util_att_group_type_entry { + uint16_t start_handle; /* 0 on last entry */ + uint16_t end_handle; /* 0 on last entry */ + const ble_uuid_t *uuid; +}; + +#define BLE_HS_TEST_UTIL_L2CAP_HCI_HDR(handle, pb, len) \ + ((struct hci_data_hdr) { \ + .hdh_handle_pb_bc = ((handle) << 0) | \ + ((pb) << 12), \ + .hdh_len = (len) \ + }) + +#define BLE_HS_TEST_CONN_FEAT_ALL (0xFF) +#define BLE_HS_TEST_CONN_FEAT_NO_CONN_PARAM (0xFD) + +void ble_hs_test_util_prev_tx_enqueue(struct os_mbuf *om); +struct os_mbuf *ble_hs_test_util_prev_tx_dequeue(void); +struct os_mbuf *ble_hs_test_util_prev_tx_dequeue_pullup(void); +int ble_hs_test_util_prev_tx_queue_sz(void); +void ble_hs_test_util_prev_tx_queue_clear(void); + +void ble_hs_test_util_create_rpa_conn(uint16_t handle, uint8_t own_addr_type, + const uint8_t *our_rpa, + uint8_t peer_addr_type, + const uint8_t *peer_id_addr, + const uint8_t *peer_rpa, + uint8_t conn_features, + ble_gap_event_fn *cb, void *cb_arg); +void ble_hs_test_util_create_conn(uint16_t handle, const uint8_t *addr, + ble_gap_event_fn *cb, void *cb_arg); +void ble_hs_test_util_create_conn_feat(uint16_t handle, const uint8_t *addr, + uint8_t conn_features, + ble_gap_event_fn *cb, void *cb_arg); +int ble_hs_test_util_connect(uint8_t own_addr_type, + const ble_addr_t *peer_addr, + int32_t duration_ms, + const struct ble_gap_conn_params *params, + ble_gap_event_fn *cb, + void *cb_arg, + uint8_t ack_status); +int ble_hs_test_util_conn_cancel(uint8_t ack_status); +void ble_hs_test_util_rx_conn_cancel_evt(void); +void ble_hs_test_util_conn_cancel_full(void); +int ble_hs_test_util_conn_terminate(uint16_t conn_handle, uint8_t hci_status); +void ble_hs_test_util_rx_disconn_complete(uint16_t conn_handle, + uint8_t reason); +void ble_hs_test_util_conn_disconnect(uint16_t conn_handle); +int ble_hs_test_util_disc(uint8_t own_addr_type, int32_t duration_ms, + const struct ble_gap_disc_params *disc_params, + ble_gap_event_fn *cb, void *cb_arg, int fail_idx, + uint8_t fail_status); +int ble_hs_test_util_disc_cancel(uint8_t ack_status); +int ble_hs_test_util_adv_set_fields(const struct ble_hs_adv_fields *adv_fields, + int cmd_fail_idx, uint8_t hci_status); +int ble_hs_test_util_adv_rsp_set_fields( + const struct ble_hs_adv_fields *adv_fields, + int cmd_fail_idx, uint8_t hci_status); +int ble_hs_test_util_adv_start(uint8_t own_addr_type, + const ble_addr_t *peer_addr, + const struct ble_gap_adv_params *adv_params, + int32_t duration_ms, + ble_gap_event_fn *cb, void *cb_arg, + int fail_idx, uint8_t fail_status); +int ble_hs_test_util_adv_stop(uint8_t hci_status); +int ble_hs_test_util_wl_set(ble_addr_t *addrs, uint8_t addrs_count, + int fail_idx, uint8_t fail_status); +int ble_hs_test_util_conn_update(uint16_t conn_handle, + struct ble_gap_upd_params *params, + uint8_t hci_status); +int ble_hs_test_util_set_our_irk(const uint8_t *irk, int fail_idx, + uint8_t hci_status); +int ble_hs_test_util_security_initiate(uint16_t conn_handle, + uint8_t hci_status); +int ble_hs_test_util_l2cap_rx_first_frag(uint16_t conn_handle, uint16_t cid, + struct hci_data_hdr *hci_hdr, + struct os_mbuf *om); +int ble_hs_test_util_l2cap_rx(uint16_t conn_handle, + struct hci_data_hdr *hci_hdr, + struct os_mbuf *om); +int ble_hs_test_util_l2cap_rx_payload_flat(uint16_t conn_handle, uint16_t cid, + const void *data, int len); +uint8_t ble_hs_test_util_verify_tx_l2cap_sig(uint16_t opcode, void *cmd, + uint16_t cmd_size); +int ble_hs_test_util_inject_rx_l2cap_sig(uint16_t conn_handle, uint8_t opcode, + uint8_t id, void *cmd, uint16_t cmd_size); +void ble_hs_test_util_verify_tx_l2cap(struct os_mbuf *txom); +void ble_hs_test_util_inject_rx_l2cap(uint16_t conn_handle, uint16_t cid, + struct os_mbuf *rxom); +void ble_hs_test_util_set_att_mtu(uint16_t conn_handle, uint16_t mtu); +int ble_hs_test_util_rx_att_mtu_cmd(uint16_t conn_handle, int is_req, + uint16_t mtu); +int ble_hs_test_util_rx_att_find_info_req(uint16_t conn_handle, + uint16_t start_handle, + uint16_t end_handle); +int ble_hs_test_util_rx_att_find_type_value_req(uint16_t conn_handle, + uint16_t start_handle, + uint16_t end_handle, + uint16_t attr_type, + const void *attr_val, + uint16_t attr_len); +int ble_hs_test_util_rx_att_read_type_req(uint16_t conn_handle, + uint16_t start_handle, + uint16_t end_handle, + const ble_uuid_t *uuid); +int ble_hs_test_util_rx_att_read_type_req16(uint16_t conn_handle, + uint16_t start_handle, + uint16_t end_handle, + uint16_t uuid16); +int ble_hs_test_util_rx_att_read_req(uint16_t conn_handle, + uint16_t attr_handle); +int ble_hs_test_util_rx_att_read_blob_req(uint16_t conn_handle, + uint16_t attr_handle, + uint16_t offset); +int ble_hs_test_util_rx_att_read_mult_req(uint16_t conn_handle, + const uint16_t *handles, + int num_handles); +int ble_hs_test_util_rx_att_read_group_type_req(uint16_t conn_handle, + uint16_t start_handle, + uint16_t end_handle, + const ble_uuid_t *uuid); +int ble_hs_test_util_rx_att_read_group_type_req16(uint16_t conn_handle, + uint16_t start_handle, + uint16_t end_handle, + uint16_t uuid16); +int ble_hs_test_util_rx_att_write_req(uint16_t conn_handle, + uint16_t attr_handle, + const void *attr_val, + uint16_t attr_len); +int ble_hs_test_util_rx_att_write_cmd(uint16_t conn_handle, + uint16_t attr_handle, + const void *attr_val, + uint16_t attr_len); +int ble_hs_test_util_rx_att_prep_write_req(uint16_t conn_handle, + uint16_t attr_handle, + uint16_t offset, + const void *attr_val, + uint16_t attr_len); +int ble_hs_test_util_rx_att_exec_write_req(uint16_t conn_handle, + uint8_t flags); +int ble_hs_test_util_rx_att_notify_req(uint16_t conn_handle, + uint16_t attr_handle, + void *attr_val, + uint16_t attr_len); +int ble_hs_test_util_rx_att_indicate_req(uint16_t conn_handle, + uint16_t attr_handle, + void *attr_val, + uint16_t attr_len); +void ble_hs_test_util_rx_att_err_rsp(uint16_t conn_handle, uint8_t req_op, + uint8_t error_code, uint16_t err_handle); +void ble_hs_test_util_verify_tx_prep_write(uint16_t attr_handle, + uint16_t offset, + const void *data, int data_len); +void ble_hs_test_util_verify_tx_exec_write(uint8_t expected_flags); +void ble_hs_test_util_verify_tx_find_type_value(uint16_t start_handle, + uint16_t end_handle, + uint16_t attr_type, + const void *value, + uint16_t value_len); +void ble_hs_test_util_verify_tx_disc_svc_uuid(const ble_uuid_t *uuid); +void ble_hs_test_util_verify_tx_read_rsp(uint8_t *attr_data, int attr_len); +void ble_hs_test_util_verify_tx_read_blob_rsp(uint8_t *attr_data, + int attr_len); +void ble_hs_test_util_verify_tx_write_rsp(void); +void ble_hs_test_util_verify_tx_find_info_rsp( + struct ble_hs_test_util_att_info_entry *entries); +void ble_hs_test_util_verify_tx_mtu_cmd(int is_req, uint16_t mtu); +void ble_hs_test_util_verify_tx_read_group_type_rsp( + struct ble_hs_test_util_att_group_type_entry *entries); +void ble_hs_test_util_verify_tx_err_rsp(uint8_t req_op, uint16_t handle, + uint8_t error_code); +void ble_hs_test_util_verify_tx_write_cmd(uint16_t handle, const void *data, + uint16_t data_len); + +uint8_t ble_hs_test_util_verify_tx_l2cap_update_req( + struct ble_l2cap_sig_update_params *params); +int ble_hs_test_util_rx_l2cap_update_rsp(uint16_t conn_handle, + uint8_t id, uint16_t result); +void ble_hs_test_util_verify_tx_l2cap_update_rsp(uint8_t exp_id, + uint16_t exp_result); +void ble_hs_test_util_set_static_rnd_addr(const uint8_t *addr); +struct os_mbuf *ble_hs_test_util_om_from_flat(const void *buf, uint16_t len); +int ble_hs_test_util_flat_attr_cmp(const struct ble_hs_test_util_flat_attr *a, + const struct ble_hs_test_util_flat_attr *b); +void ble_hs_test_util_attr_to_flat(struct ble_hs_test_util_flat_attr *flat, + const struct ble_gatt_attr *attr); +void ble_hs_test_util_attr_from_flat( + struct ble_gatt_attr *attr, const struct ble_hs_test_util_flat_attr *flat); +int ble_hs_test_util_read_local_flat(uint16_t attr_handle, uint16_t max_len, + void *buf, uint16_t *out_len); +int ble_hs_test_util_write_local_flat(uint16_t attr_handle, + const void *buf, uint16_t buf_len); +int ble_hs_test_util_gatt_write_flat(uint16_t conn_handle, + uint16_t attr_handle, + const void *data, uint16_t data_len, + ble_gatt_attr_fn *cb, void *cb_arg); +int ble_hs_test_util_gatt_write_no_rsp_flat(uint16_t conn_handle, + uint16_t attr_handle, + const void *data, + uint16_t data_len); +int ble_hs_test_util_gatt_write_long_flat(uint16_t conn_handle, + uint16_t attr_handle, + const void *data, uint16_t data_len, + ble_gatt_attr_fn *cb, void *cb_arg); +struct os_mbuf *ble_hs_test_util_mbuf_alloc_all_but(int count); +int ble_hs_test_util_mbuf_count( + const struct ble_hs_test_util_mbuf_params *params); +void ble_hs_test_util_assert_mbufs_freed( + const struct ble_hs_test_util_mbuf_params *params); +void ble_hs_test_util_post_test(void *arg); +int ble_hs_test_util_num_cccds(void); +int ble_hs_test_util_num_our_secs(void); +int ble_hs_test_util_num_peer_secs(void); +void ble_hs_test_util_reg_svcs(const struct ble_gatt_svc_def *svcs, + ble_gatt_register_fn *reg_cb, + void *cb_arg); +void ble_hs_test_util_init_no_start(void); +void ble_hs_test_util_init_no_sysinit_no_start(void); +void ble_hs_test_util_init(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_test_util_hci.c b/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_test_util_hci.c new file mode 100644 index 00000000..a53c5d9f --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_test_util_hci.c @@ -0,0 +1,616 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "testutil/testutil.h" +#include "nimble/ble.h" +#include "nimble/hci_common.h" +#include "transport/ram/ble_hci_ram.h" +#include "ble_hs_test_util.h" + +#define BLE_HCI_EVENT_CMD_COMPLETE_HDR_LEN (5) +#define BLE_HCI_EVENT_CMD_STATUS_LEN (6) +#define BLE_HCI_ADD_TO_RESOLV_LIST_LEN (39) +#define BLE_HCI_LE_SET_PRIVACY_MODE_LEN (8) +#define BLE_HCI_DISCONNECT_CMD_LEN (3) +#define BLE_HCI_EVENT_HDR_LEN (2) +#define BLE_HCI_EVENT_DISCONN_COMPLETE_LEN (4) + +#define BLE_HS_TEST_UTIL_PREV_HCI_TX_CNT 64 + +static uint8_t +ble_hs_test_util_hci_out_queue[BLE_HS_TEST_UTIL_PREV_HCI_TX_CNT][260]; +static int ble_hs_test_util_hci_out_queue_sz; +static uint8_t ble_hs_test_util_hci_out_cur[260]; + +static struct ble_hs_test_util_hci_ack +ble_hs_test_util_hci_acks[BLE_HS_TEST_UTIL_PHONY_ACK_MAX]; +static int ble_hs_test_util_hci_num_acks; + +/***************************************************************************** + * $tx queue * + *****************************************************************************/ + +void +ble_hs_test_util_hci_out_adj(int count) +{ + if (count >= 0) { + TEST_ASSERT(ble_hs_test_util_hci_out_queue_sz >= count); + + ble_hs_test_util_hci_out_queue_sz -= count; + if (ble_hs_test_util_hci_out_queue_sz > 0) { + memmove( + ble_hs_test_util_hci_out_queue, + ble_hs_test_util_hci_out_queue + count, + sizeof ble_hs_test_util_hci_out_queue[0] * + ble_hs_test_util_hci_out_queue_sz); + } + } else { + TEST_ASSERT(ble_hs_test_util_hci_out_queue_sz >= -count); + + ble_hs_test_util_hci_out_adj( + ble_hs_test_util_hci_out_queue_sz + count); + } +} + +void * +ble_hs_test_util_hci_out_first(void) +{ + if (ble_hs_test_util_hci_out_queue_sz == 0) { + return NULL; + } + + memcpy(ble_hs_test_util_hci_out_cur, ble_hs_test_util_hci_out_queue[0], + sizeof ble_hs_test_util_hci_out_cur); + + ble_hs_test_util_hci_out_adj(1); + + return ble_hs_test_util_hci_out_cur; +} + +void * +ble_hs_test_util_hci_out_last(void) +{ + if (ble_hs_test_util_hci_out_queue_sz == 0) { + return NULL; + } + + ble_hs_test_util_hci_out_queue_sz--; + memcpy(ble_hs_test_util_hci_out_cur, + ble_hs_test_util_hci_out_queue + ble_hs_test_util_hci_out_queue_sz, + sizeof ble_hs_test_util_hci_out_cur); + + return ble_hs_test_util_hci_out_cur; +} + +void +ble_hs_test_util_hci_out_enqueue(void *cmd) +{ + TEST_ASSERT_FATAL(ble_hs_test_util_hci_out_queue_sz < + BLE_HS_TEST_UTIL_PREV_HCI_TX_CNT); + memcpy(ble_hs_test_util_hci_out_queue + ble_hs_test_util_hci_out_queue_sz, + cmd, 260); + + ble_hs_test_util_hci_out_queue_sz++; +} + +void +ble_hs_test_util_hci_out_clear(void) +{ + ble_hs_test_util_hci_out_queue_sz = 0; +} + +void +ble_hs_test_util_hci_acks_clear(void) +{ + ble_hs_test_util_hci_num_acks = 0; +} + +/***************************************************************************** + * $build * + *****************************************************************************/ + +void +ble_hs_test_util_hci_build_cmd_complete(uint8_t *dst, int len, + uint8_t param_len, uint8_t num_pkts, + uint16_t opcode) +{ + TEST_ASSERT(len >= BLE_HCI_EVENT_CMD_COMPLETE_HDR_LEN); + + dst[0] = BLE_HCI_EVCODE_COMMAND_COMPLETE; + dst[1] = 3 + param_len; + dst[2] = num_pkts; + put_le16(dst + 3, opcode); +} + +void +ble_hs_test_util_hci_build_cmd_status(uint8_t *dst, int len, + uint8_t status, uint8_t num_pkts, + uint16_t opcode) +{ + TEST_ASSERT(len >= BLE_HCI_EVENT_CMD_STATUS_LEN); + + dst[0] = BLE_HCI_EVCODE_COMMAND_STATUS; + dst[1] = BLE_HCI_EVENT_CMD_STATUS_LEN; + dst[2] = status; + dst[3] = num_pkts; + put_le16(dst + 4, opcode); +} + +static void +ble_hs_test_util_hci_build_ack_params( + struct ble_hs_test_util_hci_ack *ack, + uint16_t opcode, uint8_t status, void *params, uint8_t params_len) +{ + ack->opcode = opcode; + ack->status = status; + + if (params == NULL || params_len == 0) { + ack->evt_params_len = 0; + } else { + memcpy(ack->evt_params, params, params_len); + ack->evt_params_len = params_len; + } +} + +/***************************************************************************** + * $ack * + *****************************************************************************/ + +static int +ble_hs_test_util_hci_ack_cb(uint8_t *ack, int ack_buf_len) +{ + struct ble_hs_test_util_hci_ack *entry; + + if (ble_hs_test_util_hci_num_acks == 0) { + return BLE_HS_ETIMEOUT_HCI; + } + + entry = ble_hs_test_util_hci_acks; + + ble_hs_test_util_hci_build_cmd_complete(ack, 256, + entry->evt_params_len + 1, 1, + entry->opcode); + ack[BLE_HCI_EVENT_CMD_COMPLETE_HDR_LEN] = entry->status; + memcpy(ack + BLE_HCI_EVENT_CMD_COMPLETE_HDR_LEN + 1, entry->evt_params, + entry->evt_params_len); + + ble_hs_test_util_hci_num_acks--; + if (ble_hs_test_util_hci_num_acks > 0) { + memmove(ble_hs_test_util_hci_acks, + ble_hs_test_util_hci_acks + 1, + sizeof *entry * ble_hs_test_util_hci_num_acks); + } + + return 0; +} + +void +ble_hs_test_util_hci_ack_set_params(uint16_t opcode, uint8_t status, + void *params, uint8_t params_len) +{ + struct ble_hs_test_util_hci_ack *ack; + + ack = ble_hs_test_util_hci_acks + 0; + ble_hs_test_util_hci_build_ack_params(ack, opcode, status, params, + params_len); + ble_hs_test_util_hci_num_acks = 1; + + ble_hs_hci_set_phony_ack_cb(ble_hs_test_util_hci_ack_cb); +} + +void +ble_hs_test_util_hci_ack_set(uint16_t opcode, uint8_t status) +{ + ble_hs_test_util_hci_ack_set_params(opcode, status, NULL, 0); +} + +void +ble_hs_test_util_hci_ack_append_params(uint16_t opcode, uint8_t status, + void *params, uint8_t params_len) +{ + struct ble_hs_test_util_hci_ack *ack; + + ack = ble_hs_test_util_hci_acks + ble_hs_test_util_hci_num_acks; + ble_hs_test_util_hci_build_ack_params(ack, opcode, status, params, + params_len); + ble_hs_test_util_hci_num_acks++; + + ble_hs_hci_set_phony_ack_cb(ble_hs_test_util_hci_ack_cb); +} + +void +ble_hs_test_util_hci_ack_append(uint16_t opcode, uint8_t status) +{ + ble_hs_test_util_hci_ack_append_params(opcode, status, NULL, 0); +} + +static const struct ble_hs_test_util_hci_ack hci_startup_seq[] = { + { + .opcode = ble_hs_hci_util_opcode_join(BLE_HCI_OGF_CTLR_BASEBAND, + BLE_HCI_OCF_CB_RESET), + }, + { + .opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_INFO_PARAMS, BLE_HCI_OCF_IP_RD_LOCAL_VER), + .evt_params = { 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + .evt_params_len = 8, + }, + { + .opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_INFO_PARAMS, BLE_HCI_OCF_IP_RD_LOC_SUPP_FEAT), + .evt_params = { 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00}, + .evt_params_len = 8, + }, + { + .opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_CTLR_BASEBAND, BLE_HCI_OCF_CB_SET_EVENT_MASK), + }, + { + .opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_CTLR_BASEBAND, BLE_HCI_OCF_CB_SET_EVENT_MASK2), + }, + { + .opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_EVENT_MASK), + }, + { + .opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RD_BUF_SIZE), + /* Use a very low buffer size (20) to test fragmentation. + * Use a large num-pkts (200) to prevent controller buf exhaustion. + */ + .evt_params = { 0x14, 0x00, 200 }, + .evt_params_len = 3, + }, + { + .opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RD_LOC_SUPP_FEAT), + .evt_params = { 0 }, + .evt_params_len = 8, + }, + { + .opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_INFO_PARAMS, BLE_HCI_OCF_IP_RD_BD_ADDR), + .evt_params = BLE_HS_TEST_UTIL_PUB_ADDR_VAL, + .evt_params_len = 6, + }, + { + .opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_ADDR_RES_EN), + }, + { + .opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_CLR_RESOLV_LIST), + }, + { + .opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_ADDR_RES_EN), + }, + { + .opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_ADV_ENABLE), + }, + { + .opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_ADD_RESOLV_LIST), + }, + { + .opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_PRIVACY_MODE), + }, + { 0 } +}; + +void +ble_hs_test_util_hci_ack_set_seq(const struct ble_hs_test_util_hci_ack *acks) +{ + int i; + + for (i = 0; acks[i].opcode != 0; i++) { + ble_hs_test_util_hci_acks[i] = acks[i]; + } + ble_hs_test_util_hci_num_acks = i; + + ble_hs_hci_set_phony_ack_cb(ble_hs_test_util_hci_ack_cb); +} + +int +ble_hs_test_util_hci_startup_seq_cnt(void) +{ + /* last element is terminator, don't count it*/ + return sizeof(hci_startup_seq)/sizeof(hci_startup_seq[0]) - 1; +} + +void +ble_hs_test_util_hci_ack_set_startup(void) +{ + /* Receive acknowledgements for the startup sequence. We sent the + * corresponding requests when the host task was started. + */ + ble_hs_test_util_hci_ack_set_seq(hci_startup_seq); +} + +void +ble_hs_test_util_hci_ack_set_disc(uint8_t own_addr_type, + int fail_idx, uint8_t fail_status) +{ + static bool privacy_enabled; + + /* + * SET_RPA_TMO should be expected only when test uses RPA and privacy has + * not yet been enabled. The Bluetooth stack remembers that privacy is + * enabled and does not send SET_RPA_TMO every time. For test purpose + * let's track privacy state in here. + */ + if ((own_addr_type == BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT || + own_addr_type == BLE_OWN_ADDR_RPA_RANDOM_DEFAULT) && + !privacy_enabled) { + + privacy_enabled = true; + ble_hs_test_util_hci_ack_set_seq(((struct ble_hs_test_util_hci_ack[]) { + { + BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_SET_RPA_TMO), + ble_hs_test_util_hci_misc_exp_status(0, fail_idx, fail_status), + }, + { + BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_SET_SCAN_PARAMS), + ble_hs_test_util_hci_misc_exp_status(1, fail_idx, fail_status), + }, + { + BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_SET_SCAN_ENABLE), + ble_hs_test_util_hci_misc_exp_status(2, fail_idx, fail_status), + }, + + { 0 } + })); + } else { + ble_hs_test_util_hci_ack_set_seq(((struct ble_hs_test_util_hci_ack[]) { + { + BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_SET_SCAN_PARAMS), + ble_hs_test_util_hci_misc_exp_status(0, fail_idx, fail_status), + }, + { + BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_SET_SCAN_ENABLE), + ble_hs_test_util_hci_misc_exp_status(1, fail_idx, fail_status), + }, + + { 0 } + })); + } +} + +void +ble_hs_test_util_hci_ack_set_disconnect(uint8_t hci_status) +{ + ble_hs_test_util_hci_ack_set( + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LINK_CTRL, + BLE_HCI_OCF_DISCONNECT_CMD), + hci_status); +} + +/***************************************************************************** + * $verify tx * + *****************************************************************************/ + +void +ble_hs_test_util_hci_verify_tx_add_irk(uint8_t addr_type, + const uint8_t *addr, + const uint8_t *peer_irk, + const uint8_t *local_irk) +{ + uint8_t param_len; + uint8_t *param; + + + param = ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_ADD_RESOLV_LIST, + ¶m_len); + TEST_ASSERT(param_len == BLE_HCI_ADD_TO_RESOLV_LIST_LEN); + + TEST_ASSERT(param[0] == addr_type); + TEST_ASSERT(memcmp(param + 1, addr, 6) == 0); + TEST_ASSERT(memcmp(param + 7, peer_irk, 16) == 0); + TEST_ASSERT(memcmp(param + 23, local_irk, 16) == 0); +} + +void +ble_hs_test_util_hci_verify_tx_set_priv_mode(uint8_t addr_type, + const uint8_t *addr, + uint8_t priv_mode) +{ + uint8_t param_len; + uint8_t *param; + + param = ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_SET_PRIVACY_MODE, + ¶m_len); + TEST_ASSERT(param_len == BLE_HCI_LE_SET_PRIVACY_MODE_LEN); + + TEST_ASSERT(param[0] == addr_type); + TEST_ASSERT(memcmp(param + 1, addr, 6) == 0); + TEST_ASSERT(param[7] == priv_mode); +} + +void +ble_hs_test_util_hci_verify_tx_disconnect(uint16_t handle, uint8_t reason) +{ + uint8_t param_len; + uint8_t *param; + + param = ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LINK_CTRL, + BLE_HCI_OCF_DISCONNECT_CMD, + ¶m_len); + TEST_ASSERT(param_len == BLE_HCI_DISCONNECT_CMD_LEN); + + TEST_ASSERT(get_le16(param + 0) == handle); + TEST_ASSERT(param[2] == reason); +} + +void +ble_hs_test_util_hci_verify_tx_create_conn(const struct hci_create_conn *exp) +{ + uint8_t param_len; + uint8_t *param; + + param = ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_CREATE_CONN, + ¶m_len); + TEST_ASSERT(param_len == BLE_HCI_CREATE_CONN_LEN); + + TEST_ASSERT(get_le16(param + 0) == exp->scan_itvl); + TEST_ASSERT(get_le16(param + 2) == exp->scan_window); + TEST_ASSERT(param[4] == exp->filter_policy); + TEST_ASSERT(param[5] == exp->peer_addr_type); + TEST_ASSERT(memcmp(param + 6, exp->peer_addr, 6) == 0); + TEST_ASSERT(param[12] == exp->own_addr_type); + TEST_ASSERT(get_le16(param + 13) == exp->conn_itvl_min); + TEST_ASSERT(get_le16(param + 15) == exp->conn_itvl_max); + TEST_ASSERT(get_le16(param + 17) == exp->conn_latency); + TEST_ASSERT(get_le16(param + 19) == exp->supervision_timeout); + TEST_ASSERT(get_le16(param + 21) == exp->min_ce_len); + TEST_ASSERT(get_le16(param + 23) == exp->max_ce_len); +} + +uint8_t * +ble_hs_test_util_hci_verify_tx(uint8_t ogf, uint16_t ocf, + uint8_t *out_param_len) +{ + uint16_t opcode; + uint8_t *cmd; + + cmd = ble_hs_test_util_hci_out_first(); + TEST_ASSERT_FATAL(cmd != NULL); + + opcode = get_le16(cmd); + TEST_ASSERT(BLE_HCI_OGF(opcode) == ogf); + TEST_ASSERT(BLE_HCI_OCF(opcode) == ocf); + + if (out_param_len != NULL) { + *out_param_len = cmd[2]; + } + + return cmd + 3; +} + +/***************************************************************************** + * $rx * + *****************************************************************************/ + +static void +ble_hs_test_util_hci_rx_evt(uint8_t *evt) +{ + uint8_t *evbuf; + int totlen; + int rc; + + totlen = BLE_HCI_EVENT_HDR_LEN + evt[1]; + TEST_ASSERT_FATAL(totlen <= UINT8_MAX + BLE_HCI_EVENT_HDR_LEN); + + evbuf = ble_hci_trans_buf_alloc( + BLE_HCI_TRANS_BUF_EVT_LO); + TEST_ASSERT_FATAL(evbuf != NULL); + + memcpy(evbuf, evt, totlen); + + if (os_started()) { + rc = ble_hci_trans_ll_evt_tx(evbuf); + } else { + rc = ble_hs_hci_evt_process((void *)evbuf); + } + + TEST_ASSERT_FATAL(rc == 0); +} + +void +ble_hs_test_util_hci_rx_num_completed_pkts_event( + struct ble_hs_test_util_hci_num_completed_pkts_entry *entries) +{ + struct ble_hs_test_util_hci_num_completed_pkts_entry *entry; + uint8_t buf[1024]; + int num_entries; + int off; + int i; + + /* Count number of entries. */ + num_entries = 0; + for (entry = entries; entry->handle_id != 0; entry++) { + num_entries++; + } + TEST_ASSERT_FATAL(num_entries <= UINT8_MAX); + + buf[0] = BLE_HCI_EVCODE_NUM_COMP_PKTS; + buf[2] = num_entries; + + off = 3; + for (i = 0; i < num_entries; i++) { + put_le16(buf + off, entries[i].handle_id); + off += 2; + put_le16(buf + off, entries[i].num_pkts); + off += 2; + } + + buf[1] = off - 2; + + ble_hs_test_util_hci_rx_evt(buf); +} + +void +ble_hs_test_util_hci_rx_disconn_complete_event(uint16_t conn_handle, + uint8_t status, uint8_t reason) +{ + uint8_t buf[BLE_HCI_EVENT_HDR_LEN + BLE_HCI_EVENT_DISCONN_COMPLETE_LEN]; + + buf[0] = BLE_HCI_EVCODE_DISCONN_CMP; + buf[1] = BLE_HCI_EVENT_DISCONN_COMPLETE_LEN; + buf[2] = status; + put_le16(buf + 3, conn_handle); + buf[5] = reason; + + ble_hs_test_util_hci_rx_evt(buf); +} + +void +ble_hs_test_util_hci_rx_conn_cancel_evt(void) +{ + struct ble_gap_conn_complete evt; + int rc; + + memset(&evt, 0, sizeof evt); + evt.status = BLE_ERR_UNK_CONN_ID; + /* test if host correctly ignores other fields if status is error */ + evt.connection_handle = 0x0fff; + + rc = ble_gap_rx_conn_complete(&evt, 0); + TEST_ASSERT_FATAL(rc == 0); +} + +/***************************************************************************** + * $misc * + *****************************************************************************/ + +int +ble_hs_test_util_hci_misc_exp_status(int cmd_idx, int fail_idx, + uint8_t fail_status) +{ + if (cmd_idx == fail_idx) { + return BLE_HS_HCI_ERR(fail_status); + } else { + return 0; + } +} diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_test_util_hci.h b/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_test_util_hci.h new file mode 100644 index 00000000..dde04557 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_hs_test_util_hci.h @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_HS_TEST_UTIL_HCI_ +#define H_BLE_HS_TEST_UTIL_HCI_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* leave this as macro so it may be used for static const initialization */ +#define ble_hs_hci_util_opcode_join(ogf, ocf) (((ogf) << 10) | (ocf)) + +#define BLE_HS_TEST_UTIL_PHONY_ACK_MAX 64 +struct ble_hs_test_util_hci_ack { + uint16_t opcode; + uint8_t status; + uint8_t evt_params[256]; + uint8_t evt_params_len; +}; + +struct ble_hs_test_util_hci_num_completed_pkts_entry { + uint16_t handle_id; /* 0 for terminating entry in array. */ + uint16_t num_pkts; +}; + +/* $out queue */ +void ble_hs_test_util_hci_out_adj(int count); +void *ble_hs_test_util_hci_out_first(void); +void *ble_hs_test_util_hci_out_last(void); +void ble_hs_test_util_hci_out_enqueue(void *cmd); +void ble_hs_test_util_hci_out_clear(void); +void ble_hs_test_util_hci_acks_clear(void); + +/* $build */ +void ble_hs_test_util_hci_build_cmd_complete(uint8_t *dst, int len, + uint8_t param_len, + uint8_t num_pkts, + uint16_t opcode); +void ble_hs_test_util_hci_build_cmd_status(uint8_t *dst, int len, + uint8_t status, uint8_t num_pkts, + uint16_t opcode); + +/* $ack */ +void ble_hs_test_util_hci_ack_set_params(uint16_t opcode, uint8_t status, + void *params, uint8_t params_len); +void ble_hs_test_util_hci_ack_set(uint16_t opcode, uint8_t status); +void ble_hs_test_util_hci_ack_append_params(uint16_t opcode, uint8_t status, + void *params, uint8_t params_len); +void ble_hs_test_util_hci_ack_append(uint16_t opcode, uint8_t status); +void ble_hs_test_util_hci_ack_set_seq(const struct ble_hs_test_util_hci_ack *acks); +void ble_hs_test_util_hci_ack_set_startup(void); +void ble_hs_test_util_hci_ack_set_disc(uint8_t own_addr_type, + int fail_idx, uint8_t fail_status); +void ble_hs_test_util_hci_ack_set_disconnect(uint8_t hci_status); + +int ble_hs_test_util_hci_startup_seq_cnt(void); + +/* $verify tx */ +void ble_hs_test_util_hci_verify_tx_add_irk(uint8_t addr_type, + const uint8_t *addr, + const uint8_t *peer_irk, + const uint8_t *local_irk); +void ble_hs_test_util_hci_verify_tx_set_priv_mode(uint8_t addr_type, + const uint8_t *addr, + uint8_t priv_mode); +void ble_hs_test_util_hci_verify_tx_disconnect(uint16_t handle, + uint8_t reason); +void ble_hs_test_util_hci_verify_tx_create_conn( + const struct hci_create_conn *exp); +uint8_t *ble_hs_test_util_hci_verify_tx(uint8_t ogf, uint16_t ocf, + uint8_t *out_param_len); + +/* $rx */ +void ble_hs_test_util_hci_rx_num_completed_pkts_event( + struct ble_hs_test_util_hci_num_completed_pkts_entry *entries); +void ble_hs_test_util_hci_rx_disconn_complete_event(uint16_t conn_handle, + uint8_t status, uint8_t reason); +void ble_hs_test_util_hci_rx_conn_cancel_evt(void); + +/* $misc */ +int ble_hs_test_util_hci_misc_exp_status(int cmd_idx, int fail_idx, + uint8_t fail_status); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_l2cap_test.c b/src/libs/mynewt-nimble/nimble/host/test/src/ble_l2cap_test.c new file mode 100644 index 00000000..2b17da06 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_l2cap_test.c @@ -0,0 +1,1500 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include "testutil/testutil.h" +#include "nimble/hci_common.h" +#include "ble_hs_test.h" +#include "ble_hs_test_util.h" + +#define BLE_HCI_CONN_UPDATE_LEN (14) + +#define BLE_L2CAP_TEST_PSM (90) +#define BLE_L2CAP_TEST_CID (99) +#define BLE_L2CAP_TEST_COC_MTU (256) +/* We use same pool for incoming and outgoing sdu */ +#define BLE_L2CAP_TEST_COC_BUF_COUNT (6 * MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)) + +static uint16_t ble_l2cap_test_update_conn_handle; +static int ble_l2cap_test_update_status; +static void *ble_l2cap_test_update_arg; + +static void *test_sdu_coc_mem; +struct os_mbuf_pool sdu_os_mbuf_pool; +static struct os_mempool sdu_coc_mbuf_mempool; +static uint16_t current_cid = 0x0040; +/***************************************************************************** + * $util * + *****************************************************************************/ + +static void +ble_l2cap_test_util_init(void) +{ + ble_hs_test_util_init(); + ble_l2cap_test_update_conn_handle = BLE_HS_CONN_HANDLE_NONE; + ble_l2cap_test_update_status = -1; + ble_l2cap_test_update_arg = (void *)(uintptr_t)-1; + int rc; + + if (test_sdu_coc_mem) { + free(test_sdu_coc_mem); + } + + /* For testing we want to support all the available channels */ + test_sdu_coc_mem = malloc( + OS_MEMPOOL_BYTES(BLE_L2CAP_TEST_COC_BUF_COUNT,BLE_L2CAP_TEST_COC_MTU)); + assert(test_sdu_coc_mem != NULL); + + rc = os_mempool_init(&sdu_coc_mbuf_mempool, BLE_L2CAP_TEST_COC_BUF_COUNT, + BLE_L2CAP_TEST_COC_MTU, test_sdu_coc_mem, + "test_coc_sdu_pool"); + assert(rc == 0); + + rc = os_mbuf_pool_init(&sdu_os_mbuf_pool, &sdu_coc_mbuf_mempool, + BLE_L2CAP_TEST_COC_MTU, BLE_L2CAP_TEST_COC_BUF_COUNT); + assert(rc == 0); + +} + +static void +ble_l2cap_test_util_rx_update_req(uint16_t conn_handle, uint8_t id, + struct ble_l2cap_sig_update_params *params) +{ + struct ble_l2cap_sig_update_req *req; + struct hci_data_hdr hci_hdr; + struct os_mbuf *om; + int rc; + + hci_hdr = BLE_HS_TEST_UTIL_L2CAP_HCI_HDR( + 2, BLE_HCI_PB_FIRST_FLUSH, + BLE_L2CAP_HDR_SZ + BLE_L2CAP_SIG_HDR_SZ + BLE_L2CAP_SIG_UPDATE_REQ_SZ); + + req = ble_l2cap_sig_cmd_get(BLE_L2CAP_SIG_OP_UPDATE_REQ, id, + BLE_L2CAP_SIG_UPDATE_REQ_SZ, &om); + TEST_ASSERT_FATAL(req != NULL); + + req->itvl_min = htole16(params->itvl_min); + req->itvl_max = htole16(params->itvl_max); + req->slave_latency = htole16(params->slave_latency); + req->timeout_multiplier = htole16(params->timeout_multiplier); + + ble_hs_test_util_hci_ack_set( + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_CONN_UPDATE), 0); + rc = ble_hs_test_util_l2cap_rx_first_frag(conn_handle, BLE_L2CAP_CID_SIG, + &hci_hdr, om); + TEST_ASSERT_FATAL(rc == 0); +} + +static void +ble_l2cap_test_util_verify_tx_update_conn( + struct ble_gap_upd_params *params) +{ + uint8_t param_len; + uint8_t *param; + + param = ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_CONN_UPDATE, + ¶m_len); + TEST_ASSERT(param_len == BLE_HCI_CONN_UPDATE_LEN); + TEST_ASSERT(get_le16(param + 0) == 2); + TEST_ASSERT(get_le16(param + 2) == params->itvl_min); + TEST_ASSERT(get_le16(param + 4) == params->itvl_max); + TEST_ASSERT(get_le16(param + 6) == params->latency); + TEST_ASSERT(get_le16(param + 8) == params->supervision_timeout); + TEST_ASSERT(get_le16(param + 10) == params->min_ce_len); + TEST_ASSERT(get_le16(param + 12) == params->max_ce_len); +} + +static int +ble_l2cap_test_util_dummy_rx(struct ble_l2cap_chan *chan) +{ + return 0; +} + +static void +ble_l2cap_test_util_create_conn(uint16_t conn_handle, uint8_t *addr, + ble_gap_event_fn *cb, void *cb_arg) +{ + struct ble_l2cap_chan *chan; + struct ble_hs_conn *conn; + + ble_hs_test_util_create_conn(conn_handle, addr, cb, cb_arg); + + ble_hs_lock(); + + conn = ble_hs_conn_find(conn_handle); + TEST_ASSERT_FATAL(conn != NULL); + + chan = ble_l2cap_chan_alloc(conn_handle); + TEST_ASSERT_FATAL(chan != NULL); + + chan->scid = BLE_L2CAP_TEST_CID; + chan->my_mtu = 240; + chan->rx_fn = ble_l2cap_test_util_dummy_rx; + + ble_hs_conn_chan_insert(conn, chan); + + ble_hs_test_util_hci_out_clear(); + + ble_hs_unlock(); +} + +static int +ble_l2cap_test_util_rx_first_frag(uint16_t conn_handle, + uint16_t l2cap_frag_len, + uint16_t cid, uint16_t l2cap_len) +{ + struct hci_data_hdr hci_hdr; + struct os_mbuf *om; + uint16_t hci_len; + void *v; + int rc; + + om = ble_hs_mbuf_l2cap_pkt(); + TEST_ASSERT_FATAL(om != NULL); + + v = os_mbuf_extend(om, l2cap_frag_len); + TEST_ASSERT_FATAL(v != NULL); + + om = ble_l2cap_prepend_hdr(om, cid, l2cap_len); + TEST_ASSERT_FATAL(om != NULL); + + hci_len = sizeof hci_hdr + l2cap_frag_len; + hci_hdr = BLE_HS_TEST_UTIL_L2CAP_HCI_HDR(conn_handle, + BLE_HCI_PB_FIRST_FLUSH, hci_len); + rc = ble_hs_test_util_l2cap_rx(conn_handle, &hci_hdr, om); + return rc; +} + +static int +ble_l2cap_test_util_rx_next_frag(uint16_t conn_handle, uint16_t hci_len) +{ + struct hci_data_hdr hci_hdr; + struct os_mbuf *om; + void *v; + int rc; + + om = ble_hs_mbuf_l2cap_pkt(); + TEST_ASSERT_FATAL(om != NULL); + + v = os_mbuf_extend(om, hci_len); + TEST_ASSERT_FATAL(v != NULL); + + hci_hdr = BLE_HS_TEST_UTIL_L2CAP_HCI_HDR(conn_handle, + BLE_HCI_PB_MIDDLE, hci_len); + rc = ble_hs_test_util_l2cap_rx(conn_handle, &hci_hdr, om); + return rc; +} + +static void +ble_l2cap_test_util_verify_first_frag(uint16_t conn_handle, + uint16_t l2cap_frag_len, + uint16_t l2cap_len) +{ + struct ble_hs_conn *conn; + int rc; + + rc = ble_l2cap_test_util_rx_first_frag(conn_handle, l2cap_frag_len, + BLE_L2CAP_TEST_CID, l2cap_len); + TEST_ASSERT(rc == 0); + + ble_hs_lock(); + + conn = ble_hs_conn_find(conn_handle); + TEST_ASSERT_FATAL(conn != NULL); + TEST_ASSERT(conn->bhc_rx_chan != NULL && + conn->bhc_rx_chan->scid == BLE_L2CAP_TEST_CID); + + ble_hs_unlock(); +} + +static void +ble_l2cap_test_util_verify_middle_frag(uint16_t conn_handle, + uint16_t hci_len) +{ + struct ble_hs_conn *conn; + int rc; + + rc = ble_l2cap_test_util_rx_next_frag(conn_handle, hci_len); + TEST_ASSERT(rc == 0); + + ble_hs_lock(); + + conn = ble_hs_conn_find(conn_handle); + TEST_ASSERT_FATAL(conn != NULL); + TEST_ASSERT(conn->bhc_rx_chan != NULL && + conn->bhc_rx_chan->scid == BLE_L2CAP_TEST_CID); + + ble_hs_unlock(); +} + +static void +ble_l2cap_test_util_verify_last_frag(uint16_t conn_handle, + uint16_t hci_len) +{ + struct ble_hs_conn *conn; + int rc; + + rc = ble_l2cap_test_util_rx_next_frag(conn_handle, hci_len); + TEST_ASSERT(rc == 0); + + ble_hs_lock(); + + conn = ble_hs_conn_find(conn_handle); + TEST_ASSERT_FATAL(conn != NULL); + TEST_ASSERT(conn->bhc_rx_chan == NULL); + + ble_hs_unlock(); +} + +/***************************************************************************** + * $rx * + *****************************************************************************/ + +TEST_CASE_SELF(ble_l2cap_test_case_bad_header) +{ + int rc; + + ble_l2cap_test_util_init(); + + ble_l2cap_test_util_create_conn(2, ((uint8_t[]){1,2,3,4,5,6}), + NULL, NULL); + + rc = ble_l2cap_test_util_rx_first_frag(2, 14, 1234, 10); + TEST_ASSERT(rc == BLE_HS_ENOENT); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_l2cap_test_case_bad_handle) +{ + int rc; + + ble_l2cap_test_util_init(); + + ble_l2cap_test_util_create_conn(2, ((uint8_t[]){1,2,3,4,5,6}), + NULL, NULL); + + rc = ble_l2cap_test_util_rx_first_frag(1234, 14, 1234, 10); + TEST_ASSERT(rc == BLE_HS_ENOTCONN); + + /* Ensure we did not send anything in return. */ + TEST_ASSERT_FATAL(ble_hs_test_util_prev_tx_dequeue() == NULL); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +/***************************************************************************** + * $fragmentation * + *****************************************************************************/ + +TEST_CASE_SELF(ble_l2cap_test_case_frag_single) +{ + struct hci_data_hdr hci_hdr; + struct os_mbuf *om; + int rc; + + ble_l2cap_test_util_init(); + + ble_l2cap_test_util_create_conn(2, ((uint8_t[]){1,2,3,4,5,6}), + NULL, NULL); + + /*** HCI header specifies middle fragment without start. */ + hci_hdr = BLE_HS_TEST_UTIL_L2CAP_HCI_HDR(2, BLE_HCI_PB_MIDDLE, 10); + + om = ble_hs_mbuf_l2cap_pkt(); + TEST_ASSERT_FATAL(om != NULL); + + om = ble_l2cap_prepend_hdr(om, 0, 5); + TEST_ASSERT_FATAL(om != NULL); + + rc = ble_hs_test_util_l2cap_rx(2, &hci_hdr, om); + TEST_ASSERT(rc == BLE_HS_EBADDATA); + + /*** Packet consisting of three fragments. */ + ble_l2cap_test_util_verify_first_frag(2, 10, 30); + ble_l2cap_test_util_verify_middle_frag(2, 10); + ble_l2cap_test_util_verify_last_frag(2, 10); + + /*** Packet consisting of five fragments. */ + ble_l2cap_test_util_verify_first_frag(2, 8, 49); + ble_l2cap_test_util_verify_middle_frag(2, 13); + ble_l2cap_test_util_verify_middle_frag(2, 2); + ble_l2cap_test_util_verify_middle_frag(2, 21); + ble_l2cap_test_util_verify_last_frag(2, 5); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_l2cap_test_case_frag_multiple) +{ + ble_l2cap_test_util_init(); + + ble_l2cap_test_util_create_conn(2, ((uint8_t[]){1,2,3,4,5,6}), + NULL, NULL); + ble_l2cap_test_util_create_conn(3, ((uint8_t[]){2,3,4,5,6,7}), + NULL, NULL); + ble_l2cap_test_util_create_conn(4, ((uint8_t[]){3,4,5,6,7,8}), + NULL, NULL); + + ble_l2cap_test_util_verify_first_frag(2, 3, 10); + ble_l2cap_test_util_verify_first_frag(3, 2, 5); + ble_l2cap_test_util_verify_middle_frag(2, 6); + ble_l2cap_test_util_verify_first_frag(4, 1, 4); + ble_l2cap_test_util_verify_middle_frag(3, 2); + ble_l2cap_test_util_verify_last_frag(3, 1); + ble_l2cap_test_util_verify_middle_frag(4, 2); + ble_l2cap_test_util_verify_last_frag(4, 1); + ble_l2cap_test_util_verify_last_frag(2, 1); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_l2cap_test_case_frag_channels) +{ + struct ble_hs_conn *conn; + int rc; + uint16_t data_len = 30; + + ble_l2cap_test_util_init(); + + ble_l2cap_test_util_create_conn(2, ((uint8_t[]){1,2,3,4,5,6}), + NULL, NULL); + + /* Receive a starting fragment on the first channel. */ + rc = ble_l2cap_test_util_rx_first_frag(2, 14, BLE_L2CAP_TEST_CID, data_len); + TEST_ASSERT(rc == 0); + + ble_hs_lock(); + conn = ble_hs_conn_find(2); + TEST_ASSERT_FATAL(conn != NULL); + TEST_ASSERT(conn->bhc_rx_chan != NULL && + conn->bhc_rx_chan->scid == BLE_L2CAP_TEST_CID); + ble_hs_unlock(); + + /* Receive a starting fragment on a different channel. The first fragment + * should get discarded. + */ + ble_hs_test_util_set_att_mtu(conn->bhc_handle, data_len); + rc = ble_l2cap_test_util_rx_first_frag(2, 14, BLE_L2CAP_CID_ATT, data_len); + TEST_ASSERT(rc == 0); + + ble_hs_lock(); + conn = ble_hs_conn_find(2); + TEST_ASSERT_FATAL(conn != NULL); + TEST_ASSERT(conn->bhc_rx_chan != NULL && + conn->bhc_rx_chan->scid == BLE_L2CAP_CID_ATT); + ble_hs_unlock(); + + /* Terminate the connection. The received fragments should get freed. + * Mbuf leaks are tested in the post-test-case callback. + */ + ble_hs_test_util_conn_disconnect(2); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_l2cap_test_case_frag_timeout) +{ + int32_t ticks_from_now; + int rc; + + ble_l2cap_test_util_init(); + + ble_l2cap_test_util_create_conn(2, ((uint8_t[]){1,2,3,4,5,6}), + NULL, NULL); + + /* Ensure timer is not set. */ + ticks_from_now = ble_hs_conn_timer(); + TEST_ASSERT_FATAL(ticks_from_now == BLE_HS_FOREVER); + + /* Receive the first fragment of a multipart ACL data packet. */ + rc = ble_l2cap_test_util_rx_first_frag(2, 14, BLE_L2CAP_TEST_CID, 30); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure timer will expire in 30 seconds. */ + ticks_from_now = ble_hs_conn_timer(); + TEST_ASSERT(ticks_from_now == MYNEWT_VAL(BLE_L2CAP_RX_FRAG_TIMEOUT)); + + /* Almost let the timer expire. */ + os_time_advance(MYNEWT_VAL(BLE_L2CAP_RX_FRAG_TIMEOUT) - 1); + ticks_from_now = ble_hs_conn_timer(); + TEST_ASSERT(ticks_from_now == 1); + + /* Receive a second fragment. */ + rc = ble_l2cap_test_util_rx_next_frag(2, 14); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure timer got reset. */ + ticks_from_now = ble_hs_conn_timer(); + TEST_ASSERT(ticks_from_now == MYNEWT_VAL(BLE_L2CAP_RX_FRAG_TIMEOUT)); + + /* Allow the timer to expire. */ + ble_hs_test_util_hci_ack_set_disconnect(0); + os_time_advance(MYNEWT_VAL(BLE_L2CAP_RX_FRAG_TIMEOUT)); + ticks_from_now = ble_hs_conn_timer(); + TEST_ASSERT(ticks_from_now == BLE_HS_FOREVER); + + /* Ensure connection was terminated. */ + ble_hs_test_util_hci_verify_tx_disconnect(2, BLE_ERR_REM_USER_CONN_TERM); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +/***************************************************************************** + * $unsolicited response * + *****************************************************************************/ + +TEST_CASE_SELF(ble_l2cap_test_case_sig_unsol_rsp) +{ + int rc; + + ble_l2cap_test_util_init(); + + ble_l2cap_test_util_create_conn(2, ((uint8_t[]){1,2,3,4,5,6}), + NULL, NULL); + + /* Receive an unsolicited response. */ + rc = ble_hs_test_util_rx_l2cap_update_rsp(2, 100, 0); + TEST_ASSERT(rc == 0); + + /* Ensure we did not send anything in return. */ + TEST_ASSERT_FATAL(ble_hs_test_util_prev_tx_dequeue() == NULL); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +/***************************************************************************** + * $update * + *****************************************************************************/ + +static int +ble_l2cap_test_util_conn_cb(struct ble_gap_event *event, void *arg) +{ + int *accept; + + switch (event->type) { + case BLE_GAP_EVENT_L2CAP_UPDATE_REQ: + accept = arg; + return !*accept; + + default: + return 0; + } +} + +static void +ble_l2cap_test_util_peer_updates(int accept) +{ + struct ble_l2cap_sig_update_params l2cap_params; + struct ble_gap_upd_params params; + + ble_l2cap_test_util_init(); + + ble_l2cap_test_util_create_conn(2, ((uint8_t[]){1,2,3,4,5,6}), + ble_l2cap_test_util_conn_cb, + &accept); + + l2cap_params.itvl_min = 0x200; + l2cap_params.itvl_max = 0x300; + l2cap_params.slave_latency = 0; + l2cap_params.timeout_multiplier = 0x500; + ble_l2cap_test_util_rx_update_req(2, 1, &l2cap_params); + + /* Ensure an update response command got sent. */ + ble_hs_test_util_verify_tx_l2cap_update_rsp(1, !accept); + + if (accept) { + params.itvl_min = 0x200; + params.itvl_max = 0x300; + params.latency = 0; + params.supervision_timeout = 0x500; + params.min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN; + params.max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN; + ble_l2cap_test_util_verify_tx_update_conn(¶ms); + } else { + /* Ensure no update got scheduled. */ + TEST_ASSERT(!ble_gap_dbg_update_active(2)); + } +} + +static void +ble_l2cap_test_util_update_cb(uint16_t conn_handle, int status, void *arg) +{ + ble_l2cap_test_update_conn_handle = conn_handle; + ble_l2cap_test_update_status = status; + ble_l2cap_test_update_arg = arg; +} + +static void +ble_l2cap_test_util_we_update(int peer_accepts) +{ + struct ble_l2cap_sig_update_params params; + uint8_t id; + int rc; + + ble_l2cap_test_util_init(); + + ble_l2cap_test_util_create_conn(2, ((uint8_t[]){1,2,3,4,5,6}), + ble_l2cap_test_util_conn_cb, NULL); + + /* Only the slave can initiate the L2CAP connection update procedure. */ + ble_hs_atomic_conn_set_flags(2, BLE_HS_CONN_F_MASTER, 0); + + params.itvl_min = 0x200; + params.itvl_max = 0x300; + params.slave_latency = 0; + params.timeout_multiplier = 0x100; + rc = ble_l2cap_sig_update(2, ¶ms, ble_l2cap_test_util_update_cb, NULL); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure an update request got sent. */ + id = ble_hs_test_util_verify_tx_l2cap_update_req(¶ms); + + /* Receive response from peer. */ + rc = ble_hs_test_util_rx_l2cap_update_rsp(2, id, !peer_accepts); + TEST_ASSERT(rc == 0); + + /* Ensure callback got called. */ + if (peer_accepts) { + TEST_ASSERT(ble_l2cap_test_update_status == 0); + } else { + TEST_ASSERT(ble_l2cap_test_update_status == BLE_HS_EREJECT); + } + TEST_ASSERT(ble_l2cap_test_update_arg == NULL); +} + +TEST_CASE_SELF(ble_l2cap_test_case_sig_update_accept) +{ + ble_l2cap_test_util_peer_updates(1); + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_l2cap_test_case_sig_update_reject) +{ + ble_l2cap_test_util_peer_updates(0); + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_l2cap_test_case_sig_update_init_accept) +{ + ble_l2cap_test_util_we_update(1); + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_l2cap_test_case_sig_update_init_reject) +{ + ble_l2cap_test_util_we_update(0); + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_l2cap_test_case_sig_update_init_fail_master) +{ + struct ble_l2cap_sig_update_params params; + int rc; + + ble_l2cap_test_util_init(); + + ble_l2cap_test_util_create_conn(2, ((uint8_t[]){1,2,3,4,5,6}), + ble_l2cap_test_util_conn_cb, NULL); + + params.itvl_min = 0x200; + params.itvl_max = 0x300; + params.slave_latency = 0; + params.timeout_multiplier = 0x100; + rc = ble_l2cap_sig_update(2, ¶ms, ble_l2cap_test_util_update_cb, NULL); + TEST_ASSERT_FATAL(rc == BLE_HS_EINVAL); + + /* Ensure callback never called. */ + TEST_ASSERT(ble_l2cap_test_update_status == -1); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_l2cap_test_case_sig_update_init_fail_bad_id) +{ + struct ble_l2cap_sig_update_params params; + uint8_t id; + int rc; + + ble_l2cap_test_util_init(); + + ble_l2cap_test_util_create_conn(2, ((uint8_t[]){1,2,3,4,5,6}), + ble_l2cap_test_util_conn_cb, NULL); + + /* Only the slave can initiate the L2CAP connection update procedure. */ + ble_hs_atomic_conn_set_flags(2, BLE_HS_CONN_F_MASTER, 0); + + params.itvl_min = 0x200; + params.itvl_max = 0x300; + params.slave_latency = 0; + params.timeout_multiplier = 0x100; + rc = ble_l2cap_sig_update(2, ¶ms, ble_l2cap_test_util_update_cb, NULL); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure an update request got sent. */ + id = ble_hs_test_util_verify_tx_l2cap_update_req(¶ms); + + /* Receive response from peer with incorrect ID. */ + rc = ble_hs_test_util_rx_l2cap_update_rsp(2, id + 1, 0); + TEST_ASSERT(rc == 0); + + /* Ensure callback did not get called. */ + TEST_ASSERT(ble_l2cap_test_update_status == -1); + + /* Receive response from peer with correct ID. */ + rc = ble_hs_test_util_rx_l2cap_update_rsp(2, id, 0); + TEST_ASSERT(rc == 0); + + /* Ensure callback got called. */ + TEST_ASSERT(ble_l2cap_test_update_status == 0); + TEST_ASSERT(ble_l2cap_test_update_arg == NULL); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +/* Test enum but first four events matches to events which L2CAP sends to + * application. We need this in order to add additional SEND_DATA event for + * testing + */ + +enum { + BLE_L2CAP_TEST_EVENT_COC_CONNECT = 0, + BLE_L2CAP_TEST_EVENT_COC_DISCONNECT, + BLE_L2CAP_TEST_EVENT_COC_ACCEPT, + BLE_L2CAP_TEST_EVENT_COC_RECV_DATA, + BLE_L2CAP_TEST_EVENT_COC_SEND_DATA, +}; + +struct event { + uint8_t type; + uint16_t early_error; + uint16_t l2cap_status; + uint16_t app_status; + uint8_t handled; + uint8_t *data; + uint16_t data_len; +}; + +struct test_data { + struct event event[3]; + uint16_t expected_num_of_ev; + uint16_t expected_num_iters; + /* This we use to track number of events sent to application*/ + uint16_t event_cnt; + /* This we use to track verified events (received or not) */ + uint16_t event_iter; + uint16_t psm; + uint16_t mtu; + uint8_t num; + struct ble_l2cap_chan *chan[5]; +}; + +static int +ble_l2cap_test_event(struct ble_l2cap_event *event, void *arg) +{ + struct test_data *t = arg; + struct event *ev = &t->event[t->event_cnt++]; + struct os_mbuf *sdu_rx; + + assert(ev->type == event->type); + ev->handled = 1; + switch(event->type) { + case BLE_L2CAP_EVENT_COC_CONNECTED: + assert(ev->app_status == event->connect.status); + t->chan[0] = event->connect.chan; + return 0; + case BLE_L2CAP_EVENT_COC_DISCONNECTED: + return 0; + case BLE_L2CAP_EVENT_COC_ACCEPT: + if (ev->app_status != 0) { + return ev->app_status; + } + + sdu_rx = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0); + assert(sdu_rx != NULL); + ble_l2cap_recv_ready(event->accept.chan, sdu_rx); + + return 0; + + case BLE_L2CAP_EVENT_COC_DATA_RECEIVED: + sdu_rx = os_mbuf_pullup(event->receive.sdu_rx, + OS_MBUF_PKTLEN(event->receive.sdu_rx)); + TEST_ASSERT(memcmp(sdu_rx->om_data, ev->data, ev->data_len) == 0); + return 0; + case BLE_L2CAP_EVENT_COC_TX_UNSTALLED: + /* TODO Add tests for this */ + return 0; + default: + return 0; + } +} + +static uint16_t ble_l2cap_calculate_credits(uint16_t mtu, uint16_t mps) +{ + int credits; + + credits = mtu / mps; + if (mtu % mps) { + credits++; + } + + return credits; +} + +static void +ble_l2cap_test_coc_connect_multi(struct test_data *t) +{ + struct ble_l2cap_sig_credit_base_connect_req *req; + struct ble_l2cap_sig_credit_base_connect_rsp *rsp; + struct os_mbuf *sdu_rx[t->num]; + struct event *ev = &t->event[t->event_iter++]; + uint8_t id; + int rc; + int i; + + req = malloc(sizeof(*req) + (sizeof(uint16_t) * t->num)); + rsp = malloc(sizeof(*rsp) + (sizeof(uint16_t) * t->num)); + + ble_l2cap_test_util_init(); + + ble_l2cap_test_util_create_conn(2, ((uint8_t[]) {1, 2, 3, 4, 5, 6}), + ble_l2cap_test_util_conn_cb, NULL); + + for (i = 0; i < t->num; i++) { + sdu_rx[i] = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0); + assert(sdu_rx[i] != NULL); + } + + rc = ble_l2cap_sig_ecoc_connect(2, t->psm, t->mtu, t->num, sdu_rx, + ble_l2cap_test_event, t); + TEST_ASSERT_FATAL(rc == ev->early_error); + + if (rc != 0) { + for (i = 0; i< t->num; i++) { + rc = os_mbuf_free_chain(sdu_rx[i]); + TEST_ASSERT_FATAL(rc == 0); + } + + return; + } + + req->credits = htole16( + ble_l2cap_calculate_credits(t->mtu, + MYNEWT_VAL(BLE_L2CAP_COC_MPS))); + req->mps = htole16(MYNEWT_VAL(BLE_L2CAP_COC_MPS)); + req->mtu = htole16(t->mtu); + req->psm = htole16(t->psm); + for (i = 0; i < t->num; i++) { + req->scids[i] = htole16(current_cid + i); + } + + /* Ensure an update request got sent. */ + id = ble_hs_test_util_verify_tx_l2cap_sig( + BLE_L2CAP_SIG_OP_CREDIT_CONNECT_REQ, + req, sizeof(*req) + t->num * sizeof(uint16_t)); + + /* Use some different parameters for peer. Just keep mtu same for testing + * only*/ + rsp->credits = htole16(10); + for (i = 0; i < t->num; i++) { + rsp->dcids[i] = htole16(current_cid + i); + } + rsp->mps = htole16(MYNEWT_VAL(BLE_L2CAP_COC_MPS) + 16); + rsp->mtu = htole16(t->mtu); + rsp->result = htole16(ev->l2cap_status); + + rc = ble_hs_test_util_inject_rx_l2cap_sig(2, + BLE_L2CAP_SIG_OP_CREDIT_CONNECT_RSP, + id, rsp, sizeof(*rsp) + t->num * sizeof(uint16_t)); + TEST_ASSERT(rc == 0); + + /* Ensure callback got called. */ + TEST_ASSERT(ev->handled); +} + +static void +ble_l2cap_test_coc_connect(struct test_data *t) +{ + struct ble_l2cap_sig_le_con_req req = {}; + struct ble_l2cap_sig_le_con_rsp rsp = {}; + struct os_mbuf *sdu_rx; + struct event *ev = &t->event[t->event_iter++]; + uint8_t id; + int rc; + + ble_l2cap_test_util_init(); + + ble_l2cap_test_util_create_conn(2, ((uint8_t[]){1,2,3,4,5,6}), + ble_l2cap_test_util_conn_cb, NULL); + + sdu_rx = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0); + assert(sdu_rx != NULL); + + rc = ble_l2cap_sig_coc_connect(2, t->psm, t->mtu, sdu_rx, + ble_l2cap_test_event, t); + TEST_ASSERT_FATAL(rc == ev->early_error); + + if (rc != 0) { + rc = os_mbuf_free_chain(sdu_rx); + TEST_ASSERT_FATAL(rc == 0); + return; + } + + req.credits = htole16( + ble_l2cap_calculate_credits(t->mtu, + MYNEWT_VAL(BLE_L2CAP_COC_MPS))); + req.mps = htole16(MYNEWT_VAL(BLE_L2CAP_COC_MPS)); + req.mtu = htole16(t->mtu); + req.psm = htole16(t->psm); + req.scid = htole16(current_cid); + + /* Ensure an update request got sent. */ + id = ble_hs_test_util_verify_tx_l2cap_sig( + BLE_L2CAP_SIG_OP_LE_CREDIT_CONNECT_REQ, + &req, sizeof(req)); + + /* Use some different parameters for peer. Just keep mtu same for testing + * only*/ + rsp.credits = htole16(10); + rsp.dcid = htole16(current_cid); + rsp.mps = htole16(MYNEWT_VAL(BLE_L2CAP_COC_MPS) + 16); + rsp.mtu = htole16(t->mtu); + rsp.result = htole16(ev->l2cap_status); + + rc = ble_hs_test_util_inject_rx_l2cap_sig(2, + BLE_L2CAP_SIG_OP_LE_CREDIT_CONNECT_RSP, + id, &rsp, sizeof(rsp)); + TEST_ASSERT(rc == 0); + + /* Ensure callback got called. */ + TEST_ASSERT(ev->handled); +} + +static void +ble_l2cap_test_coc_connect_by_peer(struct test_data *t) +{ + struct ble_l2cap_sig_le_con_req req = {}; + struct ble_l2cap_sig_le_con_rsp rsp = {}; + uint8_t id = 10; + int rc; + struct event *ev = &t->event[t->event_iter++]; + + ble_l2cap_test_util_create_conn(2, ((uint8_t[]){1,2,3,4,5,6}), + ble_l2cap_test_util_conn_cb, NULL); + + /* Use some different parameters for peer */ + req.credits = htole16(30); + req.mps = htole16(MYNEWT_VAL(BLE_L2CAP_COC_MPS) + 16); + req.mtu = htole16(t->mtu); + req.psm = htole16(t->psm); + req.scid = htole16(0x0040); + + /* Receive remote request*/ + rc = ble_hs_test_util_inject_rx_l2cap_sig(2, + BLE_L2CAP_SIG_OP_LE_CREDIT_CONNECT_REQ, + id, &req, sizeof(req)); + TEST_ASSERT_FATAL(rc == 0); + + if (ev->type == BLE_L2CAP_EVENT_COC_ACCEPT) { + /* Lets check if there is accept event */ + TEST_ASSERT(ev->handled); + /* Ensure callback got called. */ + ev = &t->event[t->event_iter++]; + } + + if (ev->l2cap_status != 0) { + rsp.result = htole16(ev->l2cap_status); + } else { + /* Receive response from peer.*/ + rsp.credits = htole16( + ble_l2cap_calculate_credits(t->mtu, + MYNEWT_VAL(BLE_L2CAP_COC_MPS))); + rsp.dcid = htole16(current_cid); + rsp.mps = htole16(MYNEWT_VAL(BLE_L2CAP_COC_MPS)); + rsp.mtu = htole16(t->mtu); + } + + /* Ensure we sent response. */ + TEST_ASSERT(id == ble_hs_test_util_verify_tx_l2cap_sig( + BLE_L2CAP_SIG_OP_LE_CREDIT_CONNECT_RSP, + &rsp, sizeof(rsp))); + + if (ev->l2cap_status == 0) { + TEST_ASSERT(ev->handled); + } else { + TEST_ASSERT(!ev->handled); + } +} + +static void +ble_l2cap_test_coc_disc(struct test_data *t) +{ + struct ble_l2cap_sig_disc_req req; + struct event *ev = &t->event[t->event_iter++]; + uint8_t id; + int rc; + + rc = ble_l2cap_sig_disconnect(t->chan[0]); + TEST_ASSERT_FATAL(rc == 0); + + req.dcid = htole16(t->chan[0]->dcid); + req.scid = htole16(t->chan[0]->scid); + + /* Ensure an update request got sent. */ + id = ble_hs_test_util_verify_tx_l2cap_sig(BLE_L2CAP_SIG_OP_DISCONN_REQ, + &req, sizeof(req)); + + /* Receive response from peer. Note it shall be same as request */ + rc = ble_hs_test_util_inject_rx_l2cap_sig(2, BLE_L2CAP_SIG_OP_DISCONN_RSP, + id, &req, sizeof(req)); + TEST_ASSERT(rc == 0); + + /* Ensure callback got called. */ + TEST_ASSERT(ev->handled); +} + +static void +ble_l2cap_test_coc_disc_by_peer(struct test_data *t) +{ + struct ble_l2cap_sig_disc_req req; + struct event *ev = &t->event[t->event_iter++]; + uint8_t id = 10; + int rc; + + /* Receive disconnect request from peer. Note that source cid + * and destination cid are from peer perspective */ + req.dcid = htole16(t->chan[0]->scid); + req.scid = htole16(t->chan[0]->dcid); + + rc = ble_hs_test_util_inject_rx_l2cap_sig(2, BLE_L2CAP_SIG_OP_DISCONN_REQ, + id, &req, sizeof(req)); + TEST_ASSERT(rc == 0); + + /* Ensure callback got called. */ + TEST_ASSERT(ev->handled); + + /* Ensure an we sent back response. Note that payload is same as request, + * lets reuse it */ + TEST_ASSERT(ble_hs_test_util_verify_tx_l2cap_sig( + BLE_L2CAP_SIG_OP_DISCONN_RSP, + &req, sizeof(req)) == id); +} + +static void +ble_l2cap_test_coc_invalid_disc_by_peer(struct test_data *t) +{ + struct ble_l2cap_sig_disc_req req; + uint8_t id = 10; + int rc; + struct event *ev = &t->event[t->event_iter++]; + + /* Receive disconnect request from peer. Note that source cid + * and destination cid are from peer perspective */ + req.dcid = htole16(t->chan[0]->scid); + req.scid = htole16(0); + + rc = ble_hs_test_util_inject_rx_l2cap_sig(2, BLE_L2CAP_SIG_OP_DISCONN_REQ, + id, &req, sizeof(req)); + TEST_ASSERT(rc == 0); + + /* Ensure callback HAS NOT BEEN*/ + TEST_ASSERT(!ev->handled); +} + +static void +ble_l2cap_test_coc_send_data(struct test_data *t) +{ + struct os_mbuf *sdu; + struct os_mbuf *sdu_copy; + struct event *ev = &t->event[t->event_iter++]; + int rc; + + /* Send data event is created only for testing. + * Since application callback do caching of real stack event + * and checks the type of the event, lets increase event counter here and + * fake that this event is handled*/ + t->event_cnt++; + + sdu = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0); + assert(sdu != NULL); + + sdu_copy = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0); + assert(sdu_copy != NULL); + + rc = os_mbuf_append(sdu, ev->data, ev->data_len); + TEST_ASSERT(rc == 0); + + rc = os_mbuf_append(sdu_copy, ev->data, ev->data_len); + TEST_ASSERT(rc == 0); + + rc = ble_l2cap_send(t->chan[0], sdu); + TEST_ASSERT(rc == ev->early_error); + + if (rc) { + rc = os_mbuf_free(sdu); + TEST_ASSERT_FATAL(rc == 0); + + rc = os_mbuf_free(sdu_copy); + TEST_ASSERT_FATAL(rc == 0); + return; + } + + /* Add place for SDU len */ + sdu_copy = os_mbuf_prepend_pullup(sdu_copy, 2); + assert(sdu_copy != NULL); + put_le16(sdu_copy->om_data, ev->data_len); + + ble_hs_test_util_verify_tx_l2cap(sdu); + + rc = os_mbuf_free_chain(sdu_copy); + TEST_ASSERT_FATAL(rc == 0); +} + +static void +ble_l2cap_test_coc_recv_data(struct test_data *t) +{ + struct os_mbuf *sdu; + int rc; + struct event *ev = &t->event[t->event_iter++]; + + sdu = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0); + assert(sdu != NULL); + + rc = os_mbuf_append(sdu, ev->data, ev->data_len); + TEST_ASSERT(rc == 0); + + /* TODO handle fragmentation */ + + /* Add place for SDU len */ + sdu = os_mbuf_prepend_pullup(sdu, 2); + assert(sdu != NULL); + put_le16(sdu->om_data, ev->data_len); + + ble_hs_test_util_inject_rx_l2cap(2, t->chan[0]->scid, sdu); +} + +static void +ble_l2cap_test_set_chan_test_conf(uint16_t psm, uint16_t mtu, + struct test_data *t) +{ + memset(t, 0, sizeof(*t)); + + t->psm = psm; + t->mtu = mtu; +} + +TEST_CASE_SELF(ble_l2cap_test_case_sig_coc_conn_invalid_psm) +{ + struct test_data t; + + ble_l2cap_test_util_init(); + ble_l2cap_test_set_chan_test_conf(BLE_L2CAP_TEST_PSM, + BLE_L2CAP_TEST_COC_MTU, &t); + t.expected_num_of_ev = 1; + t.expected_num_iters = 1; + + t.event[0].type = BLE_L2CAP_EVENT_COC_CONNECTED; + t.event[0].app_status = BLE_HS_ENOTSUP; + t.event[0].l2cap_status = BLE_L2CAP_COC_ERR_UNKNOWN_LE_PSM; + + ble_l2cap_test_coc_connect(&t); + + TEST_ASSERT(t.expected_num_of_ev == t.event_cnt); + TEST_ASSERT(t.expected_num_iters == t.event_iter); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_l2cap_test_case_sig_coc_conn_out_of_resource) +{ + struct test_data t; + + ble_l2cap_test_util_init(); + + ble_l2cap_test_set_chan_test_conf(BLE_L2CAP_TEST_PSM, + BLE_L2CAP_TEST_COC_MTU, &t); + t.expected_num_of_ev = 1; + t.expected_num_iters = 1; + + t.event[0].type = BLE_L2CAP_EVENT_COC_CONNECTED; + t.event[0].app_status = BLE_HS_ENOMEM; + t.event[0].l2cap_status = BLE_L2CAP_COC_ERR_NO_RESOURCES; + + ble_l2cap_test_coc_connect(&t); + + TEST_ASSERT(t.expected_num_of_ev == t.event_cnt); + TEST_ASSERT(t.expected_num_iters == t.event_iter); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_l2cap_test_case_sig_coc_conn_invalid_cid) +{ + struct test_data t; + + ble_l2cap_test_util_init(); + + ble_l2cap_test_set_chan_test_conf(BLE_L2CAP_TEST_PSM, + BLE_L2CAP_TEST_COC_MTU, &t); + t.expected_num_of_ev = 1; + + t.event[0].type = BLE_L2CAP_EVENT_COC_CONNECTED; + t.event[0].app_status = BLE_HS_EREJECT; + t.event[0].l2cap_status = BLE_L2CAP_COC_ERR_INVALID_SOURCE_CID; + + ble_l2cap_test_coc_connect(&t); + + TEST_ASSERT(t.expected_num_of_ev == t.event_cnt); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_l2cap_test_case_sig_coc_conn_insuff_authen) +{ + struct test_data t; + + ble_l2cap_test_util_init(); + + ble_l2cap_test_set_chan_test_conf(BLE_L2CAP_TEST_PSM, + BLE_L2CAP_TEST_COC_MTU, &t); + t.expected_num_of_ev = 1; + + t.event[0].type = BLE_L2CAP_EVENT_COC_CONNECTED; + t.event[0].app_status = BLE_HS_EAUTHEN; + t.event[0].l2cap_status = BLE_L2CAP_COC_ERR_INSUFFICIENT_AUTHEN; + + ble_l2cap_test_coc_connect(&t); + + TEST_ASSERT(t.expected_num_of_ev == t.event_cnt); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_l2cap_test_case_sig_coc_conn_insuff_author) +{ + struct test_data t; + + ble_l2cap_test_util_init(); + + ble_l2cap_test_set_chan_test_conf(BLE_L2CAP_TEST_PSM, + BLE_L2CAP_TEST_COC_MTU, &t); + t.expected_num_of_ev = 1; + + t.event[0].type = BLE_L2CAP_EVENT_COC_CONNECTED; + t.event[0].app_status = BLE_HS_EAUTHOR; + t.event[0].l2cap_status = BLE_L2CAP_COC_ERR_INSUFFICIENT_AUTHOR; + + ble_l2cap_test_coc_connect(&t); + + TEST_ASSERT(t.expected_num_of_ev == t.event_cnt); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_l2cap_test_case_sig_coc_incoming_conn_invalid_psm) +{ + struct test_data t; + + ble_l2cap_test_util_init(); + + ble_l2cap_test_set_chan_test_conf(BLE_L2CAP_TEST_PSM, + BLE_L2CAP_TEST_COC_MTU, &t); + t.expected_num_of_ev = 0; + t.expected_num_iters = 1; + + t.event[0].type = BLE_L2CAP_EVENT_COC_CONNECTED; + t.event[0].l2cap_status = BLE_L2CAP_COC_ERR_UNKNOWN_LE_PSM; + + ble_l2cap_test_coc_connect_by_peer(&t); + + TEST_ASSERT(t.expected_num_iters == t.event_iter); + TEST_ASSERT(t.expected_num_of_ev == t.event_cnt); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_l2cap_test_case_sig_coc_incoming_conn_rejected_by_app) +{ + struct test_data t; + int rc; + + ble_l2cap_test_util_init(); + + ble_l2cap_test_set_chan_test_conf(BLE_L2CAP_TEST_PSM, + BLE_L2CAP_TEST_COC_MTU, &t); + t.expected_num_of_ev = 1; + t.expected_num_iters = 2; + + t.event[0].type = BLE_L2CAP_EVENT_COC_ACCEPT; + t.event[0].app_status = BLE_HS_ENOMEM; + + /* This event will not be called and test is going to verify it*/ + t.event[1].type = BLE_L2CAP_EVENT_COC_CONNECTED; + t.event[1].l2cap_status = BLE_L2CAP_COC_ERR_NO_RESOURCES; + + /* Register server */ + rc = ble_l2cap_create_server(t.psm, BLE_L2CAP_TEST_COC_MTU, + ble_l2cap_test_event, &t); + TEST_ASSERT(rc == 0); + + ble_l2cap_test_coc_connect_by_peer(&t); + + TEST_ASSERT(t.expected_num_iters == t.event_iter); + TEST_ASSERT(t.expected_num_of_ev == t.event_cnt); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_l2cap_test_case_sig_coc_incoming_conn_success) +{ + struct test_data t; + int rc; + + ble_l2cap_test_util_init(); + + ble_l2cap_test_set_chan_test_conf(BLE_L2CAP_TEST_PSM, + BLE_L2CAP_TEST_COC_MTU, &t); + t.expected_num_of_ev = 2; + + t.event[0].type = BLE_L2CAP_EVENT_COC_ACCEPT; + t.event[1].type = BLE_L2CAP_EVENT_COC_CONNECTED; + + /* Register server */ + rc = ble_l2cap_create_server(t.psm, BLE_L2CAP_TEST_COC_MTU, + ble_l2cap_test_event, &t); + TEST_ASSERT(rc == 0); + + ble_l2cap_test_coc_connect_by_peer(&t); + + TEST_ASSERT(t.expected_num_of_ev == t.event_cnt); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_l2cap_test_case_sig_coc_disconnect_succeed) +{ + struct test_data t; + + ble_l2cap_test_util_init(); + + ble_l2cap_test_set_chan_test_conf(BLE_L2CAP_TEST_PSM, + BLE_L2CAP_TEST_COC_MTU, &t); + t. expected_num_of_ev = 2; + + t.event[0].type = BLE_L2CAP_EVENT_COC_CONNECTED; + t.event[0].app_status = 0; + t.event[0].l2cap_status = BLE_L2CAP_COC_ERR_CONNECTION_SUCCESS; + t.event[1].type = BLE_L2CAP_EVENT_COC_DISCONNECTED; + + ble_l2cap_test_coc_connect(&t); + ble_l2cap_test_coc_disc(&t); + + TEST_ASSERT(t.expected_num_of_ev == t.event_cnt); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_l2cap_test_case_sig_coc_incoming_disconnect_succeed) +{ + struct test_data t; + + ble_l2cap_test_util_init(); + + ble_l2cap_test_set_chan_test_conf(BLE_L2CAP_TEST_PSM, + BLE_L2CAP_TEST_COC_MTU, &t); + t.expected_num_of_ev = 2; + + t.event[0].type = BLE_L2CAP_EVENT_COC_CONNECTED; + t.event[0].app_status = 0; + t.event[0].l2cap_status = BLE_L2CAP_COC_ERR_CONNECTION_SUCCESS; + t.event[1].type = BLE_L2CAP_EVENT_COC_DISCONNECTED; + + ble_l2cap_test_coc_connect(&t); + ble_l2cap_test_coc_disc_by_peer(&t); + + TEST_ASSERT(t.expected_num_of_ev == t.event_cnt); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_l2cap_test_case_sig_coc_incoming_disconnect_failed) +{ + struct test_data t; + + ble_l2cap_test_util_init(); + + ble_l2cap_test_set_chan_test_conf(BLE_L2CAP_TEST_PSM, + BLE_L2CAP_TEST_COC_MTU, &t); + t.expected_num_of_ev = 1; + t.expected_num_iters = 2; + + t.event[0].type = BLE_L2CAP_EVENT_COC_CONNECTED; + t.event[0].app_status = 0; + t.event[0].l2cap_status = BLE_L2CAP_COC_ERR_CONNECTION_SUCCESS; + t.event[1].type = BLE_L2CAP_EVENT_COC_DISCONNECTED; + + ble_l2cap_test_coc_connect(&t); + ble_l2cap_test_coc_invalid_disc_by_peer(&t); + + TEST_ASSERT(t.expected_num_iters == t.event_iter); + TEST_ASSERT(t.expected_num_of_ev == t.event_cnt); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_l2cap_test_case_coc_send_data_succeed) +{ + struct test_data t; + uint8_t buf[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; + + ble_l2cap_test_util_init(); + + ble_l2cap_test_set_chan_test_conf(BLE_L2CAP_TEST_PSM, + BLE_L2CAP_TEST_COC_MTU, &t); + t.expected_num_of_ev = 3; + + t.event[0].type = BLE_L2CAP_TEST_EVENT_COC_CONNECT; + t.event[1].type = BLE_L2CAP_TEST_EVENT_COC_SEND_DATA; + t.event[1].data = buf; + t.event[1].data_len = sizeof(buf); + t.event[2].type = BLE_L2CAP_TEST_EVENT_COC_DISCONNECT; + + ble_l2cap_test_coc_connect(&t); + ble_l2cap_test_coc_send_data(&t); + ble_l2cap_test_coc_disc(&t); + + TEST_ASSERT(t.expected_num_of_ev == t.event_cnt); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_l2cap_test_case_coc_send_data_failed_too_big_sdu) +{ + struct test_data t = {}; + uint16_t small_mtu = 27; + uint8_t buf[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; + + ble_l2cap_test_util_init(); + + ble_l2cap_test_set_chan_test_conf(BLE_L2CAP_TEST_PSM, small_mtu, &t); + t.expected_num_of_ev = 3; + + t.event[0].type = BLE_L2CAP_TEST_EVENT_COC_CONNECT; + t.event[1].type = BLE_L2CAP_TEST_EVENT_COC_SEND_DATA; + t.event[1].data = buf; + t.event[1].data_len = sizeof(buf); + t.event[1].early_error = BLE_HS_EBADDATA; + t.event[2].type = BLE_L2CAP_TEST_EVENT_COC_DISCONNECT; + + ble_l2cap_test_coc_connect(&t); + ble_l2cap_test_coc_send_data(&t); + ble_l2cap_test_coc_disc(&t); + + TEST_ASSERT(t.expected_num_of_ev == t.event_cnt); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_l2cap_test_case_coc_recv_data_succeed) +{ + struct test_data t = {}; + uint8_t buf[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; + + ble_l2cap_test_util_init(); + + ble_l2cap_test_set_chan_test_conf(BLE_L2CAP_TEST_PSM, + BLE_L2CAP_TEST_COC_MTU, &t); + t.expected_num_of_ev = 3; + + t.event[0].type = BLE_L2CAP_EVENT_COC_CONNECTED; + t.event[1].type = BLE_L2CAP_EVENT_COC_DATA_RECEIVED; + t.event[1].data = buf; + t.event[1].data_len = sizeof(buf); + t.event[2].type = BLE_L2CAP_EVENT_COC_DISCONNECTED; + + ble_l2cap_test_coc_connect(&t); + ble_l2cap_test_coc_recv_data(&t); + ble_l2cap_test_coc_disc(&t); + + TEST_ASSERT(t.expected_num_of_ev == t.event_cnt); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_l2cap_test_case_sig_coc_conn_multi) +{ + struct test_data t; + int rc; + + ble_l2cap_test_util_init(); + ble_l2cap_test_set_chan_test_conf(BLE_L2CAP_TEST_PSM, + BLE_L2CAP_TEST_COC_MTU, &t); + t.expected_num_of_ev = 2; + t.num = 2; + + t.event[0].type = BLE_L2CAP_EVENT_COC_CONNECTED; + t.event[1].type = BLE_L2CAP_EVENT_COC_CONNECTED; + + /* Register server */ + rc = ble_l2cap_create_server(t.psm, BLE_L2CAP_TEST_COC_MTU, + ble_l2cap_test_event, &t); + TEST_ASSERT(rc == 0); + + ble_l2cap_test_coc_connect_multi(&t); + + TEST_ASSERT(t.expected_num_of_ev == t.event_cnt); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_l2cap_test_suite) +{ + ble_l2cap_test_case_bad_header(); + ble_l2cap_test_case_bad_handle(); + ble_l2cap_test_case_frag_single(); + ble_l2cap_test_case_frag_multiple(); + ble_l2cap_test_case_frag_channels(); + ble_l2cap_test_case_frag_timeout(); + ble_l2cap_test_case_sig_unsol_rsp(); + ble_l2cap_test_case_sig_update_accept(); + ble_l2cap_test_case_sig_update_reject(); + ble_l2cap_test_case_sig_update_init_accept(); + ble_l2cap_test_case_sig_update_init_reject(); + ble_l2cap_test_case_sig_update_init_fail_master(); + ble_l2cap_test_case_sig_update_init_fail_bad_id(); + ble_l2cap_test_case_sig_coc_conn_invalid_psm(); + ble_l2cap_test_case_sig_coc_conn_out_of_resource(); + ble_l2cap_test_case_sig_coc_conn_invalid_cid(); + ble_l2cap_test_case_sig_coc_conn_insuff_authen(); + ble_l2cap_test_case_sig_coc_conn_insuff_author(); + ble_l2cap_test_case_sig_coc_incoming_conn_invalid_psm(); + ble_l2cap_test_case_sig_coc_incoming_conn_rejected_by_app(); + ble_l2cap_test_case_sig_coc_incoming_conn_success(); + ble_l2cap_test_case_sig_coc_disconnect_succeed(); + ble_l2cap_test_case_sig_coc_incoming_disconnect_succeed(); + ble_l2cap_test_case_sig_coc_incoming_disconnect_failed(); + ble_l2cap_test_case_coc_send_data_succeed(); + ble_l2cap_test_case_coc_send_data_failed_too_big_sdu(); + ble_l2cap_test_case_coc_recv_data_succeed(); + ble_l2cap_test_case_sig_coc_conn_multi(); +} diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_os_test.c b/src/libs/mynewt-nimble/nimble/host/test/src/ble_os_test.c new file mode 100644 index 00000000..fa57571b --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_os_test.c @@ -0,0 +1,388 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include "os/os.h" +#include "testutil/testutil.h" +#include "nimble/hci_common.h" +#include "nimble/ble_hci_trans.h" +#include "ble_hs_test.h" +#include "host/ble_gap.h" +#include "ble_hs_test_util.h" + +#define BLE_OS_TEST_STACK_SIZE 256 +#define BLE_OS_TEST_APP_STACK_SIZE 256 + +#define BLE_OS_TEST_APP_PRIO 9 +#define BLE_OS_TEST_TASK_PRIO 10 + +static struct os_task ble_os_test_task; +static struct os_task ble_os_test_app_task; +static os_stack_t ble_os_test_stack[OS_STACK_ALIGN(BLE_OS_TEST_STACK_SIZE)]; + +static os_stack_t +ble_os_test_app_stack[OS_STACK_ALIGN(BLE_OS_TEST_APP_STACK_SIZE)]; + +static uint8_t ble_os_test_peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + +static void ble_os_test_app_task_handler(void *arg); + +static int ble_os_test_gap_event_type; + +static void +ble_os_test_init_app_task(void) +{ + int rc; + + rc = os_task_init(&ble_os_test_app_task, + "ble_gap_terminate_test_task", + ble_os_test_app_task_handler, NULL, + BLE_OS_TEST_APP_PRIO, OS_WAIT_FOREVER, + ble_os_test_app_stack, + OS_STACK_ALIGN(BLE_OS_TEST_APP_STACK_SIZE)); + TEST_ASSERT_FATAL(rc == 0); +} + +static void +ble_os_test_misc_init(void) +{ + extern os_time_t g_os_time; + + ble_hs_test_util_init_no_start(); + + /* Allow the OS to approach tick rollover. This will help ensure host + * timers don't break when the tick counter resets. + */ + g_os_time = UINT32_MAX - 10 * OS_TICKS_PER_SEC; + + /* Receive acknowledgements for the startup sequence. We sent the + * corresponding requests when the host task was started. + */ + ble_hs_test_util_hci_ack_set_startup(); + + ble_os_test_init_app_task(); +} + +static int +ble_os_test_misc_conn_exists(uint16_t conn_handle) +{ + struct ble_hs_conn *conn; + + ble_hs_lock(); + + if (conn_handle == BLE_HS_CONN_HANDLE_NONE) { + conn = ble_hs_conn_first(); + } else { + conn = ble_hs_conn_find(conn_handle); + } + + ble_hs_unlock(); + + return conn != NULL; +} + +static int +ble_gap_direct_connect_test_connect_cb(struct ble_gap_event *event, void *arg) +{ + struct ble_gap_conn_desc desc; + int *cb_called; + int rc; + + cb_called = arg; + *cb_called = 1; + + TEST_ASSERT(event->type == BLE_GAP_EVENT_CONNECT); + TEST_ASSERT(event->connect.status == 0); + TEST_ASSERT(event->connect.conn_handle == 2); + + rc = ble_gap_conn_find(event->connect.conn_handle, &desc); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(desc.peer_id_addr.type == BLE_ADDR_PUBLIC); + TEST_ASSERT(memcmp(desc.peer_id_addr.val, ble_os_test_peer_addr, 6) == 0); + + return 0; +} + +static void +ble_gap_direct_connect_test_task_handler(void *arg) +{ + struct ble_gap_conn_complete evt; + ble_addr_t addr = { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 }}; + int cb_called; + int rc; + + /* Set the connect callback so we can verify that it gets called with the + * proper arguments. + */ + cb_called = 0; + + /* Make sure there are no created connections and no connections in + * progress. + */ + TEST_ASSERT(!ble_os_test_misc_conn_exists(BLE_HS_CONN_HANDLE_NONE)); + + /* Initiate a direct connection. */ + ble_hs_test_util_connect(BLE_OWN_ADDR_PUBLIC, &addr, 0, NULL, + ble_gap_direct_connect_test_connect_cb, + &cb_called, 0); + TEST_ASSERT(!ble_os_test_misc_conn_exists(BLE_HS_CONN_HANDLE_NONE)); + TEST_ASSERT(!cb_called); + + /* ble_gap_rx_conn_complete() will send extra HCI command, need phony ack */ + ble_hs_test_util_hci_ack_set(ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_RD_REM_FEAT), 0); + + /* Receive an HCI connection-complete event. */ + memset(&evt, 0, sizeof evt); + evt.status = BLE_ERR_SUCCESS; + evt.connection_handle = 2; + memcpy(evt.peer_addr, addr.val, 6); + rc = ble_gap_rx_conn_complete(&evt, 0); + TEST_ASSERT(rc == 0); + + /* The connection should now be created. */ + TEST_ASSERT(ble_os_test_misc_conn_exists(2)); + TEST_ASSERT(cb_called); + + tu_restart(); +} + +TEST_CASE_SELF(ble_gap_direct_connect_test_case) +{ + ble_os_test_misc_init(); + + os_task_init(&ble_os_test_task, + "ble_gap_direct_connect_test_task", + ble_gap_direct_connect_test_task_handler, NULL, + BLE_OS_TEST_TASK_PRIO, OS_WAIT_FOREVER, ble_os_test_stack, + OS_STACK_ALIGN(BLE_OS_TEST_STACK_SIZE)); + + os_start(); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +static int +ble_os_disc_test_cb(struct ble_gap_event *event, void *arg) +{ + int *cb_called; + + cb_called = arg; + *cb_called = 1; + + TEST_ASSERT(event->type == BLE_GAP_EVENT_DISC_COMPLETE); + + return 0; +} + +static void +ble_os_disc_test_task_handler(void *arg) +{ + struct ble_gap_disc_params disc_params; + int cb_called; + int rc; + + /* Receive acknowledgements for the startup sequence. We sent the + * corresponding requests when the host task was started. + */ + ble_hs_test_util_hci_ack_set_startup(); + + /* Set the connect callback so we can verify that it gets called with the + * proper arguments. + */ + cb_called = 0; + + os_time_delay(10); + + /* Make sure there are no created connections and no connections in + * progress. + */ + TEST_ASSERT(!ble_os_test_misc_conn_exists(BLE_HS_CONN_HANDLE_NONE)); + TEST_ASSERT(!ble_gap_master_in_progress()); + + /* Initiate the general discovery procedure with a 300 ms timeout. */ + memset(&disc_params, 0, sizeof disc_params); + rc = ble_hs_test_util_disc(BLE_OWN_ADDR_PUBLIC, 300, &disc_params, + ble_os_disc_test_cb, + &cb_called, 0, 0); + TEST_ASSERT(rc == 0); + TEST_ASSERT(!ble_os_test_misc_conn_exists(BLE_HS_CONN_HANDLE_NONE)); + TEST_ASSERT(ble_gap_master_in_progress()); + TEST_ASSERT(!cb_called); + + /* Receive acks from the controller. */ + TEST_ASSERT(!ble_os_test_misc_conn_exists(BLE_HS_CONN_HANDLE_NONE)); + TEST_ASSERT(ble_gap_master_in_progress()); + TEST_ASSERT(!cb_called); + + /* Wait 100 ms; verify scan still in progress. */ + os_time_delay(100 * OS_TICKS_PER_SEC / 1000); + TEST_ASSERT(!ble_os_test_misc_conn_exists(BLE_HS_CONN_HANDLE_NONE)); + TEST_ASSERT(ble_gap_master_in_progress()); + TEST_ASSERT(!cb_called); + + ble_hs_test_util_hci_ack_set( + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_SET_SCAN_ENABLE), + 0); + + /* Wait 250 more ms; verify scan completed. */ + os_time_delay(250 * OS_TICKS_PER_SEC / 1000); + TEST_ASSERT(!ble_os_test_misc_conn_exists(BLE_HS_CONN_HANDLE_NONE)); + TEST_ASSERT(!ble_gap_master_in_progress()); + TEST_ASSERT(cb_called); + + tu_restart(); +} + +TEST_CASE_SELF(ble_os_disc_test_case) +{ + ble_os_test_misc_init(); + + os_task_init(&ble_os_test_task, + "ble_os_disc_test_task", + ble_os_disc_test_task_handler, NULL, + BLE_OS_TEST_TASK_PRIO, OS_WAIT_FOREVER, ble_os_test_stack, + OS_STACK_ALIGN(BLE_OS_TEST_STACK_SIZE)); + + os_start(); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +static int +ble_gap_terminate_cb(struct ble_gap_event *event, void *arg) +{ + int *disconn_handle; + + ble_os_test_gap_event_type = event->type; + + if (event->type == BLE_GAP_EVENT_DISCONNECT) { + disconn_handle = arg; + *disconn_handle = event->disconnect.conn.conn_handle; + } + + return 0; +} + +static void +ble_gap_terminate_test_task_handler(void *arg) +{ + struct ble_gap_conn_complete conn_evt; + ble_addr_t addr1 = { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 }}; + ble_addr_t addr2 = { BLE_ADDR_PUBLIC, { 2, 3, 4, 5, 6, 7 }}; + int disconn_handle; + int rc; + + /* Receive acknowledgements for the startup sequence. We sent the + * corresponding requests when the host task was started. + */ + ble_hs_test_util_hci_ack_set_startup(); + + /* Set the connect callback so we can verify that it gets called with the + * proper arguments. + */ + disconn_handle = 0; + + /* Make sure there are no created connections and no connections in + * progress. + */ + TEST_ASSERT(!ble_os_test_misc_conn_exists(BLE_HS_CONN_HANDLE_NONE)); + TEST_ASSERT(!ble_gap_master_in_progress()); + + /* Create two direct connections. */ + ble_hs_test_util_connect(BLE_OWN_ADDR_PUBLIC, + &addr1, 0, NULL, ble_gap_terminate_cb, + &disconn_handle, 0); + /* ble_gap_rx_conn_complete() will send extra HCI command, need phony ack */ + ble_hs_test_util_hci_ack_set(ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_RD_REM_FEAT), 0); + memset(&conn_evt, 0, sizeof conn_evt); + conn_evt.status = BLE_ERR_SUCCESS; + conn_evt.connection_handle = 1; + memcpy(conn_evt.peer_addr, addr1.val, 6); + rc = ble_gap_rx_conn_complete(&conn_evt, 0); + TEST_ASSERT(rc == 0); + + ble_hs_test_util_connect(BLE_OWN_ADDR_PUBLIC, + &addr2, 0, NULL, ble_gap_terminate_cb, + &disconn_handle, 0); + /* ble_gap_rx_conn_complete() will send extra HCI command, need phony ack */ + ble_hs_test_util_hci_ack_set(ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_RD_REM_FEAT), 0); + memset(&conn_evt, 0, sizeof conn_evt); + conn_evt.status = BLE_ERR_SUCCESS; + conn_evt.connection_handle = 2; + memcpy(conn_evt.peer_addr, addr2.val, 6); + rc = ble_gap_rx_conn_complete(&conn_evt, 0); + TEST_ASSERT(rc == 0); + + TEST_ASSERT_FATAL(ble_os_test_misc_conn_exists(1)); + TEST_ASSERT_FATAL(ble_os_test_misc_conn_exists(2)); + + /* Terminate the first one. */ + rc = ble_hs_test_util_conn_terminate(1, 0); + TEST_ASSERT(rc == 0); + ble_hs_test_util_hci_rx_disconn_complete_event(1, 0, BLE_ERR_REM_USER_CONN_TERM); + TEST_ASSERT(ble_os_test_gap_event_type == BLE_GAP_EVENT_DISCONNECT); + TEST_ASSERT(disconn_handle == 1); + TEST_ASSERT_FATAL(!ble_os_test_misc_conn_exists(1)); + TEST_ASSERT_FATAL(ble_os_test_misc_conn_exists(2)); + + /* Terminate the second one. */ + rc = ble_hs_test_util_conn_terminate(2, 0); + TEST_ASSERT(rc == 0); + ble_hs_test_util_hci_rx_disconn_complete_event(2, 0, BLE_ERR_REM_USER_CONN_TERM); + TEST_ASSERT(ble_os_test_gap_event_type == BLE_GAP_EVENT_DISCONNECT); + TEST_ASSERT(disconn_handle == 2); + TEST_ASSERT_FATAL(!ble_os_test_misc_conn_exists(1)); + TEST_ASSERT_FATAL(!ble_os_test_misc_conn_exists(2)); + + tu_restart(); +} + +static void +ble_os_test_app_task_handler(void *arg) +{ + while (1) { + os_eventq_run(os_eventq_dflt_get()); + } +} + +TEST_CASE_SELF(ble_gap_terminate_test_case) +{ + ble_os_test_misc_init(); + + os_task_init(&ble_os_test_task, + "ble_gap_terminate_test_task", + ble_gap_terminate_test_task_handler, NULL, + BLE_OS_TEST_TASK_PRIO, OS_WAIT_FOREVER, ble_os_test_stack, + OS_STACK_ALIGN(BLE_OS_TEST_STACK_SIZE)); + + os_start(); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_os_test_suite) +{ + ble_os_disc_test_case(); + ble_gap_direct_connect_test_case(); + ble_gap_terminate_test_case(); +} diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_sm_lgcy_test.c b/src/libs/mynewt-nimble/nimble/host/test/src/ble_sm_lgcy_test.c new file mode 100644 index 00000000..4529d362 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_sm_lgcy_test.c @@ -0,0 +1,849 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include "testutil/testutil.h" +#include "nimble/hci_common.h" +#include "nimble/nimble_opt.h" +#include "host/ble_sm.h" +#include "ble_hs_test.h" +#include "ble_hs_test_util.h" +#include "ble_sm_test_util.h" + +#if NIMBLE_BLE_SM + +/** + * Legacy pairing + * Master: peer + * Pair algorithm: just works + * Initiator IO capabilities: 4 + * Responder IO capabilities: 3 + * Bonding: true + * Initiator address type: BLE_ADDR_PUBLIC + * Responder address type: BLE_ADDR_PUBLIC + * Initiator key distribution: 7 + * Responder key distribution: 7 + */ +TEST_CASE_SELF(ble_sm_lgcy_peer_jw_iio4_rio3_b1_iat0_rat0_ik7_rk7) +{ + struct ble_sm_test_params params; + + params = (struct ble_sm_test_params) { + .init_id_addr = { + 0xe1, 0xfc, 0xda, 0xf4, 0xb7, 0x6c, + }, + .resp_id_addr = { + 0x33, 0x22, 0x11, 0x00, 0x45, 0x0a, + }, + .pair_req = { + .io_cap = 0x04, + .oob_data_flag = 0x00, + .authreq = 0x05, + .max_enc_key_size = 0x10, + .init_key_dist = 0x07, + .resp_key_dist = 0x07, + }, + .pair_rsp = { + .io_cap = 0x03, + .oob_data_flag = 0x00, + .authreq = 0x09, + .max_enc_key_size = 0x10, + .init_key_dist = 0x07, + .resp_key_dist = 0x07, + }, + .confirm_req[0] = { + .value = { + 0xcd, 0x5b, 0x79, 0x29, 0x53, 0x31, 0x56, 0x23, + 0x2c, 0x08, 0xed, 0x81, 0x16, 0x55, 0x8e, 0x01, + }, + }, + .confirm_rsp[0] = { + .value = { + 0x49, 0x39, 0x22, 0x0f, 0x7b, 0x1b, 0x80, 0xcd, + 0xbe, 0x89, 0xd1, 0x4c, 0xbd, 0x6f, 0xda, 0x2c, + }, + }, + .random_req[0] = { + .value = { + 0x7f, 0x42, 0xc0, 0x2f, 0x1d, 0x07, 0x37, 0xfc, + 0x04, 0x5b, 0x05, 0x9a, 0xed, 0x67, 0xa5, 0x68, + }, + }, + .random_rsp[0] = { + .value = { + 0x42, 0x1a, 0x58, 0xa2, 0x3b, 0x80, 0xde, 0xef, + 0x95, 0x0d, 0xf7, 0xca, 0x06, 0x05, 0x01, 0x3c, + }, + }, + .enc_info_req = { + .ltk = { + 0x2f, 0x9b, 0x16, 0xff, 0xf3, 0x73, 0x30, 0x08, + 0xa8, 0xe5, 0x01, 0xb1, 0x3b, 0xe1, 0x87, 0x00, + }, + }, + .master_id_req = { + .ediv = 0xf8e0, + .rand_val = 0xef7c818b00000000, + }, + .id_info_req = { + .irk = { + 0xef, 0x8d, 0xe2, 0x16, 0x4f, 0xec, 0x43, 0x0d, + 0xbf, 0x5b, 0xdd, 0x34, 0xc0, 0x53, 0x1e, 0xb8, + }, + }, + .id_addr_info_req = { + .addr_type = 0, + .bd_addr = { + 0x33, 0x22, 0x11, 0x00, 0x45, 0x0a, + }, + }, + .sign_info_req = { + .sig_key = { + 0xc6, 0x17, 0xc0, 0x02, 0x40, 0x0d, 0x27, 0x51, + 0x8a, 0x77, 0xb5, 0xae, 0xd8, 0xa9, 0x7a, 0x7a, + }, + }, + .enc_info_rsp = { + .ltk = { + 0xd7, 0x07, 0x22, 0x79, 0x24, 0xc6, 0xcb, 0x4d, + 0xa3, 0xdd, 0x01, 0xfb, 0x48, 0x87, 0xd4, 0xcf, + }, + }, + .master_id_rsp = { + .ediv = 0x9a39, + .rand_val = 0x8e76d9b00000000, + }, + .id_info_rsp = { + .irk = { + 0xeb, 0x8a, 0x06, 0xc4, 0x93, 0x51, 0x04, 0xb3, + 0x8b, 0xbf, 0xe8, 0x1f, 0x0e, 0x96, 0x2a, 0x54, + }, + }, + .id_addr_info_rsp = { + .addr_type = 0, + .bd_addr = { + 0xe1, 0xfc, 0xda, 0xf4, 0xb7, 0x6c, + }, + }, + .sign_info_rsp = { + .sig_key = { + 0x14, 0x55, 0x93, 0xe1, 0xd1, 0xe7, 0xc4, 0x5d, + 0x35, 0x97, 0xd3, 0x05, 0x30, 0xc8, 0x9d, 0x83, + }, + }, + .stk = { + 0x1c, 0xd7, 0xb6, 0x35, 0x48, 0xfc, 0x9f, 0xef, + 0x0e, 0x2f, 0x51, 0x77, 0xed, 0xdd, 0xbc, 0xaf, + }, + .pair_alg = 0, + .authenticated = false, + .passkey_info = { + .passkey = { + .action = BLE_SM_IOACT_NONE, + }, + }, + }; + ble_sm_test_util_peer_lgcy_good(¶ms); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +/** + * Legacy pairing + * Master: peer + * Pair algorithm: passkey entry + * Initiator IO capabilities: 4 + * Responder IO capabilities: 0 + * Bonding: true + * Initiator address type: BLE_ADDR_PUBLIC + * Responder address type: BLE_ADDR_PUBLIC + * Initiator key distribution: 7 + * Responder key distribution: 7 + */ +TEST_CASE_SELF(ble_sm_lgcy_peer_pk_iio4_rio0_b1_iat0_rat0_ik7_rk7) +{ + struct ble_sm_test_params params; + + params = (struct ble_sm_test_params) { + .init_id_addr = { + 0xe1, 0xfc, 0xda, 0xf4, 0xb7, 0x6c, + }, + .resp_id_addr = { + 0x33, 0x22, 0x11, 0x00, 0x45, 0x0a, + }, + .pair_req = { + .io_cap = 0x04, + .oob_data_flag = 0x00, + .authreq = 0x05, + .max_enc_key_size = 0x10, + .init_key_dist = 0x07, + .resp_key_dist = 0x07, + }, + .pair_rsp = { + .io_cap = 0x00, + .oob_data_flag = 0x00, + .authreq = 0x09, + .max_enc_key_size = 0x10, + .init_key_dist = 0x07, + .resp_key_dist = 0x07, + }, + .confirm_req[0] = { + .value = { + 0xa0, 0x10, 0x4a, 0xaa, 0x8b, 0x53, 0x78, 0xbb, + 0xd2, 0xae, 0x71, 0x1f, 0x4e, 0x00, 0x70, 0x8b, + }, + }, + .confirm_rsp[0] = { + .value = { + 0x62, 0xf3, 0xba, 0x0e, 0xe5, 0xbe, 0x2e, 0xd8, + 0x25, 0xb2, 0xec, 0x4c, 0x28, 0x77, 0x28, 0x60, + }, + }, + .random_req[0] = { + .value = { + 0x84, 0xcf, 0xe4, 0x04, 0x7d, 0xf3, 0xfc, 0xa1, + 0x3f, 0x75, 0xd6, 0x5a, 0x7c, 0xb7, 0xa4, 0x39, + }, + }, + .random_rsp[0] = { + .value = { + 0xef, 0x6a, 0x61, 0x6e, 0x02, 0x60, 0x7f, 0x5d, + 0x7f, 0x0d, 0xa6, 0x3c, 0x06, 0x1a, 0x5d, 0xd6, + }, + }, + .enc_info_req = { + .ltk = { + 0xad, 0x01, 0x6d, 0x76, 0xa9, 0xd0, 0x23, 0xc9, + 0x40, 0x0c, 0xbf, 0x2a, 0x4c, 0x23, 0x31, 0xc5, + }, + }, + .master_id_req = { + .ediv = 0xa74f, + .rand_val = 0x81cab3fd00000000, + }, + .id_info_req = { + .irk = { + 0xef, 0x8d, 0xe2, 0x16, 0x4f, 0xec, 0x43, 0x0d, + 0xbf, 0x5b, 0xdd, 0x34, 0xc0, 0x53, 0x1e, 0xb8, + }, + }, + .id_addr_info_req = { + .addr_type = 0, + .bd_addr = { + 0x33, 0x22, 0x11, 0x00, 0x45, 0x0a, + }, + }, + .sign_info_req = { + .sig_key = { + 0x60, 0x08, 0x49, 0x00, 0x6d, 0x76, 0x98, 0x73, + 0x9c, 0x95, 0xc4, 0xd9, 0xe8, 0x3a, 0x69, 0xbb, + }, + }, + .enc_info_rsp = { + .ltk = { + 0x5b, 0x73, 0x39, 0xd9, 0x51, 0x3d, 0x92, 0xa4, + 0x34, 0x65, 0xa5, 0x70, 0x49, 0xbe, 0x11, 0x28, + }, + }, + .master_id_rsp = { + .ediv = 0x9705, + .rand_val = 0x592f1e8d00000000, + }, + .id_info_rsp = { + .irk = { + 0xeb, 0x8a, 0x06, 0xc4, 0x93, 0x51, 0x04, 0xb3, + 0x8b, 0xbf, 0xe8, 0x1f, 0x0e, 0x96, 0x2a, 0x54, + }, + }, + .id_addr_info_rsp = { + .addr_type = 0, + .bd_addr = { + 0xe1, 0xfc, 0xda, 0xf4, 0xb7, 0x6c, + }, + }, + .sign_info_rsp = { + .sig_key = { + 0xc9, 0x9b, 0xf2, 0x75, 0xb7, 0x0d, 0xe8, 0x60, + 0x3d, 0xf0, 0xd6, 0xa8, 0x16, 0xc5, 0x6c, 0x2a, + }, + }, + .stk = { + 0xf2, 0x3c, 0x36, 0xc4, 0xa1, 0xfb, 0x5a, 0xa7, + 0x96, 0x20, 0xe4, 0x29, 0xb7, 0x58, 0x22, 0x7a, + }, + .pair_alg = 1, + .authenticated = true, + .passkey_info = { + .passkey = { + .action = BLE_SM_IOACT_DISP, + .passkey = 46128, + }, + }, + }; + ble_sm_test_util_peer_lgcy_good(¶ms); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +/** + * Legacy pairing + * Master: us + * Pair algorithm: just works + * Initiator IO capabilities: 3 + * Responder IO capabilities: 3 + * Bonding: true + * Initiator address type: BLE_ADDR_PUBLIC + * Responder address type: BLE_ADDR_RANDOM + * Initiator key distribution: 7 + * Responder key distribution: 5 + */ +TEST_CASE_SELF(ble_sm_lgcy_us_jw_iio3_rio3_b1_iat0_rat1_ik7_rk5) +{ + struct ble_sm_test_params params; + + params = (struct ble_sm_test_params) { + .init_id_addr = { + 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, + }, + .resp_addr_type = BLE_ADDR_RANDOM, + .resp_id_addr = { + 0x11, 0x22, 0x11, 0x22, 0x11, 0xcc, + }, + .pair_req = { + .io_cap = 0x03, + .oob_data_flag = 0x00, + .authreq = 0x01, + .max_enc_key_size = 0x10, + .init_key_dist = 0x07, + .resp_key_dist = 0x07, + }, + .pair_rsp = { + .io_cap = 0x03, + .oob_data_flag = 0x00, + .authreq = 0x01, + .max_enc_key_size = 0x10, + .init_key_dist = 0x07, + .resp_key_dist = 0x05, + }, + .confirm_req[0] = { + .value = { + 0x1c, 0xb6, 0x10, 0xea, 0x02, 0x08, 0x90, 0x64, + 0xc7, 0xf8, 0xe5, 0x9c, 0xb4, 0x3a, 0x18, 0xca, + }, + }, + .confirm_rsp[0] = { + .value = { + 0xb8, 0x6f, 0xd1, 0xc6, 0x74, 0x35, 0xa3, 0x94, + 0x68, 0x2f, 0xf1, 0x4c, 0x78, 0x44, 0xe8, 0x0d, + }, + }, + .random_req[0] = { + .value = { + 0x40, 0x48, 0x17, 0x4d, 0x42, 0xa0, 0xf8, 0xd5, + 0xbf, 0x65, 0x67, 0xb8, 0x5e, 0x57, 0x38, 0xac, + }, + }, + .random_rsp[0] = { + .value = { + 0x2c, 0xa1, 0xb1, 0xf5, 0x54, 0x9b, 0x43, 0xe9, + 0xb0, 0x62, 0x6a, 0xb0, 0x02, 0xb8, 0x6c, 0xca, + }, + }, + .enc_info_req = { + .ltk = { + 0x01, 0x15, 0xb6, 0x93, 0xc9, 0xff, 0xfe, 0x27, + 0x02, 0x41, 0xfd, 0x7b, 0x0e, 0x31, 0xd4, 0xa6, + }, + }, + .master_id_req = { + .ediv = 0xe4fb, + .rand_val = 0x8eee76b100000000, + }, + .sign_info_req = { + .sig_key = { + 0x00, 0x2d, 0xf6, 0x3e, 0x5e, 0x0f, 0xd1, 0xe8, + 0x4e, 0x5f, 0x61, 0x1c, 0x2c, 0x0b, 0xa5, 0x51, + }, + }, + .enc_info_rsp = { + .ltk = { + 0x88, 0xbc, 0x95, 0x8d, 0xaa, 0x26, 0x8d, 0xd5, + 0x18, 0xc9, 0x06, 0x70, 0xc2, 0x30, 0x56, 0x4c, + }, + }, + .master_id_rsp = { + .ediv = 0x4413, + .rand_val = 0xfad1c27300000000, + }, + .id_info_rsp = { + .irk = { + 0xef, 0x8d, 0xe2, 0x16, 0x4f, 0xec, 0x43, 0x0d, + 0xbf, 0x5b, 0xdd, 0x34, 0xc0, 0x53, 0x1e, 0xb8, + }, + }, + .id_addr_info_rsp = { + .addr_type = 0, + .bd_addr = { + 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, + }, + }, + .sign_info_rsp = { + .sig_key = { + 0x03, 0xad, 0xa4, 0xe1, 0x34, 0x76, 0x95, 0x54, + 0xe5, 0x8f, 0xa4, 0x06, 0x72, 0xe6, 0xfc, 0x65, + }, + }, + .stk = { + 0x31, 0x54, 0x42, 0x6c, 0x1c, 0x03, 0x36, 0x44, + 0x0b, 0x72, 0x90, 0xa5, 0x1f, 0x79, 0x5b, 0xe9, + }, + .pair_alg = 0, + .authenticated = false, + .passkey_info = { + .passkey = { + .action = BLE_SM_IOACT_NONE, + }, + }, + }; + ble_sm_test_util_us_lgcy_good(¶ms); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +/** + * Legacy pairing + * Master: us + * Pair algorithm: passkey entry + * Initiator IO capabilities: 4 + * Responder IO capabilities: 2 + * Bonding: true + * Initiator address type: BLE_ADDR_PUBLIC + * Responder address type: BLE_ADDR_RANDOM + * Initiator key distribution: 7 + * Responder key distribution: 5 + */ +TEST_CASE_SELF(ble_sm_lgcy_us_pk_iio4_rio2_b1_iat0_rat1_ik7_rk5) +{ + struct ble_sm_test_params params; + + params = (struct ble_sm_test_params) { + .init_id_addr = { + 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, + }, + .resp_addr_type = BLE_ADDR_RANDOM, + .resp_id_addr = { + 0x11, 0x22, 0x11, 0x22, 0x11, 0xcc, + }, + .pair_req = { + .io_cap = 0x04, + .oob_data_flag = 0x00, + .authreq = 0x0d, + .max_enc_key_size = 0x10, + .init_key_dist = 0x07, + .resp_key_dist = 0x07, + }, + .pair_rsp = { + .io_cap = 0x02, + .oob_data_flag = 0x00, + .authreq = 0x05, + .max_enc_key_size = 0x10, + .init_key_dist = 0x07, + .resp_key_dist = 0x05, + }, + .confirm_req[0] = { + .value = { + 0xb5, 0xd4, 0xc5, 0xe8, 0xef, 0xef, 0xd8, 0xd7, + 0x2b, 0x14, 0x34, 0x35, 0x29, 0x18, 0xda, 0x12, + }, + }, + .confirm_rsp[0] = { + .value = { + 0x1a, 0x03, 0x20, 0xda, 0x60, 0x21, 0x9b, 0x4b, + 0x5d, 0x45, 0x90, 0x64, 0xe1, 0x24, 0x2c, 0xb6, + }, + }, + .random_req[0] = { + .value = { + 0x45, 0xa3, 0x1a, 0x0b, 0xf6, 0x0f, 0x7c, 0xcf, + 0x1a, 0xfb, 0xfc, 0x1a, 0xad, 0x62, 0x0e, 0x76, + }, + }, + .random_rsp[0] = { + .value = { + 0x82, 0xbb, 0x9f, 0x67, 0xc4, 0x88, 0xcb, 0x58, + 0xee, 0xf9, 0x34, 0x35, 0x23, 0xa3, 0xd0, 0x22, + }, + }, + .enc_info_req = { + .ltk = { + 0xfa, 0x43, 0x8f, 0x1f, 0xe6, 0x2a, 0x94, 0x5b, + 0x54, 0x89, 0x2b, 0x0f, 0xd7, 0x23, 0x77, 0x9e, + }, + }, + .master_id_req = { + .ediv = 0x88b3, + .rand_val = 0x7c970e18dec74560, + }, + .sign_info_req = { + .sig_key = { + 0x2e, 0x70, 0x3c, 0xbf, 0x20, 0xbe, 0x7d, 0x2d, + 0xb3, 0x50, 0x46, 0x33, 0x4c, 0x20, 0x0e, 0xc8, + }, + }, + .enc_info_rsp = { + .ltk = { + 0xc1, 0x64, 0x33, 0x10, 0x0f, 0x70, 0x2f, 0x9c, + 0xe7, 0x31, 0xc5, 0x32, 0xdd, 0x98, 0x16, 0x75, + }, + }, + .master_id_rsp = { + .ediv = 0x1c19, + .rand_val = 0xef308872dc2a4cc2, + }, + .id_info_rsp = { + .irk = { + 0xef, 0x8d, 0xe2, 0x16, 0x4f, 0xec, 0x43, 0x0d, + 0xbf, 0x5b, 0xdd, 0x34, 0xc0, 0x53, 0x1e, 0xb8, + }, + }, + .id_addr_info_rsp = { + .addr_type = 0, + .bd_addr = { + 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, + }, + }, + .sign_info_rsp = { + .sig_key = { + 0xd7, 0x75, 0xfa, 0xed, 0xd7, 0xdd, 0x7b, 0xb3, + 0xa4, 0x20, 0xea, 0x2f, 0x75, 0x60, 0xb1, 0x84, + }, + }, + .stk = { + 0x9e, 0xe8, 0x35, 0x22, 0xb6, 0xbb, 0x54, 0x0d, + 0x48, 0x1b, 0x25, 0xa0, 0xd8, 0xe2, 0xa5, 0x08, + }, + .pair_alg = 1, + .authenticated = true, + .passkey_info = { + .passkey = { + .action = BLE_SM_IOACT_DISP, + .passkey = 46128, + }, + }, + }; + ble_sm_test_util_us_lgcy_good(¶ms); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +/** + * Legacy pairing + * Master: us + * Pair algorithm: out of band + * Initiator IO capabilities: 3 + * Responder IO capabilities: 3 + * Bonding: true + * Initiator address type: BLE_ADDR_PUBLIC + * Responder address type: BLE_ADDR_PUBLIC + * Initiator key distribution: 7 + * Responder key distribution: 7 + */ +TEST_CASE_SELF(ble_sm_lgcy_us_ob_iio3_rio3_b1_iat0_rat0_ik7_rk7) +{ + struct ble_sm_test_params params; + + params = (struct ble_sm_test_params) { + .init_id_addr = { + 0x01, 0x01, 0x01, 0x07, 0x08, 0x01, + }, + .resp_id_addr = { + 0x66, 0x33, 0x22, 0x66, 0x55, 0x11, + }, + .pair_req = { + .io_cap = 0x03, + .oob_data_flag = 0x01, + .authreq = 0x05, + .max_enc_key_size = 0x10, + .init_key_dist = 0x07, + .resp_key_dist = 0x07, + }, + .pair_rsp = { + .io_cap = 0x03, + .oob_data_flag = 0x01, + .authreq = 0x05, + .max_enc_key_size = 0x10, + .init_key_dist = 0x07, + .resp_key_dist = 0x07, + }, + .confirm_req[0] = { + .value = { + 0x2c, 0x3f, 0x3e, 0xf5, 0x39, 0x50, 0x78, 0x4a, + 0x3e, 0x14, 0x1a, 0x51, 0xfb, 0x8d, 0x6c, 0x10, + }, + }, + .confirm_rsp[0] = { + .value = { + 0xa9, 0x5c, 0x18, 0xb1, 0xdb, 0x51, 0x53, 0xa5, + 0xd3, 0xe7, 0x72, 0x17, 0xfb, 0xa8, 0xfb, 0xeb, + }, + }, + .random_req[0] = { + .value = { + 0x40, 0x2f, 0x42, 0xba, 0x10, 0x7b, 0x22, 0x65, + 0x84, 0xef, 0x63, 0xdf, 0x84, 0x7b, 0x04, 0xef, + }, + }, + .random_rsp[0] = { + .value = { + 0x94, 0xdc, 0x3c, 0xef, 0x65, 0xf7, 0x99, 0x2e, + 0x50, 0x29, 0x97, 0x2a, 0x57, 0xfd, 0xe6, 0x6a, + }, + }, + .enc_info_req = { + .ltk = { + 0x8c, 0x8e, 0x57, 0xba, 0x17, 0xbb, 0x04, 0xb5, + 0x16, 0xad, 0x31, 0x37, 0xf8, 0x3e, 0x4f, 0x21, + }, + }, + .master_id_req = { + .ediv = 0xaaa4, + .rand_val = 0xc0c830e300000000, + }, + .id_info_req = { + .irk = { + 0xef, 0x8d, 0xe2, 0x16, 0x4f, 0xec, 0x43, 0x0d, + 0xbf, 0x5b, 0xdd, 0x34, 0xc0, 0x53, 0x1e, 0xb8, + }, + }, + .id_addr_info_req = { + .addr_type = 0, + .bd_addr = { + 0x66, 0x33, 0x22, 0x66, 0x55, 0x11, + }, + }, + .sign_info_req = { + .sig_key = { + 0x5a, 0xe4, 0x2b, 0x40, 0x3a, 0x34, 0x1d, 0x94, + 0x56, 0x7d, 0xf4, 0x41, 0x23, 0x81, 0xc4, 0x11, + }, + }, + .enc_info_rsp = { + .ltk = { + 0xa6, 0x8e, 0xa0, 0xa4, 0x02, 0x64, 0x4c, 0x09, + 0x31, 0x25, 0x8a, 0x4f, 0x49, 0x35, 0xb0, 0x1f, + }, + }, + .master_id_rsp = { + .ediv = 0x57a3, + .rand_val = 0x8276af9000000000, + }, + .id_info_rsp = { + .irk = { + 0xef, 0x8d, 0xe2, 0x16, 0x4f, 0xec, 0x43, 0x0d, + 0xbf, 0x5b, 0xdd, 0x34, 0xc0, 0x53, 0x1e, 0xb8, + }, + }, + .id_addr_info_rsp = { + .addr_type = 0, + .bd_addr = { + 0x01, 0x01, 0x01, 0x07, 0x08, 0x01, + }, + }, + .sign_info_rsp = { + .sig_key = { + 0x8e, 0xef, 0x53, 0x5c, 0x1b, 0x21, 0x67, 0x8d, + 0x07, 0x5e, 0xaa, 0xe8, 0x41, 0xa9, 0x36, 0xcf, + }, + }, + .stk = { + 0x4c, 0xd4, 0xa7, 0xee, 0x83, 0xcd, 0xd1, 0x9e, + 0x84, 0xeb, 0xb8, 0xd2, 0xaf, 0x4a, 0x71, 0x2e, + }, + .pair_alg = 2, + .authenticated = 1, + .passkey_info = { + .passkey = { + .action = BLE_SM_IOACT_OOB, + .oob = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, + }, + }, + }, + }; + ble_sm_test_util_us_lgcy_good(¶ms); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +/** + * Legacy pairing + * Master: peer + * Pair algorithm: passkey entry + * Initiator IO capabilities: 4 + * Responder IO capabilities: 4 + * Bonding: true + * Initiator address type: BLE_ADDR_PUBLIC + * Responder address type: BLE_ADDR_PUBLIC + * Initiator key distribution: 7 + * Responder key distribution: 7 + */ +TEST_CASE_SELF(ble_sm_lgcy_peer_pk_iio4_rio4_b1_iat0_rat0_ik7_rk7) +{ + struct ble_sm_test_params params; + + params = (struct ble_sm_test_params) { + .init_id_addr = { + 0xe1, 0xfc, 0xda, 0xf4, 0xb7, 0x6c, + }, + .resp_id_addr = { + 0x33, 0x22, 0x11, 0x00, 0x45, 0x0a, + }, + .pair_req = { + .io_cap = 0x04, + .oob_data_flag = 0x00, + .authreq = 0x05, + .max_enc_key_size = 0x10, + .init_key_dist = 0x07, + .resp_key_dist = 0x07, + }, + .pair_rsp = { + .io_cap = 0x04, + .oob_data_flag = 0x00, + .authreq = 0x0d, + .max_enc_key_size = 0x10, + .init_key_dist = 0x07, + .resp_key_dist = 0x07, + }, + .confirm_req[0] = { + .value = { + 0x93, 0x64, 0xb1, 0xb0, 0x07, 0x41, 0x22, 0xe7, + 0x3e, 0x5a, 0x87, 0xf5, 0x1f, 0x25, 0x79, 0x11, + }, + }, + .confirm_rsp[0] = { + .value = { + 0x2d, 0x40, 0x15, 0xc4, 0x21, 0xeb, 0xd5, 0x73, + 0xc8, 0x5d, 0xb8, 0xb9, 0x45, 0x31, 0xd5, 0x58, + }, + }, + .random_req[0] = { + .value = { + 0x8c, 0x2c, 0x3b, 0xf3, 0x90, 0xaa, 0x2e, 0xcf, + 0xc7, 0x5b, 0xf6, 0xae, 0xb6, 0x4c, 0xc3, 0x61, + }, + }, + .random_rsp[0] = { + .value = { + 0x7a, 0x94, 0x97, 0x0a, 0xbe, 0xaf, 0xc0, 0x6b, + 0xd4, 0xf4, 0x04, 0xd1, 0x21, 0x46, 0x34, 0xf3, + }, + }, + .enc_info_req = { + .ltk = { + 0x3a, 0x10, 0xd1, 0xab, 0x13, 0xee, 0x16, 0xee, + 0xcf, 0xae, 0xf1, 0x63, 0xf0, 0x6f, 0xb0, 0x89, + }, + }, + .master_id_req = { + .ediv = 0xb634, + .rand_val = 0xa99ac2007b4278a8, + }, + .id_info_req = { + .irk = { + 0xef, 0x8d, 0xe2, 0x16, 0x4f, 0xec, 0x43, 0x0d, + 0xbf, 0x5b, 0xdd, 0x34, 0xc0, 0x53, 0x1e, 0xb8, + }, + }, + .id_addr_info_req = { + .addr_type = 0, + .bd_addr = { + 0x33, 0x22, 0x11, 0x00, 0x45, 0x0a, + }, + }, + .sign_info_req = { + .sig_key = { + 0x51, 0x4b, 0x7b, 0x31, 0xf7, 0xa6, 0x8a, 0x60, + 0x4f, 0x10, 0x04, 0x5f, 0xb8, 0xee, 0xf6, 0xb3, + }, + }, + .enc_info_rsp = { + .ltk = { + 0xa1, 0x1d, 0xdd, 0xee, 0x85, 0xcb, 0xe0, 0x48, + 0x1e, 0xdd, 0xa4, 0x9d, 0xed, 0x3f, 0x15, 0x17, + }, + }, + .master_id_rsp = { + .ediv = 0x7e06, + .rand_val = 0xe6077f688c5ca67, + }, + .id_info_rsp = { + .irk = { + 0xeb, 0x8a, 0x06, 0xc4, 0x93, 0x51, 0x04, 0xb3, + 0x8b, 0xbf, 0xe8, 0x1f, 0x0e, 0x96, 0x2a, 0x54, + }, + }, + .id_addr_info_rsp = { + .addr_type = 0, + .bd_addr = { + 0xe1, 0xfc, 0xda, 0xf4, 0xb7, 0x6c, + }, + }, + .sign_info_rsp = { + .sig_key = { + 0x16, 0x7a, 0x2e, 0x9d, 0x43, 0x4d, 0x7b, 0x0b, + 0x88, 0xe2, 0x11, 0xb0, 0x4d, 0xa1, 0xed, 0x08, + }, + }, + .stk = { + 0x6c, 0x3e, 0x78, 0x47, 0xe8, 0x57, 0x9f, 0xe9, + 0x3a, 0x8f, 0x0a, 0xbb, 0xd4, 0x60, 0xf6, 0x0d, + }, + .pair_alg = 1, + .authenticated = true, + .passkey_info = { + .passkey = { + .action = BLE_SM_IOACT_INPUT, + .passkey = 449182, + }, + }, + }; + ble_sm_test_util_peer_lgcy_good(¶ms); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_sm_lgcy_test_suite) +{ + /*** No privacy. */ + + /* Peer as initiator. */ + ble_sm_lgcy_peer_jw_iio4_rio3_b1_iat0_rat0_ik7_rk7(); + ble_sm_lgcy_peer_pk_iio4_rio0_b1_iat0_rat0_ik7_rk7(); + ble_sm_lgcy_peer_pk_iio4_rio4_b1_iat0_rat0_ik7_rk7(); + + /* Us as initiator. */ + ble_sm_lgcy_us_jw_iio3_rio3_b1_iat0_rat1_ik7_rk5(); + ble_sm_lgcy_us_pk_iio4_rio2_b1_iat0_rat1_ik7_rk5(); + ble_sm_lgcy_us_ob_iio3_rio3_b1_iat0_rat0_ik7_rk7(); +} + +#endif diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_sm_sc_test.c b/src/libs/mynewt-nimble/nimble/host/test/src/ble_sm_sc_test.c new file mode 100644 index 00000000..c3d19550 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_sm_sc_test.c @@ -0,0 +1,4938 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include "testutil/testutil.h" +#include "nimble/hci_common.h" +#include "nimble/nimble_opt.h" +#include "host/ble_sm.h" +#include "ble_hs_test.h" +#include "ble_hs_test_util.h" +#include "ble_sm_test_util.h" + +#if NIMBLE_BLE_SM + +/** + * Secure connections pairing + * Master: peer + * Pair algorithm: just works + * Initiator IO capabilities: 3 + * Responder IO capabilities: 3 + * Bonding: true + * Initiator address type: 0 + * Responder address type: 0 + * Initiator key distribution: 5 + * Responder key distribution: 7 + */ +TEST_CASE_SELF(ble_sm_sc_peer_jw_iio3_rio3_b1_iat0_rat0_ik5_rk7) +{ + struct ble_sm_test_params params; + + params = (struct ble_sm_test_params) { + .init_id_addr = { + 0xca, 0x61, 0xa0, 0x67, 0x94, 0xe0, + }, + .resp_id_addr = { + 0x33, 0x22, 0x11, 0x00, 0x45, 0x0a, + }, + .pair_req = { + .io_cap = 0x03, + .oob_data_flag = 0x00, + .authreq = 0x09, + .max_enc_key_size = 0x10, + .init_key_dist = 0x0d, + .resp_key_dist = 0x0f, + }, + .pair_rsp = { + .io_cap = 0x03, + .oob_data_flag = 0x00, + .authreq = 0x09, + .max_enc_key_size = 0x10, + .init_key_dist = 0x05, + .resp_key_dist = 0x07, + }, + .our_priv_key = { + 0x54, 0x8d, 0x20, 0xb8, 0x97, 0x0b, 0xbc, 0x43, + 0x9a, 0xad, 0x10, 0x6f, 0x60, 0x74, 0xd4, 0x6a, + 0x55, 0xc1, 0x7a, 0x17, 0x8b, 0x60, 0xe0, 0xb4, + 0x5a, 0xe6, 0x58, 0xf1, 0xea, 0x12, 0xd9, 0xfb, + }, + .public_key_req = { + .x = { + 0xbc, 0xf2, 0xd8, 0xa5, 0xdb, 0xa3, 0x95, 0x6c, + 0x99, 0xf9, 0x11, 0x0d, 0x4d, 0x2e, 0xf0, 0xbd, + 0xee, 0x9b, 0x69, 0xb6, 0xcd, 0x88, 0x74, 0xbe, + 0x40, 0xe8, 0xe5, 0xcc, 0xdc, 0x88, 0x44, 0x53, + }, + .y = { + 0xbf, 0xa9, 0x82, 0x0e, 0x18, 0x7a, 0x14, 0xf8, + 0x77, 0xfd, 0x8e, 0x92, 0x2a, 0xf8, 0x5d, 0x39, + 0xd1, 0x6d, 0x92, 0x1f, 0x38, 0x74, 0x99, 0xdc, + 0x6c, 0x2c, 0x94, 0x23, 0xf9, 0x72, 0x56, 0xab, + }, + }, + .public_key_rsp = { + .x = { + 0x72, 0x8c, 0xd1, 0x88, 0xd7, 0xbe, 0x49, 0xb2, + 0xc5, 0x5c, 0x95, 0xb3, 0x64, 0xe0, 0x12, 0x32, + 0xb6, 0xc9, 0x47, 0x63, 0x37, 0x38, 0x5b, 0x9c, + 0x1e, 0x1b, 0x1a, 0x06, 0x09, 0xe2, 0x31, 0x85, + }, + .y = { + 0x19, 0x3a, 0x29, 0x69, 0x62, 0xd6, 0x30, 0xe7, + 0xe8, 0x48, 0x63, 0xdc, 0x00, 0x73, 0x0a, 0x70, + 0x7d, 0x2e, 0x29, 0xcc, 0x91, 0x77, 0x71, 0xb1, + 0x75, 0xb8, 0xf7, 0xdc, 0xb0, 0xe2, 0x91, 0x10, + }, + }, + .confirm_rsp[0] = { + .value = { + 0x82, 0xed, 0xd0, 0x62, 0x91, 0x3d, 0x96, 0x7f, + 0x13, 0xc5, 0x0d, 0x02, 0x2b, 0x5e, 0x43, 0x16, + }, + }, + .random_req[0] = { + .value = { + 0xa4, 0x34, 0x5f, 0xb3, 0xaf, 0x73, 0x43, 0x64, + 0xcd, 0x19, 0x1b, 0x5b, 0x87, 0x58, 0x31, 0x66, + }, + }, + .random_rsp[0] = { + .value = { + 0xc0, 0x91, 0xfb, 0xb3, 0x77, 0xa2, 0x02, 0x0b, + 0xc6, 0xcd, 0x6c, 0x04, 0x51, 0x45, 0x45, 0x39, + }, + }, + .dhkey_check_req = { + .value = { + 0x82, 0x65, 0x1d, 0x02, 0xed, 0x89, 0x13, 0x44, + 0x04, 0x1a, 0x14, 0x7c, 0x32, 0x9a, 0x1e, 0x7d, + }, + }, + .dhkey_check_rsp = { + .value = { + 0x06, 0x3c, 0x28, 0x4a, 0xe5, 0x48, 0x4b, 0x51, + 0x65, 0x4e, 0x14, 0x5e, 0x2f, 0xdd, 0xfa, 0x22, + }, + }, + .id_info_req = { + .irk = { + 0xef, 0x8d, 0xe2, 0x16, 0x4f, 0xec, 0x43, 0x0d, + 0xbf, 0x5b, 0xdd, 0x34, 0xc0, 0x53, 0x1e, 0xb8, + }, + }, + .id_addr_info_req = { + .addr_type = 0, + .bd_addr = { + 0x33, 0x22, 0x11, 0x00, 0x45, 0x0a, + }, + }, + .sign_info_req = { + .sig_key = { + 0x40, 0x53, 0xeb, 0x7a, 0x4d, 0x8e, 0xa2, 0xb5, + 0xca, 0xa1, 0xb6, 0xae, 0x7e, 0x6a, 0x4d, 0xd9, + }, + }, + .sign_info_rsp = { + .sig_key = { + 0xbc, 0x13, 0x4b, 0x45, 0xda, 0x76, 0x5b, 0xcd, + 0xc2, 0x43, 0x81, 0xb8, 0xc3, 0x68, 0x12, 0xbb, + }, + }, + .ltk = { + 0x63, 0x59, 0x8a, 0x14, 0x09, 0x4b, 0x94, 0x6e, + 0xff, 0xae, 0x5e, 0x53, 0x86, 0x02, 0xa3, 0x6c, + }, + .pair_alg = BLE_SM_PAIR_ALG_JW, + .authenticated = 0, + .passkey_info = { + .passkey = { + .action = BLE_SM_IOACT_NONE, + }, + }, + }; + ble_sm_test_util_peer_sc_good(¶ms); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +/** + * Secure connections pairing + * Master: peer + * Pair algorithm: passkey entry + * Initiator IO capabilities: 0 + * Responder IO capabilities: 2 + * Bonding: true + * Initiator address type: 0 + * Responder address type: 0 + * Initiator key distribution: 5 + * Responder key distribution: 7 + */ +TEST_CASE_SELF(ble_sm_sc_peer_pk_iio0_rio2_b1_iat0_rat0_ik5_rk7) +{ + struct ble_sm_test_params params; + + params = (struct ble_sm_test_params) { + .init_id_addr = { + 0xca, 0x61, 0xa0, 0x67, 0x94, 0xe0, + }, + .resp_id_addr = { + 0x33, 0x22, 0x11, 0x00, 0x45, 0x0a, + }, + .pair_req = { + .io_cap = 0x00, + .oob_data_flag = 0x00, + .authreq = 0x0d, + .max_enc_key_size = 0x10, + .init_key_dist = 0x0d, + .resp_key_dist = 0x0f, + }, + .pair_rsp = { + .io_cap = 0x02, + .oob_data_flag = 0x00, + .authreq = 0x0d, + .max_enc_key_size = 0x10, + .init_key_dist = 0x05, + .resp_key_dist = 0x07, + }, + .our_priv_key = { + 0x54, 0x8d, 0x20, 0xb8, 0x97, 0x0b, 0xbc, 0x43, + 0x9a, 0xad, 0x10, 0x6f, 0x60, 0x74, 0xd4, 0x6a, + 0x55, 0xc1, 0x7a, 0x17, 0x8b, 0x60, 0xe0, 0xb4, + 0x5a, 0xe6, 0x58, 0xf1, 0xea, 0x12, 0xd9, 0xfb, + }, + .public_key_req = { + .x = { + 0x22, 0x26, 0xcc, 0x64, 0x4d, 0xc1, 0x01, 0xd1, + 0xb9, 0x8d, 0xe2, 0xd4, 0xbc, 0x55, 0x37, 0x4c, + 0x12, 0x81, 0x14, 0x83, 0x81, 0xe8, 0x36, 0x1b, + 0x78, 0xff, 0x49, 0xfc, 0xe9, 0x2e, 0x56, 0xc0, + }, + .y = { + 0xd9, 0x31, 0xa5, 0x8d, 0x02, 0xf1, 0x94, 0xb6, + 0x83, 0x97, 0xd1, 0xfb, 0x01, 0x97, 0x4d, 0x06, + 0xec, 0x18, 0x8d, 0x4a, 0xd2, 0x14, 0x12, 0x95, + 0x2d, 0x4d, 0x18, 0xde, 0x4d, 0xaa, 0x91, 0x25, + }, + }, + .public_key_rsp = { + .x = { + 0x72, 0x8c, 0xd1, 0x88, 0xd7, 0xbe, 0x49, 0xb2, + 0xc5, 0x5c, 0x95, 0xb3, 0x64, 0xe0, 0x12, 0x32, + 0xb6, 0xc9, 0x47, 0x63, 0x37, 0x38, 0x5b, 0x9c, + 0x1e, 0x1b, 0x1a, 0x06, 0x09, 0xe2, 0x31, 0x85, + }, + .y = { + 0x19, 0x3a, 0x29, 0x69, 0x62, 0xd6, 0x30, 0xe7, + 0xe8, 0x48, 0x63, 0xdc, 0x00, 0x73, 0x0a, 0x70, + 0x7d, 0x2e, 0x29, 0xcc, 0x91, 0x77, 0x71, 0xb1, + 0x75, 0xb8, 0xf7, 0xdc, 0xb0, 0xe2, 0x91, 0x10, + }, + }, + .confirm_req[0] = { + .value = { + 0x2c, 0x16, 0x15, 0x0d, 0xe8, 0x18, 0x50, 0xd8, + 0xae, 0x04, 0x6c, 0xa8, 0x50, 0xb8, 0xe5, 0x85, + }, + }, + .confirm_rsp[0] = { + .value = { + 0x62, 0x53, 0xfb, 0x69, 0x94, 0x33, 0x11, 0xd3, + 0x8e, 0x03, 0xd5, 0x05, 0xd7, 0x68, 0x33, 0x16, + }, + }, + .random_req[0] = { + .value = { + 0xd5, 0x0e, 0x27, 0xcf, 0xa4, 0xc1, 0x52, 0x1b, + 0xf1, 0x9d, 0x5f, 0xbe, 0xe2, 0xc0, 0x48, 0x38, + }, + }, + .random_rsp[0] = { + .value = { + 0x94, 0x31, 0x95, 0x44, 0x6c, 0xc5, 0x73, 0xc8, + 0x8d, 0x72, 0x06, 0xe7, 0xfd, 0x16, 0x70, 0x5d, + }, + }, + .confirm_req[1] = { + .value = { + 0x80, 0xae, 0x74, 0xaa, 0x9a, 0xfc, 0x09, 0x97, + 0x10, 0x01, 0x4e, 0xbb, 0x16, 0x36, 0x6b, 0xc7, + }, + }, + .confirm_rsp[1] = { + .value = { + 0x5a, 0xb1, 0xe5, 0x81, 0x5a, 0x1b, 0xef, 0xf4, + 0xa8, 0x3d, 0xaa, 0x3f, 0x02, 0x1f, 0x78, 0x55, + }, + }, + .random_req[1] = { + .value = { + 0x04, 0x4a, 0xf4, 0xd5, 0x4b, 0x4f, 0x77, 0x37, + 0x2a, 0x3c, 0xfe, 0x83, 0x34, 0x6b, 0x38, 0x1a, + }, + }, + .random_rsp[1] = { + .value = { + 0x24, 0xb3, 0x47, 0xc8, 0xb0, 0xa2, 0xa3, 0xd8, + 0x78, 0x3d, 0x09, 0x8d, 0xea, 0x49, 0xf6, 0x22, + }, + }, + .confirm_req[2] = { + .value = { + 0x56, 0x5f, 0x07, 0x30, 0x3a, 0xc1, 0x44, 0xf9, + 0x00, 0x03, 0xb3, 0x93, 0x58, 0xb4, 0x2c, 0x85, + }, + }, + .confirm_rsp[2] = { + .value = { + 0x50, 0x8a, 0xb3, 0x0b, 0xe4, 0x2e, 0xd3, 0x49, + 0x59, 0x40, 0xb2, 0x71, 0xc9, 0x49, 0x29, 0x19, + }, + }, + .random_req[2] = { + .value = { + 0x32, 0x37, 0x8e, 0x63, 0x6d, 0xbd, 0xd6, 0x18, + 0xee, 0xa7, 0x0e, 0xe5, 0x7e, 0x5f, 0xe1, 0x80, + }, + }, + .random_rsp[2] = { + .value = { + 0xa2, 0x1a, 0x92, 0xcd, 0xc0, 0x8f, 0x92, 0xb0, + 0xe6, 0xbe, 0x43, 0x55, 0xc8, 0x47, 0x56, 0x4b, + }, + }, + .confirm_req[3] = { + .value = { + 0x1b, 0xa0, 0x82, 0xda, 0xfc, 0xaf, 0x3f, 0x9c, + 0xdf, 0xff, 0xa2, 0x18, 0xba, 0xbd, 0x9b, 0x48, + }, + }, + .confirm_rsp[3] = { + .value = { + 0x6a, 0x90, 0xb7, 0x1c, 0x93, 0x4e, 0x4a, 0x8b, + 0xda, 0xe8, 0x13, 0x6e, 0x01, 0x91, 0x74, 0xb1, + }, + }, + .random_req[3] = { + .value = { + 0x41, 0xbf, 0x60, 0x64, 0x1d, 0xfc, 0xe2, 0xee, + 0x00, 0xa3, 0x2a, 0xb1, 0xf8, 0x34, 0x6b, 0xeb, + }, + }, + .random_rsp[3] = { + .value = { + 0xeb, 0x9c, 0xaf, 0x20, 0x14, 0x0f, 0xf2, 0x3e, + 0xee, 0x45, 0xca, 0xe8, 0xdc, 0x17, 0xab, 0x22, + }, + }, + .confirm_req[4] = { + .value = { + 0x75, 0x8f, 0x97, 0xbb, 0x87, 0xa8, 0x70, 0xda, + 0x94, 0x5a, 0xd6, 0x09, 0x78, 0xe3, 0xdd, 0x43, + }, + }, + .confirm_rsp[4] = { + .value = { + 0x8c, 0x2d, 0xa7, 0x44, 0xd9, 0x15, 0xa8, 0x9e, + 0xdf, 0x3a, 0x59, 0xa5, 0xee, 0x92, 0x24, 0x3c, + }, + }, + .random_req[4] = { + .value = { + 0xb9, 0xe0, 0xf3, 0xf6, 0x6f, 0xbd, 0xa0, 0x7a, + 0x82, 0x20, 0x61, 0xbe, 0xf3, 0xe6, 0x4e, 0xac, + }, + }, + .random_rsp[4] = { + .value = { + 0xdd, 0x9b, 0xd3, 0x10, 0xed, 0x12, 0xe8, 0xb5, + 0xa2, 0x59, 0xe1, 0xdc, 0x5c, 0xd8, 0x6e, 0x96, + }, + }, + .confirm_req[5] = { + .value = { + 0x9d, 0xc7, 0x97, 0x67, 0x8d, 0xd0, 0xd6, 0x1a, + 0x4d, 0x52, 0xc0, 0x8d, 0x87, 0xa9, 0x75, 0xf5, + }, + }, + .confirm_rsp[5] = { + .value = { + 0xd4, 0x5d, 0x61, 0x76, 0x38, 0xe3, 0x81, 0x85, + 0x18, 0x5f, 0xac, 0xde, 0x49, 0x57, 0xf6, 0x9b, + }, + }, + .random_req[5] = { + .value = { + 0xfe, 0x83, 0xe9, 0xc6, 0xe9, 0xa4, 0x83, 0x0d, + 0xaf, 0x27, 0x6f, 0x79, 0x7a, 0x2b, 0x2d, 0x1f, + }, + }, + .random_rsp[5] = { + .value = { + 0xf2, 0x0c, 0x9e, 0x75, 0x5b, 0xb1, 0x8c, 0xf1, + 0x46, 0x4f, 0x68, 0xe8, 0x0a, 0x65, 0xd5, 0x81, + }, + }, + .confirm_req[6] = { + .value = { + 0x15, 0x2b, 0x2e, 0x14, 0xf7, 0x31, 0xa2, 0xff, + 0x93, 0xa7, 0x28, 0x65, 0xb1, 0x68, 0x96, 0xc6, + }, + }, + .confirm_rsp[6] = { + .value = { + 0x6f, 0x01, 0x22, 0x14, 0x78, 0xfb, 0x93, 0xf4, + 0xfa, 0xf1, 0x6d, 0x33, 0x49, 0x0e, 0x7d, 0x56, + }, + }, + .random_req[6] = { + .value = { + 0x05, 0xe5, 0xed, 0x99, 0x63, 0x05, 0x29, 0xb1, + 0xbd, 0xf7, 0x2b, 0xa6, 0x94, 0xfe, 0x45, 0xb2, + }, + }, + .random_rsp[6] = { + .value = { + 0x51, 0xf1, 0x2a, 0xa6, 0x7b, 0xe0, 0xb3, 0x20, + 0x7d, 0x7e, 0xd3, 0x47, 0xfb, 0x83, 0xe1, 0xc6, + }, + }, + .confirm_req[7] = { + .value = { + 0x9e, 0x7a, 0x3d, 0x12, 0x3b, 0x30, 0x81, 0x23, + 0x1c, 0x94, 0x42, 0x73, 0x41, 0x68, 0xc6, 0x17, + }, + }, + .confirm_rsp[7] = { + .value = { + 0x55, 0x31, 0x41, 0xe8, 0x1f, 0x11, 0xa6, 0x06, + 0x7a, 0x7c, 0x84, 0x10, 0xad, 0xd3, 0x73, 0xcf, + }, + }, + .random_req[7] = { + .value = { + 0xcb, 0x92, 0x18, 0xf6, 0x59, 0x6a, 0x1b, 0x18, + 0x63, 0x72, 0x54, 0xc2, 0x1a, 0x3d, 0x09, 0x67, + }, + }, + .random_rsp[7] = { + .value = { + 0xae, 0xf2, 0x96, 0xfd, 0xff, 0xd7, 0x18, 0xac, + 0x5d, 0xb2, 0x9d, 0x89, 0x56, 0x2a, 0x19, 0xae, + }, + }, + .confirm_req[8] = { + .value = { + 0x06, 0x8d, 0x5d, 0x19, 0xb3, 0x27, 0xc9, 0x6a, + 0xe8, 0x58, 0xe7, 0x17, 0x10, 0x6a, 0xf9, 0xf7, + }, + }, + .confirm_rsp[8] = { + .value = { + 0xf0, 0xbc, 0x2a, 0x03, 0x1f, 0x9b, 0x7b, 0x58, + 0x43, 0x0f, 0xf5, 0x17, 0xc4, 0xbd, 0xec, 0x23, + }, + }, + .random_req[8] = { + .value = { + 0xbe, 0x78, 0xcd, 0x84, 0x91, 0x4a, 0x1b, 0xdd, + 0x6a, 0x0d, 0x88, 0x72, 0x9e, 0xc2, 0x4f, 0x5a, + }, + }, + .random_rsp[8] = { + .value = { + 0xff, 0xac, 0xfe, 0x71, 0x2f, 0x6a, 0x13, 0xdc, + 0xd3, 0x02, 0x81, 0x88, 0xbf, 0xc9, 0x9c, 0xd6, + }, + }, + .confirm_req[9] = { + .value = { + 0xb0, 0x8d, 0x47, 0x23, 0x7e, 0xdb, 0xf5, 0x64, + 0x5e, 0x83, 0x52, 0x9f, 0x06, 0x65, 0x84, 0x10, + }, + }, + .confirm_rsp[9] = { + .value = { + 0x4d, 0x3f, 0xd4, 0x5a, 0x45, 0x57, 0xe9, 0xd7, + 0x1e, 0x65, 0x7a, 0xa0, 0xd8, 0x5a, 0xa8, 0x29, + }, + }, + .random_req[9] = { + .value = { + 0xb0, 0xcd, 0xfa, 0x39, 0x0d, 0x2e, 0x07, 0xfe, + 0x36, 0x47, 0x8d, 0x8e, 0x1a, 0x47, 0x67, 0xf2, + }, + }, + .random_rsp[9] = { + .value = { + 0xb4, 0xf5, 0x12, 0x64, 0xf4, 0xf6, 0xd7, 0x6e, + 0xeb, 0x1e, 0x9a, 0x3f, 0x18, 0xba, 0xfb, 0x99, + }, + }, + .confirm_req[10] = { + .value = { + 0xc9, 0x76, 0xb3, 0x3f, 0x80, 0xd9, 0x0c, 0xfb, + 0xe3, 0x90, 0x1b, 0x7a, 0xbc, 0xe1, 0x7c, 0xde, + }, + }, + .confirm_rsp[10] = { + .value = { + 0x21, 0x6a, 0x45, 0x6e, 0x6a, 0xac, 0xba, 0x9e, + 0x66, 0x39, 0x5b, 0xb6, 0x74, 0xfe, 0x2b, 0x28, + }, + }, + .random_req[10] = { + .value = { + 0xc0, 0xd4, 0xdf, 0x7b, 0x0f, 0x2f, 0xaa, 0x68, + 0x4e, 0x3d, 0xa4, 0x59, 0x6f, 0x24, 0xe6, 0x7e, + }, + }, + .random_rsp[10] = { + .value = { + 0xdf, 0x89, 0x49, 0xe7, 0x9f, 0x60, 0xdd, 0xf6, + 0x44, 0x97, 0xe3, 0x15, 0x52, 0x65, 0x67, 0x3e, + }, + }, + .confirm_req[11] = { + .value = { + 0xb0, 0x3f, 0x34, 0xce, 0x7d, 0x2e, 0xf1, 0xab, + 0x23, 0xd5, 0x89, 0xf5, 0xaa, 0xa8, 0x59, 0x9f, + }, + }, + .confirm_rsp[11] = { + .value = { + 0xb1, 0x33, 0x6a, 0x64, 0xd8, 0xeb, 0x8b, 0xa0, + 0xf4, 0x1a, 0x15, 0x28, 0xb9, 0xe4, 0xa1, 0x31, + }, + }, + .random_req[11] = { + .value = { + 0xd2, 0x88, 0x24, 0xfe, 0x95, 0x11, 0xc5, 0x0a, + 0x21, 0xfb, 0x96, 0xea, 0x61, 0xb9, 0x8b, 0x26, + }, + }, + .random_rsp[11] = { + .value = { + 0x8f, 0x22, 0x66, 0x8e, 0x7e, 0x62, 0x34, 0x37, + 0xfc, 0x4a, 0x48, 0x1f, 0xf7, 0x38, 0x3b, 0x4e, + }, + }, + .confirm_req[12] = { + .value = { + 0xc4, 0x50, 0xc8, 0x53, 0x58, 0xfb, 0xea, 0x9a, + 0xdc, 0x35, 0xc7, 0xf3, 0x5b, 0x7c, 0xfb, 0xe4, + }, + }, + .confirm_rsp[12] = { + .value = { + 0x27, 0xd9, 0x32, 0xd6, 0x43, 0xbf, 0x57, 0x3f, + 0x35, 0x73, 0x3c, 0x3e, 0xbe, 0x53, 0x19, 0xff, + }, + }, + .random_req[12] = { + .value = { + 0x99, 0xa1, 0x7a, 0x5f, 0xe0, 0x48, 0x1c, 0x6c, + 0x84, 0xac, 0xab, 0xed, 0x69, 0x55, 0x1e, 0x66, + }, + }, + .random_rsp[12] = { + .value = { + 0x37, 0x50, 0x90, 0x35, 0xef, 0x84, 0x06, 0x18, + 0xfd, 0x3b, 0xc1, 0x8a, 0x46, 0x91, 0xb8, 0x21, + }, + }, + .confirm_req[13] = { + .value = { + 0x2f, 0xcb, 0x3e, 0xc3, 0xce, 0x82, 0x0b, 0x5c, + 0xdc, 0x9c, 0xbd, 0x44, 0xf9, 0x04, 0x22, 0x8c, + }, + }, + .confirm_rsp[13] = { + .value = { + 0xab, 0xf2, 0x2e, 0x40, 0xd0, 0x74, 0x4f, 0xd4, + 0x26, 0x9c, 0x89, 0x9e, 0x38, 0x77, 0xac, 0x9d, + }, + }, + .random_req[13] = { + .value = { + 0xbc, 0xda, 0x58, 0xa2, 0x98, 0x88, 0xfe, 0x9f, + 0x95, 0x0e, 0x3a, 0x91, 0xba, 0xe9, 0xbf, 0x02, + }, + }, + .random_rsp[13] = { + .value = { + 0x04, 0xb9, 0x4c, 0x26, 0xce, 0x87, 0x8f, 0x17, + 0xdc, 0xbc, 0x36, 0x94, 0x47, 0x67, 0x9f, 0xde, + }, + }, + .confirm_req[14] = { + .value = { + 0xbd, 0xb6, 0x54, 0xc8, 0x1f, 0x51, 0x23, 0x98, + 0x48, 0x3d, 0x47, 0x9d, 0xa3, 0xb8, 0xe7, 0x55, + }, + }, + .confirm_rsp[14] = { + .value = { + 0x06, 0xc2, 0x7b, 0x80, 0x76, 0x9c, 0x37, 0x78, + 0x46, 0xc5, 0x45, 0x43, 0x5d, 0x8d, 0x5b, 0x3e, + }, + }, + .random_req[14] = { + .value = { + 0xef, 0x9e, 0x8a, 0x3a, 0xb7, 0xde, 0xa8, 0x07, + 0x58, 0x73, 0xe0, 0x07, 0xfc, 0x62, 0xdb, 0x62, + }, + }, + .random_rsp[14] = { + .value = { + 0xfa, 0xd5, 0xb2, 0x4e, 0x20, 0x01, 0x93, 0xc0, + 0xb3, 0x76, 0xa5, 0x7a, 0x92, 0x8f, 0xb9, 0x6d, + }, + }, + .confirm_req[15] = { + .value = { + 0x76, 0x2e, 0xc6, 0x64, 0x6c, 0x13, 0x01, 0x7e, + 0x34, 0x78, 0x12, 0xb8, 0x1a, 0xb7, 0xf7, 0x39, + }, + }, + .confirm_rsp[15] = { + .value = { + 0xbd, 0xae, 0x10, 0x32, 0xdb, 0x63, 0x30, 0x6f, + 0x68, 0x19, 0x49, 0x5e, 0x34, 0x4f, 0x13, 0xc6, + }, + }, + .random_req[15] = { + .value = { + 0x95, 0x2e, 0xe4, 0xe3, 0xb2, 0xdc, 0x79, 0xad, + 0x5f, 0x0c, 0x19, 0x9c, 0x47, 0x9c, 0x79, 0x17, + }, + }, + .random_rsp[15] = { + .value = { + 0x9e, 0x3d, 0x7f, 0xcd, 0x18, 0x40, 0xd7, 0xac, + 0xa1, 0x45, 0x5f, 0xcb, 0x29, 0x57, 0x2b, 0x63, + }, + }, + .confirm_req[16] = { + .value = { + 0x10, 0x18, 0x9d, 0xf2, 0xed, 0x76, 0x5c, 0x5f, + 0x32, 0xa6, 0x29, 0x61, 0x12, 0xb2, 0xb8, 0xa2, + }, + }, + .confirm_rsp[16] = { + .value = { + 0x3c, 0xd4, 0xbd, 0xe9, 0xd3, 0x29, 0xac, 0xf7, + 0xfc, 0x04, 0xd3, 0xe4, 0x46, 0x14, 0x28, 0x2c, + }, + }, + .random_req[16] = { + .value = { + 0x6d, 0xe8, 0x77, 0xc3, 0xab, 0x49, 0x6b, 0x79, + 0x4f, 0x0f, 0x4c, 0x65, 0xc5, 0x77, 0x68, 0xd9, + }, + }, + .random_rsp[16] = { + .value = { + 0xd0, 0x59, 0xf3, 0x53, 0xb1, 0x14, 0x81, 0x88, + 0x26, 0x88, 0xef, 0x4b, 0xa4, 0x7d, 0x0a, 0x84, + }, + }, + .confirm_req[17] = { + .value = { + 0xa3, 0x96, 0x9f, 0x96, 0x53, 0x0e, 0x38, 0x78, + 0x9e, 0xbd, 0xf7, 0x65, 0x23, 0x73, 0x99, 0xa7, + }, + }, + .confirm_rsp[17] = { + .value = { + 0x6b, 0x25, 0x8d, 0x51, 0xd8, 0xc4, 0xd9, 0xbf, + 0xa6, 0x4f, 0xa3, 0x25, 0x28, 0xb5, 0x7c, 0x05, + }, + }, + .random_req[17] = { + .value = { + 0xa5, 0xac, 0xd9, 0xb6, 0x9e, 0x98, 0x75, 0xae, + 0x9b, 0x16, 0xe1, 0x60, 0xc6, 0xa5, 0x07, 0xf2, + }, + }, + .random_rsp[17] = { + .value = { + 0x65, 0x53, 0x56, 0xe6, 0x2c, 0x22, 0x68, 0xc9, + 0xb8, 0xbe, 0xb1, 0x40, 0x08, 0xe2, 0xb6, 0xb9, + }, + }, + .confirm_req[18] = { + .value = { + 0x67, 0xcd, 0x0e, 0x4f, 0xfc, 0x38, 0x7f, 0x8a, + 0x3b, 0xea, 0xff, 0x86, 0xf3, 0x8a, 0x92, 0xcb, + }, + }, + .confirm_rsp[18] = { + .value = { + 0x22, 0x95, 0x1f, 0x20, 0xc9, 0x5c, 0x73, 0x39, + 0xa4, 0xd9, 0xc1, 0x37, 0x9d, 0x94, 0xb2, 0xfd, + }, + }, + .random_req[18] = { + .value = { + 0xe1, 0x80, 0x82, 0xdd, 0x21, 0x6c, 0xe4, 0x93, + 0xa3, 0x41, 0x0f, 0xfc, 0x96, 0x42, 0x8b, 0xde, + }, + }, + .random_rsp[18] = { + .value = { + 0x11, 0x1c, 0xd7, 0x7a, 0xe7, 0x1a, 0x88, 0xdd, + 0x2a, 0xdf, 0xe5, 0x30, 0xca, 0x0b, 0x9f, 0xb6, + }, + }, + .confirm_req[19] = { + .value = { + 0x45, 0x9b, 0x36, 0x3d, 0xf8, 0xc0, 0x43, 0x6d, + 0x94, 0xcf, 0xbd, 0x5f, 0xfe, 0xec, 0xd7, 0x4b, + }, + }, + .confirm_rsp[19] = { + .value = { + 0xf0, 0xaa, 0xfd, 0xae, 0xb7, 0x73, 0x3c, 0x9d, + 0x93, 0xd4, 0x00, 0xea, 0x81, 0x31, 0xde, 0x41, + }, + }, + .random_req[19] = { + .value = { + 0x1a, 0xaa, 0xff, 0x2a, 0xdc, 0xcc, 0x89, 0xbc, + 0xcf, 0x48, 0x5c, 0x1e, 0x4d, 0x69, 0x85, 0x39, + }, + }, + .random_rsp[19] = { + .value = { + 0xe7, 0xd0, 0xcb, 0x9a, 0xb5, 0x76, 0xec, 0xfc, + 0x48, 0xa3, 0x41, 0x48, 0x4c, 0xa7, 0xec, 0xb7, + }, + }, + .dhkey_check_req = { + .value = { + 0xe3, 0x4e, 0x42, 0xb5, 0xe3, 0x63, 0x4b, 0x7c, + 0xf0, 0x9f, 0xef, 0x6e, 0x97, 0xe2, 0x86, 0xc0, + }, + }, + .dhkey_check_rsp = { + .value = { + 0xea, 0x8a, 0xab, 0x7f, 0x15, 0x21, 0x5a, 0x36, + 0x9b, 0x56, 0xee, 0x51, 0x61, 0x97, 0xe2, 0x0a, + }, + }, + .id_info_req = { + .irk = { + 0xef, 0x8d, 0xe2, 0x16, 0x4f, 0xec, 0x43, 0x0d, + 0xbf, 0x5b, 0xdd, 0x34, 0xc0, 0x53, 0x1e, 0xb8, + }, + }, + .id_addr_info_req = { + .addr_type = 0, + .bd_addr = { + 0x33, 0x22, 0x11, 0x00, 0x45, 0x0a, + }, + }, + .sign_info_req = { + .sig_key = { + 0x85, 0x54, 0x52, 0xe3, 0xb4, 0xe8, 0x26, 0xa4, + 0x38, 0xb0, 0x4c, 0xa0, 0x41, 0xf5, 0x30, 0x6e, + }, + }, + .sign_info_rsp = { + .sig_key = { + 0x6f, 0x93, 0xb8, 0x9c, 0x26, 0x88, 0xb4, 0x20, + 0x87, 0x95, 0xf2, 0xf4, 0x3a, 0xbe, 0x92, 0xb7, + }, + }, + .ltk = { + 0x30, 0xf6, 0xd3, 0x2e, 0x1c, 0x81, 0x2c, 0x96, + 0x56, 0x30, 0x55, 0xec, 0x9b, 0x72, 0xf4, 0x83, + }, + .pair_alg = BLE_SM_PAIR_ALG_PASSKEY, + .authenticated = 1, + .passkey_info = { + .passkey = { + .action = BLE_SM_IOACT_INPUT, + .passkey = 879894, + }, + }, + }; + ble_sm_test_util_peer_sc_good(¶ms); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +/** + * Secure connections pairing + * Master: peer + * Pair algorithm: passkey entry + * Initiator IO capabilities: 2 + * Responder IO capabilities: 0 + * Bonding: true + * Initiator address type: 0 + * Responder address type: 0 + * Initiator key distribution: 5 + * Responder key distribution: 7 + */ +TEST_CASE_SELF(ble_sm_sc_peer_pk_iio2_rio0_b1_iat0_rat0_ik5_rk7) +{ + struct ble_sm_test_params params; + + params = (struct ble_sm_test_params) { + .init_id_addr = { + 0xca, 0x61, 0xa0, 0x67, 0x94, 0xe0, + }, + .resp_id_addr = { + 0x33, 0x22, 0x11, 0x00, 0x45, 0x0a, + }, + .pair_req = { + .io_cap = 0x02, + .oob_data_flag = 0x00, + .authreq = 0x0d, + .max_enc_key_size = 0x10, + .init_key_dist = 0x0d, + .resp_key_dist = 0x0f, + }, + .pair_rsp = { + .io_cap = 0x00, + .oob_data_flag = 0x00, + .authreq = 0x0d, + .max_enc_key_size = 0x10, + .init_key_dist = 0x05, + .resp_key_dist = 0x07, + }, + .our_priv_key = { + 0xd6, 0x2f, 0x4f, 0x6b, 0xeb, 0xfc, 0xbd, 0xee, + 0x9b, 0x94, 0xd7, 0x15, 0x98, 0xc6, 0x0c, 0x83, + 0x9b, 0xc7, 0xa2, 0x45, 0xfd, 0x00, 0xe8, 0xa4, + 0x52, 0xe9, 0x70, 0x2f, 0xd7, 0x62, 0xf1, 0xa4, + }, + .public_key_req = { + .x = { + 0xd6, 0xa7, 0xaf, 0xc1, 0x18, 0x8b, 0x92, 0x2f, + 0xbc, 0xbc, 0x4d, 0xb8, 0x5c, 0xfb, 0x39, 0x7c, + 0x1e, 0x90, 0x7e, 0xfa, 0xa2, 0x0d, 0xee, 0x9e, + 0xb4, 0x9e, 0xbe, 0x50, 0xf0, 0xbc, 0x2c, 0x10, + }, + .y = { + 0xa4, 0x25, 0xad, 0x75, 0xbe, 0xab, 0x1e, 0xcf, + 0x4e, 0xc8, 0x19, 0xab, 0x6c, 0x68, 0x38, 0xa4, + 0xe7, 0x43, 0x7b, 0x19, 0xef, 0x28, 0xd5, 0x93, + 0x52, 0xe9, 0xb9, 0x31, 0x68, 0x60, 0x19, 0x71, + }, + }, + .public_key_rsp = { + .x = { + 0xbc, 0x6a, 0xcf, 0xc6, 0x8a, 0x3a, 0xdc, 0x89, + 0xdd, 0xa9, 0xaf, 0x29, 0xc7, 0xaf, 0xe2, 0x8b, + 0x25, 0xee, 0xce, 0xa6, 0x10, 0x1d, 0x33, 0x2f, + 0xd5, 0xfc, 0x30, 0xb8, 0xb1, 0x7b, 0xb1, 0x6e, + }, + .y = { + 0x1a, 0xc6, 0x42, 0x36, 0x98, 0x40, 0x4f, 0x90, + 0x82, 0xa0, 0x10, 0x3a, 0xa5, 0x0f, 0xcf, 0x57, + 0xd2, 0x2e, 0x80, 0x9d, 0x61, 0xc7, 0x21, 0xac, + 0x47, 0x5b, 0x93, 0x75, 0x02, 0x30, 0x40, 0x14, + }, + }, + .confirm_req[0] = { + .value = { + 0xd1, 0x64, 0x49, 0xa0, 0xc4, 0x28, 0x81, 0x57, + 0x0c, 0x25, 0x62, 0xfb, 0x2c, 0xa2, 0xb0, 0xc7, + }, + }, + .confirm_rsp[0] = { + .value = { + 0xea, 0xae, 0x4e, 0x03, 0x00, 0xf9, 0xd1, 0x65, + 0xc7, 0x6a, 0x0d, 0x74, 0x4f, 0x02, 0x0b, 0x94, + }, + }, + .random_req[0] = { + .value = { + 0x05, 0xb2, 0x09, 0x9b, 0x36, 0x23, 0x4f, 0x74, + 0x4e, 0xc9, 0x7a, 0x2c, 0x65, 0x3a, 0xd1, 0xf6, + }, + }, + .random_rsp[0] = { + .value = { + 0x50, 0xd8, 0x88, 0xd4, 0x7e, 0xc1, 0x36, 0x92, + 0x0f, 0xa7, 0x17, 0x3c, 0xb4, 0xeb, 0xee, 0xa6, + }, + }, + .confirm_req[1] = { + .value = { + 0xab, 0xa2, 0xd0, 0xec, 0xdd, 0xf3, 0xd2, 0xa9, + 0x2d, 0xde, 0x4b, 0x02, 0x66, 0x45, 0x2f, 0xc0, + }, + }, + .confirm_rsp[1] = { + .value = { + 0xa9, 0xc1, 0x9d, 0x75, 0xd0, 0xb6, 0xec, 0x06, + 0x31, 0x87, 0xb6, 0x9d, 0x31, 0xdc, 0x92, 0x7c, + }, + }, + .random_req[1] = { + .value = { + 0xb9, 0x5b, 0xe0, 0x0f, 0x83, 0xe7, 0x2d, 0x77, + 0x2f, 0x55, 0x0a, 0x2c, 0xd9, 0xc1, 0x46, 0xcd, + }, + }, + .random_rsp[1] = { + .value = { + 0xa2, 0x9a, 0x5b, 0x99, 0xb1, 0xc0, 0xc5, 0xd6, + 0xf1, 0x87, 0x0b, 0x49, 0x9c, 0xfd, 0xfe, 0xd5, + }, + }, + .confirm_req[2] = { + .value = { + 0x3a, 0x9d, 0x58, 0xe5, 0xb0, 0x31, 0xd9, 0xde, + 0xac, 0xd2, 0x44, 0xb7, 0xe1, 0xe5, 0x89, 0x50, + }, + }, + .confirm_rsp[2] = { + .value = { + 0xae, 0x4e, 0x4f, 0x84, 0x5f, 0x4c, 0xd1, 0x9b, + 0x81, 0x22, 0x9c, 0x68, 0x52, 0xe0, 0x9a, 0xfc, + }, + }, + .random_req[2] = { + .value = { + 0xa5, 0xbb, 0x5f, 0x9a, 0xa2, 0x97, 0xdb, 0xcd, + 0x3d, 0xfe, 0xd9, 0x58, 0x21, 0x52, 0x99, 0xb7, + }, + }, + .random_rsp[2] = { + .value = { + 0xea, 0x44, 0xdd, 0x0c, 0xbf, 0xb5, 0x6b, 0xc7, + 0xe1, 0x19, 0xe8, 0x0b, 0xc2, 0x15, 0x04, 0x37, + }, + }, + .confirm_req[3] = { + .value = { + 0xa8, 0xa3, 0xdb, 0x08, 0xca, 0x31, 0xd5, 0xef, + 0x17, 0x37, 0x77, 0xd0, 0x64, 0x2e, 0x2f, 0x2f, + }, + }, + .confirm_rsp[3] = { + .value = { + 0xe4, 0xf6, 0xa5, 0x94, 0x1a, 0x09, 0x4b, 0x75, + 0x79, 0xb8, 0x0c, 0xe6, 0xe2, 0x28, 0x5a, 0x2c, + }, + }, + .random_req[3] = { + .value = { + 0x1a, 0x3f, 0x80, 0x6f, 0xd3, 0xe8, 0xc5, 0xfb, + 0x9b, 0xda, 0xa1, 0x07, 0x68, 0x1a, 0x54, 0xbc, + }, + }, + .random_rsp[3] = { + .value = { + 0x1b, 0x48, 0x22, 0x87, 0x04, 0x24, 0x87, 0xba, + 0x14, 0xb9, 0x85, 0xb2, 0xa6, 0xf5, 0xea, 0x89, + }, + }, + .confirm_req[4] = { + .value = { + 0x31, 0xcb, 0xc4, 0x0c, 0x36, 0xb5, 0xe2, 0x32, + 0xd8, 0x0e, 0xd3, 0x86, 0x96, 0xe3, 0x8c, 0x84, + }, + }, + .confirm_rsp[4] = { + .value = { + 0x90, 0x11, 0x30, 0x35, 0x5f, 0xe5, 0x45, 0xff, + 0xab, 0xd3, 0xe0, 0xbe, 0x1c, 0x20, 0x23, 0xb8, + }, + }, + .random_req[4] = { + .value = { + 0xa0, 0xc7, 0x79, 0x28, 0x87, 0x19, 0xa3, 0x78, + 0x33, 0xe5, 0x1a, 0x81, 0xba, 0x9b, 0xe3, 0x5c, + }, + }, + .random_rsp[4] = { + .value = { + 0x43, 0xcf, 0x20, 0x1b, 0x39, 0x3f, 0xdf, 0x73, + 0x58, 0xd2, 0x0d, 0xc7, 0x41, 0xd7, 0x58, 0xea, + }, + }, + .confirm_req[5] = { + .value = { + 0x59, 0xda, 0x78, 0xeb, 0xd5, 0xcd, 0x8e, 0x23, + 0xe5, 0x5e, 0xa7, 0xa5, 0xba, 0x13, 0x00, 0xff, + }, + }, + .confirm_rsp[5] = { + .value = { + 0x31, 0x7a, 0xf0, 0x56, 0x82, 0x69, 0xdb, 0xcd, + 0x27, 0x5a, 0x11, 0xd3, 0x65, 0x82, 0x0d, 0xda, + }, + }, + .random_req[5] = { + .value = { + 0x2e, 0xe8, 0x76, 0x40, 0x9c, 0x49, 0x07, 0x42, + 0x1e, 0x45, 0x7b, 0x1e, 0x73, 0xa3, 0x71, 0x05, + }, + }, + .random_rsp[5] = { + .value = { + 0x64, 0x99, 0x42, 0x5d, 0x05, 0xd6, 0x12, 0x41, + 0x2a, 0x44, 0x55, 0x26, 0xe7, 0x08, 0x5e, 0xfb, + }, + }, + .confirm_req[6] = { + .value = { + 0x1c, 0x55, 0xe1, 0x75, 0x4f, 0x6e, 0xdd, 0x7e, + 0xc8, 0xff, 0x76, 0x25, 0xdb, 0x2a, 0x6d, 0xe3, + }, + }, + .confirm_rsp[6] = { + .value = { + 0xf6, 0x36, 0x78, 0x88, 0x62, 0xa8, 0x78, 0xe6, + 0xf9, 0xa1, 0x17, 0x63, 0x86, 0xd3, 0xae, 0x60, + }, + }, + .random_req[6] = { + .value = { + 0x96, 0x9a, 0x1c, 0xbe, 0x82, 0x82, 0xc2, 0xa7, + 0x18, 0xc3, 0x7b, 0x40, 0x5d, 0x6c, 0x4e, 0xe3, + }, + }, + .random_rsp[6] = { + .value = { + 0x2b, 0x7d, 0x36, 0xc3, 0xf7, 0x59, 0x63, 0x40, + 0x6f, 0xc0, 0x2a, 0x2b, 0x1b, 0xd7, 0x41, 0x38, + }, + }, + .confirm_req[7] = { + .value = { + 0x88, 0x99, 0x53, 0xae, 0x2a, 0xaf, 0x97, 0x5a, + 0xcc, 0x9f, 0xfd, 0xe2, 0x1d, 0xd3, 0x27, 0x66, + }, + }, + .confirm_rsp[7] = { + .value = { + 0xdb, 0xae, 0xfb, 0xf7, 0x33, 0xd4, 0xd1, 0xcb, + 0xfe, 0x75, 0x8e, 0x81, 0x16, 0xd1, 0x49, 0xeb, + }, + }, + .random_req[7] = { + .value = { + 0x13, 0x5c, 0x00, 0x34, 0xe5, 0x96, 0xd0, 0x97, + 0xb1, 0x84, 0x3d, 0x00, 0xb4, 0x2a, 0x4a, 0x12, + }, + }, + .random_rsp[7] = { + .value = { + 0xed, 0x94, 0x1f, 0x41, 0x12, 0xe5, 0x35, 0x5b, + 0xa6, 0x6a, 0x72, 0x1e, 0xa2, 0x7c, 0xe1, 0x6c, + }, + }, + .confirm_req[8] = { + .value = { + 0xa3, 0xc7, 0x17, 0xad, 0xb6, 0xe6, 0xaa, 0x16, + 0x8d, 0x4b, 0x70, 0x5f, 0x49, 0x73, 0xa7, 0x19, + }, + }, + .confirm_rsp[8] = { + .value = { + 0x10, 0xb0, 0x31, 0xa7, 0x16, 0x61, 0xf7, 0xd6, + 0xe6, 0x16, 0x9e, 0xb1, 0x9e, 0xb5, 0x5e, 0x94, + }, + }, + .random_req[8] = { + .value = { + 0x6f, 0xe7, 0x62, 0x73, 0xfb, 0xbf, 0xf1, 0x4a, + 0x14, 0xa1, 0x09, 0x45, 0xd4, 0xde, 0x26, 0xad, + }, + }, + .random_rsp[8] = { + .value = { + 0x3f, 0x48, 0xa7, 0xdf, 0x4a, 0xd5, 0x55, 0x26, + 0xd3, 0x32, 0xbf, 0x98, 0x4a, 0x20, 0xad, 0xb0, + }, + }, + .confirm_req[9] = { + .value = { + 0x88, 0x1c, 0xef, 0xfe, 0x4e, 0x68, 0x41, 0x7c, + 0xe8, 0xe8, 0x81, 0x1a, 0xb9, 0x9e, 0xaf, 0xc6, + }, + }, + .confirm_rsp[9] = { + .value = { + 0xa3, 0x53, 0x2a, 0xe1, 0xbd, 0x9d, 0xbe, 0x89, + 0xf8, 0xc7, 0x70, 0x6e, 0xa9, 0x12, 0x07, 0x0d, + }, + }, + .random_req[9] = { + .value = { + 0x52, 0x06, 0x56, 0x09, 0xf4, 0xb2, 0xb9, 0x63, + 0x3f, 0x2e, 0x59, 0x6c, 0x6b, 0x43, 0xb6, 0xc0, + }, + }, + .random_rsp[9] = { + .value = { + 0x36, 0xb0, 0x33, 0x84, 0x52, 0xd1, 0x60, 0xac, + 0x37, 0x81, 0x6b, 0x18, 0x5f, 0xfc, 0x61, 0xb1, + }, + }, + .confirm_req[10] = { + .value = { + 0xc8, 0x55, 0xb7, 0x9e, 0x3e, 0xf0, 0x26, 0xa4, + 0x55, 0xb3, 0x1d, 0x4d, 0xa1, 0x5d, 0xa9, 0xaf, + }, + }, + .confirm_rsp[10] = { + .value = { + 0xb7, 0xb9, 0x6b, 0x8e, 0xef, 0xd3, 0xbc, 0x58, + 0x10, 0xbe, 0x5a, 0x9a, 0x4d, 0xbc, 0xec, 0xe3, + }, + }, + .random_req[10] = { + .value = { + 0x55, 0xa1, 0xf4, 0xd7, 0xfa, 0xe1, 0x84, 0x03, + 0xed, 0xb6, 0x95, 0x63, 0x4b, 0x93, 0x93, 0xc2, + }, + }, + .random_rsp[10] = { + .value = { + 0x72, 0xa9, 0xe5, 0xf7, 0x48, 0x1f, 0x64, 0x71, + 0xd9, 0x81, 0xf0, 0xc5, 0x4d, 0x38, 0xac, 0x9a, + }, + }, + .confirm_req[11] = { + .value = { + 0x12, 0x37, 0x56, 0xa6, 0x66, 0xa1, 0x23, 0xee, + 0xe3, 0x1e, 0x20, 0x66, 0x66, 0x85, 0x7c, 0xa8, + }, + }, + .confirm_rsp[11] = { + .value = { + 0x74, 0xaa, 0xbb, 0x5a, 0xdf, 0xd9, 0xc4, 0xaf, + 0xe4, 0xa7, 0xe6, 0x4b, 0x45, 0x97, 0xf8, 0x7d, + }, + }, + .random_req[11] = { + .value = { + 0x29, 0xce, 0xcc, 0xb7, 0xb2, 0x1e, 0x0e, 0xa8, + 0x48, 0x90, 0x43, 0x6d, 0x34, 0xa4, 0xa3, 0x12, + }, + }, + .random_rsp[11] = { + .value = { + 0x2e, 0xaf, 0x4c, 0x63, 0x84, 0x2c, 0x62, 0x67, + 0x68, 0x8f, 0x0b, 0xfd, 0xff, 0xef, 0x15, 0x26, + }, + }, + .confirm_req[12] = { + .value = { + 0xec, 0xcf, 0x6a, 0x60, 0x77, 0x04, 0x2c, 0x62, + 0x42, 0xf0, 0x21, 0xfd, 0x53, 0xd6, 0x8a, 0xe8, + }, + }, + .confirm_rsp[12] = { + .value = { + 0x2c, 0x13, 0x65, 0x69, 0xd7, 0x66, 0x04, 0x13, + 0x3c, 0xa8, 0xfb, 0xe5, 0x76, 0xbb, 0x4f, 0x48, + }, + }, + .random_req[12] = { + .value = { + 0x0d, 0x93, 0x30, 0xe2, 0x76, 0xf1, 0xbc, 0x24, + 0x61, 0x0d, 0xcd, 0xef, 0x33, 0x98, 0xe2, 0x3b, + }, + }, + .random_rsp[12] = { + .value = { + 0xb6, 0x32, 0x69, 0x81, 0xc0, 0x81, 0x46, 0xae, + 0x8d, 0x5a, 0x17, 0xb5, 0xc0, 0x0f, 0x9f, 0x4e, + }, + }, + .confirm_req[13] = { + .value = { + 0x89, 0x96, 0x22, 0x0c, 0x76, 0xdf, 0x27, 0x13, + 0x96, 0x5a, 0x0c, 0x88, 0x65, 0x18, 0x74, 0x52, + }, + }, + .confirm_rsp[13] = { + .value = { + 0x1c, 0x77, 0x25, 0x22, 0xc0, 0x28, 0x88, 0x45, + 0x29, 0x62, 0x7a, 0x8e, 0xc0, 0x2a, 0x5c, 0xd8, + }, + }, + .random_req[13] = { + .value = { + 0xcc, 0x84, 0xb6, 0x98, 0x3e, 0xf9, 0x09, 0xd2, + 0x71, 0x47, 0x56, 0xb1, 0x09, 0xf5, 0xd2, 0x0b, + }, + }, + .random_rsp[13] = { + .value = { + 0xf0, 0xcf, 0x1c, 0xa6, 0x24, 0xcd, 0xfa, 0x42, + 0xa4, 0x93, 0x8b, 0xa0, 0xe3, 0x42, 0x72, 0x51, + }, + }, + .confirm_req[14] = { + .value = { + 0xab, 0xb0, 0xa3, 0x80, 0x0d, 0xcb, 0x8e, 0xf6, + 0x6c, 0x07, 0x50, 0xe9, 0x8a, 0x85, 0x02, 0xae, + }, + }, + .confirm_rsp[14] = { + .value = { + 0xf6, 0x52, 0xd8, 0x34, 0x15, 0x62, 0x9f, 0x6e, + 0x2b, 0x52, 0xdc, 0x1c, 0x70, 0x17, 0x0a, 0x31, + }, + }, + .random_req[14] = { + .value = { + 0x8d, 0xc9, 0x0a, 0x45, 0xe9, 0x81, 0x0d, 0x5e, + 0xbb, 0xd8, 0x94, 0x29, 0x68, 0x42, 0x44, 0xe2, + }, + }, + .random_rsp[14] = { + .value = { + 0x96, 0x2a, 0x35, 0x39, 0x09, 0xf7, 0x66, 0x5a, + 0xb6, 0x33, 0x77, 0x6d, 0xba, 0xd3, 0x8a, 0xfb, + }, + }, + .confirm_req[15] = { + .value = { + 0x53, 0x08, 0x9b, 0x37, 0xc3, 0x79, 0xe6, 0x8c, + 0x42, 0x30, 0x94, 0x73, 0x6f, 0x39, 0x64, 0x20, + }, + }, + .confirm_rsp[15] = { + .value = { + 0x4d, 0xb7, 0xe9, 0x50, 0x8e, 0x0f, 0xe0, 0xd5, + 0x3e, 0xf6, 0x32, 0xdd, 0xb8, 0x18, 0x77, 0xd3, + }, + }, + .random_req[15] = { + .value = { + 0x8d, 0x49, 0x14, 0xdd, 0x95, 0x57, 0x55, 0x14, + 0x48, 0x97, 0xd3, 0x73, 0x29, 0xa0, 0xb9, 0x2b, + }, + }, + .random_rsp[15] = { + .value = { + 0xcf, 0x38, 0x8b, 0xab, 0xe4, 0x2b, 0x3f, 0x13, + 0xc3, 0xfb, 0x07, 0xee, 0x0e, 0x33, 0x2f, 0x04, + }, + }, + .confirm_req[16] = { + .value = { + 0xc6, 0x58, 0x13, 0x19, 0x56, 0x06, 0x52, 0x4b, + 0x3d, 0x5e, 0x9d, 0xa8, 0x48, 0xf2, 0x40, 0xf3, + }, + }, + .confirm_rsp[16] = { + .value = { + 0xbb, 0x93, 0xd2, 0xed, 0x89, 0x66, 0xa5, 0x1c, + 0xc9, 0x2a, 0x42, 0x2c, 0xff, 0x4a, 0x80, 0x84, + }, + }, + .random_req[16] = { + .value = { + 0x3d, 0x9c, 0x11, 0x2a, 0xd3, 0xce, 0x4b, 0x20, + 0xf2, 0xfb, 0xdd, 0x18, 0x4d, 0x7c, 0x58, 0xb6, + }, + }, + .random_rsp[16] = { + .value = { + 0xda, 0x80, 0x63, 0x9d, 0xa2, 0x73, 0x61, 0xdd, + 0x9a, 0x45, 0x91, 0x4d, 0x78, 0x39, 0x54, 0x75, + }, + }, + .confirm_req[17] = { + .value = { + 0x2e, 0xe4, 0x44, 0xe8, 0xdb, 0xc2, 0xbd, 0x62, + 0xd1, 0xc4, 0x23, 0x4e, 0x5f, 0x65, 0xb6, 0x3b, + }, + }, + .confirm_rsp[17] = { + .value = { + 0x19, 0x91, 0xa3, 0xc7, 0x3b, 0x68, 0x12, 0x24, + 0xcd, 0xd6, 0x02, 0xf5, 0xcd, 0x19, 0x6c, 0x88, + }, + }, + .random_req[17] = { + .value = { + 0xf0, 0x28, 0x18, 0xe8, 0xa7, 0x3e, 0xd8, 0x21, + 0x42, 0x58, 0xb3, 0x72, 0xa0, 0x34, 0x89, 0x04, + }, + }, + .random_rsp[17] = { + .value = { + 0xe9, 0xff, 0x0b, 0x9a, 0xfd, 0x29, 0x95, 0x37, + 0x89, 0x2c, 0x84, 0xfa, 0x02, 0xa0, 0xb6, 0xeb, + }, + }, + .confirm_req[18] = { + .value = { + 0x4f, 0x90, 0x70, 0xbe, 0xc4, 0x81, 0x9f, 0xc1, + 0x74, 0xa3, 0x01, 0x2e, 0x78, 0x7a, 0xe2, 0x61, + }, + }, + .confirm_rsp[18] = { + .value = { + 0xbb, 0xd5, 0x91, 0xec, 0x81, 0xe0, 0x9b, 0x5e, + 0xe9, 0xd2, 0x93, 0x57, 0xa8, 0x27, 0xdd, 0x9b, + }, + }, + .random_req[18] = { + .value = { + 0x78, 0xa4, 0x35, 0x1a, 0xbc, 0xa7, 0x19, 0x8c, + 0x96, 0x8f, 0x63, 0x9d, 0x11, 0xee, 0x27, 0x44, + }, + }, + .random_rsp[18] = { + .value = { + 0x39, 0x5b, 0x71, 0xfd, 0x7e, 0x39, 0x6b, 0xbe, + 0xaf, 0xe1, 0x55, 0x90, 0xa6, 0x58, 0xec, 0xc5, + }, + }, + .confirm_req[19] = { + .value = { + 0x91, 0x43, 0xe5, 0xc8, 0x26, 0x0c, 0x8c, 0x6c, + 0xf3, 0xd1, 0x30, 0xb3, 0x22, 0x94, 0x4c, 0x67, + }, + }, + .confirm_rsp[19] = { + .value = { + 0x51, 0xc4, 0x3e, 0x09, 0xca, 0x03, 0xbe, 0x2c, + 0xe8, 0x1a, 0x5d, 0x07, 0x12, 0x14, 0x2d, 0x43, + }, + }, + .random_req[19] = { + .value = { + 0x2f, 0xa1, 0x20, 0xde, 0xf5, 0xb4, 0xa6, 0x92, + 0x31, 0xe9, 0x86, 0x63, 0xef, 0xc1, 0x85, 0x3b, + }, + }, + .random_rsp[19] = { + .value = { + 0x41, 0xd0, 0xd0, 0x96, 0x93, 0xd1, 0xcb, 0xed, + 0xab, 0x27, 0xd5, 0x88, 0x5e, 0xe6, 0x5e, 0x5c, + }, + }, + .dhkey_check_req = { + .value = { + 0xec, 0xc5, 0x5f, 0xf3, 0xae, 0xfe, 0x79, 0x65, + 0x17, 0x5a, 0x60, 0xf7, 0x36, 0x4f, 0x90, 0x45, + }, + }, + .dhkey_check_rsp = { + .value = { + 0xa7, 0x45, 0x7a, 0x54, 0x1b, 0x64, 0x08, 0x60, + 0x51, 0x7d, 0x74, 0x27, 0x48, 0xa2, 0xf1, 0x0f, + }, + }, + .id_info_req = { + .irk = { + 0xef, 0x8d, 0xe2, 0x16, 0x4f, 0xec, 0x43, 0x0d, + 0xbf, 0x5b, 0xdd, 0x34, 0xc0, 0x53, 0x1e, 0xb8, + }, + }, + .id_addr_info_req = { + .addr_type = 0, + .bd_addr = { + 0x33, 0x22, 0x11, 0x00, 0x45, 0x0a, + }, + }, + .sign_info_req = { + .sig_key = { + 0x36, 0x9a, 0xd9, 0x25, 0x5c, 0xdb, 0x78, 0xdc, + 0x1d, 0x2c, 0x83, 0xf7, 0xde, 0x99, 0xa0, 0x66, + }, + }, + .sign_info_rsp = { + .sig_key = { + 0x61, 0x6e, 0x9a, 0x26, 0xc5, 0xd0, 0x85, 0xdc, + 0xea, 0x9d, 0xca, 0x3b, 0x17, 0xd7, 0x43, 0x80, + }, + }, + .ltk = { + 0xd6, 0x02, 0xba, 0x3d, 0xa2, 0xce, 0x93, 0x1a, + 0xfd, 0xd6, 0xb5, 0x54, 0x90, 0xc4, 0x2a, 0x8f, + }, + .pair_alg = BLE_SM_PAIR_ALG_PASSKEY, + .authenticated = 1, + .passkey_info = { + .passkey = { + .action = BLE_SM_IOACT_DISP, + .passkey = 222333, + }, + }, + }; + ble_sm_test_util_peer_sc_good(¶ms); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +/** + * Secure connections pairing + * Master: peer + * Pair algorithm: numeric comparison + * Initiator IO capabilities: 1 + * Responder IO capabilities: 1 + * Bonding: true + * Initiator address type: 0 + * Responder address type: 0 + * Initiator key distribution: 5 + * Responder key distribution: 7 + */ +TEST_CASE_SELF(ble_sm_sc_peer_nc_iio1_rio1_b1_iat0_rat0_ik5_rk7) +{ + struct ble_sm_test_params params; + + params = (struct ble_sm_test_params) { + .init_id_addr = { + 0xca, 0x61, 0xa0, 0x67, 0x94, 0xe0, + }, + .resp_id_addr = { + 0x33, 0x22, 0x11, 0x00, 0x45, 0x0a, + }, + .pair_req = { + .io_cap = 0x01, + .oob_data_flag = 0x00, + .authreq = 0x0d, + .max_enc_key_size = 0x10, + .init_key_dist = 0x0d, + .resp_key_dist = 0x0f, + }, + .pair_rsp = { + .io_cap = 0x01, + .oob_data_flag = 0x00, + .authreq = 0x0d, + .max_enc_key_size = 0x10, + .init_key_dist = 0x05, + .resp_key_dist = 0x07, + }, + .our_priv_key = { + 0xd6, 0x2f, 0x4f, 0x6b, 0xeb, 0xfc, 0xbd, 0xee, + 0x9b, 0x94, 0xd7, 0x15, 0x98, 0xc6, 0x0c, 0x83, + 0x9b, 0xc7, 0xa2, 0x45, 0xfd, 0x00, 0xe8, 0xa4, + 0x52, 0xe9, 0x70, 0x2f, 0xd7, 0x62, 0xf1, 0xa4, + }, + .public_key_req = { + .x = { + 0x41, 0x0d, 0x95, 0x8a, 0x68, 0xb8, 0xcf, 0x07, + 0x58, 0x25, 0x5f, 0x97, 0xd2, 0x99, 0x71, 0x44, + 0x06, 0xfc, 0x9c, 0x4d, 0xd1, 0x74, 0x80, 0xed, + 0x49, 0xd1, 0x36, 0x6b, 0x55, 0x8b, 0x54, 0x3b, + }, + .y = { + 0x0f, 0x1a, 0x61, 0x45, 0xe5, 0x4b, 0x11, 0x13, + 0xb3, 0x15, 0x87, 0x09, 0xec, 0x16, 0xf8, 0x41, + 0x2e, 0xe2, 0x15, 0x93, 0x14, 0x56, 0x9f, 0xcd, + 0x60, 0x7d, 0x92, 0xec, 0xd3, 0xb5, 0x85, 0xc5, + }, + }, + .public_key_rsp = { + .x = { + 0xbc, 0x6a, 0xcf, 0xc6, 0x8a, 0x3a, 0xdc, 0x89, + 0xdd, 0xa9, 0xaf, 0x29, 0xc7, 0xaf, 0xe2, 0x8b, + 0x25, 0xee, 0xce, 0xa6, 0x10, 0x1d, 0x33, 0x2f, + 0xd5, 0xfc, 0x30, 0xb8, 0xb1, 0x7b, 0xb1, 0x6e, + }, + .y = { + 0x1a, 0xc6, 0x42, 0x36, 0x98, 0x40, 0x4f, 0x90, + 0x82, 0xa0, 0x10, 0x3a, 0xa5, 0x0f, 0xcf, 0x57, + 0xd2, 0x2e, 0x80, 0x9d, 0x61, 0xc7, 0x21, 0xac, + 0x47, 0x5b, 0x93, 0x75, 0x02, 0x30, 0x40, 0x14, + }, + }, + .confirm_rsp[0] = { + .value = { + 0x73, 0xc8, 0x56, 0x5e, 0x33, 0x37, 0x26, 0xb6, + 0x00, 0x65, 0x9c, 0xa1, 0xee, 0xbf, 0x61, 0xf6, + }, + }, + .random_req[0] = { + .value = { + 0x7c, 0x23, 0x03, 0x70, 0x54, 0xa2, 0x70, 0xe4, + 0x2d, 0xe9, 0x88, 0x6f, 0x40, 0xd6, 0x2f, 0xb2, + }, + }, + .random_rsp[0] = { + .value = { + 0x2d, 0x9f, 0xe8, 0x1d, 0xf2, 0x4e, 0x2e, 0x58, + 0x16, 0x8c, 0x83, 0x89, 0x92, 0x70, 0xa2, 0xba, + }, + }, + .dhkey_check_req = { + .value = { + 0xc0, 0x8a, 0x1c, 0xff, 0x7f, 0xd6, 0xbc, 0xee, + 0x19, 0xa5, 0xc6, 0x3a, 0xbd, 0x48, 0x4b, 0xc3, + }, + }, + .dhkey_check_rsp = { + .value = { + 0x38, 0x36, 0x83, 0xd5, 0x1a, 0xfb, 0xe6, 0x3c, + 0x80, 0x0c, 0x81, 0x81, 0x78, 0x12, 0x41, 0x38, + }, + }, + .id_info_req = { + .irk = { + 0xef, 0x8d, 0xe2, 0x16, 0x4f, 0xec, 0x43, 0x0d, + 0xbf, 0x5b, 0xdd, 0x34, 0xc0, 0x53, 0x1e, 0xb8, + }, + }, + .id_addr_info_req = { + .addr_type = 0, + .bd_addr = { + 0x33, 0x22, 0x11, 0x00, 0x45, 0x0a, + }, + }, + .sign_info_req = { + .sig_key = { + 0x52, 0xf4, 0xcc, 0x2f, 0xc6, 0xc1, 0xdb, 0x07, + 0xa5, 0x38, 0xc1, 0x09, 0x82, 0x2e, 0xa3, 0x53, + }, + }, + .sign_info_rsp = { + .sig_key = { + 0xc1, 0xa3, 0x62, 0x6a, 0x9e, 0xaa, 0x37, 0xd9, + 0x65, 0x9f, 0x7f, 0x5d, 0x62, 0x0c, 0x1c, 0x6c, + }, + }, + .ltk = { + 0xd8, 0x7f, 0x0a, 0x94, 0x41, 0xa5, 0xfd, 0x84, + 0x15, 0x01, 0xb7, 0x2a, 0x7a, 0xe4, 0xfd, 0xfb, + }, + .pair_alg = BLE_SM_PAIR_ALG_NUMCMP, + .authenticated = 1, + .passkey_info = { + .passkey = { + .action = BLE_SM_IOACT_NUMCMP, + .numcmp_accept = 1, + }, + .exp_numcmp = 516214, + }, + }; + ble_sm_test_util_peer_sc_good(¶ms); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +/** + * Secure connections pairing + * Master: us + * Pair algorithm: just works + * Initiator IO capabilities: 3 + * Responder IO capabilities: 4 + * Bonding: true + * Initiator address type: 0 + * Responder address type: 0 + * Initiator key distribution: 7 + * Responder key distribution: 5 + */ +TEST_CASE_SELF(ble_sm_sc_us_jw_iio3_rio4_b1_iat0_rat0_ik7_rk5) +{ + struct ble_sm_test_params params; + + params = (struct ble_sm_test_params) { + .init_id_addr = { + 0x01, 0x01, 0x01, 0x07, 0x08, 0x01, + }, + .resp_id_addr = { + 0xca, 0x61, 0xa0, 0x67, 0x94, 0xe0, + }, + .pair_req = { + .io_cap = 0x03, + .oob_data_flag = 0x00, + .authreq = 0x09, + .max_enc_key_size = 0x10, + .init_key_dist = 0x07, + .resp_key_dist = 0x07, + }, + .pair_rsp = { + .io_cap = 0x04, + .oob_data_flag = 0x00, + .authreq = 0x09, + .max_enc_key_size = 0x10, + .init_key_dist = 0x07, + .resp_key_dist = 0x05, + }, + .our_priv_key = { + 0xaf, 0xce, 0x12, 0x45, 0xa8, 0xe0, 0xa9, 0x45, + 0x8a, 0x56, 0xc5, 0xbf, 0x3b, 0xf9, 0x04, 0x69, + 0xf2, 0xf9, 0xe4, 0xd4, 0x7e, 0xb7, 0xc9, 0x65, + 0xb1, 0x68, 0x3e, 0xab, 0xcd, 0x8e, 0x6f, 0x1f, + }, + .public_key_req = { + .x = { + 0x45, 0xca, 0xda, 0xe3, 0x65, 0x7c, 0xf5, 0x37, + 0x36, 0x66, 0x8b, 0x3b, 0x54, 0xb9, 0x2b, 0xb2, + 0x09, 0xd5, 0x6e, 0xe0, 0x04, 0x1d, 0xd6, 0x49, + 0xff, 0x55, 0x41, 0x35, 0xa0, 0x2f, 0x12, 0xee, + }, + .y = { + 0x65, 0x41, 0xd3, 0x7b, 0x59, 0xf2, 0xaf, 0x94, + 0x78, 0xd8, 0x63, 0xc4, 0x9b, 0x9a, 0x9a, 0x92, + 0x33, 0x0f, 0x14, 0x67, 0x98, 0x51, 0x9d, 0xff, + 0xef, 0x59, 0xb7, 0x17, 0xc2, 0x16, 0x72, 0x18, + }, + }, + .public_key_rsp = { + .x = { + 0x9e, 0x44, 0x09, 0x57, 0xb7, 0x01, 0x78, 0x5b, + 0x4e, 0x50, 0x0d, 0x99, 0x0d, 0x52, 0x88, 0x24, + 0x19, 0xf5, 0x40, 0x53, 0x06, 0x1e, 0x68, 0xd0, + 0xfd, 0xd2, 0x84, 0x8b, 0xae, 0x9d, 0xf7, 0xd9, + }, + .y = { + 0xc2, 0xe7, 0xe0, 0x01, 0xb3, 0x2a, 0x1b, 0x01, + 0x19, 0xd1, 0x14, 0xb5, 0xc8, 0x98, 0x02, 0x2a, + 0xbe, 0x6b, 0x33, 0x1a, 0x99, 0x18, 0x77, 0x23, + 0xd4, 0x8b, 0x8c, 0x09, 0xf5, 0x77, 0x20, 0xa0, + }, + }, + .confirm_rsp[0] = { + .value = { + 0xbd, 0x85, 0xbe, 0x80, 0xd9, 0x77, 0x16, 0xa3, + 0x65, 0x1a, 0xdf, 0xff, 0x5a, 0x6f, 0x8b, 0x37, + }, + }, + .random_req[0] = { + .value = { + 0xb5, 0x59, 0x7c, 0x8e, 0x7b, 0x01, 0xac, 0x09, + 0x8f, 0xe8, 0x97, 0x98, 0x8d, 0x3f, 0xb7, 0x63, + }, + }, + .random_rsp[0] = { + .value = { + 0x86, 0x1f, 0x76, 0x11, 0x2e, 0x83, 0xed, 0x99, + 0x9b, 0xc0, 0x9a, 0xab, 0x7f, 0x94, 0x20, 0xcb, + }, + }, + .dhkey_check_req = { + .value = { + 0xe0, 0x9f, 0x87, 0x87, 0x9f, 0x82, 0xc5, 0x06, + 0x5f, 0x11, 0xfa, 0xa0, 0xe3, 0xbf, 0x72, 0xf2, + }, + }, + .dhkey_check_rsp = { + .value = { + 0x26, 0xc2, 0xf1, 0xb9, 0xf1, 0xc2, 0xbd, 0xcb, + 0xdb, 0x94, 0x96, 0x8e, 0x08, 0xcc, 0x53, 0xd4, + }, + }, + .sign_info_req = { + .sig_key = { + 0x74, 0x14, 0xcd, 0x5a, 0x49, 0x2e, 0xb6, 0x0d, + 0xc6, 0x82, 0xb0, 0x0f, 0x9c, 0xe6, 0xe5, 0x41, + }, + }, + .id_info_rsp = { + .irk = { + 0xef, 0x8d, 0xe2, 0x16, 0x4f, 0xec, 0x43, 0x0d, + 0xbf, 0x5b, 0xdd, 0x34, 0xc0, 0x53, 0x1e, 0xb8, + }, + }, + .id_addr_info_rsp = { + .addr_type = 0, + .bd_addr = { + 0x01, 0x01, 0x01, 0x07, 0x08, 0x01, + }, + }, + .sign_info_rsp = { + .sig_key = { + 0xfb, 0x93, 0xa2, 0xb7, 0x4d, 0x0e, 0xcc, 0x92, + 0xe4, 0xbf, 0x5b, 0x3c, 0x6d, 0x87, 0x5b, 0x2d, + }, + }, + .ltk = { + 0x2e, 0x6c, 0x8b, 0xdb, 0x9e, 0x19, 0x3e, 0x3d, + 0x4d, 0x6d, 0x29, 0xbc, 0x89, 0xca, 0x57, 0xed, + }, + .pair_alg = BLE_SM_PAIR_ALG_JW, + .authenticated = 0, + .passkey_info = { + .passkey = { + .action = BLE_SM_IOACT_NONE, + }, + }, + }; + ble_sm_test_util_us_sc_good(¶ms); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +/** + * Secure connections pairing + * Master: us + * Pair algorithm: passkey entry + * Initiator IO capabilities: 2 + * Responder IO capabilities: 4 + * Bonding: true + * Initiator address type: 0 + * Responder address type: 0 + * Initiator key distribution: 7 + * Responder key distribution: 5 + */ +TEST_CASE_SELF(ble_sm_sc_us_pk_iio2_rio4_b1_iat0_rat0_ik7_rk5) +{ + struct ble_sm_test_params params; + + params = (struct ble_sm_test_params) { + .init_id_addr = { + 0x01, 0x01, 0x01, 0x07, 0x08, 0x01, + }, + .resp_id_addr = { + 0xca, 0x61, 0xa0, 0x67, 0x94, 0xe0, + }, + .pair_req = { + .io_cap = 0x02, + .oob_data_flag = 0x00, + .authreq = 0x0d, + .max_enc_key_size = 0x10, + .init_key_dist = 0x07, + .resp_key_dist = 0x07, + }, + .pair_rsp = { + .io_cap = 0x04, + .oob_data_flag = 0x00, + .authreq = 0x0d, + .max_enc_key_size = 0x10, + .init_key_dist = 0x07, + .resp_key_dist = 0x05, + }, + .our_priv_key = { + 0xb1, 0x6b, 0x4f, 0x81, 0xbc, 0xe3, 0x60, 0x9e, + 0x00, 0x20, 0xf1, 0x73, 0x3e, 0xfb, 0xcc, 0x6e, + 0x8c, 0xb6, 0xd2, 0x51, 0xd9, 0x36, 0x8a, 0x6d, + 0xca, 0x8c, 0xd7, 0xbe, 0x96, 0x03, 0xdf, 0xd6, + }, + .public_key_req = { + .x = { + 0xe5, 0x0f, 0x02, 0x0a, 0x37, 0x90, 0x94, 0x5a, + 0x06, 0x21, 0xf7, 0xbc, 0xd5, 0xbe, 0xb9, 0x24, + 0x8a, 0x35, 0xfd, 0xf8, 0x5e, 0xe2, 0x70, 0xd5, + 0x5a, 0xe8, 0xe7, 0xdd, 0x13, 0x90, 0xeb, 0xd4, + }, + .y = { + 0x41, 0xc8, 0x51, 0x1a, 0x25, 0x44, 0x01, 0x53, + 0x42, 0x74, 0x07, 0x9c, 0x18, 0xe6, 0x3b, 0x8a, + 0xce, 0x7a, 0x37, 0x1f, 0x18, 0x5c, 0x02, 0x7c, + 0x67, 0x16, 0xf5, 0x30, 0x2b, 0x31, 0xa9, 0xc7, + }, + }, + .public_key_rsp = { + .x = { + 0x1b, 0xd2, 0x03, 0x79, 0xb4, 0x9b, 0x0a, 0xd7, + 0x1b, 0x28, 0x73, 0x2a, 0xd7, 0xe6, 0xa0, 0xd4, + 0x2d, 0x95, 0x8d, 0x29, 0xaf, 0x6a, 0xab, 0xee, + 0xa0, 0x0d, 0x13, 0x4d, 0xe7, 0x16, 0x76, 0x91, + }, + .y = { + 0x2a, 0x26, 0x2c, 0x50, 0x55, 0xd1, 0x2b, 0x83, + 0xf6, 0x5f, 0xdb, 0x99, 0x5f, 0x85, 0xf6, 0x78, + 0x1c, 0x14, 0xed, 0xd3, 0x70, 0x5e, 0xe5, 0x2c, + 0x05, 0x1e, 0x5c, 0xec, 0xf8, 0x65, 0x43, 0x49, + }, + }, + .confirm_req[0] = { + .value = { + 0x55, 0x2c, 0xaa, 0x41, 0x59, 0x42, 0x4d, 0xfe, + 0x47, 0x74, 0xcd, 0x2b, 0x11, 0xab, 0x21, 0xe6, + }, + }, + .confirm_rsp[0] = { + .value = { + 0x6a, 0x3c, 0x45, 0xf5, 0xb2, 0xe2, 0x04, 0x30, + 0xde, 0xd6, 0x3c, 0x6d, 0x85, 0x00, 0x00, 0x2c, + }, + }, + .random_req[0] = { + .value = { + 0x78, 0x06, 0x04, 0x60, 0x76, 0xe9, 0xc4, 0x5a, + 0xfb, 0x34, 0x44, 0xae, 0x45, 0xa0, 0x84, 0xde, + }, + }, + .random_rsp[0] = { + .value = { + 0x91, 0xc8, 0xfd, 0x1b, 0xb2, 0x85, 0x08, 0x76, + 0xd3, 0xf1, 0xc4, 0xa0, 0xfa, 0x92, 0x8c, 0x94, + }, + }, + .confirm_req[1] = { + .value = { + 0xb1, 0x2f, 0x68, 0x35, 0xa1, 0xa5, 0x84, 0xb1, + 0x4f, 0x1a, 0xb1, 0xb5, 0xf0, 0xb2, 0xbe, 0x61, + }, + }, + .confirm_rsp[1] = { + .value = { + 0x07, 0xd8, 0x43, 0x74, 0xe8, 0x42, 0xf3, 0xf1, + 0x87, 0x3d, 0x9e, 0x92, 0xea, 0x33, 0xe8, 0x54, + }, + }, + .random_req[1] = { + .value = { + 0x4c, 0xb7, 0xcc, 0x6d, 0x90, 0x9f, 0x1e, 0x2d, + 0x9d, 0x1e, 0x52, 0xa7, 0xe0, 0x0c, 0x7b, 0xf7, + }, + }, + .random_rsp[1] = { + .value = { + 0x5c, 0x32, 0x82, 0xc8, 0x76, 0x17, 0x3b, 0x18, + 0x66, 0xda, 0xbf, 0xc3, 0x13, 0x49, 0x05, 0xfb, + }, + }, + .confirm_req[2] = { + .value = { + 0x27, 0x61, 0x4d, 0x04, 0x64, 0xa9, 0x58, 0xf1, + 0xe0, 0xf9, 0xe5, 0x78, 0x0b, 0x54, 0x89, 0x0a, + }, + }, + .confirm_rsp[2] = { + .value = { + 0xe4, 0x8f, 0xdb, 0xc8, 0x35, 0xed, 0x4e, 0x7d, + 0xbc, 0x92, 0x7f, 0x58, 0x02, 0xaa, 0xbf, 0x6b, + }, + }, + .random_req[2] = { + .value = { + 0xfe, 0x85, 0x08, 0xe0, 0x35, 0x90, 0x13, 0xa9, + 0xd3, 0xcf, 0xb6, 0x6d, 0x36, 0xaf, 0xbd, 0x59, + }, + }, + .random_rsp[2] = { + .value = { + 0x47, 0x40, 0x8e, 0x97, 0xe3, 0xfe, 0x8f, 0x52, + 0x29, 0x5e, 0x6b, 0x44, 0xdf, 0x0d, 0x60, 0xf4, + }, + }, + .confirm_req[3] = { + .value = { + 0xac, 0xab, 0x13, 0x7c, 0x1a, 0x6e, 0x7a, 0xdb, + 0xf6, 0xe8, 0x72, 0x9f, 0xc5, 0xc3, 0x99, 0x1b, + }, + }, + .confirm_rsp[3] = { + .value = { + 0x79, 0xf2, 0xd1, 0x89, 0x5e, 0xa5, 0xa2, 0x90, + 0xee, 0x25, 0x36, 0x81, 0x5a, 0x87, 0x20, 0x82, + }, + }, + .random_req[3] = { + .value = { + 0xd4, 0x46, 0xa0, 0xc4, 0x3d, 0xae, 0x22, 0x06, + 0xaf, 0x5d, 0x93, 0x96, 0xb7, 0x06, 0xc3, 0x61, + }, + }, + .random_rsp[3] = { + .value = { + 0x5f, 0x81, 0x97, 0x8b, 0x52, 0x87, 0x1c, 0x67, + 0xe0, 0x04, 0xcc, 0x50, 0xd9, 0x2b, 0x16, 0xb5, + }, + }, + .confirm_req[4] = { + .value = { + 0x6c, 0x51, 0xc3, 0x61, 0x77, 0x7f, 0xf1, 0x05, + 0x9e, 0x0f, 0xba, 0xfd, 0x32, 0x02, 0x09, 0x45, + }, + }, + .confirm_rsp[4] = { + .value = { + 0x54, 0xe5, 0x24, 0x81, 0x62, 0x68, 0xe2, 0x45, + 0x86, 0x2c, 0x11, 0x28, 0x15, 0xa8, 0x8e, 0x5b, + }, + }, + .random_req[4] = { + .value = { + 0xbb, 0x29, 0x3a, 0xba, 0xe6, 0x4f, 0x06, 0xcf, + 0xa3, 0x13, 0x27, 0xf2, 0xcb, 0xe4, 0xd2, 0xe6, + }, + }, + .random_rsp[4] = { + .value = { + 0x50, 0xba, 0xd0, 0x0e, 0x26, 0xab, 0x04, 0xf8, + 0xa2, 0x03, 0x1e, 0x63, 0x9a, 0xf7, 0x15, 0xdc, + }, + }, + .confirm_req[5] = { + .value = { + 0x12, 0x3e, 0xfe, 0x5a, 0xb1, 0x09, 0x6f, 0x17, + 0xb7, 0x77, 0x7e, 0x65, 0x88, 0xd4, 0x95, 0x56, + }, + }, + .confirm_rsp[5] = { + .value = { + 0xc6, 0x9b, 0xac, 0xde, 0x7e, 0x03, 0x7a, 0xd3, + 0xf1, 0xff, 0x3c, 0x4f, 0x4a, 0x85, 0xba, 0x73, + }, + }, + .random_req[5] = { + .value = { + 0x17, 0xd5, 0x5e, 0x69, 0x30, 0x2c, 0x1f, 0x01, + 0x87, 0x9c, 0xd6, 0xd2, 0xe4, 0x48, 0x8c, 0x84, + }, + }, + .random_rsp[5] = { + .value = { + 0x9d, 0x54, 0x83, 0x4a, 0xcd, 0x93, 0x7c, 0x1e, + 0x5b, 0xaf, 0xd2, 0x66, 0x8c, 0x2d, 0xaa, 0xc3, + }, + }, + .confirm_req[6] = { + .value = { + 0xdc, 0x24, 0x69, 0xa8, 0xd3, 0xa9, 0x17, 0x11, + 0x08, 0x37, 0x1a, 0x1e, 0x92, 0x03, 0xee, 0x36, + }, + }, + .confirm_rsp[6] = { + .value = { + 0x98, 0xf8, 0x72, 0x71, 0x99, 0xa0, 0xbd, 0xcd, + 0xb1, 0x97, 0x4c, 0x8a, 0xb8, 0xa8, 0x1a, 0x52, + }, + }, + .random_req[6] = { + .value = { + 0xbf, 0xb1, 0x8e, 0xa5, 0x14, 0xe3, 0xeb, 0x9e, + 0x29, 0x27, 0xe0, 0x19, 0xb1, 0xb2, 0x5c, 0xfe, + }, + }, + .random_rsp[6] = { + .value = { + 0xae, 0x8a, 0x92, 0x78, 0x53, 0x7b, 0xdb, 0x8c, + 0xec, 0x3a, 0x99, 0x2b, 0x94, 0xf1, 0x17, 0xfe, + }, + }, + .confirm_req[7] = { + .value = { + 0xcf, 0xaf, 0x70, 0x73, 0x53, 0x65, 0x89, 0x57, + 0x36, 0x98, 0xd2, 0x28, 0x86, 0x79, 0xfe, 0x85, + }, + }, + .confirm_rsp[7] = { + .value = { + 0x0d, 0x2d, 0x77, 0x8a, 0x21, 0x11, 0xd9, 0x61, + 0x9f, 0x80, 0x32, 0x8a, 0x32, 0x09, 0x42, 0x42, + }, + }, + .random_req[7] = { + .value = { + 0x8b, 0xd2, 0x53, 0xcd, 0x96, 0xd1, 0x14, 0xb5, + 0xea, 0x17, 0xb1, 0xa3, 0xa8, 0xfc, 0x3c, 0x2b, + }, + }, + .random_rsp[7] = { + .value = { + 0xc2, 0x4f, 0x84, 0x60, 0x54, 0x79, 0x16, 0xed, + 0x1a, 0x6e, 0x78, 0xa0, 0x99, 0x58, 0xf2, 0x94, + }, + }, + .confirm_req[8] = { + .value = { + 0x9a, 0x4c, 0xbc, 0x9c, 0x55, 0x15, 0xa2, 0x4f, + 0xa2, 0x5d, 0x3b, 0xa7, 0x43, 0xb3, 0x9c, 0x63, + }, + }, + .confirm_rsp[8] = { + .value = { + 0xa3, 0xb1, 0x88, 0xa5, 0x70, 0xca, 0xa3, 0xa9, + 0x67, 0x2a, 0xac, 0x99, 0x5e, 0x61, 0x68, 0xa0, + }, + }, + .random_req[8] = { + .value = { + 0xcf, 0xcf, 0x5b, 0x94, 0xe0, 0xb2, 0x9d, 0x5a, + 0x86, 0x71, 0x45, 0xce, 0xd9, 0xce, 0x13, 0xba, + }, + }, + .random_rsp[8] = { + .value = { + 0x10, 0x96, 0x8a, 0x50, 0xa4, 0xd0, 0xaa, 0x5f, + 0xd6, 0x32, 0xdb, 0x09, 0x7e, 0x22, 0x96, 0x42, + }, + }, + .confirm_req[9] = { + .value = { + 0xf0, 0x90, 0x61, 0x25, 0x04, 0x29, 0x4f, 0xb6, + 0x8b, 0xd5, 0x73, 0x49, 0xbd, 0xf7, 0x9b, 0xe7, + }, + }, + .confirm_rsp[9] = { + .value = { + 0x5b, 0xe6, 0xb4, 0x3f, 0x1b, 0x77, 0x12, 0x75, + 0x84, 0x94, 0xc6, 0x07, 0xfa, 0xa1, 0x41, 0x94, + }, + }, + .random_req[9] = { + .value = { + 0x3d, 0x1a, 0xa3, 0x95, 0xec, 0x72, 0x84, 0xf4, + 0xc5, 0xcd, 0xaa, 0x48, 0xe9, 0x0c, 0x0f, 0xe3, + }, + }, + .random_rsp[9] = { + .value = { + 0x8a, 0x5a, 0x53, 0xfc, 0x07, 0x52, 0x01, 0xb9, + 0xe9, 0x2d, 0xe7, 0x9d, 0x8c, 0x7c, 0xc7, 0xb3, + }, + }, + .confirm_req[10] = { + .value = { + 0xe7, 0x8e, 0xc5, 0x08, 0x7f, 0x7e, 0xb8, 0xdc, + 0x05, 0x88, 0x3a, 0x92, 0x5a, 0xf5, 0x9b, 0xa9, + }, + }, + .confirm_rsp[10] = { + .value = { + 0xf7, 0xa2, 0xb6, 0xec, 0xcd, 0xef, 0xcb, 0xb7, + 0x6f, 0xc3, 0xac, 0x17, 0xe2, 0xfd, 0xfa, 0x42, + }, + }, + .random_req[10] = { + .value = { + 0x0d, 0xd1, 0xa2, 0x1d, 0xff, 0x74, 0xc5, 0x99, + 0xe0, 0x67, 0x07, 0x99, 0x95, 0x75, 0x39, 0x76, + }, + }, + .random_rsp[10] = { + .value = { + 0x2f, 0x13, 0xd1, 0x59, 0xfe, 0x20, 0x60, 0xf0, + 0x02, 0x0c, 0xea, 0x79, 0xd7, 0x40, 0x86, 0x85, + }, + }, + .confirm_req[11] = { + .value = { + 0x8b, 0x57, 0x87, 0xdd, 0xb1, 0xcc, 0x2d, 0x65, + 0xc1, 0xba, 0xac, 0x88, 0x48, 0x23, 0xda, 0xe7, + }, + }, + .confirm_rsp[11] = { + .value = { + 0xb3, 0xc4, 0x2e, 0xea, 0x33, 0xaf, 0x12, 0x9c, + 0xb5, 0xab, 0xa1, 0x95, 0x30, 0xca, 0x46, 0x48, + }, + }, + .random_req[11] = { + .value = { + 0x35, 0x57, 0xcd, 0xd5, 0xd2, 0xf8, 0xd7, 0xf2, + 0x7b, 0xe3, 0xd7, 0xba, 0x31, 0xa5, 0xca, 0xfd, + }, + }, + .random_rsp[11] = { + .value = { + 0xe2, 0x3b, 0x20, 0xbe, 0xec, 0xa5, 0x34, 0x3b, + 0x76, 0x23, 0x53, 0x28, 0x36, 0xc4, 0x60, 0x13, + }, + }, + .confirm_req[12] = { + .value = { + 0xc9, 0xfe, 0x03, 0x49, 0xe4, 0xff, 0x7e, 0xf7, + 0x00, 0xd1, 0x2b, 0x13, 0xb1, 0x15, 0x6e, 0x92, + }, + }, + .confirm_rsp[12] = { + .value = { + 0xbc, 0xa2, 0xf2, 0x03, 0x5c, 0xfd, 0x20, 0x7b, + 0xd0, 0x1f, 0xd6, 0x50, 0xec, 0xc6, 0x7b, 0x31, + }, + }, + .random_req[12] = { + .value = { + 0x04, 0x50, 0xea, 0xb8, 0xca, 0x36, 0x1a, 0x61, + 0x92, 0xed, 0xa0, 0x67, 0x78, 0x15, 0x10, 0xb5, + }, + }, + .random_rsp[12] = { + .value = { + 0x0c, 0x8e, 0x9d, 0x7b, 0x9d, 0x7e, 0xda, 0x23, + 0xbb, 0x61, 0xd9, 0xff, 0x46, 0x77, 0x33, 0x1b, + }, + }, + .confirm_req[13] = { + .value = { + 0x9a, 0xff, 0xd6, 0xe5, 0x1a, 0xc3, 0xd3, 0x37, + 0x34, 0xeb, 0x3e, 0x3a, 0x8e, 0x0b, 0x86, 0xb4, + }, + }, + .confirm_rsp[13] = { + .value = { + 0xf6, 0x32, 0x19, 0xb4, 0x08, 0x6b, 0x8a, 0x0f, + 0xc9, 0x9c, 0x1b, 0x68, 0xb8, 0xa0, 0xd0, 0xc9, + }, + }, + .random_req[13] = { + .value = { + 0x86, 0xeb, 0x5c, 0xf9, 0x33, 0x54, 0x7d, 0xe4, + 0xa4, 0xe2, 0xe1, 0xf6, 0x6b, 0xea, 0x34, 0xed, + }, + }, + .random_rsp[13] = { + .value = { + 0xad, 0x53, 0xa0, 0x6e, 0xde, 0x1d, 0xda, 0x99, + 0x31, 0x45, 0xe5, 0x3a, 0x73, 0xa1, 0x5e, 0xe1, + }, + }, + .confirm_req[14] = { + .value = { + 0x93, 0xd4, 0xe0, 0xaa, 0x0c, 0x91, 0xba, 0xde, + 0xc9, 0x5c, 0x68, 0xb0, 0xce, 0xb6, 0x84, 0xcd, + }, + }, + .confirm_rsp[14] = { + .value = { + 0x85, 0xc7, 0x05, 0x02, 0x21, 0x9d, 0x4c, 0x4c, + 0x16, 0xf7, 0x8f, 0x7b, 0xaa, 0xb4, 0x8f, 0x37, + }, + }, + .random_req[14] = { + .value = { + 0x84, 0xfd, 0xf1, 0x39, 0x1a, 0x9a, 0xa5, 0xb8, + 0x49, 0xc0, 0x66, 0xdc, 0x33, 0x71, 0x32, 0x87, + }, + }, + .random_rsp[14] = { + .value = { + 0x5d, 0xaf, 0x38, 0xcd, 0xb5, 0x83, 0xaa, 0xa0, + 0xab, 0x30, 0x82, 0xed, 0x6f, 0xd2, 0x75, 0xe7, + }, + }, + .confirm_req[15] = { + .value = { + 0x88, 0x12, 0xe8, 0x89, 0xd4, 0x52, 0x6d, 0xac, + 0x61, 0x2a, 0x85, 0x85, 0x1e, 0x9c, 0x82, 0x21, + }, + }, + .confirm_rsp[15] = { + .value = { + 0xc1, 0xe9, 0xcd, 0x21, 0x29, 0x6a, 0x78, 0xe4, + 0x7b, 0x7d, 0x73, 0x25, 0x9e, 0x9b, 0x95, 0x8b, + }, + }, + .random_req[15] = { + .value = { + 0x95, 0x87, 0x9d, 0x5a, 0x10, 0x14, 0xa0, 0xdf, + 0x5e, 0x02, 0x22, 0x39, 0x23, 0xc9, 0xbc, 0xba, + }, + }, + .random_rsp[15] = { + .value = { + 0x1b, 0x91, 0xe2, 0xdf, 0xca, 0xfe, 0x2b, 0x61, + 0x33, 0x8c, 0x83, 0xbf, 0xcf, 0xc3, 0x72, 0xcc, + }, + }, + .confirm_req[16] = { + .value = { + 0xce, 0xc9, 0x68, 0xf7, 0xea, 0x41, 0x18, 0x5c, + 0x16, 0x6a, 0x98, 0x13, 0x0c, 0x10, 0xc2, 0xa3, + }, + }, + .confirm_rsp[16] = { + .value = { + 0x97, 0x73, 0xc9, 0x72, 0x68, 0x99, 0x63, 0xed, + 0x81, 0x3b, 0x5c, 0xee, 0x37, 0xfc, 0xca, 0xae, + }, + }, + .random_req[16] = { + .value = { + 0x5b, 0x85, 0xb0, 0x1b, 0xc3, 0xde, 0x18, 0xba, + 0xc1, 0xc7, 0x89, 0x99, 0xfe, 0xcd, 0xdb, 0x6a, + }, + }, + .random_rsp[16] = { + .value = { + 0x5e, 0x1a, 0xcb, 0xbc, 0xda, 0x41, 0x06, 0x5a, + 0x14, 0x34, 0x3a, 0xb1, 0xa1, 0x6f, 0xb2, 0xd8, + }, + }, + .confirm_req[17] = { + .value = { + 0x1d, 0x59, 0x8a, 0xb0, 0x19, 0xe5, 0xff, 0x45, + 0xb6, 0xc3, 0x33, 0x64, 0xd1, 0x6e, 0xee, 0xdd, + }, + }, + .confirm_rsp[17] = { + .value = { + 0x4c, 0x9b, 0xe8, 0x68, 0x52, 0x34, 0xef, 0xe1, + 0x84, 0xbd, 0x37, 0x85, 0x53, 0x0d, 0xd5, 0xc1, + }, + }, + .random_req[17] = { + .value = { + 0xa6, 0xf7, 0x97, 0x18, 0x9a, 0x3e, 0x9d, 0xcf, + 0x91, 0xa3, 0xa3, 0x8e, 0xda, 0x8f, 0x8f, 0x90, + }, + }, + .random_rsp[17] = { + .value = { + 0x94, 0x10, 0x19, 0x17, 0x8d, 0x0a, 0x72, 0xfd, + 0x24, 0x9d, 0xfd, 0x37, 0x4e, 0xdf, 0x4c, 0x30, + }, + }, + .confirm_req[18] = { + .value = { + 0xfc, 0x64, 0x8a, 0x8b, 0x37, 0x17, 0x90, 0x6d, + 0x25, 0x0e, 0xc6, 0x18, 0xc9, 0xc9, 0xc2, 0x2a, + }, + }, + .confirm_rsp[18] = { + .value = { + 0x50, 0x98, 0x86, 0xf5, 0xc0, 0xda, 0x45, 0x2d, + 0xea, 0xc8, 0x9d, 0x28, 0x04, 0xd8, 0x73, 0x6f, + }, + }, + .random_req[18] = { + .value = { + 0x13, 0x10, 0x38, 0xe8, 0x17, 0x6d, 0x72, 0xd5, + 0x94, 0xaf, 0xed, 0x4f, 0x23, 0xa0, 0x41, 0xfc, + }, + }, + .random_rsp[18] = { + .value = { + 0xdf, 0xed, 0xf7, 0x08, 0xce, 0x64, 0xbc, 0x11, + 0x41, 0x7a, 0xd9, 0xf7, 0x4a, 0xd9, 0x4a, 0x15, + }, + }, + .confirm_req[19] = { + .value = { + 0xae, 0x24, 0x8f, 0xdf, 0xb0, 0x57, 0xc4, 0x9c, + 0xe6, 0xae, 0x9b, 0xc2, 0x4d, 0x3d, 0x1c, 0xcb, + }, + }, + .confirm_rsp[19] = { + .value = { + 0xcc, 0x5c, 0xa3, 0xbe, 0xd7, 0x83, 0xee, 0x60, + 0x80, 0xff, 0x5f, 0x1a, 0x07, 0xbf, 0x4c, 0x33, + }, + }, + .random_req[19] = { + .value = { + 0x93, 0xc3, 0x62, 0x06, 0xcb, 0xe5, 0xb0, 0x01, + 0x02, 0x18, 0xa2, 0x50, 0x4c, 0x73, 0xa2, 0x27, + }, + }, + .random_rsp[19] = { + .value = { + 0x11, 0x2a, 0xd3, 0x06, 0x28, 0x9c, 0xdf, 0x73, + 0xa5, 0xa4, 0xe5, 0x1e, 0x07, 0xcf, 0xee, 0x71, + }, + }, + .dhkey_check_req = { + .value = { + 0x73, 0xa0, 0x40, 0x58, 0x78, 0x20, 0x5f, 0x2c, + 0xf4, 0x19, 0x23, 0xa8, 0x74, 0xbd, 0xc2, 0x3e, + }, + }, + .dhkey_check_rsp = { + .value = { + 0x5a, 0x30, 0xbc, 0xce, 0xec, 0xdf, 0xf0, 0x32, + 0x3c, 0x18, 0xa3, 0xd3, 0x3f, 0x20, 0x87, 0x10, + }, + }, + .sign_info_req = { + .sig_key = { + 0x2e, 0x81, 0x09, 0xde, 0x32, 0xc5, 0x28, 0x34, + 0xe1, 0x45, 0x4a, 0x35, 0x49, 0xef, 0xa2, 0xed, + }, + }, + .id_info_rsp = { + .irk = { + 0xef, 0x8d, 0xe2, 0x16, 0x4f, 0xec, 0x43, 0x0d, + 0xbf, 0x5b, 0xdd, 0x34, 0xc0, 0x53, 0x1e, 0xb8, + }, + }, + .id_addr_info_rsp = { + .addr_type = 0, + .bd_addr = { + 0x01, 0x01, 0x01, 0x07, 0x08, 0x01, + }, + }, + .sign_info_rsp = { + .sig_key = { + 0x90, 0x3d, 0x26, 0x65, 0xc1, 0xd1, 0x5a, 0x9d, + 0xda, 0xab, 0x0d, 0x00, 0x05, 0x0e, 0x6c, 0x5d, + }, + }, + .ltk = { + 0xf1, 0x41, 0x1a, 0x5b, 0x60, 0xc1, 0x43, 0xc6, + 0x80, 0x34, 0x5e, 0x7f, 0xd8, 0x0c, 0x75, 0xdc, + }, + .pair_alg = BLE_SM_PAIR_ALG_PASSKEY, + .authenticated = 1, + .passkey_info = { + .passkey = { + .action = BLE_SM_IOACT_INPUT, + .passkey = 516645, + }, + }, + }; + ble_sm_test_util_us_sc_good(¶ms); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +/** + * Secure connections pairing + * Master: us + * Pair algorithm: passkey entry + * Initiator IO capabilities: 0 + * Responder IO capabilities: 4 + * Bonding: true + * Initiator address type: 0 + * Responder address type: 0 + * Initiator key distribution: 7 + * Responder key distribution: 5 + */ +TEST_CASE_SELF(ble_sm_sc_us_pk_iio0_rio4_b1_iat0_rat0_ik7_rk5) +{ + struct ble_sm_test_params params; + + params = (struct ble_sm_test_params) { + .init_id_addr = { + 0x01, 0x01, 0x01, 0x07, 0x08, 0x01, + }, + .resp_id_addr = { + 0xca, 0x61, 0xa0, 0x67, 0x94, 0xe0, + }, + .pair_req = { + .io_cap = 0x00, + .oob_data_flag = 0x00, + .authreq = 0x0d, + .max_enc_key_size = 0x10, + .init_key_dist = 0x07, + .resp_key_dist = 0x07, + }, + .pair_rsp = { + .io_cap = 0x04, + .oob_data_flag = 0x00, + .authreq = 0x0d, + .max_enc_key_size = 0x10, + .init_key_dist = 0x07, + .resp_key_dist = 0x05, + }, + .our_priv_key = { + 0xb1, 0x6b, 0x4f, 0x81, 0xbc, 0xe3, 0x60, 0x9e, + 0x00, 0x20, 0xf1, 0x73, 0x3e, 0xfb, 0xcc, 0x6e, + 0x8c, 0xb6, 0xd2, 0x51, 0xd9, 0x36, 0x8a, 0x6d, + 0xca, 0x8c, 0xd7, 0xbe, 0x96, 0x03, 0xdf, 0xd6, + }, + .public_key_req = { + .x = { + 0xe5, 0x0f, 0x02, 0x0a, 0x37, 0x90, 0x94, 0x5a, + 0x06, 0x21, 0xf7, 0xbc, 0xd5, 0xbe, 0xb9, 0x24, + 0x8a, 0x35, 0xfd, 0xf8, 0x5e, 0xe2, 0x70, 0xd5, + 0x5a, 0xe8, 0xe7, 0xdd, 0x13, 0x90, 0xeb, 0xd4, + }, + .y = { + 0x41, 0xc8, 0x51, 0x1a, 0x25, 0x44, 0x01, 0x53, + 0x42, 0x74, 0x07, 0x9c, 0x18, 0xe6, 0x3b, 0x8a, + 0xce, 0x7a, 0x37, 0x1f, 0x18, 0x5c, 0x02, 0x7c, + 0x67, 0x16, 0xf5, 0x30, 0x2b, 0x31, 0xa9, 0xc7, + }, + }, + .public_key_rsp = { + .x = { + 0x03, 0x0d, 0x13, 0x55, 0xd9, 0xee, 0x3f, 0xac, + 0x8e, 0x8a, 0xa6, 0x2a, 0xcb, 0x60, 0x35, 0xb9, + 0xb2, 0x4d, 0x63, 0x91, 0x5e, 0xa1, 0xdd, 0xdf, + 0x60, 0xdc, 0x6e, 0x09, 0xb9, 0x9e, 0xf1, 0x4d, + }, + .y = { + 0xa8, 0x09, 0x31, 0x1e, 0x39, 0x96, 0x74, 0x41, + 0xea, 0x19, 0x4f, 0x24, 0x36, 0x57, 0x7c, 0x9f, + 0x21, 0xa3, 0xad, 0xa1, 0x3d, 0xe2, 0x1c, 0x6a, + 0xd6, 0xc9, 0xdb, 0xff, 0xce, 0x0a, 0x94, 0x12, + }, + }, + .confirm_req[0] = { + .value = { + 0x3b, 0x3d, 0xb2, 0x2f, 0x72, 0x0f, 0x93, 0x19, + 0x95, 0xdb, 0x88, 0xdf, 0x5d, 0x58, 0x95, 0x37, + }, + }, + .confirm_rsp[0] = { + .value = { + 0x98, 0xab, 0x20, 0x8d, 0x51, 0x3b, 0x6c, 0x29, + 0x2d, 0x73, 0x15, 0xf6, 0x6d, 0x6d, 0xb9, 0xb3, + }, + }, + .random_req[0] = { + .value = { + 0xc1, 0xdf, 0x20, 0x3d, 0x7b, 0xcb, 0x5f, 0xe2, + 0x9a, 0x23, 0x9c, 0xba, 0x2f, 0x42, 0x3c, 0xb8, + }, + }, + .random_rsp[0] = { + .value = { + 0x7d, 0x82, 0xb4, 0xae, 0x41, 0xdb, 0x67, 0x8f, + 0x54, 0x01, 0x21, 0x64, 0x31, 0xd4, 0xfc, 0xb5, + }, + }, + .confirm_req[1] = { + .value = { + 0xc3, 0xa5, 0xd0, 0xdd, 0xd5, 0xec, 0x1d, 0xc3, + 0x14, 0x95, 0x79, 0xb2, 0x61, 0x4d, 0x4f, 0x36, + }, + }, + .confirm_rsp[1] = { + .value = { + 0xe2, 0x20, 0xf4, 0x4d, 0xa1, 0x9c, 0x83, 0x51, + 0x18, 0xf9, 0x35, 0x2a, 0x51, 0x50, 0xdf, 0xe7, + }, + }, + .random_req[1] = { + .value = { + 0x71, 0xcb, 0x01, 0xb4, 0x83, 0xdc, 0xd8, 0x54, + 0x0f, 0xe5, 0xd5, 0x6b, 0x6a, 0x0d, 0x98, 0xb6, + }, + }, + .random_rsp[1] = { + .value = { + 0x30, 0xbf, 0xd3, 0xfd, 0xf4, 0xc2, 0xa1, 0xd0, + 0xba, 0x4b, 0x27, 0x7c, 0x29, 0x98, 0x54, 0xa2, + }, + }, + .confirm_req[2] = { + .value = { + 0xf0, 0x92, 0xc4, 0xda, 0x8a, 0x17, 0x7c, 0xc6, + 0x14, 0x05, 0x7d, 0xbb, 0xfc, 0x7c, 0xcd, 0x0a, + }, + }, + .confirm_rsp[2] = { + .value = { + 0xf3, 0x89, 0xca, 0xe0, 0xfb, 0xbe, 0x8c, 0xc3, + 0x4c, 0x6c, 0x6e, 0x11, 0x36, 0x4e, 0xaa, 0x25, + }, + }, + .random_req[2] = { + .value = { + 0x78, 0x5a, 0xf0, 0x1e, 0x2a, 0x0d, 0x16, 0xb3, + 0x03, 0x4b, 0x4b, 0x68, 0x17, 0xe0, 0xf0, 0x82, + }, + }, + .random_rsp[2] = { + .value = { + 0xbf, 0x96, 0xdd, 0xf5, 0x30, 0x2a, 0xe9, 0x8c, + 0xb9, 0x13, 0xc5, 0xb7, 0x15, 0x1f, 0xa3, 0x9b, + }, + }, + .confirm_req[3] = { + .value = { + 0x36, 0xe4, 0x4c, 0x00, 0xe7, 0x0d, 0xee, 0xe4, + 0x95, 0xb8, 0x6a, 0xf9, 0xf7, 0x24, 0xef, 0xea, + }, + }, + .confirm_rsp[3] = { + .value = { + 0x2e, 0x90, 0x87, 0x85, 0xb8, 0x29, 0x93, 0x9e, + 0x38, 0xa6, 0xdb, 0x17, 0xb2, 0xa8, 0x32, 0x65, + }, + }, + .random_req[3] = { + .value = { + 0x0a, 0xee, 0x93, 0xf6, 0x56, 0x35, 0x8e, 0xed, + 0x3f, 0x45, 0xa5, 0x01, 0x59, 0xeb, 0xea, 0xa8, + }, + }, + .random_rsp[3] = { + .value = { + 0x38, 0xd0, 0xf8, 0x11, 0x5e, 0x47, 0x72, 0x66, + 0xce, 0x56, 0x9c, 0x81, 0x5f, 0x52, 0xd4, 0x9a, + }, + }, + .confirm_req[4] = { + .value = { + 0x2c, 0x98, 0x9b, 0x71, 0xe4, 0xde, 0x6d, 0x20, + 0x84, 0x30, 0xab, 0x7a, 0xfc, 0x43, 0x82, 0xc6, + }, + }, + .confirm_rsp[4] = { + .value = { + 0x76, 0xfe, 0x1f, 0x78, 0xaa, 0x42, 0xd5, 0xc6, + 0x9f, 0xe4, 0xa7, 0xc7, 0xb8, 0xd2, 0x1e, 0x59, + }, + }, + .random_req[4] = { + .value = { + 0x61, 0x5e, 0x47, 0xb1, 0x77, 0x6f, 0x04, 0xee, + 0x94, 0xc4, 0x6c, 0xa9, 0xf5, 0xf8, 0x11, 0x6e, + }, + }, + .random_rsp[4] = { + .value = { + 0xa5, 0xad, 0x98, 0x65, 0x28, 0xfc, 0x6b, 0x02, + 0x6d, 0x9a, 0x29, 0x61, 0x1c, 0x02, 0x0a, 0x6b, + }, + }, + .confirm_req[5] = { + .value = { + 0x4d, 0x55, 0x3e, 0x1f, 0x87, 0x12, 0xc7, 0x6c, + 0xd7, 0x9a, 0xa6, 0xf1, 0x6e, 0x48, 0xd3, 0x7d, + }, + }, + .confirm_rsp[5] = { + .value = { + 0xff, 0x77, 0x6e, 0xba, 0x1f, 0xb7, 0xbd, 0x0b, + 0x3f, 0xce, 0xd5, 0x39, 0x81, 0x17, 0x51, 0xfc, + }, + }, + .random_req[5] = { + .value = { + 0xf9, 0x2c, 0x77, 0x41, 0xcd, 0x9a, 0x10, 0x99, + 0xc6, 0x70, 0x5a, 0xc8, 0x24, 0x26, 0xb2, 0xc8, + }, + }, + .random_rsp[5] = { + .value = { + 0xa0, 0x44, 0x0a, 0x8b, 0xda, 0x6a, 0x74, 0x90, + 0x5f, 0x89, 0x44, 0xa5, 0x9a, 0x58, 0xd5, 0x08, + }, + }, + .confirm_req[6] = { + .value = { + 0x7e, 0x6e, 0x89, 0xc8, 0xbe, 0xde, 0x1c, 0xc3, + 0x45, 0xb6, 0x4c, 0x83, 0x71, 0xe2, 0xd6, 0xda, + }, + }, + .confirm_rsp[6] = { + .value = { + 0x4a, 0x29, 0x7b, 0x88, 0x97, 0xc1, 0x60, 0x85, + 0x32, 0x7d, 0xf1, 0xaa, 0x04, 0x13, 0x89, 0x11, + }, + }, + .random_req[6] = { + .value = { + 0x2a, 0xaf, 0x7d, 0x21, 0x4e, 0x14, 0xf5, 0x7e, + 0xcc, 0x39, 0xf7, 0x56, 0x45, 0x87, 0x23, 0x64, + }, + }, + .random_rsp[6] = { + .value = { + 0x74, 0xd2, 0xff, 0xf0, 0x19, 0xf7, 0x87, 0xe7, + 0x0d, 0x65, 0x27, 0x61, 0xea, 0x9e, 0x05, 0x3d, + }, + }, + .confirm_req[7] = { + .value = { + 0x4f, 0x77, 0x22, 0x08, 0x58, 0xed, 0x8c, 0x60, + 0xbf, 0xbc, 0x78, 0x0c, 0x80, 0xc9, 0xb7, 0x60, + }, + }, + .confirm_rsp[7] = { + .value = { + 0xd2, 0x47, 0xfd, 0xea, 0xa3, 0x32, 0x53, 0xc1, + 0x06, 0xcd, 0x64, 0xeb, 0x88, 0x64, 0x0e, 0xe5, + }, + }, + .random_req[7] = { + .value = { + 0xc8, 0xd0, 0x45, 0xa8, 0x29, 0xdb, 0x5a, 0x42, + 0xfe, 0x68, 0xa8, 0x7a, 0x0a, 0x13, 0x22, 0xa4, + }, + }, + .random_rsp[7] = { + .value = { + 0x78, 0x14, 0x46, 0xe2, 0x47, 0x0e, 0xd4, 0xb4, + 0xde, 0x35, 0x4a, 0x82, 0x4b, 0x32, 0x9b, 0x46, + }, + }, + .confirm_req[8] = { + .value = { + 0x24, 0x96, 0xe5, 0x50, 0xfa, 0xff, 0xba, 0xdf, + 0x6b, 0x76, 0x40, 0x60, 0x56, 0x5e, 0x5a, 0x66, + }, + }, + .confirm_rsp[8] = { + .value = { + 0x09, 0xfe, 0x15, 0x3e, 0x55, 0xe5, 0xbe, 0xb7, + 0x8d, 0xaa, 0x04, 0x59, 0xe6, 0x8b, 0x2c, 0x4e, + }, + }, + .random_req[8] = { + .value = { + 0x02, 0x25, 0xbe, 0x88, 0x37, 0xb4, 0x6e, 0xcb, + 0xbc, 0xa9, 0xef, 0x5a, 0xfd, 0x1a, 0x5f, 0x5f, + }, + }, + .random_rsp[8] = { + .value = { + 0x0b, 0x35, 0xdc, 0x9b, 0x3d, 0xf7, 0xa6, 0x99, + 0xf3, 0xb9, 0x3c, 0x73, 0x67, 0x0e, 0xcc, 0x12, + }, + }, + .confirm_req[9] = { + .value = { + 0x38, 0x1c, 0xf7, 0xf0, 0x31, 0xb1, 0x20, 0xa0, + 0x51, 0x1c, 0xf1, 0xbd, 0x67, 0xfa, 0x84, 0xb4, + }, + }, + .confirm_rsp[9] = { + .value = { + 0x8e, 0xa1, 0xc1, 0xf5, 0x39, 0xf0, 0x00, 0x49, + 0xfb, 0xfc, 0xdc, 0xdf, 0x87, 0x0e, 0x96, 0x7e, + }, + }, + .random_req[9] = { + .value = { + 0xd0, 0xed, 0x6c, 0x52, 0x20, 0x4b, 0x7b, 0x24, + 0xdd, 0x28, 0x53, 0x2d, 0x71, 0x76, 0xfb, 0x8f, + }, + }, + .random_rsp[9] = { + .value = { + 0xac, 0xd7, 0x34, 0x6b, 0x7b, 0x59, 0x9e, 0x9b, + 0x5b, 0x37, 0xc6, 0x5c, 0x3e, 0x9d, 0xe2, 0x13, + }, + }, + .confirm_req[10] = { + .value = { + 0xa6, 0xd7, 0xb6, 0xd6, 0xb5, 0x01, 0x4a, 0x02, + 0x0d, 0xf0, 0x22, 0xcb, 0x68, 0xad, 0x7d, 0x73, + }, + }, + .confirm_rsp[10] = { + .value = { + 0x01, 0xcc, 0x5f, 0xbc, 0xd0, 0x22, 0xa1, 0xb2, + 0x71, 0x9d, 0x5c, 0x97, 0xfa, 0xd3, 0x6a, 0xc7, + }, + }, + .random_req[10] = { + .value = { + 0x9f, 0x3a, 0x25, 0xc7, 0x9b, 0xb7, 0xb3, 0x51, + 0xff, 0xde, 0x3b, 0x1c, 0xdd, 0xf5, 0x08, 0x21, + }, + }, + .random_rsp[10] = { + .value = { + 0x75, 0x1e, 0x8d, 0xa4, 0x5b, 0x35, 0xec, 0xae, + 0x17, 0xda, 0xa5, 0x43, 0x76, 0x3c, 0x6a, 0x67, + }, + }, + .confirm_req[11] = { + .value = { + 0xfc, 0x0c, 0x3f, 0x86, 0xbf, 0xbe, 0x96, 0x0f, + 0x99, 0x11, 0xa5, 0x36, 0x03, 0xcd, 0xbd, 0x7f, + }, + }, + .confirm_rsp[11] = { + .value = { + 0x48, 0xcd, 0xc8, 0x89, 0xd6, 0x1c, 0x0d, 0xb1, + 0x90, 0x01, 0x0e, 0xea, 0x80, 0xbc, 0xff, 0xb3, + }, + }, + .random_req[11] = { + .value = { + 0xec, 0xfc, 0xe3, 0x0a, 0x97, 0xed, 0xe8, 0x51, + 0x5d, 0x64, 0x3c, 0x73, 0x59, 0x2e, 0x62, 0xac, + }, + }, + .random_rsp[11] = { + .value = { + 0x81, 0x74, 0x44, 0xca, 0xec, 0x38, 0x20, 0x6d, + 0x52, 0x27, 0x49, 0x55, 0x61, 0x97, 0x01, 0x34, + }, + }, + .confirm_req[12] = { + .value = { + 0x27, 0x8c, 0x88, 0x09, 0xcb, 0xd6, 0x45, 0xb7, + 0x30, 0x4b, 0x1b, 0xcd, 0xc3, 0xac, 0x83, 0xd6, + }, + }, + .confirm_rsp[12] = { + .value = { + 0xea, 0xbc, 0xe2, 0x43, 0xc8, 0xe0, 0x06, 0xd8, + 0x7b, 0x3e, 0xa4, 0x55, 0x95, 0xa2, 0x23, 0x9b, + }, + }, + .random_req[12] = { + .value = { + 0x68, 0x8f, 0xb6, 0x7b, 0x91, 0x0d, 0xc9, 0x30, + 0xe7, 0xb7, 0xb7, 0x7a, 0x79, 0x29, 0x59, 0x7d, + }, + }, + .random_rsp[12] = { + .value = { + 0xfd, 0xa1, 0x3d, 0xaf, 0x8d, 0xd2, 0xa0, 0x02, + 0x82, 0x92, 0xeb, 0x2e, 0x4d, 0x6c, 0x8d, 0x69, + }, + }, + .confirm_req[13] = { + .value = { + 0x6f, 0xa8, 0x20, 0x81, 0x1c, 0x4b, 0xe8, 0xe3, + 0xdc, 0xea, 0x39, 0xbd, 0xfb, 0xbf, 0x79, 0xc4, + }, + }, + .confirm_rsp[13] = { + .value = { + 0x2a, 0x09, 0xec, 0x32, 0x63, 0x3d, 0x38, 0x5d, + 0x28, 0xb2, 0xb1, 0x62, 0xee, 0x6c, 0x0a, 0x6c, + }, + }, + .random_req[13] = { + .value = { + 0x35, 0xb5, 0xc5, 0xc0, 0x74, 0x1f, 0x40, 0xac, + 0x23, 0x52, 0x02, 0x68, 0xdf, 0x62, 0x73, 0xca, + }, + }, + .random_rsp[13] = { + .value = { + 0xb8, 0xe2, 0x65, 0xdc, 0x22, 0xcb, 0xc2, 0xdb, + 0x00, 0x60, 0x37, 0xe2, 0xcc, 0xc0, 0x41, 0x72, + }, + }, + .confirm_req[14] = { + .value = { + 0x05, 0x0b, 0x5c, 0xa7, 0x58, 0x9c, 0x08, 0x81, + 0x4a, 0x6b, 0x12, 0xae, 0xaa, 0xe5, 0x81, 0xf3, + }, + }, + .confirm_rsp[14] = { + .value = { + 0xdd, 0x2b, 0xd1, 0xdd, 0x49, 0x92, 0xf3, 0xe1, + 0xae, 0xf3, 0x6d, 0x89, 0xfd, 0x77, 0xf9, 0xaa, + }, + }, + .random_req[14] = { + .value = { + 0xbc, 0x27, 0x29, 0x1b, 0xc4, 0xbc, 0x0e, 0x88, + 0x95, 0x50, 0xf7, 0x92, 0xe6, 0xf7, 0x29, 0xe8, + }, + }, + .random_rsp[14] = { + .value = { + 0xe7, 0x15, 0xfe, 0x53, 0x77, 0xd9, 0x98, 0x1d, + 0x5b, 0x4e, 0x37, 0xa3, 0x1f, 0xc9, 0x47, 0x5d, + }, + }, + .confirm_req[15] = { + .value = { + 0x75, 0x70, 0x9f, 0x84, 0x3e, 0x6b, 0x88, 0xcb, + 0x66, 0xda, 0x8f, 0x79, 0xbc, 0xf8, 0x44, 0x99, + }, + }, + .confirm_rsp[15] = { + .value = { + 0x13, 0xe4, 0x43, 0xb2, 0x61, 0x72, 0xfd, 0x33, + 0xba, 0x87, 0x44, 0x27, 0x6f, 0x9a, 0xea, 0x19, + }, + }, + .random_req[15] = { + .value = { + 0xda, 0x90, 0x59, 0x72, 0xed, 0x67, 0xde, 0x65, + 0x21, 0xab, 0x7d, 0x9d, 0x72, 0x8c, 0x88, 0x8e, + }, + }, + .random_rsp[15] = { + .value = { + 0x94, 0x92, 0x0f, 0x6c, 0x08, 0xde, 0xae, 0xa7, + 0xfd, 0x36, 0xe0, 0x02, 0xc8, 0xfd, 0xdd, 0x69, + }, + }, + .confirm_req[16] = { + .value = { + 0x35, 0x68, 0x1e, 0x80, 0x37, 0xc4, 0x91, 0xe8, + 0xbf, 0x5e, 0x27, 0x0c, 0xaa, 0x8e, 0x85, 0x7b, + }, + }, + .confirm_rsp[16] = { + .value = { + 0x1e, 0x42, 0x47, 0x29, 0x06, 0xdc, 0x2b, 0x45, + 0xec, 0x95, 0x23, 0x31, 0x29, 0x24, 0x95, 0xf0, + }, + }, + .random_req[16] = { + .value = { + 0x4e, 0x9f, 0x5d, 0x5a, 0x8f, 0xf7, 0x28, 0xc9, + 0x29, 0x62, 0x0a, 0x67, 0x19, 0x17, 0x5e, 0xa7, + }, + }, + .random_rsp[16] = { + .value = { + 0x7c, 0xd4, 0x13, 0xba, 0x27, 0x16, 0x39, 0xe7, + 0xf0, 0xbf, 0xec, 0x1e, 0xe5, 0xcc, 0x20, 0x0b, + }, + }, + .confirm_req[17] = { + .value = { + 0xb9, 0xcd, 0xf5, 0xf9, 0x2b, 0x4f, 0x6d, 0x08, + 0x51, 0xe0, 0x92, 0x99, 0x15, 0xca, 0x15, 0x2a, + }, + }, + .confirm_rsp[17] = { + .value = { + 0xb8, 0xf2, 0xf9, 0x61, 0x4f, 0x0e, 0xfd, 0x19, + 0xcb, 0x5d, 0x7e, 0x93, 0x87, 0x7a, 0x0a, 0x6e, + }, + }, + .random_req[17] = { + .value = { + 0x8b, 0xf8, 0xc8, 0xeb, 0xe5, 0xdb, 0xcf, 0xfe, + 0x68, 0x70, 0x1f, 0xbe, 0x1e, 0x3c, 0x94, 0x7d, + }, + }, + .random_rsp[17] = { + .value = { + 0x0d, 0xfc, 0x68, 0x2e, 0x50, 0x31, 0x9f, 0x60, + 0xe6, 0x12, 0x72, 0x24, 0x7c, 0xad, 0xf7, 0x48, + }, + }, + .confirm_req[18] = { + .value = { + 0x27, 0x68, 0x07, 0xaa, 0xa6, 0x33, 0x13, 0x49, + 0x65, 0x4c, 0x80, 0x54, 0xfb, 0x69, 0xcb, 0x0e, + }, + }, + .confirm_rsp[18] = { + .value = { + 0xc5, 0x8d, 0x45, 0x81, 0xb0, 0x5a, 0x69, 0x0f, + 0x6c, 0x89, 0x0b, 0x60, 0x1e, 0x27, 0x9b, 0x9e, + }, + }, + .random_req[18] = { + .value = { + 0x97, 0x46, 0x95, 0xb5, 0x86, 0xa1, 0xc1, 0x86, + 0x3a, 0x8a, 0x1f, 0x29, 0x38, 0xe0, 0x69, 0x7f, + }, + }, + .random_rsp[18] = { + .value = { + 0x8f, 0x0e, 0x56, 0x17, 0x1c, 0x4b, 0x78, 0x1f, + 0xd1, 0x8a, 0x69, 0xbd, 0x65, 0xe3, 0xde, 0x3c, + }, + }, + .confirm_req[19] = { + .value = { + 0xd2, 0xa5, 0x4e, 0x31, 0x34, 0xde, 0x68, 0xf0, + 0x69, 0x88, 0x6f, 0x28, 0xa2, 0xdd, 0xba, 0xe1, + }, + }, + .confirm_rsp[19] = { + .value = { + 0xf8, 0x5e, 0x4f, 0x4d, 0x56, 0xf6, 0x22, 0xc0, + 0x57, 0x04, 0x04, 0x45, 0x24, 0x83, 0x09, 0x80, + }, + }, + .random_req[19] = { + .value = { + 0x64, 0xe1, 0x5a, 0x76, 0x71, 0x94, 0xc0, 0x64, + 0x2b, 0xea, 0x9d, 0xaf, 0xbd, 0x10, 0x25, 0x9b, + }, + }, + .random_rsp[19] = { + .value = { + 0x1e, 0x38, 0x6e, 0x66, 0x55, 0xf1, 0x7f, 0x55, + 0x7c, 0x00, 0xff, 0xad, 0x07, 0x13, 0x25, 0x97, + }, + }, + .dhkey_check_req = { + .value = { + 0x98, 0xf1, 0x5a, 0x24, 0x81, 0x5d, 0xb5, 0xac, + 0x04, 0x4e, 0x3a, 0x31, 0x8b, 0x7d, 0xf6, 0x09, + }, + }, + .dhkey_check_rsp = { + .value = { + 0x1a, 0xb4, 0xf4, 0xf3, 0xc0, 0x5a, 0xf3, 0x13, + 0x8d, 0x6e, 0x01, 0x16, 0x1e, 0x54, 0xf3, 0xe1, + }, + }, + .sign_info_req = { + .sig_key = { + 0x4b, 0x01, 0x33, 0x5f, 0x4b, 0xfe, 0x12, 0x8b, + 0x9f, 0x81, 0x44, 0x78, 0x90, 0x03, 0x9e, 0x53, + }, + }, + .id_info_rsp = { + .irk = { + 0xef, 0x8d, 0xe2, 0x16, 0x4f, 0xec, 0x43, 0x0d, + 0xbf, 0x5b, 0xdd, 0x34, 0xc0, 0x53, 0x1e, 0xb8, + }, + }, + .id_addr_info_rsp = { + .addr_type = 0, + .bd_addr = { + 0x01, 0x01, 0x01, 0x07, 0x08, 0x01, + }, + }, + .sign_info_rsp = { + .sig_key = { + 0xd2, 0xa1, 0x2c, 0xf0, 0xa6, 0xeb, 0x97, 0x5e, + 0xac, 0x53, 0xa1, 0x3d, 0x41, 0x40, 0x36, 0x2f, + }, + }, + .ltk = { + 0xce, 0x28, 0x91, 0xa9, 0x36, 0xb7, 0xe1, 0xda, + 0x3c, 0x66, 0xd9, 0x33, 0x3d, 0x03, 0x8e, 0x31, + }, + .pair_alg = BLE_SM_PAIR_ALG_PASSKEY, + .authenticated = 1, + .passkey_info = { + .passkey = { + .action = BLE_SM_IOACT_DISP, + .passkey = 866744, + }, + }, + }; + ble_sm_test_util_us_sc_good(¶ms); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +/** + * Secure connections pairing + * Master: us + * Pair algorithm: numeric comparison + * Initiator IO capabilities: 1 + * Responder IO capabilities: 4 + * Bonding: true + * Initiator address type: 0 + * Responder address type: 0 + * Initiator key distribution: 7 + * Responder key distribution: 5 + */ +TEST_CASE_SELF(ble_sm_sc_us_nc_iio1_rio4_b1_iat0_rat0_ik7_rk5) +{ + struct ble_sm_test_params params; + + params = (struct ble_sm_test_params) { + .init_id_addr = { + 0x01, 0x01, 0x01, 0x07, 0x08, 0x01, + }, + .resp_id_addr = { + 0xca, 0x61, 0xa0, 0x67, 0x94, 0xe0, + }, + .pair_req = { + .io_cap = 0x01, + .oob_data_flag = 0x00, + .authreq = 0x0d, + .max_enc_key_size = 0x10, + .init_key_dist = 0x07, + .resp_key_dist = 0x07, + }, + .pair_rsp = { + .io_cap = 0x04, + .oob_data_flag = 0x00, + .authreq = 0x0d, + .max_enc_key_size = 0x10, + .init_key_dist = 0x07, + .resp_key_dist = 0x05, + }, + .our_priv_key = { + 0xb1, 0x6b, 0x4f, 0x81, 0xbc, 0xe3, 0x60, 0x9e, + 0x00, 0x20, 0xf1, 0x73, 0x3e, 0xfb, 0xcc, 0x6e, + 0x8c, 0xb6, 0xd2, 0x51, 0xd9, 0x36, 0x8a, 0x6d, + 0xca, 0x8c, 0xd7, 0xbe, 0x96, 0x03, 0xdf, 0xd6, + }, + .public_key_req = { + .x = { + 0xe5, 0x0f, 0x02, 0x0a, 0x37, 0x90, 0x94, 0x5a, + 0x06, 0x21, 0xf7, 0xbc, 0xd5, 0xbe, 0xb9, 0x24, + 0x8a, 0x35, 0xfd, 0xf8, 0x5e, 0xe2, 0x70, 0xd5, + 0x5a, 0xe8, 0xe7, 0xdd, 0x13, 0x90, 0xeb, 0xd4, + }, + .y = { + 0x41, 0xc8, 0x51, 0x1a, 0x25, 0x44, 0x01, 0x53, + 0x42, 0x74, 0x07, 0x9c, 0x18, 0xe6, 0x3b, 0x8a, + 0xce, 0x7a, 0x37, 0x1f, 0x18, 0x5c, 0x02, 0x7c, + 0x67, 0x16, 0xf5, 0x30, 0x2b, 0x31, 0xa9, 0xc7, + }, + }, + .public_key_rsp = { + .x = { + 0x7c, 0x27, 0x39, 0xdc, 0x10, 0xfa, 0x57, 0x97, + 0x4a, 0x18, 0xdc, 0x0e, 0xfc, 0x4b, 0xd0, 0xac, + 0x3a, 0xa4, 0x4c, 0x65, 0xb5, 0xbe, 0x7b, 0xd8, + 0xd1, 0xfd, 0x9d, 0xf8, 0xe3, 0x00, 0x4e, 0xf3, + }, + .y = { + 0xae, 0xfd, 0x8e, 0x93, 0xb4, 0xa9, 0x4d, 0xd3, + 0xb6, 0xbd, 0x4c, 0x1d, 0xc1, 0x7e, 0x67, 0x57, + 0x07, 0x10, 0x4e, 0xd0, 0x0f, 0x23, 0x23, 0xab, + 0x09, 0x86, 0xc3, 0xb9, 0x63, 0x14, 0xe4, 0xe5, + }, + }, + .confirm_rsp[0] = { + .value = { + 0x40, 0x35, 0x6d, 0xa1, 0x19, 0xa6, 0x8b, 0xff, + 0x4f, 0x0c, 0x86, 0x7e, 0x95, 0x7c, 0xb8, 0xc1, + }, + }, + .random_req[0] = { + .value = { + 0x95, 0x84, 0x0d, 0x2d, 0x7a, 0xfd, 0x5a, 0xa6, + 0xea, 0xfd, 0x7b, 0xf0, 0x68, 0x95, 0xeb, 0x77, + }, + }, + .random_rsp[0] = { + .value = { + 0x25, 0x41, 0xda, 0xdf, 0xdd, 0xca, 0xcd, 0x2e, + 0x49, 0x79, 0xb0, 0xaa, 0x7a, 0x23, 0x28, 0x7f, + }, + }, + .dhkey_check_req = { + .value = { + 0x49, 0xbb, 0x89, 0x9e, 0xa1, 0x10, 0x26, 0x7a, + 0xe7, 0x42, 0x51, 0xcd, 0x1f, 0x3b, 0x22, 0x1d, + }, + }, + .dhkey_check_rsp = { + .value = { + 0x59, 0x51, 0xc8, 0x7b, 0x4f, 0xae, 0xfe, 0xb8, + 0x0c, 0x41, 0xe8, 0xe0, 0xf9, 0x4c, 0x2b, 0xc7, + }, + }, + .sign_info_req = { + .sig_key = { + 0x37, 0x26, 0xc0, 0x79, 0x59, 0xcd, 0xb7, 0x0f, + 0xa6, 0xd8, 0xe4, 0x02, 0xc9, 0xe6, 0x02, 0x71, + }, + }, + .id_info_rsp = { + .irk = { + 0xef, 0x8d, 0xe2, 0x16, 0x4f, 0xec, 0x43, 0x0d, + 0xbf, 0x5b, 0xdd, 0x34, 0xc0, 0x53, 0x1e, 0xb8, + }, + }, + .id_addr_info_rsp = { + .addr_type = 0, + .bd_addr = { + 0x01, 0x01, 0x01, 0x07, 0x08, 0x01, + }, + }, + .sign_info_rsp = { + .sig_key = { + 0x45, 0x69, 0x05, 0xe3, 0x0c, 0x9e, 0x01, 0xb3, + 0xe8, 0xea, 0xa0, 0x5b, 0x70, 0xd9, 0x62, 0x0e, + }, + }, + .ltk = { + 0xf5, 0x60, 0x02, 0x97, 0x2f, 0xbb, 0x3c, 0xe9, + 0x97, 0xd7, 0xd5, 0x58, 0x04, 0x96, 0xa6, 0xe7, + }, + .pair_alg = BLE_SM_PAIR_ALG_NUMCMP, + .authenticated = 1, + .passkey_info = { + .passkey = { + .action = BLE_SM_IOACT_NUMCMP, + .numcmp_accept = 1, + }, + .exp_numcmp = 344302, + }, + }; + ble_sm_test_util_us_sc_good(¶ms); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +/** + * Secure connections pairing + * Master: peer + * Pair algorithm: just works + * Initiator IO capabilities: 3 + * Responder IO capabilities: 3 + * Bonding: true + * Initiator address type: BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT + * Responder address type: BLE_ADDR_PUBLIC_ID + * Initiator key distribution: 7 + * Responder key distribution: 7 + */ +TEST_CASE_SELF(ble_sm_sc_peer_jw_iio3_rio3_b1_iat2_rat2_ik7_rk7) +{ + struct ble_sm_test_params params; + + params = (struct ble_sm_test_params) { + .init_addr_type = BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT, + .init_id_addr = { + 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, + }, + .init_rpa = { + 0xd0, 0x8e, 0xf7, 0x42, 0x8c, 0x69, + }, + .resp_addr_type = BLE_ADDR_PUBLIC_ID, + .resp_id_addr = { + 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, + }, + .resp_rpa = { + 0x1a, 0x6e, 0x83, 0x55, 0x5b, 0x5a, + }, + .pair_req = { + .io_cap = 0x03, + .oob_data_flag = 0x00, + .authreq = 0x0d, + .max_enc_key_size = 0x10, + .init_key_dist = 0x07, + .resp_key_dist = 0x07, + }, + .pair_rsp = { + .io_cap = 0x03, + .oob_data_flag = 0x00, + .authreq = 0x0d, + .max_enc_key_size = 0x10, + .init_key_dist = 0x07, + .resp_key_dist = 0x07, + }, + .our_priv_key = { + 0xc5, 0x04, 0xc5, 0xf9, 0x28, 0x95, 0x78, 0x17, + 0xd5, 0x97, 0x1d, 0x01, 0xbb, 0x2c, 0xcf, 0x77, + 0x5c, 0x70, 0x52, 0xc6, 0x5e, 0x33, 0x2e, 0xe7, + 0x79, 0x58, 0xc8, 0xf1, 0xc2, 0x2d, 0xb0, 0x61, + }, + .public_key_req = { + .x = { + 0x54, 0xd9, 0x8f, 0xeb, 0xc1, 0xbb, 0xe6, 0x74, + 0x8a, 0x55, 0x3a, 0x80, 0x0e, 0xef, 0x90, 0xc9, + 0xab, 0x79, 0x12, 0x88, 0x97, 0xd9, 0x1c, 0x62, + 0x0d, 0x26, 0x43, 0x7d, 0x25, 0x86, 0x79, 0xc7, + }, + .y = { + 0x07, 0x33, 0x91, 0x40, 0xde, 0x25, 0xb4, 0x3d, + 0x81, 0x2f, 0xd2, 0x41, 0x98, 0xe7, 0xaf, 0x0f, + 0x5f, 0x17, 0x85, 0x1f, 0x75, 0x6e, 0xf4, 0x0e, + 0x05, 0x19, 0x7f, 0x03, 0x9b, 0xf4, 0x41, 0x23, + }, + }, + .public_key_rsp = { + .x = { + 0x1d, 0x44, 0x66, 0x0d, 0x3a, 0x03, 0x71, 0x17, + 0xb3, 0x10, 0x2e, 0xf0, 0xd3, 0xf8, 0xa2, 0x6c, + 0x1f, 0xfc, 0xbf, 0x02, 0x62, 0x6b, 0x11, 0x5a, + 0x76, 0x5b, 0x30, 0x20, 0xb1, 0xef, 0xb3, 0x76, + }, + .y = { + 0xf1, 0x23, 0x63, 0x75, 0xfc, 0xb6, 0xc9, 0x32, + 0xa4, 0x36, 0xbe, 0x18, 0xa0, 0x7d, 0x0b, 0x16, + 0x65, 0x24, 0xd0, 0xe3, 0x74, 0x1b, 0x34, 0x1a, + 0xf9, 0xe2, 0xcb, 0x30, 0x93, 0x88, 0xd7, 0xfa, + }, + }, + .confirm_rsp[0] = { + .value = { + 0x1e, 0x07, 0x87, 0xb2, 0x54, 0x3a, 0x44, 0x6b, + 0x97, 0x45, 0xa7, 0xa2, 0x36, 0xf4, 0x10, 0x42, + }, + }, + .random_req[0] = { + .value = { + 0x99, 0xc4, 0xdf, 0x4a, 0x2f, 0x14, 0xd8, 0x11, + 0xd3, 0x93, 0x53, 0xac, 0x64, 0xc8, 0x67, 0xe6, + }, + }, + .random_rsp[0] = { + .value = { + 0xc5, 0xb0, 0xf5, 0x2a, 0x65, 0x77, 0x05, 0xb8, + 0xf7, 0x5b, 0xad, 0x4e, 0xa9, 0x9e, 0x79, 0x98, + }, + }, + .dhkey_check_req = { + .value = { + 0xbb, 0x44, 0x9b, 0x1b, 0xcd, 0xfc, 0xdf, 0xff, + 0xbb, 0x34, 0xb7, 0x3b, 0x3e, 0x30, 0xa1, 0x6e, + }, + }, + .dhkey_check_rsp = { + .value = { + 0x58, 0x8f, 0xbe, 0xa2, 0x5f, 0xe3, 0x0a, 0xbc, + 0x17, 0x0f, 0x3b, 0x23, 0x27, 0xa5, 0xfb, 0x25, + }, + }, + .id_info_req = { + .irk = { + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, + }, + }, + .id_addr_info_req = { + .addr_type = 0, + .bd_addr = { + 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, + }, + }, + .sign_info_req = { + .sig_key = { + 0xd3, 0x46, 0x86, 0xf7, 0xeb, 0x19, 0x0a, 0x18, + 0x5a, 0xb2, 0xd0, 0x5b, 0x0f, 0x03, 0x64, 0x01, + }, + }, + .id_info_rsp = { + .irk = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + }, + }, + .id_addr_info_rsp = { + .addr_type = 0, + .bd_addr = { + 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, + }, + }, + .sign_info_rsp = { + .sig_key = { + 0x84, 0x91, 0x5d, 0x89, 0xf6, 0xf0, 0x01, 0x65, + 0xed, 0xa9, 0xcc, 0x9b, 0xa4, 0xd4, 0x97, 0x86, + }, + }, + .ltk = { + 0x4b, 0xb6, 0x1d, 0xd2, 0xba, 0xa4, 0x94, 0xe5, + 0x78, 0xde, 0xee, 0x47, 0x7a, 0x95, 0x91, 0x1c, + }, + .pair_alg = BLE_SM_PAIR_ALG_JW, + .authenticated = 0, + .passkey_info = { + .passkey = { + .action = BLE_SM_IOACT_NONE, + }, + }, + }; + ble_sm_test_util_peer_sc_good(¶ms); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +/** + * Secure connections pairing + * Master: peer + * Pair algorithm: numeric comparison + * Initiator IO capabilities: 1 + * Responder IO capabilities: 1 + * Bonding: true + * Initiator address type: BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT + * Responder address type: BLE_ADDR_PUBLIC_ID + * Initiator key distribution: 3 + * Responder key distribution: 3 + */ +TEST_CASE_SELF(ble_sm_sc_peer_nc_iio1_rio1_b1_iat2_rat2_ik3_rk3) +{ + struct ble_sm_test_params params; + + params = (struct ble_sm_test_params) { + .init_addr_type = BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT, + .init_id_addr = { + 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, + }, + .init_rpa = { + 0xc5, 0xf3, 0x5d, 0x83, 0xcd, 0x4a, + }, + .resp_addr_type = BLE_ADDR_PUBLIC_ID, + .resp_id_addr = { + 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, + }, + .resp_rpa = { + 0x9f, 0x56, 0x57, 0x5e, 0x12, 0x65, + }, + .pair_req = { + .io_cap = 0x01, + .oob_data_flag = 0x00, + .authreq = 0x0d, + .max_enc_key_size = 0x10, + .init_key_dist = 0x03, + .resp_key_dist = 0x03, + }, + .pair_rsp = { + .io_cap = 0x01, + .oob_data_flag = 0x00, + .authreq = 0x0d, + .max_enc_key_size = 0x10, + .init_key_dist = 0x03, + .resp_key_dist = 0x03, + }, + .our_priv_key = { + 0xc5, 0x04, 0xc5, 0xf9, 0x28, 0x95, 0x78, 0x17, + 0xd5, 0x97, 0x1d, 0x01, 0xbb, 0x2c, 0xcf, 0x77, + 0x5c, 0x70, 0x52, 0xc6, 0x5e, 0x33, 0x2e, 0xe7, + 0x79, 0x58, 0xc8, 0xf1, 0xc2, 0x2d, 0xb0, 0x61, + }, + .public_key_req = { + .x = { + 0x54, 0xd9, 0x8f, 0xeb, 0xc1, 0xbb, 0xe6, 0x74, + 0x8a, 0x55, 0x3a, 0x80, 0x0e, 0xef, 0x90, 0xc9, + 0xab, 0x79, 0x12, 0x88, 0x97, 0xd9, 0x1c, 0x62, + 0x0d, 0x26, 0x43, 0x7d, 0x25, 0x86, 0x79, 0xc7, + }, + .y = { + 0x07, 0x33, 0x91, 0x40, 0xde, 0x25, 0xb4, 0x3d, + 0x81, 0x2f, 0xd2, 0x41, 0x98, 0xe7, 0xaf, 0x0f, + 0x5f, 0x17, 0x85, 0x1f, 0x75, 0x6e, 0xf4, 0x0e, + 0x05, 0x19, 0x7f, 0x03, 0x9b, 0xf4, 0x41, 0x23, + }, + }, + .public_key_rsp = { + .x = { + 0x1d, 0x44, 0x66, 0x0d, 0x3a, 0x03, 0x71, 0x17, + 0xb3, 0x10, 0x2e, 0xf0, 0xd3, 0xf8, 0xa2, 0x6c, + 0x1f, 0xfc, 0xbf, 0x02, 0x62, 0x6b, 0x11, 0x5a, + 0x76, 0x5b, 0x30, 0x20, 0xb1, 0xef, 0xb3, 0x76, + }, + .y = { + 0xf1, 0x23, 0x63, 0x75, 0xfc, 0xb6, 0xc9, 0x32, + 0xa4, 0x36, 0xbe, 0x18, 0xa0, 0x7d, 0x0b, 0x16, + 0x65, 0x24, 0xd0, 0xe3, 0x74, 0x1b, 0x34, 0x1a, + 0xf9, 0xe2, 0xcb, 0x30, 0x93, 0x88, 0xd7, 0xfa, + }, + }, + .confirm_rsp[0] = { + .value = { + 0x39, 0xba, 0x86, 0x47, 0x06, 0x87, 0x14, 0xe4, + 0x5c, 0x82, 0xe9, 0x6a, 0x80, 0xca, 0x87, 0xcd, + }, + }, + .random_req[0] = { + .value = { + 0xce, 0xe2, 0xa3, 0x29, 0x8a, 0xc6, 0x76, 0x1d, + 0xa2, 0xfd, 0xe0, 0x7f, 0x8c, 0xbe, 0xf8, 0x1d, + }, + }, + .random_rsp[0] = { + .value = { + 0x3d, 0xac, 0xf0, 0xfe, 0x7c, 0x78, 0x73, 0x03, + 0xe2, 0xb6, 0x59, 0x7e, 0x80, 0xb4, 0x69, 0x07, + }, + }, + .dhkey_check_req = { + .value = { + 0xaa, 0x95, 0x9f, 0x33, 0x32, 0xa1, 0xbd, 0xf9, + 0xef, 0xb9, 0x3d, 0xfb, 0x08, 0xd1, 0x28, 0xa0, + }, + }, + .dhkey_check_rsp = { + .value = { + 0x3c, 0x10, 0x17, 0x76, 0x55, 0x65, 0x6f, 0x14, + 0xfa, 0x80, 0xd3, 0x52, 0x04, 0x82, 0xe2, 0xf7, + }, + }, + .id_info_req = { + .irk = { + 0xd4, 0x66, 0x94, 0xc9, 0x96, 0xd0, 0x28, 0x96, + 0x1c, 0xa1, 0x3b, 0xf7, 0x15, 0x95, 0x95, 0x43, + }, + }, + .id_addr_info_req = { + .addr_type = 0, + .bd_addr = { + 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, + }, + }, + .id_info_rsp = { + .irk = { + 0xb7, 0x98, 0xac, 0x85, 0xc4, 0x0a, 0x69, 0x8d, + 0xa6, 0xaf, 0xf3, 0x1f, 0x63, 0x3c, 0xf2, 0x33, + }, + }, + .id_addr_info_rsp = { + .addr_type = 0, + .bd_addr = { + 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, + }, + }, + .ltk = { + 0x95, 0x46, 0xe6, 0x8e, 0x52, 0xcc, 0x05, 0xca, + 0xf4, 0x59, 0x57, 0x54, 0x8c, 0x0d, 0x51, 0xfc, + }, + .pair_alg = BLE_SM_PAIR_ALG_NUMCMP, + .authenticated = 1, + .passkey_info = { + .passkey = { + .action = BLE_SM_IOACT_NUMCMP, + .numcmp_accept = 1, + }, + .exp_numcmp = 70210, + }, + }; + ble_sm_test_util_peer_sc_good(¶ms); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +/** + * Secure connections pairing + * Master: peer + * Pair algorithm: passkey entry + * Initiator IO capabilities: 2 + * Responder IO capabilities: 0 + * Bonding: true + * Initiator address type: BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT + * Responder address type: BLE_ADDR_PUBLIC_ID + * Initiator key distribution: 7 + * Responder key distribution: 3 + */ +TEST_CASE_SELF(ble_sm_sc_peer_pk_iio2_rio0_b1_iat2_rat2_ik7_rk3) +{ + struct ble_sm_test_params params; + + params = (struct ble_sm_test_params) { + .init_addr_type = BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT, + .init_id_addr = { + 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, + }, + .init_rpa = { + 0x6e, 0x56, 0x09, 0xef, 0x1e, 0x76, + }, + .resp_addr_type = BLE_ADDR_PUBLIC_ID, + .resp_id_addr = { + 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, + }, + .resp_rpa = { + 0xb5, 0x29, 0xdf, 0xb4, 0x9b, 0x62, + }, + .pair_req = { + .io_cap = 0x02, + .oob_data_flag = 0x00, + .authreq = 0x0d, + .max_enc_key_size = 0x10, + .init_key_dist = 0x07, + .resp_key_dist = 0x03, + }, + .pair_rsp = { + .io_cap = 0x00, + .oob_data_flag = 0x00, + .authreq = 0x0d, + .max_enc_key_size = 0x10, + .init_key_dist = 0x07, + .resp_key_dist = 0x03, + }, + .our_priv_key = { + 0xc5, 0x04, 0xc5, 0xf9, 0x28, 0x95, 0x78, 0x17, + 0xd5, 0x97, 0x1d, 0x01, 0xbb, 0x2c, 0xcf, 0x77, + 0x5c, 0x70, 0x52, 0xc6, 0x5e, 0x33, 0x2e, 0xe7, + 0x79, 0x58, 0xc8, 0xf1, 0xc2, 0x2d, 0xb0, 0x61, + }, + .public_key_req = { + .x = { + 0x54, 0xd9, 0x8f, 0xeb, 0xc1, 0xbb, 0xe6, 0x74, + 0x8a, 0x55, 0x3a, 0x80, 0x0e, 0xef, 0x90, 0xc9, + 0xab, 0x79, 0x12, 0x88, 0x97, 0xd9, 0x1c, 0x62, + 0x0d, 0x26, 0x43, 0x7d, 0x25, 0x86, 0x79, 0xc7, + }, + .y = { + 0x07, 0x33, 0x91, 0x40, 0xde, 0x25, 0xb4, 0x3d, + 0x81, 0x2f, 0xd2, 0x41, 0x98, 0xe7, 0xaf, 0x0f, + 0x5f, 0x17, 0x85, 0x1f, 0x75, 0x6e, 0xf4, 0x0e, + 0x05, 0x19, 0x7f, 0x03, 0x9b, 0xf4, 0x41, 0x23, + }, + }, + .public_key_rsp = { + .x = { + 0x1d, 0x44, 0x66, 0x0d, 0x3a, 0x03, 0x71, 0x17, + 0xb3, 0x10, 0x2e, 0xf0, 0xd3, 0xf8, 0xa2, 0x6c, + 0x1f, 0xfc, 0xbf, 0x02, 0x62, 0x6b, 0x11, 0x5a, + 0x76, 0x5b, 0x30, 0x20, 0xb1, 0xef, 0xb3, 0x76, + }, + .y = { + 0xf1, 0x23, 0x63, 0x75, 0xfc, 0xb6, 0xc9, 0x32, + 0xa4, 0x36, 0xbe, 0x18, 0xa0, 0x7d, 0x0b, 0x16, + 0x65, 0x24, 0xd0, 0xe3, 0x74, 0x1b, 0x34, 0x1a, + 0xf9, 0xe2, 0xcb, 0x30, 0x93, 0x88, 0xd7, 0xfa, + }, + }, + .confirm_req[0] = { + .value = { + 0x12, 0xe3, 0x01, 0xd0, 0x30, 0x59, 0xca, 0xd9, + 0x78, 0x0b, 0x45, 0x73, 0xb1, 0x7a, 0x4d, 0xca, + }, + }, + .confirm_rsp[0] = { + .value = { + 0x47, 0x68, 0x16, 0x24, 0xd4, 0x07, 0x60, 0x6c, + 0xa5, 0x47, 0x6f, 0x05, 0x78, 0x71, 0x3e, 0xa8, + }, + }, + .random_req[0] = { + .value = { + 0x2a, 0x29, 0xa8, 0xef, 0x0b, 0x70, 0x5f, 0x1b, + 0x81, 0x4d, 0x97, 0xff, 0xfb, 0x7f, 0x30, 0x90, + }, + }, + .random_rsp[0] = { + .value = { + 0x12, 0x9e, 0x1d, 0x12, 0x11, 0x44, 0x36, 0x74, + 0xa3, 0x0c, 0xea, 0x36, 0x4d, 0xdf, 0x2d, 0x5d, + }, + }, + .confirm_req[1] = { + .value = { + 0x4d, 0x6a, 0x32, 0xfe, 0xe2, 0xa0, 0xdd, 0x92, + 0x60, 0x5c, 0x82, 0x7f, 0xa6, 0xa6, 0x24, 0xd6, + }, + }, + .confirm_rsp[1] = { + .value = { + 0xd5, 0x3e, 0xa7, 0xa0, 0xbf, 0x39, 0x8e, 0xfe, + 0xfd, 0x73, 0x47, 0x4c, 0x92, 0x8b, 0x74, 0x06, + }, + }, + .random_req[1] = { + .value = { + 0xc1, 0x88, 0xdf, 0xb0, 0x99, 0xbb, 0xbf, 0xed, + 0xdc, 0x40, 0x66, 0x55, 0xbe, 0x91, 0x56, 0x9a, + }, + }, + .random_rsp[1] = { + .value = { + 0xed, 0xed, 0x9a, 0x61, 0xb8, 0x21, 0x03, 0x77, + 0xa6, 0xcf, 0x34, 0x65, 0x8c, 0x18, 0x82, 0x9f, + }, + }, + .confirm_req[2] = { + .value = { + 0xdb, 0xea, 0x94, 0x29, 0xe4, 0x44, 0x7d, 0x7b, + 0xd3, 0x16, 0x81, 0x8e, 0xaf, 0xe6, 0x9c, 0x85, + }, + }, + .confirm_rsp[2] = { + .value = { + 0x3f, 0xdd, 0x54, 0x76, 0xab, 0x45, 0x7f, 0x53, + 0x64, 0x6b, 0x37, 0xa6, 0xc7, 0xc6, 0x4a, 0x73, + }, + }, + .random_req[2] = { + .value = { + 0x5a, 0xf1, 0xfb, 0xde, 0xb3, 0xbe, 0x6e, 0xac, + 0x68, 0x51, 0x47, 0x8e, 0x0b, 0xcd, 0xc1, 0xa0, + }, + }, + .random_rsp[2] = { + .value = { + 0x29, 0x0f, 0x5e, 0x83, 0x87, 0xca, 0xd3, 0x21, + 0xa7, 0x7e, 0x3d, 0x78, 0x47, 0x54, 0xf8, 0xe4, + }, + }, + .confirm_req[3] = { + .value = { + 0xca, 0x3e, 0xd5, 0xe3, 0x59, 0xb0, 0x5d, 0x1e, + 0x0f, 0x4c, 0x95, 0x0f, 0x6a, 0x72, 0xcf, 0x25, + }, + }, + .confirm_rsp[3] = { + .value = { + 0x2f, 0x4d, 0x06, 0x40, 0x09, 0x68, 0x68, 0x45, + 0x87, 0x79, 0x78, 0x48, 0xda, 0xe4, 0xf5, 0xae, + }, + }, + .random_req[3] = { + .value = { + 0x63, 0x5a, 0xee, 0x91, 0xe4, 0xf8, 0xe8, 0x69, + 0xd1, 0x46, 0x18, 0x0d, 0xd2, 0x94, 0xd8, 0x20, + }, + }, + .random_rsp[3] = { + .value = { + 0x76, 0x36, 0xf5, 0xc2, 0x41, 0xb6, 0x3c, 0x1f, + 0x36, 0x19, 0x58, 0xce, 0x8f, 0x41, 0xeb, 0x8c, + }, + }, + .confirm_req[4] = { + .value = { + 0x76, 0xfd, 0x84, 0x0f, 0x0f, 0x58, 0x70, 0x45, + 0x41, 0x33, 0x5d, 0xce, 0xe5, 0xe2, 0x2f, 0x83, + }, + }, + .confirm_rsp[4] = { + .value = { + 0x87, 0xcf, 0xdf, 0xa5, 0x60, 0x82, 0x4f, 0x09, + 0x4c, 0x50, 0x24, 0xba, 0x91, 0x96, 0x0d, 0x65, + }, + }, + .random_req[4] = { + .value = { + 0x67, 0xdb, 0x73, 0x1e, 0x57, 0x5c, 0xb7, 0x86, + 0xf8, 0xaf, 0x58, 0xd8, 0x0f, 0x97, 0x47, 0xce, + }, + }, + .random_rsp[4] = { + .value = { + 0xaa, 0x99, 0x90, 0x05, 0x11, 0xfc, 0xc2, 0xd9, + 0xb8, 0xd6, 0x9d, 0xef, 0x86, 0x10, 0xcf, 0x26, + }, + }, + .confirm_req[5] = { + .value = { + 0xfc, 0x22, 0xd9, 0x1f, 0x5f, 0x86, 0x25, 0xe7, + 0x5e, 0x55, 0x48, 0x35, 0xec, 0x32, 0x37, 0x6d, + }, + }, + .confirm_rsp[5] = { + .value = { + 0x98, 0xbc, 0x07, 0x72, 0xa2, 0xe7, 0xa7, 0x66, + 0x64, 0xf7, 0x29, 0x3a, 0xaf, 0x52, 0x18, 0x04, + }, + }, + .random_req[5] = { + .value = { + 0xd3, 0x36, 0xb9, 0x69, 0x6a, 0x6d, 0x55, 0xbc, + 0x82, 0xdf, 0x1c, 0x04, 0xa7, 0xd5, 0x00, 0x68, + }, + }, + .random_rsp[5] = { + .value = { + 0xb9, 0x03, 0xbf, 0xd9, 0x86, 0x5a, 0x1a, 0xb4, + 0xdc, 0xe6, 0x8f, 0x9b, 0xa4, 0xa8, 0x2a, 0x12, + }, + }, + .confirm_req[6] = { + .value = { + 0xfe, 0x14, 0xab, 0x1c, 0xfd, 0x36, 0x64, 0x38, + 0xc1, 0xf8, 0xdd, 0xcd, 0xf4, 0x77, 0xa1, 0xb8, + }, + }, + .confirm_rsp[6] = { + .value = { + 0x2e, 0x70, 0x54, 0xdc, 0xa6, 0xae, 0xb2, 0xcd, + 0x4a, 0x26, 0x97, 0xf8, 0xbf, 0xb4, 0xb4, 0x52, + }, + }, + .random_req[6] = { + .value = { + 0x1e, 0x27, 0x73, 0x94, 0x44, 0xfc, 0xd4, 0x44, + 0xbf, 0x5b, 0x7d, 0x5d, 0x6d, 0x13, 0x68, 0xb1, + }, + }, + .random_rsp[6] = { + .value = { + 0xeb, 0xfd, 0x0b, 0xa1, 0x7b, 0xda, 0x61, 0xdc, + 0x6d, 0xe4, 0x3b, 0x51, 0xa7, 0x09, 0x29, 0x6d, + }, + }, + .confirm_req[7] = { + .value = { + 0x38, 0x2b, 0x23, 0xb9, 0x18, 0x2d, 0xb9, 0x0b, + 0xe7, 0x4d, 0x20, 0x83, 0xab, 0x17, 0xfd, 0x88, + }, + }, + .confirm_rsp[7] = { + .value = { + 0x65, 0x60, 0x85, 0xef, 0x0e, 0x9a, 0x23, 0x96, + 0xe7, 0xa9, 0xee, 0xba, 0x9e, 0x48, 0xb9, 0x1c, + }, + }, + .random_req[7] = { + .value = { + 0x8b, 0xa8, 0x7a, 0x33, 0x15, 0x1e, 0xa7, 0x78, + 0x27, 0x01, 0x3e, 0x90, 0x43, 0x47, 0x5a, 0x9d, + }, + }, + .random_rsp[7] = { + .value = { + 0x76, 0xf1, 0x21, 0x67, 0x94, 0x20, 0x6f, 0xc7, + 0x84, 0xc8, 0xdb, 0x07, 0xdb, 0x77, 0xdd, 0x50, + }, + }, + .confirm_req[8] = { + .value = { + 0x4e, 0x7f, 0x83, 0x8e, 0xa6, 0x28, 0xaa, 0x46, + 0xa2, 0x69, 0x95, 0x3b, 0xf0, 0x71, 0x14, 0x24, + }, + }, + .confirm_rsp[8] = { + .value = { + 0x93, 0x0b, 0x4d, 0xbe, 0x49, 0x36, 0xa0, 0x26, + 0xe9, 0x18, 0x4e, 0xc8, 0x19, 0x59, 0xc1, 0x7d, + }, + }, + .random_req[8] = { + .value = { + 0x11, 0xa9, 0xce, 0x26, 0x0e, 0x2f, 0x11, 0x0e, + 0xc1, 0xbd, 0x68, 0x80, 0xc8, 0xf8, 0x41, 0x65, + }, + }, + .random_rsp[8] = { + .value = { + 0xb6, 0x3d, 0x6b, 0x62, 0xb5, 0x37, 0x31, 0x28, + 0x79, 0xc4, 0xe2, 0x62, 0xbb, 0x63, 0xf9, 0x91, + }, + }, + .confirm_req[9] = { + .value = { + 0x5f, 0x55, 0xb5, 0xa4, 0x80, 0xa8, 0x54, 0x47, + 0xa7, 0x79, 0x87, 0x12, 0x2e, 0x44, 0x92, 0x42, + }, + }, + .confirm_rsp[9] = { + .value = { + 0x01, 0x69, 0xa2, 0xac, 0xd6, 0x62, 0x8a, 0x64, + 0xa2, 0x0b, 0xd0, 0xb4, 0x0e, 0x68, 0xe0, 0x88, + }, + }, + .random_req[9] = { + .value = { + 0x75, 0x1e, 0x56, 0xd0, 0xcb, 0x06, 0xfd, 0x51, + 0x55, 0xae, 0x77, 0xa4, 0xf2, 0xe7, 0x86, 0x3c, + }, + }, + .random_rsp[9] = { + .value = { + 0xff, 0xab, 0x8a, 0x7d, 0xb7, 0x40, 0xe5, 0x07, + 0xfe, 0x8f, 0x74, 0xdb, 0x2c, 0x35, 0x35, 0x12, + }, + }, + .confirm_req[10] = { + .value = { + 0x1f, 0x2a, 0xed, 0xcd, 0x6b, 0x87, 0xea, 0xa2, + 0xf8, 0xd8, 0xad, 0x04, 0x23, 0xc7, 0x5d, 0x47, + }, + }, + .confirm_rsp[10] = { + .value = { + 0x5b, 0x18, 0x2d, 0x96, 0x3b, 0xf6, 0xdc, 0x82, + 0x3b, 0xfa, 0xc9, 0x81, 0xc7, 0x33, 0xa0, 0x07, + }, + }, + .random_req[10] = { + .value = { + 0xd1, 0x3a, 0x82, 0xce, 0x31, 0x75, 0xa2, 0xbf, + 0x6f, 0x12, 0xf2, 0xac, 0xf6, 0xcc, 0xea, 0x34, + }, + }, + .random_rsp[10] = { + .value = { + 0xcf, 0x11, 0x3d, 0x44, 0x10, 0x0d, 0x26, 0x32, + 0xa5, 0x61, 0x13, 0xfd, 0xb8, 0xed, 0x31, 0x53, + }, + }, + .confirm_req[11] = { + .value = { + 0x67, 0x14, 0x8a, 0xf6, 0xc8, 0xb8, 0x73, 0x6b, + 0xb2, 0xec, 0xa9, 0x61, 0xaa, 0xc0, 0xc9, 0x28, + }, + }, + .confirm_rsp[11] = { + .value = { + 0xa5, 0xbf, 0x00, 0x07, 0x48, 0xff, 0x30, 0x36, + 0x20, 0x83, 0xd7, 0xd6, 0xd0, 0x90, 0x46, 0x03, + }, + }, + .random_req[11] = { + .value = { + 0x75, 0x99, 0x9a, 0xa3, 0xad, 0x9a, 0xe5, 0x9d, + 0x2f, 0x21, 0xdb, 0x72, 0x2f, 0xaf, 0xb8, 0x79, + }, + }, + .random_rsp[11] = { + .value = { + 0xa3, 0xb7, 0xb7, 0x46, 0x39, 0x99, 0xc2, 0x82, + 0xe9, 0x31, 0x8d, 0xc2, 0x28, 0x1b, 0x86, 0x91, + }, + }, + .confirm_req[12] = { + .value = { + 0x46, 0x2f, 0xc8, 0x0e, 0x2c, 0x70, 0x3a, 0xdb, + 0x25, 0x2f, 0xce, 0xe6, 0x15, 0x1f, 0x9a, 0x06, + }, + }, + .confirm_rsp[12] = { + .value = { + 0x9a, 0xa4, 0xe0, 0x03, 0x3a, 0xb5, 0x43, 0x75, + 0x8e, 0x93, 0x35, 0x25, 0xe6, 0x5e, 0x9d, 0x7f, + }, + }, + .random_req[12] = { + .value = { + 0x1f, 0x01, 0x32, 0x56, 0x64, 0x45, 0xc5, 0x20, + 0xd4, 0xad, 0x13, 0x8f, 0xbe, 0x82, 0xc8, 0x01, + }, + }, + .random_rsp[12] = { + .value = { + 0xd4, 0x3f, 0xa4, 0xc9, 0xe9, 0x2e, 0x62, 0x77, + 0x4e, 0x21, 0x55, 0xd8, 0xde, 0x31, 0xf5, 0xea, + }, + }, + .confirm_req[13] = { + .value = { + 0x4e, 0x48, 0x88, 0x4e, 0x4f, 0x74, 0x7e, 0xec, + 0x99, 0x5d, 0xb1, 0xcb, 0x84, 0x88, 0x80, 0xe9, + }, + }, + .confirm_rsp[13] = { + .value = { + 0x1a, 0x84, 0xfa, 0x2f, 0xd7, 0x3c, 0x5f, 0xee, + 0x3e, 0x81, 0xc0, 0x4b, 0x35, 0x4b, 0x7e, 0x98, + }, + }, + .random_req[13] = { + .value = { + 0xe3, 0x3a, 0xc5, 0x2f, 0x9f, 0x91, 0x93, 0xfb, + 0xcb, 0xd8, 0x53, 0x63, 0xab, 0xc4, 0xa5, 0x85, + }, + }, + .random_rsp[13] = { + .value = { + 0xa0, 0xcf, 0xad, 0x30, 0x2d, 0xec, 0xea, 0x81, + 0xfd, 0x7f, 0xcf, 0x7c, 0x70, 0xc9, 0x89, 0x7b, + }, + }, + .confirm_req[14] = { + .value = { + 0xe1, 0x64, 0x22, 0x19, 0x41, 0x44, 0x37, 0x2b, + 0x92, 0x60, 0xa4, 0x1f, 0xd6, 0x53, 0xe0, 0xa0, + }, + }, + .confirm_rsp[14] = { + .value = { + 0x08, 0xfa, 0xa4, 0xf8, 0x04, 0x08, 0xb8, 0x9f, + 0x61, 0xb5, 0x68, 0xaf, 0x31, 0x12, 0x8d, 0x3f, + }, + }, + .random_req[14] = { + .value = { + 0xad, 0x76, 0xc3, 0x1a, 0x4c, 0x64, 0x2c, 0x11, + 0x5e, 0x48, 0x6d, 0x41, 0xf5, 0x77, 0xc2, 0x40, + }, + }, + .random_rsp[14] = { + .value = { + 0x1b, 0xec, 0x78, 0x2b, 0xd9, 0xbe, 0x93, 0xbd, + 0x0b, 0x03, 0xf1, 0xd8, 0x31, 0xe8, 0x60, 0x67, + }, + }, + .confirm_req[15] = { + .value = { + 0x5e, 0x22, 0x44, 0x09, 0x97, 0xf9, 0xc5, 0xc7, + 0x23, 0xc7, 0x74, 0x51, 0xe5, 0x9d, 0x5c, 0xed, + }, + }, + .confirm_rsp[15] = { + .value = { + 0xfe, 0xb2, 0x90, 0xa7, 0x06, 0xaf, 0xdd, 0x6a, + 0x83, 0x26, 0x3c, 0x78, 0x66, 0xe0, 0x9d, 0xd9, + }, + }, + .random_req[15] = { + .value = { + 0xb2, 0xa0, 0x75, 0x6f, 0x77, 0xc1, 0x0b, 0x4e, + 0x99, 0xfa, 0x9a, 0x02, 0xf6, 0xe4, 0x66, 0x27, + }, + }, + .random_rsp[15] = { + .value = { + 0xf9, 0xdd, 0x69, 0xae, 0xc8, 0x66, 0xa9, 0xab, + 0xb8, 0x01, 0x38, 0xc3, 0x2a, 0x6b, 0x94, 0x66, + }, + }, + .confirm_req[16] = { + .value = { + 0x17, 0xc9, 0xf7, 0x2d, 0xe6, 0xb7, 0x99, 0x77, + 0x65, 0xf7, 0x62, 0xc8, 0x0d, 0x7d, 0xbd, 0x81, + }, + }, + .confirm_rsp[16] = { + .value = { + 0x39, 0xef, 0xbf, 0x39, 0xfa, 0x79, 0xc3, 0x7b, + 0x71, 0x40, 0x3c, 0x1f, 0x67, 0xe5, 0x60, 0xe5, + }, + }, + .random_req[16] = { + .value = { + 0x32, 0xab, 0x8b, 0xed, 0x90, 0x04, 0x5e, 0x17, + 0xd2, 0x5e, 0xa8, 0x91, 0xf7, 0x77, 0xe3, 0xd7, + }, + }, + .random_rsp[16] = { + .value = { + 0x6c, 0xc7, 0x14, 0x13, 0xdf, 0xfb, 0xc6, 0xed, + 0xa3, 0x9c, 0xa7, 0x90, 0xae, 0x4c, 0x61, 0x47, + }, + }, + .confirm_req[17] = { + .value = { + 0xc5, 0x17, 0x07, 0x35, 0x34, 0xbf, 0xc1, 0x4d, + 0xc4, 0x57, 0xc0, 0xd9, 0xfd, 0xe9, 0x10, 0x08, + }, + }, + .confirm_rsp[17] = { + .value = { + 0xbb, 0xcf, 0x41, 0xd2, 0x94, 0xea, 0xbe, 0x2f, + 0xde, 0xb2, 0xb4, 0x20, 0x72, 0x1c, 0xf8, 0x35, + }, + }, + .random_req[17] = { + .value = { + 0x59, 0x20, 0xb5, 0xdc, 0xaf, 0xc3, 0x8b, 0x32, + 0xe6, 0x40, 0x0f, 0x02, 0x67, 0x45, 0x49, 0x1f, + }, + }, + .random_rsp[17] = { + .value = { + 0xf5, 0x95, 0x60, 0x4c, 0x5f, 0x39, 0x54, 0xbf, + 0x62, 0x9e, 0x85, 0xca, 0x31, 0x9a, 0x95, 0xee, + }, + }, + .confirm_req[18] = { + .value = { + 0x36, 0x50, 0x78, 0x6b, 0x0f, 0x11, 0xe3, 0xa9, + 0x79, 0x3a, 0xa6, 0x9d, 0xd4, 0x8b, 0x13, 0x3f, + }, + }, + .confirm_rsp[18] = { + .value = { + 0xa5, 0x34, 0x5d, 0x5e, 0x43, 0x01, 0xf2, 0xe1, + 0x3f, 0xf2, 0x1c, 0x8b, 0x13, 0xf7, 0x17, 0x3e, + }, + }, + .random_req[18] = { + .value = { + 0x77, 0xa1, 0xbe, 0xbf, 0x49, 0xb8, 0x74, 0x73, + 0x47, 0x78, 0x2a, 0xf8, 0x66, 0x6b, 0xff, 0xd2, + }, + }, + .random_rsp[18] = { + .value = { + 0xa2, 0x05, 0x69, 0x65, 0x3f, 0xd4, 0xb4, 0xcd, + 0xed, 0x8c, 0x36, 0x6d, 0x51, 0x6a, 0xbb, 0xef, + }, + }, + .confirm_req[19] = { + .value = { + 0xda, 0xd8, 0x96, 0xfd, 0x1c, 0x0d, 0x1e, 0x56, + 0xe2, 0x62, 0xed, 0x18, 0x4b, 0xd3, 0x46, 0x48, + }, + }, + .confirm_rsp[19] = { + .value = { + 0xeb, 0x79, 0x5e, 0x52, 0x70, 0x25, 0xa7, 0x41, + 0x33, 0xfa, 0xac, 0xd3, 0x27, 0x35, 0xfc, 0x5f, + }, + }, + .random_req[19] = { + .value = { + 0xa8, 0x9c, 0xb9, 0xcd, 0x13, 0xb8, 0xdd, 0xd2, + 0x09, 0xd6, 0xc8, 0x12, 0xc3, 0x69, 0x9a, 0x64, + }, + }, + .random_rsp[19] = { + .value = { + 0x06, 0xe3, 0x8a, 0xef, 0xe4, 0x42, 0xae, 0x86, + 0xef, 0x58, 0x80, 0xe8, 0xe3, 0xa2, 0x09, 0x44, + }, + }, + .dhkey_check_req = { + .value = { + 0x6f, 0xa5, 0x37, 0x06, 0x4a, 0x89, 0x98, 0x39, + 0xf6, 0x69, 0x48, 0x56, 0x17, 0x6d, 0x44, 0x7c, + }, + }, + .dhkey_check_rsp = { + .value = { + 0x82, 0x48, 0xd4, 0x9e, 0xb8, 0x3c, 0xb4, 0xdc, + 0x44, 0xcb, 0x19, 0xdb, 0xcb, 0xa2, 0x00, 0x5d, + }, + }, + .id_info_req = { + .irk = { + 0x79, 0x12, 0x88, 0x97, 0xd9, 0x1c, 0x62, 0x0d, + 0x26, 0x43, 0x7d, 0x25, 0x86, 0x79, 0xc7, 0x07, + }, + }, + .id_addr_info_req = { + .addr_type = 0, + .bd_addr = { + 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, + }, + }, + .id_info_rsp = { + .irk = { + 0xda, 0x6b, 0x27, 0xa0, 0xac, 0x71, 0xf0, 0xc3, + 0x75, 0x51, 0xf6, 0x21, 0x94, 0xec, 0x81, 0x92, + }, + }, + .id_addr_info_rsp = { + .addr_type = 0, + .bd_addr = { + 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, + }, + }, + .sign_info_rsp = { + .sig_key = { + 0x49, 0x5b, 0x11, 0xb3, 0x4c, 0x1a, 0x23, 0x5c, + 0x61, 0x4f, 0xe3, 0x08, 0xf9, 0x47, 0x8b, 0xdc, + }, + }, + .ltk = { + 0x5a, 0x49, 0x28, 0xf0, 0x11, 0x3b, 0x6f, 0x6b, + 0x3a, 0x69, 0x6d, 0xdd, 0xb2, 0xe5, 0xa8, 0x97, + }, + .pair_alg = BLE_SM_PAIR_ALG_PASSKEY, + .authenticated = 1, + .passkey_info = { + .passkey = { + .action = BLE_SM_IOACT_DISP, + .passkey = 4915, + }, + }, + }; + ble_sm_test_util_peer_sc_good(¶ms); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +/** + * Secure connections pairing + * Master: us + * Pair algorithm: just works + * Initiator IO capabilities: 3 + * Responder IO capabilities: 3 + * Bonding: true + * Initiator address type: BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT + * Responder address type: BLE_ADDR_PUBLIC_ID + * Initiator key distribution: 3 + * Responder key distribution: 3 + */ +TEST_CASE_SELF(ble_sm_sc_us_jw_iio3_rio3_b1_iat2_rat2_ik3_rk3) +{ + struct ble_sm_test_params params; + + params = (struct ble_sm_test_params) { + .init_addr_type = BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT, + .init_id_addr = { + 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, + }, + .init_rpa = { + 0x46, 0x85, 0x37, 0x90, 0x86, 0x58, + }, + .resp_addr_type = BLE_ADDR_PUBLIC_ID, + .resp_id_addr = { + 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, + }, + .resp_rpa = { + 0x6d, 0x59, 0x7d, 0xa9, 0x87, 0x74, + }, + .pair_req = { + .io_cap = 0x03, + .oob_data_flag = 0x00, + .authreq = 0x09, + .max_enc_key_size = 0x10, + .init_key_dist = 0x03, + .resp_key_dist = 0x03, + }, + .pair_rsp = { + .io_cap = 0x03, + .oob_data_flag = 0x00, + .authreq = 0x09, + .max_enc_key_size = 0x10, + .init_key_dist = 0x03, + .resp_key_dist = 0x03, + }, + .our_priv_key = { + 0xdb, 0x24, 0x2e, 0x91, 0xda, 0xaa, 0x33, 0x33, + 0x23, 0xa2, 0x1e, 0xbe, 0x06, 0x69, 0xdb, 0xad, + 0xa9, 0x2a, 0x91, 0xb1, 0x24, 0x0a, 0xc7, 0xaf, + 0x50, 0x0c, 0x65, 0x5b, 0x97, 0x1e, 0x12, 0x10, + }, + .public_key_req = { + .x = { + 0x54, 0xd9, 0x8f, 0xeb, 0xc1, 0xbb, 0xe6, 0x74, + 0x8a, 0x55, 0x3a, 0x80, 0x0e, 0xef, 0x90, 0xc9, + 0xab, 0x79, 0x12, 0x88, 0x97, 0xd9, 0x1c, 0x62, + 0x0d, 0x26, 0x43, 0x7d, 0x25, 0x86, 0x79, 0xc7, + }, + .y = { + 0x07, 0x33, 0x91, 0x40, 0xde, 0x25, 0xb4, 0x3d, + 0x81, 0x2f, 0xd2, 0x41, 0x98, 0xe7, 0xaf, 0x0f, + 0x5f, 0x17, 0x85, 0x1f, 0x75, 0x6e, 0xf4, 0x0e, + 0x05, 0x19, 0x7f, 0x03, 0x9b, 0xf4, 0x41, 0x23, + }, + }, + .public_key_rsp = { + .x = { + 0x1d, 0x44, 0x66, 0x0d, 0x3a, 0x03, 0x71, 0x17, + 0xb3, 0x10, 0x2e, 0xf0, 0xd3, 0xf8, 0xa2, 0x6c, + 0x1f, 0xfc, 0xbf, 0x02, 0x62, 0x6b, 0x11, 0x5a, + 0x76, 0x5b, 0x30, 0x20, 0xb1, 0xef, 0xb3, 0x76, + }, + .y = { + 0xf1, 0x23, 0x63, 0x75, 0xfc, 0xb6, 0xc9, 0x32, + 0xa4, 0x36, 0xbe, 0x18, 0xa0, 0x7d, 0x0b, 0x16, + 0x65, 0x24, 0xd0, 0xe3, 0x74, 0x1b, 0x34, 0x1a, + 0xf9, 0xe2, 0xcb, 0x30, 0x93, 0x88, 0xd7, 0xfa, + }, + }, + .confirm_rsp[0] = { + .value = { + 0x32, 0x5b, 0xee, 0x46, 0x42, 0x63, 0xca, 0x86, + 0x2d, 0xe7, 0xd2, 0x75, 0x23, 0x7b, 0x4d, 0x59, + }, + }, + .random_req[0] = { + .value = { + 0xd4, 0x66, 0x94, 0xc9, 0x96, 0xd0, 0x28, 0x96, + 0x1c, 0xa1, 0x3b, 0xf7, 0x15, 0x95, 0x95, 0x43, + }, + }, + .random_rsp[0] = { + .value = { + 0xb7, 0x98, 0xac, 0x85, 0xc4, 0x0a, 0x69, 0x8d, + 0xa6, 0xaf, 0xf3, 0x1f, 0x63, 0x3c, 0xf2, 0x33, + }, + }, + .dhkey_check_req = { + .value = { + 0x1a, 0xc7, 0x0b, 0xfe, 0xc0, 0x55, 0xc3, 0xdb, + 0x94, 0x00, 0x89, 0x4f, 0x0e, 0x64, 0x05, 0xcd, + }, + }, + .dhkey_check_rsp = { + .value = { + 0xf2, 0x45, 0x41, 0xc0, 0xba, 0x8d, 0x58, 0xec, + 0x61, 0xfb, 0x48, 0x71, 0xb4, 0x0e, 0x7b, 0x19, + }, + }, + .id_info_req = { + .irk = { + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, + }, + }, + .id_addr_info_req = { + .addr_type = 0, + .bd_addr = { + 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, + }, + }, + .id_info_rsp = { + .irk = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + }, + }, + .id_addr_info_rsp = { + .addr_type = 0, + .bd_addr = { + 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, + }, + }, + .ltk = { + 0x8b, 0xb6, 0xf6, 0x5a, 0x52, 0x7b, 0xb8, 0xf4, + 0xb8, 0x4c, 0xe7, 0x60, 0x4f, 0x0b, 0x88, 0xfe, + }, + .pair_alg = BLE_SM_PAIR_ALG_JW, + .authenticated = 0, + .passkey_info = { + .passkey = { + .action = BLE_SM_IOACT_NONE, + }, + }, + }; + ble_sm_test_util_us_sc_good(¶ms); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +/** + * Secure connections pairing + * Master: us + * Pair algorithm: numeric comparison + * Initiator IO capabilities: 1 + * Responder IO capabilities: 1 + * Bonding: true + * Initiator address type: BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT + * Responder address type: BLE_ADDR_PUBLIC_ID + * Initiator key distribution: 3 + * Responder key distribution: 3 + */ +TEST_CASE_SELF(ble_sm_sc_us_nc_iio1_rio1_b1_iat2_rat2_ik3_rk3) +{ + struct ble_sm_test_params params; + + params = (struct ble_sm_test_params) { + .init_addr_type = BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT, + .init_id_addr = { + 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, + }, + .init_rpa = { + 0xc5, 0xf3, 0x5d, 0x83, 0xcd, 0x4a, + }, + .resp_addr_type = BLE_ADDR_PUBLIC_ID, + .resp_id_addr = { + 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, + }, + .resp_rpa = { + 0x9f, 0x56, 0x57, 0x5e, 0x12, 0x65, + }, + .pair_req = { + .io_cap = 0x01, + .oob_data_flag = 0x00, + .authreq = 0x0d, + .max_enc_key_size = 0x10, + .init_key_dist = 0x03, + .resp_key_dist = 0x03, + }, + .pair_rsp = { + .io_cap = 0x01, + .oob_data_flag = 0x00, + .authreq = 0x0d, + .max_enc_key_size = 0x10, + .init_key_dist = 0x03, + .resp_key_dist = 0x03, + }, + .our_priv_key = { + 0xdb, 0x24, 0x2e, 0x91, 0xda, 0xaa, 0x33, 0x33, + 0x23, 0xa2, 0x1e, 0xbe, 0x06, 0x69, 0xdb, 0xad, + 0xa9, 0x2a, 0x91, 0xb1, 0x24, 0x0a, 0xc7, 0xaf, + 0x50, 0x0c, 0x65, 0x5b, 0x97, 0x1e, 0x12, 0x10, + }, + .public_key_req = { + .x = { + 0x54, 0xd9, 0x8f, 0xeb, 0xc1, 0xbb, 0xe6, 0x74, + 0x8a, 0x55, 0x3a, 0x80, 0x0e, 0xef, 0x90, 0xc9, + 0xab, 0x79, 0x12, 0x88, 0x97, 0xd9, 0x1c, 0x62, + 0x0d, 0x26, 0x43, 0x7d, 0x25, 0x86, 0x79, 0xc7, + }, + .y = { + 0x07, 0x33, 0x91, 0x40, 0xde, 0x25, 0xb4, 0x3d, + 0x81, 0x2f, 0xd2, 0x41, 0x98, 0xe7, 0xaf, 0x0f, + 0x5f, 0x17, 0x85, 0x1f, 0x75, 0x6e, 0xf4, 0x0e, + 0x05, 0x19, 0x7f, 0x03, 0x9b, 0xf4, 0x41, 0x23, + }, + }, + .public_key_rsp = { + .x = { + 0x1d, 0x44, 0x66, 0x0d, 0x3a, 0x03, 0x71, 0x17, + 0xb3, 0x10, 0x2e, 0xf0, 0xd3, 0xf8, 0xa2, 0x6c, + 0x1f, 0xfc, 0xbf, 0x02, 0x62, 0x6b, 0x11, 0x5a, + 0x76, 0x5b, 0x30, 0x20, 0xb1, 0xef, 0xb3, 0x76, + }, + .y = { + 0xf1, 0x23, 0x63, 0x75, 0xfc, 0xb6, 0xc9, 0x32, + 0xa4, 0x36, 0xbe, 0x18, 0xa0, 0x7d, 0x0b, 0x16, + 0x65, 0x24, 0xd0, 0xe3, 0x74, 0x1b, 0x34, 0x1a, + 0xf9, 0xe2, 0xcb, 0x30, 0x93, 0x88, 0xd7, 0xfa, + }, + }, + .confirm_rsp[0] = { + .value = { + 0x39, 0xba, 0x86, 0x47, 0x06, 0x87, 0x14, 0xe4, + 0x5c, 0x82, 0xe9, 0x6a, 0x80, 0xca, 0x87, 0xcd, + }, + }, + .random_req[0] = { + .value = { + 0xce, 0xe2, 0xa3, 0x29, 0x8a, 0xc6, 0x76, 0x1d, + 0xa2, 0xfd, 0xe0, 0x7f, 0x8c, 0xbe, 0xf8, 0x1d, + }, + }, + .random_rsp[0] = { + .value = { + 0x3d, 0xac, 0xf0, 0xfe, 0x7c, 0x78, 0x73, 0x03, + 0xe2, 0xb6, 0x59, 0x7e, 0x80, 0xb4, 0x69, 0x07, + }, + }, + .dhkey_check_req = { + .value = { + 0xaa, 0x95, 0x9f, 0x33, 0x32, 0xa1, 0xbd, 0xf9, + 0xef, 0xb9, 0x3d, 0xfb, 0x08, 0xd1, 0x28, 0xa0, + }, + }, + .dhkey_check_rsp = { + .value = { + 0x3c, 0x10, 0x17, 0x76, 0x55, 0x65, 0x6f, 0x14, + 0xfa, 0x80, 0xd3, 0x52, 0x04, 0x82, 0xe2, 0xf7, + }, + }, + .id_info_req = { + .irk = { + 0xd4, 0x66, 0x94, 0xc9, 0x96, 0xd0, 0x28, 0x96, + 0x1c, 0xa1, 0x3b, 0xf7, 0x15, 0x95, 0x95, 0x43, + }, + }, + .id_addr_info_req = { + .addr_type = 0, + .bd_addr = { + 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, + }, + }, + .id_info_rsp = { + .irk = { + 0xb7, 0x98, 0xac, 0x85, 0xc4, 0x0a, 0x69, 0x8d, + 0xa6, 0xaf, 0xf3, 0x1f, 0x63, 0x3c, 0xf2, 0x33, + }, + }, + .id_addr_info_rsp = { + .addr_type = 0, + .bd_addr = { + 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, + }, + }, + .ltk = { + 0x95, 0x46, 0xe6, 0x8e, 0x52, 0xcc, 0x05, 0xca, + 0xf4, 0x59, 0x57, 0x54, 0x8c, 0x0d, 0x51, 0xfc, + }, + .pair_alg = BLE_SM_PAIR_ALG_NUMCMP, + .authenticated = 1, + .passkey_info = { + .passkey = { + .action = BLE_SM_IOACT_NUMCMP, + .numcmp_accept = 1, + }, + .exp_numcmp = 70210, + }, + }; + ble_sm_test_util_us_sc_good(¶ms); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +/** + * Secure connections pairing + * Master: us + * Pair algorithm: passkey entry + * Initiator IO capabilities: 2 + * Responder IO capabilities: 0 + * Bonding: true + * Initiator address type: BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT + * Responder address type: BLE_ADDR_PUBLIC_ID + * Initiator key distribution: 7 + * Responder key distribution: 3 + */ +TEST_CASE_SELF(ble_sm_sc_us_pk_iio2_rio0_b1_iat2_rat2_ik7_rk3) +{ + struct ble_sm_test_params params; + + params = (struct ble_sm_test_params) { + .init_addr_type = BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT, + .init_id_addr = { + 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, + }, + .init_rpa = { + 0x6e, 0x56, 0x09, 0xef, 0x1e, 0x76, + }, + .resp_addr_type = BLE_ADDR_PUBLIC_ID, + .resp_id_addr = { + 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, + }, + .resp_rpa = { + 0xb5, 0x29, 0xdf, 0xb4, 0x9b, 0x62, + }, + .pair_req = { + .io_cap = 0x02, + .oob_data_flag = 0x00, + .authreq = 0x0d, + .max_enc_key_size = 0x10, + .init_key_dist = 0x07, + .resp_key_dist = 0x03, + }, + .pair_rsp = { + .io_cap = 0x00, + .oob_data_flag = 0x00, + .authreq = 0x0d, + .max_enc_key_size = 0x10, + .init_key_dist = 0x07, + .resp_key_dist = 0x03, + }, + .our_priv_key = { + 0xdb, 0x24, 0x2e, 0x91, 0xda, 0xaa, 0x33, 0x33, + 0x23, 0xa2, 0x1e, 0xbe, 0x06, 0x69, 0xdb, 0xad, + 0xa9, 0x2a, 0x91, 0xb1, 0x24, 0x0a, 0xc7, 0xaf, + 0x50, 0x0c, 0x65, 0x5b, 0x97, 0x1e, 0x12, 0x10, + }, + .public_key_req = { + .x = { + 0x54, 0xd9, 0x8f, 0xeb, 0xc1, 0xbb, 0xe6, 0x74, + 0x8a, 0x55, 0x3a, 0x80, 0x0e, 0xef, 0x90, 0xc9, + 0xab, 0x79, 0x12, 0x88, 0x97, 0xd9, 0x1c, 0x62, + 0x0d, 0x26, 0x43, 0x7d, 0x25, 0x86, 0x79, 0xc7, + }, + .y = { + 0x07, 0x33, 0x91, 0x40, 0xde, 0x25, 0xb4, 0x3d, + 0x81, 0x2f, 0xd2, 0x41, 0x98, 0xe7, 0xaf, 0x0f, + 0x5f, 0x17, 0x85, 0x1f, 0x75, 0x6e, 0xf4, 0x0e, + 0x05, 0x19, 0x7f, 0x03, 0x9b, 0xf4, 0x41, 0x23, + }, + }, + .public_key_rsp = { + .x = { + 0x1d, 0x44, 0x66, 0x0d, 0x3a, 0x03, 0x71, 0x17, + 0xb3, 0x10, 0x2e, 0xf0, 0xd3, 0xf8, 0xa2, 0x6c, + 0x1f, 0xfc, 0xbf, 0x02, 0x62, 0x6b, 0x11, 0x5a, + 0x76, 0x5b, 0x30, 0x20, 0xb1, 0xef, 0xb3, 0x76, + }, + .y = { + 0xf1, 0x23, 0x63, 0x75, 0xfc, 0xb6, 0xc9, 0x32, + 0xa4, 0x36, 0xbe, 0x18, 0xa0, 0x7d, 0x0b, 0x16, + 0x65, 0x24, 0xd0, 0xe3, 0x74, 0x1b, 0x34, 0x1a, + 0xf9, 0xe2, 0xcb, 0x30, 0x93, 0x88, 0xd7, 0xfa, + }, + }, + .confirm_req[0] = { + .value = { + 0x12, 0xe3, 0x01, 0xd0, 0x30, 0x59, 0xca, 0xd9, + 0x78, 0x0b, 0x45, 0x73, 0xb1, 0x7a, 0x4d, 0xca, + }, + }, + .confirm_rsp[0] = { + .value = { + 0x47, 0x68, 0x16, 0x24, 0xd4, 0x07, 0x60, 0x6c, + 0xa5, 0x47, 0x6f, 0x05, 0x78, 0x71, 0x3e, 0xa8, + }, + }, + .random_req[0] = { + .value = { + 0x2a, 0x29, 0xa8, 0xef, 0x0b, 0x70, 0x5f, 0x1b, + 0x81, 0x4d, 0x97, 0xff, 0xfb, 0x7f, 0x30, 0x90, + }, + }, + .random_rsp[0] = { + .value = { + 0x12, 0x9e, 0x1d, 0x12, 0x11, 0x44, 0x36, 0x74, + 0xa3, 0x0c, 0xea, 0x36, 0x4d, 0xdf, 0x2d, 0x5d, + }, + }, + .confirm_req[1] = { + .value = { + 0x4d, 0x6a, 0x32, 0xfe, 0xe2, 0xa0, 0xdd, 0x92, + 0x60, 0x5c, 0x82, 0x7f, 0xa6, 0xa6, 0x24, 0xd6, + }, + }, + .confirm_rsp[1] = { + .value = { + 0xd5, 0x3e, 0xa7, 0xa0, 0xbf, 0x39, 0x8e, 0xfe, + 0xfd, 0x73, 0x47, 0x4c, 0x92, 0x8b, 0x74, 0x06, + }, + }, + .random_req[1] = { + .value = { + 0xc1, 0x88, 0xdf, 0xb0, 0x99, 0xbb, 0xbf, 0xed, + 0xdc, 0x40, 0x66, 0x55, 0xbe, 0x91, 0x56, 0x9a, + }, + }, + .random_rsp[1] = { + .value = { + 0xed, 0xed, 0x9a, 0x61, 0xb8, 0x21, 0x03, 0x77, + 0xa6, 0xcf, 0x34, 0x65, 0x8c, 0x18, 0x82, 0x9f, + }, + }, + .confirm_req[2] = { + .value = { + 0xdb, 0xea, 0x94, 0x29, 0xe4, 0x44, 0x7d, 0x7b, + 0xd3, 0x16, 0x81, 0x8e, 0xaf, 0xe6, 0x9c, 0x85, + }, + }, + .confirm_rsp[2] = { + .value = { + 0x3f, 0xdd, 0x54, 0x76, 0xab, 0x45, 0x7f, 0x53, + 0x64, 0x6b, 0x37, 0xa6, 0xc7, 0xc6, 0x4a, 0x73, + }, + }, + .random_req[2] = { + .value = { + 0x5a, 0xf1, 0xfb, 0xde, 0xb3, 0xbe, 0x6e, 0xac, + 0x68, 0x51, 0x47, 0x8e, 0x0b, 0xcd, 0xc1, 0xa0, + }, + }, + .random_rsp[2] = { + .value = { + 0x29, 0x0f, 0x5e, 0x83, 0x87, 0xca, 0xd3, 0x21, + 0xa7, 0x7e, 0x3d, 0x78, 0x47, 0x54, 0xf8, 0xe4, + }, + }, + .confirm_req[3] = { + .value = { + 0xca, 0x3e, 0xd5, 0xe3, 0x59, 0xb0, 0x5d, 0x1e, + 0x0f, 0x4c, 0x95, 0x0f, 0x6a, 0x72, 0xcf, 0x25, + }, + }, + .confirm_rsp[3] = { + .value = { + 0x2f, 0x4d, 0x06, 0x40, 0x09, 0x68, 0x68, 0x45, + 0x87, 0x79, 0x78, 0x48, 0xda, 0xe4, 0xf5, 0xae, + }, + }, + .random_req[3] = { + .value = { + 0x63, 0x5a, 0xee, 0x91, 0xe4, 0xf8, 0xe8, 0x69, + 0xd1, 0x46, 0x18, 0x0d, 0xd2, 0x94, 0xd8, 0x20, + }, + }, + .random_rsp[3] = { + .value = { + 0x76, 0x36, 0xf5, 0xc2, 0x41, 0xb6, 0x3c, 0x1f, + 0x36, 0x19, 0x58, 0xce, 0x8f, 0x41, 0xeb, 0x8c, + }, + }, + .confirm_req[4] = { + .value = { + 0x76, 0xfd, 0x84, 0x0f, 0x0f, 0x58, 0x70, 0x45, + 0x41, 0x33, 0x5d, 0xce, 0xe5, 0xe2, 0x2f, 0x83, + }, + }, + .confirm_rsp[4] = { + .value = { + 0x87, 0xcf, 0xdf, 0xa5, 0x60, 0x82, 0x4f, 0x09, + 0x4c, 0x50, 0x24, 0xba, 0x91, 0x96, 0x0d, 0x65, + }, + }, + .random_req[4] = { + .value = { + 0x67, 0xdb, 0x73, 0x1e, 0x57, 0x5c, 0xb7, 0x86, + 0xf8, 0xaf, 0x58, 0xd8, 0x0f, 0x97, 0x47, 0xce, + }, + }, + .random_rsp[4] = { + .value = { + 0xaa, 0x99, 0x90, 0x05, 0x11, 0xfc, 0xc2, 0xd9, + 0xb8, 0xd6, 0x9d, 0xef, 0x86, 0x10, 0xcf, 0x26, + }, + }, + .confirm_req[5] = { + .value = { + 0xfc, 0x22, 0xd9, 0x1f, 0x5f, 0x86, 0x25, 0xe7, + 0x5e, 0x55, 0x48, 0x35, 0xec, 0x32, 0x37, 0x6d, + }, + }, + .confirm_rsp[5] = { + .value = { + 0x98, 0xbc, 0x07, 0x72, 0xa2, 0xe7, 0xa7, 0x66, + 0x64, 0xf7, 0x29, 0x3a, 0xaf, 0x52, 0x18, 0x04, + }, + }, + .random_req[5] = { + .value = { + 0xd3, 0x36, 0xb9, 0x69, 0x6a, 0x6d, 0x55, 0xbc, + 0x82, 0xdf, 0x1c, 0x04, 0xa7, 0xd5, 0x00, 0x68, + }, + }, + .random_rsp[5] = { + .value = { + 0xb9, 0x03, 0xbf, 0xd9, 0x86, 0x5a, 0x1a, 0xb4, + 0xdc, 0xe6, 0x8f, 0x9b, 0xa4, 0xa8, 0x2a, 0x12, + }, + }, + .confirm_req[6] = { + .value = { + 0xfe, 0x14, 0xab, 0x1c, 0xfd, 0x36, 0x64, 0x38, + 0xc1, 0xf8, 0xdd, 0xcd, 0xf4, 0x77, 0xa1, 0xb8, + }, + }, + .confirm_rsp[6] = { + .value = { + 0x2e, 0x70, 0x54, 0xdc, 0xa6, 0xae, 0xb2, 0xcd, + 0x4a, 0x26, 0x97, 0xf8, 0xbf, 0xb4, 0xb4, 0x52, + }, + }, + .random_req[6] = { + .value = { + 0x1e, 0x27, 0x73, 0x94, 0x44, 0xfc, 0xd4, 0x44, + 0xbf, 0x5b, 0x7d, 0x5d, 0x6d, 0x13, 0x68, 0xb1, + }, + }, + .random_rsp[6] = { + .value = { + 0xeb, 0xfd, 0x0b, 0xa1, 0x7b, 0xda, 0x61, 0xdc, + 0x6d, 0xe4, 0x3b, 0x51, 0xa7, 0x09, 0x29, 0x6d, + }, + }, + .confirm_req[7] = { + .value = { + 0x38, 0x2b, 0x23, 0xb9, 0x18, 0x2d, 0xb9, 0x0b, + 0xe7, 0x4d, 0x20, 0x83, 0xab, 0x17, 0xfd, 0x88, + }, + }, + .confirm_rsp[7] = { + .value = { + 0x65, 0x60, 0x85, 0xef, 0x0e, 0x9a, 0x23, 0x96, + 0xe7, 0xa9, 0xee, 0xba, 0x9e, 0x48, 0xb9, 0x1c, + }, + }, + .random_req[7] = { + .value = { + 0x8b, 0xa8, 0x7a, 0x33, 0x15, 0x1e, 0xa7, 0x78, + 0x27, 0x01, 0x3e, 0x90, 0x43, 0x47, 0x5a, 0x9d, + }, + }, + .random_rsp[7] = { + .value = { + 0x76, 0xf1, 0x21, 0x67, 0x94, 0x20, 0x6f, 0xc7, + 0x84, 0xc8, 0xdb, 0x07, 0xdb, 0x77, 0xdd, 0x50, + }, + }, + .confirm_req[8] = { + .value = { + 0x4e, 0x7f, 0x83, 0x8e, 0xa6, 0x28, 0xaa, 0x46, + 0xa2, 0x69, 0x95, 0x3b, 0xf0, 0x71, 0x14, 0x24, + }, + }, + .confirm_rsp[8] = { + .value = { + 0x93, 0x0b, 0x4d, 0xbe, 0x49, 0x36, 0xa0, 0x26, + 0xe9, 0x18, 0x4e, 0xc8, 0x19, 0x59, 0xc1, 0x7d, + }, + }, + .random_req[8] = { + .value = { + 0x11, 0xa9, 0xce, 0x26, 0x0e, 0x2f, 0x11, 0x0e, + 0xc1, 0xbd, 0x68, 0x80, 0xc8, 0xf8, 0x41, 0x65, + }, + }, + .random_rsp[8] = { + .value = { + 0xb6, 0x3d, 0x6b, 0x62, 0xb5, 0x37, 0x31, 0x28, + 0x79, 0xc4, 0xe2, 0x62, 0xbb, 0x63, 0xf9, 0x91, + }, + }, + .confirm_req[9] = { + .value = { + 0x5f, 0x55, 0xb5, 0xa4, 0x80, 0xa8, 0x54, 0x47, + 0xa7, 0x79, 0x87, 0x12, 0x2e, 0x44, 0x92, 0x42, + }, + }, + .confirm_rsp[9] = { + .value = { + 0x01, 0x69, 0xa2, 0xac, 0xd6, 0x62, 0x8a, 0x64, + 0xa2, 0x0b, 0xd0, 0xb4, 0x0e, 0x68, 0xe0, 0x88, + }, + }, + .random_req[9] = { + .value = { + 0x75, 0x1e, 0x56, 0xd0, 0xcb, 0x06, 0xfd, 0x51, + 0x55, 0xae, 0x77, 0xa4, 0xf2, 0xe7, 0x86, 0x3c, + }, + }, + .random_rsp[9] = { + .value = { + 0xff, 0xab, 0x8a, 0x7d, 0xb7, 0x40, 0xe5, 0x07, + 0xfe, 0x8f, 0x74, 0xdb, 0x2c, 0x35, 0x35, 0x12, + }, + }, + .confirm_req[10] = { + .value = { + 0x1f, 0x2a, 0xed, 0xcd, 0x6b, 0x87, 0xea, 0xa2, + 0xf8, 0xd8, 0xad, 0x04, 0x23, 0xc7, 0x5d, 0x47, + }, + }, + .confirm_rsp[10] = { + .value = { + 0x5b, 0x18, 0x2d, 0x96, 0x3b, 0xf6, 0xdc, 0x82, + 0x3b, 0xfa, 0xc9, 0x81, 0xc7, 0x33, 0xa0, 0x07, + }, + }, + .random_req[10] = { + .value = { + 0xd1, 0x3a, 0x82, 0xce, 0x31, 0x75, 0xa2, 0xbf, + 0x6f, 0x12, 0xf2, 0xac, 0xf6, 0xcc, 0xea, 0x34, + }, + }, + .random_rsp[10] = { + .value = { + 0xcf, 0x11, 0x3d, 0x44, 0x10, 0x0d, 0x26, 0x32, + 0xa5, 0x61, 0x13, 0xfd, 0xb8, 0xed, 0x31, 0x53, + }, + }, + .confirm_req[11] = { + .value = { + 0x67, 0x14, 0x8a, 0xf6, 0xc8, 0xb8, 0x73, 0x6b, + 0xb2, 0xec, 0xa9, 0x61, 0xaa, 0xc0, 0xc9, 0x28, + }, + }, + .confirm_rsp[11] = { + .value = { + 0xa5, 0xbf, 0x00, 0x07, 0x48, 0xff, 0x30, 0x36, + 0x20, 0x83, 0xd7, 0xd6, 0xd0, 0x90, 0x46, 0x03, + }, + }, + .random_req[11] = { + .value = { + 0x75, 0x99, 0x9a, 0xa3, 0xad, 0x9a, 0xe5, 0x9d, + 0x2f, 0x21, 0xdb, 0x72, 0x2f, 0xaf, 0xb8, 0x79, + }, + }, + .random_rsp[11] = { + .value = { + 0xa3, 0xb7, 0xb7, 0x46, 0x39, 0x99, 0xc2, 0x82, + 0xe9, 0x31, 0x8d, 0xc2, 0x28, 0x1b, 0x86, 0x91, + }, + }, + .confirm_req[12] = { + .value = { + 0x46, 0x2f, 0xc8, 0x0e, 0x2c, 0x70, 0x3a, 0xdb, + 0x25, 0x2f, 0xce, 0xe6, 0x15, 0x1f, 0x9a, 0x06, + }, + }, + .confirm_rsp[12] = { + .value = { + 0x9a, 0xa4, 0xe0, 0x03, 0x3a, 0xb5, 0x43, 0x75, + 0x8e, 0x93, 0x35, 0x25, 0xe6, 0x5e, 0x9d, 0x7f, + }, + }, + .random_req[12] = { + .value = { + 0x1f, 0x01, 0x32, 0x56, 0x64, 0x45, 0xc5, 0x20, + 0xd4, 0xad, 0x13, 0x8f, 0xbe, 0x82, 0xc8, 0x01, + }, + }, + .random_rsp[12] = { + .value = { + 0xd4, 0x3f, 0xa4, 0xc9, 0xe9, 0x2e, 0x62, 0x77, + 0x4e, 0x21, 0x55, 0xd8, 0xde, 0x31, 0xf5, 0xea, + }, + }, + .confirm_req[13] = { + .value = { + 0x4e, 0x48, 0x88, 0x4e, 0x4f, 0x74, 0x7e, 0xec, + 0x99, 0x5d, 0xb1, 0xcb, 0x84, 0x88, 0x80, 0xe9, + }, + }, + .confirm_rsp[13] = { + .value = { + 0x1a, 0x84, 0xfa, 0x2f, 0xd7, 0x3c, 0x5f, 0xee, + 0x3e, 0x81, 0xc0, 0x4b, 0x35, 0x4b, 0x7e, 0x98, + }, + }, + .random_req[13] = { + .value = { + 0xe3, 0x3a, 0xc5, 0x2f, 0x9f, 0x91, 0x93, 0xfb, + 0xcb, 0xd8, 0x53, 0x63, 0xab, 0xc4, 0xa5, 0x85, + }, + }, + .random_rsp[13] = { + .value = { + 0xa0, 0xcf, 0xad, 0x30, 0x2d, 0xec, 0xea, 0x81, + 0xfd, 0x7f, 0xcf, 0x7c, 0x70, 0xc9, 0x89, 0x7b, + }, + }, + .confirm_req[14] = { + .value = { + 0xe1, 0x64, 0x22, 0x19, 0x41, 0x44, 0x37, 0x2b, + 0x92, 0x60, 0xa4, 0x1f, 0xd6, 0x53, 0xe0, 0xa0, + }, + }, + .confirm_rsp[14] = { + .value = { + 0x08, 0xfa, 0xa4, 0xf8, 0x04, 0x08, 0xb8, 0x9f, + 0x61, 0xb5, 0x68, 0xaf, 0x31, 0x12, 0x8d, 0x3f, + }, + }, + .random_req[14] = { + .value = { + 0xad, 0x76, 0xc3, 0x1a, 0x4c, 0x64, 0x2c, 0x11, + 0x5e, 0x48, 0x6d, 0x41, 0xf5, 0x77, 0xc2, 0x40, + }, + }, + .random_rsp[14] = { + .value = { + 0x1b, 0xec, 0x78, 0x2b, 0xd9, 0xbe, 0x93, 0xbd, + 0x0b, 0x03, 0xf1, 0xd8, 0x31, 0xe8, 0x60, 0x67, + }, + }, + .confirm_req[15] = { + .value = { + 0x5e, 0x22, 0x44, 0x09, 0x97, 0xf9, 0xc5, 0xc7, + 0x23, 0xc7, 0x74, 0x51, 0xe5, 0x9d, 0x5c, 0xed, + }, + }, + .confirm_rsp[15] = { + .value = { + 0xfe, 0xb2, 0x90, 0xa7, 0x06, 0xaf, 0xdd, 0x6a, + 0x83, 0x26, 0x3c, 0x78, 0x66, 0xe0, 0x9d, 0xd9, + }, + }, + .random_req[15] = { + .value = { + 0xb2, 0xa0, 0x75, 0x6f, 0x77, 0xc1, 0x0b, 0x4e, + 0x99, 0xfa, 0x9a, 0x02, 0xf6, 0xe4, 0x66, 0x27, + }, + }, + .random_rsp[15] = { + .value = { + 0xf9, 0xdd, 0x69, 0xae, 0xc8, 0x66, 0xa9, 0xab, + 0xb8, 0x01, 0x38, 0xc3, 0x2a, 0x6b, 0x94, 0x66, + }, + }, + .confirm_req[16] = { + .value = { + 0x17, 0xc9, 0xf7, 0x2d, 0xe6, 0xb7, 0x99, 0x77, + 0x65, 0xf7, 0x62, 0xc8, 0x0d, 0x7d, 0xbd, 0x81, + }, + }, + .confirm_rsp[16] = { + .value = { + 0x39, 0xef, 0xbf, 0x39, 0xfa, 0x79, 0xc3, 0x7b, + 0x71, 0x40, 0x3c, 0x1f, 0x67, 0xe5, 0x60, 0xe5, + }, + }, + .random_req[16] = { + .value = { + 0x32, 0xab, 0x8b, 0xed, 0x90, 0x04, 0x5e, 0x17, + 0xd2, 0x5e, 0xa8, 0x91, 0xf7, 0x77, 0xe3, 0xd7, + }, + }, + .random_rsp[16] = { + .value = { + 0x6c, 0xc7, 0x14, 0x13, 0xdf, 0xfb, 0xc6, 0xed, + 0xa3, 0x9c, 0xa7, 0x90, 0xae, 0x4c, 0x61, 0x47, + }, + }, + .confirm_req[17] = { + .value = { + 0xc5, 0x17, 0x07, 0x35, 0x34, 0xbf, 0xc1, 0x4d, + 0xc4, 0x57, 0xc0, 0xd9, 0xfd, 0xe9, 0x10, 0x08, + }, + }, + .confirm_rsp[17] = { + .value = { + 0xbb, 0xcf, 0x41, 0xd2, 0x94, 0xea, 0xbe, 0x2f, + 0xde, 0xb2, 0xb4, 0x20, 0x72, 0x1c, 0xf8, 0x35, + }, + }, + .random_req[17] = { + .value = { + 0x59, 0x20, 0xb5, 0xdc, 0xaf, 0xc3, 0x8b, 0x32, + 0xe6, 0x40, 0x0f, 0x02, 0x67, 0x45, 0x49, 0x1f, + }, + }, + .random_rsp[17] = { + .value = { + 0xf5, 0x95, 0x60, 0x4c, 0x5f, 0x39, 0x54, 0xbf, + 0x62, 0x9e, 0x85, 0xca, 0x31, 0x9a, 0x95, 0xee, + }, + }, + .confirm_req[18] = { + .value = { + 0x36, 0x50, 0x78, 0x6b, 0x0f, 0x11, 0xe3, 0xa9, + 0x79, 0x3a, 0xa6, 0x9d, 0xd4, 0x8b, 0x13, 0x3f, + }, + }, + .confirm_rsp[18] = { + .value = { + 0xa5, 0x34, 0x5d, 0x5e, 0x43, 0x01, 0xf2, 0xe1, + 0x3f, 0xf2, 0x1c, 0x8b, 0x13, 0xf7, 0x17, 0x3e, + }, + }, + .random_req[18] = { + .value = { + 0x77, 0xa1, 0xbe, 0xbf, 0x49, 0xb8, 0x74, 0x73, + 0x47, 0x78, 0x2a, 0xf8, 0x66, 0x6b, 0xff, 0xd2, + }, + }, + .random_rsp[18] = { + .value = { + 0xa2, 0x05, 0x69, 0x65, 0x3f, 0xd4, 0xb4, 0xcd, + 0xed, 0x8c, 0x36, 0x6d, 0x51, 0x6a, 0xbb, 0xef, + }, + }, + .confirm_req[19] = { + .value = { + 0xda, 0xd8, 0x96, 0xfd, 0x1c, 0x0d, 0x1e, 0x56, + 0xe2, 0x62, 0xed, 0x18, 0x4b, 0xd3, 0x46, 0x48, + }, + }, + .confirm_rsp[19] = { + .value = { + 0xeb, 0x79, 0x5e, 0x52, 0x70, 0x25, 0xa7, 0x41, + 0x33, 0xfa, 0xac, 0xd3, 0x27, 0x35, 0xfc, 0x5f, + }, + }, + .random_req[19] = { + .value = { + 0xa8, 0x9c, 0xb9, 0xcd, 0x13, 0xb8, 0xdd, 0xd2, + 0x09, 0xd6, 0xc8, 0x12, 0xc3, 0x69, 0x9a, 0x64, + }, + }, + .random_rsp[19] = { + .value = { + 0x06, 0xe3, 0x8a, 0xef, 0xe4, 0x42, 0xae, 0x86, + 0xef, 0x58, 0x80, 0xe8, 0xe3, 0xa2, 0x09, 0x44, + }, + }, + .dhkey_check_req = { + .value = { + 0x6f, 0xa5, 0x37, 0x06, 0x4a, 0x89, 0x98, 0x39, + 0xf6, 0x69, 0x48, 0x56, 0x17, 0x6d, 0x44, 0x7c, + }, + }, + .dhkey_check_rsp = { + .value = { + 0x82, 0x48, 0xd4, 0x9e, 0xb8, 0x3c, 0xb4, 0xdc, + 0x44, 0xcb, 0x19, 0xdb, 0xcb, 0xa2, 0x00, 0x5d, + }, + }, + .id_info_req = { + .irk = { + 0x79, 0x12, 0x88, 0x97, 0xd9, 0x1c, 0x62, 0x0d, + 0x26, 0x43, 0x7d, 0x25, 0x86, 0x79, 0xc7, 0x07, + }, + }, + .id_addr_info_req = { + .addr_type = 0, + .bd_addr = { + 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, + }, + }, + .id_info_rsp = { + .irk = { + 0xda, 0x6b, 0x27, 0xa0, 0xac, 0x71, 0xf0, 0xc3, + 0x75, 0x51, 0xf6, 0x21, 0x94, 0xec, 0x81, 0x92, + }, + }, + .id_addr_info_rsp = { + .addr_type = 0, + .bd_addr = { + 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, + }, + }, + .sign_info_rsp = { + .sig_key = { + 0x49, 0x5b, 0x11, 0xb3, 0x4c, 0x1a, 0x23, 0x5c, + 0x61, 0x4f, 0xe3, 0x08, 0xf9, 0x47, 0x8b, 0xdc, + }, + }, + .ltk = { + 0x5a, 0x49, 0x28, 0xf0, 0x11, 0x3b, 0x6f, 0x6b, + 0x3a, 0x69, 0x6d, 0xdd, 0xb2, 0xe5, 0xa8, 0x97, + }, + .pair_alg = BLE_SM_PAIR_ALG_PASSKEY, + .authenticated = 1, + .passkey_info = { + .passkey = { + .action = BLE_SM_IOACT_INPUT, + .passkey = 4915, + }, + }, + }; + ble_sm_test_util_us_sc_good(¶ms); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_sm_sc_test_suite) +{ + /*** No privacy. */ + + /* Peer as initiator. */ + ble_sm_sc_peer_jw_iio3_rio3_b1_iat0_rat0_ik5_rk7(); + ble_sm_sc_peer_pk_iio0_rio2_b1_iat0_rat0_ik5_rk7(); + ble_sm_sc_peer_pk_iio2_rio0_b1_iat0_rat0_ik5_rk7(); + ble_sm_sc_peer_nc_iio1_rio1_b1_iat0_rat0_ik5_rk7(); + + /* Us as initiator. */ + ble_sm_sc_us_jw_iio3_rio4_b1_iat0_rat0_ik7_rk5(); + ble_sm_sc_us_pk_iio2_rio4_b1_iat0_rat0_ik7_rk5(); + ble_sm_sc_us_pk_iio0_rio4_b1_iat0_rat0_ik7_rk5(); + ble_sm_sc_us_nc_iio1_rio4_b1_iat0_rat0_ik7_rk5(); + + /*** Privacy (id = public). */ + // FIXME: needs to be fixed due to fix for address type used +#if 0 + /* Peer as initiator. */ + ble_sm_sc_peer_jw_iio3_rio3_b1_iat2_rat2_ik7_rk7(); + ble_sm_sc_peer_nc_iio1_rio1_b1_iat2_rat2_ik3_rk3(); + ble_sm_sc_peer_pk_iio2_rio0_b1_iat2_rat2_ik7_rk3(); + + /* Us as initiator. */ + ble_sm_sc_us_jw_iio3_rio3_b1_iat2_rat2_ik3_rk3(); + ble_sm_sc_us_nc_iio1_rio1_b1_iat2_rat2_ik3_rk3(); + ble_sm_sc_us_pk_iio2_rio0_b1_iat2_rat2_ik7_rk3(); +#endif +} + +#endif /* NIMBLE_BLE_SM */ diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_sm_test.c b/src/libs/mynewt-nimble/nimble/host/test/src/ble_sm_test.c new file mode 100644 index 00000000..be4285fd --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_sm_test.c @@ -0,0 +1,414 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include "testutil/testutil.h" +#include "nimble/hci_common.h" +#include "nimble/nimble_opt.h" +#include "host/ble_sm.h" +#include "ble_hs_test.h" +#include "ble_hs_test_util.h" +#include "ble_sm_test_util.h" + +#if NIMBLE_BLE_SM + +/***************************************************************************** + * $misc * + *****************************************************************************/ + +TEST_CASE_SELF(ble_sm_test_case_f4) +{ + uint8_t u[32] = { 0xe6, 0x9d, 0x35, 0x0e, 0x48, 0x01, 0x03, 0xcc, + 0xdb, 0xfd, 0xf4, 0xac, 0x11, 0x91, 0xf4, 0xef, + 0xb9, 0xa5, 0xf9, 0xe9, 0xa7, 0x83, 0x2c, 0x5e, + 0x2c, 0xbe, 0x97, 0xf2, 0xd2, 0x03, 0xb0, 0x20 }; + uint8_t v[32] = { 0xfd, 0xc5, 0x7f, 0xf4, 0x49, 0xdd, 0x4f, 0x6b, + 0xfb, 0x7c, 0x9d, 0xf1, 0xc2, 0x9a, 0xcb, 0x59, + 0x2a, 0xe7, 0xd4, 0xee, 0xfb, 0xfc, 0x0a, 0x90, + 0x9a, 0xbb, 0xf6, 0x32, 0x3d, 0x8b, 0x18, 0x55 }; + uint8_t x[16] = { 0xab, 0xae, 0x2b, 0x71, 0xec, 0xb2, 0xff, 0xff, + 0x3e, 0x73, 0x77, 0xd1, 0x54, 0x84, 0xcb, 0xd5 }; + uint8_t z = 0x00; + uint8_t exp[16] = { 0x2d, 0x87, 0x74, 0xa9, 0xbe, 0xa1, 0xed, 0xf1, + 0x1c, 0xbd, 0xa9, 0x07, 0xf1, 0x16, 0xc9, 0xf2 }; + uint8_t res[16]; + int err; + + err = ble_sm_alg_f4(u, v, x, z, res); + TEST_ASSERT_FATAL(err == 0); + TEST_ASSERT(memcmp(res, exp, 16) == 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_sm_test_case_f5) +{ + uint8_t w[32] = { 0x98, 0xa6, 0xbf, 0x73, 0xf3, 0x34, 0x8d, 0x86, + 0xf1, 0x66, 0xf8, 0xb4, 0x13, 0x6b, 0x79, 0x99, + 0x9b, 0x7d, 0x39, 0x0a, 0xa6, 0x10, 0x10, 0x34, + 0x05, 0xad, 0xc8, 0x57, 0xa3, 0x34, 0x02, 0xec }; + uint8_t n1[16] = { 0xab, 0xae, 0x2b, 0x71, 0xec, 0xb2, 0xff, 0xff, + 0x3e, 0x73, 0x77, 0xd1, 0x54, 0x84, 0xcb, 0xd5 }; + uint8_t n2[16] = { 0xcf, 0xc4, 0x3d, 0xff, 0xf7, 0x83, 0x65, 0x21, + 0x6e, 0x5f, 0xa7, 0x25, 0xcc, 0xe7, 0xe8, 0xa6 }; + uint8_t a1t = 0x00; + uint8_t a1[6] = { 0xce, 0xbf, 0x37, 0x37, 0x12, 0x56 }; + uint8_t a2t = 0x00; + uint8_t a2[6] = { 0xc1, 0xcf, 0x2d, 0x70, 0x13, 0xa7 }; + uint8_t exp_ltk[16] = { 0x38, 0x0a, 0x75, 0x94, 0xb5, 0x22, 0x05, + 0x98, 0x23, 0xcd, 0xd7, 0x69, 0x11, 0x79, + 0x86, 0x69 }; + uint8_t exp_mackey[16] = { 0x20, 0x6e, 0x63, 0xce, 0x20, 0x6a, 0x3f, + 0xfd, 0x02, 0x4a, 0x08, 0xa1, 0x76, 0xf1, + 0x65, 0x29 }; + uint8_t mackey[16], ltk[16]; + int err; + + err = ble_sm_alg_f5(w, n1, n2, a1t, a1, a2t, a2, mackey, ltk); + TEST_ASSERT_FATAL(err == 0); + TEST_ASSERT(memcmp(mackey, exp_mackey, 16) == 0); + TEST_ASSERT(memcmp(ltk, exp_ltk, 16) == 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_sm_test_case_f6) +{ + uint8_t w[16] = { 0x20, 0x6e, 0x63, 0xce, 0x20, 0x6a, 0x3f, 0xfd, + 0x02, 0x4a, 0x08, 0xa1, 0x76, 0xf1, 0x65, 0x29 }; + uint8_t n1[16] = { 0xab, 0xae, 0x2b, 0x71, 0xec, 0xb2, 0xff, 0xff, + 0x3e, 0x73, 0x77, 0xd1, 0x54, 0x84, 0xcb, 0xd5 }; + uint8_t n2[16] = { 0xcf, 0xc4, 0x3d, 0xff, 0xf7, 0x83, 0x65, 0x21, + 0x6e, 0x5f, 0xa7, 0x25, 0xcc, 0xe7, 0xe8, 0xa6 }; + uint8_t r[16] = { 0xc8, 0x0f, 0x2d, 0x0c, 0xd2, 0x42, 0xda, 0x08, + 0x54, 0xbb, 0x53, 0xb4, 0x3b, 0x34, 0xa3, 0x12 }; + uint8_t io_cap[3] = { 0x02, 0x01, 0x01 }; + uint8_t a1t = 0x00; + uint8_t a1[6] = { 0xce, 0xbf, 0x37, 0x37, 0x12, 0x56 }; + uint8_t a2t = 0x00; + uint8_t a2[6] = { 0xc1, 0xcf, 0x2d, 0x70, 0x13, 0xa7 }; + uint8_t exp[16] = { 0x61, 0x8f, 0x95, 0xda, 0x09, 0x0b, 0x6c, 0xd2, + 0xc5, 0xe8, 0xd0, 0x9c, 0x98, 0x73, 0xc4, 0xe3 }; + uint8_t res[16]; + int err; + + err = ble_sm_alg_f6(w, n1, n2, r, io_cap, a1t, a1, a2t, a2, res); + TEST_ASSERT_FATAL(err == 0); + TEST_ASSERT(memcmp(res, exp, 16) == 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_sm_test_case_g2) +{ + uint8_t u[32] = { 0xe6, 0x9d, 0x35, 0x0e, 0x48, 0x01, 0x03, 0xcc, + 0xdb, 0xfd, 0xf4, 0xac, 0x11, 0x91, 0xf4, 0xef, + 0xb9, 0xa5, 0xf9, 0xe9, 0xa7, 0x83, 0x2c, 0x5e, + 0x2c, 0xbe, 0x97, 0xf2, 0xd2, 0x03, 0xb0, 0x20 }; + uint8_t v[32] = { 0xfd, 0xc5, 0x7f, 0xf4, 0x49, 0xdd, 0x4f, 0x6b, + 0xfb, 0x7c, 0x9d, 0xf1, 0xc2, 0x9a, 0xcb, 0x59, + 0x2a, 0xe7, 0xd4, 0xee, 0xfb, 0xfc, 0x0a, 0x90, + 0x9a, 0xbb, 0xf6, 0x32, 0x3d, 0x8b, 0x18, 0x55 }; + uint8_t x[16] = { 0xab, 0xae, 0x2b, 0x71, 0xec, 0xb2, 0xff, 0xff, + 0x3e, 0x73, 0x77, 0xd1, 0x54, 0x84, 0xcb, 0xd5 }; + uint8_t y[16] = { 0xcf, 0xc4, 0x3d, 0xff, 0xf7, 0x83, 0x65, 0x21, + 0x6e, 0x5f, 0xa7, 0x25, 0xcc, 0xe7, 0xe8, 0xa6 }; + uint32_t exp_val = 0x2f9ed5ba % 1000000; + uint32_t val; + int err; + + err = ble_sm_alg_g2(u, v, x, y, &val); + TEST_ASSERT_FATAL(err == 0); + TEST_ASSERT(val == exp_val); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_sm_test_case_conn_broken) +{ + struct ble_hci_ev_disconn_cmp disconn_evt; + int rc; + + ble_sm_test_util_init(); + + ble_sm_dbg_set_next_pair_rand(((uint8_t[16]){0})); + + ble_hs_test_util_create_conn(2, ((uint8_t[6]){1,2,3,5,6,7}), + ble_sm_test_util_conn_cb, NULL); + + /* Initiate the pairing procedure. */ + rc = ble_hs_test_util_security_initiate(2, 0); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, BLE_SM_IOACT_NONE); + + /* Terminate the connection. */ + disconn_evt.conn_handle = htole16(2); + disconn_evt.status = 0; + disconn_evt.reason = BLE_ERR_REM_USER_CONN_TERM; + ble_gap_rx_disconn_complete(&disconn_evt); + + /* Verify security callback got called. */ + TEST_ASSERT(ble_sm_test_gap_status == BLE_HS_ENOTCONN); + TEST_ASSERT(!ble_sm_test_sec_state.encrypted); + TEST_ASSERT(!ble_sm_test_sec_state.authenticated); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +/***************************************************************************** + * $peer * + *****************************************************************************/ + +TEST_CASE_SELF(ble_sm_test_case_peer_fail_inval) +{ + /* Invalid role detected before other arguments. */ + ble_sm_test_util_peer_fail_inval( + 1, + ((uint8_t[]){0xe1, 0xfc, 0xda, 0xf4, 0xb7, 0x6c}), + ((uint8_t[]){0x03, 0x02, 0x01, 0x50, 0x13, 0x00}), + ((struct ble_sm_pair_cmd[1]) { { + .io_cap = 0x14, + .oob_data_flag = 0, + .authreq = 0x12, + .max_enc_key_size = 20, + .init_key_dist = 0x0b, + .resp_key_dist = 0x11, + } }), + ((struct ble_sm_pair_fail[1]) { { + .reason = BLE_SM_ERR_CMD_NOT_SUPP, + } }) + ); + + /* Invalid key size - too small. */ + ble_sm_test_util_peer_fail_inval( + 0, + ((uint8_t[]){0xe1, 0xfc, 0xda, 0xf4, 0xb7, 0x6c}), + ((uint8_t[]){0x03, 0x02, 0x01, 0x50, 0x13, 0x00}), + ((struct ble_sm_pair_cmd[1]) { { + .io_cap = 0x04, + .oob_data_flag = 0, + .authreq = 0x5, + .max_enc_key_size = 6, + .init_key_dist = 0x07, + .resp_key_dist = 0x07, + } }), + ((struct ble_sm_pair_fail[1]) { { + .reason = BLE_SM_ERR_ENC_KEY_SZ, + } }) + ); + + /* Invalid key size - too large. */ + ble_sm_test_util_peer_fail_inval( + 0, + ((uint8_t[]){0xe1, 0xfc, 0xda, 0xf4, 0xb7, 0x6c}), + ((uint8_t[]){0x03, 0x02, 0x01, 0x50, 0x13, 0x00}), + ((struct ble_sm_pair_cmd[1]) { { + .io_cap = 0x04, + .oob_data_flag = 0, + .authreq = 0x5, + .max_enc_key_size = 17, + .init_key_dist = 0x07, + .resp_key_dist = 0x07, + } }), + ((struct ble_sm_pair_fail[1]) { { + .reason = BLE_SM_ERR_INVAL, + } }) + ); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_sm_test_case_peer_lgcy_fail_confirm) +{ + ble_sm_test_util_peer_lgcy_fail_confirm( + ((uint8_t[]){0xe1, 0xfc, 0xda, 0xf4, 0xb7, 0x6c}), + ((uint8_t[]){0x03, 0x02, 0x01, 0x50, 0x13, 0x00}), + ((struct ble_sm_pair_cmd[1]) { { + .io_cap = 0x04, + .oob_data_flag = 0, + .authreq = 0x05, + .max_enc_key_size = 16, + .init_key_dist = 0x07, + .resp_key_dist = 0x07, + } }), + ((struct ble_sm_pair_cmd[1]) { { + .io_cap = 3, + .oob_data_flag = 0, + .authreq = 0, + .max_enc_key_size = 16, + .init_key_dist = 0, + .resp_key_dist = 0, + } }), + ((struct ble_sm_pair_confirm[1]) { { + .value = { + 0x0a, 0xac, 0xa2, 0xae, 0xa6, 0x98, 0xdc, 0x6d, + 0x65, 0x84, 0x11, 0x69, 0x47, 0x36, 0x8d, 0xa0, + }, + } }), + ((struct ble_sm_pair_confirm[1]) { { + .value = { + 0x45, 0xd2, 0x2c, 0x38, 0xd8, 0x91, 0x4f, 0x19, + 0xa2, 0xd4, 0xfc, 0x7d, 0xad, 0x37, 0x79, 0xe0 + }, + } }), + ((struct ble_sm_pair_random[1]) { { + .value = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + }, + } }), + ((struct ble_sm_pair_random[1]) { { + .value = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + } }), + ((struct ble_sm_pair_fail[1]) { { + .reason = BLE_SM_ERR_CONFIRM_MISMATCH, + } }) + ); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_sm_test_case_peer_bonding_bad) +{ + ble_sm_test_util_peer_bonding_bad(0x5684, 32); + ble_sm_test_util_peer_bonding_bad(54325, 65437); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_sm_test_case_peer_sec_req_inval) +{ + struct ble_sm_pair_fail fail; + struct ble_sm_sec_req sec_req; + int rc; + + ble_sm_test_util_init(); + + ble_sm_dbg_set_next_pair_rand(((uint8_t[16]){0})); + + ble_hs_test_util_create_conn(2, ((uint8_t[6]){1,2,3,5,6,7}), + ble_sm_test_util_conn_cb, + NULL); + + /*** We are the slave; reject the security request. */ + ble_hs_atomic_conn_set_flags(2, BLE_HS_CONN_F_MASTER, 0); + + sec_req.authreq = 0; + ble_sm_test_util_rx_sec_req( + 2, &sec_req, BLE_HS_SM_US_ERR(BLE_SM_ERR_CMD_NOT_SUPP)); + + fail.reason = BLE_SM_ERR_CMD_NOT_SUPP; + ble_sm_test_util_verify_tx_pair_fail(&fail); + + /*** Pairing already in progress; ignore security request. */ + ble_hs_atomic_conn_set_flags(2, BLE_HS_CONN_F_MASTER, 1); + rc = ble_sm_pair_initiate(2); + TEST_ASSERT_FATAL(rc == 0); + ble_hs_test_util_prev_tx_queue_clear(); + + ble_sm_test_util_rx_sec_req(2, &sec_req, BLE_HS_EALREADY); + TEST_ASSERT(ble_hs_test_util_prev_tx_queue_sz() == 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +/***************************************************************************** + * $us * + *****************************************************************************/ + +TEST_CASE_SELF(ble_sm_test_case_us_fail_inval) +{ + struct ble_sm_test_params params; + + /* Invalid key size - too small. */ + params = (struct ble_sm_test_params) { + .init_id_addr = {0xe1, 0xfc, 0xda, 0xf4, 0xb7, 0x6c}, + .resp_id_addr = {0x03, 0x02, 0x01, 0x50, 0x13, 0x00}, + .pair_req = (struct ble_sm_pair_cmd) { + .io_cap = 3, + .oob_data_flag = 0, + .authreq = 0, + .max_enc_key_size = 16, + .init_key_dist = 0, + .resp_key_dist = 0, + }, + .pair_rsp = (struct ble_sm_pair_cmd) { + .io_cap = 0x04, + .oob_data_flag = 0, + .authreq = 0x05, + .max_enc_key_size = 6, + .init_key_dist = 0x07, + .resp_key_dist = 0x07, + }, + .pair_fail = (struct ble_sm_pair_fail) { + .reason = BLE_SM_ERR_ENC_KEY_SZ, + }, + }; + ble_sm_test_util_us_fail_inval(¶ms); + + /* Invalid key size - too large. */ + params = (struct ble_sm_test_params) { + .init_id_addr = {0xe1, 0xfc, 0xda, 0xf4, 0xb7, 0x6c}, + .resp_id_addr = {0x03, 0x02, 0x01, 0x50, 0x13, 0x00}, + .pair_req = (struct ble_sm_pair_cmd) { + .io_cap = 3, + .oob_data_flag = 0, + .authreq = 0, + .max_enc_key_size = 16, + .init_key_dist = 0, + .resp_key_dist = 0, + }, + .pair_rsp = (struct ble_sm_pair_cmd) { + .io_cap = 0x04, + .oob_data_flag = 0, + .authreq = 0x05, + .max_enc_key_size = 17, + .init_key_dist = 0x07, + .resp_key_dist = 0x07, + }, + .pair_fail = (struct ble_sm_pair_fail) { + .reason = BLE_SM_ERR_INVAL, + }, + }; + ble_sm_test_util_us_fail_inval(¶ms); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_sm_gen_test_suite) +{ + ble_sm_test_case_f4(); + ble_sm_test_case_f5(); + ble_sm_test_case_f6(); + ble_sm_test_case_g2(); + + ble_sm_test_case_peer_fail_inval(); + ble_sm_test_case_peer_lgcy_fail_confirm(); + ble_sm_test_case_us_fail_inval(); + ble_sm_test_case_peer_bonding_bad(); + ble_sm_test_case_conn_broken(); + ble_sm_test_case_peer_sec_req_inval(); +} +#endif diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_sm_test_util.c b/src/libs/mynewt-nimble/nimble/host/test/src/ble_sm_test_util.c new file mode 100644 index 00000000..6170371f --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_sm_test_util.c @@ -0,0 +1,2967 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include "testutil/testutil.h" +#include "nimble/hci_common.h" +#include "nimble/nimble_opt.h" +#include "host/ble_sm.h" +#include "ble_hs_test.h" +#include "host/ble_hs_id.h" +#include "ble_hs_test_util.h" +#include "ble_sm_test_util.h" + +#define BLE_HCI_LT_KEY_REQ_REPLY_LEN (18) +#define BLE_HCI_LT_KEY_REQ_NEG_REPLY_LEN (2) +#define BLE_HCI_LT_KEY_REQ_REPLY_ACK_PARAM_LEN (2) /* No status byte. */ +#define BLE_HCI_LT_KEY_REQ_NEG_REPLY_ACK_PARAM_LEN (2) +#define BLE_HCI_LE_START_ENCRYPT_LEN (28) +#define BLE_HCI_ADD_TO_RESOLV_LIST_LEN (39) + +int ble_sm_test_gap_event_type; +int ble_sm_test_gap_status; +struct ble_gap_sec_state ble_sm_test_sec_state; +static struct ble_gap_passkey_params ble_sm_test_ioact; + +static struct { + /** Handle reported in previous repeat pairing event. */ + struct ble_gap_repeat_pairing rp; + + struct ble_sm_test_params params; + + /** What the callback should return this time. */ + int rc; + + /** What the callback should return next time. */ + int next_rc; + + /** + * Whether the callback should erase the conflicting entry before retrying. + */ + int erase_on_retry; + + /** The number of times the event got reported. */ + int num_calls; +} ble_sm_test_repeat_pairing; + +struct ble_sm_test_util_entity { + uint8_t addr_type; + uint8_t id_addr_type; + uint8_t *id_addr; + uint8_t *rpa; + + struct ble_sm_pair_cmd *pair_cmd; + struct ble_sm_pair_confirm *confirms; + struct ble_sm_pair_random *randoms; + struct ble_sm_id_info *id_info; + struct ble_sm_id_addr_info *id_addr_info; + struct ble_sm_sign_info *sign_info; + uint8_t *ltk; + + uint8_t key_dist; + + /*** Secure connections fields. */ + struct ble_sm_public_key *public_key; + struct ble_sm_dhkey_check *dhkey_check; + + /*** Legacy fields. */ + struct ble_sm_enc_info *enc_info; + struct ble_sm_master_id *master_id; + uint64_t rand_num; + uint16_t ediv; +}; + +static void ble_sm_test_util_repeat_pairing(struct ble_sm_test_params *params, + int sc); + +#define BLE_SM_TEST_UTIL_HCI_HDR(handle, pb, len) \ + ((struct hci_data_hdr) { \ + .hdh_handle_pb_bc = ((handle) << 0) | \ + ((pb) << 12), \ + .hdh_len = (len) \ + }) + +static void +ble_sm_pair_cmd_parse(void *payload, int len, struct ble_sm_pair_cmd *cmd) +{ + uint8_t *u8ptr; + + BLE_HS_DBG_ASSERT(len >= sizeof(struct ble_sm_pair_cmd)); + + u8ptr = payload; + cmd->io_cap = u8ptr[0]; + cmd->oob_data_flag = u8ptr[1]; + cmd->authreq = u8ptr[2]; + cmd->max_enc_key_size = u8ptr[3]; + cmd->init_key_dist = u8ptr[4]; + cmd->resp_key_dist = u8ptr[5]; +} + +static void +ble_sm_pair_cmd_write(void *payload, int len, int is_req, + struct ble_sm_pair_cmd *cmd) +{ + uint8_t *u8ptr; + + BLE_HS_DBG_ASSERT( + len >= sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_pair_cmd)); + + u8ptr = payload; + u8ptr[0] = is_req ? BLE_SM_OP_PAIR_REQ : BLE_SM_OP_PAIR_RSP; + u8ptr[1] = cmd->io_cap; + u8ptr[2] = cmd->oob_data_flag; + u8ptr[3] = cmd->authreq; + u8ptr[4] = cmd->max_enc_key_size; + u8ptr[5] = cmd->init_key_dist; + u8ptr[6] = cmd->resp_key_dist; +} + +static void +ble_sm_pair_confirm_parse(void *payload, int len, + struct ble_sm_pair_confirm *cmd) +{ + BLE_HS_DBG_ASSERT(len >= sizeof(struct ble_sm_pair_confirm)); + memcpy(cmd->value, payload, sizeof cmd->value); +} + +static void +ble_sm_pair_confirm_write(void *payload, int len, + struct ble_sm_pair_confirm *cmd) +{ + uint8_t *u8ptr; + + BLE_HS_DBG_ASSERT( + len >= sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_pair_confirm)); + + u8ptr = payload; + + u8ptr[0] = BLE_SM_OP_PAIR_CONFIRM; + memcpy(u8ptr + sizeof(struct ble_sm_hdr), cmd->value, sizeof cmd->value); +} + +static void +ble_sm_pair_random_parse(void *payload, int len, + struct ble_sm_pair_random *cmd) +{ + BLE_HS_DBG_ASSERT(len >= sizeof(struct ble_sm_pair_random)); + memcpy(cmd->value, payload, sizeof cmd->value); +} + +static void +ble_sm_pair_random_write(void *payload, int len, + struct ble_sm_pair_random *cmd) +{ + uint8_t *u8ptr; + + BLE_HS_DBG_ASSERT( + len >= sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_pair_random)); + + u8ptr = payload; + + u8ptr[0] = BLE_SM_OP_PAIR_RANDOM; + memcpy(u8ptr + sizeof(struct ble_sm_hdr), cmd->value, sizeof cmd->value); +} + +static void +ble_sm_pair_fail_parse(void *payload, int len, struct ble_sm_pair_fail *cmd) +{ + uint8_t *u8ptr; + + BLE_HS_DBG_ASSERT(len >= sizeof(struct ble_sm_pair_fail)); + + u8ptr = payload; + cmd->reason = u8ptr[0]; +} + +static void +ble_sm_enc_info_parse(void *payload, int len, struct ble_sm_enc_info *cmd) +{ + BLE_HS_DBG_ASSERT(len >= sizeof(struct ble_sm_enc_info)); + + memcpy(cmd->ltk, payload, sizeof cmd->ltk); +} + +static void +ble_sm_enc_info_write(void *payload, int len, struct ble_sm_enc_info *cmd) +{ + uint8_t *u8ptr; + + BLE_HS_DBG_ASSERT( + len >= sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_enc_info)); + + u8ptr = payload; + + u8ptr[0] = BLE_SM_OP_ENC_INFO; + memcpy(u8ptr + 1, cmd->ltk, sizeof cmd->ltk); +} + +static void +ble_sm_master_id_parse(void *payload, int len, struct ble_sm_master_id *cmd) +{ + uint8_t *u8ptr; + + BLE_HS_DBG_ASSERT(len >= sizeof(struct ble_sm_master_id)); + + u8ptr = payload; + + cmd->ediv = get_le16(u8ptr); + cmd->rand_val = get_le64(u8ptr + 2); +} + +static void +ble_sm_master_id_write(void *payload, int len, struct ble_sm_master_id *cmd) +{ + uint8_t *u8ptr; + + BLE_HS_DBG_ASSERT( + len >= sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_master_id)); + + u8ptr = payload; + + u8ptr[0] = BLE_SM_OP_MASTER_ID; + put_le16(u8ptr + 1, cmd->ediv); + put_le64(u8ptr + 3, cmd->rand_val); +} + +static void +ble_sm_id_info_parse(void *payload, int len, struct ble_sm_id_info *cmd) +{ + BLE_HS_DBG_ASSERT(len >= sizeof(struct ble_sm_id_info)); + + memcpy(cmd->irk, payload, 16); +} + +static void +ble_sm_id_info_write(void *payload, int len, struct ble_sm_id_info *cmd) +{ + uint8_t *u8ptr; + + BLE_HS_DBG_ASSERT( + len >= sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_id_info)); + + u8ptr = payload; + + u8ptr[0] = BLE_SM_OP_IDENTITY_INFO; + memcpy(u8ptr + sizeof(struct ble_sm_hdr), cmd->irk, sizeof cmd->irk); +} + +static void +ble_sm_id_addr_info_parse(void *payload, int len, + struct ble_sm_id_addr_info *cmd) +{ + uint8_t *u8ptr; + + BLE_HS_DBG_ASSERT(len >= sizeof(struct ble_sm_id_addr_info)); + + u8ptr = payload; + + cmd->addr_type = *u8ptr; + memcpy(cmd->bd_addr, u8ptr + 1, 6); +} + +static void +ble_sm_id_addr_info_write(void *payload, int len, + struct ble_sm_id_addr_info *cmd) +{ + uint8_t *u8ptr; + + BLE_HS_DBG_ASSERT( + len >= sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_id_addr_info)); + + u8ptr = payload; + + u8ptr[0] = BLE_SM_OP_IDENTITY_ADDR_INFO; + u8ptr[1] = cmd->addr_type; + memcpy(u8ptr + 2, cmd->bd_addr, sizeof cmd->bd_addr); +} + +static void +ble_sm_sign_info_parse(void *payload, int len, struct ble_sm_sign_info *cmd) +{ + BLE_HS_DBG_ASSERT(len >= sizeof(struct ble_sm_sign_info)); + + memcpy(cmd->sig_key, payload, 16); +} + +static void +ble_sm_sign_info_write(void *payload, int len, struct ble_sm_sign_info *cmd) +{ + uint8_t *u8ptr; + + BLE_HS_DBG_ASSERT( + len >= sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_sign_info)); + + u8ptr = payload; + + u8ptr[0] = BLE_SM_OP_SIGN_INFO; + memcpy(u8ptr + sizeof(struct ble_sm_hdr), + cmd->sig_key, sizeof cmd->sig_key); +} + +static void +ble_sm_sec_req_parse(void *payload, int len, struct ble_sm_sec_req *cmd) +{ + uint8_t *u8ptr; + + BLE_HS_DBG_ASSERT(len >= sizeof(struct ble_sm_sec_req)); + + u8ptr = payload; + cmd->authreq = *u8ptr; +} + +static void +ble_sm_sec_req_write(void *payload, int len, struct ble_sm_sec_req *cmd) +{ + uint8_t *u8ptr; + + BLE_HS_DBG_ASSERT( + len >= sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_sec_req)); + + u8ptr = payload; + + u8ptr[0] = BLE_SM_OP_SEC_REQ; + u8ptr[1] = cmd->authreq; +} + +static void +ble_sm_public_key_parse(void *payload, int len, struct ble_sm_public_key *cmd) +{ + uint8_t *u8ptr; + + BLE_HS_DBG_ASSERT(len >= sizeof(struct ble_sm_public_key)); + + u8ptr = payload; + + memcpy(cmd->x, u8ptr, sizeof cmd->x); + u8ptr += sizeof cmd->x; + + memcpy(cmd->y, u8ptr, sizeof cmd->y); + u8ptr += sizeof cmd->y; +} + +static void +ble_sm_public_key_write(void *payload, int len, struct ble_sm_public_key *cmd) +{ + uint8_t *u8ptr; + + BLE_HS_DBG_ASSERT( + len >= sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_public_key)); + + u8ptr = payload; + + *u8ptr = BLE_SM_OP_PAIR_PUBLIC_KEY; + u8ptr++; + + memcpy(u8ptr, cmd->x, sizeof cmd->x); + memcpy(u8ptr + 32, cmd->y, sizeof cmd->y); +} + +static void +ble_sm_dhkey_check_parse(void *payload, int len, + struct ble_sm_dhkey_check *cmd) +{ + BLE_HS_DBG_ASSERT(len >= sizeof(struct ble_sm_dhkey_check)); + + memcpy(cmd->value, payload, sizeof cmd->value); +} + +static void +ble_sm_dhkey_check_write(void *payload, int len, + struct ble_sm_dhkey_check *cmd) +{ + uint8_t *u8ptr; + + BLE_HS_DBG_ASSERT( + len >= sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_dhkey_check)); + + u8ptr = payload; + + *u8ptr = BLE_SM_OP_PAIR_DHKEY_CHECK; + u8ptr++; + + memcpy(u8ptr, cmd->value, sizeof cmd->value); +} + +void +ble_sm_test_util_init(void) +{ + ble_hs_test_util_init(); + + ble_sm_test_gap_event_type = -1; + ble_sm_test_gap_status = -1; + memset(&ble_sm_test_repeat_pairing, 0, sizeof ble_sm_test_repeat_pairing); + ble_sm_test_repeat_pairing.rp.conn_handle = BLE_HS_CONN_HANDLE_NONE; + + memset(&ble_sm_test_ioact, 0, sizeof ble_sm_test_ioact); + memset(&ble_sm_test_sec_state, 0xff, sizeof ble_sm_test_sec_state); +} + +static void +ble_sm_test_util_params_to_entity(struct ble_sm_test_params *params, + int initiator, + struct ble_sm_test_util_entity *out_entity) +{ + int sc; + + memset(out_entity, 0, sizeof *out_entity); + + sc = params->pair_req.authreq & BLE_SM_PAIR_AUTHREQ_SC && + params->pair_rsp.authreq & BLE_SM_PAIR_AUTHREQ_SC; + + if (initiator) { + out_entity->key_dist = params->pair_rsp.init_key_dist; + + out_entity->addr_type = params->init_addr_type; + out_entity->id_addr = params->init_id_addr; + out_entity->rpa = params->init_rpa; + + out_entity->pair_cmd = ¶ms->pair_req; + out_entity->confirms = params->confirm_req; + out_entity->randoms = params->random_req; + out_entity->id_info = ¶ms->id_info_rsp; + out_entity->id_addr_info = ¶ms->id_addr_info_rsp; + out_entity->sign_info = ¶ms->sign_info_rsp; + + if (sc) { + out_entity->ltk = params->ltk; + out_entity->public_key = ¶ms->public_key_req; + out_entity->dhkey_check = ¶ms->dhkey_check_req; + } else { + out_entity->enc_info = ¶ms->enc_info_rsp; + out_entity->master_id = ¶ms->master_id_rsp; + if (out_entity->key_dist & BLE_SM_PAIR_KEY_DIST_ENC) { + out_entity->rand_num = params->master_id_rsp.rand_val; + out_entity->ediv = params->master_id_rsp.ediv; + out_entity->ltk = params->enc_info_rsp.ltk; + } + } + } else { + out_entity->key_dist = params->pair_rsp.resp_key_dist; + + out_entity->addr_type = params->resp_addr_type; + out_entity->id_addr = params->resp_id_addr; + out_entity->rpa = params->resp_rpa; + + out_entity->pair_cmd = ¶ms->pair_rsp; + out_entity->confirms = params->confirm_rsp; + out_entity->randoms = params->random_rsp; + out_entity->id_info = ¶ms->id_info_req; + out_entity->id_addr_info = ¶ms->id_addr_info_req; + out_entity->sign_info = ¶ms->sign_info_req; + + if (sc) { + out_entity->ltk = params->ltk; + out_entity->public_key = ¶ms->public_key_rsp; + out_entity->dhkey_check = ¶ms->dhkey_check_rsp; + } else { + out_entity->enc_info = ¶ms->enc_info_req; + out_entity->master_id = ¶ms->master_id_req; + if (out_entity->key_dist & BLE_SM_PAIR_KEY_DIST_ENC) { + out_entity->rand_num = params->master_id_req.rand_val; + out_entity->ediv = params->master_id_req.ediv; + out_entity->ltk = params->enc_info_req.ltk; + } + } + } + + out_entity->id_addr_type = + ble_hs_misc_own_addr_type_to_id(out_entity->addr_type); +} + +static void +ble_sm_test_util_params_to_entities(struct ble_sm_test_params *params, + int we_are_initiator, + struct ble_sm_test_util_entity *out_us, + struct ble_sm_test_util_entity *out_peer) +{ + ble_sm_test_util_params_to_entity(params, we_are_initiator, out_us); + ble_sm_test_util_params_to_entity(params, !we_are_initiator, out_peer); +} + +static void +ble_sm_test_util_init_good(struct ble_sm_test_params *params, + int we_are_initiator, + struct ble_hs_conn **out_conn, + struct ble_sm_test_util_entity *out_us, + struct ble_sm_test_util_entity *out_peer) +{ + struct ble_hs_conn *conn; + + ble_sm_test_util_init(); + + ble_sm_test_util_params_to_entities(params, we_are_initiator, + out_us, out_peer); + + ble_hs_cfg.sm_io_cap = out_us->pair_cmd->io_cap; + ble_hs_cfg.sm_oob_data_flag = out_us->pair_cmd->oob_data_flag; + ble_hs_cfg.sm_bonding = !!(out_us->pair_cmd->authreq & + BLE_SM_PAIR_AUTHREQ_BOND); + ble_hs_cfg.sm_mitm = !!(out_us->pair_cmd->authreq & + BLE_SM_PAIR_AUTHREQ_MITM); + ble_hs_cfg.sm_sc = !!(out_us->pair_cmd->authreq & + BLE_SM_PAIR_AUTHREQ_SC); + ble_hs_cfg.sm_keypress = !!(out_us->pair_cmd->authreq & + BLE_SM_PAIR_AUTHREQ_KEYPRESS); + + if (we_are_initiator) { + ble_hs_cfg.sm_our_key_dist = out_us->pair_cmd->init_key_dist; + ble_hs_cfg.sm_their_key_dist = out_us->pair_cmd->resp_key_dist; + } else { + ble_hs_cfg.sm_our_key_dist = out_us->pair_cmd->resp_key_dist; + ble_hs_cfg.sm_their_key_dist = out_us->pair_cmd->init_key_dist; + } + + ble_hs_id_set_pub(out_us->id_addr); + ble_sm_dbg_set_next_pair_rand(out_us->randoms[0].value); + ble_sm_dbg_set_next_ediv(out_us->ediv); + ble_sm_dbg_set_next_master_id_rand(out_us->rand_num); + ble_sm_dbg_set_next_ltk(out_us->ltk); + ble_hs_test_util_set_our_irk(out_us->id_info->irk, 0, 0); + ble_sm_dbg_set_next_csrk(out_us->sign_info->sig_key); + + if (out_us->public_key != NULL) { + ble_sm_dbg_set_sc_keys((uint8_t *)out_us->public_key, + params->our_priv_key); + } + + ble_hs_test_util_create_rpa_conn(2, out_us->addr_type, out_us->rpa, + out_peer->addr_type, + out_peer->id_addr, out_peer->rpa, + BLE_HS_TEST_CONN_FEAT_ALL, + ble_sm_test_util_conn_cb, + NULL); + + /* This test code and modifies the connection object after unlocking + * the host mutex. It is not OK for real code to do this, but this test + * can assume the connection list is unchanging. + */ + ble_hs_lock(); + conn = ble_hs_conn_find(2); + TEST_ASSERT_FATAL(conn != NULL); + ble_hs_unlock(); + + if (!we_are_initiator) { + /* Peer is the initiator so we must be the slave. */ + conn->bhc_flags &= ~BLE_HS_CONN_F_MASTER; + } + + if (out_conn != NULL) { + *out_conn = conn; + } +} + +static int +ble_sm_test_util_repeat_pairing_cb(const struct ble_gap_repeat_pairing *rp) +{ + struct ble_store_value_sec value_sec; + struct ble_store_key_sec key_sec; + struct ble_gap_conn_desc desc; + int rc; + + TEST_ASSERT_FATAL(rp->conn_handle != BLE_HS_CONN_HANDLE_NONE); + + ble_sm_test_repeat_pairing.num_calls++; + + rc = ble_gap_conn_find(rp->conn_handle, &desc); + TEST_ASSERT_FATAL(rc == 0); + + memset(&key_sec, 0, sizeof key_sec); + key_sec.peer_addr = desc.peer_id_addr; + rc = ble_store_read_peer_sec(&key_sec, &value_sec); + TEST_ASSERT_FATAL(rc == 0); + + /* Verify current bond is reported correctly. */ + TEST_ASSERT(rp->cur_key_size == value_sec.key_size); + TEST_ASSERT(rp->cur_authenticated == value_sec.authenticated); + TEST_ASSERT(rp->cur_sc == value_sec.sc); + + /* Verify new pairing request is reported correctly. */ + TEST_ASSERT( + rp->new_key_size == + min(ble_sm_test_repeat_pairing.params.pair_req.max_enc_key_size, + ble_sm_test_repeat_pairing.params.pair_rsp.max_enc_key_size)); + TEST_ASSERT( + rp->new_authenticated == + !!(ble_sm_test_repeat_pairing.params.passkey_info.passkey.action)); + TEST_ASSERT( + rp->new_sc == + ((ble_sm_test_repeat_pairing.params.pair_req.authreq & + BLE_SM_PAIR_AUTHREQ_SC) + && + (ble_sm_test_repeat_pairing.params.pair_rsp.authreq & + BLE_SM_PAIR_AUTHREQ_SC))); + TEST_ASSERT( + rp->new_bonding == + ((ble_sm_test_repeat_pairing.params.pair_req.authreq & + BLE_SM_PAIR_AUTHREQ_BOND) + && + (ble_sm_test_repeat_pairing.params.pair_rsp.authreq & + BLE_SM_PAIR_AUTHREQ_BOND))); + + if (ble_sm_test_repeat_pairing.rp.conn_handle == + BLE_HS_CONN_HANDLE_NONE) { + + ble_sm_test_repeat_pairing.rp.conn_handle = rp->conn_handle; + } else { + /* Ensure the correct connection handle gets reported each time. */ + TEST_ASSERT(rp->conn_handle == + ble_sm_test_repeat_pairing.rp.conn_handle); + } + + ble_sm_test_repeat_pairing.rp = *rp; + + if (ble_sm_test_repeat_pairing.rc == BLE_GAP_REPEAT_PAIRING_RETRY && + ble_sm_test_repeat_pairing.erase_on_retry) { + + rc = ble_gap_conn_find(rp->conn_handle, &desc); + TEST_ASSERT_FATAL(rc == 0); + + rc = ble_store_util_delete_peer(&desc.peer_id_addr); + TEST_ASSERT_FATAL(rc == 0); + } + + rc = ble_sm_test_repeat_pairing.rc; + ble_sm_test_repeat_pairing.rc = ble_sm_test_repeat_pairing.next_rc; + + return rc; +} + +int +ble_sm_test_util_conn_cb(struct ble_gap_event *event, void *arg) +{ + struct ble_gap_conn_desc desc; + int rc; + + switch (event->type) { + case BLE_GAP_EVENT_ENC_CHANGE: + ble_sm_test_gap_status = event->enc_change.status; + + rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc); + TEST_ASSERT_FATAL(rc == 0); + ble_sm_test_sec_state = desc.sec_state; + rc = 0; + break; + + case BLE_GAP_EVENT_PASSKEY_ACTION: + ble_sm_test_ioact = event->passkey.params; + rc = 0; + break; + + case BLE_GAP_EVENT_REPEAT_PAIRING: + rc = ble_sm_test_util_repeat_pairing_cb(&event->repeat_pairing); + break; + + default: + return 0; + } + + ble_sm_test_gap_event_type = event->type; + return rc; +} + +static void +ble_sm_test_util_rx_pair_cmd(uint16_t conn_handle, uint8_t op, + struct ble_sm_pair_cmd *cmd, + int rx_status) +{ + struct hci_data_hdr hci_hdr; + struct os_mbuf *om; + void *v; + int payload_len; + int rc; + + hci_hdr = BLE_SM_TEST_UTIL_HCI_HDR( + 2, BLE_HCI_PB_FIRST_FLUSH, + BLE_L2CAP_HDR_SZ + + sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_pair_cmd)); + + om = ble_hs_mbuf_l2cap_pkt(); + TEST_ASSERT_FATAL(om != NULL); + + payload_len = sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_pair_cmd); + + v = os_mbuf_extend(om, payload_len); + TEST_ASSERT_FATAL(v != NULL); + + ble_sm_pair_cmd_write(v, payload_len, op == BLE_SM_OP_PAIR_REQ, cmd); + + rc = ble_hs_test_util_l2cap_rx_first_frag(conn_handle, BLE_L2CAP_CID_SM, + &hci_hdr, om); + TEST_ASSERT(rc == rx_status); +} + +static void +ble_sm_test_util_rx_pair_req(uint16_t conn_handle, + struct ble_sm_pair_cmd *req, + int rx_status) +{ + ble_sm_test_util_rx_pair_cmd(conn_handle, BLE_SM_OP_PAIR_REQ, + req, rx_status); +} + +static void +ble_sm_test_util_rx_pair_rsp(uint16_t conn_handle, struct ble_sm_pair_cmd *rsp, + int rx_status) +{ + ble_sm_test_util_rx_pair_cmd(conn_handle, BLE_SM_OP_PAIR_RSP, + rsp, rx_status); +} + +static void +ble_sm_test_util_rx_confirm(uint16_t conn_handle, + struct ble_sm_pair_confirm *cmd) +{ + struct hci_data_hdr hci_hdr; + struct os_mbuf *om; + void *v; + int payload_len; + int rc; + + hci_hdr = BLE_SM_TEST_UTIL_HCI_HDR( + 2, BLE_HCI_PB_FIRST_FLUSH, + BLE_L2CAP_HDR_SZ + + sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_pair_confirm)); + + om = ble_hs_mbuf_l2cap_pkt(); + TEST_ASSERT_FATAL(om != NULL); + + payload_len = + sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_pair_confirm); + + v = os_mbuf_extend(om, payload_len); + TEST_ASSERT_FATAL(v != NULL); + + ble_sm_pair_confirm_write(v, payload_len, cmd); + + rc = ble_hs_test_util_l2cap_rx_first_frag(conn_handle, BLE_L2CAP_CID_SM, + &hci_hdr, om); + TEST_ASSERT_FATAL(rc == 0); +} + +static void +ble_sm_test_util_rx_random(uint16_t conn_handle, + struct ble_sm_pair_random *cmd, + int exp_status) +{ + struct hci_data_hdr hci_hdr; + struct os_mbuf *om; + void *v; + int payload_len; + int rc; + + hci_hdr = BLE_SM_TEST_UTIL_HCI_HDR( + 2, BLE_HCI_PB_FIRST_FLUSH, + BLE_L2CAP_HDR_SZ + sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_pair_random)); + + om = ble_hs_mbuf_l2cap_pkt(); + TEST_ASSERT_FATAL(om != NULL); + + payload_len = sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_pair_random); + + v = os_mbuf_extend(om, payload_len); + TEST_ASSERT_FATAL(v != NULL); + + ble_sm_pair_random_write(v, payload_len, cmd); + + rc = ble_hs_test_util_l2cap_rx_first_frag(conn_handle, BLE_L2CAP_CID_SM, + &hci_hdr, om); + TEST_ASSERT_FATAL(rc == exp_status); +} + +void +ble_sm_test_util_rx_sec_req(uint16_t conn_handle, struct ble_sm_sec_req *cmd, + int exp_status) +{ + struct hci_data_hdr hci_hdr; + struct os_mbuf *om; + void *v; + int payload_len; + int rc; + + hci_hdr = BLE_SM_TEST_UTIL_HCI_HDR( + 2, BLE_HCI_PB_FIRST_FLUSH, + BLE_L2CAP_HDR_SZ + sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_sec_req)); + + om = ble_hs_mbuf_l2cap_pkt(); + TEST_ASSERT_FATAL(om != NULL); + + payload_len = sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_sec_req); + + v = os_mbuf_extend(om, payload_len); + TEST_ASSERT_FATAL(v != NULL); + + ble_sm_sec_req_write(v, payload_len, cmd); + + rc = ble_hs_test_util_l2cap_rx_first_frag(conn_handle, BLE_L2CAP_CID_SM, + &hci_hdr, om); + TEST_ASSERT_FATAL(rc == exp_status); +} + +static void +ble_sm_test_util_rx_public_key(uint16_t conn_handle, + struct ble_sm_public_key *cmd) +{ + struct hci_data_hdr hci_hdr; + struct os_mbuf *om; + void *v; + int payload_len; + int rc; + + hci_hdr = BLE_SM_TEST_UTIL_HCI_HDR( + 2, BLE_HCI_PB_FIRST_FLUSH, + BLE_L2CAP_HDR_SZ + sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_public_key)); + + om = ble_hs_mbuf_l2cap_pkt(); + TEST_ASSERT_FATAL(om != NULL); + + payload_len = sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_public_key); + + v = os_mbuf_extend(om, payload_len); + TEST_ASSERT_FATAL(v != NULL); + + ble_sm_public_key_write(v, payload_len, cmd); + + rc = ble_hs_test_util_l2cap_rx_first_frag(conn_handle, BLE_L2CAP_CID_SM, + &hci_hdr, om); + TEST_ASSERT_FATAL(rc == 0); +} + +static void +ble_sm_test_util_rx_dhkey_check(uint16_t conn_handle, + struct ble_sm_dhkey_check *cmd, + int exp_status) +{ + struct hci_data_hdr hci_hdr; + struct os_mbuf *om; + void *v; + int payload_len; + int rc; + + hci_hdr = BLE_SM_TEST_UTIL_HCI_HDR( + 2, BLE_HCI_PB_FIRST_FLUSH, + BLE_L2CAP_HDR_SZ + sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_dhkey_check)); + + om = ble_hs_mbuf_l2cap_pkt(); + TEST_ASSERT_FATAL(om != NULL); + + payload_len = sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_dhkey_check); + + v = os_mbuf_extend(om, payload_len); + TEST_ASSERT_FATAL(v != NULL); + + ble_sm_dhkey_check_write(v, payload_len, cmd); + + rc = ble_hs_test_util_l2cap_rx_first_frag(conn_handle, BLE_L2CAP_CID_SM, + &hci_hdr, om); + TEST_ASSERT_FATAL(rc == exp_status); +} + +static void +ble_sm_test_util_rx_enc_info(uint16_t conn_handle, + struct ble_sm_enc_info *cmd, + int exp_status) +{ + struct hci_data_hdr hci_hdr; + struct os_mbuf *om; + void *v; + int payload_len; + int rc; + + hci_hdr = BLE_SM_TEST_UTIL_HCI_HDR( + 2, BLE_HCI_PB_FIRST_FLUSH, + BLE_L2CAP_HDR_SZ + sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_enc_info)); + + om = ble_hs_mbuf_l2cap_pkt(); + TEST_ASSERT_FATAL(om != NULL); + + payload_len = sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_enc_info); + + v = os_mbuf_extend(om, payload_len); + TEST_ASSERT_FATAL(v != NULL); + + ble_sm_enc_info_write(v, payload_len, cmd); + + rc = ble_hs_test_util_l2cap_rx_first_frag(conn_handle, BLE_L2CAP_CID_SM, + &hci_hdr, om); + TEST_ASSERT_FATAL(rc == exp_status); +} + +static void +ble_sm_test_util_rx_master_id(uint16_t conn_handle, + struct ble_sm_master_id *cmd, + int exp_status) +{ + struct hci_data_hdr hci_hdr; + struct os_mbuf *om; + void *v; + int payload_len; + int rc; + + hci_hdr = BLE_SM_TEST_UTIL_HCI_HDR( + 2, BLE_HCI_PB_FIRST_FLUSH, + BLE_L2CAP_HDR_SZ + sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_master_id)); + + om = ble_hs_mbuf_l2cap_pkt(); + TEST_ASSERT_FATAL(om != NULL); + + payload_len = sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_master_id); + + v = os_mbuf_extend(om, payload_len); + TEST_ASSERT_FATAL(v != NULL); + + ble_sm_master_id_write(v, payload_len, cmd); + + rc = ble_hs_test_util_l2cap_rx_first_frag(conn_handle, BLE_L2CAP_CID_SM, + &hci_hdr, om); + TEST_ASSERT_FATAL(rc == exp_status); +} + +static void +ble_sm_test_util_rx_id_info(uint16_t conn_handle, + struct ble_sm_id_info *cmd, + int exp_status) +{ + struct hci_data_hdr hci_hdr; + struct os_mbuf *om; + void *v; + int payload_len; + int rc; + + hci_hdr = BLE_SM_TEST_UTIL_HCI_HDR( + 2, BLE_HCI_PB_FIRST_FLUSH, + BLE_L2CAP_HDR_SZ + sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_id_info)); + + om = ble_hs_mbuf_l2cap_pkt(); + TEST_ASSERT_FATAL(om != NULL); + + payload_len = sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_id_info); + + v = os_mbuf_extend(om, payload_len); + TEST_ASSERT_FATAL(v != NULL); + + ble_sm_id_info_write(v, payload_len, cmd); + + rc = ble_hs_test_util_l2cap_rx_first_frag(conn_handle, BLE_L2CAP_CID_SM, + &hci_hdr, om); + TEST_ASSERT_FATAL(rc == exp_status); +} + +static void +ble_sm_test_util_rx_id_addr_info(uint16_t conn_handle, + struct ble_sm_id_addr_info *cmd, + int exp_status) +{ + struct hci_data_hdr hci_hdr; + struct os_mbuf *om; + void *v; + int payload_len; + int rc; + + hci_hdr = BLE_SM_TEST_UTIL_HCI_HDR( + 2, BLE_HCI_PB_FIRST_FLUSH, + BLE_L2CAP_HDR_SZ + sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_id_addr_info)); + + om = ble_hs_mbuf_l2cap_pkt(); + TEST_ASSERT_FATAL(om != NULL); + + payload_len = sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_id_addr_info); + + v = os_mbuf_extend(om, payload_len); + TEST_ASSERT_FATAL(v != NULL); + + ble_sm_id_addr_info_write(v, payload_len, cmd); + + rc = ble_hs_test_util_l2cap_rx_first_frag(conn_handle, BLE_L2CAP_CID_SM, + &hci_hdr, om); + TEST_ASSERT_FATAL(rc == exp_status); +} + +static void +ble_sm_test_util_rx_sign_info(uint16_t conn_handle, + struct ble_sm_sign_info *cmd, + int exp_status) +{ + struct hci_data_hdr hci_hdr; + struct os_mbuf *om; + void *v; + int payload_len; + int rc; + + hci_hdr = BLE_SM_TEST_UTIL_HCI_HDR( + 2, BLE_HCI_PB_FIRST_FLUSH, + BLE_L2CAP_HDR_SZ + sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_sign_info)); + + om = ble_hs_mbuf_l2cap_pkt(); + TEST_ASSERT_FATAL(om != NULL); + + payload_len = sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_sign_info); + + v = os_mbuf_extend(om, payload_len); + TEST_ASSERT_FATAL(v != NULL); + + ble_sm_sign_info_write(v, payload_len, cmd); + + rc = ble_hs_test_util_l2cap_rx_first_frag(conn_handle, BLE_L2CAP_CID_SM, + &hci_hdr, om); + TEST_ASSERT_FATAL(rc == exp_status); +} + +static struct os_mbuf * +ble_sm_test_util_verify_tx_hdr(uint8_t sm_op, uint16_t payload_len) +{ + struct os_mbuf *om; + + om = ble_hs_test_util_prev_tx_dequeue_pullup(); + TEST_ASSERT_FATAL(om != NULL); + + TEST_ASSERT(OS_MBUF_PKTLEN(om) == sizeof(struct ble_sm_hdr) + payload_len); + TEST_ASSERT_FATAL(om->om_data[0] == sm_op); + + om->om_data += sizeof(struct ble_sm_hdr); + om->om_len -= sizeof(struct ble_sm_hdr); + + return om; +} + +static void +ble_sm_test_util_verify_tx_pair_cmd( + uint8_t op, + struct ble_sm_pair_cmd *exp_cmd) +{ + struct ble_sm_pair_cmd cmd; + struct os_mbuf *om; + + om = ble_sm_test_util_verify_tx_hdr(op, sizeof(struct ble_sm_pair_cmd)); + ble_sm_pair_cmd_parse(om->om_data, om->om_len, &cmd); + + TEST_ASSERT(cmd.io_cap == exp_cmd->io_cap); + TEST_ASSERT(cmd.oob_data_flag == exp_cmd->oob_data_flag); + TEST_ASSERT(cmd.authreq == exp_cmd->authreq); + TEST_ASSERT(cmd.max_enc_key_size == exp_cmd->max_enc_key_size); + TEST_ASSERT(cmd.init_key_dist == exp_cmd->init_key_dist); + TEST_ASSERT(cmd.resp_key_dist == exp_cmd->resp_key_dist); +} + +static void +ble_sm_test_util_verify_tx_pair_req( + struct ble_sm_pair_cmd *exp_req) +{ + ble_sm_test_util_verify_tx_pair_cmd(BLE_SM_OP_PAIR_REQ, + exp_req); +} + +static void +ble_sm_test_util_verify_tx_pair_rsp( + struct ble_sm_pair_cmd *exp_rsp) +{ + ble_sm_test_util_verify_tx_pair_cmd(BLE_SM_OP_PAIR_RSP, + exp_rsp); +} + +static void +ble_sm_test_util_verify_tx_pair_confirm( + struct ble_sm_pair_confirm *exp_cmd) +{ + struct ble_sm_pair_confirm cmd; + struct os_mbuf *om; + + om = ble_sm_test_util_verify_tx_hdr(BLE_SM_OP_PAIR_CONFIRM, sizeof(cmd)); + ble_sm_pair_confirm_parse(om->om_data, om->om_len, &cmd); + + TEST_ASSERT(memcmp(cmd.value, exp_cmd->value, 16) == 0); +} + +static void +ble_sm_test_util_verify_tx_pair_random( + struct ble_sm_pair_random *exp_cmd) +{ + struct ble_sm_pair_random cmd; + struct os_mbuf *om; + + om = ble_sm_test_util_verify_tx_hdr(BLE_SM_OP_PAIR_RANDOM, + sizeof(struct ble_sm_pair_random)); + ble_sm_pair_random_parse(om->om_data, om->om_len, &cmd); + + TEST_ASSERT(memcmp(cmd.value, exp_cmd->value, 16) == 0); +} + +static void +ble_sm_test_util_verify_tx_public_key( + struct ble_sm_public_key *exp_cmd) +{ + struct ble_sm_public_key cmd; + struct os_mbuf *om; + + om = ble_sm_test_util_verify_tx_hdr(BLE_SM_OP_PAIR_PUBLIC_KEY, + sizeof(struct ble_sm_public_key)); + ble_sm_public_key_parse(om->om_data, om->om_len, &cmd); + + TEST_ASSERT(memcmp(cmd.x, exp_cmd->x, sizeof cmd.x) == 0); + TEST_ASSERT(memcmp(cmd.y, exp_cmd->y, sizeof cmd.y) == 0); +} + +static void +ble_sm_test_util_verify_tx_dhkey_check( + struct ble_sm_dhkey_check *exp_cmd) +{ + struct ble_sm_dhkey_check cmd; + struct os_mbuf *om; + + om = ble_sm_test_util_verify_tx_hdr(BLE_SM_OP_PAIR_DHKEY_CHECK, + sizeof(struct ble_sm_dhkey_check)); + ble_sm_dhkey_check_parse(om->om_data, om->om_len, &cmd); + + TEST_ASSERT(memcmp(cmd.value, exp_cmd->value, 16) == 0); +} + +static void +ble_sm_test_util_verify_tx_enc_info(struct ble_sm_enc_info *exp_cmd) +{ + struct ble_sm_enc_info cmd; + struct os_mbuf *om; + + om = ble_sm_test_util_verify_tx_hdr(BLE_SM_OP_ENC_INFO, + sizeof(struct ble_sm_enc_info)); + ble_sm_enc_info_parse(om->om_data, om->om_len, &cmd); + + TEST_ASSERT(memcmp(cmd.ltk, exp_cmd->ltk, 16) == 0); + + /* Ensure LTK is sent in little endian. */ + TEST_ASSERT(memcmp(om->om_data, cmd.ltk, 16) == 0); +} + +static void +ble_sm_test_util_verify_tx_master_id(struct ble_sm_master_id *exp_cmd) +{ + struct ble_sm_master_id cmd; + struct os_mbuf *om; + + om = ble_sm_test_util_verify_tx_hdr(BLE_SM_OP_MASTER_ID, + sizeof(struct ble_sm_master_id)); + ble_sm_master_id_parse(om->om_data, om->om_len, &cmd); + + TEST_ASSERT(cmd.ediv == exp_cmd->ediv); + TEST_ASSERT(cmd.rand_val == exp_cmd->rand_val); +} + +static void +ble_sm_test_util_verify_tx_id_info(struct ble_sm_id_info *exp_cmd) +{ + struct ble_sm_id_info cmd; + struct os_mbuf *om; + + om = ble_sm_test_util_verify_tx_hdr(BLE_SM_OP_IDENTITY_INFO, + sizeof(struct ble_sm_id_info)); + ble_sm_id_info_parse(om->om_data, om->om_len, &cmd); + + TEST_ASSERT(memcmp(cmd.irk, exp_cmd->irk, 16) == 0); + + /* Ensure IRK is sent in little endian. */ + TEST_ASSERT(memcmp(om->om_data, cmd.irk, 16) == 0); +} + +static void +ble_sm_test_util_verify_tx_id_addr_info(struct ble_sm_id_addr_info *exp_cmd) +{ + struct ble_sm_id_addr_info cmd; + struct os_mbuf *om; + const uint8_t *our_id_addr; + int rc; + + ble_hs_lock(); + rc = ble_hs_id_addr(exp_cmd->addr_type, &our_id_addr, NULL); + ble_hs_unlock(); + + TEST_ASSERT_FATAL(rc == 0); + + om = ble_sm_test_util_verify_tx_hdr(BLE_SM_OP_IDENTITY_ADDR_INFO, + sizeof(struct ble_sm_id_addr_info)); + ble_sm_id_addr_info_parse(om->om_data, om->om_len, &cmd); + + TEST_ASSERT(cmd.addr_type == exp_cmd->addr_type); + TEST_ASSERT(memcmp(cmd.bd_addr, exp_cmd->bd_addr, 6) == 0); + TEST_ASSERT(memcmp(cmd.bd_addr, our_id_addr, 6) == 0); +} + +static void +ble_sm_test_util_verify_tx_sign_info(struct ble_sm_sign_info *exp_cmd) +{ + struct ble_sm_sign_info cmd; + struct os_mbuf *om; + + om = ble_sm_test_util_verify_tx_hdr(BLE_SM_OP_SIGN_INFO, + sizeof(struct ble_sm_sign_info)); + ble_sm_sign_info_parse(om->om_data, om->om_len, &cmd); + + TEST_ASSERT(memcmp(cmd.sig_key, exp_cmd->sig_key, 16) == 0); + + /* Ensure CSRK is sent in little endian. */ + TEST_ASSERT(memcmp(om->om_data, cmd.sig_key, 16) == 0); +} + +static void +ble_sm_test_util_verify_tx_sec_req(struct ble_sm_sec_req *exp_cmd) +{ + struct ble_sm_sec_req cmd; + struct os_mbuf *om; + + om = ble_sm_test_util_verify_tx_hdr(BLE_SM_OP_SEC_REQ, sizeof(struct ble_sm_sec_req)); + ble_sm_sec_req_parse(om->om_data, om->om_len, &cmd); + + TEST_ASSERT(cmd.authreq == exp_cmd->authreq); +} + +void +ble_sm_test_util_verify_tx_pair_fail( + struct ble_sm_pair_fail *exp_cmd) +{ + struct ble_sm_pair_fail cmd; + struct os_mbuf *om; + + om = ble_sm_test_util_verify_tx_hdr(BLE_SM_OP_PAIR_FAIL, + sizeof(struct ble_sm_pair_fail)); + ble_sm_pair_fail_parse(om->om_data, om->om_len, &cmd); + + TEST_ASSERT(cmd.reason == exp_cmd->reason); +} + +static void +ble_sm_test_util_rx_lt_key_req(uint16_t conn_handle, uint64_t r, uint16_t ediv) +{ + struct ble_hci_ev_le_subev_lt_key_req evt; + int rc; + + evt.subev_code = BLE_HCI_LE_SUBEV_LT_KEY_REQ; + evt.conn_handle = htole16(conn_handle); + evt.rand = htole64(r); + evt.div = htole16(ediv); + + rc = ble_sm_ltk_req_rx(&evt); + TEST_ASSERT_FATAL(rc == 0); +} + +static void +ble_sm_test_util_verify_tx_lt_key_req_reply(uint16_t conn_handle, uint8_t *stk) +{ + uint8_t param_len; + uint8_t *param; + + param = ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_LT_KEY_REQ_REPLY, + ¶m_len); + TEST_ASSERT(param_len == BLE_HCI_LT_KEY_REQ_REPLY_LEN); + TEST_ASSERT(get_le16(param + 0) == conn_handle); + TEST_ASSERT(memcmp(param + 2, stk, 16) == 0); +} + +static void +ble_sm_test_util_verify_tx_lt_key_req_neg_reply(uint16_t conn_handle) +{ + uint8_t param_len; + uint8_t *param; + + param = ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_LT_KEY_REQ_NEG_REPLY, + ¶m_len); + TEST_ASSERT(param_len == BLE_HCI_LT_KEY_REQ_NEG_REPLY_LEN); + TEST_ASSERT(get_le16(param + 0) == conn_handle); +} + +static void +ble_sm_test_util_set_lt_key_req_neg_reply_ack(uint8_t status, + uint16_t conn_handle) +{ + static uint8_t params[BLE_HCI_LT_KEY_REQ_NEG_REPLY_ACK_PARAM_LEN]; + + put_le16(params, conn_handle); + ble_hs_test_util_hci_ack_set_params( + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_LT_KEY_REQ_NEG_REPLY), + status, params, sizeof params); +} + +static void +ble_sm_test_util_set_lt_key_req_reply_ack(uint8_t status, uint16_t conn_handle) +{ + static uint8_t params[BLE_HCI_LT_KEY_REQ_REPLY_ACK_PARAM_LEN]; + + put_le16(params, conn_handle); + ble_hs_test_util_hci_ack_set_params( + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_LT_KEY_REQ_REPLY), + status, params, sizeof params); +} + +static void +ble_sm_test_util_rx_enc_change(uint16_t conn_handle, uint8_t status, + uint8_t encryption_enabled) +{ + struct ble_hci_ev_enrypt_chg evt; + + evt.status = status; + evt.enabled = encryption_enabled; + evt.connection_handle = htole16(conn_handle); + + ble_sm_enc_change_rx(&evt); +} + +static void +ble_sm_test_util_verify_tx_start_enc(uint16_t conn_handle, + uint64_t random_number, + uint16_t ediv, + uint8_t *ltk) +{ + uint8_t param_len; + uint8_t *param; + + param = ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_START_ENCRYPT, + ¶m_len); + TEST_ASSERT(param_len == BLE_HCI_LE_START_ENCRYPT_LEN); + TEST_ASSERT(get_le16(param + 0) == conn_handle); + TEST_ASSERT(get_le64(param + 2) == random_number); + TEST_ASSERT(get_le16(param + 10) == ediv); + TEST_ASSERT(memcmp(param + 12, ltk, 16) == 0); +} + +static void +ble_sm_test_util_verify_tx_add_resolve_list(uint8_t peer_id_addr_type, + uint8_t *peer_id_addr, + uint8_t *peer_irk, + uint8_t *our_irk) +{ + uint8_t param_len; + uint8_t *param; + + ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_SET_ADV_ENABLE, + NULL); + + param = ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_ADD_RESOLV_LIST, + ¶m_len); + TEST_ASSERT(param_len == BLE_HCI_ADD_TO_RESOLV_LIST_LEN); + TEST_ASSERT(param[0] == peer_id_addr_type); + TEST_ASSERT(memcmp(param + 1, peer_id_addr, 6) == 0); + + /* Ensure IRKs are sent in little endian. */ + TEST_ASSERT(memcmp(param + 7, peer_irk, 16) == 0); + TEST_ASSERT(memcmp(param + 23, our_irk, 16) == 0); +} + +void +ble_sm_test_util_io_inject(struct ble_sm_test_passkey_info *passkey_info, + uint8_t cur_sm_state) +{ + uint8_t io_sm_state; + int rc; + + io_sm_state = ble_sm_ioact_state(passkey_info->passkey.action); + if (io_sm_state != cur_sm_state) { + TEST_ASSERT(ble_sm_test_ioact.action == BLE_SM_IOACT_NONE); + return; + } + + TEST_ASSERT(ble_sm_test_ioact.action == passkey_info->passkey.action); + + if (passkey_info->passkey.action == BLE_SM_IOACT_NUMCMP) { + TEST_ASSERT(ble_sm_test_ioact.numcmp == passkey_info->exp_numcmp); + } + + rc = ble_sm_inject_io(2, &passkey_info->passkey); + TEST_ASSERT(rc == 0); + + ble_sm_test_ioact.action = BLE_SM_IOACT_NONE; +} + +void +ble_sm_test_util_io_inject_bad(uint16_t conn_handle, uint8_t correct_io_act) +{ + struct ble_sm_proc *proc; + struct ble_sm_io io; + uint8_t io_sm_state; + int already_injected; + int rc; + int i; + + /* Lock mutex to prevent thread-safety assert from failing. */ + ble_hs_lock(); + proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_NONE, -1, NULL); + ble_hs_unlock(); + + TEST_ASSERT_FATAL(proc != NULL); + + io_sm_state = ble_sm_ioact_state(correct_io_act); + + for (i = 1; i < BLE_SM_IOACT_MAX_PLUS_ONE; i++) { + if (io_sm_state != proc->state || + i != correct_io_act || + proc->flags & BLE_SM_PROC_F_IO_INJECTED) { + + already_injected = proc->flags & BLE_SM_PROC_F_IO_INJECTED; + + io.action = i; + rc = ble_sm_inject_io(conn_handle, &io); + + if (already_injected) { + TEST_ASSERT(rc == BLE_HS_EALREADY); + } else { + TEST_ASSERT(rc == BLE_HS_EINVAL); + } + } + } +} + +void +ble_sm_test_util_io_check_pre(struct ble_sm_test_passkey_info *passkey_info, + uint8_t cur_sm_state) +{ + uint8_t io_sm_state; + int rc; + + io_sm_state = ble_sm_ioact_state(passkey_info->passkey.action); + if (io_sm_state != cur_sm_state) { + return; + } + + if (!passkey_info->io_before_rx) { + return; + } + + if (passkey_info->passkey.action == BLE_SM_IOACT_NUMCMP) { + TEST_ASSERT(ble_sm_test_ioact.numcmp == passkey_info->exp_numcmp); + } + + rc = ble_sm_inject_io(2, &passkey_info->passkey); + TEST_ASSERT(rc == 0); +} + +void +ble_sm_test_util_io_check_post(struct ble_sm_test_passkey_info *passkey_info, + uint8_t cur_sm_state) +{ + uint8_t io_sm_state; + int rc; + + io_sm_state = ble_sm_ioact_state(passkey_info->passkey.action); + if (io_sm_state != cur_sm_state) { + return; + } + + if (passkey_info->io_before_rx) { + return; + } + + if (passkey_info->passkey.action == BLE_SM_IOACT_NUMCMP) { + TEST_ASSERT(ble_sm_test_ioact.numcmp == passkey_info->exp_numcmp); + } + + /* Ensure response not sent until user performs IO. */ + TEST_ASSERT(ble_hs_test_util_prev_tx_queue_sz() == 0); + + rc = ble_sm_inject_io(2, &passkey_info->passkey); + TEST_ASSERT_FATAL(rc == 0); +} + +static void +ble_sm_test_util_verify_persist(struct ble_sm_test_params *params, + int we_are_initiator) +{ + struct ble_sm_test_util_entity peer_entity; + struct ble_sm_test_util_entity our_entity; + struct ble_store_value_sec value_sec; + struct ble_store_key_sec key_sec; + int csrk_expected; + int ltk_expected; + int peer_irk_expected; + int our_irk_expected; + int bonding; + int sc; + int rc; + + ble_sm_test_util_params_to_entities(params, we_are_initiator, + &our_entity, &peer_entity); + + sc = params->pair_req.authreq & BLE_SM_PAIR_AUTHREQ_SC && + params->pair_rsp.authreq & BLE_SM_PAIR_AUTHREQ_SC; + + bonding = params->pair_req.authreq & BLE_SM_PAIR_AUTHREQ_BOND && + params->pair_rsp.authreq & BLE_SM_PAIR_AUTHREQ_BOND; + + memset(&key_sec, 0, sizeof key_sec); + key_sec.peer_addr = *BLE_ADDR_ANY; + + rc = ble_store_read_peer_sec(&key_sec, &value_sec); + if (!bonding) { + TEST_ASSERT(rc == BLE_HS_ENOENT); + peer_irk_expected = 0; + } else { + TEST_ASSERT_FATAL(rc == 0); + + ltk_expected = + sc || !!(peer_entity.key_dist & BLE_SM_PAIR_KEY_DIST_ENC); + peer_irk_expected = + !!(peer_entity.key_dist & BLE_SM_PAIR_KEY_DIST_ID); + csrk_expected = + !!(peer_entity.key_dist & BLE_SM_PAIR_KEY_DIST_SIGN); + + TEST_ASSERT(value_sec.peer_addr.type == peer_entity.id_addr_type); + TEST_ASSERT( + memcmp(value_sec.peer_addr.val, peer_entity.id_addr, 6) == 0); + TEST_ASSERT(value_sec.ediv == peer_entity.ediv); + TEST_ASSERT(value_sec.rand_num == peer_entity.rand_num); + TEST_ASSERT(value_sec.authenticated == params->authenticated); + + TEST_ASSERT(value_sec.ltk_present == ltk_expected); + TEST_ASSERT(memcmp(value_sec.ltk, peer_entity.ltk, 16) == 0); + + TEST_ASSERT(value_sec.irk_present == peer_irk_expected); + if (peer_irk_expected) { + TEST_ASSERT(memcmp(value_sec.irk, + peer_entity.id_info->irk, 16) == 0); + } + + TEST_ASSERT(value_sec.csrk_present == csrk_expected); + if (csrk_expected) { + TEST_ASSERT(memcmp(value_sec.csrk, + peer_entity.sign_info->sig_key, 16) == 0); + } + } + + rc = ble_store_read_our_sec(&key_sec, &value_sec); + if (!bonding) { + TEST_ASSERT(rc == BLE_HS_ENOENT); + } else { + TEST_ASSERT_FATAL(rc == 0); + + ltk_expected = + sc || !!(our_entity.key_dist & BLE_SM_PAIR_KEY_DIST_ENC); + our_irk_expected = + !!(our_entity.key_dist & BLE_SM_PAIR_KEY_DIST_ID); + csrk_expected = + !!(our_entity.key_dist & BLE_SM_PAIR_KEY_DIST_SIGN); + + TEST_ASSERT(value_sec.peer_addr.type == peer_entity.id_addr_type); + TEST_ASSERT(memcmp(value_sec.peer_addr.val, peer_entity.id_addr, 6) == 0); + TEST_ASSERT(value_sec.ediv == our_entity.ediv); + TEST_ASSERT(value_sec.rand_num == our_entity.rand_num); + TEST_ASSERT(value_sec.authenticated == params->authenticated); + + TEST_ASSERT(value_sec.ltk_present == ltk_expected); + TEST_ASSERT(memcmp(value_sec.ltk, our_entity.ltk, 16) == 0); + + TEST_ASSERT(value_sec.irk_present == our_irk_expected); + if (our_irk_expected) { + TEST_ASSERT(memcmp(value_sec.irk, + our_entity.id_info->irk, 16) == 0); + } + + TEST_ASSERT(value_sec.csrk_present == csrk_expected); + if (csrk_expected) { + TEST_ASSERT(memcmp(value_sec.csrk, + our_entity.sign_info->sig_key, 16) == 0); + } + } + + /* Verify no other keys were persisted. */ + key_sec.idx++; + rc = ble_store_read_our_sec(&key_sec, &value_sec); + TEST_ASSERT_FATAL(rc == BLE_HS_ENOENT); + rc = ble_store_read_peer_sec(&key_sec, &value_sec); + TEST_ASSERT_FATAL(rc == BLE_HS_ENOENT); + + /* Verify we sent the peer's IRK to the controller. */ + if (peer_irk_expected) { + ble_sm_test_util_verify_tx_add_resolve_list(peer_entity.id_addr_type, + peer_entity.id_addr, + peer_entity.id_info->irk, + our_entity.id_info->irk); + } +} + +static void +ble_sm_test_util_peer_bonding_good(int send_enc_req, + uint8_t our_addr_type, + uint8_t *our_rpa, + uint8_t peer_addr_type, + uint8_t *peer_id_addr, + uint8_t *peer_rpa, + uint8_t *ltk, int authenticated, + uint16_t ediv, uint64_t rand_num) +{ + struct ble_hs_conn *conn; + int rc; + + ble_hs_test_util_create_rpa_conn(2, our_addr_type, our_rpa, peer_addr_type, + peer_id_addr, peer_rpa, + BLE_HS_TEST_CONN_FEAT_ALL, + ble_sm_test_util_conn_cb, NULL); + + /* This test inspects and modifies the connection object after unlocking + * the host mutex. It is not OK for real code to do this, but this test + * can assume the connection list is unchanging. + */ + ble_hs_lock(); + conn = ble_hs_conn_find(2); + TEST_ASSERT_FATAL(conn != NULL); + conn->bhc_flags &= ~BLE_HS_CONN_F_MASTER; + ble_hs_unlock(); + + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 0); + + if (send_enc_req) { + rc = ble_sm_slave_initiate(2); + TEST_ASSERT(rc == 0); + } + + /* Receive a long term key request from the controller. */ + ble_sm_test_util_set_lt_key_req_reply_ack(0, 2); + ble_sm_test_util_rx_lt_key_req(2, rand_num, ediv); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + + /* Ensure the LTK request event got sent to the application. */ + TEST_ASSERT(ble_sm_test_store_obj_type == BLE_STORE_OBJ_TYPE_OUR_SEC); + TEST_ASSERT(ble_sm_test_store_key.sec.peer_addr.type == + ble_hs_misc_peer_addr_type_to_id(peer_addr_type)); + TEST_ASSERT(ble_sm_test_store_key.sec.ediv_rand_present); + TEST_ASSERT(ble_sm_test_store_key.sec.ediv == ediv); + TEST_ASSERT(ble_sm_test_store_key.sec.rand_num == rand_num); + + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, BLE_SM_IOACT_NONE); + + /* Ensure we sent the expected long term key request reply command. */ + ble_sm_test_util_verify_tx_lt_key_req_reply(2, ltk); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, BLE_SM_IOACT_NONE); + + /* Receive an encryption changed event. */ + ble_sm_test_util_rx_enc_change(2, 0, 1); + + /* Pairing should now be complete. */ + TEST_ASSERT(ble_sm_num_procs() == 0); + + /* Verify that security callback was executed. */ + TEST_ASSERT(ble_sm_test_gap_event_type == BLE_GAP_EVENT_ENC_CHANGE); + TEST_ASSERT(ble_sm_test_gap_status == 0); + TEST_ASSERT(ble_sm_test_sec_state.encrypted); + TEST_ASSERT(ble_sm_test_sec_state.authenticated == + authenticated); + + /* Verify that connection has correct security state. */ + TEST_ASSERT(ble_sm_test_sec_state.encrypted); + TEST_ASSERT(ble_sm_test_sec_state.authenticated == + authenticated); + + ble_hs_test_util_conn_disconnect(2); +} + +void +ble_sm_test_util_peer_bonding_bad(uint16_t ediv, uint64_t rand_num) +{ + struct ble_hs_conn *conn; + + ble_sm_test_util_init(); + + ble_hs_test_util_create_conn(2, ((uint8_t[6]){1,2,3,4,5,6}), + ble_sm_test_util_conn_cb, + NULL); + + /* This test inspects and modifies the connection object after unlocking + * the host mutex. It is not OK for real code to do this, but this test + * can assume the connection list is unchanging. + */ + ble_hs_lock(); + conn = ble_hs_conn_find(2); + TEST_ASSERT_FATAL(conn != NULL); + conn->bhc_flags &= ~BLE_HS_CONN_F_MASTER; + ble_hs_unlock(); + + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 0); + + /* Receive a long term key request from the controller. */ + ble_sm_test_util_set_lt_key_req_neg_reply_ack(0, 2); + ble_sm_test_util_rx_lt_key_req(2, rand_num, ediv); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + + /* Ensure the LTK request event got sent to the application. */ + TEST_ASSERT(ble_sm_test_store_obj_type == + BLE_STORE_OBJ_TYPE_OUR_SEC); + TEST_ASSERT(ble_sm_test_store_key.sec.ediv_rand_present); + TEST_ASSERT(ble_sm_test_store_key.sec.ediv == ediv); + TEST_ASSERT(ble_sm_test_store_key.sec.rand_num == rand_num); + + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + + /* Ensure we sent the expected long term key request neg reply command. */ + ble_sm_test_util_verify_tx_lt_key_req_neg_reply(2); + + /* Ensure the security procedure was aborted. */ + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(!conn->bhc_sec_state.authenticated); + TEST_ASSERT(ble_sm_num_procs() == 0); +} + +/** + * @param send_enc_req Whether this procedure is initiated by a slave + * security request; + * 1: Peer sends a security request at start. + * 0: No security request; we initiate. + */ +static void +ble_sm_test_util_us_bonding_good(int send_enc_req, uint8_t our_addr_type, + uint8_t *our_rpa, + uint8_t peer_addr_type, + uint8_t *peer_id_addr, uint8_t *peer_rpa, + uint8_t *ltk, int authenticated, + uint16_t ediv, uint64_t rand_num) +{ + struct ble_sm_sec_req sec_req; + struct ble_hs_conn *conn; + + ble_hs_test_util_create_rpa_conn(2, our_addr_type, our_rpa, + peer_addr_type, peer_id_addr, + peer_rpa, BLE_HS_TEST_CONN_FEAT_ALL, + ble_sm_test_util_conn_cb, NULL); + + /* This test inspects and modifies the connection object after unlocking + * the host mutex. It is not OK for real code to do this, but this test + * can assume the connection list is unchanging. + */ + ble_hs_lock(); + conn = ble_hs_conn_find(2); + TEST_ASSERT_FATAL(conn != NULL); + ble_hs_unlock(); + + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 0); + + ble_hs_test_util_hci_ack_set( + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_START_ENCRYPT), + 0); + + if (send_enc_req) { + sec_req.authreq = 0; + sec_req.authreq |= BLE_SM_PAIR_AUTHREQ_BOND; + if (authenticated) { + sec_req.authreq |= BLE_SM_PAIR_AUTHREQ_MITM; + } + ble_sm_test_util_rx_sec_req(2, &sec_req, 0); + } else { + ble_gap_security_initiate(2); + } + + /* Ensure we sent the expected start encryption command. */ + ble_sm_test_util_verify_tx_start_enc(2, rand_num, ediv, ltk); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, BLE_SM_IOACT_NONE); + + /* Receive an encryption changed event. */ + ble_sm_test_util_rx_enc_change(2, 0, 1); + + /* Pairing should now be complete. */ + TEST_ASSERT(ble_sm_num_procs() == 0); + + /* Verify that security callback was executed. */ + TEST_ASSERT(ble_sm_test_gap_event_type == BLE_GAP_EVENT_ENC_CHANGE); + TEST_ASSERT(ble_sm_test_gap_status == 0); + TEST_ASSERT(ble_sm_test_sec_state.encrypted); + TEST_ASSERT(ble_sm_test_sec_state.authenticated == + authenticated); + + /* Verify that connection has correct security state. */ + TEST_ASSERT(ble_sm_test_sec_state.encrypted); + TEST_ASSERT(ble_sm_test_sec_state.authenticated == + authenticated); + + ble_hs_test_util_conn_disconnect(2); +} + +void +ble_sm_test_util_peer_fail_inval( + int we_are_master, + uint8_t *init_id_addr, + uint8_t *resp_addr, + struct ble_sm_pair_cmd *pair_req, + struct ble_sm_pair_fail *pair_fail) +{ + struct ble_hs_conn *conn; + + ble_sm_test_util_init(); + ble_hs_id_set_pub(resp_addr); + + ble_hs_test_util_create_conn(2, init_id_addr, ble_sm_test_util_conn_cb, + NULL); + + /* This test inspects and modifies the connection object after unlocking + * the host mutex. It is not OK for real code to do this, but this test + * can assume the connection list is unchanging. + */ + ble_hs_lock(); + conn = ble_hs_conn_find(2); + TEST_ASSERT_FATAL(conn != NULL); + ble_hs_unlock(); + + if (!we_are_master) { + conn->bhc_flags &= ~BLE_HS_CONN_F_MASTER; + } + + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 0); + + /* Receive a pair request from the peer. */ + ble_sm_test_util_rx_pair_req(2, pair_req, + BLE_HS_SM_US_ERR(pair_fail->reason)); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 0); + + /* Ensure we sent the expected pair fail. */ + ble_sm_test_util_verify_tx_pair_fail(pair_fail); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 0); + + /* Verify that security callback was not executed. */ + TEST_ASSERT(ble_sm_test_gap_event_type == -1); + TEST_ASSERT(ble_sm_test_gap_status == -1); + + /* Verify that connection has correct security state. */ + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(!conn->bhc_sec_state.authenticated); +} + +void +ble_sm_test_util_peer_lgcy_fail_confirm( + uint8_t *init_id_addr, + uint8_t *resp_addr, + struct ble_sm_pair_cmd *pair_req, + struct ble_sm_pair_cmd *pair_rsp, + struct ble_sm_pair_confirm *confirm_req, + struct ble_sm_pair_confirm *confirm_rsp, + struct ble_sm_pair_random *random_req, + struct ble_sm_pair_random *random_rsp, + struct ble_sm_pair_fail *fail_rsp) +{ + struct ble_hs_conn *conn; + + ble_sm_test_util_init(); + ble_hs_id_set_pub(resp_addr); + ble_sm_dbg_set_next_pair_rand(random_rsp->value); + + if (pair_rsp->authreq & BLE_SM_PAIR_AUTHREQ_SC) { + ble_hs_cfg.sm_sc = 1; + } else { + ble_hs_cfg.sm_sc = 0; + } + + ble_hs_test_util_create_conn(2, init_id_addr, ble_sm_test_util_conn_cb, + NULL); + + /* This test inspects and modifies the connection object after unlocking + * the host mutex. It is not OK for real code to do this, but this test + * can assume the connection list is unchanging. + */ + ble_hs_lock(); + conn = ble_hs_conn_find(2); + TEST_ASSERT_FATAL(conn != NULL); + ble_hs_unlock(); + + /* Peer is the initiator so we must be the slave. */ + conn->bhc_flags &= ~BLE_HS_CONN_F_MASTER; + + TEST_ASSERT(ble_sm_num_procs() == 0); + + /* Receive a pair request from the peer. */ + ble_sm_test_util_rx_pair_req(2, pair_req, 0); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, BLE_SM_IOACT_NONE); + + /* Ensure we sent the expected pair response. */ + ble_sm_test_util_verify_tx_pair_rsp(pair_rsp); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, BLE_SM_IOACT_NONE); + + /* Receive a pair confirm from the peer. */ + ble_sm_test_util_rx_confirm(2, confirm_req); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, BLE_SM_IOACT_NONE); + + /* Ensure we sent the expected pair confirm. */ + ble_sm_test_util_verify_tx_pair_confirm(confirm_rsp); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, BLE_SM_IOACT_NONE); + + /* Receive a pair random from the peer. */ + ble_sm_test_util_rx_random( + 2, random_req, BLE_HS_SM_US_ERR(BLE_SM_ERR_CONFIRM_MISMATCH)); + + /* Ensure we sent the expected pair fail. */ + ble_sm_test_util_verify_tx_pair_fail(fail_rsp); + + /* The proc should now be freed. */ + TEST_ASSERT(ble_sm_num_procs() == 0); + + /* Verify that security callback was executed. */ + TEST_ASSERT(ble_sm_test_gap_event_type == BLE_GAP_EVENT_ENC_CHANGE); + TEST_ASSERT(ble_sm_test_gap_status == + BLE_HS_SM_US_ERR(BLE_SM_ERR_CONFIRM_MISMATCH)); + TEST_ASSERT(!ble_sm_test_sec_state.encrypted); + TEST_ASSERT(!ble_sm_test_sec_state.authenticated); + + /* Verify that connection has correct security state. */ + TEST_ASSERT(ble_sm_test_sec_state.encrypted == + conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_test_sec_state.authenticated == + conn->bhc_sec_state.authenticated); +} + +static void +ble_sm_test_util_bonding_all(struct ble_sm_test_params *params, + int we_are_original_initiator) +{ + struct ble_sm_test_util_entity peer_entity; + struct ble_sm_test_util_entity our_entity; + int sc; + + if (!(params->pair_req.authreq & BLE_SM_PAIR_AUTHREQ_BOND) || + !(params->pair_rsp.authreq & BLE_SM_PAIR_AUTHREQ_BOND)) { + + /* Bonding not performed. */ + return; + } + + sc = params->pair_req.authreq & BLE_SM_PAIR_AUTHREQ_SC && + params->pair_rsp.authreq & BLE_SM_PAIR_AUTHREQ_SC; + + ble_sm_test_util_params_to_entities(params, we_are_original_initiator, + &our_entity, &peer_entity); + + if (sc || peer_entity.key_dist & BLE_SM_PAIR_KEY_DIST_ENC) { + /* We are master; we initiate procedure. */ + ble_sm_test_util_us_bonding_good(0, our_entity.addr_type, + our_entity.rpa, + peer_entity.addr_type, + peer_entity.id_addr, + peer_entity.rpa, + peer_entity.ltk, + params->authenticated, + peer_entity.ediv, + peer_entity.rand_num); + + /* We are master; peer initiates procedure via security request. */ + ble_sm_test_util_us_bonding_good(1, our_entity.addr_type, + our_entity.rpa, + peer_entity.addr_type, + peer_entity.id_addr, + peer_entity.rpa, + peer_entity.ltk, + params->authenticated, + peer_entity.ediv, + peer_entity.rand_num); + } + + if (sc || our_entity.key_dist & BLE_SM_PAIR_KEY_DIST_ENC) { + /* Peer is master; peer initiates procedure. */ + ble_sm_test_util_peer_bonding_good(0, our_entity.addr_type, + our_entity.rpa, + peer_entity.addr_type, + peer_entity.id_addr, + peer_entity.rpa, + our_entity.ltk, + params->authenticated, + our_entity.ediv, + our_entity.rand_num); + + /* Peer is master; we initiate procedure via security request. */ + ble_sm_test_util_peer_bonding_good(1, our_entity.addr_type, + our_entity.rpa, + peer_entity.addr_type, + peer_entity.id_addr, + peer_entity.rpa, + our_entity.ltk, + params->authenticated, + our_entity.ediv, + our_entity.rand_num); + } +} + +static void +ble_sm_test_util_rx_keys(struct ble_sm_test_params *params, + int we_are_initiator) +{ + struct ble_sm_id_addr_info *peer_id_addr_info; + struct ble_sm_sign_info *peer_sign_info; + struct ble_sm_master_id *peer_master_id; + struct ble_sm_enc_info *peer_enc_info; + struct ble_sm_id_info *peer_id_info; + uint8_t peer_key_dist; + int sc; + + if (we_are_initiator) { + peer_key_dist = params->pair_rsp.resp_key_dist; + peer_id_addr_info = ¶ms->id_addr_info_req; + peer_sign_info = ¶ms->sign_info_req; + peer_master_id = ¶ms->master_id_req; + peer_enc_info = ¶ms->enc_info_req; + peer_id_info = ¶ms->id_info_req; + } else { + peer_key_dist = params->pair_rsp.init_key_dist; + peer_id_addr_info = ¶ms->id_addr_info_rsp; + peer_sign_info = ¶ms->sign_info_rsp; + peer_master_id = ¶ms->master_id_rsp; + peer_enc_info = ¶ms->enc_info_rsp; + peer_id_info = ¶ms->id_info_rsp; + } + + sc = params->pair_req.authreq & BLE_SM_PAIR_AUTHREQ_SC && + params->pair_rsp.authreq & BLE_SM_PAIR_AUTHREQ_SC; + + /* Receive key material from peer. */ + if (!sc && (peer_key_dist & BLE_SM_PAIR_KEY_DIST_ENC)) { + ble_sm_test_util_rx_enc_info(2, peer_enc_info, 0); + ble_sm_test_util_rx_master_id(2, peer_master_id, 0); + } + if (peer_key_dist & BLE_SM_PAIR_KEY_DIST_ID) { + + ble_hs_test_util_hci_ack_set_seq(((struct ble_hs_test_util_hci_ack[]) { + { + .opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_ADV_ENABLE), + }, + { + .opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_ADD_RESOLV_LIST), + }, + { + .opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_PRIVACY_MODE), + }, + { 0 } + })); + + ble_sm_test_util_rx_id_info(2, peer_id_info, 0); + ble_sm_test_util_rx_id_addr_info(2, peer_id_addr_info, 0); + } + if (peer_key_dist & BLE_SM_PAIR_KEY_DIST_SIGN) { + ble_sm_test_util_rx_sign_info(2, peer_sign_info, 0); + } +} + +static void +ble_sm_test_util_verify_tx_keys(struct ble_sm_test_params *params, + int we_are_initiator) +{ + struct ble_sm_id_addr_info *our_id_addr_info; + struct ble_sm_sign_info *our_sign_info; + struct ble_sm_master_id *our_master_id; + struct ble_sm_enc_info *our_enc_info; + struct ble_sm_id_info *our_id_info; + uint8_t our_key_dist; + int sc; + + if (we_are_initiator) { + our_key_dist = params->pair_rsp.init_key_dist; + our_id_addr_info = ¶ms->id_addr_info_rsp; + our_sign_info = ¶ms->sign_info_rsp; + our_master_id = ¶ms->master_id_rsp; + our_enc_info = ¶ms->enc_info_rsp; + our_id_info = ¶ms->id_info_rsp; + } else { + our_key_dist = params->pair_rsp.resp_key_dist; + our_id_addr_info = ¶ms->id_addr_info_req; + our_sign_info = ¶ms->sign_info_req; + our_master_id = ¶ms->master_id_req; + our_enc_info = ¶ms->enc_info_req; + our_id_info = ¶ms->id_info_req; + } + + sc = params->pair_req.authreq & BLE_SM_PAIR_AUTHREQ_SC && + params->pair_rsp.authreq & BLE_SM_PAIR_AUTHREQ_SC; + + if (!sc && our_key_dist & BLE_SM_PAIR_KEY_DIST_ENC) { + ble_sm_test_util_verify_tx_enc_info(our_enc_info); + ble_sm_test_util_verify_tx_master_id(our_master_id); + } + if (our_key_dist & BLE_SM_PAIR_KEY_DIST_ID) { + ble_sm_test_util_verify_tx_id_info(our_id_info); + ble_sm_test_util_verify_tx_id_addr_info(our_id_addr_info); + } + if (our_key_dist & BLE_SM_PAIR_KEY_DIST_SIGN) { + ble_sm_test_util_verify_tx_sign_info(our_sign_info); + } +} + +static void +ble_sm_test_util_us_lgcy_good_once_no_init( + struct ble_sm_test_params *params, + struct ble_hs_conn *conn, + struct ble_sm_test_util_entity *our_entity, + struct ble_sm_test_util_entity *peer_entity) +{ + int rc; + + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 0); + + ble_hs_test_util_hci_ack_set( + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_START_ENCRYPT), 0); + if (params->sec_req.authreq != 0) { + ble_sm_test_util_rx_sec_req(2, ¶ms->sec_req, 0); + } else { + /* Initiate the pairing procedure. */ + rc = ble_gap_security_initiate(2); + TEST_ASSERT_FATAL(rc == 0); + } + + /* Ensure we sent the expected pair request. */ + ble_sm_test_util_verify_tx_pair_req(our_entity->pair_cmd); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + /* Receive a pair response from the peer. */ + ble_sm_test_util_rx_pair_rsp(2, peer_entity->pair_cmd, 0); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + ble_sm_test_util_io_inject(¶ms->passkey_info, + BLE_SM_PROC_STATE_CONFIRM); + + /* Ensure we sent the expected pair confirm. */ + ble_sm_test_util_verify_tx_pair_confirm(our_entity->confirms); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + /* Receive a pair confirm from the peer. */ + ble_sm_test_util_rx_confirm(2, peer_entity->confirms); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + /* Ensure we sent the expected pair random. */ + ble_sm_test_util_verify_tx_pair_random(our_entity->randoms); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + /* Receive a pair random from the peer. */ + ble_sm_test_util_rx_random(2, peer_entity->randoms, 0); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + /* Ensure we sent the expected start encryption command. */ + ble_sm_test_util_verify_tx_start_enc(2, 0, 0, params->stk); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + /* Receive an encryption changed event. */ + ble_sm_test_util_rx_enc_change(2, 0, 1); + + /* Receive key material from peer. */ + ble_sm_test_util_rx_keys(params, 1); + + /* Verify key material gets sent to peer. */ + ble_sm_test_util_verify_tx_keys(params, 1); + + /* Pairing should now be complete. */ + TEST_ASSERT(ble_sm_num_procs() == 0); + + /* Verify that security callback was executed. */ + TEST_ASSERT(ble_sm_test_gap_event_type == BLE_GAP_EVENT_ENC_CHANGE); + TEST_ASSERT(ble_sm_test_gap_status == 0); + TEST_ASSERT(ble_sm_test_sec_state.encrypted); + TEST_ASSERT(ble_sm_test_sec_state.authenticated == params->authenticated); + + /* Verify that connection has correct security state. */ + TEST_ASSERT(ble_sm_test_sec_state.encrypted == + conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_test_sec_state.authenticated == + conn->bhc_sec_state.authenticated); + + /* Verify the appropriate security material was persisted. */ + ble_sm_test_util_verify_persist(params, 1); + + ble_hs_test_util_conn_disconnect(2); +} + +static void +ble_sm_test_util_us_lgcy_good_once(struct ble_sm_test_params *params) +{ + struct ble_sm_test_util_entity peer_entity; + struct ble_sm_test_util_entity our_entity; + struct ble_hs_conn *conn; + + ble_sm_test_util_init_good(params, 1, &conn, &our_entity, &peer_entity); + ble_sm_test_util_us_lgcy_good_once_no_init( + params, conn, &our_entity, &peer_entity); +} + +void +ble_sm_test_util_us_lgcy_good(struct ble_sm_test_params *params) +{ + ble_addr_t peer_addr; + int rc; + + /*** We are master. */ + + /* We initiate pairing. */ + params->sec_req.authreq = 0; + ble_sm_test_util_us_lgcy_good_once(params); + + /* Peer initiates with security request. */ + params->sec_req.authreq = params->pair_rsp.authreq; + ble_sm_test_util_us_lgcy_good_once(params); + + /* Verify link can be restored via the encryption procedure. */ + ble_sm_test_util_bonding_all(params, 1); + + /* Verify programmatic unbonding. */ + peer_addr.type = ble_hs_misc_peer_addr_type_to_id(params->resp_addr_type); + memcpy(peer_addr.val, params->resp_id_addr, sizeof peer_addr.val); + rc = ble_store_util_delete_peer(&peer_addr); + TEST_ASSERT(rc == 0); + + TEST_ASSERT(ble_hs_test_util_num_our_secs() == 0); + TEST_ASSERT(ble_hs_test_util_num_peer_secs() == 0); +} + +void +ble_sm_test_util_peer_lgcy_good_once_no_init( + struct ble_sm_test_params *params, + struct ble_hs_conn *conn, + struct ble_sm_test_util_entity *our_entity, + struct ble_sm_test_util_entity *peer_entity) +{ + int rc; + + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 0); + + if (params->sec_req.authreq != 0) { + rc = ble_sm_slave_initiate(2); + TEST_ASSERT(rc == 0); + + /* Ensure we sent the expected security request. */ + ble_sm_test_util_verify_tx_sec_req(¶ms->sec_req); + } + + /* Receive a pair request from the peer. */ + ble_sm_test_util_rx_pair_req(2, peer_entity->pair_cmd, 0); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + /* Ensure we sent the expected pair response. */ + ble_sm_test_util_verify_tx_pair_rsp(our_entity->pair_cmd); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + ble_sm_test_util_io_check_pre(¶ms->passkey_info, + BLE_SM_PROC_STATE_CONFIRM); + + /* Receive a pair confirm from the peer. */ + ble_sm_test_util_rx_confirm(2, peer_entity->confirms); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + ble_sm_test_util_io_check_post(¶ms->passkey_info, + BLE_SM_PROC_STATE_CONFIRM); + + /* Ensure we sent the expected pair confirm. */ + ble_sm_test_util_verify_tx_pair_confirm(our_entity->confirms); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + /* Receive a pair random from the peer. */ + ble_sm_test_util_rx_random(2, peer_entity->randoms, 0); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + /* Ensure we sent the expected pair random. */ + ble_sm_test_util_verify_tx_pair_random(our_entity->randoms); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + /* Receive a long term key request from the controller. */ + ble_sm_test_util_set_lt_key_req_reply_ack(0, 2); + ble_sm_test_util_rx_lt_key_req(2, 0, 0); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + /* Ensure we sent the expected long term key request reply command. */ + ble_sm_test_util_verify_tx_lt_key_req_reply(2, params->stk); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + /* Receive an encryption changed event. */ + ble_sm_test_util_rx_enc_change(2, 0, 1); + + /* Verify key material gets sent to peer. */ + ble_sm_test_util_verify_tx_keys(params, 0); + + /* Receive key material from peer. */ + ble_sm_test_util_rx_keys(params, 0); + + /* Pairing should now be complete. */ + TEST_ASSERT(ble_sm_num_procs() == 0); + + /* Verify that security callback was executed. */ + TEST_ASSERT(ble_sm_test_gap_event_type == BLE_GAP_EVENT_ENC_CHANGE); + TEST_ASSERT(ble_sm_test_gap_status == 0); + TEST_ASSERT(ble_sm_test_sec_state.encrypted); + TEST_ASSERT(ble_sm_test_sec_state.authenticated == + params->authenticated); + + /* Verify that connection has correct security state. */ + TEST_ASSERT(ble_sm_test_sec_state.encrypted == + conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_test_sec_state.authenticated == + conn->bhc_sec_state.authenticated); + + /* Verify the appropriate security material was persisted. */ + ble_sm_test_util_verify_persist(params, 0); + + ble_hs_test_util_conn_disconnect(2); +} + +void +ble_sm_test_util_peer_lgcy_good_once(struct ble_sm_test_params *params) +{ + struct ble_sm_test_util_entity peer_entity; + struct ble_sm_test_util_entity our_entity; + struct ble_hs_conn *conn; + + ble_sm_test_util_init_good(params, 0, &conn, &our_entity, &peer_entity); + ble_sm_test_util_peer_lgcy_good_once_no_init( + params, conn, &our_entity, &peer_entity); +} + +void +ble_sm_test_util_peer_lgcy_good(struct ble_sm_test_params *params) +{ + ble_addr_t peer_addr; + int rc; + + /*** Peer is master. */ + + /* Peer performs IO first; peer initiates pairing. */ + params->passkey_info.io_before_rx = 0; + params->sec_req.authreq = 0; + ble_sm_test_util_peer_lgcy_good_once(params); + + /* Peer performs IO first; we initiate with security request. */ + params->passkey_info.io_before_rx = 0; + params->sec_req.authreq = params->pair_rsp.authreq; + ble_sm_test_util_peer_lgcy_good_once(params); + + /* We perform IO first; peer initiates pairing. */ + params->passkey_info.io_before_rx = 1; + params->sec_req.authreq = 0; + ble_sm_test_util_peer_lgcy_good_once(params); + + /* We perform IO first; we initiate with security request. */ + params->passkey_info.io_before_rx = 1; + params->sec_req.authreq = params->pair_rsp.authreq; + ble_sm_test_util_peer_lgcy_good_once(params); + + /* Verify link can be restored via the encryption procedure. */ + ble_sm_test_util_bonding_all(params, 0); + + /* Verify repeating pairing event generated when peer attempts to pair + * while bonded. + */ + ble_sm_test_util_repeat_pairing(params, 0); + + /* Verify programmatic unbonding. */ + peer_addr.type = ble_hs_misc_peer_addr_type_to_id(params->init_addr_type); + memcpy(peer_addr.val, params->init_id_addr, sizeof peer_addr.val); + rc = ble_store_util_delete_peer(&peer_addr); + TEST_ASSERT(rc == 0); + + TEST_ASSERT(ble_hs_test_util_num_our_secs() == 0); + TEST_ASSERT(ble_hs_test_util_num_peer_secs() == 0); +} + +static void +ble_sm_test_util_us_sc_good_once_no_init( + struct ble_sm_test_params *params, + struct ble_hs_conn *conn, + struct ble_sm_test_util_entity *our_entity, + struct ble_sm_test_util_entity *peer_entity) +{ + int num_iters; + int rc; + int i; + + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 0); + + ble_hs_test_util_hci_ack_set( + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_START_ENCRYPT), 0); + if (params->sec_req.authreq != 0) { + ble_sm_test_util_rx_sec_req(2, ¶ms->sec_req, 0); + } else { + /* Initiate the pairing procedure. */ + rc = ble_gap_security_initiate(2); + TEST_ASSERT_FATAL(rc == 0); + } + + /* Ensure we sent the expected pair request. */ + ble_sm_test_util_verify_tx_pair_req(our_entity->pair_cmd); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + /* Receive a pair response from the peer. */ + ble_sm_test_util_rx_pair_rsp(2, peer_entity->pair_cmd, 0); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + /* Ensure we sent the expected public key. */ + ble_sm_test_util_verify_tx_public_key(our_entity->public_key); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + /* Receive a public key from the peer. */ + ble_sm_test_util_rx_public_key(2, peer_entity->public_key); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + switch (params->pair_alg) { + case BLE_SM_PAIR_ALG_PASSKEY: + num_iters = 20; + break; + + default: + num_iters = 1; + break; + } + + ble_sm_test_util_io_inject(¶ms->passkey_info, + BLE_SM_PROC_STATE_CONFIRM); + + for (i = 0; i < num_iters; i++) { + if (params->pair_alg != BLE_SM_PAIR_ALG_JW && + params->pair_alg != BLE_SM_PAIR_ALG_NUMCMP) { + + if (i < num_iters - 1) { + ble_sm_dbg_set_next_pair_rand( + our_entity->randoms[i + 1].value); + } + + /* Ensure we sent the expected pair confirm. */ + ble_sm_test_util_verify_tx_pair_confirm(our_entity->confirms + i); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad( + 2, params->passkey_info.passkey.action); + } + + /* Receive a pair confirm from the peer. */ + ble_sm_test_util_rx_confirm(2, peer_entity->confirms + i); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + /* Ensure we sent the expected pair random. */ + ble_sm_test_util_verify_tx_pair_random(our_entity->randoms + i); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + /* Receive a pair random from the peer. */ + ble_sm_test_util_rx_random(2, peer_entity->randoms + i, 0); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + } + + ble_sm_test_util_io_inject(¶ms->passkey_info, + BLE_SM_PROC_STATE_DHKEY_CHECK); + + /* Ensure we sent the expected dhkey check. */ + ble_sm_test_util_verify_tx_dhkey_check(our_entity->dhkey_check); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + /* Receive a dhkey check from the peer. */ + ble_sm_test_util_rx_dhkey_check(2, peer_entity->dhkey_check, 0); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + /* Ensure we sent the expected start encryption command. */ + ble_sm_test_util_verify_tx_start_enc(2, 0, 0, params->ltk); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + /* Receive an encryption changed event. */ + ble_sm_test_util_rx_enc_change(2, 0, 1); + + /* Receive key material from peer. */ + ble_sm_test_util_rx_keys(params, 1); + + /* Verify key material gets sent to peer. */ + ble_sm_test_util_verify_tx_keys(params, 1); + + /* Pairing should now be complete. */ + TEST_ASSERT(ble_sm_num_procs() == 0); + + /* Verify that security callback was executed. */ + TEST_ASSERT(ble_sm_test_gap_event_type == BLE_GAP_EVENT_ENC_CHANGE); + TEST_ASSERT(ble_sm_test_gap_status == 0); + TEST_ASSERT(ble_sm_test_sec_state.encrypted); + TEST_ASSERT(ble_sm_test_sec_state.authenticated == + params->authenticated); + + /* Verify that connection has correct security state. */ + TEST_ASSERT(ble_sm_test_sec_state.encrypted == + conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_test_sec_state.authenticated == + conn->bhc_sec_state.authenticated); + + /* Verify the appropriate security material was persisted. */ + ble_sm_test_util_verify_persist(params, 1); + + ble_hs_test_util_conn_disconnect(2); +} + +static void +ble_sm_test_util_us_sc_good_once(struct ble_sm_test_params *params) +{ + struct ble_sm_test_util_entity peer_entity; + struct ble_sm_test_util_entity our_entity; + struct ble_hs_conn *conn; + + ble_sm_test_util_init_good(params, 1, &conn, &our_entity, &peer_entity); + ble_sm_test_util_us_sc_good_once_no_init( + params, conn, &our_entity, &peer_entity); +} + +void +ble_sm_test_util_us_sc_good(struct ble_sm_test_params *params) +{ + ble_addr_t peer_addr; + int rc; + + /*** We are master. */ + + /* We initiate pairing. */ + params->passkey_info.io_before_rx = 0; + params->sec_req.authreq = 0; + ble_sm_test_util_us_sc_good_once(params); + + /* Peer initiates with security request. */ + params->passkey_info.io_before_rx = 0; + params->sec_req.authreq = params->pair_rsp.authreq; + ble_sm_test_util_us_sc_good_once(params); + + /* Verify link can be restored via the encryption procedure. */ + ble_sm_test_util_bonding_all(params, 1); + + /* Verify programmatic unbonding. */ + peer_addr.type = ble_hs_misc_peer_addr_type_to_id(params->resp_addr_type); + memcpy(peer_addr.val, params->resp_id_addr, sizeof peer_addr.val); + rc = ble_store_util_delete_peer(&peer_addr); + TEST_ASSERT(rc == 0); + + TEST_ASSERT(ble_hs_test_util_num_our_secs() == 0); + TEST_ASSERT(ble_hs_test_util_num_peer_secs() == 0); +} + +static void +ble_sm_test_util_peer_sc_good_once_no_init( + struct ble_sm_test_params *params, + struct ble_hs_conn *conn, + struct ble_sm_test_util_entity *our_entity, + struct ble_sm_test_util_entity *peer_entity) +{ + int num_iters; + int rc; + int i; + + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 0); + + if (params->sec_req.authreq != 0) { + rc = ble_sm_slave_initiate(2); + TEST_ASSERT(rc == 0); + + /* Ensure we sent the expected security request. */ + ble_sm_test_util_verify_tx_sec_req(¶ms->sec_req); + } + + /* Receive a pair request from the peer. */ + ble_sm_test_util_rx_pair_req(2, peer_entity->pair_cmd, 0); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + /* Ensure we sent the expected pair response. */ + ble_sm_test_util_verify_tx_pair_rsp(our_entity->pair_cmd); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + /* Receive a public key from the peer. */ + ble_sm_test_util_rx_public_key(2, peer_entity->public_key); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + /* Ensure we sent the expected public key. */ + ble_sm_test_util_verify_tx_public_key(our_entity->public_key); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + switch (params->pair_alg) { + case BLE_SM_PAIR_ALG_PASSKEY: + num_iters = 20; + break; + + default: + num_iters = 1; + break; + } + + ble_sm_test_util_io_check_pre(¶ms->passkey_info, + BLE_SM_PROC_STATE_CONFIRM); + + for (i = 0; i < num_iters; i++) { + if (params->pair_alg != BLE_SM_PAIR_ALG_JW && + params->pair_alg != BLE_SM_PAIR_ALG_NUMCMP) { + + /* Receive a pair confirm from the peer. */ + ble_sm_test_util_rx_confirm(2, peer_entity->confirms + i); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad( + 2, params->passkey_info.passkey.action); + + if (i < num_iters - 1) { + ble_sm_dbg_set_next_pair_rand( + our_entity->randoms[i + 1].value); + } + } + + if (i == 0) { + ble_sm_test_util_io_check_post(¶ms->passkey_info, + BLE_SM_PROC_STATE_CONFIRM); + } + + /* Ensure we sent the expected pair confirm. */ + ble_sm_test_util_verify_tx_pair_confirm(our_entity->confirms + i); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + /* Receive a pair random from the peer. */ + ble_sm_test_util_rx_random(2, peer_entity->randoms + i, 0); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + /* Ensure we sent the expected pair random. */ + ble_sm_test_util_verify_tx_pair_random(our_entity->randoms + i); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + } + + ble_sm_test_util_io_check_pre(¶ms->passkey_info, + BLE_SM_PROC_STATE_DHKEY_CHECK); + + /* Receive a dhkey check from the peer. */ + ble_sm_test_util_rx_dhkey_check(2, peer_entity->dhkey_check, 0); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + ble_sm_test_util_io_check_post(¶ms->passkey_info, + BLE_SM_PROC_STATE_DHKEY_CHECK); + + /* Ensure we sent the expected dhkey check. */ + ble_sm_test_util_verify_tx_dhkey_check(our_entity->dhkey_check); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + /* Receive a long term key request from the controller. */ + ble_sm_test_util_set_lt_key_req_reply_ack(0, 2); + ble_sm_test_util_rx_lt_key_req(2, 0, 0); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + /* Ensure we sent the expected long term key request reply command. */ + ble_sm_test_util_verify_tx_lt_key_req_reply(2, params->ltk); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + /* Receive an encryption changed event. */ + ble_sm_test_util_rx_enc_change(2, 0, 1); + + /* Verify key material gets sent to peer. */ + ble_sm_test_util_verify_tx_keys(params, 0); + + /* Receive key material from peer. */ + ble_sm_test_util_rx_keys(params, 0); + + /* Pairing should now be complete. */ + TEST_ASSERT(ble_sm_num_procs() == 0); + + /* Verify that security callback was executed. */ + TEST_ASSERT(ble_sm_test_gap_event_type == BLE_GAP_EVENT_ENC_CHANGE); + TEST_ASSERT(ble_sm_test_gap_status == 0); + TEST_ASSERT(ble_sm_test_sec_state.encrypted); + TEST_ASSERT(ble_sm_test_sec_state.authenticated == + params->authenticated); + + /* Verify that connection has correct security state. */ + TEST_ASSERT(ble_sm_test_sec_state.encrypted == + conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_test_sec_state.authenticated == + conn->bhc_sec_state.authenticated); + + /* Verify the appropriate security material was persisted. */ + ble_sm_test_util_verify_persist(params, 0); + + ble_hs_test_util_conn_disconnect(2); +} + +static void +ble_sm_test_util_peer_sc_good_once(struct ble_sm_test_params *params) +{ + struct ble_sm_test_util_entity peer_entity; + struct ble_sm_test_util_entity our_entity; + struct ble_hs_conn *conn; + + ble_sm_test_util_init_good(params, 0, &conn, &our_entity, &peer_entity); + ble_sm_test_util_peer_sc_good_once_no_init( + params, conn, &our_entity, &peer_entity); +} + +void +ble_sm_test_util_peer_sc_good(struct ble_sm_test_params *params) +{ + ble_addr_t peer_addr; + int rc; + + /*** Peer is master. */ + + /* Peer performs IO first; peer initiates pairing. */ + params->passkey_info.io_before_rx = 0; + params->sec_req.authreq = 0; + ble_sm_test_util_peer_sc_good_once(params); + + /* Peer performs IO first; we initiate with security request. */ + params->passkey_info.io_before_rx = 0; + params->sec_req.authreq = params->pair_req.authreq; + ble_sm_test_util_peer_sc_good_once(params); + + /* We perform IO first; peer initiates pairing. */ + params->passkey_info.io_before_rx = 1; + params->sec_req.authreq = 0; + ble_sm_test_util_peer_sc_good_once(params); + + /* We perform IO first; we initiate with security request. */ + params->passkey_info.io_before_rx = 1; + params->sec_req.authreq = params->pair_req.authreq; + ble_sm_test_util_peer_sc_good_once(params); + + /* Verify link can be restored via the encryption procedure. */ + ble_sm_test_util_bonding_all(params, 0); + + /* Verify repeating pairing event generated when peer attempts to pair + * while bonded. + */ + ble_sm_test_util_repeat_pairing(params, 1); + + /* Verify programmatic unbonding. */ + peer_addr.type = ble_hs_misc_peer_addr_type_to_id(params->init_addr_type); + memcpy(peer_addr.val, params->init_id_addr, sizeof peer_addr.val); + rc = ble_store_util_delete_peer(&peer_addr); + TEST_ASSERT(rc == 0); + + TEST_ASSERT(ble_hs_test_util_num_our_secs() == 0); + TEST_ASSERT(ble_hs_test_util_num_peer_secs() == 0); +} + +void +ble_sm_test_util_us_fail_inval(struct ble_sm_test_params *params) +{ + struct ble_hs_conn *conn; + int rc; + + ble_sm_test_util_init(); + ble_hs_id_set_pub(params->resp_id_addr); + + ble_sm_dbg_set_next_pair_rand(((uint8_t[16]){0})); + + ble_hs_test_util_create_conn(2, params->init_id_addr, + ble_sm_test_util_conn_cb, + NULL); + + /* This test inspects and modifies the connection object after unlocking + * the host mutex. It is not OK for real code to do this, but this test + * can assume the connection list is unchanging. + */ + ble_hs_lock(); + conn = ble_hs_conn_find(2); + TEST_ASSERT_FATAL(conn != NULL); + ble_hs_unlock(); + + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 0); + + /* Initiate the pairing procedure. */ + rc = ble_hs_test_util_security_initiate(2, 0); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure we sent the expected pair request. */ + ble_sm_test_util_verify_tx_pair_req(¶ms->pair_req); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + /* Receive a pair response from the peer. */ + ble_sm_test_util_rx_pair_rsp( + 2, ¶ms->pair_rsp, BLE_HS_SM_US_ERR(params->pair_fail.reason)); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 0); + + /* Ensure we sent the expected pair fail. */ + ble_sm_test_util_verify_tx_pair_fail(¶ms->pair_fail); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 0); + + /* Verify that security callback was not executed. */ + TEST_ASSERT(ble_sm_test_gap_event_type == -1); + TEST_ASSERT(ble_sm_test_gap_status == -1); + + /* Verify that connection has correct security state. */ + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(!conn->bhc_sec_state.authenticated); +} + +static void +ble_sm_test_util_repeat_pairing(struct ble_sm_test_params *params, int sc) +{ + struct ble_sm_test_util_entity peer_entity; + struct ble_sm_test_util_entity our_entity; + struct ble_hs_conn *conn; + + ble_sm_test_util_params_to_entities(params, 0, &our_entity, &peer_entity); + + ble_sm_test_repeat_pairing.params = *params; + ble_hs_id_set_pub(our_entity.id_addr); + ble_sm_dbg_set_next_pair_rand(our_entity.randoms[0].value); + ble_sm_dbg_set_next_ediv(our_entity.ediv); + ble_sm_dbg_set_next_master_id_rand(our_entity.rand_num); + ble_sm_dbg_set_next_ltk(our_entity.ltk); + ble_hs_test_util_set_our_irk(our_entity.id_info->irk, 0, 0); + ble_sm_dbg_set_next_csrk(our_entity.sign_info->sig_key); + + ble_hs_test_util_create_rpa_conn(2, our_entity.addr_type, our_entity.rpa, + peer_entity.addr_type, + peer_entity.id_addr, peer_entity.rpa, + BLE_HS_TEST_CONN_FEAT_ALL, + ble_sm_test_util_conn_cb, + NULL); + ble_hs_lock(); + conn = ble_hs_conn_find(2); + TEST_ASSERT_FATAL(conn != NULL); + conn->bhc_flags &= ~BLE_HS_CONN_F_MASTER; + ble_hs_unlock(); + + ble_hs_test_util_prev_tx_queue_clear(); + + /* First repeat pairing event: retry; + * Second repeat pairing event: ignore. + */ + ble_sm_test_repeat_pairing.rc = BLE_GAP_REPEAT_PAIRING_RETRY; + ble_sm_test_repeat_pairing.next_rc = BLE_GAP_REPEAT_PAIRING_IGNORE; + + /* Receive a pair request from the peer. */ + ble_sm_test_util_rx_pair_req(2, peer_entity.pair_cmd, BLE_HS_EALREADY); + + /* Verify repeat pairing event got reported twice. */ + TEST_ASSERT(ble_sm_test_repeat_pairing.num_calls == 2); + + /* Verify no pairing procedures in progress. */ + TEST_ASSERT(ble_sm_num_procs() == 0); + + /* Verify no SM messages were sent. */ + TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue() == NULL); + + /*** Receive another pairing request. */ + + ble_sm_test_repeat_pairing.num_calls = 0; + + /* First repeat pairing event: erase and retry. */ + ble_sm_test_repeat_pairing.rc = BLE_GAP_REPEAT_PAIRING_RETRY; + ble_sm_test_repeat_pairing.erase_on_retry = 1; + + ble_hs_lock(); + conn = ble_hs_conn_find(2); + TEST_ASSERT_FATAL(conn != NULL); + ble_hs_unlock(); + + /* Receive a pair request from the peer; verify pairing procedure completes + * successfully. + */ + if (!sc) { + ble_sm_test_util_peer_lgcy_good_once_no_init( + params, conn, &our_entity, &peer_entity); + } else { + ble_sm_test_util_peer_sc_good_once_no_init( + params, conn, &our_entity, &peer_entity); + } + + /* Verify repeat pairing event got reported once. */ + TEST_ASSERT(ble_sm_test_repeat_pairing.num_calls == 1); +} diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_sm_test_util.h b/src/libs/mynewt-nimble/nimble/host/test/src/ble_sm_test_util.h new file mode 100644 index 00000000..d8629b60 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_sm_test_util.h @@ -0,0 +1,128 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_SM_TEST_UTIL_ +#define H_BLE_SM_TEST_UTIL_ + +#ifdef __cplusplus +extern "C" { +#endif + +struct ble_sm_test_passkey_info { + struct ble_sm_io passkey; + uint32_t exp_numcmp; + unsigned io_before_rx:1; +}; + +struct ble_sm_test_params { + uint8_t init_addr_type; + uint8_t init_id_addr[6]; + uint8_t init_rpa[6]; + uint8_t resp_addr_type; + uint8_t resp_id_addr[6]; + uint8_t resp_rpa[6]; + struct ble_sm_test_passkey_info passkey_info; + + struct ble_sm_sec_req sec_req; + struct ble_sm_pair_cmd pair_req; + struct ble_sm_pair_cmd pair_rsp; + struct ble_sm_pair_confirm confirm_req[20]; + struct ble_sm_pair_confirm confirm_rsp[20]; + struct ble_sm_pair_random random_req[20]; + struct ble_sm_pair_random random_rsp[20]; + struct ble_sm_id_info id_info_req; + struct ble_sm_id_info id_info_rsp; + struct ble_sm_id_addr_info id_addr_info_req; + struct ble_sm_id_addr_info id_addr_info_rsp; + struct ble_sm_sign_info sign_info_req; + struct ble_sm_sign_info sign_info_rsp; + struct ble_sm_pair_fail pair_fail; + + int pair_alg; + unsigned authenticated:1; + + /*** Secure connections fields. */ + uint8_t ltk[16]; + uint8_t our_priv_key[32]; + struct ble_sm_public_key public_key_req; + struct ble_sm_public_key public_key_rsp; + struct ble_sm_dhkey_check dhkey_check_req; + struct ble_sm_dhkey_check dhkey_check_rsp; + + /*** Legacy fields. */ + uint8_t stk[16]; + struct ble_sm_enc_info enc_info_req; + struct ble_sm_enc_info enc_info_rsp; + struct ble_sm_master_id master_id_req; + struct ble_sm_master_id master_id_rsp; +}; + +extern int ble_sm_test_gap_event; +extern int ble_sm_test_gap_status; +extern struct ble_gap_sec_state ble_sm_test_sec_state; + +extern int ble_sm_test_store_obj_type; +extern union ble_store_key ble_sm_test_store_key; +extern union ble_store_value ble_sm_test_store_value; + +void ble_sm_test_util_init(void); +int ble_sm_test_util_conn_cb(struct ble_gap_event *ctxt, void *arg); +void ble_sm_test_util_io_inject(struct ble_sm_test_passkey_info *passkey_info, + uint8_t cur_sm_state); +void ble_sm_test_util_io_inject_bad(uint16_t conn_handle, + uint8_t correct_io_act); +void ble_sm_test_util_io_check_pre( + struct ble_sm_test_passkey_info *passkey_info, + uint8_t cur_sm_state); +void ble_sm_test_util_io_check_post( + struct ble_sm_test_passkey_info *passkey_info, + uint8_t cur_sm_state); +void ble_sm_test_util_rx_sec_req(uint16_t conn_handle, + struct ble_sm_sec_req *cmd, + int exp_status); +void ble_sm_test_util_verify_tx_pair_fail(struct ble_sm_pair_fail *exp_cmd); +void ble_sm_test_util_us_lgcy_good(struct ble_sm_test_params *params); +void ble_sm_test_util_peer_fail_inval(int we_are_master, + uint8_t *init_addr, + uint8_t *resp_addr, + struct ble_sm_pair_cmd *pair_req, + struct ble_sm_pair_fail *pair_fail); +void ble_sm_test_util_peer_lgcy_fail_confirm( + uint8_t *init_addr, + uint8_t *resp_addr, + struct ble_sm_pair_cmd *pair_req, + struct ble_sm_pair_cmd *pair_rsp, + struct ble_sm_pair_confirm *confirm_req, + struct ble_sm_pair_confirm *confirm_rsp, + struct ble_sm_pair_random *random_req, + struct ble_sm_pair_random *random_rsp, + struct ble_sm_pair_fail *fail_rsp); + +void ble_sm_test_util_peer_lgcy_good_once(struct ble_sm_test_params *params); +void ble_sm_test_util_peer_lgcy_good(struct ble_sm_test_params *params); +void ble_sm_test_util_peer_bonding_bad(uint16_t ediv, uint64_t rand_num); +void ble_sm_test_util_peer_sc_good(struct ble_sm_test_params *params); +void ble_sm_test_util_us_sc_good(struct ble_sm_test_params *params); +void ble_sm_test_util_us_fail_inval(struct ble_sm_test_params *params); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_store_test.c b/src/libs/mynewt-nimble/nimble/host/test/src/ble_store_test.c new file mode 100644 index 00000000..75d3a490 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_store_test.c @@ -0,0 +1,435 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "testutil/testutil.h" +#include "ble_hs_test.h" +#include "ble_hs_test_util.h" + +static struct ble_store_status_event ble_store_test_status_event; + +static void +ble_store_test_util_verify_peer_deleted(const ble_addr_t *addr) +{ + union ble_store_value value; + union ble_store_key key; + ble_addr_t addrs[64]; + int num_addrs; + int rc; + int i; + + memset(&key, 0, sizeof key); + key.sec.peer_addr = *addr; + rc = ble_store_read(BLE_STORE_OBJ_TYPE_OUR_SEC, &key, &value); + TEST_ASSERT(rc == BLE_HS_ENOENT); + rc = ble_store_read(BLE_STORE_OBJ_TYPE_PEER_SEC, &key, &value); + TEST_ASSERT(rc == BLE_HS_ENOENT); + + memset(&key, 0, sizeof key); + key.cccd.peer_addr = *addr; + rc = ble_store_read(BLE_STORE_OBJ_TYPE_CCCD, &key, &value); + TEST_ASSERT(rc == BLE_HS_ENOENT); + + rc = ble_store_util_bonded_peers(addrs, &num_addrs, + sizeof addrs / sizeof addrs[0]); + TEST_ASSERT_FATAL(rc == 0); + for (i = 0; i < num_addrs; i++) { + TEST_ASSERT(ble_addr_cmp(addr, addrs + i) != 0); + } +} + +static int +ble_store_test_util_status_overflow(struct ble_store_status_event *event, + void *arg) +{ + int *status; + + status = arg; + + ble_store_test_status_event = *event; + return *status; +} + +static void +ble_store_test_util_overflow_sec(int is_our_sec) +{ + union ble_store_value val; + int obj_type; + int status; + int rc; + int i; + + ble_hs_test_util_init(); + + ble_hs_cfg.store_status_cb = ble_store_test_util_status_overflow; + ble_hs_cfg.store_status_arg = &status; + + if (is_our_sec) { + obj_type = BLE_STORE_OBJ_TYPE_OUR_SEC; + } else { + obj_type = BLE_STORE_OBJ_TYPE_PEER_SEC; + } + + memset(&ble_store_test_status_event, 0, + sizeof ble_store_test_status_event); + memset(&val, 0, sizeof val); + + val.sec.peer_addr = + (ble_addr_t){ BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 } }; + val.sec.ltk_present = 1, + + status = BLE_HS_ESTORE_CAP; + for (i = 0; ; i++) { + rc = ble_store_write(obj_type, &val); + if (i < MYNEWT_VAL(BLE_STORE_MAX_BONDS)) { + TEST_ASSERT_FATAL(rc == 0); + } else { + /* This record should have caused an overflow. */ + TEST_ASSERT(rc == BLE_HS_ESTORE_CAP); + TEST_ASSERT(ble_store_test_status_event.event_code == + BLE_STORE_EVENT_OVERFLOW); + TEST_ASSERT(ble_store_test_status_event.overflow.obj_type == + obj_type); + TEST_ASSERT(ble_store_test_status_event.overflow.value == &val); + break; + } + + val.sec.peer_addr.val[0]++; + } +} + +static int +ble_store_test_util_count(int obj_type) +{ + int count; + int rc; + + rc = ble_store_util_count(obj_type, &count); + TEST_ASSERT_FATAL(rc == 0); + + return count; +} + +TEST_CASE_SELF(ble_store_test_peers) +{ + struct ble_store_value_sec secs[3] = { + { + .peer_addr = { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 } }, + .ltk_present = 1, + }, + { + /* Address value is a duplicate of above, but type differs. */ + .peer_addr = { BLE_ADDR_RANDOM, { 1, 2, 3, 4, 5, 6 } }, + .ltk_present = 1, + }, + { + .peer_addr = { BLE_ADDR_PUBLIC, { 2, 3, 4, 5, 6, 7 } }, + .ltk_present = 1, + }, + }; + ble_addr_t peer_addrs[3]; + int num_addrs; + int rc; + int i; + + ble_hs_test_util_init(); + + for (i = 0; i < sizeof secs / sizeof secs[0]; i++) { + rc = ble_store_write_our_sec(secs + i); + TEST_ASSERT_FATAL(rc == 0); + rc = ble_store_write_peer_sec(secs + i); + TEST_ASSERT_FATAL(rc == 0); + } + + rc = ble_store_util_bonded_peers(peer_addrs, &num_addrs, + sizeof peer_addrs / sizeof peer_addrs[0]); + TEST_ASSERT_FATAL(rc == 0); + + TEST_ASSERT(num_addrs == sizeof secs / sizeof secs[0]); + for (i = 0; i < num_addrs; i++) { + TEST_ASSERT(ble_addr_cmp(&peer_addrs[i], &secs[i].peer_addr) == 0); + } + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_store_test_delete_peer) +{ + struct ble_store_value_sec secs[2] = { + { + .peer_addr = { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 } }, + .ltk_present = 1, + }, + { + /* Address value is a duplicate of above, but type differs. */ + .peer_addr = { BLE_ADDR_RANDOM, { 1, 2, 3, 4, 5, 6 } }, + .ltk_present = 1, + }, + }; + struct ble_store_value_cccd cccds[3] = { + /* First two belong to first peer. */ + { + .peer_addr = secs[0].peer_addr, + .chr_val_handle = 5, + }, + { + .peer_addr = secs[0].peer_addr, + .chr_val_handle = 8, + }, + + /* Last belongs to second peer. */ + { + .peer_addr = secs[1].peer_addr, + .chr_val_handle = 5, + }, + }; + union ble_store_value value; + union ble_store_key key; + int count; + int rc; + int i; + + ble_hs_test_util_init(); + + for (i = 0; i < sizeof secs / sizeof secs[0]; i++) { + rc = ble_store_write_our_sec(secs + i); + TEST_ASSERT_FATAL(rc == 0); + rc = ble_store_write_peer_sec(secs + i); + TEST_ASSERT_FATAL(rc == 0); + } + + for (i = 0; i < sizeof cccds / sizeof cccds[0]; i++) { + rc = ble_store_write_cccd(cccds + i); + TEST_ASSERT_FATAL(rc == 0); + } + + /* Delete first peer. */ + rc = ble_store_util_delete_peer(&secs[0].peer_addr); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure all traces of first peer have been removed. */ + ble_store_test_util_verify_peer_deleted(&secs[0].peer_addr); + + /* Ensure second peer data is still intact. */ + ble_store_key_from_value_sec(&key.sec, secs + 1); + + rc = ble_store_util_count(BLE_STORE_OBJ_TYPE_OUR_SEC, &count); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(count == 1); + + rc = ble_store_read_our_sec(&key.sec, &value.sec); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(memcmp(&value.sec, secs + 1, sizeof value.sec) == 0); + + rc = ble_store_util_count(BLE_STORE_OBJ_TYPE_PEER_SEC, &count); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(count == 1); + + rc = ble_store_read_peer_sec(&key.sec, &value.sec); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(memcmp(&value.sec, secs + 1, sizeof value.sec) == 0); + + ble_store_key_from_value_cccd(&key.cccd, cccds + 2); + + rc = ble_store_util_count(BLE_STORE_OBJ_TYPE_CCCD, &count); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(count == 1); + + rc = ble_store_read_cccd(&key.cccd, &value.cccd); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(memcmp(&value.cccd, cccds + 2, sizeof value.cccd) == 0); + + /* Delete second peer. */ + rc = ble_store_util_delete_peer(&secs[1].peer_addr); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure all traces of first peer have been removed. */ + ble_store_test_util_verify_peer_deleted(&secs[1].peer_addr); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_store_test_count) +{ + struct ble_store_value_sec secs[4] = { + { + .peer_addr = { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 } }, + .ltk_present = 1, + }, + { + .peer_addr = { BLE_ADDR_RANDOM, { 1, 2, 3, 4, 5, 6 } }, + .ltk_present = 1, + }, + { + .peer_addr = { BLE_ADDR_PUBLIC, { 2, 3, 4, 5, 6, 7 } }, + .ltk_present = 1, + }, + { + .peer_addr = { BLE_ADDR_RANDOM, { 3, 4, 5, 6, 7, 8 } }, + .ltk_present = 1, + }, + }; + struct ble_store_value_cccd cccds[2] = { + { + .peer_addr = secs[0].peer_addr, + .chr_val_handle = 5, + }, + { + .peer_addr = secs[0].peer_addr, + .chr_val_handle = 8, + }, + }; + int count; + int rc; + int i; + + ble_hs_test_util_init(); + + /*** Verify initial counts are 0. */ + + rc = ble_store_util_count(BLE_STORE_OBJ_TYPE_OUR_SEC, &count); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(count == 0); + + rc = ble_store_util_count(BLE_STORE_OBJ_TYPE_PEER_SEC, &count); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(count == 0); + + rc = ble_store_util_count(BLE_STORE_OBJ_TYPE_CCCD, &count); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(count == 0); + + /* Write some test data. */ + + for (i = 0; i < 3; i++) { + rc = ble_store_write_our_sec(secs + i); + TEST_ASSERT_FATAL(rc == 0); + } + for (i = 0; i < 2; i++) { + rc = ble_store_write_peer_sec(secs + i); + TEST_ASSERT_FATAL(rc == 0); + } + for (i = 0; i < 1; i++) { + rc = ble_store_write_cccd(cccds + i); + TEST_ASSERT_FATAL(rc == 0); + } + + /*** Verify counts after populating store. */ + rc = ble_store_util_count(BLE_STORE_OBJ_TYPE_OUR_SEC, &count); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(count == 3); + + rc = ble_store_util_count(BLE_STORE_OBJ_TYPE_PEER_SEC, &count); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(count == 2); + + rc = ble_store_util_count(BLE_STORE_OBJ_TYPE_CCCD, &count); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(count == 1); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_store_test_overflow) +{ + ble_store_test_util_overflow_sec(0); + ble_store_test_util_overflow_sec(1); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_store_test_clear) +{ + const struct ble_store_value_sec secs[2] = { + { + .peer_addr = { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 } }, + .ltk_present = 1, + }, + { + /* Address value is a duplicate of above, but type differs. */ + .peer_addr = { BLE_ADDR_RANDOM, { 1, 2, 3, 4, 5, 6 } }, + .ltk_present = 1, + }, + }; + const struct ble_store_value_cccd cccds[3] = { + /* First two belong to first peer. */ + { + .peer_addr = secs[0].peer_addr, + .chr_val_handle = 5, + }, + { + .peer_addr = secs[0].peer_addr, + .chr_val_handle = 8, + }, + + /* Last belongs to second peer. */ + { + .peer_addr = secs[1].peer_addr, + .chr_val_handle = 5, + }, + }; + int rc; + int i; + + ble_hs_test_util_init(); + + for (i = 0; i < sizeof secs / sizeof secs[0]; i++) { + rc = ble_store_write_our_sec(secs + i); + TEST_ASSERT_FATAL(rc == 0); + rc = ble_store_write_peer_sec(secs + i); + TEST_ASSERT_FATAL(rc == 0); + } + + for (i = 0; i < sizeof cccds / sizeof cccds[0]; i++) { + rc = ble_store_write_cccd(cccds + i); + TEST_ASSERT_FATAL(rc == 0); + } + + /* Sanity check. */ + TEST_ASSERT_FATAL( + ble_store_test_util_count(BLE_STORE_OBJ_TYPE_OUR_SEC) == 2); + TEST_ASSERT_FATAL( + ble_store_test_util_count(BLE_STORE_OBJ_TYPE_PEER_SEC) == 2); + TEST_ASSERT_FATAL( + ble_store_test_util_count(BLE_STORE_OBJ_TYPE_CCCD) == 3); + + /* Ensure store is empty after clear gets called. */ + rc = ble_store_clear(); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(ble_store_test_util_count(BLE_STORE_OBJ_TYPE_OUR_SEC) == 0); + TEST_ASSERT(ble_store_test_util_count(BLE_STORE_OBJ_TYPE_PEER_SEC) == 0); + TEST_ASSERT(ble_store_test_util_count(BLE_STORE_OBJ_TYPE_CCCD) == 0); + + /* Ensure second clear succeeds with no effect. */ + rc = ble_store_clear(); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(ble_store_test_util_count(BLE_STORE_OBJ_TYPE_OUR_SEC) == 0); + TEST_ASSERT(ble_store_test_util_count(BLE_STORE_OBJ_TYPE_PEER_SEC) == 0); + TEST_ASSERT(ble_store_test_util_count(BLE_STORE_OBJ_TYPE_CCCD) == 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_store_suite) +{ + ble_store_test_peers(); + ble_store_test_delete_peer(); + ble_store_test_count(); + ble_store_test_overflow(); + ble_store_test_clear(); +} diff --git a/src/libs/mynewt-nimble/nimble/host/test/src/ble_uuid_test.c b/src/libs/mynewt-nimble/nimble/host/test/src/ble_uuid_test.c new file mode 100644 index 00000000..786e371a --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/src/ble_uuid_test.c @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include "testutil/testutil.h" +#include "ble_hs_test.h" +#include "host/ble_uuid.h" +#include "ble_hs_test_util.h" + +TEST_CASE_SELF(ble_uuid_test) +{ + uint8_t buf_16[2] = { 0x00, 0x18 }; + uint8_t buf_128[16] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF }; + + const ble_uuid_t *uuid16_1 = BLE_UUID16_DECLARE(0x1800); + const ble_uuid_t *uuid16_2 = BLE_UUID16_DECLARE(0x1801); + + const ble_uuid_t *uuid128_1 = + BLE_UUID128_DECLARE(0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF); + const ble_uuid_t *uuid128_2 = + BLE_UUID128_DECLARE(0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xEE); + + ble_uuid_any_t uuid; + int rc; + + rc = ble_uuid_init_from_buf(&uuid, buf_16, 2); + TEST_ASSERT(rc == 0); + + rc = ble_uuid_cmp(&uuid.u, uuid16_1); + TEST_ASSERT(rc == 0); + + rc = ble_uuid_cmp(&uuid.u, uuid16_2); + TEST_ASSERT(rc != 0); + + rc = ble_uuid_cmp(uuid16_1, uuid16_2); + TEST_ASSERT(rc != 0); + + rc = ble_uuid_init_from_buf(&uuid, buf_128, 16); + TEST_ASSERT(rc == 0); + + rc = ble_uuid_cmp(&uuid.u, uuid128_1); + TEST_ASSERT(rc == 0); + + rc = ble_uuid_cmp(&uuid.u, uuid128_2); + TEST_ASSERT(rc != 0); + + rc = ble_uuid_cmp(uuid128_1, uuid128_2); + TEST_ASSERT(rc != 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_uuid_test_suite) +{ + ble_uuid_test(); +} diff --git a/src/libs/mynewt-nimble/nimble/host/test/syscfg.yml b/src/libs/mynewt-nimble/nimble/host/test/syscfg.yml new file mode 100644 index 00000000..6307398e --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/host/test/syscfg.yml @@ -0,0 +1,31 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.vals: + BLE_HS_DEBUG: 1 + BLE_HS_PHONY_HCI_ACKS: 1 + BLE_HS_REQUIRE_OS: 0 + BLE_MAX_CONNECTIONS: 8 + BLE_GATT_MAX_PROCS: 16 + BLE_SM: 1 + BLE_SM_SC: 1 + MSYS_1_BLOCK_COUNT: 100 + BLE_L2CAP_COC_MAX_NUM: 2 + CONFIG_FCB: 1 + BLE_VERSION: 52 + BLE_L2CAP_ENHANCED_COC: 1 -- cgit v1.2.3