diff --git a/subsys/bluetooth/mesh/proxy_srv.c b/subsys/bluetooth/mesh/proxy_srv.c index 9cad9e2fe04..25a44abfded 100644 --- a/subsys/bluetooth/mesh/proxy_srv.c +++ b/subsys/bluetooth/mesh/proxy_srv.c @@ -712,6 +712,13 @@ static bool proxy_adv_request_get(struct bt_mesh_subnet *sub, struct proxy_adv_r return false; } + /** The priority for proxy adv is first solicitation, then Node Identity, + * and lastly Network ID. Network ID is prioritized last since, in many + * cases, another device can fulfill the same demand. Solicitation is + * prioritized first since legacy devices are dependent on this to + * connect to the network. + */ + #if defined(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV) if (bt_mesh_od_priv_proxy_get() > 0 && sub->solicited) { int32_t timeout = MSEC_PER_SEC * (int32_t)bt_mesh_od_priv_proxy_get(); @@ -753,7 +760,7 @@ static bool proxy_adv_request_get(struct bt_mesh_subnet *sub, struct proxy_adv_r static struct bt_mesh_subnet *adv_sub_get_next(struct bt_mesh_subnet *sub_start, struct proxy_adv_request *request) { - struct bt_mesh_subnet *sub_temp = sub_start; + struct bt_mesh_subnet *sub_temp = bt_mesh_subnet_next(sub_start); do { if (proxy_adv_request_get(sub_temp, request)) { @@ -823,7 +830,7 @@ static int gatt_proxy_advertise(void) } } - sub = adv_sub_get_next(bt_mesh_subnet_next(sub_adv.sub), &request); + sub = adv_sub_get_next(sub_adv.sub, &request); if (!sub) { LOG_ERR("Could not find subnet to advertise"); return -ENOENT; diff --git a/tests/bsim/bluetooth/mesh/overlay_gatt.conf b/tests/bsim/bluetooth/mesh/overlay_gatt.conf index f94a26d623f..7660313b700 100644 --- a/tests/bsim/bluetooth/mesh/overlay_gatt.conf +++ b/tests/bsim/bluetooth/mesh/overlay_gatt.conf @@ -6,3 +6,4 @@ CONFIG_BT_MESH_LOW_POWER=n CONFIG_BT_MESH_FRIEND=n CONFIG_BT_CENTRAL=y CONFIG_BT_MESH_PROXY_CLIENT=y +CONFIG_BT_MESH_PROXY_SOLICITATION=y diff --git a/tests/bsim/bluetooth/mesh/src/test_beacon.c b/tests/bsim/bluetooth/mesh/src/test_beacon.c index f9230a397a9..e5f7d515da7 100644 --- a/tests/bsim/bluetooth/mesh/src/test_beacon.c +++ b/tests/bsim/bluetooth/mesh/src/test_beacon.c @@ -31,7 +31,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_INF); #define BEACON_TYPE_PRIVATE 0x02 #endif -static uint8_t test_net_key_secondary[16] = { 0xca, 0x11, 0xab, 0x1e }; +static uint8_t test_net_key_2[16] = { 0xca, 0x11, 0xab, 0x1e }; static struct { uint8_t primary[16]; uint8_t secondary[16]; @@ -334,6 +334,7 @@ static struct { uint8_t random[13]; uint64_t pp_hash; uint64_t pp_random; + uint64_t net_id; bt_addr_le_t adv_addr; #endif bool (*process_cb)(const uint8_t *net_id, void *ctx); @@ -625,7 +626,7 @@ static void test_tx_kr_old_key(void) * 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_secondary, 0x03, 0x0001); + 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)); @@ -645,7 +646,7 @@ static void test_tx_kr_old_key(void) /* 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_secondary, 0x02, 0x0001); + 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)); @@ -665,7 +666,7 @@ static void test_tx_kr_old_key(void) /* 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_secondary, 0x00, 0x0001); + 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)); @@ -686,7 +687,7 @@ static void test_rx_kr_old_key(void) 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_secondary, &status); + 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); } @@ -1541,60 +1542,73 @@ static void test_tx_priv_beacon_cache(void) #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 pp_netkey_ctx { +struct netkey_ctx { uint8_t *net_key; uint8_t net_id[8]; + uint8_t net_idx; struct bt_mesh_key id_key; }; -static struct pp_netkey_ctx pp_net0 = {.net_key = (uint8_t *)test_net_key}; -static struct pp_netkey_ctx pp_net1 = {.net_key = (uint8_t *)test_net_key_secondary}; +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 pp_netkey_ctx *net) +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 bool pp_type_check(uint16_t expected_beacon, uint8_t adv_type, struct net_buf_simple *buf) +static uint8_t proxy_adv_type_get(uint8_t adv_type, struct net_buf_simple *buf) { - if (adv_type != BT_GAP_ADV_TYPE_ADV_IND || buf->len != BEACON_TYPE_PRIVATE_LEN) { - return false; + uint8_t type; + uint8_t len = buf->len; + + if (adv_type != BT_GAP_ADV_TYPE_ADV_IND || len < 12) { + return 0xFF; } - /* Remove Header */ (void)net_buf_simple_pull_mem(buf, 11); - - uint8_t beacon_type = net_buf_simple_pull_u8(buf); - - if (beacon_type != expected_beacon) { - return false; + 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 true; + return type; } -static uint64_t pp_hash_calc(struct pp_netkey_ctx *net, uint64_t random, uint16_t *addr) +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, 0, 0, 0, 0, 3}; + uint8_t tmp[16] = {0}; + + tmp[5] = is_priv ? 3 : 0; if (addr) { memcpy(&tmp[6], &random, 8); @@ -1616,7 +1630,7 @@ 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, - pp_hash_calc(&pp_net0, beacon.pp_random, test_ctx->node_id_addr)); + 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; @@ -1632,15 +1646,58 @@ static void priv_scan_cb(const bt_addr_le_t *addr, int8_t rssi, uint8_t adv_type { struct priv_test_ctx *ctx = (struct priv_test_ctx *)beacon.user_ctx; - if (!pp_type_check(ctx->beacon_type, adv_type, buf)) { + if (proxy_adv_type_get(adv_type, buf) != ctx->beacon_type) { /* Wrong message type */ return; } bt_addr_le_copy(&beacon.adv_addr, addr); - beacon.pp_hash = net_buf_simple_pull_le64(buf); - beacon.pp_random = net_buf_simple_pull_le64(buf); + 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); @@ -1656,11 +1713,11 @@ static void rx_priv_common_init(uint16_t wait) ASSERT_OK_MSG(bt_enable(NULL), "Bluetooth init failed"); } -static void tx_priv_common_init(uint16_t wait) +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(&tx_cfg); + provision(cfg); /* Disable GATT proxy */ ASSERT_OK_MSG(bt_mesh_gatt_proxy_set(BT_MESH_GATT_PROXY_DISABLED), @@ -1669,7 +1726,7 @@ static void tx_priv_common_init(uint16_t wait) static void test_tx_priv_net_id(void) { - tx_priv_common_init(PP_NET_ID_WAIT_TIME); + 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), @@ -1708,7 +1765,7 @@ static void test_tx_priv_node_id(void) { enum bt_mesh_feat_state state; - tx_priv_common_init(PP_NODE_ID_WAIT_TIME); + 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), @@ -1761,10 +1818,10 @@ static void test_rx_priv_node_id(void) static void test_tx_priv_multi_net_id(void) { - tx_priv_common_init(PP_MULT_NET_ID_WAIT_TIME); + 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_secondary), + ASSERT_OK_MSG(bt_mesh_subnet_add(TEST_NET_IDX2, test_net_key_2), "Failed to add second subnet"); /* Enable private GATT proxy */ @@ -1774,6 +1831,246 @@ static void test_tx_priv_multi_net_id(void) 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 events in period %llums-%llums", + exp_evts[i].evt_cnt, proxy_adv_str[exp_evts[i].evt_type], + 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); + 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); + 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 = 17, + .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_2, + .before = PROXY_ADV_MULTI_CHECKPOINT_3}}, + {.evt_type = BEACON_TYPE_NODE_ID, .net_idx = 1, .evt_cnt = 17, + .time = {.after = PROXY_ADV_MULTI_CHECKPOINT_2, + .before = PROXY_ADV_MULTI_CHECKPOINT_3}}, + {.evt_type = BEACON_TYPE_NET_ID, .net_idx = 2, .evt_cnt = 17, + .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 = 9, + .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 = 9, + .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 = 19, + .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); @@ -1787,7 +2084,7 @@ static void test_rx_priv_multi_net_id(void) uint16_t itr = 4; static uint8_t old_idx = 0xff; static struct { - struct pp_netkey_ctx *net; + struct netkey_ctx *net; uint16_t recv_cnt; int64_t start; } net_ctx[2] = { @@ -1802,7 +2099,7 @@ static void test_rx_priv_multi_net_id(void) for (size_t i = 0; i < ARRAY_SIZE(net_ctx); i++) { if (beacon.pp_hash == - pp_hash_calc(net_ctx[i].net, beacon.pp_random, NULL)) { + 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; @@ -1931,6 +2228,8 @@ static const struct bst_test_instance test_beacon[] = { 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 #endif @@ -1951,6 +2250,7 @@ static const struct bst_test_instance test_beacon[] = { 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 #endif BSTEST_END_MARKER diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/proxy_adv_multi_subnet_coex.sh b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/proxy_adv_multi_subnet_coex.sh new file mode 100755 index 00000000000..aa96ee325d8 --- /dev/null +++ b/tests/bsim/bluetooth/mesh/tests_scripts/priv_beacon/proxy_adv_multi_subnet_coex.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +# Copyright 2023 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh + +# Test Proxy advertisement Coex + +# This test verifies correct Proxy advertisement behavior for a device +# where the Proxy adv requirements changes over time, both for single +# and multiple subnets. The TX device is the DUT in this instance, while +# the RX device scans and verifies that the correct proxy adv messages of +# the different subnets is sent within the expected time delta. + +# Note 1: The maximum allowed timeslot for a subnet to advertise proxy +# in this scenario is 10 seconds when there is more than one subnet that +# has active proxy adv work. This is reflected in the scanning criteria +# on the RX device. + +# Note 2: The expected message received count for each event is based on +# what would be a reasonable/acceptable to receive within a given time +# window. The Mesh Protocol specification does not specify exactly the +# timing for Proxy ADV messages. + +# Test procedure: +# 1. (0-20 seconds) A single subnet is active on the TX device with GATT +# Proxy enabled. RX device verifies that the single subnet has exclusive +# access to the adv medium. +# 2. (20-50 seconds) Two additional subnets are added to the TX device. RX +# device checks that the subnets are sharing the adv medium, advertising +# NET_ID beacons. +# 3. (50-110 seconds) The second subnet enables Node Identity. RX device +# checks that NODE_ID is advertised by this subnet, and that the two +# others continues to advertise NET_ID. +# 4. (110-130 seconds) The first and second subnet gets solicited. RX device +# checks that PRIVATE_NET_ID is advertised by these subnets. +# 5. (130-150 seconds) The second and third subnet are disabled on the TX +# device. RX device verifies that the single subnet has exclusive access +# to the adv medium again. + + +conf=prj_mesh1d1_conf +overlay=overlay_gatt_conf +RunTest proxy_adv_multi_subnet_coex \ + beacon_tx_proxy_adv_multi_subnet_coex \ + beacon_rx_proxy_adv_multi_subnet_coex \ + beacon_tx_proxy_adv_solicit_trigger + +conf=prj_mesh1d1_conf +overlay=overlay_gatt_conf_overlay_psa_conf +RunTest proxy_adv_multi_subnet_coex \ + beacon_tx_proxy_adv_multi_subnet_coex \ + beacon_rx_proxy_adv_multi_subnet_coex \ + beacon_tx_proxy_adv_solicit_trigger