| /* |
| * Copyright (c) 2021 Nordic Semiconductor |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| #include <zephyr/kernel.h> |
| #include <zephyr/bluetooth/hci.h> |
| #include "mesh_test.h" |
| #include "mesh/net.h" |
| #include "mesh/beacon.h" |
| #include "mesh/mesh.h" |
| #include "mesh/foundation.h" |
| #include "mesh/crypto.h" |
| #include "argparse.h" |
| #include "mesh/proxy_cli.h" |
| #include "mesh/proxy.h" |
| |
| #define LOG_MODULE_NAME test_beacon |
| |
| #include <zephyr/logging/log.h> |
| LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_INF); |
| |
| #define GROUP_ADDR 0xc000 |
| #define WAIT_TIME 60 /*seconds*/ |
| #define MULT_NETKEYS_WAIT_TIME 350 /*seconds*/ |
| #define BEACON_INTERVAL_WAIT_TIME 750 /*seconds*/ |
| #define BEACON_INTERVAL 10 /*seconds*/ |
| |
| #define BEACON_TYPE_SECURE 0x01 |
| #define BEACON_TYPE_PRIVATE 0x02 |
| |
| static uint8_t test_net_key_2[16] = { 0xca, 0x11, 0xab, 0x1e }; |
| static struct { |
| uint8_t primary[16]; |
| uint8_t secondary[16]; |
| } net_key_pairs[] = { |
| { "\x01\x02", "\x03\x04" }, |
| { "\x11\x12", "\x13\x14" }, |
| { "\x21\x22", "\x23\x24" }, |
| { "\x31\x32", "\x33\x34" }, |
| }; |
| |
| extern enum bst_result_t bst_result; |
| |
| static const struct bt_mesh_test_cfg tx_cfg = { |
| .addr = 0x0001, |
| .dev_key = { 0x01 }, |
| }; |
| static const struct bt_mesh_test_cfg rx_cfg = { |
| .addr = 0x0002, |
| .dev_key = { 0x02 }, |
| }; |
| |
| typedef void (*snb_cb)(const struct bt_mesh_snb *snb); |
| |
| static snb_cb snb_cb_ptr; |
| static struct k_sem beacon_sem; |
| |
| static void snb_received(const struct bt_mesh_snb *snb) |
| { |
| if (snb_cb_ptr) { |
| snb_cb_ptr(snb); |
| } |
| } |
| |
| BT_MESH_BEACON_CB_DEFINE(snb) = { |
| .snb_received = snb_received, |
| }; |
| |
| /* Setting for scanner defining what beacon is expected next, SNB as default */ |
| static uint8_t expected_beacon = BEACON_TYPE_SECURE; |
| static struct bt_mesh_cfg_cli cfg_cli; |
| |
| static struct bt_mesh_priv_beacon_cli priv_beacon_cli; |
| |
| static const struct bt_mesh_comp prb_comp = { |
| .elem = |
| (const struct bt_mesh_elem[]){ |
| BT_MESH_ELEM(1, |
| MODEL_LIST(BT_MESH_MODEL_CFG_SRV, |
| BT_MESH_MODEL_CFG_CLI(&cfg_cli), |
| BT_MESH_MODEL_PRIV_BEACON_SRV, |
| BT_MESH_MODEL_PRIV_BEACON_CLI(&priv_beacon_cli)), |
| BT_MESH_MODEL_NONE), |
| }, |
| .elem_count = 1, |
| }; |
| |
| static struct bt_mesh_prov prov; |
| static uint8_t net_key[16] = { 1, 2, 3 }; |
| const uint8_t app_key[16] = { 4, 5, 6 }; |
| static uint8_t net_key_new[16] = { 7, 8, 9 }; |
| |
| static uint8_t last_random[13]; |
| |
| static bt_addr_le_t last_beacon_adv_addr; |
| |
| static struct bt_mesh_key priv_beacon_key; |
| |
| static int random_interval; |
| |
| static void test_args_parse(int argc, char *argv[]) |
| { |
| bs_args_struct_t args_struct[] = { |
| { |
| .dest = &random_interval, |
| .type = 'i', |
| .name = "{Random interval}", |
| .option = "rand-int", |
| .descript = "Random interval to be set for Private Beacon" |
| }, |
| }; |
| |
| bs_args_parse_all_cmd_line(argc, argv, args_struct); |
| } |
| |
| static void test_tx_init(void) |
| { |
| bt_mesh_test_cfg_set(&tx_cfg, WAIT_TIME); |
| } |
| |
| static void test_rx_init(void) |
| { |
| bt_mesh_test_cfg_set(&rx_cfg, WAIT_TIME); |
| } |
| |
| static void ivu_log(void) |
| { |
| LOG_DBG("ivi: %i", bt_mesh.iv_index); |
| LOG_DBG("flags:"); |
| |
| if (atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR)) { |
| LOG_DBG("IVU initiator"); |
| } |
| |
| if (atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS)) { |
| LOG_DBG("IVU in progress"); |
| } |
| |
| if (atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_PENDING)) { |
| LOG_DBG("IVU pending"); |
| } |
| |
| if (atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_TEST)) { |
| LOG_DBG("IVU in test mode"); |
| } |
| } |
| |
| static void tx_on_iv_update_test(void) |
| { |
| ASSERT_TRUE(!atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR)); |
| ASSERT_TRUE(!atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS)); |
| ASSERT_TRUE(!atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_PENDING)); |
| ASSERT_TRUE(!atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_TEST)); |
| ASSERT_TRUE(bt_mesh.iv_index == 0); |
| |
| /* shift beaconing time line to avoid boundary cases. */ |
| k_sleep(K_SECONDS(1)); |
| |
| bt_mesh_iv_update_test(true); |
| ASSERT_TRUE(atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_TEST)); |
| |
| ASSERT_TRUE(bt_mesh_iv_update()); |
| ASSERT_TRUE(atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS)); |
| ASSERT_TRUE(bt_mesh.iv_index == 1); |
| |
| k_sleep(K_SECONDS(BEACON_INTERVAL)); |
| |
| ASSERT_TRUE(!bt_mesh_iv_update()); |
| ASSERT_TRUE(!atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS)); |
| ASSERT_TRUE(bt_mesh.iv_index == 1); |
| |
| k_sleep(K_SECONDS(BEACON_INTERVAL)); |
| |
| ASSERT_TRUE(bt_mesh_iv_update()); |
| ASSERT_TRUE(atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS)); |
| ASSERT_TRUE(bt_mesh.iv_index == 2); |
| |
| k_sleep(K_SECONDS(BEACON_INTERVAL)); |
| |
| PASS(); |
| } |
| |
| static void test_tx_on_iv_update(void) |
| { |
| bt_mesh_test_setup(); |
| tx_on_iv_update_test(); |
| } |
| |
| static void test_rx_on_iv_update(void) |
| { |
| bt_mesh_test_setup(); |
| /* disable beaconing from Rx device to prevent |
| * the time line adaptation due to observation algorithm. |
| */ |
| bt_mesh_beacon_disable(); |
| ASSERT_TRUE(!atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR)); |
| ASSERT_TRUE(!atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS)); |
| ASSERT_TRUE(!atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_PENDING)); |
| ASSERT_TRUE(!atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_TEST)); |
| ASSERT_TRUE(bt_mesh.iv_index == 0); |
| |
| /* shift beaconing time line to avoid boundary cases. */ |
| k_sleep(K_SECONDS(1)); |
| |
| bt_mesh_iv_update_test(true); |
| ASSERT_TRUE(atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_TEST)); |
| ivu_log(); |
| |
| k_sleep(K_SECONDS(BEACON_INTERVAL)); |
| |
| ASSERT_TRUE(atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS)); |
| ASSERT_TRUE(bt_mesh.iv_index == 1); |
| ivu_log(); |
| |
| k_sleep(K_SECONDS(BEACON_INTERVAL)); |
| |
| ASSERT_TRUE(!atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS)); |
| ASSERT_TRUE(bt_mesh.iv_index == 1); |
| ivu_log(); |
| |
| k_sleep(K_SECONDS(BEACON_INTERVAL)); |
| |
| ASSERT_TRUE(atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS)); |
| ASSERT_TRUE(bt_mesh.iv_index == 2); |
| ivu_log(); |
| |
| PASS(); |
| } |
| |
| static void tx_on_key_refresh_test(void) |
| { |
| const uint8_t new_key[16] = {0x01}; |
| uint8_t phase; |
| uint8_t status; |
| |
| status = bt_mesh_subnet_kr_phase_get(BT_MESH_KEY_PRIMARY, &phase); |
| ASSERT_TRUE(status == STATUS_SUCCESS); |
| ASSERT_TRUE(phase == BT_MESH_KR_NORMAL); |
| |
| /* shift beaconing time line to avoid boundary cases. */ |
| k_sleep(K_SECONDS(1)); |
| |
| status = bt_mesh_subnet_update(BT_MESH_KEY_PRIMARY, new_key); |
| ASSERT_TRUE(status == STATUS_SUCCESS); |
| status = bt_mesh_subnet_kr_phase_get(BT_MESH_KEY_PRIMARY, &phase); |
| ASSERT_TRUE(status == STATUS_SUCCESS); |
| ASSERT_TRUE(phase == BT_MESH_KR_PHASE_1); |
| |
| k_sleep(K_SECONDS(BEACON_INTERVAL)); |
| |
| phase = BT_MESH_KR_PHASE_2; |
| status = bt_mesh_subnet_kr_phase_set(BT_MESH_KEY_PRIMARY, &phase); |
| ASSERT_TRUE(status == STATUS_SUCCESS); |
| status = bt_mesh_subnet_kr_phase_get(BT_MESH_KEY_PRIMARY, &phase); |
| ASSERT_TRUE(status == STATUS_SUCCESS); |
| ASSERT_TRUE(phase == BT_MESH_KR_PHASE_2); |
| |
| k_sleep(K_SECONDS(BEACON_INTERVAL)); |
| |
| phase = BT_MESH_KR_PHASE_3; |
| status = bt_mesh_subnet_kr_phase_set(BT_MESH_KEY_PRIMARY, &phase); |
| ASSERT_TRUE(status == STATUS_SUCCESS); |
| status = bt_mesh_subnet_kr_phase_get(BT_MESH_KEY_PRIMARY, &phase); |
| ASSERT_TRUE(status == STATUS_SUCCESS); |
| ASSERT_TRUE(phase == BT_MESH_KR_NORMAL); |
| |
| k_sleep(K_SECONDS(BEACON_INTERVAL)); |
| |
| PASS(); |
| } |
| |
| static void test_tx_on_key_refresh(void) |
| { |
| bt_mesh_test_setup(); |
| tx_on_key_refresh_test(); |
| } |
| |
| static void test_rx_on_key_refresh(void) |
| { |
| const uint8_t new_key[16] = {0x01}; |
| uint8_t phase; |
| uint8_t status; |
| |
| bt_mesh_test_setup(); |
| /* disable beaconing from Rx device to prevent |
| * the time line adaptation due to observation algorithm. |
| */ |
| bt_mesh_beacon_disable(); |
| |
| status = bt_mesh_subnet_kr_phase_get(BT_MESH_KEY_PRIMARY, &phase); |
| ASSERT_TRUE(status == STATUS_SUCCESS); |
| ASSERT_TRUE(phase == BT_MESH_KR_NORMAL); |
| |
| /* shift beaconing time line to avoid boundary cases. */ |
| k_sleep(K_SECONDS(1)); |
| |
| status = bt_mesh_subnet_update(BT_MESH_KEY_PRIMARY, new_key); |
| ASSERT_TRUE(status == STATUS_SUCCESS); |
| status = bt_mesh_subnet_kr_phase_get(BT_MESH_KEY_PRIMARY, &phase); |
| ASSERT_TRUE(status == STATUS_SUCCESS); |
| ASSERT_TRUE(phase == BT_MESH_KR_PHASE_1); |
| |
| k_sleep(K_SECONDS(BEACON_INTERVAL)); |
| |
| status = bt_mesh_subnet_kr_phase_get(BT_MESH_KEY_PRIMARY, &phase); |
| ASSERT_TRUE(status == STATUS_SUCCESS); |
| ASSERT_TRUE(phase == BT_MESH_KR_PHASE_1); |
| |
| k_sleep(K_SECONDS(BEACON_INTERVAL)); |
| |
| status = bt_mesh_subnet_kr_phase_get(BT_MESH_KEY_PRIMARY, &phase); |
| ASSERT_TRUE(status == STATUS_SUCCESS); |
| ASSERT_TRUE(phase == BT_MESH_KR_PHASE_2); |
| |
| k_sleep(K_SECONDS(BEACON_INTERVAL)); |
| |
| status = bt_mesh_subnet_kr_phase_get(BT_MESH_KEY_PRIMARY, &phase); |
| ASSERT_TRUE(status == STATUS_SUCCESS); |
| ASSERT_TRUE(phase == BT_MESH_KR_NORMAL); |
| |
| PASS(); |
| } |
| |
| static struct k_sem observer_sem; |
| static struct { |
| uint8_t flags; |
| uint32_t iv_index; |
| uint8_t random[13]; |
| uint64_t pp_hash; |
| uint64_t pp_random; |
| uint64_t net_id; |
| bt_addr_le_t adv_addr; |
| bool (*process_cb)(const uint8_t *net_id, void *ctx); |
| void *user_ctx; |
| } beacon; |
| |
| static void beacon_scan_cb(const bt_addr_le_t *addr, int8_t rssi, uint8_t adv_type, |
| struct net_buf_simple *buf) |
| { |
| const uint8_t *net_id; |
| uint8_t ad_data_type, beacon_type, length; |
| |
| ASSERT_EQUAL(BT_GAP_ADV_TYPE_ADV_NONCONN_IND, adv_type); |
| |
| length = net_buf_simple_pull_u8(buf); |
| ASSERT_EQUAL(buf->len, length); |
| ad_data_type = net_buf_simple_pull_u8(buf); |
| |
| if (ad_data_type != BT_DATA_MESH_BEACON) { |
| return; |
| } |
| |
| beacon_type = net_buf_simple_pull_u8(buf); |
| if (expected_beacon == BEACON_TYPE_SECURE) { |
| ASSERT_EQUAL(expected_beacon, beacon_type); |
| beacon.flags = net_buf_simple_pull_u8(buf); |
| net_id = net_buf_simple_pull_mem(buf, 8); |
| beacon.iv_index = net_buf_simple_pull_be32(buf); |
| } |
| else if (expected_beacon == BEACON_TYPE_PRIVATE) { |
| uint8_t private_beacon_data[5]; |
| |
| ASSERT_EQUAL(expected_beacon, beacon_type); |
| memcpy(beacon.random, buf->data, 13); |
| bt_addr_le_copy(&beacon.adv_addr, addr); |
| |
| bt_mesh_beacon_decrypt(&priv_beacon_key, &buf->data[0], &buf->data[13], |
| &buf->data[20], private_beacon_data); |
| beacon.flags = private_beacon_data[0]; |
| beacon.iv_index = sys_get_be32(&private_beacon_data[1]); |
| } |
| |
| if (!beacon.process_cb || beacon.process_cb(net_id, beacon.user_ctx)) { |
| k_sem_give(&observer_sem); |
| } |
| } |
| |
| /* Listens to beacons */ |
| static bool wait_for_beacon(bt_le_scan_cb_t scan_cb, uint16_t wait, |
| bool (*process_cb)(const uint8_t *net_id, void *ctx), void *ctx) |
| { |
| beacon.process_cb = process_cb; |
| beacon.user_ctx = ctx; |
| |
| /* Listen to beacons ONLY for one beacon interval. |
| * Tests start quite often the waiting for the next beacon after |
| * transmission or receiving the previous one. If start waiting timer |
| * for BEACON_INTERVAL interval then timer expiration and receiving of |
| * the beacon happen about the same time. That is possible unstable behavior |
| * or failing some tests. To avoid this it is worth to add 1 second to |
| * waiting time (BEACON_INTERVAL + 1) to guarantee that beacon comes |
| * before timer expiration. |
| */ |
| bool received = !bt_mesh_test_wait_for_packet(scan_cb, &observer_sem, wait); |
| |
| /* Sleep a little to get to the next beacon interval. Otherwise, calling this function |
| * again will catch the old beacon. This happens due to a known bug in legacy advertiser, |
| * which transmits advertisements longer than should. |
| */ |
| if (received && IS_ENABLED(CONFIG_BT_MESH_ADV_LEGACY)) { |
| k_sleep(K_SECONDS(1)); |
| } |
| |
| return received; |
| } |
| |
| static void send_beacon(struct net_buf_simple *buf) |
| { |
| struct bt_data ad; |
| int err; |
| |
| ad.type = BT_DATA_MESH_BEACON; |
| ad.data = buf->data; |
| ad.data_len = buf->len; |
| |
| err = bt_le_adv_start(BT_LE_ADV_NCONN, &ad, 1, NULL, 0); |
| if (err) { |
| FAIL("Advertising failed to start (err %d)\n", err); |
| } |
| |
| LOG_INF("Advertising started\n"); |
| |
| k_sleep(K_MSEC(100)); |
| |
| err = bt_le_adv_stop(); |
| if (err) { |
| FAIL("Unable to stop advertising"); |
| } |
| } |
| |
| static void beacon_create(struct net_buf_simple *buf, const uint8_t net_key[16], uint8_t flags, |
| uint32_t iv_index) |
| { |
| struct bt_mesh_key beacon_key; |
| uint8_t net_id[8]; |
| uint8_t auth[8]; |
| int err; |
| |
| err = bt_mesh_k3(net_key, net_id); |
| if (err) { |
| FAIL("Unable to generate Net ID"); |
| } |
| |
| err = bt_mesh_beacon_key(net_key, &beacon_key); |
| if (err) { |
| FAIL("Unable to generate beacon key"); |
| } |
| |
| err = bt_mesh_beacon_auth(&beacon_key, flags, net_id, iv_index, auth); |
| if (err) { |
| FAIL("Unable to generate auth value"); |
| } |
| |
| err = bt_mesh_key_destroy(&beacon_key); |
| if (err) { |
| FAIL("Unable to destroy beacon key"); |
| } |
| |
| net_buf_simple_reset(buf); |
| net_buf_simple_add_u8(buf, BEACON_TYPE_SECURE); |
| net_buf_simple_add_u8(buf, flags); |
| net_buf_simple_add_mem(buf, net_id, 8); |
| net_buf_simple_add_be32(buf, iv_index); |
| net_buf_simple_add_mem(buf, auth, 8); |
| } |
| |
| /* Test reception of invalid beacons. */ |
| static void corrupted_beacon_test(const uint8_t *offsets, |
| ssize_t field_count, |
| struct net_buf_simple *buf) |
| { |
| /* Send corrupted beacons */ |
| for (int i = 0; i < field_count; i++) { |
| buf->data[offsets[i]] ^= 0xFF; |
| send_beacon(buf); |
| buf->data[offsets[i]] ^= 0xFF; |
| /* Ensure that interval is not affected. */ |
| ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); |
| ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); |
| ASSERT_EQUAL(0x00, beacon.flags); |
| ASSERT_EQUAL(0x0000, beacon.iv_index); |
| } |
| |
| /* Now the beacon payload is valid and it shall trigger IV Update on the node. It shall also |
| * increase the beacon interval. We delay the outgoing beacon for a couple of seconds to |
| * avoid near perfect syncing with the beacon interval cycle of the device we just received |
| * a beacon from. |
| */ |
| k_sleep(K_SECONDS(3)); |
| send_beacon(buf); |
| |
| /* The beacon interval shall be changed and the node shall skip transmission of the next |
| * beacon. |
| */ |
| ASSERT_FALSE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); |
| ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); |
| ASSERT_EQUAL(0x02, beacon.flags); |
| ASSERT_EQUAL(0x0001, beacon.iv_index); |
| } |
| |
| static void test_tx_invalid(void) |
| { |
| NET_BUF_SIMPLE_DEFINE(buf, 22); |
| /* Offsets of data to be corrupted: Flags, Network ID, IV Index, Authentication value */ |
| uint8_t fields_offsets[4] = {1, 2, 10, 14}; |
| int err; |
| |
| bt_mesh_test_cfg_set(&tx_cfg, 130); |
| bt_mesh_crypto_init(); |
| k_sem_init(&observer_sem, 0, 1); |
| |
| err = bt_enable(NULL); |
| if (err) { |
| FAIL("Bluetooth init failed (err %d)", err); |
| return; |
| } |
| |
| LOG_INF("Bluetooth initialized"); |
| |
| /* Let the rx node send the first beacon. */ |
| k_sleep(K_SECONDS(5)); |
| |
| /* Create a valid beacon with IV Update Flag set to 1 and new IV Index. */ |
| beacon_create(&buf, test_net_key, 0x02, 0x0001); |
| |
| corrupted_beacon_test(fields_offsets, ARRAY_SIZE(fields_offsets), &buf); |
| |
| PASS(); |
| } |
| |
| /* Test reception of invalid beacons. */ |
| static void test_rx_invalid(void) |
| { |
| bt_mesh_test_cfg_set(&rx_cfg, 130); |
| bt_mesh_test_setup(); |
| bt_mesh_iv_update_test(true); |
| |
| k_sleep(K_SECONDS(10)); |
| |
| for (size_t i = 0; i < 4; i++) { |
| ASSERT_FALSE(atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS)); |
| ASSERT_EQUAL(0, bt_mesh.iv_index); |
| |
| k_sleep(K_SECONDS((BEACON_INTERVAL + 1) * 2)); |
| } |
| |
| /* Only the last beacon shall change IV Update state. */ |
| ASSERT_TRUE(atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS)); |
| ASSERT_EQUAL(1, bt_mesh.iv_index); |
| |
| PASS(); |
| } |
| |
| /* Test beacons reception with Key Refresh and IV Update on primary subnet. */ |
| static void test_tx_kr_old_key(void) |
| { |
| NET_BUF_SIMPLE_DEFINE(buf, 22); |
| int err; |
| |
| bt_mesh_test_cfg_set(&tx_cfg, 170); |
| bt_mesh_crypto_init(); |
| k_sem_init(&observer_sem, 0, 1); |
| |
| err = bt_enable(NULL); |
| if (err) { |
| FAIL("Bluetooth init failed (err %d)", err); |
| return; |
| } |
| |
| LOG_INF("Bluetooth initialized"); |
| |
| /* Let the rx node send the first beacon. */ |
| k_sleep(K_SECONDS(5)); |
| |
| /* The node has added a new Net Key. */ |
| |
| /* Send a beacon with Key Refresh flag set to 1, but secured with the old Net Key. The |
| * beacon shall not change Key Refresh phase, but should still be processed. The beacon |
| * interval shall be increased. |
| */ |
| beacon_create(&buf, test_net_key, 0x01, 0x0000); |
| send_beacon(&buf); |
| ASSERT_FALSE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); |
| ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); |
| ASSERT_EQUAL(0x00, beacon.flags); |
| ASSERT_EQUAL(0x0000, beacon.iv_index); |
| |
| /* The old Net Key can still initiate IV Index update. */ |
| beacon_create(&buf, test_net_key, 0x02, 0x0001); |
| send_beacon(&buf); |
| ASSERT_FALSE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); |
| ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); |
| ASSERT_EQUAL(0x02, beacon.flags); |
| ASSERT_EQUAL(0x0001, beacon.iv_index); |
| |
| /* Send beacon with Key Refresh flag set to 1, IV Update flag set to 1, but secured with |
| * the new Net Key. The node shall set Key Refresh phase to 2. The beacon interval shall |
| * be increased. |
| */ |
| beacon_create(&buf, test_net_key_2, 0x03, 0x0001); |
| send_beacon(&buf); |
| ASSERT_FALSE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); |
| ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); |
| ASSERT_EQUAL(0x03, beacon.flags); |
| ASSERT_EQUAL(0x0001, beacon.iv_index); |
| |
| /* Send beacon with Key Refresh flag set to 1, IV Update flag set to 0, but secured with |
| * the old Net Key. The beacon shall be rejected. The beacon interval shall not be changed. |
| */ |
| beacon_create(&buf, test_net_key, 0x01, 0x0001); |
| send_beacon(&buf); |
| ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); |
| ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); |
| ASSERT_EQUAL(0x03, beacon.flags); |
| ASSERT_EQUAL(0x0001, beacon.iv_index); |
| |
| /* Try the same with the new Net Key. Now the node shall change Key Refresh phase to 0. The |
| * beacon interval shall be increased. |
| */ |
| beacon_create(&buf, test_net_key_2, 0x02, 0x0001); |
| send_beacon(&buf); |
| ASSERT_FALSE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); |
| ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); |
| ASSERT_EQUAL(0x02, beacon.flags); |
| ASSERT_EQUAL(0x0001, beacon.iv_index); |
| |
| /* Send beacon with IV Update flag set to 0 and secured with the old Net Key. The beacon |
| * shall be ignored. The beacon interval shall not be changed. |
| */ |
| beacon_create(&buf, test_net_key, 0x00, 0x0001); |
| send_beacon(&buf); |
| ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); |
| ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); |
| ASSERT_EQUAL(0x02, beacon.flags); |
| ASSERT_EQUAL(0x0001, beacon.iv_index); |
| |
| /* Do the same, but secure beacon with the new Net Key. Now the node shall change IV Update |
| * flag to 0. The beacon interval shall be increased. |
| */ |
| beacon_create(&buf, test_net_key_2, 0x00, 0x0001); |
| send_beacon(&buf); |
| ASSERT_FALSE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); |
| ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); |
| ASSERT_EQUAL(0x00, beacon.flags); |
| ASSERT_EQUAL(0x0001, beacon.iv_index); |
| |
| PASS(); |
| } |
| |
| /* Test beacons reception with Key Refresh and IV Update on primary subnet. */ |
| static void test_rx_kr_old_key(void) |
| { |
| uint8_t phase; |
| uint8_t status; |
| int err; |
| |
| bt_mesh_test_cfg_set(&rx_cfg, 170); |
| bt_mesh_test_setup(); |
| bt_mesh_iv_update_test(true); |
| |
| err = bt_mesh_cfg_cli_net_key_update(0, cfg->addr, 0, test_net_key_2, &status); |
| if (err || status) { |
| FAIL("Net Key update failed (err %d, status %u)", err, status); |
| } |
| |
| static struct { |
| uint8_t phase; |
| bool ivu; |
| uint32_t ivi; |
| } test_vector[] = { |
| /* Old Net Key, attempt to change Key Refresh phase to 2. */ |
| { .phase = BT_MESH_KR_PHASE_1, .ivu = false, .ivi = 0 }, |
| /* Old Net Key, changing IV Update state. */ |
| { .phase = BT_MESH_KR_PHASE_1, .ivu = true, .ivi = 1 }, |
| /* New Net Key, changing Key Refresh phase. */ |
| { .phase = BT_MESH_KR_PHASE_2, .ivu = true, .ivi = 1 }, |
| /* Old Net Key, attempt to change IV Update state. */ |
| { .phase = BT_MESH_KR_PHASE_2, .ivu = true, .ivi = 1 }, |
| /* New Net Key, changing Key Refresh phase to 0. */ |
| { .phase = BT_MESH_KR_NORMAL, .ivu = true, .ivi = 1 }, |
| /* Old Net Key, attempt to change IV Update state to Idle.*/ |
| { .phase = BT_MESH_KR_NORMAL, .ivu = true, .ivi = 1 }, |
| /* Net Net Key, changing IV Update state to Idle. */ |
| { .phase = BT_MESH_KR_NORMAL, .ivu = false, .ivi = 1 }, |
| }; |
| |
| k_sleep(K_SECONDS(8)); |
| |
| for (size_t i = 0; i < ARRAY_SIZE(test_vector); i++) { |
| status = bt_mesh_subnet_kr_phase_get(0, &phase); |
| if (status != STATUS_SUCCESS) { |
| FAIL("Unable to populate Key Refresh phase (status: %d)", status); |
| } |
| |
| ASSERT_EQUAL(test_vector[i].phase, phase); |
| ASSERT_EQUAL(test_vector[i].ivu, atomic_test_bit(bt_mesh.flags, |
| BT_MESH_IVU_IN_PROGRESS)); |
| ASSERT_EQUAL(test_vector[i].ivi, bt_mesh.iv_index); |
| |
| k_sleep(K_SECONDS((BEACON_INTERVAL + 1) * 2)); |
| } |
| |
| PASS(); |
| } |
| |
| static bool beacon_confirm_by_subnet(const uint8_t *net_id, void *ctx) |
| { |
| const uint8_t *expected_net_id = ctx; |
| |
| return !memcmp(expected_net_id, net_id, 8); |
| } |
| |
| static bool beacon_confirm_all_subnets(const uint8_t *net_id, void *ctx) |
| { |
| static uint32_t counter; |
| int err; |
| |
| for (size_t i = 0; i < ARRAY_SIZE(net_key_pairs); i++) { |
| uint8_t expected_net_id[8]; |
| |
| err = bt_mesh_k3(net_key_pairs[i].secondary, expected_net_id); |
| if (err) { |
| FAIL("Unable to generate Net ID"); |
| } |
| |
| if (!memcmp(expected_net_id, net_id, 8)) { |
| LOG_INF("Received beacon for Net Key Idx %d", (i + 1)); |
| counter |= 1 << i; |
| |
| ASSERT_EQUAL(0x00, beacon.flags); |
| ASSERT_EQUAL(0x0000, beacon.iv_index); |
| } |
| } |
| |
| if (counter == BIT_MASK(ARRAY_SIZE(net_key_pairs))) { |
| counter = 0; |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| /* Test beacons rejection with multiple Net Keys. */ |
| static void test_tx_multiple_netkeys(void) |
| { |
| NET_BUF_SIMPLE_DEFINE(buf, 22); |
| int err; |
| |
| bt_mesh_test_cfg_set(&tx_cfg, MULT_NETKEYS_WAIT_TIME); |
| bt_mesh_crypto_init(); |
| k_sem_init(&observer_sem, 0, 1); |
| |
| err = bt_enable(NULL); |
| if (err) { |
| FAIL("Bluetooth init failed (err %d)", err); |
| return; |
| } |
| |
| LOG_INF("Bluetooth initialized"); |
| |
| /* Let the rx node send the first beacon. */ |
| k_sleep(K_SECONDS(5)); |
| |
| /* The node has added new Net Keys. */ |
| |
| for (size_t i = 0; i < ARRAY_SIZE(net_key_pairs); i++) { |
| uint8_t net_id_secondary[8]; |
| |
| err = bt_mesh_k3(net_key_pairs[i].secondary, net_id_secondary); |
| if (err) { |
| FAIL("Unable to generate Net ID"); |
| } |
| |
| /* Send beacon with Key Refresh flag set to 1, but secured with the old Net Key. |
| * The beacon shall be processed, but shall not change Key Refresh phase. |
| */ |
| beacon_create(&buf, net_key_pairs[i].primary, 0x01, 0x0000); |
| send_beacon(&buf); |
| ASSERT_FALSE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, |
| beacon_confirm_by_subnet, &buf.data[2])); |
| ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, |
| beacon_confirm_by_subnet, &buf.data[2])); |
| ASSERT_EQUAL(0x00, beacon.flags); |
| ASSERT_EQUAL(0x0000, beacon.iv_index); |
| |
| /* Wait for end of sending all beacons from the rx node before sending beacon back |
| * to prevent beacon collision. |
| */ |
| k_sleep(K_MSEC(500)); |
| |
| /* Do the same, but secure beacon with the new Net Key. The node shall set Key |
| * Refresh phase to 2. |
| */ |
| beacon_create(&buf, net_key_pairs[i].secondary, 0x01, 0x0000); |
| send_beacon(&buf); |
| ASSERT_FALSE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, |
| beacon_confirm_by_subnet, net_id_secondary)); |
| ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, |
| beacon_confirm_by_subnet, net_id_secondary)); |
| ASSERT_EQUAL(0x01, beacon.flags); |
| ASSERT_EQUAL(0x0000, beacon.iv_index); |
| |
| /* Wait for end of sending all beacons from the rx node before sending beacon back |
| * to prevent beacon collision. |
| */ |
| k_sleep(K_MSEC(500)); |
| |
| /* Send beacon with Key Refresh flag set to 0, but secured with the old Net Key. |
| * The beacon shall be rejected. The beacon interval shall not be changed. |
| */ |
| beacon_create(&buf, net_key_pairs[i].primary, 0x00, 0x0000); |
| send_beacon(&buf); |
| ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, |
| beacon_confirm_by_subnet, net_id_secondary)); |
| ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, |
| beacon_confirm_by_subnet, net_id_secondary)); |
| ASSERT_EQUAL(0x01, beacon.flags); |
| ASSERT_EQUAL(0x0000, beacon.iv_index); |
| |
| /* Wait for end of sending all beacons from the rx node before sending beacon back |
| * to prevent beacon collision. |
| */ |
| k_sleep(K_MSEC(500)); |
| |
| /* Do the same with the new Net Key. Now the node shall change Key Refresh phase |
| * to 0. The beacon interval shall be increased. |
| */ |
| beacon_create(&buf, net_key_pairs[i].secondary, 0x00, 0x0000); |
| send_beacon(&buf); |
| ASSERT_FALSE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, |
| beacon_confirm_by_subnet, net_id_secondary)); |
| ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, |
| beacon_confirm_by_subnet, net_id_secondary)); |
| ASSERT_EQUAL(0x00, beacon.flags); |
| ASSERT_EQUAL(0x0000, beacon.iv_index); |
| |
| /* Wait for end of sending all beacons from the rx node before sending beacon back |
| * to prevent beacon collision. |
| */ |
| k_sleep(K_MSEC(500)); |
| } |
| |
| /* Create a valid beacon secured with unknown Net Key. The node shall ignore the beacon and |
| * continue sending beacons regularly. |
| */ |
| uint8_t unknown_net_key[16] = {0xde, 0xad, 0xbe, 0xef}; |
| |
| beacon_create(&buf, unknown_net_key, 0x00, 0x0000); |
| send_beacon(&buf); |
| /* Ensure that interval is not affected. */ |
| ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, beacon_confirm_all_subnets, |
| NULL)); |
| ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, beacon_confirm_all_subnets, |
| NULL)); |
| |
| PASS(); |
| } |
| |
| /* Test beacons rejection with multiple Net Keys. */ |
| static void test_rx_multiple_netkeys(void) |
| { |
| uint8_t phase; |
| uint8_t status; |
| int err; |
| |
| bt_mesh_test_cfg_set(&rx_cfg, MULT_NETKEYS_WAIT_TIME); |
| bt_mesh_test_setup(); |
| bt_mesh_iv_update_test(true); |
| |
| /* Add new Net Keys and switch Key Refresh phase to 1 so that beacons can trigger Key |
| * Refresh procedure. |
| */ |
| for (size_t i = 0; i < ARRAY_SIZE(net_key_pairs); i++) { |
| err = bt_mesh_cfg_cli_net_key_add(0, cfg->addr, i + 1, net_key_pairs[i].primary, |
| &status); |
| if (err || status) { |
| FAIL("Net Key add failed (err %d, status %u)", err, status); |
| } |
| |
| err = bt_mesh_cfg_cli_net_key_update(0, cfg->addr, i + 1, |
| net_key_pairs[i].secondary, &status); |
| if (err || status) { |
| FAIL("Net Key update failed (err %d, status %u)", err, status); |
| } |
| } |
| |
| for (size_t i = 0; i < ARRAY_SIZE(net_key_pairs); i++) { |
| /* Tx device shall change Key Refresh phase to 2. */ |
| k_sleep(K_SECONDS(40)); |
| |
| status = bt_mesh_subnet_kr_phase_get(i + 1, &phase); |
| if (status != STATUS_SUCCESS) { |
| FAIL("Unable to populate Key Refresh phase (status: %d)", status); |
| } |
| |
| ASSERT_EQUAL(BT_MESH_KR_PHASE_2, phase); |
| |
| /* Tx device shall change Key Refresh phase to 0. */ |
| k_sleep(K_SECONDS(40)); |
| |
| status = bt_mesh_subnet_kr_phase_get(i + 1, &phase); |
| if (status != STATUS_SUCCESS) { |
| FAIL("Unable to populate Key Refresh phase (status: %d)", status); |
| } |
| |
| ASSERT_EQUAL(BT_MESH_KR_NORMAL, phase); |
| } |
| |
| PASS(); |
| |
| } |
| |
| static struct k_work_delayable beacon_timer; |
| |
| static void secure_beacon_send(struct k_work *work) |
| { |
| NET_BUF_SIMPLE_DEFINE(buf, 22); |
| beacon_create(&buf, test_net_key, 0, 0); |
| send_beacon(&buf); |
| /** |
| * Sending SNB(secure network beacon) faster to guarantee |
| * at least one beacon is received by tx node in 10s period. |
| */ |
| k_work_schedule(&beacon_timer, K_SECONDS(2)); |
| } |
| |
| static void test_tx_secure_beacon_interval(void) |
| { |
| bt_mesh_test_cfg_set(&tx_cfg, BEACON_INTERVAL_WAIT_TIME); |
| k_sleep(K_SECONDS(2)); |
| bt_mesh_test_setup(); |
| PASS(); |
| } |
| |
| static void test_rx_secure_beacon_interval(void) |
| { |
| NET_BUF_SIMPLE_DEFINE(buf, 22); |
| int err; |
| int64_t beacon_recv_time; |
| int64_t delta; |
| |
| bt_mesh_test_cfg_set(&rx_cfg, BEACON_INTERVAL_WAIT_TIME); |
| bt_mesh_crypto_init(); |
| k_sem_init(&observer_sem, 0, 1); |
| k_work_init_delayable(&beacon_timer, secure_beacon_send); |
| |
| err = bt_enable(NULL); |
| if (err) { |
| FAIL("Bluetooth init failed (err %d)", err); |
| } |
| |
| beacon_create(&buf, test_net_key, 0, 0); |
| k_sleep(K_SECONDS(5)); |
| /*wait provisioned tx node to send the first beacon*/ |
| ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); |
| k_sleep(K_SECONDS(2)); |
| |
| /** |
| * Sending 2 SNB 20ms apart by only sending for even values of loop variable. |
| * And verify that tx node adapts to 20s SNB interval after sending enough |
| * beacons in for loop. |
| */ |
| for (size_t i = 1; i < 5; i++) { |
| if (i % 2) { |
| send_beacon(&buf); |
| ASSERT_FALSE( |
| wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); |
| } else { |
| ASSERT_TRUE( |
| wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); |
| } |
| } |
| |
| /** |
| * Verify that tx node keeps the 20s SNB interval until adapts itself and |
| * sends SNB in 10s again. |
| */ |
| ASSERT_FALSE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); |
| ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); |
| ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); |
| beacon_recv_time = k_uptime_get(); |
| /* Start sending SNB */ |
| k_work_schedule(&beacon_timer, K_NO_WAIT); |
| |
| /** |
| * Send SNB so that the tx node stays silent and eventually sends |
| * an SNB after 600s, which is the maximum time for SNB interval. |
| * Sending beacon with 2sec interval. |
| */ |
| delta = 0; |
| for (size_t i = 0; i < 60; i++) { |
| if (wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)) { |
| delta = k_uptime_delta(&beacon_recv_time); |
| break; |
| } |
| } |
| |
| ASSERT_TRUE(delta >= (600 * MSEC_PER_SEC)); |
| PASS(); |
| } |
| |
| static uint8_t snb_cnt; |
| |
| static void snb_recv(const struct bt_mesh_snb *snb) |
| { |
| /* IV idx of 2 marks end of test */ |
| if (snb->iv_idx == 2) { |
| k_sem_give(&beacon_sem); |
| return; |
| } |
| |
| ASSERT_EQUAL(snb->flags, 0x02); |
| ASSERT_EQUAL(snb->iv_idx, 1); |
| snb_cnt++; |
| } |
| |
| static void test_rx_beacon_cache(void) |
| { |
| k_sem_init(&beacon_sem, 0, 1); |
| snb_cb_ptr = snb_recv; |
| |
| bt_mesh_test_cfg_set(&rx_cfg, WAIT_TIME); |
| bt_mesh_test_setup(); |
| |
| /* Wait for secondary SNB to end test. */ |
| ASSERT_OK_MSG(k_sem_take(&beacon_sem, K_SECONDS(40)), |
| "Didn't receive SNB in time"); |
| |
| /* Verify that only one SNB for IV_idx=1 was handled. */ |
| ASSERT_EQUAL(snb_cnt, 1); |
| PASS(); |
| } |
| |
| static void test_tx_beacon_cache(void) |
| { |
| bt_mesh_test_cfg_set(NULL, WAIT_TIME); |
| bt_mesh_crypto_init(); |
| ASSERT_OK_MSG(bt_enable(NULL), "Bluetooth init failed"); |
| |
| NET_BUF_SIMPLE_DEFINE(iv1, 22); |
| NET_BUF_SIMPLE_DEFINE(iv2, 22); |
| beacon_create(&iv1, test_net_key, 0x02, 0x0001); |
| beacon_create(&iv2, test_net_key, 0x02, 0x0002); |
| |
| /* Send two copies of the same SNB. */ |
| for (size_t i = 0; i < 2; i++) { |
| k_sleep(K_SECONDS(5)); |
| send_beacon(&iv1); |
| } |
| |
| /* Send secondary SNB to mark end of test. */ |
| k_sleep(K_SECONDS(5)); |
| send_beacon(&iv2); |
| |
| PASS(); |
| } |
| |
| typedef void (*priv_beacon_cb)(const struct bt_mesh_prb *prb); |
| |
| static priv_beacon_cb priv_beacon_cb_ptr; |
| |
| static void priv_received(const struct bt_mesh_prb *prb) |
| { |
| if (priv_beacon_cb_ptr) { |
| priv_beacon_cb_ptr(prb); |
| } |
| } |
| |
| BT_MESH_BEACON_CB_DEFINE(priv_beacon) = { |
| .priv_received = priv_received, |
| }; |
| |
| static bool private_beacon_check(const uint8_t *net_id, void *ctx) |
| { |
| bool ret; |
| bool same_random = *(bool *)ctx; |
| |
| if (memcmp(beacon.adv_addr.a.val, last_beacon_adv_addr.a.val, BT_ADDR_SIZE) == 0) { |
| return false; |
| } |
| |
| memcpy(&last_beacon_adv_addr.a.val, beacon.adv_addr.a.val, BT_ADDR_SIZE); |
| |
| if (same_random) { |
| ret = memcmp(beacon.random, last_random, 13) == 0; |
| } else { |
| ret = memcmp(beacon.random, last_random, 13) != 0; |
| } |
| |
| memcpy(&last_random, beacon.random, 13); |
| |
| return ret; |
| } |
| |
| static void provision(const struct bt_mesh_test_cfg *dev_cfg) |
| { |
| int err; |
| |
| err = bt_mesh_provision(net_key, 0, 0, 0, dev_cfg->addr, dev_cfg->dev_key); |
| if (err) { |
| FAIL("Provisioning failed (err %d)", err); |
| } |
| } |
| |
| static void tx_priv_setup(void) |
| { |
| uint8_t status; |
| struct bt_mesh_priv_beacon val; |
| int err; |
| |
| bt_mesh_test_cfg_set(NULL, WAIT_TIME); |
| bt_mesh_device_setup(&prov, &prb_comp); |
| provision(&tx_cfg); |
| |
| val.enabled = 1; |
| val.rand_interval = random_interval; |
| |
| err = bt_mesh_cfg_cli_beacon_set(0, tx_cfg.addr, 0, &status); |
| if (err || status != 0) { |
| FAIL("Beacon set failed (err %d, status %u)", err, status); |
| } |
| |
| err = bt_mesh_priv_beacon_cli_set(0, tx_cfg.addr, &val, &val); |
| if (err) { |
| FAIL("Failed to enable Private Beacon (err=%d)", err); |
| } |
| } |
| |
| static void test_tx_priv_on_iv_update(void) |
| { |
| tx_priv_setup(); |
| |
| tx_on_iv_update_test(); |
| } |
| |
| static void test_tx_priv_on_key_refresh(void) |
| { |
| tx_priv_setup(); |
| |
| tx_on_key_refresh_test(); |
| } |
| |
| static void test_tx_priv_adv(void) |
| { |
| uint8_t status; |
| struct bt_mesh_priv_beacon val; |
| int err; |
| |
| bt_mesh_test_cfg_set(NULL, BEACON_INTERVAL_WAIT_TIME); |
| bt_mesh_device_setup(&prov, &prb_comp); |
| provision(&tx_cfg); |
| |
| err = bt_mesh_cfg_cli_beacon_set(0, tx_cfg.addr, 0, &status); |
| if (err || status != 0) { |
| FAIL("Beacon set failed (err %d, status %u)", err, status); |
| } |
| |
| val.enabled = 1; |
| val.rand_interval = 1; |
| |
| err = bt_mesh_priv_beacon_cli_set(0, tx_cfg.addr, &val, &val); |
| if (err) { |
| FAIL("Failed to enable Private Beacon (err=%d)", err); |
| } |
| |
| k_sleep(K_SECONDS(6 * BEACON_INTERVAL)); |
| |
| val.rand_interval = 0; |
| |
| err = bt_mesh_priv_beacon_cli_set(0, tx_cfg.addr, &val, &val); |
| if (err) { |
| FAIL("Failed to enable Private Beacon (err=%d)", err); |
| } |
| |
| k_sleep(K_SECONDS(6 * BEACON_INTERVAL)); |
| |
| val.rand_interval = 0; |
| |
| err = bt_mesh_priv_beacon_cli_set(0, tx_cfg.addr, &val, &val); |
| if (err) { |
| FAIL("Failed to enable Private Beacon (err=%d)", err); |
| } |
| |
| k_sleep(K_SECONDS(6 * BEACON_INTERVAL)); |
| |
| val.rand_interval = 3; |
| |
| err = bt_mesh_priv_beacon_cli_set(0, tx_cfg.addr, &val, &val); |
| if (err) { |
| FAIL("Failed to enable Private Beacon (err=%d)", err); |
| } |
| |
| PASS(); |
| } |
| |
| static void test_rx_priv_adv(void) |
| { |
| bool same_random; |
| int err, i; |
| |
| bt_mesh_test_cfg_set(&rx_cfg, BEACON_INTERVAL_WAIT_TIME); |
| k_sem_init(&observer_sem, 0, 1); |
| |
| err = bt_enable(NULL); |
| if (err) { |
| FAIL("Bluetooth init failed (err %d)", err); |
| } |
| |
| expected_beacon = BEACON_TYPE_PRIVATE; |
| |
| same_random = false; |
| /* TX device is advertising with Random Interval = 1 for 6 intervals |
| * and with Random Interval = 0 for another 6 |
| */ |
| for (i = 0; i < 12; i++) { |
| wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, private_beacon_check, |
| &same_random); |
| } |
| |
| /* TX device is advertising with Random Interval = 3 */ |
| for (i = 0; i < 2; i++) { |
| same_random = true; |
| |
| for (int j = 0; j < 2; j++) { |
| wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, private_beacon_check, |
| &same_random); |
| } |
| |
| k_sleep(K_SECONDS(BEACON_INTERVAL)); |
| |
| /* Beacon random should change here */ |
| same_random = true; |
| wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, private_beacon_check, |
| &same_random); |
| } |
| |
| PASS(); |
| } |
| |
| static void private_beacon_create(struct net_buf_simple *buf, const uint8_t *net_key, uint8_t flags, |
| uint32_t iv_index) |
| { |
| uint8_t net_id[8]; |
| uint8_t auth[8]; |
| uint8_t data[5]; |
| uint8_t random_val[13]; |
| int err; |
| |
| err = bt_mesh_k3(net_key, net_id); |
| if (err) { |
| FAIL("Unable to generate Net ID"); |
| } |
| |
| err = bt_mesh_private_beacon_key(net_key, &priv_beacon_key); |
| if (err) { |
| FAIL("Unable to generate beacon key"); |
| } |
| |
| bt_rand(random_val, sizeof(random_val)); |
| bt_mesh_beacon_encrypt(&priv_beacon_key, flags, iv_index, |
| random_val, data, auth); |
| |
| net_buf_simple_reset(buf); |
| net_buf_simple_add_u8(buf, BEACON_TYPE_PRIVATE); |
| net_buf_simple_add_mem(buf, random_val, 13); |
| net_buf_simple_add_mem(buf, data, 5); |
| net_buf_simple_add_mem(buf, auth, 8); |
| } |
| |
| static void test_tx_priv_invalid(void) |
| { |
| uint8_t fields_offsets[4] = {1, 14, 15, 19}; |
| |
| NET_BUF_SIMPLE_DEFINE(buf, 27); |
| int err; |
| |
| bt_mesh_test_cfg_set(&tx_cfg, 130); |
| bt_mesh_crypto_init(); |
| k_sem_init(&observer_sem, 0, 1); |
| |
| err = bt_enable(NULL); |
| if (err) { |
| FAIL("Bluetooth init failed (err %d)", err); |
| } |
| |
| LOG_INF("Bluetooth initialized"); |
| |
| /* Let the rx node send the first beacon. */ |
| k_sleep(K_SECONDS(5)); |
| |
| /* Create a valid beacon with IV Update Flag set to 1 and new IV Index. */ |
| private_beacon_create(&buf, net_key, 0x02, 0x0001); |
| |
| expected_beacon = BEACON_TYPE_PRIVATE; |
| |
| corrupted_beacon_test(fields_offsets, ARRAY_SIZE(fields_offsets), &buf); |
| |
| PASS(); |
| } |
| |
| static void test_rx_priv_invalid(void) |
| { |
| uint8_t status; |
| struct bt_mesh_priv_beacon val; |
| int err; |
| |
| bt_mesh_test_cfg_set(NULL, 130); |
| bt_mesh_device_setup(&prov, &prb_comp); |
| provision(&rx_cfg); |
| bt_mesh_iv_update_test(true); |
| |
| val.enabled = 1; |
| val.rand_interval = random_interval; |
| |
| err = bt_mesh_cfg_cli_beacon_set(0, rx_cfg.addr, 0, &status); |
| if (err || status != 0) { |
| FAIL("Beacon set failed (err %d, status %u)", err, status); |
| } |
| |
| err = bt_mesh_priv_beacon_cli_set(0, rx_cfg.addr, &val, &val); |
| if (err) { |
| FAIL("Failed to enable Private Beacon (err=%d)", err); |
| } |
| |
| for (size_t i = 0; i < 4; i++) { |
| ASSERT_FALSE(atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS)); |
| ASSERT_EQUAL(0, bt_mesh.iv_index); |
| |
| k_sleep(K_SECONDS((BEACON_INTERVAL + 1) * 2)); |
| } |
| |
| /* Only the last beacon shall change IV Update state. */ |
| ASSERT_TRUE(atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS)); |
| ASSERT_EQUAL(1, bt_mesh.iv_index); |
| |
| PASS(); |
| } |
| |
| static void toggle_priv_beacon(uint16_t addr, uint8_t enabled) |
| { |
| int err; |
| uint8_t status; |
| struct bt_mesh_priv_beacon val; |
| |
| err = bt_mesh_cfg_cli_beacon_set(0, addr, !enabled, &status); |
| if (err || status != !enabled) { |
| FAIL("Beacon set failed (err %d, status %u)", err, status); |
| } |
| |
| val.enabled = enabled; |
| val.rand_interval = 1; |
| |
| err = bt_mesh_priv_beacon_cli_set(0, addr, &val, &val); |
| if (err) { |
| FAIL("Failed to enable Private Beacon (err=%d)", err); |
| } |
| } |
| |
| static void test_tx_priv_interleave(void) |
| { |
| uint8_t phase; |
| uint8_t status; |
| struct bt_mesh_subnet *sub; |
| |
| |
| bt_mesh_test_cfg_set(NULL, WAIT_TIME); |
| bt_mesh_device_setup(&prov, &prb_comp); |
| provision(&tx_cfg); |
| |
| sub = bt_mesh_subnet_get(0); |
| ASSERT_TRUE(sub != NULL); |
| |
| ASSERT_TRUE(!atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR)); |
| ASSERT_TRUE(!atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS)); |
| ASSERT_TRUE(!atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_PENDING)); |
| ASSERT_TRUE(!atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_TEST)); |
| ASSERT_TRUE(bt_mesh.iv_index == 0); |
| |
| status = bt_mesh_subnet_kr_phase_get(0, &phase); |
| ASSERT_TRUE(status == STATUS_SUCCESS); |
| ASSERT_TRUE(phase == BT_MESH_KR_NORMAL); |
| |
| /* Wait for SNB being advertised and switch beacon type between Beacon Intervals */ |
| k_sleep(K_SECONDS(BEACON_INTERVAL + 5)); |
| |
| toggle_priv_beacon(tx_cfg.addr, 1); |
| |
| bt_mesh_iv_update_test(true); |
| ASSERT_TRUE(atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_TEST)); |
| |
| ASSERT_TRUE(bt_mesh_iv_update()); |
| ASSERT_TRUE(atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS)); |
| ASSERT_TRUE(bt_mesh.iv_index == 1); |
| |
| /* Switch beacon type between Beacon Intervals */ |
| k_sleep(K_SECONDS(BEACON_INTERVAL + 5)); |
| |
| toggle_priv_beacon(tx_cfg.addr, 0); |
| /* Small delay to let beacons complete before subnet update is applied */ |
| k_sleep(K_MSEC(20)); |
| |
| status = bt_mesh_subnet_update(BT_MESH_KEY_PRIMARY, net_key_new); |
| ASSERT_TRUE(status == STATUS_SUCCESS); |
| status = bt_mesh_subnet_kr_phase_get(BT_MESH_KEY_PRIMARY, &phase); |
| ASSERT_TRUE(status == STATUS_SUCCESS); |
| ASSERT_TRUE(phase == BT_MESH_KR_PHASE_1); |
| |
| phase = BT_MESH_KR_PHASE_2; |
| status = bt_mesh_subnet_kr_phase_set(BT_MESH_KEY_PRIMARY, &phase); |
| ASSERT_TRUE(status == STATUS_SUCCESS); |
| status = bt_mesh_subnet_kr_phase_get(BT_MESH_KEY_PRIMARY, &phase); |
| ASSERT_TRUE(status == STATUS_SUCCESS); |
| ASSERT_TRUE(phase == BT_MESH_KR_PHASE_2); |
| |
| k_sleep(K_SECONDS(BEACON_INTERVAL + 7)); |
| toggle_priv_beacon(tx_cfg.addr, 1); |
| |
| PASS(); |
| } |
| |
| static void test_rx_priv_interleave(void) |
| { |
| int err; |
| bool same_random = false; |
| |
| bt_mesh_test_cfg_set(&rx_cfg, WAIT_TIME); |
| bt_mesh_crypto_init(); |
| k_sem_init(&observer_sem, 0, 1); |
| |
| err = bt_mesh_private_beacon_key(net_key, &priv_beacon_key); |
| if (err) { |
| FAIL("Unable to generate beacon key"); |
| } |
| |
| err = bt_enable(NULL); |
| if (err) { |
| FAIL("Bluetooth init failed (err %d)", err); |
| } |
| |
| expected_beacon = BEACON_TYPE_SECURE; |
| ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); |
| |
| expected_beacon = BEACON_TYPE_PRIVATE; |
| ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, private_beacon_check, |
| &same_random)); |
| |
| /* IVU was started here */ |
| ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, private_beacon_check, |
| &same_random)); |
| ASSERT_EQUAL(0x02, beacon.flags); |
| ASSERT_EQUAL(0x0001, beacon.iv_index); |
| |
| memset(&beacon, 0, sizeof(beacon)); |
| expected_beacon = BEACON_TYPE_SECURE; |
| |
| ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); |
| ASSERT_EQUAL(0x02, beacon.flags); |
| ASSERT_EQUAL(0x0001, beacon.iv_index); |
| |
| /* KR was started here */ |
| ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, NULL, NULL)); |
| ASSERT_EQUAL(0x03, beacon.flags); |
| ASSERT_EQUAL(0x0001, beacon.iv_index); |
| |
| expected_beacon = BEACON_TYPE_PRIVATE; |
| |
| err = bt_mesh_private_beacon_key(net_key_new, &priv_beacon_key); |
| |
| ASSERT_TRUE(wait_for_beacon(beacon_scan_cb, BEACON_INTERVAL + 1, private_beacon_check, |
| &same_random)); |
| ASSERT_EQUAL(0x03, beacon.flags); |
| ASSERT_EQUAL(0x0001, beacon.iv_index); |
| |
| PASS(); |
| } |
| |
| static uint8_t prb_cnt; |
| |
| static void priv_beacon_recv(const struct bt_mesh_prb *prb) |
| { |
| /* IV idx of 2 marks end of test */ |
| if (prb->iv_idx == 2) { |
| k_sem_give(&beacon_sem); |
| return; |
| } |
| |
| ASSERT_EQUAL(prb->flags, 0x02); |
| ASSERT_EQUAL(prb->iv_idx, 1); |
| prb_cnt++; |
| } |
| |
| static void test_rx_priv_beacon_cache(void) |
| { |
| k_sem_init(&beacon_sem, 0, 1); |
| priv_beacon_cb_ptr = priv_beacon_recv; |
| |
| bt_mesh_test_cfg_set(&rx_cfg, WAIT_TIME); |
| bt_mesh_device_setup(&prov, &prb_comp); |
| provision(&rx_cfg); |
| |
| /* Wait for secondary private beacon to end test. */ |
| ASSERT_OK_MSG(k_sem_take(&beacon_sem, K_SECONDS(40)), |
| "Didn't receive private beacon in time"); |
| |
| /* Verify that only one private beacon for IV_idx=1 was handled. */ |
| ASSERT_EQUAL(prb_cnt, 1); |
| PASS(); |
| } |
| |
| static void test_tx_priv_beacon_cache(void) |
| { |
| bt_mesh_test_cfg_set(NULL, WAIT_TIME); |
| bt_mesh_crypto_init(); |
| ASSERT_OK_MSG(bt_enable(NULL), "Bluetooth init failed"); |
| |
| NET_BUF_SIMPLE_DEFINE(iv1, 27); |
| NET_BUF_SIMPLE_DEFINE(iv2, 27); |
| private_beacon_create(&iv1, test_net_key, 0x02, 0x0001); |
| private_beacon_create(&iv2, test_net_key, 0x02, 0x0002); |
| |
| /* Send two copies of the same private beacon. */ |
| for (size_t i = 0; i < 2; i++) { |
| k_sleep(K_SECONDS(5)); |
| send_beacon(&iv1); |
| } |
| |
| /* Send secondary private beacon to mark end of test. */ |
| k_sleep(K_SECONDS(5)); |
| send_beacon(&iv2); |
| |
| PASS(); |
| } |
| |
| #if IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) |
| |
| static uint8_t test_net_key_3[16] = {0x12, 0x54, 0xab, 0x1e}; |
| |
| #define UNTIL_UPTIME(time) (k_uptime_get() > (time) ? K_NO_WAIT : K_MSEC((time) - k_uptime_get())) |
| #define BEACON_TYPE_NET_ID 0 |
| #define BEACON_TYPE_NODE_ID 1 |
| #define BEACON_TYPE_PRIVATE_NET_ID 2 |
| #define BEACON_TYPE_PRIVATE_NODE_ID 3 |
| #define BEACON_TYPE_PRIVATE_LEN 28 |
| #define TEST_NET_IDX1 0 |
| #define TEST_NET_IDX2 1 |
| #define TEST_NET_IDX3 2 |
| #define MAX_TIMEOUT ((CONFIG_BT_MESH_NODE_ID_TIMEOUT * 1000) / 6) |
| |
| #define PP_NET_ID_WAIT_TIME 610 /*seconds*/ |
| #define PP_NODE_ID_WAIT_TIME 80 /*seconds*/ |
| #define PP_MULT_NET_ID_WAIT_TIME 50 /*seconds*/ |
| #define PROXY_ADV_MULTI_SUBNET_COEX_WAIT_TIME 151 /*seconds*/ |
| |
| struct netkey_ctx { |
| uint8_t *net_key; |
| uint8_t net_id[8]; |
| uint8_t net_idx; |
| struct bt_mesh_key id_key; |
| }; |
| |
| static struct netkey_ctx pp_net0 = {.net_key = (uint8_t *)test_net_key, .net_idx = 0}; |
| static struct netkey_ctx pp_net1 = {.net_key = (uint8_t *)test_net_key_2, .net_idx = 1}; |
| static struct netkey_ctx pp_net2 = {.net_key = (uint8_t *)test_net_key_3, .net_idx = 2}; |
| |
| struct priv_test_ctx { |
| uint8_t beacon_type; |
| uint16_t *node_id_addr; |
| }; |
| |
| static void pp_netkey_ctx_init(struct netkey_ctx *net) |
| { |
| ASSERT_OK_MSG(bt_mesh_identity_key(net->net_key, &net->id_key), |
| "Failed to generate ID key"); |
| ASSERT_OK_MSG(bt_mesh_k3(net->net_key, net->net_id), "Failed to generate Net ID"); |
| } |
| |
| static uint8_t proxy_adv_type_get(uint8_t adv_type, struct net_buf_simple *buf) |
| { |
| uint8_t type; |
| uint8_t len = buf->len; |
| |
| if (adv_type != BT_GAP_ADV_TYPE_ADV_IND || len < 12) { |
| return 0xFF; |
| } |
| |
| (void)net_buf_simple_pull_mem(buf, 11); |
| type = net_buf_simple_pull_u8(buf); |
| /* BEACON_TYPE_NET_ID is 20 bytes long, while the three other accepted types are 28 bytes*/ |
| if (len != ((type == BEACON_TYPE_NET_ID) ? 20 : 28)) { |
| return 0xFF; |
| } |
| |
| return type; |
| } |
| |
| static uint64_t proxy_adv_hash_calc(struct netkey_ctx *net, uint64_t random, uint16_t *addr, |
| bool is_priv) |
| { |
| uint64_t hash; |
| uint8_t tmp[16] = {0}; |
| |
| tmp[5] = is_priv ? 3 : 0; |
| |
| if (addr) { |
| memcpy(&tmp[6], &random, 8); |
| sys_put_be16(*addr, &tmp[14]); |
| |
| } else { |
| memcpy(&tmp[0], net->net_id, 8); |
| memcpy(&tmp[8], &random, 8); |
| } |
| |
| bt_mesh_encrypt(&net->id_key, tmp, tmp); |
| memcpy(&hash, &tmp[8], 8); |
| |
| return hash; |
| } |
| |
| static bool pp_beacon_check(const uint8_t *net_id, void *ctx) |
| { |
| struct priv_test_ctx *test_ctx = (struct priv_test_ctx *)ctx; |
| |
| ASSERT_EQUAL(beacon.pp_hash, |
| proxy_adv_hash_calc(&pp_net0, beacon.pp_random, test_ctx->node_id_addr, true)); |
| |
| if (memcmp(beacon.adv_addr.a.val, last_beacon_adv_addr.a.val, BT_ADDR_SIZE) == 0) { |
| return false; |
| } |
| |
| memcpy(&last_beacon_adv_addr.a.val, beacon.adv_addr.a.val, BT_ADDR_SIZE); |
| |
| return true; |
| } |
| |
| static void priv_scan_cb(const bt_addr_le_t *addr, int8_t rssi, uint8_t adv_type, |
| struct net_buf_simple *buf) |
| { |
| struct priv_test_ctx *ctx = (struct priv_test_ctx *)beacon.user_ctx; |
| |
| if (proxy_adv_type_get(adv_type, buf) != ctx->beacon_type) { |
| /* Wrong message type */ |
| return; |
| } |
| |
| bt_addr_le_copy(&beacon.adv_addr, addr); |
| |
| if (ctx->beacon_type == BEACON_TYPE_NET_ID) { |
| beacon.net_id = net_buf_simple_pull_le64(buf); |
| } else { |
| beacon.pp_hash = net_buf_simple_pull_le64(buf); |
| beacon.pp_random = net_buf_simple_pull_le64(buf); |
| } |
| |
| if (!beacon.process_cb || beacon.process_cb(NULL, beacon.user_ctx)) { |
| k_sem_give(&observer_sem); |
| } |
| } |
| |
| struct proxy_adv_beacon { |
| uint8_t evt_type; |
| uint8_t net_idx; |
| int64_t rx_timestamp; |
| union { |
| uint64_t net_id; |
| struct { |
| uint64_t hash; |
| uint64_t random; |
| } enc; |
| } ctx; |
| }; |
| |
| static void proxy_adv_scan_all_cb(const bt_addr_le_t *addr, int8_t rssi, uint8_t adv_type, |
| struct net_buf_simple *buf) |
| { |
| struct proxy_adv_beacon *beac = (struct proxy_adv_beacon *)beacon.user_ctx; |
| |
| beac->evt_type = proxy_adv_type_get(adv_type, buf); |
| if (beac->evt_type == 0xFF) { |
| /* Not a related beacon type */ |
| return; |
| } |
| |
| bt_addr_le_copy(&beacon.adv_addr, addr); |
| beac->rx_timestamp = k_uptime_get(); |
| |
| if (beac->evt_type == BEACON_TYPE_NET_ID) { |
| beac->ctx.net_id = net_buf_simple_pull_le64(buf); |
| } else { |
| beac->ctx.enc.hash = net_buf_simple_pull_le64(buf); |
| beac->ctx.enc.random = net_buf_simple_pull_le64(buf); |
| } |
| |
| if (!beacon.process_cb || beacon.process_cb(NULL, beacon.user_ctx)) { |
| k_sem_give(&observer_sem); |
| } |
| } |
| |
| static void rx_priv_common_init(uint16_t wait) |
| { |
| bt_mesh_test_cfg_set(&rx_cfg, wait); |
| bt_mesh_crypto_init(); |
| pp_netkey_ctx_init(&pp_net0); |
| k_sem_init(&observer_sem, 0, 1); |
| ASSERT_OK_MSG(bt_enable(NULL), "Bluetooth init failed"); |
| } |
| |
| static void tx_proxy_adv_common_init(uint16_t wait, const struct bt_mesh_test_cfg *cfg) |
| { |
| bt_mesh_test_cfg_set(NULL, wait); |
| bt_mesh_device_setup(&prov, &prb_comp); |
| provision(cfg); |
| |
| /* Disable GATT proxy */ |
| ASSERT_OK_MSG(bt_mesh_gatt_proxy_set(BT_MESH_GATT_PROXY_DISABLED), |
| "Failed to disable gatt proxy"); |
| } |
| |
| static void test_tx_priv_net_id(void) |
| { |
| tx_proxy_adv_common_init(PP_NET_ID_WAIT_TIME, &tx_cfg); |
| |
| /* Enable private GATT proxy */ |
| ASSERT_OK_MSG(bt_mesh_priv_gatt_proxy_set(BT_MESH_GATT_PROXY_ENABLED), |
| "Failed to set private gatt proxy"); |
| |
| PASS(); |
| } |
| |
| static void test_rx_priv_net_id(void) |
| { |
| struct priv_test_ctx ctx = { |
| .beacon_type = BEACON_TYPE_PRIVATE_NET_ID, |
| .node_id_addr = NULL, |
| }; |
| |
| rx_priv_common_init(PP_NET_ID_WAIT_TIME); |
| |
| /* Scan for first net ID */ |
| ASSERT_TRUE( |
| wait_for_beacon(priv_scan_cb, 5, pp_beacon_check, &ctx)); |
| |
| uint64_t last_pp_random = beacon.pp_random; |
| |
| /* Wait for 10 minutes, then scan for another net |
| * ID beacon and verify that random field has changed |
| */ |
| k_sleep(K_SECONDS(600)); |
| ASSERT_TRUE( |
| wait_for_beacon(priv_scan_cb, 5, pp_beacon_check, &ctx)); |
| ASSERT_FALSE(beacon.pp_random == last_pp_random); |
| |
| PASS(); |
| } |
| |
| static void test_tx_priv_node_id(void) |
| { |
| enum bt_mesh_feat_state state; |
| |
| tx_proxy_adv_common_init(PP_NODE_ID_WAIT_TIME, &tx_cfg); |
| |
| /* Start first node advertisement */ |
| ASSERT_OK_MSG(bt_mesh_subnet_priv_node_id_set(TEST_NET_IDX1, BT_MESH_NODE_IDENTITY_RUNNING), |
| "Failed to set private node ID"); |
| |
| /* Wait for Node ID advertising to end */ |
| k_sleep(K_SECONDS(65)); |
| |
| /* Check that advertisment has stopped */ |
| ASSERT_OK_MSG(bt_mesh_subnet_priv_node_id_get(TEST_NET_IDX1, &state), |
| "Failed to get private node ID"); |
| ASSERT_EQUAL(state, BT_MESH_NODE_IDENTITY_STOPPED); |
| |
| /* Start second node advertisement */ |
| ASSERT_OK_MSG(bt_mesh_subnet_priv_node_id_set(TEST_NET_IDX1, BT_MESH_NODE_IDENTITY_RUNNING), |
| "Failed to set private node ID"); |
| |
| /* Wait to let node ID advertise for a while */ |
| k_sleep(K_SECONDS(5)); |
| |
| PASS(); |
| } |
| |
| static void test_rx_priv_node_id(void) |
| { |
| struct priv_test_ctx ctx = { |
| .beacon_type = BEACON_TYPE_PRIVATE_NODE_ID, |
| .node_id_addr = (uint16_t *)&tx_cfg.addr, |
| }; |
| |
| rx_priv_common_init(PP_NODE_ID_WAIT_TIME); |
| |
| /* Scan for first node ID */ |
| ASSERT_TRUE( |
| wait_for_beacon(priv_scan_cb, 5, pp_beacon_check, &ctx)); |
| |
| uint64_t last_pp_random = beacon.pp_random; |
| |
| /* Wait for first node ID advertisment to finish, then scan for |
| * second node ID and verify that random field has changed |
| */ |
| |
| k_sleep(K_SECONDS(65)); |
| ASSERT_TRUE( |
| wait_for_beacon(priv_scan_cb, 5, pp_beacon_check, &ctx)); |
| ASSERT_FALSE(beacon.pp_random == last_pp_random); |
| |
| PASS(); |
| } |
| |
| static void test_tx_priv_multi_net_id(void) |
| { |
| tx_proxy_adv_common_init(PP_MULT_NET_ID_WAIT_TIME, &tx_cfg); |
| |
| /* Add second network */ |
| ASSERT_OK_MSG(bt_mesh_subnet_add(TEST_NET_IDX2, test_net_key_2), |
| "Failed to add second subnet"); |
| |
| /* Enable private GATT proxy */ |
| ASSERT_OK_MSG(bt_mesh_priv_gatt_proxy_set(BT_MESH_GATT_PROXY_ENABLED), |
| "Failed to set private gatt proxy"); |
| |
| PASS(); |
| } |
| |
| static void proxy_adv_subnet_find(struct proxy_adv_beacon *beac, struct netkey_ctx **nets, |
| uint8_t net_cnt) |
| { |
| for (size_t i = 0; i < net_cnt; i++) { |
| |
| switch (beac->evt_type) { |
| case BEACON_TYPE_NET_ID: |
| if (!memcmp(nets[i]->net_id, &beac->ctx.net_id, 8)) { |
| beac->net_idx = nets[i]->net_idx; |
| return; |
| } |
| break; |
| case BEACON_TYPE_NODE_ID: |
| if (beac->ctx.enc.hash == |
| proxy_adv_hash_calc(nets[i], beac->ctx.enc.random, |
| (uint16_t *)&tx_cfg.addr, false)) { |
| beac->net_idx = nets[i]->net_idx; |
| return; |
| } |
| break; |
| case BEACON_TYPE_PRIVATE_NET_ID: |
| if (beac->ctx.enc.hash == |
| proxy_adv_hash_calc(nets[i], beac->ctx.enc.random, |
| NULL, true)) { |
| beac->net_idx = nets[i]->net_idx; |
| return; |
| } |
| break; |
| case BEACON_TYPE_PRIVATE_NODE_ID: |
| if (beac->ctx.enc.hash == |
| proxy_adv_hash_calc(nets[i], beac->ctx.enc.random, |
| (uint16_t *)&tx_cfg.addr, true)) { |
| beac->net_idx = nets[i]->net_idx; |
| return; |
| } |
| break; |
| |
| default: |
| FAIL("Unexpected beacon type"); |
| break; |
| } |
| } |
| |
| FAIL("Could not find matching subnet for incoming proxy adv beacon"); |
| } |
| |
| static const char *const proxy_adv_str[] = {"Net_ID", "Node_ID", "Priv_Net_ID", "Priv_Node_ID"}; |
| struct expected_proxy_adv_evt { |
| uint8_t evt_type; |
| uint8_t net_idx; |
| uint16_t evt_cnt; |
| struct { |
| int64_t after; |
| int64_t before; |
| } time; |
| }; |
| |
| static void proxy_adv_register_evt(struct proxy_adv_beacon *beac, |
| struct expected_proxy_adv_evt *exp_evts, uint8_t cnt) |
| { |
| for (int i = 0; i < cnt; i++) { |
| if ((exp_evts[i].evt_cnt) && (beac->evt_type == exp_evts[i].evt_type) && |
| (beac->net_idx == exp_evts[i].net_idx) && |
| (beac->rx_timestamp >= exp_evts[i].time.after) && |
| (beac->rx_timestamp <= exp_evts[i].time.before)) { |
| exp_evts[i].evt_cnt--; |
| } |
| } |
| } |
| |
| static void proxy_adv_confirm_evt(struct expected_proxy_adv_evt *exp_evts, uint8_t cnt) |
| { |
| bool missing_evts = false; |
| |
| for (int i = 0; i < cnt; i++) { |
| if (exp_evts[i].evt_cnt) { |
| LOG_ERR("Missing %d expected %s idx %d events in period %llums-%llums", |
| exp_evts[i].evt_cnt, proxy_adv_str[exp_evts[i].evt_type], |
| exp_evts[i].net_idx, exp_evts[i].time.after, |
| exp_evts[i].time.before); |
| missing_evts = true; |
| } |
| } |
| |
| if (missing_evts) { |
| FAIL("Test failed due to missing events"); |
| } |
| } |
| |
| static void proxy_adv_scan_all(struct netkey_ctx **nets, uint16_t net_cnt, |
| struct expected_proxy_adv_evt *exp_evt, uint16_t exp_evt_cnt, |
| int64_t timeout) |
| { |
| struct proxy_adv_beacon beac; |
| |
| while (k_uptime_get() < timeout) { |
| |
| ASSERT_TRUE(wait_for_beacon(proxy_adv_scan_all_cb, 2, NULL, &beac)); |
| proxy_adv_subnet_find(&beac, nets, net_cnt); |
| proxy_adv_register_evt(&beac, exp_evt, exp_evt_cnt); |
| |
| /** We want to monitor an even distribution of adv events. |
| * To ensure this, we wait a little less than the minimum |
| * proxy adv period (1 second) before scanning for the next |
| * evt. |
| */ |
| k_sleep(K_MSEC(990)); |
| } |
| |
| proxy_adv_confirm_evt(exp_evt, exp_evt_cnt); |
| } |
| |
| #define PROXY_ADV_MULTI_CHECKPOINT_1 20000 |
| #define PROXY_ADV_MULTI_CHECKPOINT_2 50000 |
| #define PROXY_ADV_MULTI_CHECKPOINT_3 110000 |
| #define PROXY_ADV_MULTI_CHECKPOINT_4 130000 |
| #define PROXY_ADV_MULTI_CHECKPOINT_END 150000 |
| |
| static void test_tx_proxy_adv_multi_subnet_coex(void) |
| { |
| tx_proxy_adv_common_init(PROXY_ADV_MULTI_SUBNET_COEX_WAIT_TIME, &tx_cfg); |
| |
| /* Enable GATT proxy */ |
| ASSERT_OK_MSG(bt_mesh_gatt_proxy_set(BT_MESH_GATT_PROXY_ENABLED), |
| "Failed to Enable gatt proxy"); |
| |
| k_sleep(UNTIL_UPTIME(PROXY_ADV_MULTI_CHECKPOINT_1)); |
| /* Add second and third network */ |
| ASSERT_OK_MSG(bt_mesh_subnet_add(TEST_NET_IDX2, test_net_key_2), |
| "Failed to add second subnet"); |
| ASSERT_OK_MSG(bt_mesh_subnet_add(TEST_NET_IDX3, test_net_key_3), |
| "Failed to add third subnet"); |
| |
| k_sleep(UNTIL_UPTIME(PROXY_ADV_MULTI_CHECKPOINT_2)); |
| /* Start Node Identity on second network */ |
| bt_mesh_proxy_identity_start(bt_mesh_subnet_get(TEST_NET_IDX2), false); |
| |
| k_sleep(UNTIL_UPTIME(PROXY_ADV_MULTI_CHECKPOINT_3)); |
| /* Prepare for solicitation */ |
| ASSERT_OK_MSG(bt_mesh_gatt_proxy_set(BT_MESH_GATT_PROXY_DISABLED), |
| "Failed to Enable gatt proxy"); |
| ASSERT_OK_MSG(bt_mesh_od_priv_proxy_set(20), "Failed to set OD priv proxy state"); |
| |
| k_sleep(UNTIL_UPTIME(PROXY_ADV_MULTI_CHECKPOINT_4)); |
| /* Re-enable GATT proxy and remove second and third network */ |
| ASSERT_OK_MSG(bt_mesh_gatt_proxy_set(BT_MESH_GATT_PROXY_ENABLED), |
| "Failed to Enable gatt proxy"); |
| ASSERT_OK_MSG(bt_mesh_subnet_del(TEST_NET_IDX2), "Failed to delete subnet"); |
| ASSERT_OK_MSG(bt_mesh_subnet_del(TEST_NET_IDX3), "Failed to delete subnet"); |
| |
| PASS(); |
| } |
| |
| static const struct bt_mesh_test_cfg solicit_trigger_cfg = { |
| .addr = 0x0003, |
| .dev_key = { 0x03 }, |
| }; |
| |
| static void test_tx_proxy_adv_solicit_trigger(void) |
| { |
| tx_proxy_adv_common_init(PROXY_ADV_MULTI_SUBNET_COEX_WAIT_TIME, &solicit_trigger_cfg); |
| /* Disable SNB. */ |
| bt_mesh_beacon_set(false); |
| ASSERT_OK_MSG(bt_mesh_subnet_add(TEST_NET_IDX2, test_net_key_2), |
| "Failed to add second subnet"); |
| |
| k_sleep(UNTIL_UPTIME(PROXY_ADV_MULTI_CHECKPOINT_3)); |
| |
| /* Solicit first and second network */ |
| ASSERT_OK_MSG(bt_mesh_proxy_solicit(TEST_NET_IDX1), |
| "Failed to start solicitation"); |
| ASSERT_OK_MSG(bt_mesh_proxy_solicit(TEST_NET_IDX2), |
| "Failed to start solicitation"); |
| |
| PASS(); |
| } |
| |
| static void test_rx_proxy_adv_multi_subnet_coex(void) |
| { |
| rx_priv_common_init(PROXY_ADV_MULTI_SUBNET_COEX_WAIT_TIME); |
| /* Disable SNB. */ |
| bt_mesh_beacon_set(false); |
| pp_netkey_ctx_init(&pp_net1); |
| pp_netkey_ctx_init(&pp_net2); |
| |
| struct netkey_ctx *nets[] = {&pp_net0, &pp_net1, &pp_net2}; |
| struct expected_proxy_adv_evt exp_evt[] = { |
| /** A single subnet is active on the device with GATT Proxy |
| * enabled. Verify that the single subnet has exclusive |
| * access to the adv medium. |
| */ |
| {.evt_type = BEACON_TYPE_NET_ID, .net_idx = 0, .evt_cnt = 19, |
| .time = {.after = 0, .before = PROXY_ADV_MULTI_CHECKPOINT_1}}, |
| |
| /** Two additional subnets are added to the device. |
| * Check that the subnets are sharing the adv medium, |
| * advertising NET_ID beacons. |
| */ |
| {.evt_type = BEACON_TYPE_NET_ID, .net_idx = 0, .evt_cnt = 8, |
| .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_1, |
| .before = PROXY_ADV_MULTI_CHECKPOINT_2}}, |
| {.evt_type = BEACON_TYPE_NET_ID, .net_idx = 1, .evt_cnt = 8, |
| .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_1, |
| .before = PROXY_ADV_MULTI_CHECKPOINT_2}}, |
| {.evt_type = BEACON_TYPE_NET_ID, .net_idx = 2, .evt_cnt = 8, |
| .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_1, |
| .before = PROXY_ADV_MULTI_CHECKPOINT_2}}, |
| |
| /** The second subnet enables Node Identity. Check that NODE_ID |
| * is advertised by this subnet, and that the two others |
| * continues to advertise NET_ID. |
| */ |
| {.evt_type = BEACON_TYPE_NET_ID, .net_idx = 0, .evt_cnt = 16, |
| .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_2, |
| .before = PROXY_ADV_MULTI_CHECKPOINT_3}}, |
| {.evt_type = BEACON_TYPE_NODE_ID, .net_idx = 1, .evt_cnt = 16, |
| .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_2, |
| .before = PROXY_ADV_MULTI_CHECKPOINT_3}}, |
| {.evt_type = BEACON_TYPE_NET_ID, .net_idx = 2, .evt_cnt = 16, |
| .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_2, |
| .before = PROXY_ADV_MULTI_CHECKPOINT_3}}, |
| |
| /** The first and second subnet gets solicited. Check that |
| * PRIVATE_NET_ID is advertised by these subnet, |
| */ |
| {.evt_type = BEACON_TYPE_PRIVATE_NET_ID, .net_idx = 0, .evt_cnt = 8, |
| .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_3, |
| .before = PROXY_ADV_MULTI_CHECKPOINT_4}}, |
| {.evt_type = BEACON_TYPE_PRIVATE_NET_ID, .net_idx = 1, .evt_cnt = 8, |
| .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_3, |
| .before = PROXY_ADV_MULTI_CHECKPOINT_4}}, |
| |
| /** Second and third subnet are disabled. Verify that the single |
| * subnet has exclusive access to the adv medium. |
| */ |
| {.evt_type = BEACON_TYPE_NET_ID, .net_idx = 0, .evt_cnt = 18, |
| .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_4, |
| .before = PROXY_ADV_MULTI_CHECKPOINT_END}}, |
| }; |
| |
| proxy_adv_scan_all(nets, ARRAY_SIZE(nets), exp_evt, ARRAY_SIZE(exp_evt), |
| PROXY_ADV_MULTI_CHECKPOINT_END); |
| PASS(); |
| } |
| |
| static void test_rx_priv_multi_net_id(void) |
| { |
| rx_priv_common_init(PP_MULT_NET_ID_WAIT_TIME); |
| pp_netkey_ctx_init(&pp_net1); |
| |
| struct priv_test_ctx ctx = { |
| .beacon_type = BEACON_TYPE_PRIVATE_NET_ID, |
| .node_id_addr = NULL, |
| }; |
| |
| uint16_t itr = 4; |
| static uint8_t old_idx = 0xff; |
| static struct { |
| struct netkey_ctx *net; |
| uint16_t recv_cnt; |
| int64_t start; |
| } net_ctx[2] = { |
| {.net = &pp_net0}, |
| |
| {.net = &pp_net1}, |
| }; |
| |
| while (itr) { |
| /* Scan for net ID from both networks */ |
| ASSERT_TRUE(wait_for_beacon(priv_scan_cb, 5, NULL, &ctx)); |
| |
| for (size_t i = 0; i < ARRAY_SIZE(net_ctx); i++) { |
| if (beacon.pp_hash == |
| proxy_adv_hash_calc(net_ctx[i].net, beacon.pp_random, NULL, true)) { |
| if (old_idx == 0xff) { |
| /* Received first Net ID advertisment */ |
| old_idx = i; |
| net_ctx[i].start = k_uptime_get(); |
| net_ctx[i].recv_cnt++; |
| } else if (old_idx != i) { |
| /* Received Net ID adv for new subnet */ |
| |
| /* Verify last Net ID adv result */ |
| ASSERT_IN_RANGE(k_uptime_get() - net_ctx[old_idx].start, |
| MAX_TIMEOUT - 1000, MAX_TIMEOUT + 1000); |
| ASSERT_IN_RANGE(net_ctx[old_idx].recv_cnt, 9, 12); |
| net_ctx[old_idx].recv_cnt = 0; |
| old_idx = i; |
| |
| /* The test ends when all itterations are completed */ |
| itr--; |
| |
| net_ctx[i].start = k_uptime_get(); |
| net_ctx[i].recv_cnt++; |
| } else { |
| /* Received another Net ID adv from same subnet*/ |
| net_ctx[i].recv_cnt++; |
| } |
| |
| break; |
| } |
| } |
| } |
| |
| PASS(); |
| } |
| |
| static void test_tx_priv_gatt_proxy(void) |
| { |
| bt_mesh_test_cfg_set(NULL, WAIT_TIME); |
| bt_mesh_device_setup(&prov, &prb_comp); |
| provision(&tx_cfg); |
| bt_mesh_iv_update_test(true); |
| |
| ASSERT_TRUE(bt_mesh.iv_index == 0); |
| |
| /* Disable SNB. */ |
| bt_mesh_beacon_set(false); |
| ASSERT_OK_MSG(bt_mesh_scan_disable(), "Failed to disable scanner"); |
| ASSERT_OK_MSG(bt_mesh_gatt_proxy_set(BT_MESH_GATT_PROXY_DISABLED), |
| "Failed to disable gatt proxy"); |
| ASSERT_OK_MSG(bt_mesh_priv_gatt_proxy_set(BT_MESH_PRIV_GATT_PROXY_ENABLED), |
| "Failed to set private gatt proxy"); |
| |
| /* Wait for proxy connection to complete. */ |
| WAIT_FOR_COND(bt_mesh_proxy_srv_connected_cnt() == 1, 10); |
| |
| /* Wait a bit so RX device can disable scanner, then start IV update */ |
| k_sleep(K_SECONDS(2)); |
| ASSERT_TRUE(bt_mesh_iv_update()); |
| |
| /* Check that IV index has updated */ |
| ASSERT_TRUE(bt_mesh.iv_index == 1); |
| PASS(); |
| } |
| |
| static void test_rx_priv_gatt_proxy(void) |
| { |
| bt_mesh_test_cfg_set(NULL, WAIT_TIME); |
| bt_mesh_device_setup(&prov, &prb_comp); |
| provision(&rx_cfg); |
| bt_mesh_iv_update_test(true); |
| |
| ASSERT_TRUE(bt_mesh.iv_index == 0); |
| |
| /* Disable SNB. */ |
| bt_mesh_beacon_set(false); |
| ASSERT_OK_MSG(bt_mesh_gatt_proxy_set(BT_MESH_GATT_PROXY_DISABLED), |
| "Failed to disable gatt proxy"); |
| ASSERT_OK_MSG(bt_mesh_priv_gatt_proxy_set(BT_MESH_PRIV_GATT_PROXY_ENABLED), |
| "Failed to set private gatt proxy"); |
| ASSERT_OK_MSG(bt_mesh_proxy_connect(TEST_NET_IDX1), "Failed to connect over proxy"); |
| |
| /* Wait for connection to complete, then disable scanner |
| * to ensure that all RX communication arrives over GATT. |
| */ |
| WAIT_FOR_COND(bt_mesh_proxy_cli_is_connected(TEST_NET_IDX1), 10); |
| ASSERT_OK_MSG(bt_mesh_scan_disable(), "Failed to disable scanner"); |
| |
| /* Wait for the IV index to update. |
| * Verifying that IV index has changed proves that a private |
| * beacon arrived successfully over the GATT connection. |
| */ |
| WAIT_FOR_COND(bt_mesh.iv_index == 1, 10); |
| |
| PASS(); |
| } |
| |
| #endif |
| |
| #define TEST_CASE(role, name, description) \ |
| { \ |
| .test_id = "beacon_" #role "_" #name, \ |
| .test_descr = description, \ |
| .test_pre_init_f = test_##role##_init, \ |
| .test_tick_f = bt_mesh_test_timeout, \ |
| .test_main_f = test_##role##_##name, \ |
| .test_args_f = test_args_parse, \ |
| } |
| |
| static const struct bst_test_instance test_beacon[] = { |
| TEST_CASE(tx, on_iv_update, "Beacon: send on IV update"), |
| TEST_CASE(tx, on_key_refresh, "Beacon: send on key refresh"), |
| TEST_CASE(tx, invalid, "Beacon: send invalid beacon"), |
| TEST_CASE(tx, kr_old_key, "Beacon: send old Net Key"), |
| TEST_CASE(tx, multiple_netkeys, "Beacon: multiple Net Keys"), |
| TEST_CASE(tx, secure_beacon_interval, "Beacon: send secure beacons"), |
| TEST_CASE(tx, beacon_cache, "Beacon: advertise duplicate SNBs"), |
| TEST_CASE(tx, priv_on_iv_update, "Private Beacon: send on IV update"), |
| TEST_CASE(tx, priv_on_key_refresh, "Private Beacon: send on Key Refresh"), |
| TEST_CASE(tx, priv_adv, "Private Beacon: advertise Private Beacons"), |
| TEST_CASE(tx, priv_invalid, "Private Beacon: advertise invalid beacons"), |
| TEST_CASE(tx, priv_interleave, "Private Beacon: advertise interleaved with SNB"), |
| TEST_CASE(tx, priv_beacon_cache, "Private Beacon: advertise duplicate Private Beacons"), |
| #if CONFIG_BT_MESH_GATT_PROXY |
| TEST_CASE(tx, priv_net_id, "Private Proxy: advertise Net ID"), |
| TEST_CASE(tx, priv_node_id, "Private Proxy: advertise Node ID"), |
| TEST_CASE(tx, priv_multi_net_id, "Private Proxy: advertise multiple Net ID"), |
| TEST_CASE(tx, priv_gatt_proxy, "Private Proxy: Send Private Beacons over GATT"), |
| TEST_CASE(tx, proxy_adv_multi_subnet_coex, "Proxy Adv: Multi subnet coex proxy adv"), |
| TEST_CASE(tx, proxy_adv_solicit_trigger, "Proxy Adv: Trigger Solicitation"), |
| #endif |
| |
| TEST_CASE(rx, on_iv_update, "Beacon: receive with IV update flag"), |
| TEST_CASE(rx, on_key_refresh, "Beacon: receive with key refresh flag"), |
| TEST_CASE(rx, invalid, "Beacon: receive invalid beacon"), |
| TEST_CASE(rx, kr_old_key, "Beacon: receive old Net Key"), |
| TEST_CASE(rx, multiple_netkeys, "Beacon: multiple Net Keys"), |
| TEST_CASE(rx, secure_beacon_interval, "Beacon: receive and send secure beacons"), |
| TEST_CASE(rx, beacon_cache, "Beacon: receive duplicate SNBs"), |
| TEST_CASE(rx, priv_adv, "Private Beacon: verify random regeneration"), |
| TEST_CASE(rx, priv_invalid, "Private Beacon: receive invalid beacons"), |
| TEST_CASE(rx, priv_interleave, "Private Beacon: interleaved with SNB"), |
| TEST_CASE(rx, priv_beacon_cache, "Private Beacon: receive duplicate Private Beacons"), |
| #if CONFIG_BT_MESH_GATT_PROXY |
| TEST_CASE(rx, priv_net_id, "Private Proxy: scan for Net ID"), |
| TEST_CASE(rx, priv_node_id, "Private Proxy: scan for Node ID"), |
| TEST_CASE(rx, priv_multi_net_id, "Private Proxy: scan for multiple Net ID"), |
| TEST_CASE(rx, priv_gatt_proxy, "Private Proxy: Receive Private Beacons over GATT"), |
| TEST_CASE(rx, proxy_adv_multi_subnet_coex, "Proxy Adv: Multi subnet coex proxy adv"), |
| #endif |
| BSTEST_END_MARKER |
| }; |
| |
| struct bst_test_list *test_beacon_install(struct bst_test_list *tests) |
| { |
| tests = bst_add_tests(tests, test_beacon); |
| return tests; |
| } |