| 
 | 1 | +/*  | 
 | 2 | + * Copyright (c) 2021 Nordic Semiconductor  | 
 | 3 | + *  | 
 | 4 | + * SPDX-License-Identifier: Apache-2.0  | 
 | 5 | + */  | 
 | 6 | +#include "mesh_test.h"  | 
 | 7 | +#include "settings_test_backend.h"  | 
 | 8 | +#include "mesh/mesh.h"  | 
 | 9 | +#include "mesh/net.h"  | 
 | 10 | + | 
 | 11 | +#define LOG_MODULE_NAME test_rpc  | 
 | 12 | + | 
 | 13 | +#include <logging/log.h>  | 
 | 14 | +LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_INF);  | 
 | 15 | + | 
 | 16 | +#define WAIT_TIME 60 /*seconds*/  | 
 | 17 | +#define TEST_DATA_WAITING_TIME 5 /* seconds */  | 
 | 18 | +#define TEST_DATA_SIZE 20  | 
 | 19 | + | 
 | 20 | +static const struct bt_mesh_test_cfg tx_cfg = {  | 
 | 21 | +	.addr = 0x0001,  | 
 | 22 | +	.dev_key = { 0x01 },  | 
 | 23 | +};  | 
 | 24 | +static const struct bt_mesh_test_cfg rx_cfg = {  | 
 | 25 | +	.addr = 0x0002,  | 
 | 26 | +	.dev_key = { 0x02 },  | 
 | 27 | +};  | 
 | 28 | + | 
 | 29 | +static uint8_t test_data[TEST_DATA_SIZE];  | 
 | 30 | +static uint8_t rx_cnt;  | 
 | 31 | +static bool is_tx_succeeded;  | 
 | 32 | + | 
 | 33 | +static void test_tx_init(void)  | 
 | 34 | +{  | 
 | 35 | +	bt_mesh_test_cfg_set(&tx_cfg, WAIT_TIME);  | 
 | 36 | +}  | 
 | 37 | + | 
 | 38 | +static void test_rx_init(void)  | 
 | 39 | +{  | 
 | 40 | +	bt_mesh_test_cfg_set(&rx_cfg, WAIT_TIME);  | 
 | 41 | +}  | 
 | 42 | + | 
 | 43 | +static void tx_started(uint16_t dur, int err, void *data)  | 
 | 44 | +{  | 
 | 45 | +	if (err) {  | 
 | 46 | +		FAIL("Couldn't start sending (err: %d)", err);  | 
 | 47 | +	}  | 
 | 48 | + | 
 | 49 | +	LOG_INF("Sending started");  | 
 | 50 | +}  | 
 | 51 | + | 
 | 52 | +static void tx_ended(int err, void *data)  | 
 | 53 | +{  | 
 | 54 | +	struct k_sem *sem = data;  | 
 | 55 | + | 
 | 56 | +	if (err) {  | 
 | 57 | +		is_tx_succeeded = false;  | 
 | 58 | +		LOG_INF("Sending failed (%d)", err);  | 
 | 59 | +	} else {  | 
 | 60 | +		is_tx_succeeded = true;  | 
 | 61 | +		LOG_INF("Sending succeeded");  | 
 | 62 | +	}  | 
 | 63 | + | 
 | 64 | +	k_sem_give(sem);  | 
 | 65 | +}  | 
 | 66 | + | 
 | 67 | +static void rx_ended(uint8_t *data, size_t len)  | 
 | 68 | +{  | 
 | 69 | +	memset(test_data, rx_cnt++, sizeof(test_data));  | 
 | 70 | + | 
 | 71 | +	if (memcmp(test_data, data, len)) {  | 
 | 72 | +		FAIL("Unexpected rx data");  | 
 | 73 | +	}  | 
 | 74 | + | 
 | 75 | +	LOG_INF("Receiving succeeded");  | 
 | 76 | +}  | 
 | 77 | + | 
 | 78 | +static void test_tx_immediate_replay_attack(void)  | 
 | 79 | +{  | 
 | 80 | +	settings_test_backend_clear();  | 
 | 81 | +	bt_mesh_test_setup();  | 
 | 82 | + | 
 | 83 | +	static const struct bt_mesh_send_cb send_cb = {  | 
 | 84 | +		.start = tx_started,  | 
 | 85 | +		.end = tx_ended,  | 
 | 86 | +	};  | 
 | 87 | +	struct k_sem sem;  | 
 | 88 | + | 
 | 89 | +	k_sem_init(&sem, 0, 1);  | 
 | 90 | + | 
 | 91 | +	uint32_t seq = bt_mesh.seq;  | 
 | 92 | + | 
 | 93 | +	for (int i = 0; i < 3; i++) {  | 
 | 94 | +		is_tx_succeeded = false;  | 
 | 95 | + | 
 | 96 | +		memset(test_data, i, sizeof(test_data));  | 
 | 97 | +		ASSERT_OK(bt_mesh_test_send_ra(rx_cfg.addr, test_data,  | 
 | 98 | +			sizeof(test_data), &send_cb, &sem));  | 
 | 99 | + | 
 | 100 | +		if (k_sem_take(&sem, K_SECONDS(TEST_DATA_WAITING_TIME))) {  | 
 | 101 | +			LOG_ERR("Send timed out");  | 
 | 102 | +		}  | 
 | 103 | + | 
 | 104 | +		ASSERT_TRUE(is_tx_succeeded);  | 
 | 105 | +	}  | 
 | 106 | + | 
 | 107 | +	bt_mesh.seq = seq;  | 
 | 108 | + | 
 | 109 | +	for (int i = 0; i < 3; i++) {  | 
 | 110 | +		is_tx_succeeded = true;  | 
 | 111 | + | 
 | 112 | +		memset(test_data, i, sizeof(test_data));  | 
 | 113 | +		ASSERT_OK(bt_mesh_test_send_ra(rx_cfg.addr, test_data,  | 
 | 114 | +			sizeof(test_data), &send_cb, &sem));  | 
 | 115 | + | 
 | 116 | +		if (k_sem_take(&sem, K_SECONDS(TEST_DATA_WAITING_TIME))) {  | 
 | 117 | +			LOG_ERR("Send timed out");  | 
 | 118 | +		}  | 
 | 119 | + | 
 | 120 | +		ASSERT_TRUE(!is_tx_succeeded);  | 
 | 121 | +	}  | 
 | 122 | + | 
 | 123 | +	PASS();  | 
 | 124 | +}  | 
 | 125 | + | 
 | 126 | +static void test_rx_immediate_replay_attack(void)  | 
 | 127 | +{  | 
 | 128 | +	settings_test_backend_clear();  | 
 | 129 | +	bt_mesh_test_setup();  | 
 | 130 | +	bt_mesh_test_ra_cb_setup(rx_ended);  | 
 | 131 | + | 
 | 132 | +	k_sleep(K_SECONDS(6 * TEST_DATA_WAITING_TIME));  | 
 | 133 | + | 
 | 134 | +	ASSERT_TRUE(rx_cnt == 3, "Device didn't receive expected data");  | 
 | 135 | + | 
 | 136 | +	PASS();  | 
 | 137 | +}  | 
 | 138 | + | 
 | 139 | +static void test_tx_power_replay_attack(void)  | 
 | 140 | +{  | 
 | 141 | +	settings_test_backend_clear();  | 
 | 142 | +	bt_mesh_test_setup();  | 
 | 143 | + | 
 | 144 | +	static const struct bt_mesh_send_cb send_cb = {  | 
 | 145 | +		.start = tx_started,  | 
 | 146 | +		.end = tx_ended,  | 
 | 147 | +	};  | 
 | 148 | +	struct k_sem sem;  | 
 | 149 | + | 
 | 150 | +	k_sem_init(&sem, 0, 1);  | 
 | 151 | + | 
 | 152 | +	for (int i = 0; i < 3; i++) {  | 
 | 153 | +		is_tx_succeeded = true;  | 
 | 154 | + | 
 | 155 | +		memset(test_data, i, sizeof(test_data));  | 
 | 156 | +		ASSERT_OK(bt_mesh_test_send_ra(rx_cfg.addr, test_data,  | 
 | 157 | +			sizeof(test_data), &send_cb, &sem));  | 
 | 158 | + | 
 | 159 | +		if (k_sem_take(&sem, K_SECONDS(TEST_DATA_WAITING_TIME))) {  | 
 | 160 | +			LOG_ERR("Send timed out");  | 
 | 161 | +		}  | 
 | 162 | + | 
 | 163 | +		ASSERT_TRUE(!is_tx_succeeded);  | 
 | 164 | +	}  | 
 | 165 | + | 
 | 166 | +	for (int i = 0; i < 3; i++) {  | 
 | 167 | +		is_tx_succeeded = false;  | 
 | 168 | + | 
 | 169 | +		memset(test_data, i, sizeof(test_data));  | 
 | 170 | +		ASSERT_OK(bt_mesh_test_send_ra(rx_cfg.addr, test_data,  | 
 | 171 | +			sizeof(test_data), &send_cb, &sem));  | 
 | 172 | + | 
 | 173 | +		if (k_sem_take(&sem, K_SECONDS(TEST_DATA_WAITING_TIME))) {  | 
 | 174 | +			LOG_ERR("Send timed out");  | 
 | 175 | +		}  | 
 | 176 | + | 
 | 177 | +		ASSERT_TRUE(is_tx_succeeded);  | 
 | 178 | +	}  | 
 | 179 | + | 
 | 180 | +	PASS();  | 
 | 181 | +}  | 
 | 182 | + | 
 | 183 | +static void test_rx_power_replay_attack(void)  | 
 | 184 | +{  | 
 | 185 | +	bt_mesh_test_setup();  | 
 | 186 | +	bt_mesh_test_ra_cb_setup(rx_ended);  | 
 | 187 | + | 
 | 188 | +	k_sleep(K_SECONDS(6 * TEST_DATA_WAITING_TIME));  | 
 | 189 | + | 
 | 190 | +	ASSERT_TRUE(rx_cnt == 3, "Device didn't receive expected data");  | 
 | 191 | + | 
 | 192 | +	PASS();  | 
 | 193 | +}  | 
 | 194 | + | 
 | 195 | +#define TEST_CASE(role, name, description)                     \  | 
 | 196 | +	{                                                      \  | 
 | 197 | +		.test_id = "rpc_" #role "_" #name,             \  | 
 | 198 | +		.test_descr = description,                     \  | 
 | 199 | +		.test_post_init_f = test_##role##_init,        \  | 
 | 200 | +		.test_tick_f = bt_mesh_test_timeout,           \  | 
 | 201 | +		.test_main_f = test_##role##_##name,           \  | 
 | 202 | +	}  | 
 | 203 | + | 
 | 204 | +static const struct bst_test_instance test_rpc[] = {  | 
 | 205 | +	TEST_CASE(tx, immediate_replay_attack, "RPC: perform replay attack immediately"),  | 
 | 206 | +	TEST_CASE(tx, power_replay_attack,     "RPC: perform replay attack after power cycle"),  | 
 | 207 | + | 
 | 208 | +	TEST_CASE(rx, immediate_replay_attack, "RPC: device under immediate attack"),  | 
 | 209 | +	TEST_CASE(rx, power_replay_attack,     "RPC: device under power cycle reply attack"),  | 
 | 210 | +	BSTEST_END_MARKER  | 
 | 211 | +};  | 
 | 212 | + | 
 | 213 | +struct bst_test_list *test_rpc_install(struct bst_test_list *tests)  | 
 | 214 | +{  | 
 | 215 | +	tests = bst_add_tests(tests, test_rpc);  | 
 | 216 | +	return tests;  | 
 | 217 | +}  | 
0 commit comments