1 /*
2 * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <string.h>
8 #include <errno.h>
9
10 #include "mesh_common.h"
11 #include "settings_uid.h"
12 #include "settings.h"
13
14 #if CONFIG_BLE_MESH_SETTINGS
15
16 enum settings_type {
17 SETTINGS_CORE,
18 #if CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE
19 SETTINGS_UID,
20 #endif
21 };
22
23 struct settings_context {
24 char *nvs_name;
25 bt_mesh_nvs_handle_t handle;
26
27 int (*settings_init)(void);
28 int (*settings_load)(void);
29 int (*settings_commit)(void);
30 #if CONFIG_BLE_MESH_DEINIT
31 int (*settings_deinit)(void);
32 int (*settings_erase)(void);
33 #endif /* CONFIG_BLE_MESH_DEINIT */
34 };
35
36 static struct settings_context settings_ctx[] = {
37 [SETTINGS_CORE] = {
38 .nvs_name = "mesh_core",
39 .settings_init = settings_core_init,
40 .settings_load = settings_core_load,
41 .settings_commit = settings_core_commit,
42 #if CONFIG_BLE_MESH_DEINIT
43 .settings_deinit = settings_core_deinit,
44 .settings_erase = settings_core_erase,
45 #endif /* CONFIG_BLE_MESH_DEINIT */
46 },
47 #if CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE
48 [SETTINGS_UID] = {
49 .nvs_name = "mesh_user_id",
50 .settings_init = settings_uid_init,
51 .settings_load = settings_uid_load,
52 .settings_commit = NULL,
53 #if CONFIG_BLE_MESH_DEINIT
54 .settings_deinit = settings_uid_deinit,
55 .settings_erase = settings_uid_erase,
56 #endif /* CONFIG_BLE_MESH_DEINIT */
57 },
58 #endif /* CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE */
59 };
60
61 /* API used to initialize, load and commit BLE Mesh related settings */
62
bt_mesh_settings_nvs_open(const char * name,bt_mesh_nvs_handle_t * handle)63 int bt_mesh_settings_nvs_open(const char* name, bt_mesh_nvs_handle_t *handle)
64 {
65 #if CONFIG_BLE_MESH_SPECIFIC_PARTITION
66 return nvs_open_from_partition(CONFIG_BLE_MESH_PARTITION_NAME, name, NVS_READWRITE, handle);
67 #else
68 return nvs_open(name, NVS_READWRITE, handle);
69 #endif
70 }
71
bt_mesh_settings_nvs_close(bt_mesh_nvs_handle_t handle)72 void bt_mesh_settings_nvs_close(bt_mesh_nvs_handle_t handle)
73 {
74 nvs_close(handle);
75 }
76
bt_mesh_settings_init_foreach(void)77 void bt_mesh_settings_init_foreach(void)
78 {
79 int err = 0;
80 int i;
81
82 #if CONFIG_BLE_MESH_SPECIFIC_PARTITION
83 err = nvs_flash_init_partition(CONFIG_BLE_MESH_PARTITION_NAME);
84 if (err != ESP_OK) {
85 BT_ERR("Init mesh partition failed, name %s, err %d", CONFIG_BLE_MESH_PARTITION_NAME, err);
86 return;
87 }
88 #endif /* CONFIG_BLE_MESH_SPECIFIC_PARTITION */
89
90 for (i = 0; i < ARRAY_SIZE(settings_ctx); i++) {
91 struct settings_context *ctx = &settings_ctx[i];
92
93 /* Settings initialization is always needed. */
94 if (ctx->settings_init && ctx->settings_init()) {
95 BT_ERR("Init settings failed, name %s", ctx->nvs_name);
96 return;
97 }
98
99 #if CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE
100 /* If multiple nvs namespace functionality is enabled,
101 * no need to perform the following operations during
102 * initialization. And they will be performed when the
103 * application layer tries to open settings.
104 */
105 if (i != SETTINGS_UID) {
106 continue;
107 }
108 #endif /* CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE */
109
110 err = bt_mesh_settings_nvs_open(ctx->nvs_name, &ctx->handle);
111 if (err) {
112 BT_ERR("Open nvs failed, name %s, err %d", ctx->nvs_name, err);
113 return;
114 }
115
116 if (ctx->settings_load && ctx->settings_load()) {
117 BT_ERR("Load settings failed, name %s", ctx->nvs_name);
118 return;
119 }
120
121 /* If not using multiple nvs namespaces, we will follow the normal
122 * procedure, i.e. restoring all the mesh information.
123 * If using multiple nvs namespaces, we will only restore user_id.
124 */
125 if (ctx->settings_commit && ctx->settings_commit()) {
126 BT_ERR("Commit settings failed, name %s", ctx->nvs_name);
127 return;
128 }
129 }
130 }
131
132 #if CONFIG_BLE_MESH_DEINIT
bt_mesh_settings_deinit_foreach(bool erase)133 void bt_mesh_settings_deinit_foreach(bool erase)
134 {
135 int i;
136
137 for (i = 0; i < ARRAY_SIZE(settings_ctx); i++) {
138 struct settings_context *ctx = &settings_ctx[i];
139
140 if (ctx->settings_deinit && ctx->settings_deinit()) {
141 BT_ERR("Deinit settings failed, name %s", ctx->nvs_name);
142 continue;
143 }
144
145 if (erase && ctx->settings_erase && ctx->settings_erase()) {
146 BT_ERR("Erase settings failed, name %s", ctx->nvs_name);
147 continue;
148 }
149
150 bt_mesh_settings_nvs_close(ctx->handle);
151 }
152
153 #if CONFIG_BLE_MESH_SPECIFIC_PARTITION
154 nvs_flash_deinit_partition(CONFIG_BLE_MESH_PARTITION_NAME);
155 #endif
156 }
157 #endif /* CONFIG_BLE_MESH_DEINIT */
158
bt_mesh_settings_direct_open(bt_mesh_nvs_handle_t * handle)159 int bt_mesh_settings_direct_open(bt_mesh_nvs_handle_t *handle)
160 {
161 int err = 0;
162 int i;
163
164 #if CONFIG_BLE_MESH_SPECIFIC_PARTITION
165 err = nvs_flash_init_partition(CONFIG_BLE_MESH_PARTITION_NAME);
166 if (err != ESP_OK) {
167 BT_ERR("Init mesh partition failed, name %s, err %d", CONFIG_BLE_MESH_PARTITION_NAME, err);
168 return -EIO;
169 }
170 #endif /* CONFIG_BLE_MESH_SPECIFIC_PARTITION */
171
172 for (i = 0; i < ARRAY_SIZE(settings_ctx); i++) {
173 struct settings_context *ctx = &settings_ctx[i];
174
175 err = bt_mesh_settings_nvs_open(ctx->nvs_name, &ctx->handle);
176 if (err) {
177 BT_ERR("Open nvs failed, name %s, err %d", ctx->nvs_name, err);
178 return -EIO;
179 }
180
181 if (i == SETTINGS_CORE && handle) {
182 *handle = ctx->handle;
183 }
184 }
185
186 return 0;
187 }
188
bt_mesh_settings_direct_close(void)189 void bt_mesh_settings_direct_close(void)
190 {
191 int i;
192
193 for (i = 0; i < ARRAY_SIZE(settings_ctx); i++) {
194 bt_mesh_settings_nvs_close(settings_ctx[i].handle);
195 }
196
197 #if CONFIG_BLE_MESH_SPECIFIC_PARTITION
198 nvs_flash_deinit_partition(CONFIG_BLE_MESH_PARTITION_NAME);
199 #endif
200 }
201
202 /* API used to get BLE Mesh related nvs handle */
203
settings_get_nvs_handle(enum settings_type type)204 static inline bt_mesh_nvs_handle_t settings_get_nvs_handle(enum settings_type type)
205 {
206 #if CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE
207 if (type == SETTINGS_CORE) {
208 extern bt_mesh_nvs_handle_t get_core_settings_handle(void);
209 return get_core_settings_handle();
210 }
211 #endif
212 return settings_ctx[type].handle;
213 }
214
215 /* API used to store/erase BLE Mesh related settings */
216
settings_save(bt_mesh_nvs_handle_t handle,const char * key,const uint8_t * val,size_t len)217 static int settings_save(bt_mesh_nvs_handle_t handle, const char *key, const uint8_t *val, size_t len)
218 {
219 int err = 0;
220
221 if (key == NULL) {
222 BT_ERR("%s, Invalid parameter", __func__);
223 return -EINVAL;
224 }
225
226 BT_DBG("nvs %s, key %s", val ? "set" : "erase", key);
227
228 if (val) {
229 err = nvs_set_blob(handle, key, val, len);
230 } else {
231 err = nvs_erase_key(handle, key);
232 if (err == ESP_ERR_NVS_NOT_FOUND) {
233 BT_DBG("%s not exists", key);
234 return 0;
235 }
236 }
237 if (err != ESP_OK) {
238 BT_ERR("Failed to %s %s data (err %d)",
239 val ? "set" : "erase", key, err);
240 return -EIO;
241 }
242
243 err = nvs_commit(handle);
244 if (err != ESP_OK) {
245 BT_ERR("Failed to commit settings (err %d)", err);
246 return -EIO;
247 }
248
249 return 0;
250 }
251
bt_mesh_save_settings(bt_mesh_nvs_handle_t handle,const char * key,const uint8_t * val,size_t len)252 int bt_mesh_save_settings(bt_mesh_nvs_handle_t handle, const char *key,
253 const uint8_t *val, size_t len)
254 {
255 int err = 0;
256 bt_mesh_settings_lock();
257 err = settings_save(handle, key, val, len);
258 bt_mesh_settings_unlock();
259 return err;
260 }
261
bt_mesh_save_core_settings(const char * key,const uint8_t * val,size_t len)262 int bt_mesh_save_core_settings(const char *key, const uint8_t *val, size_t len)
263 {
264 bt_mesh_nvs_handle_t handle = settings_get_nvs_handle(SETTINGS_CORE);
265 return bt_mesh_save_settings(handle, key, val, len);
266 }
267
268 #if CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE
bt_mesh_save_uid_settings(const char * key,const uint8_t * val,size_t len)269 int bt_mesh_save_uid_settings(const char *key, const uint8_t *val, size_t len)
270 {
271 bt_mesh_nvs_handle_t handle = settings_get_nvs_handle(SETTINGS_UID);
272 return bt_mesh_save_settings(handle, key, val, len);
273 }
274 #endif
275
bt_mesh_erase_settings(bt_mesh_nvs_handle_t handle,const char * key)276 int bt_mesh_erase_settings(bt_mesh_nvs_handle_t handle, const char *key)
277 {
278 return bt_mesh_save_settings(handle, key, NULL, 0);
279 }
280
bt_mesh_erase_core_settings(const char * key)281 int bt_mesh_erase_core_settings(const char *key)
282 {
283 return bt_mesh_save_core_settings(key, NULL, 0);
284 }
285
286 #if CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE
bt_mesh_erase_uid_settings(const char * name)287 int bt_mesh_erase_uid_settings(const char *name)
288 {
289 return bt_mesh_save_uid_settings(name, NULL, 0);
290 }
291 #endif
292
293 /* API used to load BLE Mesh related settings */
294
settings_load(bt_mesh_nvs_handle_t handle,const char * key,uint8_t * buf,size_t buf_len,bool * exist)295 static int settings_load(bt_mesh_nvs_handle_t handle, const char *key,
296 uint8_t *buf, size_t buf_len, bool *exist)
297 {
298 int err = 0;
299
300 if (key == NULL || buf == NULL || exist == NULL) {
301 BT_ERR("%s, Invalid parameter", __func__);
302 return -EINVAL;
303 }
304
305 err = nvs_get_blob(handle, key, buf, &buf_len);
306 if (err != ESP_OK) {
307 if (err == ESP_ERR_NVS_NOT_FOUND) {
308 BT_DBG("Settings %s not found", key);
309 *exist = false;
310 return 0;
311 }
312
313 BT_ERR("Failed to get %s data (err %d)", key, err);
314 return -EIO;
315 }
316
317 *exist = true;
318 return 0;
319 }
320
bt_mesh_load_settings(bt_mesh_nvs_handle_t handle,const char * key,uint8_t * buf,size_t buf_len,bool * exist)321 int bt_mesh_load_settings(bt_mesh_nvs_handle_t handle, const char *key,
322 uint8_t *buf, size_t buf_len, bool *exist)
323 {
324 int err = 0;
325 bt_mesh_settings_lock();
326 err = settings_load(handle, key, buf, buf_len, exist);
327 bt_mesh_settings_unlock();
328 return err;
329 }
330
bt_mesh_load_core_settings(const char * key,uint8_t * buf,size_t buf_len,bool * exist)331 int bt_mesh_load_core_settings(const char *key, uint8_t *buf, size_t buf_len, bool *exist)
332 {
333 bt_mesh_nvs_handle_t handle = settings_get_nvs_handle(SETTINGS_CORE);
334 return bt_mesh_load_settings(handle, key, buf, buf_len, exist);
335 }
336
337 #if CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE
bt_mesh_load_uid_settings(const char * key,uint8_t * buf,size_t buf_len,bool * exist)338 int bt_mesh_load_uid_settings(const char *key, uint8_t *buf, size_t buf_len, bool *exist)
339 {
340 bt_mesh_nvs_handle_t handle = settings_get_nvs_handle(SETTINGS_UID);
341 return bt_mesh_load_settings(handle, key, buf, buf_len, exist);
342 }
343 #endif
344
345 /* API used to get length of BLE Mesh related settings */
346
settings_get_length(bt_mesh_nvs_handle_t handle,const char * key)347 static size_t settings_get_length(bt_mesh_nvs_handle_t handle, const char *key)
348 {
349 size_t len = 0U;
350 int err = 0;
351
352 if (key == NULL) {
353 BT_ERR("%s, Invalid parameter", __func__);
354 return 0;
355 }
356
357 err = nvs_get_blob(handle, key, NULL, &len);
358 if (err != ESP_OK) {
359 if (err != ESP_ERR_NVS_NOT_FOUND) {
360 BT_ERR("Failed to get %s length (err %d)", key, err);
361 }
362 return 0;
363 }
364
365 return len;
366 }
367
368 /* API used to get BLE Mesh related items. Here items mean model key, NetKey/AppKey
369 * Index, etc. which are going to be used as the prefix of the nvs keys of the BLE
370 * Mesh settings.
371 */
372
settings_get_item(bt_mesh_nvs_handle_t handle,const char * key)373 static struct net_buf_simple *settings_get_item(bt_mesh_nvs_handle_t handle, const char *key)
374 {
375 struct net_buf_simple *buf = NULL;
376 size_t length = 0U;
377 bool exist = false;
378 int err = 0;
379
380 length = settings_get_length(handle, key);
381 if (!length) {
382 BT_DBG("Empty %s", key);
383 return NULL;
384 }
385
386 buf = bt_mesh_alloc_buf(length);
387 if (!buf) {
388 BT_ERR("%s, Out of memory", __func__);
389 /* TODO: in this case, erase all related settings? */
390 return NULL;
391 }
392
393 err = settings_load(handle, key, buf->data, length, &exist);
394 if (err) {
395 BT_ERR("Failed to load %s", key);
396 /* TODO: in this case, erase all related settings? */
397 bt_mesh_free_buf(buf);
398 return NULL;
399 }
400
401 if (exist == false) {
402 bt_mesh_free_buf(buf);
403 return NULL;
404 }
405
406 buf->len = length;
407 return buf;
408 }
409
bt_mesh_get_settings_item(bt_mesh_nvs_handle_t handle,const char * key)410 struct net_buf_simple *bt_mesh_get_settings_item(bt_mesh_nvs_handle_t handle, const char *key)
411 {
412 struct net_buf_simple *buf = NULL;
413 bt_mesh_settings_lock();
414 buf = settings_get_item(handle, key);
415 bt_mesh_settings_unlock();
416 return buf;
417 }
418
bt_mesh_get_core_settings_item(const char * key)419 struct net_buf_simple *bt_mesh_get_core_settings_item(const char *key)
420 {
421 bt_mesh_nvs_handle_t handle = settings_get_nvs_handle(SETTINGS_CORE);
422 return bt_mesh_get_settings_item(handle, key);
423 }
424
425 #if CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE
bt_mesh_get_uid_settings_item(const char * key)426 struct net_buf_simple *bt_mesh_get_uid_settings_item(const char *key)
427 {
428 bt_mesh_nvs_handle_t handle = settings_get_nvs_handle(SETTINGS_UID);
429 return bt_mesh_get_settings_item(handle, key);
430 }
431 #endif
432
433 /* API used to check if the settings item exists */
434
is_settings_item_exist(struct net_buf_simple * buf,const uint16_t val)435 static bool is_settings_item_exist(struct net_buf_simple *buf, const uint16_t val)
436 {
437 struct net_buf_simple_state state = {0};
438 size_t length = 0U;
439 int i;
440
441 if (!buf) {
442 return false;
443 }
444
445 net_buf_simple_save(buf, &state);
446
447 length = buf->len;
448 for (i = 0; i < length / SETTINGS_ITEM_SIZE; i++) {
449 uint16_t item = net_buf_simple_pull_le16(buf);
450 if (item == val) {
451 net_buf_simple_restore(buf, &state);
452 return true;
453 }
454 }
455
456 net_buf_simple_restore(buf, &state);
457 return false;
458 }
459
460 /* API used to add the settings item */
461
settings_add_item(bt_mesh_nvs_handle_t handle,const char * key,const uint16_t val)462 static int settings_add_item(bt_mesh_nvs_handle_t handle, const char *key, const uint16_t val)
463 {
464 struct net_buf_simple *store = NULL;
465 struct net_buf_simple *buf = NULL;
466 size_t length = 0U;
467 int err = 0;
468
469 buf = settings_get_item(handle, key);
470
471 /* Check if val already exists */
472 if (is_settings_item_exist(buf, val) == true) {
473 BT_DBG("0x%04x already exists", val);
474 bt_mesh_free_buf(buf);
475 return 0;
476 }
477
478 length = (buf ? buf->len : 0) + sizeof(val);
479
480 store = bt_mesh_alloc_buf(length);
481 if (!store) {
482 BT_ERR("%s, Out of memory", __func__);
483 bt_mesh_free_buf(buf);
484 return -ENOMEM;
485 }
486
487 if (buf) {
488 net_buf_simple_add_mem(store, buf->data, buf->len);
489 }
490 net_buf_simple_add_mem(store, &val, sizeof(val));
491
492 err = settings_save(handle, key, store->data, store->len);
493
494 bt_mesh_free_buf(store);
495 bt_mesh_free_buf(buf);
496 return err;
497 }
498
bt_mesh_add_settings_item(bt_mesh_nvs_handle_t handle,const char * key,const uint16_t val)499 int bt_mesh_add_settings_item(bt_mesh_nvs_handle_t handle, const char *key, const uint16_t val)
500 {
501 int err = 0;
502 bt_mesh_settings_lock();
503 err = settings_add_item(handle, key, val);
504 bt_mesh_settings_unlock();
505 return err;
506 }
507
bt_mesh_add_core_settings_item(const char * key,const uint16_t val)508 int bt_mesh_add_core_settings_item(const char *key, const uint16_t val)
509 {
510 bt_mesh_nvs_handle_t handle = settings_get_nvs_handle(SETTINGS_CORE);
511 return bt_mesh_add_settings_item(handle, key, val);
512 }
513
514 #if CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE
bt_mesh_add_uid_settings_item(const char * key,const uint16_t val)515 int bt_mesh_add_uid_settings_item(const char *key, const uint16_t val)
516 {
517 bt_mesh_nvs_handle_t handle = settings_get_nvs_handle(SETTINGS_UID);
518 return bt_mesh_add_settings_item(handle, key, val);
519 }
520 #endif
521
522 /* API used to remove the settings item */
523
settings_remove_item(bt_mesh_nvs_handle_t handle,const char * key,const uint16_t val)524 static int settings_remove_item(bt_mesh_nvs_handle_t handle, const char *key, const uint16_t val)
525 {
526 struct net_buf_simple *store = NULL;
527 struct net_buf_simple *buf = NULL;
528 size_t length = 0U;
529 size_t buf_len = 0U;
530 int err = 0;
531 int i;
532
533 buf = settings_get_item(handle, key);
534
535 /* Check if val does exist */
536 if (is_settings_item_exist(buf, val) == false) {
537 BT_DBG("0x%04x not exists", val);
538 bt_mesh_free_buf(buf);
539 return 0;
540 }
541
542 length = buf->len - sizeof(val);
543 if (!length) {
544 settings_save(handle, key, NULL, 0);
545 bt_mesh_free_buf(buf);
546 return 0;
547 }
548
549 store = bt_mesh_alloc_buf(length);
550 if (!store) {
551 BT_ERR("%s, Out of memory", __func__);
552 bt_mesh_free_buf(buf);
553 return -ENOMEM;
554 }
555
556 buf_len = buf->len;
557 for (i = 0; i < buf_len / SETTINGS_ITEM_SIZE; i++) {
558 uint16_t item = net_buf_simple_pull_le16(buf);
559 if (item != val) {
560 net_buf_simple_add_le16(store, item);
561 }
562 }
563
564 err = settings_save(handle, key, store->data, store->len);
565
566 bt_mesh_free_buf(store);
567 bt_mesh_free_buf(buf);
568 return err;
569 }
570
bt_mesh_remove_settings_item(bt_mesh_nvs_handle_t handle,const char * key,const uint16_t val)571 int bt_mesh_remove_settings_item(bt_mesh_nvs_handle_t handle, const char *key, const uint16_t val)
572 {
573 int err = 0;
574 bt_mesh_settings_lock();
575 err = settings_remove_item(handle, key, val);
576 bt_mesh_settings_unlock();
577 return err;
578 }
579
bt_mesh_remove_core_settings_item(const char * key,const uint16_t val)580 int bt_mesh_remove_core_settings_item(const char *key, const uint16_t val)
581 {
582 bt_mesh_nvs_handle_t handle = settings_get_nvs_handle(SETTINGS_CORE);
583 return bt_mesh_remove_settings_item(handle, key, val);
584 }
585
586 #if CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE
bt_mesh_remove_uid_settings_item(const char * key,const uint16_t val)587 int bt_mesh_remove_uid_settings_item(const char *key, const uint16_t val)
588 {
589 bt_mesh_nvs_handle_t handle = settings_get_nvs_handle(SETTINGS_UID);
590 return bt_mesh_remove_settings_item(handle, key, val);
591 }
592 #endif
593
bt_mesh_settings_erase_key(bt_mesh_nvs_handle_t handle,const char * key)594 int bt_mesh_settings_erase_key(bt_mesh_nvs_handle_t handle, const char *key)
595 {
596 int err = 0;
597
598 err = nvs_erase_key(handle, key);
599 if (err != ESP_OK) {
600 if (err == ESP_ERR_NVS_NOT_FOUND) {
601 return 0;
602 }
603
604 BT_ERR("Failed to erase %s (err %d)", key, err);
605 return -EIO;
606 }
607
608 err = nvs_commit(handle);
609 if (err != ESP_OK) {
610 BT_ERR("Failed to commit nvs (err %d)", err);
611 return -EIO;
612 }
613
614 return 0;
615 }
616
bt_mesh_settings_erase_all(bt_mesh_nvs_handle_t handle)617 int bt_mesh_settings_erase_all(bt_mesh_nvs_handle_t handle)
618 {
619 int err = 0;
620
621 err = nvs_erase_all(handle);
622 if (err != ESP_OK) {
623 BT_ERR("Failed to erase all (err %d)", err);
624 return -EIO;
625 }
626
627 err = nvs_commit(handle);
628 if (err != ESP_OK) {
629 BT_ERR("Failed to commit nvs (err %d)", err);
630 return -EIO;
631 }
632
633 return 0;
634 }
635 #endif /* CONFIG_BLE_MESH_SETTINGS */
636