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