diff --git a/subsys/bluetooth/host/keys.c b/subsys/bluetooth/host/keys.c index 63aaf14295d..e2d824e2f03 100644 --- a/subsys/bluetooth/host/keys.c +++ b/subsys/bluetooth/host/keys.c @@ -544,4 +544,11 @@ struct bt_keys *bt_keys_get_key_pool(void) { return key_pool; } + +#if IS_ENABLED(CONFIG_BT_KEYS_OVERWRITE_OLDEST) +uint32_t bt_keys_get_aging_counter_val(void) +{ + return aging_counter_val; +} +#endif /* CONFIG_BT_KEYS_OVERWRITE_OLDEST */ #endif /* ZTEST_UNITTEST */ diff --git a/tests/bluetooth/host/keys/bt_keys_get_addr/CMakeLists.txt b/tests/bluetooth/host/keys/bt_keys_get_addr/CMakeLists.txt new file mode 100644 index 00000000000..ee31433debd --- /dev/null +++ b/tests/bluetooth/host/keys/bt_keys_get_addr/CMakeLists.txt @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +FILE(GLOB SOURCES src/*.c) + +project(bt_keys_get_addr) +find_package(Zephyr COMPONENTS unittest HINTS $ENV{ZEPHYR_BASE}) + +add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/host host_mocks) +add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/host/keys mocks) + +target_link_libraries(testbinary PRIVATE mocks host_mocks) diff --git a/tests/bluetooth/host/keys/bt_keys_get_addr/prj.conf b/tests/bluetooth/host/keys/bt_keys_get_addr/prj.conf new file mode 100644 index 00000000000..89d6267d5b3 --- /dev/null +++ b/tests/bluetooth/host/keys/bt_keys_get_addr/prj.conf @@ -0,0 +1,8 @@ +CONFIG_ZTEST=y +CONFIG_ZTEST_NEW_API=y +CONFIG_BT=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_MAX_PAIRED=4 +CONFIG_ASSERT=y +CONFIG_ASSERT_LEVEL=2 +CONFIG_ASSERT_VERBOSE=y diff --git a/tests/bluetooth/host/keys/bt_keys_get_addr/src/main.c b/tests/bluetooth/host/keys/bt_keys_get_addr/src/main.c new file mode 100644 index 00000000000..df9ea10afc8 --- /dev/null +++ b/tests/bluetooth/host/keys/bt_keys_get_addr/src/main.c @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "mocks/conn.h" +#include "mocks/hci_core.h" +#include "mocks/keys_help_utils.h" +#include "host_mocks/assert.h" +#include "host_mocks/print_utils.h" +#include "testing_common_defs.h" + +/* This LUT contains different combinations of ID and Address pairs */ +const struct id_addr_pair testing_id_addr_pair_lut[] = { + { BT_ADDR_ID_1, BT_ADDR_LE_1 }, + { BT_ADDR_ID_1, BT_ADDR_LE_2 }, + { BT_ADDR_ID_2, BT_ADDR_LE_1 }, + { BT_ADDR_ID_2, BT_ADDR_LE_2 } +}; + +/* This list will hold returned references while filling keys pool */ +struct bt_keys *returned_keys_refs[CONFIG_BT_MAX_PAIRED]; + +static bool all_startup_checks_executed; + +BUILD_ASSERT(ARRAY_SIZE(testing_id_addr_pair_lut) == CONFIG_BT_MAX_PAIRED); +BUILD_ASSERT(ARRAY_SIZE(testing_id_addr_pair_lut) == ARRAY_SIZE(returned_keys_refs)); + +static bool startup_suite_predicate(const void *global_state) +{ + return (all_startup_checks_executed == false); +} + +ZTEST_SUITE(bt_keys_get_addr_startup, startup_suite_predicate, NULL, NULL, NULL, NULL); + +/* + * Check if the keys pool list is empty after starting up + * + * Constraints: + * - Check is executed after starting up, prior to adding any keys + * + * Expected behaviour: + * - Keys pool list is empty + */ +ZTEST(bt_keys_get_addr_startup, test_keys_pool_list_is_empty_at_startup) +{ + zassert_true(check_key_pool_is_empty(), + "List isn't empty, make sure to run this test just after a fresh start"); +} + +ZTEST_SUITE(bt_keys_get_addr_populate_non_existing_keys, NULL, NULL, NULL, NULL, NULL); + +/* + * Test filling the keys pool with (ID, Address) pairs + * + * Constraints: + * - Keys pool list is empty after starting up + * + * Expected behaviour: + * - A valid reference is returned by bt_keys_get_addr() + * - ID value matches the one passed to bt_keys_get_addr() + * - Address value matches the one passed to bt_keys_get_addr() + */ +ZTEST(bt_keys_get_addr_populate_non_existing_keys, test_populate_key_pool) +{ + struct id_addr_pair const *current_params_vector; + struct bt_keys *returned_key; + uint8_t id; + bt_addr_le_t *addr; + + for (size_t i = 0; i < ARRAY_SIZE(testing_id_addr_pair_lut); i++) { + + current_params_vector = &testing_id_addr_pair_lut[i]; + id = current_params_vector->id; + addr = current_params_vector->addr; + + returned_key = bt_keys_get_addr(id, addr); + returned_keys_refs[i] = returned_key; + + zassert_true(returned_key != NULL, + "bt_keys_get_addr() failed to add key %d to the keys pool", i); + zassert_true(returned_key->id == id, + "bt_keys_get_addr() returned a reference with an incorrect ID"); + zassert_true(!bt_addr_le_cmp(&returned_key->addr, addr), + "bt_keys_get_addr() set incorrect address %s value, expected %s", + bt_addr_le_str(&returned_key->addr), bt_addr_le_str(addr)); + } +} + +/* + * Test no equal references returned by bt_keys_get_addr() + * + * Constraints: + * - Keys pool has been filled + * + * Expected behaviour: + * - All returned references are different from each other + */ +ZTEST(bt_keys_get_addr_populate_non_existing_keys, test_no_equal_references) +{ + struct bt_keys *keys_pool = bt_keys_get_key_pool(); + + for (uint32_t i = 0; i < ARRAY_SIZE(returned_keys_refs); i++) { + struct bt_keys *returned_ref = returned_keys_refs[i]; + + zassert_equal_ptr(keys_pool + i, returned_ref, + "bt_keys_get_addr() returned unexpected reference at slot %u", i); + } +} + +/* Setup test variables */ +static void test_case_setup(void *f) +{ + clear_key_pool(); + + int rv = fill_key_pool_by_id_addr(testing_id_addr_pair_lut, + ARRAY_SIZE(testing_id_addr_pair_lut), returned_keys_refs); + + zassert_true(rv == 0, "Failed to fill keys pool list, error code %d", -rv); +} + +ZTEST_SUITE(bt_keys_get_addr_get_existing_keys, NULL, NULL, test_case_setup, NULL, NULL); + +/* + * Test getting a valid key reference by a matching ID and address pair + * + * Constraints: + * - ID and address pairs has been inserted in the list + * + * Expected behaviour: + * - A valid reference is returned by bt_keys_get_addr() that + * matches the one returned after adding the ID and address pair + * - ID value matches the one passed to bt_keys_get_addr() + * - Address value matches the one passed to bt_keys_get_addr() + */ +ZTEST(bt_keys_get_addr_get_existing_keys, test_get_key_by_matched_id_and_address) +{ + struct bt_keys *returned_key, *expected_key_ref; + struct id_addr_pair const *current_params_vector; + uint8_t id; + bt_addr_le_t *addr; + + for (size_t i = 0; i < ARRAY_SIZE(testing_id_addr_pair_lut); i++) { + current_params_vector = &testing_id_addr_pair_lut[i]; + id = current_params_vector->id; + addr = current_params_vector->addr; + + returned_key = bt_keys_get_addr(id, addr); + expected_key_ref = returned_keys_refs[i]; + + zassert_true(returned_key != NULL, + "bt_keys_get_addr() failed to add key %d to the keys pool", i); + zassert_equal_ptr(returned_key, expected_key_ref, + "bt_keys_get_addr() returned unexpected reference"); + } +} + +static void fff_reset_rule_before(const struct ztest_unit_test *test, void *fixture) +{ + + /* Skip tests if not all startup suite hasn't been executed */ + if (strcmp(test->test_suite_name, "bt_keys_get_addr_startup")) { + zassume_true(all_startup_checks_executed == true, NULL); + } + + ASSERT_FFF_FAKES_LIST(RESET_FAKE); + CONN_FFF_FAKES_LIST(RESET_FAKE); + HCI_CORE_FFF_FAKES_LIST(RESET_FAKE); +} + +ZTEST_RULE(fff_reset_rule, fff_reset_rule_before, NULL); + +void test_main(void) +{ + /* Only startup suite will run. */ + all_startup_checks_executed = false; + ztest_run_all(NULL); + + /* All other suites, except startup suite, will run. */ + all_startup_checks_executed = true; + ztest_run_all(NULL); + + /* Check that all the suites in this binary ran at least once. */ + ztest_verify_all_test_suites_ran(); +} diff --git a/tests/bluetooth/host/keys/bt_keys_get_addr/src/test_suite_full_list_invalid_values.c b/tests/bluetooth/host/keys/bt_keys_get_addr/src/test_suite_full_list_invalid_values.c new file mode 100644 index 00000000000..b872a2ced62 --- /dev/null +++ b/tests/bluetooth/host/keys/bt_keys_get_addr/src/test_suite_full_list_invalid_values.c @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "mocks/conn.h" +#include "mocks/hci_core.h" +#include "mocks/keys_help_utils.h" +#include "mocks/hci_core_expects.h" +#include "host_mocks/assert.h" +#include "testing_common_defs.h" + +/* This LUT contains different combinations of ID and Address pairs */ +extern const struct id_addr_pair testing_id_addr_pair_lut[CONFIG_BT_MAX_PAIRED]; + +/* This list holds returned references while filling keys pool */ +extern struct bt_keys *returned_keys_refs[CONFIG_BT_MAX_PAIRED]; + +static int bt_unpair_unreachable_custom_fake(uint8_t id, const bt_addr_le_t *addr) +{ + ARG_UNUSED(id); + ARG_UNUSED(addr); + zassert_unreachable("Unexpected call to 'bt_unpair()' occurred"); + return 0; +} + +static void bt_conn_foreach_conn_ref_null_custom_fake(int type, bt_conn_foreach_cb func, + void *data) +{ + func(NULL, data); +} + +static void bt_conn_foreach_data_ref_null_custom_fake(int type, bt_conn_foreach_cb func, + void *data) +{ + struct bt_conn conn; + + func(&conn, NULL); +} + +/* Setup test variables */ +static void test_case_setup(void *f) +{ + clear_key_pool(); + + int rv = fill_key_pool_by_id_addr(testing_id_addr_pair_lut, + ARRAY_SIZE(testing_id_addr_pair_lut), returned_keys_refs); + + zassert_true(rv == 0, "Failed to fill keys pool list, error code %d", -rv); +} + +ZTEST_SUITE(bt_keys_find_key_in_use_invalid_cases, NULL, NULL, test_case_setup, NULL, NULL); + +/* + * Test adding extra (ID, Address) pair while the keys pool list is full, but while looking + * for the keys in use, find_key_in_use() receives an invalid NULL connection reference. + * + * Constraints: + * - Keys pool list is full + * - CONFIG_BT_KEYS_OVERWRITE_OLDEST is enabled + * + * Expected behaviour: + * - Internal function find_key_in_use() receives a NULL connection reference + * - An assertion fails at find_key_in_use() and execution stops + */ +ZTEST(bt_keys_find_key_in_use_invalid_cases, test_find_key_in_use_receives_null_conn_ref) +{ + uint8_t id = BT_ADDR_ID_5; + bt_addr_le_t *addr = BT_ADDR_LE_5; + + Z_TEST_SKIP_IFNDEF(CONFIG_BT_KEYS_OVERWRITE_OLDEST); + + bt_unpair_fake.custom_fake = bt_unpair_unreachable_custom_fake; + bt_conn_foreach_fake.custom_fake = bt_conn_foreach_conn_ref_null_custom_fake; + + expect_assert(); + bt_keys_get_addr(id, addr); + + /* Should not reach this point */ + zassert_unreachable(NULL); +} + +/* + * Test adding extra (ID, Address) pair while the keys pool list is full, but while looking + * for the keys in use, find_key_in_use() receives an invalid NULL data reference. + * + * Constraints: + * - Keys pool list is full + * - CONFIG_BT_KEYS_OVERWRITE_OLDEST is enabled + * + * Expected behaviour: + * - Internal function find_key_in_use() receives a NULL data reference + * - An assertion fails at find_key_in_use() and execution stops + */ +ZTEST(bt_keys_find_key_in_use_invalid_cases, test_find_key_in_use_receives_null_data_ref) +{ + uint8_t id = BT_ADDR_ID_5; + bt_addr_le_t *addr = BT_ADDR_LE_5; + + Z_TEST_SKIP_IFNDEF(CONFIG_BT_KEYS_OVERWRITE_OLDEST); + + bt_unpair_fake.custom_fake = bt_unpair_unreachable_custom_fake; + bt_conn_foreach_fake.custom_fake = bt_conn_foreach_data_ref_null_custom_fake; + + expect_assert(); + bt_keys_get_addr(id, addr); + + /* Should not reach this point */ + zassert_unreachable(NULL); +} + +ZTEST_SUITE(bt_keys_get_addr_null_reference, NULL, NULL, NULL, NULL, NULL); + +/* + * Test invalid (NULL) BT address reference + * + * Constraints: + * - Address value is NULL + * + * Expected behaviour: + * - An assertion fails and execution stops + */ +ZTEST(bt_keys_get_addr_null_reference, test_null_address_reference) +{ + expect_assert(); + bt_keys_get_addr(0x00, NULL); +} diff --git a/tests/bluetooth/host/keys/bt_keys_get_addr/src/test_suite_full_list_no_overwrite.c b/tests/bluetooth/host/keys/bt_keys_get_addr/src/test_suite_full_list_no_overwrite.c new file mode 100644 index 00000000000..e0e7222b042 --- /dev/null +++ b/tests/bluetooth/host/keys/bt_keys_get_addr/src/test_suite_full_list_no_overwrite.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "mocks/keys_help_utils.h" +#include "mocks/hci_core_expects.h" +#include "testing_common_defs.h" + +/* This LUT contains different combinations of ID and Address pairs */ +extern const struct id_addr_pair testing_id_addr_pair_lut[CONFIG_BT_MAX_PAIRED]; + +/* This list holds returned references while filling keys pool */ +extern struct bt_keys *returned_keys_refs[CONFIG_BT_MAX_PAIRED]; + +/* Setup test variables */ +static void test_case_setup(void *f) +{ + Z_TEST_SKIP_IFDEF(CONFIG_BT_KEYS_OVERWRITE_OLDEST); + + clear_key_pool(); + + int rv = fill_key_pool_by_id_addr(testing_id_addr_pair_lut, + ARRAY_SIZE(testing_id_addr_pair_lut), returned_keys_refs); + + zassert_true(rv == 0, "Failed to fill keys pool list, error code %d", -rv); +} + +ZTEST_SUITE(bt_keys_get_addr_full_list_no_overwrite, NULL, NULL, test_case_setup, NULL, NULL); + +/* + * Test adding extra (ID, Address) pair while the keys pool list is full. + * As 'CONFIG_BT_KEYS_OVERWRITE_OLDEST' isn't enabled, no (ID, Address) pairs can be added while + * the list is full. + * + * Constraints: + * - Keys pool list is full + * - CONFIG_BT_KEYS_OVERWRITE_OLDEST isn't enabled + * + * Expected behaviour: + * - NULL reference pointer is returned + */ +ZTEST(bt_keys_get_addr_full_list_no_overwrite, test_adding_new_pair_to_full_list) +{ + struct bt_keys *returned_key; + uint8_t id = BT_ADDR_ID_3; + bt_addr_le_t *addr = BT_ADDR_LE_3; + + returned_key = bt_keys_get_addr(id, addr); + + expect_not_called_bt_unpair(); + + zassert_true(returned_key == NULL, "bt_keys_get_addr() returned a non-NULL reference"); +} diff --git a/tests/bluetooth/host/keys/bt_keys_get_addr/src/test_suite_full_list_overwrite_oldest.c b/tests/bluetooth/host/keys/bt_keys_get_addr/src/test_suite_full_list_overwrite_oldest.c new file mode 100644 index 00000000000..b60a5e84b42 --- /dev/null +++ b/tests/bluetooth/host/keys/bt_keys_get_addr/src/test_suite_full_list_overwrite_oldest.c @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "mocks/conn.h" +#include "mocks/hci_core.h" +#include "mocks/keys_help_utils.h" +#include "mocks/hci_core_expects.h" +#include "testing_common_defs.h" + +/* This LUT contains different combinations of ID and Address pairs */ +extern const struct id_addr_pair testing_id_addr_pair_lut[CONFIG_BT_MAX_PAIRED]; + +/* This list holds returned references while filling keys pool */ +extern struct bt_keys *returned_keys_refs[CONFIG_BT_MAX_PAIRED]; + +/* Pointer to the current set of oldest testing parameter */ +struct id_addr_pair const *oldest_params_vector; + +static int bt_unpair_custom_fake(uint8_t id, const bt_addr_le_t *addr) +{ + struct bt_keys *keys = NULL; + + /* Find the key slot with matched id and address */ + keys = bt_keys_find_addr(id, addr); + if (keys) { + bt_keys_clear(keys); + } + + /* This check is used here because bt_unpair() is called with a local variable address */ + expect_single_call_bt_unpair(oldest_params_vector->id, oldest_params_vector->addr); + + return 0; +} + +static int bt_unpair_unreachable_custom_fake(uint8_t id, const bt_addr_le_t *addr) +{ + ARG_UNUSED(id); + ARG_UNUSED(addr); + zassert_unreachable("Unexpected call to 'bt_unpair()' occurred"); + return 0; +} + +static void bt_conn_foreach_key_slot_0_in_use_custom_fake(int type, bt_conn_foreach_cb func, + void *data) +{ + struct bt_conn conn; + + /* This will make the effect as if there is a disconnection */ + conn.state = BT_CONN_DISCONNECTED; + conn.id = 0x9E; + func(&conn, data); + + /* This will make the effect as if there is a connection with no key */ + conn.state = BT_CONN_CONNECTED; + conn.id = 0xFF; + bt_addr_le_copy(&conn.le.dst, (const bt_addr_le_t *)BT_ADDR_LE_ANY); + bt_conn_get_dst_fake.return_val = &conn.le.dst; + func(&conn, data); + + /* This will make the effect as if key at slot 0 is in use with a connection */ + conn.state = BT_CONN_CONNECTED; + conn.id = testing_id_addr_pair_lut[0].id; + bt_addr_le_copy(&conn.le.dst, testing_id_addr_pair_lut[0].addr); + bt_conn_get_dst_fake.return_val = &conn.le.dst; + func(&conn, data); +} + +static void bt_conn_foreach_all_keys_in_use_custom_fake(int type, bt_conn_foreach_cb func, + void *data) +{ + struct bt_conn conn; + + /* This will make the effect as if key at slot 'x' is in use with a connection */ + for (size_t i = 0; i < ARRAY_SIZE(testing_id_addr_pair_lut); i++) { + conn.state = BT_CONN_CONNECTED; + conn.id = testing_id_addr_pair_lut[i].id; + bt_addr_le_copy(&conn.le.dst, testing_id_addr_pair_lut[i].addr); + bt_conn_get_dst_fake.return_val = &conn.le.dst; + func(&conn, data); + } +} + +static void bt_conn_foreach_no_keys_in_use_custom_fake(int type, bt_conn_foreach_cb func, + void *data) +{ + struct bt_conn conn; + + /* This will make the effect as if key at slot 'x' is in use with a connection */ + for (size_t i = 0; i < ARRAY_SIZE(testing_id_addr_pair_lut); i++) { + conn.state = BT_CONN_DISCONNECTED; + conn.id = testing_id_addr_pair_lut[i].id; + bt_addr_le_copy(&conn.le.dst, testing_id_addr_pair_lut[i].addr); + bt_conn_get_dst_fake.return_val = &conn.le.dst; + func(&conn, data); + } +} + +/* Setup test variables */ +static void test_case_setup(void *f) +{ + Z_TEST_SKIP_IFNDEF(CONFIG_BT_KEYS_OVERWRITE_OLDEST); + + clear_key_pool(); + + int rv = fill_key_pool_by_id_addr(testing_id_addr_pair_lut, + ARRAY_SIZE(testing_id_addr_pair_lut), returned_keys_refs); + + zassert_true(rv == 0, "Failed to fill keys pool list, error code %d", -rv); +} + +ZTEST_SUITE(bt_keys_get_addr_full_list_overwrite_oldest, NULL, NULL, test_case_setup, NULL, NULL); + +/* + * Test adding extra (ID, Address) pair while the keys pool list is full while all keys are in + * use with connections so that no more (ID, Address) pairs can be added. + * + * Constraints: + * - Keys pool list is full + * - All Keys are used with a connection + * - CONFIG_BT_KEYS_OVERWRITE_OLDEST is enabled + * + * Expected behaviour: + * - NULL pointer is returned as there is no room + */ +ZTEST(bt_keys_get_addr_full_list_overwrite_oldest, test_full_list_all_keys_in_use) +{ + struct bt_keys *returned_key; + uint8_t id = BT_ADDR_ID_3; + bt_addr_le_t *addr = BT_ADDR_LE_3; + + bt_unpair_fake.custom_fake = bt_unpair_unreachable_custom_fake; + bt_conn_foreach_fake.custom_fake = bt_conn_foreach_all_keys_in_use_custom_fake; + + returned_key = bt_keys_get_addr(id, addr); + + zassert_true(returned_key == NULL, "bt_keys_get_addr() returned a non-NULL reference"); +} + +/* + * Test adding extra (ID, Address) pair while the keys pool list is full, but no keys are used with + * connections. New (ID, Address) pairs can be added by replacing the oldest pair. + * + * Constraints: + * - Keys pool list is full + * - All Keys are not used with a connection + * - CONFIG_BT_KEYS_OVERWRITE_OLDEST is enabled + * + * Expected behaviour: + * - A valid pointer in the keys pool is returned, matching the one previously assigned to the + * oldest key (index 0). + */ +ZTEST(bt_keys_get_addr_full_list_overwrite_oldest, test_full_list_no_keys_in_use) +{ + struct bt_keys *returned_key; + uint8_t id = BT_ADDR_ID_3; + bt_addr_le_t *addr = BT_ADDR_LE_3; + uint32_t expected_oldest_params_ref_idx; + + expected_oldest_params_ref_idx = 0; + oldest_params_vector = &testing_id_addr_pair_lut[expected_oldest_params_ref_idx]; + bt_unpair_fake.custom_fake = bt_unpair_custom_fake; + bt_conn_foreach_fake.custom_fake = bt_conn_foreach_no_keys_in_use_custom_fake; + + returned_key = bt_keys_get_addr(id, addr); + + zassert_true(returned_key != NULL, "bt_keys_get_addr() returned a NULL reference"); + zassert_true(returned_key == returned_keys_refs[expected_oldest_params_ref_idx], + "bt_keys_get_addr() returned reference doesn't match expected one"); +} + +/* + * Test adding extra (ID, Address) pair while the keys pool list is full when the oldest key slot + * is in use with a connection but others keys aren't. + * New (ID, address) pair should replace the oldest one that's not in use. + * + * Constraints: + * - Keys pool list is full + * - Oldest key at slot 0 is used with a connection + * - Next oldest key (slot 1) isn't used with a connection + * - CONFIG_BT_KEYS_OVERWRITE_OLDEST is enabled + * + * Expected behaviour: + * - A valid pointer in the keys pool is returned, matching the one previously assigned to the + * oldest key (index 1). + */ +ZTEST(bt_keys_get_addr_full_list_overwrite_oldest, test_full_list_key_0_in_use_key_1_oldest) +{ + struct bt_keys *returned_key; + uint8_t id = BT_ADDR_ID_4; + bt_addr_le_t *addr = BT_ADDR_LE_4; + uint32_t expected_oldest_params_ref_idx; + + expected_oldest_params_ref_idx = 1; + oldest_params_vector = &testing_id_addr_pair_lut[expected_oldest_params_ref_idx]; + bt_unpair_fake.custom_fake = bt_unpair_custom_fake; + bt_conn_foreach_fake.custom_fake = bt_conn_foreach_key_slot_0_in_use_custom_fake; + + returned_key = bt_keys_get_addr(id, addr); + + zassert_true(returned_key != NULL, "bt_keys_get_addr() returned a NULL reference"); + zassert_true(returned_key == returned_keys_refs[expected_oldest_params_ref_idx], + "bt_keys_get_addr() returned reference doesn't match expected one"); +} + +/* + * Test adding extra (ID, Address) pair while the keys pool list is full when the oldest key slot + * is in use with a connection but others keys aren't. + * New (ID, address) pair should replace the oldest one that's not in use. + * + * Constraints: + * - Keys pool list is full + * - Key at slot 0 is used with a connection + * - oldest key (slot 2) isn't used with a connection + * - CONFIG_BT_KEYS_OVERWRITE_OLDEST is enabled + * + * Expected behaviour: + * - A valid pointer in the keys pool is returned, matching the one previously assigned to the + * oldest key (index 2). + */ +ZTEST(bt_keys_get_addr_full_list_overwrite_oldest, test_full_list_key_0_in_use_key_2_oldest) +{ + struct bt_keys *returned_key; + uint8_t id = BT_ADDR_ID_5; + bt_addr_le_t *addr = BT_ADDR_LE_5; + uint32_t expected_oldest_params_ref_idx; + +#if IS_ENABLED(CONFIG_BT_KEYS_OVERWRITE_OLDEST) + /* Normally first items inserted in the list are the oldest. + * For this particular test, we need to override that by setting + * the 'aging_counter' + */ + returned_keys_refs[1]->aging_counter = bt_keys_get_aging_counter_val(); +#endif + + expected_oldest_params_ref_idx = 2; + oldest_params_vector = &testing_id_addr_pair_lut[expected_oldest_params_ref_idx]; + bt_unpair_fake.custom_fake = bt_unpair_custom_fake; + bt_conn_foreach_fake.custom_fake = bt_conn_foreach_key_slot_0_in_use_custom_fake; + + returned_key = bt_keys_get_addr(id, addr); + + zassert_true(returned_key != NULL, "bt_keys_get_addr() returned a NULL reference"); + zassert_true(returned_key == returned_keys_refs[expected_oldest_params_ref_idx], + "bt_keys_get_addr() returned reference doesn't match expected one"); +} diff --git a/tests/bluetooth/host/keys/bt_keys_get_addr/testcase.yaml b/tests/bluetooth/host/keys/bt_keys_get_addr/testcase.yaml new file mode 100644 index 00000000000..3e27f20acef --- /dev/null +++ b/tests/bluetooth/host/keys/bt_keys_get_addr/testcase.yaml @@ -0,0 +1,10 @@ +common: + tags: test_framework bluetooth host +tests: + bluetooth.host.bt_keys_get_addr.default: + type: unit + bluetooth.host.bt_keys_get_addr.keys_overwrite_oldest: + type: unit + extra_configs: + - CONFIG_BT_SMP=y + - CONFIG_BT_KEYS_OVERWRITE_OLDEST=y diff --git a/tests/bluetooth/host/keys/mocks/keys_help_utils.c b/tests/bluetooth/host/keys/mocks/keys_help_utils.c index 222106faa44..a65c3080696 100644 --- a/tests/bluetooth/host/keys/mocks/keys_help_utils.c +++ b/tests/bluetooth/host/keys/mocks/keys_help_utils.c @@ -9,6 +9,39 @@ #include #include "keys_help_utils.h" +void clear_key_pool(void) +{ + struct bt_keys *key_pool; + + key_pool = bt_keys_get_key_pool(); + memset(key_pool, 0x00, sizeof(struct bt_keys) * CONFIG_BT_MAX_PAIRED); +} + +int fill_key_pool_by_id_addr(const struct id_addr_pair src[], int size, struct bt_keys *refs[]) +{ + uint8_t id; + bt_addr_le_t *addr; + struct id_addr_pair const *params_vector; + + if (!check_key_pool_is_empty()) { + printk("'%s' Error ! Keys pool isn't empty\n", __func__); + return -ENOSR; + } + + for (size_t it = 0; it < size; it++) { + params_vector = &src[it]; + id = params_vector->id; + addr = params_vector->addr; + refs[it] = bt_keys_get_addr(id, addr); + if (refs[it] == NULL) { + printk("'%s' Failed to add key %d to the keys pool\n", __func__, it); + return -ENOBUFS; + } + } + + return 0; +} + bool check_key_pool_is_empty(void) { int i; diff --git a/tests/bluetooth/host/keys/mocks/keys_help_utils.h b/tests/bluetooth/host/keys/mocks/keys_help_utils.h index 4ceb0d3ccd2..0f55786c0b9 100644 --- a/tests/bluetooth/host/keys/mocks/keys_help_utils.h +++ b/tests/bluetooth/host/keys/mocks/keys_help_utils.h @@ -14,8 +14,13 @@ struct id_addr_pair { /* keys.c declarations */ struct bt_keys *bt_keys_get_key_pool(void); +#if IS_ENABLED(CONFIG_BT_KEYS_OVERWRITE_OLDEST) +uint32_t bt_keys_get_aging_counter_val(void); +#endif /* keys_help_utils.c declarations */ +void clear_key_pool(void); +int fill_key_pool_by_id_addr(const struct id_addr_pair src[], int size, struct bt_keys *refs[]); bool check_key_pool_is_empty(void); /* Repeat test entries */