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