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