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