BLE Host - unit tests for persisted CCCDs.
Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/f98cc567 Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/f98cc567 Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/f98cc567 Branch: refs/heads/develop Commit: f98cc5679ce1b3ac803fdde36907b8cd9ee21f81 Parents: 54a4b7f Author: Christopher Collins <[email protected]> Authored: Tue May 24 14:24:18 2016 -0700 Committer: Christopher Collins <[email protected]> Committed: Tue May 24 14:27:21 2016 -0700 ---------------------------------------------------------------------- .../host/src/test/ble_gatts_notify_test.c | 337 +++++++++++++++++-- net/nimble/host/src/test/ble_hs_test_util.c | 8 +- net/nimble/host/src/test/ble_l2cap_sm_test.c | 18 + 3 files changed, 325 insertions(+), 38 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f98cc567/net/nimble/host/src/test/ble_gatts_notify_test.c ---------------------------------------------------------------------- diff --git a/net/nimble/host/src/test/ble_gatts_notify_test.c b/net/nimble/host/src/test/ble_gatts_notify_test.c index 29ebd92..96730f1 100644 --- a/net/nimble/host/src/test/ble_gatts_notify_test.c +++ b/net/nimble/host/src/test/ble_gatts_notify_test.c @@ -24,6 +24,7 @@ #include "host/ble_uuid.h" #include "host/ble_hs_test.h" #include "ble_hs_test_util.h" +#include "ble_hs_test_util_store.h" #define BLE_GATTS_NOTIFY_TEST_CHR_1_UUID 0x1111 #define BLE_GATTS_NOTIFY_TEST_CHR_2_UUID 0x2222 @@ -66,13 +67,50 @@ 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; +typedef int ble_store_write_fn(int obj_type, union ble_store_value *val); + +typedef int ble_store_delete_fn(int obj_type, union ble_store_key *key); + +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); + + ble_hs_test_util_tx_all(); + + 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 = le16toh(om->om_data + 1); + return flags; +} + static void ble_gatts_notify_test_misc_init(uint16_t *out_conn_handle) { + uint16_t flags; int rc; ble_hs_test_util_init(); + ble_hs_test_util_store_init(10, 10, 10); + ble_hs_cfg.store_read_cb = ble_hs_test_util_store_read; + ble_hs_cfg.store_write_cb = ble_hs_test_util_store_write; + rc = ble_gatts_register_svcs(ble_gatts_notify_test_svcs, ble_gatts_notify_test_misc_reg_cb, NULL); TEST_ASSERT_FATAL(rc == 0); @@ -84,6 +122,14 @@ ble_gatts_notify_test_misc_init(uint16_t *out_conn_handle) ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), NULL, NULL); *out_conn_handle = 2; + + /* 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); } static void @@ -104,34 +150,6 @@ ble_gatts_notify_test_misc_enable_notify(uint16_t conn_handle, TEST_ASSERT(rc == 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); - - ble_hs_test_util_tx_all(); - - 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 = le16toh(om->om_data + 1); - return flags; -} - static void ble_gatts_notify_test_misc_reg_cb(uint8_t op, union ble_gatt_register_ctxt *ctxt, @@ -253,9 +271,18 @@ TEST_CASE(ble_gatts_notify_test_n) BLE_GATTS_CLT_CFG_F_NOTIFY); /* Toss both write responses. */ - ble_hs_test_util_tx_all(); - ble_hs_test_util_prev_tx_dequeue(); - ble_hs_test_util_prev_tx_dequeue(); + ble_hs_test_util_prev_tx_queue_clear(); + + /* Ensure nothing got persisted since peer is not bonded. */ + TEST_ASSERT(ble_hs_test_util_store_num_cccds == 0); + + /* 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); /* Update characteristic 1's value. */ ble_gatts_notify_test_chr_1_len = 1; @@ -325,9 +352,18 @@ TEST_CASE(ble_gatts_notify_test_i) BLE_GATTS_CLT_CFG_F_INDICATE); /* Toss both write responses. */ - ble_hs_test_util_tx_all(); - ble_hs_test_util_prev_tx_dequeue(); - ble_hs_test_util_prev_tx_dequeue(); + ble_hs_test_util_prev_tx_queue_clear(); + + /* Ensure nothing got persisted since peer is not bonded. */ + TEST_ASSERT(ble_hs_test_util_store_num_cccds == 0); + + /* Ensure indications 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_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); /* Update characteristic 1's value. */ ble_gatts_notify_test_chr_1_len = 1; @@ -397,10 +433,243 @@ TEST_CASE(ble_gatts_notify_test_i) TEST_ASSERT(flags == 0); } +TEST_CASE(ble_gatts_notify_test_bonded_n) +{ + struct ble_hs_conn *conn; + uint16_t conn_handle; + uint16_t flags; + + ble_gatts_notify_test_misc_init(&conn_handle); + + /* Enable bonding. */ + ble_hs_lock(); + conn = ble_hs_conn_find(conn_handle); + TEST_ASSERT_FATAL(conn != NULL); + conn->bhc_sec_state.enc_enabled = 1; + conn->bhc_sec_state.authenticated = 1; + conn->bhc_sec_state.bonded = 1; + ble_hs_unlock(); + + /* Enable notifications on both characteristics. */ + ble_gatts_notify_test_misc_enable_notify( + conn_handle, ble_gatts_notify_test_chr_1_def_handle, + BLE_GATTS_CLT_CFG_F_NOTIFY); + ble_gatts_notify_test_misc_enable_notify( + conn_handle, ble_gatts_notify_test_chr_2_def_handle, + BLE_GATTS_CLT_CFG_F_NOTIFY); + + /* Toss both write responses. */ + ble_hs_test_util_prev_tx_queue_clear(); + + /* Ensure both CCCDs got persisted. */ + TEST_ASSERT(ble_hs_test_util_store_num_cccds == 2); + + /* 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); + + /* Disconnect. */ + ble_hs_test_util_conn_disconnect(conn_handle); + + /* Ensure both CCCDs still persisted. */ + TEST_ASSERT(ble_hs_test_util_store_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}), + NULL, 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); + + /* Simulate a successful encryption procedure (bonding restoration). */ + ble_hs_lock(); + conn = ble_hs_conn_find(conn_handle); + TEST_ASSERT_FATAL(conn != NULL); + conn->bhc_sec_state.enc_enabled = 1; + conn->bhc_sec_state.authenticated = 1; + conn->bhc_sec_state.bonded = 1; + ble_hs_unlock(); + + ble_gatts_bonding_restored(conn_handle); + + /* Verify notifications sent properly. */ + ble_gatts_notify_test_misc_verify_tx_n(ble_gatts_notify_test_chr_1_val, + ble_gatts_notify_test_chr_1_len); + ble_gatts_notify_test_misc_verify_tx_n(ble_gatts_notify_test_chr_2_val, + ble_gatts_notify_test_chr_2_len); + + /* 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_store_num_cccds == 2); +} + +TEST_CASE(ble_gatts_notify_test_bonded_i) +{ + struct ble_hs_conn *conn; + uint16_t conn_handle; + uint16_t flags; + + ble_gatts_notify_test_misc_init(&conn_handle); + + /* Enable bonding. */ + ble_hs_lock(); + conn = ble_hs_conn_find(conn_handle); + TEST_ASSERT_FATAL(conn != NULL); + conn->bhc_sec_state.enc_enabled = 1; + conn->bhc_sec_state.authenticated = 1; + conn->bhc_sec_state.bonded = 1; + ble_hs_unlock(); + + /* Enable indications on both characteristics. */ + ble_gatts_notify_test_misc_enable_notify( + conn_handle, ble_gatts_notify_test_chr_1_def_handle, + BLE_GATTS_CLT_CFG_F_INDICATE); + ble_gatts_notify_test_misc_enable_notify( + conn_handle, ble_gatts_notify_test_chr_2_def_handle, + BLE_GATTS_CLT_CFG_F_INDICATE); + + /* Toss both write responses. */ + ble_hs_test_util_prev_tx_queue_clear(); + + /* Ensure both CCCDs got persisted. */ + TEST_ASSERT(ble_hs_test_util_store_num_cccds == 2); + + /* Ensure indications 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_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); + + /* Disconnect. */ + ble_hs_test_util_conn_disconnect(conn_handle); + + /* Ensure both CCCDs still persisted. */ + TEST_ASSERT(ble_hs_test_util_store_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}), + NULL, 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_hs_lock(); + conn = ble_hs_conn_find(conn_handle); + TEST_ASSERT_FATAL(conn != NULL); + conn->bhc_sec_state.enc_enabled = 1; + conn->bhc_sec_state.authenticated = 1; + conn->bhc_sec_state.bonded = 1; + ble_hs_unlock(); + + ble_gatts_bonding_restored(conn_handle); + + /* Verify first indication sent properly. */ + ble_gatts_notify_test_misc_verify_tx_i(ble_gatts_notify_test_chr_1_val, + ble_gatts_notify_test_chr_1_len); + + /* Verify the second indication doesn't get sent until the first is + * confirmed. + */ + ble_hs_test_util_tx_all(); + 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); + + /* Verify indication sent properly. */ + ble_hs_test_util_tx_all(); + ble_gatts_notify_test_misc_verify_tx_i(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); + + /* 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_store_num_cccds == 2); +} + 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(); + + /* XXX: Test corner cases: + * o Bonding after CCCD configuration. + * o Disconnect prior to rx of indicate ack. + * o Multiple characteristic updates prior to rx of indicate ack. + */ } int http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f98cc567/net/nimble/host/src/test/ble_hs_test_util.c ---------------------------------------------------------------------- diff --git a/net/nimble/host/src/test/ble_hs_test_util.c b/net/nimble/host/src/test/ble_hs_test_util.c index 810cc19..fb3bf3b 100644 --- a/net/nimble/host/src/test/ble_hs_test_util.c +++ b/net/nimble/host/src/test/ble_hs_test_util.c @@ -76,11 +76,9 @@ ble_hs_test_util_prev_tx_dequeue(void) os_mbuf_free_chain(ble_hs_test_util_prev_tx_cur); - omp = STAILQ_LAST(&ble_hs_test_util_prev_tx_queue, os_mbuf_pkthdr, - omp_next); + omp = STAILQ_FIRST(&ble_hs_test_util_prev_tx_queue); if (omp != NULL) { - STAILQ_REMOVE(&ble_hs_test_util_prev_tx_queue, omp, os_mbuf_pkthdr, - omp_next); + STAILQ_REMOVE_HEAD(&ble_hs_test_util_prev_tx_queue, omp_next); ble_hs_test_util_prev_tx_cur = OS_MBUF_PKTHDR_TO_MBUF(omp); } else { ble_hs_test_util_prev_tx_cur = NULL; @@ -120,6 +118,7 @@ ble_hs_test_util_prev_tx_queue_sz(void) void ble_hs_test_util_prev_tx_queue_clear(void) { + ble_hs_test_util_tx_all(); while (!STAILQ_EMPTY(&ble_hs_test_util_prev_tx_queue)) { ble_hs_test_util_prev_tx_dequeue(); } @@ -759,6 +758,7 @@ ble_hs_test_util_set_public_addr(uint8_t *addr) memcpy(ble_hs_our_dev.public_addr, addr, 6); } + void ble_hs_test_util_init(void) { http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f98cc567/net/nimble/host/src/test/ble_l2cap_sm_test.c ---------------------------------------------------------------------- diff --git a/net/nimble/host/src/test/ble_l2cap_sm_test.c b/net/nimble/host/src/test/ble_l2cap_sm_test.c index 1159028..c58396d 100644 --- a/net/nimble/host/src/test/ble_l2cap_sm_test.c +++ b/net/nimble/host/src/test/ble_l2cap_sm_test.c @@ -412,6 +412,21 @@ ble_l2cap_sm_test_util_verify_tx_enc_info( } static void +ble_l2cap_sm_test_util_verify_tx_sec_req(struct ble_l2cap_sm_sec_req *exp_cmd) +{ + struct ble_l2cap_sm_sec_req cmd; + struct os_mbuf *om; + + ble_hs_test_util_tx_all(); + + om = ble_l2cap_sm_test_util_verify_tx_hdr(BLE_L2CAP_SM_OP_SEC_REQ, + BLE_L2CAP_SM_SEC_REQ_SZ); + ble_l2cap_sm_sec_req_parse(om->om_data, om->om_len, &cmd); + + TEST_ASSERT(cmd.authreq == exp_cmd->authreq); +} + +static void ble_l2cap_sm_test_util_verify_tx_pair_fail( struct ble_l2cap_sm_pair_fail *exp_cmd) { @@ -914,6 +929,9 @@ ble_l2cap_sm_test_util_peer_lgcy_good( if (params->has_sec_req) { rc = ble_l2cap_sm_slave_initiate(2); TEST_ASSERT(rc == 0); + + /* Ensure we sent the expected security request. */ + ble_l2cap_sm_test_util_verify_tx_sec_req(¶ms->sec_req); } /* Receive a pair request from the peer. */
