1 /*
2 * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <errno.h>
8 #include <string.h>
9 #include <stdint.h>
10
11 #include "mesh.h"
12 #include "mesh_main.h"
13 #include "mesh_common.h"
14 #include "settings_nvs.h"
15 #include "settings.h"
16 #include "transport.h"
17 #include "provisioner_prov.h"
18
19 #if CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE
20 /*
21 * key: "mesh/uid" -> write/read to set/get all the user ids.
22 * key: "mesh/id/xxxx" -> write/read to set/get the "xxxx" user id.
23 */
24 #define SETTINGS_NVS_NAME_SIZE 15
25 #define SETTINGS_UID_SIZE 20
26 #define INVALID_SETTINGS_INDEX 0xFF
27 #define INVALID_SETTINGS_HANDLE UINT32_MAX
28
29 static struct settings_uid {
30 bool open; /* Indicate if settings is open */
31 char id[SETTINGS_UID_SIZE + 1]; /* Settings user id */
32 char name[SETTINGS_NVS_NAME_SIZE + 1]; /* Settings nvs namespace */
33 bt_mesh_nvs_handle_t handle; /* Core Settings nvs handle */
34 } user_ids[CONFIG_BLE_MESH_MAX_NVS_NAMESPACE];
35
36 static int settings_direct_erase(uint8_t index);
37
settings_uid_empty(struct settings_uid * uid)38 static inline bool settings_uid_empty(struct settings_uid *uid)
39 {
40 return (uid->id[0] == '\0') ? true : false;
41 }
42
get_core_settings_handle(void)43 bt_mesh_nvs_handle_t get_core_settings_handle(void)
44 {
45 int i;
46
47 for (i = 0; i < ARRAY_SIZE(user_ids); i++) {
48 if (user_ids[i].open) {
49 return user_ids[i].handle;
50 }
51 }
52
53 BT_ERR("No settings handle found");
54 return INVALID_SETTINGS_HANDLE;
55 }
56
settings_uid_init(void)57 int settings_uid_init(void)
58 {
59 int i;
60
61 for (i = 0; i < ARRAY_SIZE(user_ids); i++) {
62 memset(&user_ids[i], 0, sizeof(struct settings_uid));
63 user_ids[i].handle = INVALID_SETTINGS_HANDLE;
64 }
65
66 return 0;
67 }
68
settings_uid_load(void)69 int settings_uid_load(void)
70 {
71 struct net_buf_simple *buf = NULL;
72 char name[16] = {'\0'};
73 bool exist = false;
74 size_t length = 0;
75 int err = 0;
76 int i;
77
78 /* Before using user id to search settings, we need to
79 * restore all the settings user_ids properly.
80 */
81
82 buf = bt_mesh_get_uid_settings_item("mesh/uid");
83 if (!buf) {
84 return 0;
85 }
86
87 length = buf->len;
88
89 for (i = 0; i < length / SETTINGS_ITEM_SIZE; i++) {
90 uint16_t index = net_buf_simple_pull_le16(buf);
91
92 sprintf(name, "mesh/id/%04x", index);
93
94 err = bt_mesh_load_uid_settings(name, (uint8_t *)user_ids[index].id,
95 SETTINGS_UID_SIZE, &exist);
96 if (err) {
97 continue;
98 }
99
100 if (exist == false) {
101 continue;
102 }
103
104 BT_INFO("Restored settings %d, uid %s", index, user_ids[index].id);
105 }
106
107 bt_mesh_free_buf(buf);
108 return err;
109 }
110
111 #if CONFIG_BLE_MESH_DEINIT
settings_uid_deinit(bool erase)112 int settings_uid_deinit(bool erase)
113 {
114 int i;
115
116 for (i = 0; i < ARRAY_SIZE(user_ids); i++) {
117 memset(&user_ids[i], 0, offsetof(struct settings_uid, handle));
118 /* Can not reset handle here, since it will be used
119 * in the settings_uid_erase().
120 */
121 }
122
123 return 0;
124 }
125
settings_uid_erase(void)126 int settings_uid_erase(void)
127 {
128 int i;
129
130 for (i = 0; i < ARRAY_SIZE(user_ids); i++) {
131 if (user_ids[i].open == true) {
132 /* When a nvs namespace is open, which means it is
133 * being used currently. And its information will
134 * be erased when the deinit function is invoked,
135 * no need to erase it here.
136 */
137 bt_mesh_settings_nvs_close(user_ids[i].handle);
138 } else if (settings_uid_empty(&user_ids[i]) == false) {
139 /* When a user id is not empty, which means the nvs
140 * namespace may contains mesh information, need to
141 * erase it here.
142 */
143 settings_direct_erase(i);
144 }
145
146 user_ids[i].handle = INVALID_SETTINGS_HANDLE;
147 }
148
149 bt_mesh_erase_uid_settings("mesh/uid");
150 return 0;
151 }
152 #endif /* CONFIG_BLE_MESH_DEINIT */
153
settings_direct_erase(uint8_t index)154 static int settings_direct_erase(uint8_t index)
155 {
156 bt_mesh_nvs_handle_t handle = 0;
157 char name[16] = {'\0'};
158 int err = 0;
159
160 sprintf(name, "%s_%02x", "mesh_core", index);
161
162 /* Get handle for core settings */
163 err = bt_mesh_settings_nvs_open(name, &handle);
164 if (err) {
165 BT_ERR("Open nvs failed, name %s, err %d", name, err);
166 return -EIO;
167 }
168
169 /* Erase mesh information */
170 err = bt_mesh_settings_erase_all(handle);
171 if (err) {
172 BT_ERR("Erase settings failed, index %d", index);
173 return err;
174 }
175
176 bt_mesh_settings_nvs_close(handle);
177
178 /* Erase settings user id */
179 memset(name, 0, sizeof(name));
180 sprintf(name, "mesh/id/%04x", index);
181
182 bt_mesh_erase_uid_settings(name);
183 bt_mesh_remove_uid_settings_item("mesh/uid", index);
184
185 return 0;
186 }
187
settings_index_get(const char * id,uint8_t * index)188 static uint8_t settings_index_get(const char *id, uint8_t *index)
189 {
190 uint8_t idx = 0;
191 int i;
192
193 for (i = 0; i < ARRAY_SIZE(user_ids); i++) {
194 if (strlen(user_ids[i].id) != strlen(id)) {
195 continue;
196 }
197
198 if (!strncmp(user_ids[i].id, id, strlen(id))) {
199 idx = i;
200 break;
201 }
202 }
203
204 if (i == ARRAY_SIZE(user_ids)) {
205 idx = INVALID_SETTINGS_INDEX;
206 }
207
208 if (index) {
209 *index = idx;
210 }
211 return idx;
212 }
213
settings_open(uint8_t index)214 static int settings_open(uint8_t index)
215 {
216 struct settings_uid *uid = &user_ids[index];
217 char name[16] = {'\0'};
218 int err = 0;
219 int i;
220
221 /* Check if the nvs namespace is already open */
222 if (uid->open == true) {
223 BT_WARN("Settings already open, index %d", index);
224 return -EALREADY;
225 }
226
227 /* Check if another nvs namespace is already open */
228 for (i = 0; i < ARRAY_SIZE(user_ids); i++) {
229 if (i != index && user_ids[i].open == true) {
230 BT_ERR("Settings %d is open, close it first", i);
231 return -EBUSY;
232 }
233 }
234
235 memset(uid->name, 0, sizeof(uid->name));
236 sprintf(uid->name, "%s_%02x", "mesh_core", index);
237
238 err = bt_mesh_settings_nvs_open(uid->name, &uid->handle);
239 if (err) {
240 BT_ERR("Open nvs failed, name %s, err %d", uid->name, err);
241 return -EIO;
242 }
243
244 if (settings_uid_empty(uid)) {
245 /* If the settings is not open with user id, then we use
246 * the index as the user id. Or when the device restarts,
247 * the user id may be restored, in this case the user id
248 * shall not be updated.
249 */
250 sprintf(uid->id, "%04x", index);
251 }
252
253 BT_INFO("Open settings, index %d, uid %s", index, uid->id);
254
255 sprintf(name, "mesh/id/%04x", index);
256 err = bt_mesh_save_uid_settings(name, (const uint8_t *)uid->id, SETTINGS_UID_SIZE);
257 if (err) {
258 BT_ERR("Save uid failed, name %s", name);
259 return err;
260 }
261
262 err = bt_mesh_add_uid_settings_item("mesh/uid", index);
263 if (err) {
264 BT_ERR("Add uid failed, index %d", index);
265 return err;
266 }
267
268 /* Mark this as open here, because we need this flag for
269 * finding nvs handle before restoring mesh information.
270 */
271 uid->open = true;
272
273 err = settings_core_load();
274 if (err) {
275 BT_ERR("Load settings failed, name %s", uid->name);
276 return err;
277 }
278
279 err = settings_core_commit();
280 if (err) {
281 BT_ERR("Commit settings failed, name %s", uid->name);
282 return err;
283 }
284
285 return 0;
286 }
287
bt_mesh_provisioner_open_settings_with_index(uint8_t index)288 int bt_mesh_provisioner_open_settings_with_index(uint8_t index)
289 {
290 if (index >= ARRAY_SIZE(user_ids)) {
291 BT_ERR("Invalid settings index %d", index);
292 return -EINVAL;
293 }
294
295 return settings_open(index);
296 }
297
bt_mesh_provisioner_open_settings_with_uid(const char * id,uint8_t * index)298 int bt_mesh_provisioner_open_settings_with_uid(const char *id, uint8_t *index)
299 {
300 uint8_t idx = 0;
301 int i;
302
303 if (!id || strlen(id) > SETTINGS_UID_SIZE) {
304 BT_ERR("Invalid settings uid");
305 return -EINVAL;
306 }
307
308 idx = settings_index_get(id, index);
309
310 /* If user id not exists, try to add this as a new one. */
311 if (idx >= ARRAY_SIZE(user_ids)) {
312 for (i = 0; i < ARRAY_SIZE(user_ids); i++) {
313 if (settings_uid_empty(&user_ids[i])) {
314 strncpy(user_ids[i].id, id, SETTINGS_UID_SIZE);
315 if (index) {
316 *index = i;
317 }
318 break;
319 }
320 }
321
322 if (i == ARRAY_SIZE(user_ids)) {
323 BT_ERR("Settings uid is full!");
324 return -ENOMEM;
325 }
326
327 idx = i;
328 }
329
330 return settings_open(idx);
331 }
332
settings_close(uint8_t index,bool erase)333 static int settings_close(uint8_t index, bool erase)
334 {
335 struct settings_uid *uid = &user_ids[index];
336 char name[16] = {'\0'};
337 int err = 0;
338
339 if (uid->open == false) {
340 BT_ERR("Settings not open, index %d", index);
341 return -EIO;
342 }
343
344 BT_INFO("Close settings, index %d, uid %s", index, uid->id);
345
346 /* Disable Provisioner firstly */
347 err = bt_mesh_provisioner_disable(BLE_MESH_PROV_ADV | BLE_MESH_PROV_GATT);
348 if (err && err != -EALREADY) {
349 BT_ERR("Disable Provisioner failed (err %d)", err);
350 return err;
351 }
352
353 /* Reset (and erase) mesh information */
354 bt_mesh_provisioner_prov_reset(erase);
355 bt_mesh_provisioner_main_reset(erase);
356 bt_mesh_net_reset();
357 bt_mesh_rx_reset(erase);
358 bt_mesh_tx_reset();
359 bt_mesh_settings_reset(erase);
360
361 if (erase == true) {
362 /* Erase and reset settings user id */
363 sprintf(name, "mesh/id/%04x", index);
364
365 bt_mesh_erase_uid_settings(name);
366 bt_mesh_remove_uid_settings_item("mesh/uid", index);
367
368 memset(uid->id, 0, sizeof(uid->id));
369 }
370
371 bt_mesh_settings_nvs_close(uid->handle);
372 uid->open = false;
373
374 return 0;
375 }
376
bt_mesh_provisioner_close_settings_with_index(uint8_t index,bool erase)377 int bt_mesh_provisioner_close_settings_with_index(uint8_t index, bool erase)
378 {
379 if (index >= ARRAY_SIZE(user_ids)) {
380 BT_ERR("Invalid settings index %d", index);
381 return -EINVAL;
382 }
383
384 return settings_close(index, erase);
385 }
386
bt_mesh_provisioner_close_settings_with_uid(const char * id,bool erase,uint8_t * index)387 int bt_mesh_provisioner_close_settings_with_uid(const char *id, bool erase, uint8_t *index)
388 {
389 uint8_t idx = 0;
390
391 if (!id || strlen(id) > SETTINGS_UID_SIZE) {
392 BT_ERR("Invalid settings uid");
393 return -EINVAL;
394 }
395
396 idx = settings_index_get(id, index);
397 if (idx >= ARRAY_SIZE(user_ids)) {
398 BT_ERR("Settings uid %s not exists", id);
399 return -ENODEV;
400 }
401
402 return settings_close(idx, erase);
403 }
404
settings_delete(uint8_t index)405 static int settings_delete(uint8_t index)
406 {
407 /* The function is used to erase mesh information from
408 * the nvs namespace when it is not open and restored,
409 * and delete the corresponding user id.
410 */
411 struct settings_uid *uid = &user_ids[index];
412
413 if (uid->open == true) {
414 BT_ERR("Settings being used, index %d", index);
415 return -EBUSY;
416 }
417
418 BT_INFO("Delete settings, index %d, uid %s", index, uid->id);
419
420 settings_direct_erase(index);
421
422 memset(uid, 0, sizeof(struct settings_uid));
423 uid->handle = INVALID_SETTINGS_HANDLE;
424
425 return 0;
426 }
427
bt_mesh_provisioner_delete_settings_with_index(uint8_t index)428 int bt_mesh_provisioner_delete_settings_with_index(uint8_t index)
429 {
430 if (index >= ARRAY_SIZE(user_ids)) {
431 BT_ERR("Invalid settings index %d", index);
432 return -EINVAL;
433 }
434
435 return settings_delete(index);
436 }
437
bt_mesh_provisioner_delete_settings_with_uid(const char * id,uint8_t * index)438 int bt_mesh_provisioner_delete_settings_with_uid(const char *id, uint8_t *index)
439 {
440 uint8_t idx = 0;
441
442 if (!id || strlen(id) > SETTINGS_UID_SIZE) {
443 BT_ERR("Invalid settings uid");
444 return -EINVAL;
445 }
446
447 idx = settings_index_get(id, index);
448 if (idx >= ARRAY_SIZE(user_ids)) {
449 BT_ERR("Settings uid %s not exists", id);
450 return -ENODEV;
451 }
452
453 return settings_delete(idx);
454 }
455
bt_mesh_provisioner_get_settings_uid(uint8_t index)456 const char *bt_mesh_provisioner_get_settings_uid(uint8_t index)
457 {
458 if (index >= ARRAY_SIZE(user_ids)) {
459 BT_ERR("Invalid settings index %d", index);
460 return NULL;
461 }
462
463 return user_ids[index].id;
464 }
465
bt_mesh_provisioner_get_settings_index(const char * id)466 uint8_t bt_mesh_provisioner_get_settings_index(const char *id)
467 {
468 uint8_t idx = 0;
469
470 if (!id || strlen(id) > SETTINGS_UID_SIZE) {
471 BT_ERR("Invalid settings uid");
472 return INVALID_SETTINGS_INDEX;
473 }
474
475 idx = settings_index_get(id, NULL);
476 if (idx >= ARRAY_SIZE(user_ids)) {
477 BT_ERR("Settings uid %s not exists", id);
478 }
479
480 return idx;
481 }
482
bt_mesh_provisioner_get_free_settings_count(void)483 uint8_t bt_mesh_provisioner_get_free_settings_count(void)
484 {
485 uint8_t count = 0;
486 int i;
487
488 for (i = 0; i < ARRAY_SIZE(user_ids); i++) {
489 if (settings_uid_empty(&user_ids[i])) {
490 count++;
491 }
492 }
493
494 return count;
495 }
496 #endif /* CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE */
497
498 #if CONFIG_BLE_MESH_SETTINGS && CONFIG_BLE_MESH_PROVISIONER
bt_mesh_provisioner_direct_erase_settings(void)499 int bt_mesh_provisioner_direct_erase_settings(void)
500 {
501 bt_mesh_nvs_handle_t handle = 0;
502 int err = 0;
503
504 err = bt_mesh_settings_direct_open(&handle);
505 if (err) {
506 return err;
507 }
508
509 #if CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE
510 for (int i = 0; i < ARRAY_SIZE(user_ids); i++) {
511 settings_direct_erase(i);
512 }
513
514 bt_mesh_erase_uid_settings("mesh/uid");
515 #else
516 err = bt_mesh_settings_erase_all(handle);
517 #endif
518
519 bt_mesh_settings_direct_close();
520 return err;
521 }
522 #endif /* CONFIG_BLE_MESH_SETTINGS && CONFIG_BLE_MESH_PROVISIONER */
523