1 /*
2  * Copyright (c) 2024 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/ztest.h>
8 #include <stdbool.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <zephyr/kernel.h>
12 #include <zephyr/settings/settings.h>
13 
14 #include <zephyr/fff.h>
15 
16 #include <zephyr/net/wifi_credentials.h>
17 
18 #include "wifi_credentials_internal.h"
19 
20 #define MAX_KEY_LEN 16
21 
22 #define SSID1     "test1"
23 #define PSK1      "super secret"
24 #define SECURITY1 WIFI_SECURITY_TYPE_PSK
25 #define BSSID1    "abcdef"
26 #define FLAGS1    WIFI_CREDENTIALS_FLAG_BSSID
27 
28 #define SSID2     "test2"
29 #define PSK2      NULL
30 #define SECURITY2 WIFI_SECURITY_TYPE_NONE
31 #define BSSID2    NULL
32 #define FLAGS2    0
33 
34 DEFINE_FFF_GLOBALS;
35 
36 K_MUTEX_DEFINE(wifi_credentials_mutex);
37 
38 FAKE_VALUE_FUNC(int, settings_subsys_init);
39 FAKE_VALUE_FUNC(int, settings_save_one, const char *, const void *, size_t);
40 FAKE_VALUE_FUNC(int, settings_delete, const char *);
41 FAKE_VALUE_FUNC(int, settings_load_subtree_direct, const char *, settings_load_direct_cb, void *);
42 FAKE_VOID_FUNC(wifi_credentials_cache_ssid, size_t, const struct wifi_credentials_header *);
43 
44 static uint8_t fake_settings_buf[CONFIG_WIFI_CREDENTIALS_MAX_ENTRIES][ENTRY_MAX_LEN];
45 static char fake_settings_buf_keys[CONFIG_WIFI_CREDENTIALS_MAX_ENTRIES][MAX_KEY_LEN];
46 static size_t fake_settings_buf_lens[CONFIG_WIFI_CREDENTIALS_MAX_ENTRIES];
47 
48 typedef int (*settings_set_cb)(const char *key, size_t len, settings_read_cb read_cb, void *cb_arg);
49 
50 static const struct wifi_credentials_personal example1 = {
51 	.header = {
52 		.ssid = SSID1,
53 		.ssid_len = strlen(SSID1),
54 		.type = SECURITY1,
55 		.bssid = BSSID1,
56 		.flags = FLAGS1,
57 	},
58 	.password = PSK1,
59 	.password_len = strlen(PSK1),
60 };
61 
62 static const struct wifi_credentials_personal example2 = {
63 	.header = {
64 		.ssid = SSID2,
65 		.ssid_len = strlen(SSID2),
66 		.type = SECURITY2,
67 		.flags = FLAGS2,
68 	},
69 };
70 
71 /**
72  * @brief load content of given settings index to given buffer
73  *
74  * @param cb_arg size_t *idx
75  * @param data destination
76  * @param len length
77  * @return ssize_t MIN(length, length_available)
78  */
custom_settings_read_cb(void * cb_arg,void * data,size_t len)79 ssize_t custom_settings_read_cb(void *cb_arg, void *data, size_t len)
80 {
81 	size_t *idx = cb_arg;
82 
83 	zassert_true(len <= ENTRY_MAX_LEN, "Length exceeds ENTRY_MAX_LEN");
84 	memcpy(data, fake_settings_buf[*idx], len);
85 	return len;
86 }
87 
custom_settings_save_one(const char * name,const void * value,size_t val_len)88 static int custom_settings_save_one(const char *name, const void *value, size_t val_len)
89 {
90 	zassert_true(strlen(name) < MAX_KEY_LEN, "Name length exceeds MAX_KEY_LEN");
91 	zassert_true(val_len <= ENTRY_MAX_LEN, "Value length exceeds ENTRY_MAX_LEN");
92 
93 	for (size_t i = 0; i < CONFIG_WIFI_CREDENTIALS_MAX_ENTRIES; ++i) {
94 		if (strlen(fake_settings_buf_keys[i]) == 0 ||
95 		    strcmp(name, fake_settings_buf_keys[i]) == 0) {
96 			strcpy(fake_settings_buf_keys[i], name);
97 			memcpy(fake_settings_buf[i], value, val_len);
98 			fake_settings_buf_lens[i] = val_len;
99 			return 0;
100 		}
101 	}
102 	return -ENOBUFS;
103 }
104 
custom_settings_delete(const char * name)105 static int custom_settings_delete(const char *name)
106 {
107 	zassert_true(strlen(name) < MAX_KEY_LEN, "Name length exceeds MAX_KEY_LEN");
108 	for (size_t i = 0; i < CONFIG_WIFI_CREDENTIALS_MAX_ENTRIES; ++i) {
109 		if (strcmp(name, fake_settings_buf_keys[i]) == 0) {
110 			memset(fake_settings_buf_keys[i], 0, MAX_KEY_LEN);
111 			memset(fake_settings_buf[i], 0, ENTRY_MAX_LEN);
112 			fake_settings_buf_lens[i] = 0;
113 			return 0;
114 		}
115 	}
116 	return -ENOENT;
117 }
118 
custom_settings_load_subtree_direct(const char * subtree,settings_load_direct_cb cb,void * param)119 static int custom_settings_load_subtree_direct(const char *subtree, settings_load_direct_cb cb,
120 					       void *param)
121 {
122 	size_t subtree_len = strlen(subtree);
123 
124 	zassert_true(subtree_len < MAX_KEY_LEN, "Subtree length exceeds MAX_KEY_LEN");
125 
126 	for (size_t i = 0; i < CONFIG_WIFI_CREDENTIALS_MAX_ENTRIES; ++i) {
127 		if (strncmp(subtree, fake_settings_buf_keys[i], subtree_len) == 0) {
128 			const char *key = fake_settings_buf_keys[i] + subtree_len + 1;
129 
130 			cb(key, fake_settings_buf_lens[i], custom_settings_read_cb, &i, param);
131 		}
132 	}
133 	return 0;
134 }
135 
custom_wifi_credentials_cache_ssid(size_t idx,const struct wifi_credentials_header * buf)136 static void custom_wifi_credentials_cache_ssid(size_t idx,
137 					       const struct wifi_credentials_header *buf)
138 {
139 	char name[16] = "";
140 
141 	snprintk(name, ARRAY_SIZE(name), "wifi_cred/%d", idx);
142 	for (size_t i = 0; i < CONFIG_WIFI_CREDENTIALS_MAX_ENTRIES; ++i) {
143 		if (strcmp(name, fake_settings_buf_keys[i]) == 0) {
144 			zassert_equal(memcmp(buf, &fake_settings_buf[i],
145 					     sizeof(struct wifi_credentials_header)),
146 				      0, "Buffer mismatch");
147 			return;
148 		}
149 	}
150 	zassert_true(false, "SSID not found in cache");
151 }
152 
wifi_credentials_backend_settings_setup(void * _unused)153 static void wifi_credentials_backend_settings_setup(void *_unused)
154 {
155 	RESET_FAKE(settings_save_one);
156 	RESET_FAKE(settings_delete);
157 	RESET_FAKE(settings_load_subtree_direct);
158 	RESET_FAKE(wifi_credentials_cache_ssid);
159 	settings_save_one_fake.custom_fake = custom_settings_save_one;
160 	settings_delete_fake.custom_fake = custom_settings_delete;
161 	settings_load_subtree_direct_fake.custom_fake = custom_settings_load_subtree_direct;
162 	wifi_credentials_cache_ssid_fake.custom_fake = custom_wifi_credentials_cache_ssid;
163 	memset(fake_settings_buf_lens, 0, ARRAY_SIZE(fake_settings_buf_lens) * sizeof(size_t));
164 	memset(fake_settings_buf_keys, 0, CONFIG_WIFI_CREDENTIALS_MAX_ENTRIES * MAX_KEY_LEN);
165 	memset(fake_settings_buf, 0, CONFIG_WIFI_CREDENTIALS_MAX_ENTRIES * ENTRY_MAX_LEN);
166 }
167 
ZTEST(wifi_credentials_backend_settings,test_init)168 ZTEST(wifi_credentials_backend_settings, test_init)
169 {
170 	int ret;
171 
172 	ret = wifi_credentials_store_entry(0, &example1, sizeof(struct wifi_credentials_personal));
173 	zassert_equal(ret, 0, "Failed to store entry 0");
174 	ret = wifi_credentials_store_entry(1, &example2, sizeof(struct wifi_credentials_personal));
175 	zassert_equal(ret, 0, "Failed to store entry 1");
176 
177 	ret = wifi_credentials_backend_init();
178 
179 	zassert_equal(ret, 0, "Backend init failed");
180 	zassert_equal(settings_subsys_init_fake.call_count, 1,
181 		      "settings_subsys_init call count mismatch");
182 	zassert_equal(wifi_credentials_cache_ssid_fake.call_count, 2,
183 		      "wifi_credentials_cache_ssid call count mismatch");
184 	zassert_equal(wifi_credentials_cache_ssid_fake.arg0_history[0], 0,
185 		      "First cache SSID index mismatch");
186 	zassert_equal(wifi_credentials_cache_ssid_fake.arg0_history[1], 1,
187 		      "Second cache SSID index mismatch");
188 }
189 
ZTEST(wifi_credentials_backend_settings,test_add)190 ZTEST(wifi_credentials_backend_settings, test_add)
191 {
192 	int ret = wifi_credentials_store_entry(0, "abc", 3);
193 
194 	zassert_equal(ret, 0, "Failed to add entry");
195 	zassert_equal(settings_save_one_fake.call_count, 1,
196 		      "settings_save_one call count mismatch");
197 	zassert_equal(strcmp(fake_settings_buf_keys[0], "wifi_cred/0"), 0, "Key mismatch");
198 	zassert_equal(strcmp(fake_settings_buf[0], "abc"), 0, "Value mismatch");
199 	zassert_equal(fake_settings_buf_lens[0], 3, "Length mismatch");
200 }
201 
ZTEST(wifi_credentials_backend_settings,test_get)202 ZTEST(wifi_credentials_backend_settings, test_get)
203 {
204 	int ret;
205 
206 	ret = wifi_credentials_store_entry(0, &example1, sizeof(struct wifi_credentials_personal));
207 	zassert_equal(ret, 0, "Failed to store entry 0");
208 	ret = wifi_credentials_store_entry(1, &example2, sizeof(struct wifi_credentials_personal));
209 	zassert_equal(ret, 0, "Failed to store entry 1");
210 
211 	char buf[ENTRY_MAX_LEN] = {0};
212 
213 	ret = wifi_credentials_load_entry(0, buf, ARRAY_SIZE(buf));
214 	zassert_equal(ret, 0, "Failed to load entry 0");
215 	zassert_equal(memcmp(&example1, buf, ARRAY_SIZE(buf)), 0, "Entry 0 data mismatch");
216 	ret = wifi_credentials_load_entry(1, buf, ARRAY_SIZE(buf));
217 	zassert_equal(ret, 0, "Failed to load entry 1");
218 	zassert_equal(memcmp(&example2, buf, ARRAY_SIZE(buf)), 0, "Entry 1 data mismatch");
219 }
220 
ZTEST(wifi_credentials_backend_settings,test_delete)221 ZTEST(wifi_credentials_backend_settings, test_delete)
222 {
223 	int ret;
224 
225 	ret = wifi_credentials_store_entry(0, "abc", 3);
226 	zassert_equal(ret, 0, "Failed to store entry");
227 
228 	ret = wifi_credentials_delete_entry(0);
229 	zassert_equal(ret, 0, "Failed to delete entry");
230 	zassert_equal(settings_delete_fake.call_count, 1, "settings_delete call count mismatch");
231 }
232 
233 ZTEST_SUITE(wifi_credentials_backend_settings, NULL, NULL, wifi_credentials_backend_settings_setup,
234 	    NULL, NULL);
235