Bluetooth: Mesh: Fixed issue with RPR server and client.

Fixed issue when reprovisioning is done on a device with
both RPR client and server on the same device.

Signed-off-by: Ingar Kulbrandstad <ingar.kulbrandstad@nordicsemi.no>
This commit is contained in:
Ingar Kulbrandstad 2023-10-02 17:41:31 +02:00 committed by Johan Hedberg
commit a5d15ec017
3 changed files with 444 additions and 123 deletions

View file

@ -857,6 +857,72 @@ int bt_mesh_pb_remote_open(struct bt_mesh_rpr_cli *cli,
return link_open(uuid, &pb_remote_cli, net_idx, addr, 0, &ctx, 0); return link_open(uuid, &pb_remote_cli, net_idx, addr, 0, &ctx, 0);
} }
/* Remote Provision done where client and server is on same node, skip open link
* and sending of reprovision message, just execute reprovisioning on it self.
*/
static int reprovision_local_client_server(uint16_t addr)
{
int err;
const uint8_t *pub_key;
const uint8_t *priv_key = NULL;
if (atomic_test_and_set_bit(bt_mesh_prov_link.flags, LINK_ACTIVE)) {
return -EBUSY;
}
LOG_DBG("net_idx %u iv_index 0x%08x, addr 0x%04x",
prov_device.node->net_idx, bt_mesh_cdb.iv_index, addr);
atomic_set_bit(bt_mesh_prov_link.flags, REPROVISION);
atomic_set_bit(bt_mesh_prov_link.flags, PROVISIONER);
bt_mesh_prov_link.addr = addr;
bt_mesh_prov_link.bearer = &pb_remote_cli;
bt_mesh_prov_link.role = &role_provisioner;
prov_device.net_idx = prov_device.node->net_idx;
prov_device.attention_duration = 0;
if (IS_ENABLED(CONFIG_BT_MESH_PROV_OOB_PUBLIC_KEY) &&
bt_mesh_prov->public_key_be && bt_mesh_prov->private_key_be) {
LOG_DBG("Use OOB Public and Private key");
pub_key = bt_mesh_prov->public_key_be;
priv_key = bt_mesh_prov->private_key_be;
} else {
pub_key = bt_mesh_pub_key_get();
}
if (!pub_key) {
LOG_ERR("No public key available");
return -ENOEXEC;
}
if (bt_mesh_dhkey_gen(pub_key, priv_key, bt_mesh_prov_link.dhkey)) {
LOG_ERR("Failed to generate DHKey");
return -ENOEXEC;
}
LOG_DBG("DHkey: %s", bt_hex(bt_mesh_prov_link.dhkey, DH_KEY_SIZE));
err = bt_mesh_dev_key(bt_mesh_prov_link.dhkey,
bt_mesh_prov_link.prov_salt, prov_device.new_dev_key);
if (err) {
LOG_ERR("Unable to generate device key");
return err;
}
bt_mesh_dev_key_cand(prov_device.new_dev_key);
/* Mark the link that was never opened as closed. */
atomic_set_bit(bt_mesh_prov_link.flags, COMPLETE);
bt_mesh_reprovision(addr);
bt_mesh_dev_key_cand_activate();
if (bt_mesh_prov->reprovisioned) {
LOG_DBG("Application reprovisioned callback 0x%04x", bt_mesh_primary_addr());
bt_mesh_prov->reprovisioned(bt_mesh_primary_addr());
}
prov_link_closed(PROV_BEARER_LINK_STATUS_SUCCESS);
return 0;
}
int bt_mesh_pb_remote_open_node(struct bt_mesh_rpr_cli *cli, int bt_mesh_pb_remote_open_node(struct bt_mesh_rpr_cli *cli,
struct bt_mesh_rpr_node *srv, uint16_t addr, struct bt_mesh_rpr_node *srv, uint16_t addr,
bool composition_change) bool composition_change)
@ -877,6 +943,11 @@ int bt_mesh_pb_remote_open_node(struct bt_mesh_rpr_cli *cli,
return -ENOENT; return -ENOENT;
} }
/* Check if server is on same device as client */
if (IS_ENABLED(CONFIG_BT_MESH_RPR_SRV) && bt_mesh_has_addr(srv->addr)) {
return reprovision_local_client_server(addr);
}
return link_open(NULL, &pb_remote_cli, prov_device.node->net_idx, addr, return link_open(NULL, &pb_remote_cli, prov_device.node->net_idx, addr,
0, &ctx, 0); 0, &ctx, 0);
} }

View file

@ -139,6 +139,19 @@ static const struct bt_mesh_comp rpr_srv_comp = {
.elem_count = 1, .elem_count = 1,
}; };
static const struct bt_mesh_comp rpr_cli_srv_comp = {
.elem =
(struct bt_mesh_elem[]){
BT_MESH_ELEM(1,
MODEL_LIST(BT_MESH_MODEL_CFG_SRV,
BT_MESH_MODEL_CFG_CLI(&(struct bt_mesh_cfg_cli){}),
BT_MESH_MODEL_RPR_CLI(&rpr_cli),
BT_MESH_MODEL_RPR_SRV),
BT_MESH_MODEL_NONE),
},
.elem_count = 1,
};
static int mock_pdu_send(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, static int mock_pdu_send(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf) struct net_buf_simple *buf)
{ {
@ -1072,18 +1085,127 @@ static void test_provisioner_pb_remote_client_provision_timeout(void)
PASS(); PASS();
} }
static void reprovision_remote_devkey_client(struct bt_mesh_rpr_node *srv,
struct bt_mesh_cdb_node *node)
{
uint8_t status;
uint8_t prev_node_dev_key[16];
ASSERT_OK_MSG(bt_mesh_cdb_node_key_export(node, prev_node_dev_key),
"Can't export device key from cdb");
bt_mesh_reprovision_remote(&rpr_cli, srv, current_dev_addr, false);
ASSERT_OK(k_sem_take(&reprov_sem, K_SECONDS(20)));
/* Check that CDB has updated Device Key for the node. */
ASSERT_TRUE(bt_mesh_key_compare(prev_node_dev_key, &node->dev_key));
ASSERT_OK_MSG(bt_mesh_cdb_node_key_export(node, prev_node_dev_key),
"Can't export device key from cdb");
/* Check device key by adding appkey. */
ASSERT_OK(bt_mesh_cfg_cli_app_key_add(0, current_dev_addr, 0, 0, test_app_key,
&status));
ASSERT_OK(status);
/* Let RPR Server verify Device Key. */
k_sleep(K_SECONDS(2));
}
static void reprovision_remote_comp_data_client(struct bt_mesh_rpr_node *srv,
struct bt_mesh_cdb_node *node,
struct net_buf_simple *dev_comp)
{
NET_BUF_SIMPLE_DEFINE(new_dev_comp, BT_MESH_RX_SDU_MAX);
uint8_t prev_node_dev_key[16];
uint8_t page;
ASSERT_OK_MSG(bt_mesh_cdb_node_key_export(node, prev_node_dev_key),
"Can't export device key from cdb");
bt_mesh_reprovision_remote(&rpr_cli, srv, current_dev_addr, true);
ASSERT_OK(k_sem_take(&reprov_sem, K_SECONDS(20)));
/* Check that CDB has updated Device Key for the node. */
ASSERT_TRUE(bt_mesh_key_compare(prev_node_dev_key, &node->dev_key));
ASSERT_OK_MSG(bt_mesh_cdb_node_key_export(node, prev_node_dev_key),
"Can't export device key from cdb");
/* Check that Composition Data Page 128 is now Page 0. */
net_buf_simple_reset(&new_dev_comp);
ASSERT_OK(bt_mesh_cfg_cli_comp_data_get(0, current_dev_addr, 0, &page,
&new_dev_comp));
ASSERT_EQUAL(0, page);
ASSERT_EQUAL(dev_comp->len, new_dev_comp.len);
if (memcmp(dev_comp->data, new_dev_comp.data, dev_comp->len)) {
FAIL("Wrong composition data page 0");
}
/* Let RPR Server verify Device Key. */
k_sleep(K_SECONDS(2));
}
static void reprovision_remote_address_client(struct bt_mesh_rpr_node *srv,
struct bt_mesh_cdb_node *node)
{
uint8_t status;
uint8_t prev_node_dev_key[16];
ASSERT_OK_MSG(bt_mesh_cdb_node_key_export(node, prev_node_dev_key),
"Can't export device key from cdb");
bt_mesh_reprovision_remote(&rpr_cli, srv, current_dev_addr + 1, false);
ASSERT_OK(k_sem_take(&reprov_sem, K_SECONDS(20)));
current_dev_addr++;
srv->addr++;
/* Check that device doesn't respond to old address with old and new device key. */
struct bt_mesh_cdb_node *prev_node;
uint8_t tmp[16];
prev_node = bt_mesh_cdb_node_alloc((uint8_t[16]) {}, current_dev_addr - 1, 1, 0);
ASSERT_TRUE(node);
ASSERT_OK_MSG(bt_mesh_cdb_node_key_import(prev_node, prev_node_dev_key),
"Can't import device key into cdb");
ASSERT_EQUAL(-ETIMEDOUT, bt_mesh_cfg_cli_app_key_add(0, current_dev_addr - 1, 0, 0,
test_app_key, &status));
ASSERT_OK_MSG(bt_mesh_cdb_node_key_export(node, tmp),
"Can't export device key from cdb");
ASSERT_OK_MSG(bt_mesh_cdb_node_key_import(prev_node, tmp),
"Can't import device key into cdb");
ASSERT_EQUAL(-ETIMEDOUT, bt_mesh_cfg_cli_app_key_add(0, current_dev_addr - 1, 0, 0,
test_app_key, &status));
bt_mesh_cdb_node_del(prev_node, false);
/* Check that CDB has updated Device Key for the node. */
ASSERT_TRUE(bt_mesh_key_compare(prev_node_dev_key, &node->dev_key));
ASSERT_OK_MSG(bt_mesh_cdb_node_key_export(node, prev_node_dev_key),
"Can't export device key from cdb");
/* Check new device address by adding appkey. */
ASSERT_OK(bt_mesh_cfg_cli_app_key_add(0, current_dev_addr, 0, 0, test_app_key,
&status));
ASSERT_OK(status);
/* Let RPR Server verify Device Key. */
k_sleep(K_SECONDS(2));
}
/** @brief Verify robustness of NPPI procedures on a RPR Client by running Device Key Refresh, /** @brief Verify robustness of NPPI procedures on a RPR Client by running Device Key Refresh,
* Node Composition Refresh and Node Address Refresh procedures. * Node Composition Refresh and Node Address Refresh procedures.
*/ */
static void test_provisioner_pb_remote_client_nppi_robustness(void) static void test_provisioner_pb_remote_client_nppi_robustness(void)
{ {
NET_BUF_SIMPLE_DEFINE(dev_comp, BT_MESH_RX_SDU_MAX); NET_BUF_SIMPLE_DEFINE(dev_comp, BT_MESH_RX_SDU_MAX);
NET_BUF_SIMPLE_DEFINE(new_dev_comp, BT_MESH_RX_SDU_MAX);
uint8_t page; uint8_t page;
uint16_t pb_remote_server_addr; uint16_t pb_remote_server_addr;
uint8_t status; uint8_t status;
struct bt_mesh_cdb_node *node; struct bt_mesh_cdb_node *node;
uint8_t prev_node_dev_key[16];
provisioner_pb_remote_client_setup(); provisioner_pb_remote_client_setup();
@ -1111,96 +1233,23 @@ static void test_provisioner_pb_remote_client_nppi_robustness(void)
node = bt_mesh_cdb_node_get(current_dev_addr); node = bt_mesh_cdb_node_get(current_dev_addr);
ASSERT_TRUE(node); ASSERT_TRUE(node);
ASSERT_OK_MSG(bt_mesh_cdb_node_key_export(node, prev_node_dev_key),
"Can't export device key from cdb");
LOG_INF("Testing DevKey refresh..."); LOG_INF("Testing DevKey refresh...");
for (int i = 0; i < PROV_REPROV_COUNT; i++) { for (int i = 0; i < PROV_REPROV_COUNT; i++) {
LOG_INF("Refreshing device key #%d...\n", i); LOG_INF("Refreshing device key #%d...\n", i);
bt_mesh_reprovision_remote(&rpr_cli, &srv, current_dev_addr, false); reprovision_remote_devkey_client(&srv, node);
ASSERT_OK(k_sem_take(&reprov_sem, K_SECONDS(20)));
/* Check that CDB has updated Device Key for the node. */
ASSERT_TRUE(bt_mesh_key_compare(prev_node_dev_key, &node->dev_key));
ASSERT_OK_MSG(bt_mesh_cdb_node_key_export(node, prev_node_dev_key),
"Can't export device key from cdb");
/* Check device key by adding appkey. */
ASSERT_OK(bt_mesh_cfg_cli_app_key_add(0, current_dev_addr, 0, 0, test_app_key,
&status));
ASSERT_OK(status);
/* Let RPR Server verify Device Key. */
k_sleep(K_SECONDS(2));
} }
LOG_INF("Testing Composition Data refresh..."); LOG_INF("Testing Composition Data refresh...");
for (int i = 0; i < PROV_REPROV_COUNT; i++) { for (int i = 0; i < PROV_REPROV_COUNT; i++) {
LOG_INF("Changing Composition Data #%d...\n", i); LOG_INF("Changing Composition Data #%d...\n", i);
bt_mesh_reprovision_remote(&rpr_cli, &srv, current_dev_addr, true); reprovision_remote_comp_data_client(&srv, node, &dev_comp);
ASSERT_OK(k_sem_take(&reprov_sem, K_SECONDS(20)));
/* Check that CDB has updated Device Key for the node. */
ASSERT_TRUE(bt_mesh_key_compare(prev_node_dev_key, &node->dev_key));
ASSERT_OK_MSG(bt_mesh_cdb_node_key_export(node, prev_node_dev_key),
"Can't export device key from cdb");
/* Check that Composition Data Page 128 is now Page 0. */
net_buf_simple_reset(&new_dev_comp);
ASSERT_OK(bt_mesh_cfg_cli_comp_data_get(0, current_dev_addr, 0, &page,
&new_dev_comp));
ASSERT_EQUAL(0, page);
ASSERT_EQUAL(dev_comp.len, new_dev_comp.len);
if (memcmp(dev_comp.data, new_dev_comp.data, dev_comp.len)) {
FAIL("Wrong composition data page 0");
}
/* Let RPR Server verify Device Key. */
k_sleep(K_SECONDS(2));
} }
LOG_INF("Testing address refresh..."); LOG_INF("Testing address refresh...");
for (int i = 0; i < PROV_REPROV_COUNT; i++) { for (int i = 0; i < PROV_REPROV_COUNT; i++) {
LOG_INF("Changing address #%d...\n", i); LOG_INF("Changing address #%d...\n", i);
bt_mesh_reprovision_remote(&rpr_cli, &srv, current_dev_addr + 1, false); reprovision_remote_address_client(&srv, node);
ASSERT_OK(k_sem_take(&reprov_sem, K_SECONDS(20)));
current_dev_addr++;
srv.addr++;
/* Check that device doesn't respond to old address with old and new device key. */
struct bt_mesh_cdb_node *prev_node;
uint8_t tmp[16];
prev_node = bt_mesh_cdb_node_alloc((uint8_t[16]) {}, current_dev_addr - 1, 1, 0);
ASSERT_TRUE(node);
ASSERT_OK_MSG(bt_mesh_cdb_node_key_import(prev_node, prev_node_dev_key),
"Can't import device key into cdb");
ASSERT_EQUAL(-ETIMEDOUT, bt_mesh_cfg_cli_app_key_add(0, current_dev_addr - 1, 0, 0,
test_app_key, &status));
ASSERT_OK_MSG(bt_mesh_cdb_node_key_export(node, tmp),
"Can't export device key from cdb");
ASSERT_OK_MSG(bt_mesh_cdb_node_key_import(prev_node, tmp),
"Can't import device key into cdb");
ASSERT_EQUAL(-ETIMEDOUT, bt_mesh_cfg_cli_app_key_add(0, current_dev_addr - 1, 0, 0,
test_app_key, &status));
bt_mesh_cdb_node_del(prev_node, false);
/* Check that CDB has updated Device Key for the node. */
ASSERT_TRUE(bt_mesh_key_compare(prev_node_dev_key, &node->dev_key));
ASSERT_OK_MSG(bt_mesh_cdb_node_key_export(node, prev_node_dev_key),
"Can't export device key from cdb");
/* Check new device address by adding appkey. */
ASSERT_OK(bt_mesh_cfg_cli_app_key_add(0, current_dev_addr, 0, 0, test_app_key,
&status));
ASSERT_OK(status);
/* Let RPR Server verify Device Key. */
k_sleep(K_SECONDS(2));
} }
PASS(); PASS();
@ -1240,13 +1289,78 @@ static void test_device_pb_remote_server_proved(void)
PASS(); PASS();
} }
static void reprovision_remote_devkey_server(const uint16_t initial_addr)
{
uint8_t prev_dev_key[16];
uint8_t dev_key[16];
ASSERT_OK(bt_mesh_key_export(prev_dev_key, &bt_mesh.dev_key));
ASSERT_OK(k_sem_take(&reprov_sem, K_SECONDS(30)));
ASSERT_EQUAL(initial_addr, bt_mesh_primary_addr());
/* Let Configuration Client activate the new Device Key and verify that it has
* been changed.
*/
k_sleep(K_SECONDS(2));
ASSERT_OK(bt_mesh_key_export(dev_key, &bt_mesh.dev_key));
ASSERT_TRUE(memcmp(&prev_dev_key, dev_key, sizeof(dev_key)));
}
static void reprovision_remote_comp_data_server(const uint16_t initial_addr)
{
u_int8_t prev_dev_key[16];
u_int8_t dev_key[16];
/* The RPR Server won't let to run Node Composition Refresh procedure without first
* setting the BT_MESH_COMP_DIRTY flag. The flag is set on a boot if there is a
* "bt/mesh/cmp" entry in settings. The entry is added by the
* `bt_mesh_comp_change_prepare() call. The test suite is not compiled
* with CONFIG_BT_SETTINGS, so the flag will never be set. Since the purpose of the
* test is to check RPR Server behavior, but not the actual swap of the Composition
* Data, the flag is toggled directly from the test.
*/
atomic_set_bit(bt_mesh.flags, BT_MESH_COMP_DIRTY);
ASSERT_OK(bt_mesh_key_export(prev_dev_key, &bt_mesh.dev_key));
ASSERT_OK(k_sem_take(&reprov_sem, K_SECONDS(30)));
/* Drop the flag manually as CONFIG_BT_SETTINGS is not enabled. */
atomic_clear_bit(bt_mesh.flags, BT_MESH_COMP_DIRTY);
ASSERT_EQUAL(initial_addr, bt_mesh_primary_addr());
/* Let Configuration Client activate the new Device Key and verify that it has
* been changed.
*/
k_sleep(K_SECONDS(2));
ASSERT_OK(bt_mesh_key_export(dev_key, &bt_mesh.dev_key));
ASSERT_TRUE(memcmp(prev_dev_key, dev_key, sizeof(dev_key)));
}
static void reprovision_remote_address_server(const uint16_t initial_addr)
{
uint8_t prev_dev_key[16];
uint8_t dev_key[16];
ASSERT_OK(bt_mesh_key_export(prev_dev_key, &bt_mesh.dev_key));
ASSERT_OK(k_sem_take(&reprov_sem, K_SECONDS(30)));
ASSERT_EQUAL(initial_addr + 1, bt_mesh_primary_addr());
/* Let Configuration Client activate the new Device Key and verify that it has
* been changed.
*/
k_sleep(K_SECONDS(2));
ASSERT_OK(bt_mesh_key_export(dev_key, &bt_mesh.dev_key));
ASSERT_TRUE(memcmp(prev_dev_key, dev_key, sizeof(dev_key)));
}
/** @brief Verify robustness of NPPI procedures on a RPR Server by running Device Key Refresh, /** @brief Verify robustness of NPPI procedures on a RPR Server by running Device Key Refresh,
* Node Composition Refresh and Node Address Refresh procedures multiple times each. * Node Composition Refresh and Node Address Refresh procedures multiple times each.
*/ */
static void test_device_pb_remote_server_nppi_robustness(void) static void test_device_pb_remote_server_nppi_robustness(void)
{ {
struct bt_mesh_key prev_dev_key;
k_sem_init(&prov_sem, 0, 1); k_sem_init(&prov_sem, 0, 1);
k_sem_init(&reprov_sem, 0, 1); k_sem_init(&reprov_sem, 0, 1);
@ -1259,65 +1373,25 @@ static void test_device_pb_remote_server_nppi_robustness(void)
ASSERT_OK(k_sem_take(&prov_sem, K_SECONDS(20))); ASSERT_OK(k_sem_take(&prov_sem, K_SECONDS(20)));
const uint16_t initial_addr = bt_mesh_primary_addr(); const uint16_t initial_addr = bt_mesh_primary_addr();
memcpy(&prev_dev_key, &bt_mesh.dev_key, sizeof(struct bt_mesh_key));
LOG_INF("Enabling PB-Remote server"); LOG_INF("Enabling PB-Remote server");
ASSERT_OK(bt_mesh_prov_enable(BT_MESH_PROV_REMOTE)); ASSERT_OK(bt_mesh_prov_enable(BT_MESH_PROV_REMOTE));
/* Test Device Key Refresh procedure robustness. */ /* Test Device Key Refresh procedure robustness. */
for (int i = 0; i < PROV_REPROV_COUNT; i++) { for (int i = 0; i < PROV_REPROV_COUNT; i++) {
LOG_INF("Devkey refresh loop #%d, waiting for being reprov ...\n", i); LOG_INF("Devkey refresh loop #%d, waiting for being reprov ...\n", i);
ASSERT_OK(k_sem_take(&reprov_sem, K_SECONDS(30))); reprovision_remote_devkey_server(initial_addr);
ASSERT_EQUAL(initial_addr, bt_mesh_primary_addr());
/* Let Configuration Client activate the new Device Key and verify that it has
* been changed.
*/
k_sleep(K_SECONDS(2));
ASSERT_TRUE(memcmp(&prev_dev_key, &bt_mesh.dev_key, sizeof(struct bt_mesh_key)));
memcpy(&prev_dev_key, &bt_mesh.dev_key, sizeof(struct bt_mesh_key));
} }
/* Test Node Composition Refresh procedure robustness. */ /* Test Node Composition Refresh procedure robustness. */
for (int i = 0; i < PROV_REPROV_COUNT; i++) { for (int i = 0; i < PROV_REPROV_COUNT; i++) {
/* The RPR Server won't let to run Node Composition Refresh procedure without first
* setting the BT_MESH_COMP_DIRTY flag. The flag is set on a boot if there is a
* "bt/mesh/cmp" entry in settings. The entry is added by the
* `bt_mesh_comp_change_prepare() call. The test suite is not compiled
* with CONFIG_BT_SETTINGS, so the flag will never be set. Since the purpose of the
* test is to check RPR Server behavior, but not the actual swap of the Composition
* Data, the flag is toggled directly from the test.
*/
atomic_set_bit(bt_mesh.flags, BT_MESH_COMP_DIRTY);
LOG_INF("Composition data refresh loop #%d, waiting for being reprov ...\n", i); LOG_INF("Composition data refresh loop #%d, waiting for being reprov ...\n", i);
ASSERT_OK(k_sem_take(&reprov_sem, K_SECONDS(30))); reprovision_remote_comp_data_server(initial_addr);
/* Drop the flag manually as CONFIG_BT_SETTINGS is not enabled. */
atomic_clear_bit(bt_mesh.flags, BT_MESH_COMP_DIRTY);
ASSERT_EQUAL(initial_addr, bt_mesh_primary_addr());
/* Let Configuration Client activate the new Device Key and verify that it has
* been changed.
*/
k_sleep(K_SECONDS(2));
ASSERT_TRUE(memcmp(&prev_dev_key, &bt_mesh.dev_key, sizeof(struct bt_mesh_key)));
memcpy(&prev_dev_key, &bt_mesh.dev_key, sizeof(struct bt_mesh_key));
} }
/* Node Address Refresh robustness. */ /* Node Address Refresh robustness. */
for (int i = 0; i < PROV_REPROV_COUNT; i++) { for (int i = 0; i < PROV_REPROV_COUNT; i++) {
LOG_INF("Address refresh loop #%d, waiting for being reprov ...\n", i); LOG_INF("Address refresh loop #%d, waiting for being reprov ...\n", i);
ASSERT_OK(k_sem_take(&reprov_sem, K_SECONDS(30))); reprovision_remote_address_server(initial_addr+i);
ASSERT_EQUAL(initial_addr + 1 + i, bt_mesh_primary_addr());
/* Let Configuration Client activate the new Device Key and verify that it has
* been changed.
*/
k_sleep(K_SECONDS(2));
ASSERT_TRUE(memcmp(&prev_dev_key, &bt_mesh.dev_key, sizeof(struct bt_mesh_key)));
memcpy(&prev_dev_key, &bt_mesh.dev_key, sizeof(struct bt_mesh_key));
} }
PASS(); PASS();
@ -1354,6 +1428,146 @@ static void test_provisioner_pb_remote_client_ncrp_provision(void)
PASS(); PASS();
} }
/** @brief A device running a Remote Provisioning client and server that is used to reprovision
* another device and it self with the client.
*/
static void test_device_pb_remote_client_server_same_dev(void)
{
NET_BUF_SIMPLE_DEFINE(dev_comp, BT_MESH_RX_SDU_MAX);
uint8_t status;
struct bt_mesh_cdb_node *node;
uint8_t page;
uint8_t prev_dev_key[16];
uint16_t test_vector[] = { 0x0002, 0x0001 };
k_sem_init(&prov_sem, 0, 1);
k_sem_init(&reprov_sem, 0, 1);
bt_mesh_device_setup(&prov, &rpr_cli_srv_comp);
ASSERT_OK(bt_mesh_cdb_create(test_net_key));
ASSERT_OK(bt_mesh_provision(test_net_key, 0, 0, 0, 0x0001, dev_key));
LOG_INF("Enabling PB-Remote server");
ASSERT_OK(bt_mesh_prov_enable(BT_MESH_PROV_REMOTE));
/* Provision a remote device with RPR Client and Server with local RPR Server. */
current_dev_addr = 0x0001;
struct bt_mesh_rpr_node srv = {
.addr = current_dev_addr,
.net_idx = 0,
.ttl = 3,
};
LOG_INF("Provisioner prov, waiting for prov ...\n");
ASSERT_OK(provision_remote(&srv, 1, &srv.addr));
ASSERT_OK(k_sem_take(&prov_sem, K_SECONDS(20)));
/* Check device key by adding bt_mesh_reprovision_remote appkey. */
ASSERT_OK(bt_mesh_cfg_cli_app_key_add(0, current_dev_addr, 0, 0, test_app_key, &status));
ASSERT_OK(status);
/* Swap callback to catch when device reprovisioned. */
prov.node_added = prov_node_added_rpr;
/* Reprovision a device with both RPR Client and Server. */
for (int i = 0; i < ARRAY_SIZE(test_vector); i++) {
current_dev_addr = test_vector[i];
srv.addr = current_dev_addr;
bool self_reprov = (bool)(current_dev_addr == bt_mesh_primary_addr());
/* Store initial Composition Data Page 0. */
net_buf_simple_reset(&dev_comp);
ASSERT_OK(bt_mesh_cfg_cli_comp_data_get(0, current_dev_addr, 0, &page, &dev_comp));
node = bt_mesh_cdb_node_get(current_dev_addr);
ASSERT_TRUE(node);
LOG_INF("Refreshing 0x%04x device key ...\n", srv.addr);
ASSERT_OK(bt_mesh_key_export(prev_dev_key, &bt_mesh.dev_key));
reprovision_remote_devkey_client(&srv, node);
if (self_reprov) {
uint8_t dev_key[16];
ASSERT_EQUAL(current_dev_addr, bt_mesh_primary_addr());
/* Let Configuration Client activate the new Device Key
* and verify that it has been changed.
*/
ASSERT_OK(bt_mesh_key_export(dev_key, &bt_mesh.dev_key));
ASSERT_TRUE(memcmp(prev_dev_key, dev_key, sizeof(dev_key)));
}
LOG_INF("Changing 0x%04x Composition Data ...\n", srv.addr);
ASSERT_OK(bt_mesh_key_export(prev_dev_key, &bt_mesh.dev_key));
reprovision_remote_comp_data_client(&srv, node, &dev_comp);
if (self_reprov) {
uint8_t dev_key[16];
ASSERT_EQUAL(current_dev_addr, bt_mesh_primary_addr());
/* Let Configuration Client activate the new Device Key
* and verify that it has been changed.
*/
ASSERT_OK(bt_mesh_key_export(dev_key, &bt_mesh.dev_key));
ASSERT_TRUE(memcmp(prev_dev_key, dev_key, sizeof(struct bt_mesh_key)));
}
LOG_INF("Changing 0x%04x address ...\n", srv.addr);
ASSERT_OK(bt_mesh_key_export(prev_dev_key, &bt_mesh.dev_key));
reprovision_remote_address_client(&srv, node);
if (self_reprov) {
uint8_t dev_key[16];
ASSERT_EQUAL(current_dev_addr, bt_mesh_primary_addr());
/* Let Configuration Client activate the new Device Key
* and verify that it has been changed.
*/
ASSERT_OK(bt_mesh_key_export(dev_key, &bt_mesh.dev_key));
ASSERT_TRUE(memcmp(prev_dev_key, dev_key, sizeof(dev_key)));
}
}
PASS();
}
/** @brief Verify that the Remote Provisioning client and server is able to be reprovision
* by another device with a Remote Provisioning client and server.
*/
static void test_device_pb_remote_server_same_dev(void)
{
k_sem_init(&prov_sem, 0, 1);
k_sem_init(&reprov_sem, 0, 1);
bt_mesh_device_setup(&prov, &rpr_cli_srv_comp);
ASSERT_OK(bt_mesh_prov_enable(BT_MESH_PROV_ADV));
LOG_INF("Waiting for being provisioned...");
ASSERT_OK(k_sem_take(&prov_sem, K_SECONDS(20)));
LOG_INF("Enabling PB-Remote server");
ASSERT_OK(bt_mesh_prov_enable(BT_MESH_PROV_REMOTE));
/* Swap callback to catch when device reprovisioned. */
prov.node_added = prov_node_added_rpr;
const uint16_t initial_addr = bt_mesh_primary_addr();
LOG_INF("Devkey refresh, waiting for being reprov ...\n");
reprovision_remote_devkey_server(initial_addr);
LOG_INF("Composition data refresh, waiting for being reprov ...\n");
reprovision_remote_comp_data_server(initial_addr);
LOG_INF("Address refresh, waiting for being reprov ...\n");
reprovision_remote_address_server(initial_addr);
PASS();
}
static void comp_data_get(uint16_t server_addr, uint8_t page, struct net_buf_simple *comp) static void comp_data_get(uint16_t server_addr, uint8_t page, struct net_buf_simple *comp)
{ {
uint8_t page_rsp; uint8_t page_rsp;
@ -1573,6 +1787,10 @@ static const struct bst_test_instance test_connect[] = {
"Device: pb-remote reprovisioning, NPPI robustness"), "Device: pb-remote reprovisioning, NPPI robustness"),
TEST_CASE(device, pb_remote_server_unproved_unresponsive, TEST_CASE(device, pb_remote_server_unproved_unresponsive,
"Device: used for remote provisioning, starts unprovisioned, stops responding"), "Device: used for remote provisioning, starts unprovisioned, stops responding"),
TEST_CASE(device, pb_remote_client_server_same_dev,
"Device: used for remote provisioning, with both client and server"),
TEST_CASE(device, pb_remote_server_same_dev,
"Device: used for remote reprovisioning, with both client and server"),
#endif #endif
TEST_CASE(provisioner, pb_adv_no_oob, TEST_CASE(provisioner, pb_adv_no_oob,

View file

@ -0,0 +1,32 @@
#!/usr/bin/env bash
# Copyright 2023 Nordic Semiconductor
# SPDX-License-Identifier: Apache-2.0
source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh
# Test a node re-provisioning through Remote Provisioning models. Procedure:
# 1. Device (prov_device_pb_remote_client_server_same_dev) provisions it self
# and start scanning for an upprovisioned device, and provisions the the
# second device (prov_device_pb_remote_server_same_dev) with local RPR server.
# 2. The first device (prov_device_pb_remote_client_server_same_dev) execute
# device key refresh procedure the second device (prov_device_pb_remote_server_same_dev).
# 3. The first device (prov_device_pb_remote_client_server_same_dev) execute
# composition refresh procedure the second device (prov_device_pb_remote_server_same_dev).
# 4. The first device (prov_device_pb_remote_client_server_same_dev) execute
# address refresh procedure the second device (prov_device_pb_remote_server_same_dev).
# 5. The first device (prov_device_pb_remote_client_server_same_dev) execute
# device key refresh procedure on it self with local RPR client and server.
# 6. The first device (prov_device_pb_remote_client_server_same_dev) execute
# composition refresh procedure on it self with local RPR client and server.
# 7. The first device (prov_device_pb_remote_client_server_same_dev) execute
# address refresh procedure on it self with local RPR client and server.
conf=prj_mesh1d1_conf
RunTest mesh_prov_pb_remote_client_server_same_dev \
prov_device_pb_remote_client_server_same_dev \
prov_device_pb_remote_server_same_dev
conf=prj_mesh1d1_conf
overlay=overlay_psa_conf
RunTest mesh_prov_pb_remote_client_server_same_dev \
prov_device_pb_remote_client_server_same_dev \
prov_device_pb_remote_server_same_dev