1 /*
2 * Copyright (c) 2019 Tobias Svehagen
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <string.h>
9 #include <stdlib.h>
10
11 #include <zephyr/settings/settings.h>
12
13 #include <zephyr/bluetooth/mesh.h>
14
15 #include "common/bt_str.h"
16
17 #include "cdb.h"
18 #include "mesh.h"
19 #include "net.h"
20 #include "rpl.h"
21 #include "settings.h"
22 #include "keys.h"
23
24 #define LOG_LEVEL CONFIG_BT_MESH_CDB_LOG_LEVEL
25 #include <zephyr/logging/log.h>
26 LOG_MODULE_REGISTER(bt_mesh_cdb);
27
28 /* Tracking of what storage changes are pending for App and Net Keys. We
29 * track this in a separate array here instead of within the respective
30 * bt_mesh_app_key and bt_mesh_subnet structs themselves, since once a key
31 * gets deleted its struct becomes invalid and may be reused for other keys.
32 */
33 struct key_update {
34 uint16_t key_idx:12, /* AppKey or NetKey Index */
35 valid:1, /* 1 if this entry is valid, 0 if not */
36 app_key:1, /* 1 if this is an AppKey, 0 if a NetKey */
37 clear:1; /* 1 if key needs clearing, 0 if storing */
38 };
39
40 /* Tracking of what storage changes are pending for node settings. */
41 struct node_update {
42 uint16_t addr;
43 bool clear;
44 };
45
46 /* Node information for persistent storage. */
47 struct node_val {
48 uint16_t net_idx;
49 uint8_t num_elem;
50 uint8_t flags;
51 #define F_NODE_CONFIGURED 0x01
52 uint8_t uuid[16];
53 struct bt_mesh_key dev_key;
54 } __packed;
55
56 /* NetKey storage information */
57 struct net_key_val {
58 uint8_t kr_flag:1,
59 kr_phase:7;
60 struct bt_mesh_key val[2];
61 } __packed;
62
63 /* AppKey information for persistent storage. */
64 struct app_key_val {
65 uint16_t net_idx;
66 bool updated;
67 struct bt_mesh_key val[2];
68 } __packed;
69
70 /* Network information for persistent storage. */
71 struct net_val {
72 struct __packed {
73 uint32_t index;
74 bool update;
75 } iv;
76 uint16_t lowest_avail_addr;
77 } __packed;
78
79 /* One more entry for the node's address update. */
80 static struct node_update cdb_node_updates[CONFIG_BT_MESH_CDB_NODE_COUNT + 1];
81 static struct key_update cdb_key_updates[CONFIG_BT_MESH_CDB_SUBNET_COUNT +
82 CONFIG_BT_MESH_CDB_APP_KEY_COUNT];
83
84 struct bt_mesh_cdb bt_mesh_cdb = {
85 .nodes = {
86 [0 ... (CONFIG_BT_MESH_CDB_NODE_COUNT - 1)] = {
87 .addr = BT_MESH_ADDR_UNASSIGNED,
88 }
89 },
90 .subnets = {
91 [0 ... (CONFIG_BT_MESH_CDB_SUBNET_COUNT - 1)] = {
92 .net_idx = BT_MESH_KEY_UNUSED,
93 }
94 },
95 .app_keys = {
96 [0 ... (CONFIG_BT_MESH_CDB_APP_KEY_COUNT - 1)] = {
97 .app_idx = BT_MESH_KEY_UNUSED,
98 .net_idx = BT_MESH_KEY_UNUSED,
99 }
100 },
101 };
102
103 /*
104 * Check if an address range from addr_start for addr_start + num_elem - 1 is
105 * free for use. When a conflict is found, next will be set to the next address
106 * available after the conflicting range and -EAGAIN will be returned.
107 */
addr_is_free(uint16_t addr_start,uint8_t num_elem,uint16_t * next)108 static int addr_is_free(uint16_t addr_start, uint8_t num_elem, uint16_t *next)
109 {
110 uint16_t addr_end = addr_start + num_elem - 1;
111 uint16_t other_start, other_end;
112 int i;
113
114 if (!BT_MESH_ADDR_IS_UNICAST(addr_start) ||
115 !BT_MESH_ADDR_IS_UNICAST(addr_end) ||
116 num_elem == 0) {
117 return -EINVAL;
118 }
119
120 for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.nodes); i++) {
121 struct bt_mesh_cdb_node *node = &bt_mesh_cdb.nodes[i];
122
123 if (node->addr == BT_MESH_ADDR_UNASSIGNED) {
124 continue;
125 }
126
127 other_start = node->addr;
128 other_end = other_start + node->num_elem - 1;
129
130 if (!(addr_end < other_start || addr_start > other_end)) {
131 if (next) {
132 *next = other_end + 1;
133 }
134
135 return -EAGAIN;
136 }
137 }
138
139 return 0;
140 }
141
142 /*
143 * Find the lowest possible starting address that can fit num_elem elements. If
144 * a free address range cannot be found, BT_MESH_ADDR_UNASSIGNED will be
145 * returned. Otherwise the first address in the range is returned.
146 *
147 * NOTE: This is quite an ineffective algorithm as it might need to look
148 * through the array of nodes N+2 times. A more effective algorithm
149 * could be used if the nodes were stored in a sorted list.
150 */
find_lowest_free_addr(uint8_t num_elem)151 static uint16_t find_lowest_free_addr(uint8_t num_elem)
152 {
153 uint16_t addr = bt_mesh_cdb.lowest_avail_addr;
154 uint16_t next;
155 int err, i;
156
157 /*
158 * It takes a maximum of node count + 2 to find a free address if there
159 * is any. +1 for our own address and +1 for making sure that the
160 * address range is valid.
161 */
162 for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.nodes) + 2; ++i) {
163 err = addr_is_free(addr, num_elem, &next);
164 if (err == 0) {
165 break;
166 } else if (err != -EAGAIN) {
167 addr = BT_MESH_ADDR_UNASSIGNED;
168 break;
169 }
170
171 addr = next;
172 }
173
174 return addr;
175 }
176
cdb_net_set(const char * name,size_t len_rd,settings_read_cb read_cb,void * cb_arg)177 static int cdb_net_set(const char *name, size_t len_rd,
178 settings_read_cb read_cb, void *cb_arg)
179 {
180 struct net_val net;
181 int err;
182
183 if (len_rd == 0) {
184 LOG_DBG("val (null)");
185 return 0;
186 }
187
188 err = bt_mesh_settings_set(read_cb, cb_arg, &net, sizeof(net));
189 if (err) {
190 /* Try to recover previous version of the network settings without address. */
191 err = bt_mesh_settings_set(read_cb, cb_arg, &net, sizeof(net.iv));
192 if (err) {
193 LOG_ERR("Failed to set \'cdb_net\'");
194 return err;
195 }
196
197 net.lowest_avail_addr = 1;
198 }
199
200 bt_mesh_cdb.iv_index = net.iv.index;
201
202 if (net.iv.update) {
203 atomic_set_bit(bt_mesh_cdb.flags, BT_MESH_CDB_IVU_IN_PROGRESS);
204 }
205
206 bt_mesh_cdb.lowest_avail_addr = net.lowest_avail_addr;
207
208 atomic_set_bit(bt_mesh_cdb.flags, BT_MESH_CDB_VALID);
209
210 return 0;
211 }
212
cdb_node_set(const char * name,size_t len_rd,settings_read_cb read_cb,void * cb_arg)213 static int cdb_node_set(const char *name, size_t len_rd,
214 settings_read_cb read_cb, void *cb_arg)
215 {
216 struct bt_mesh_cdb_node *node;
217 struct node_val val;
218 struct bt_mesh_key tmp;
219 uint16_t addr;
220 int err;
221
222 if (!name) {
223 LOG_ERR("Insufficient number of arguments");
224 return -ENOENT;
225 }
226
227 addr = strtol(name, NULL, 16);
228
229 if (len_rd == 0) {
230 LOG_DBG("val (null)");
231 LOG_DBG("Deleting node 0x%04x", addr);
232
233 node = bt_mesh_cdb_node_get(addr);
234 if (node) {
235 bt_mesh_cdb_node_del(node, false);
236 }
237
238 return 0;
239 }
240
241 err = bt_mesh_settings_set(read_cb, cb_arg, &val, sizeof(val));
242 if (err) {
243 LOG_ERR("Failed to set \'node\'");
244 return err;
245 }
246
247 node = bt_mesh_cdb_node_get(addr);
248 if (!node) {
249 node = bt_mesh_cdb_node_alloc(val.uuid, addr, val.num_elem,
250 val.net_idx);
251 }
252
253 if (!node) {
254 LOG_ERR("No space for a new node");
255 return -ENOMEM;
256 }
257
258 if (val.flags & F_NODE_CONFIGURED) {
259 atomic_set_bit(node->flags, BT_MESH_CDB_NODE_CONFIGURED);
260 }
261
262 memcpy(node->uuid, val.uuid, 16);
263
264 /* One extra copying since val.dev_key is from packed structure
265 * and might be unaligned.
266 */
267 memcpy(&tmp, &val.dev_key, sizeof(struct bt_mesh_key));
268 bt_mesh_key_assign(&node->dev_key, &tmp);
269
270 LOG_DBG("Node 0x%04x recovered from storage", addr);
271
272 return 0;
273 }
274
cdb_subnet_set(const char * name,size_t len_rd,settings_read_cb read_cb,void * cb_arg)275 static int cdb_subnet_set(const char *name, size_t len_rd,
276 settings_read_cb read_cb, void *cb_arg)
277 {
278 struct bt_mesh_cdb_subnet *sub;
279 struct net_key_val key;
280 struct bt_mesh_key tmp[2];
281 uint16_t net_idx;
282 int err;
283
284 if (!name) {
285 LOG_ERR("Insufficient number of arguments");
286 return -ENOENT;
287 }
288
289 net_idx = strtol(name, NULL, 16);
290 sub = bt_mesh_cdb_subnet_get(net_idx);
291
292 if (len_rd == 0) {
293 LOG_DBG("val (null)");
294 if (!sub) {
295 LOG_ERR("No subnet with NetKeyIndex 0x%03x", net_idx);
296 return -ENOENT;
297 }
298
299 LOG_DBG("Deleting NetKeyIndex 0x%03x", net_idx);
300 bt_mesh_cdb_subnet_del(sub, false);
301 return 0;
302 }
303
304 err = bt_mesh_settings_set(read_cb, cb_arg, &key, sizeof(key));
305 if (err) {
306 LOG_ERR("Failed to set \'net-key\'");
307 return err;
308 }
309
310 /* One extra copying since key.val[] is from packed structure
311 * and might be unaligned.
312 */
313 memcpy(&tmp[0], &key.val[0], sizeof(struct bt_mesh_key));
314 memcpy(&tmp[1], &key.val[1], sizeof(struct bt_mesh_key));
315
316 if (sub) {
317 LOG_DBG("Updating existing NetKeyIndex 0x%03x", net_idx);
318
319 sub->kr_phase = key.kr_phase;
320 bt_mesh_key_assign(&sub->keys[0].net_key, &tmp[0]);
321 bt_mesh_key_assign(&sub->keys[1].net_key, &tmp[1]);
322
323 return 0;
324 }
325
326 sub = bt_mesh_cdb_subnet_alloc(net_idx);
327 if (!sub) {
328 LOG_ERR("No space to allocate a new subnet");
329 return -ENOMEM;
330 }
331
332 sub->kr_phase = key.kr_phase;
333 bt_mesh_key_assign(&sub->keys[0].net_key, &tmp[0]);
334 bt_mesh_key_assign(&sub->keys[1].net_key, &tmp[1]);
335
336 LOG_DBG("NetKeyIndex 0x%03x recovered from storage", net_idx);
337
338 return 0;
339 }
340
cdb_app_key_set(const char * name,size_t len_rd,settings_read_cb read_cb,void * cb_arg)341 static int cdb_app_key_set(const char *name, size_t len_rd,
342 settings_read_cb read_cb, void *cb_arg)
343 {
344 struct bt_mesh_cdb_app_key *app;
345 struct app_key_val key;
346 struct bt_mesh_key tmp[2];
347 uint16_t app_idx;
348 int err;
349
350 if (!name) {
351 LOG_ERR("Insufficient number of arguments");
352 return -ENOENT;
353 }
354
355 app_idx = strtol(name, NULL, 16);
356
357 if (len_rd == 0) {
358 LOG_DBG("val (null)");
359 LOG_DBG("Deleting AppKeyIndex 0x%03x", app_idx);
360
361 app = bt_mesh_cdb_app_key_get(app_idx);
362 if (app) {
363 bt_mesh_cdb_app_key_del(app, false);
364 }
365
366 return 0;
367 }
368
369 err = bt_mesh_settings_set(read_cb, cb_arg, &key, sizeof(key));
370 if (err) {
371 LOG_ERR("Failed to set \'app-key\'");
372 return err;
373 }
374
375 /* One extra copying since key.val[] is from packed structure
376 * and might be unaligned.
377 */
378 memcpy(&tmp[0], &key.val[0], sizeof(struct bt_mesh_key));
379 memcpy(&tmp[1], &key.val[1], sizeof(struct bt_mesh_key));
380
381 app = bt_mesh_cdb_app_key_get(app_idx);
382 if (!app) {
383 app = bt_mesh_cdb_app_key_alloc(key.net_idx, app_idx);
384 }
385
386 if (!app) {
387 LOG_ERR("No space for a new app key");
388 return -ENOMEM;
389 }
390
391 bt_mesh_key_assign(&app->keys[0].app_key, &tmp[0]);
392 bt_mesh_key_assign(&app->keys[1].app_key, &tmp[1]);
393
394 LOG_DBG("AppKeyIndex 0x%03x recovered from storage", app_idx);
395
396 return 0;
397 }
398
cdb_set(const char * name,size_t len_rd,settings_read_cb read_cb,void * cb_arg)399 static int cdb_set(const char *name, size_t len_rd,
400 settings_read_cb read_cb, void *cb_arg)
401 {
402 int len;
403 const char *next;
404
405 if (!name) {
406 LOG_ERR("Insufficient number of arguments");
407 return -ENOENT;
408 }
409
410 if (!strcmp(name, "Net")) {
411 return cdb_net_set(name, len_rd, read_cb, cb_arg);
412 }
413
414
415 len = settings_name_next(name, &next);
416
417 if (!next) {
418 LOG_ERR("Insufficient number of arguments");
419 return -ENOENT;
420 }
421
422 if (!strncmp(name, "Node", len)) {
423 return cdb_node_set(next, len_rd, read_cb, cb_arg);
424 }
425
426 if (!strncmp(name, "Subnet", len)) {
427 return cdb_subnet_set(next, len_rd, read_cb, cb_arg);
428 }
429
430 if (!strncmp(name, "AppKey", len)) {
431 return cdb_app_key_set(next, len_rd, read_cb, cb_arg);
432 }
433
434 LOG_WRN("Unknown module key %s", name);
435 return -ENOENT;
436 }
437
438 BT_MESH_SETTINGS_DEFINE(cdb, "cdb", cdb_set);
439
store_cdb_node(const struct bt_mesh_cdb_node * node)440 static void store_cdb_node(const struct bt_mesh_cdb_node *node)
441 {
442 struct node_val val;
443 char path[30];
444 int err;
445
446 val.net_idx = node->net_idx;
447 val.num_elem = node->num_elem;
448 val.flags = 0;
449
450 if (atomic_test_bit(node->flags, BT_MESH_CDB_NODE_CONFIGURED)) {
451 val.flags |= F_NODE_CONFIGURED;
452 }
453
454 memcpy(val.uuid, node->uuid, 16);
455 memcpy(&val.dev_key, &node->dev_key, sizeof(struct bt_mesh_key));
456
457 snprintk(path, sizeof(path), "bt/mesh/cdb/Node/%x", node->addr);
458
459 err = settings_save_one(path, &val, sizeof(val));
460 if (err) {
461 LOG_ERR("Failed to store Node %s value", path);
462 } else {
463 LOG_DBG("Stored Node %s value", path);
464 }
465 }
466
clear_cdb_node(uint16_t addr)467 static void clear_cdb_node(uint16_t addr)
468 {
469 char path[30];
470 int err;
471
472 LOG_DBG("Node 0x%04x", addr);
473
474 snprintk(path, sizeof(path), "bt/mesh/cdb/Node/%x", addr);
475 err = settings_delete(path);
476 if (err) {
477 LOG_ERR("Failed to clear Node 0x%04x", addr);
478 } else {
479 LOG_DBG("Cleared Node 0x%04x", addr);
480 }
481 }
482
store_cdb_subnet(const struct bt_mesh_cdb_subnet * sub)483 static void store_cdb_subnet(const struct bt_mesh_cdb_subnet *sub)
484 {
485 struct net_key_val key;
486 char path[30];
487 int err;
488
489 LOG_DBG("NetKeyIndex 0x%03x NetKey %s", sub->net_idx,
490 bt_hex(&sub->keys[0].net_key, sizeof(struct bt_mesh_key)));
491
492 memcpy(&key.val[0], &sub->keys[0].net_key, sizeof(struct bt_mesh_key));
493 memcpy(&key.val[1], &sub->keys[1].net_key, sizeof(struct bt_mesh_key));
494 key.kr_flag = 0U; /* Deprecated */
495 key.kr_phase = sub->kr_phase;
496
497 snprintk(path, sizeof(path), "bt/mesh/cdb/Subnet/%x", sub->net_idx);
498
499 err = settings_save_one(path, &key, sizeof(key));
500 if (err) {
501 LOG_ERR("Failed to store Subnet value");
502 } else {
503 LOG_DBG("Stored Subnet value");
504 }
505 }
506
clear_cdb_subnet(uint16_t net_idx)507 static void clear_cdb_subnet(uint16_t net_idx)
508 {
509 char path[30];
510 int err;
511
512 LOG_DBG("NetKeyIndex 0x%03x", net_idx);
513
514 snprintk(path, sizeof(path), "bt/mesh/cdb/Subnet/%x", net_idx);
515 err = settings_delete(path);
516 if (err) {
517 LOG_ERR("Failed to clear NetKeyIndex 0x%03x", net_idx);
518 } else {
519 LOG_DBG("Cleared NetKeyIndex 0x%03x", net_idx);
520 }
521 }
522
store_cdb_app_key(const struct bt_mesh_cdb_app_key * app)523 static void store_cdb_app_key(const struct bt_mesh_cdb_app_key *app)
524 {
525 struct app_key_val key;
526 char path[30];
527 int err;
528
529 key.net_idx = app->net_idx;
530 key.updated = false;
531 memcpy(&key.val[0], &app->keys[0].app_key, sizeof(struct bt_mesh_key));
532 memcpy(&key.val[1], &app->keys[1].app_key, sizeof(struct bt_mesh_key));
533
534 snprintk(path, sizeof(path), "bt/mesh/cdb/AppKey/%x", app->app_idx);
535
536 err = settings_save_one(path, &key, sizeof(key));
537 if (err) {
538 LOG_ERR("Failed to store AppKey %s value", path);
539 } else {
540 LOG_DBG("Stored AppKey %s value", path);
541 }
542 }
543
clear_cdb_app_key(uint16_t app_idx)544 static void clear_cdb_app_key(uint16_t app_idx)
545 {
546 char path[30];
547 int err;
548
549 snprintk(path, sizeof(path), "bt/mesh/cdb/AppKey/%x", app_idx);
550 err = settings_delete(path);
551 if (err) {
552 LOG_ERR("Failed to clear AppKeyIndex 0x%03x", app_idx);
553 } else {
554 LOG_DBG("Cleared AppKeyIndex 0x%03x", app_idx);
555 }
556 }
557
schedule_cdb_store(int flag)558 static void schedule_cdb_store(int flag)
559 {
560 atomic_set_bit(bt_mesh_cdb.flags, flag);
561 bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_CDB_PENDING);
562 }
563
update_cdb_net_settings(void)564 static void update_cdb_net_settings(void)
565 {
566 schedule_cdb_store(BT_MESH_CDB_SUBNET_PENDING);
567 }
568
cdb_node_update_find(uint16_t addr,struct node_update ** free_slot)569 static struct node_update *cdb_node_update_find(uint16_t addr,
570 struct node_update **free_slot)
571 {
572 struct node_update *match;
573 int i;
574
575 match = NULL;
576 *free_slot = NULL;
577
578 for (i = 0; i < ARRAY_SIZE(cdb_node_updates); i++) {
579 struct node_update *update = &cdb_node_updates[i];
580
581 if (update->addr == BT_MESH_ADDR_UNASSIGNED) {
582 *free_slot = update;
583 continue;
584 }
585
586 if (update->addr == addr) {
587 match = update;
588 }
589 }
590
591 return match;
592 }
593
update_cdb_node_settings(const struct bt_mesh_cdb_node * node,bool store)594 static void update_cdb_node_settings(const struct bt_mesh_cdb_node *node,
595 bool store)
596 {
597 struct node_update *update, *free_slot;
598
599 LOG_DBG("Node 0x%04x", node->addr);
600
601 update = cdb_node_update_find(node->addr, &free_slot);
602 if (update) {
603 update->clear = !store;
604 schedule_cdb_store(BT_MESH_CDB_NODES_PENDING);
605 return;
606 }
607
608 if (!free_slot) {
609 if (store) {
610 store_cdb_node(node);
611 } else {
612 clear_cdb_node(node->addr);
613 }
614 return;
615 }
616
617 free_slot->addr = node->addr;
618 free_slot->clear = !store;
619
620 schedule_cdb_store(BT_MESH_CDB_NODES_PENDING);
621 }
622
cdb_key_update_find(bool app_key,uint16_t key_idx,struct key_update ** free_slot)623 static struct key_update *cdb_key_update_find(bool app_key, uint16_t key_idx,
624 struct key_update **free_slot)
625 {
626 struct key_update *match;
627 int i;
628
629 match = NULL;
630 *free_slot = NULL;
631
632 for (i = 0; i < ARRAY_SIZE(cdb_key_updates); i++) {
633 struct key_update *update = &cdb_key_updates[i];
634
635 if (!update->valid) {
636 *free_slot = update;
637 continue;
638 }
639
640 if (update->app_key != app_key) {
641 continue;
642 }
643
644 if (update->key_idx == key_idx) {
645 match = update;
646 }
647 }
648
649 return match;
650 }
651
update_cdb_subnet_settings(const struct bt_mesh_cdb_subnet * sub,bool store)652 static void update_cdb_subnet_settings(const struct bt_mesh_cdb_subnet *sub,
653 bool store)
654 {
655 struct key_update *update, *free_slot;
656 uint8_t clear = store ? 0U : 1U;
657
658 LOG_DBG("NetKeyIndex 0x%03x", sub->net_idx);
659
660 update = cdb_key_update_find(false, sub->net_idx, &free_slot);
661 if (update) {
662 update->clear = clear;
663 schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING);
664 return;
665 }
666
667 if (!free_slot) {
668 if (store) {
669 store_cdb_subnet(sub);
670 } else {
671 clear_cdb_subnet(sub->net_idx);
672 }
673 return;
674 }
675
676 free_slot->valid = 1U;
677 free_slot->key_idx = sub->net_idx;
678 free_slot->app_key = 0U;
679 free_slot->clear = clear;
680
681 schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING);
682 }
683
update_cdb_app_key_settings(const struct bt_mesh_cdb_app_key * key,bool store)684 static void update_cdb_app_key_settings(const struct bt_mesh_cdb_app_key *key,
685 bool store)
686 {
687 struct key_update *update, *free_slot;
688 uint8_t clear = store ? 0U : 1U;
689
690 LOG_DBG("AppKeyIndex 0x%03x", key->app_idx);
691
692 update = cdb_key_update_find(true, key->app_idx, &free_slot);
693 if (update) {
694 update->clear = clear;
695 schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING);
696 return;
697 }
698
699 if (!free_slot) {
700 if (store) {
701 store_cdb_app_key(key);
702 } else {
703 clear_cdb_app_key(key->app_idx);
704 }
705
706 return;
707 }
708
709 free_slot->valid = 1U;
710 free_slot->key_idx = key->app_idx;
711 free_slot->app_key = 1U;
712 free_slot->clear = clear;
713
714 schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING);
715 }
716
addr_assign(uint16_t addr,uint8_t num_elem)717 static uint16_t addr_assign(uint16_t addr, uint8_t num_elem)
718 {
719 if (addr == BT_MESH_ADDR_UNASSIGNED) {
720 addr = find_lowest_free_addr(num_elem);
721 } else if (addr < bt_mesh_cdb.lowest_avail_addr) {
722 return BT_MESH_ADDR_UNASSIGNED;
723 } else if (addr_is_free(addr, num_elem, NULL) < 0) {
724 LOG_DBG("Address range 0x%04x-0x%04x is not free", addr,
725 addr + num_elem - 1);
726 return BT_MESH_ADDR_UNASSIGNED;
727 }
728
729 return addr;
730 }
731
bt_mesh_cdb_create(const uint8_t key[16])732 int bt_mesh_cdb_create(const uint8_t key[16])
733 {
734 struct bt_mesh_cdb_subnet *sub;
735 int err;
736
737 if (atomic_test_and_set_bit(bt_mesh_cdb.flags,
738 BT_MESH_CDB_VALID)) {
739 return -EALREADY;
740 }
741
742 sub = bt_mesh_cdb_subnet_alloc(BT_MESH_KEY_PRIMARY);
743 if (sub == NULL) {
744 return -ENOMEM;
745 }
746
747 err = bt_mesh_key_import(BT_MESH_KEY_TYPE_NET, key, &sub->keys[0].net_key);
748 if (err) {
749 return err;
750 }
751
752 bt_mesh_cdb.iv_index = 0;
753 bt_mesh_cdb.lowest_avail_addr = 1;
754
755 if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
756 update_cdb_net_settings();
757 update_cdb_subnet_settings(sub, true);
758 }
759
760 return 0;
761 }
762
bt_mesh_cdb_clear(void)763 void bt_mesh_cdb_clear(void)
764 {
765 int i;
766
767 atomic_clear_bit(bt_mesh_cdb.flags, BT_MESH_CDB_VALID);
768
769 for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.nodes); ++i) {
770 if (bt_mesh_cdb.nodes[i].addr != BT_MESH_ADDR_UNASSIGNED) {
771 bt_mesh_cdb_node_del(&bt_mesh_cdb.nodes[i], true);
772 }
773 }
774
775 for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.subnets); ++i) {
776 if (bt_mesh_cdb.subnets[i].net_idx != BT_MESH_KEY_UNUSED) {
777 bt_mesh_cdb_subnet_del(&bt_mesh_cdb.subnets[i], true);
778 }
779 }
780
781 for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.app_keys); ++i) {
782 if (bt_mesh_cdb.app_keys[i].net_idx != BT_MESH_KEY_UNUSED) {
783 bt_mesh_cdb_app_key_del(&bt_mesh_cdb.app_keys[i], true);
784 }
785 }
786
787 if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
788 update_cdb_net_settings();
789 bt_mesh_settings_store_pending();
790 }
791 }
792
bt_mesh_cdb_iv_update(uint32_t iv_index,bool iv_update)793 void bt_mesh_cdb_iv_update(uint32_t iv_index, bool iv_update)
794 {
795 LOG_DBG("Updating IV index to %d\n", iv_index);
796
797 /* Reset the last deleted addr when IV Index is updated or recovered. */
798 if (!iv_update || iv_index > bt_mesh_cdb.iv_index + 1) {
799 bt_mesh_cdb.lowest_avail_addr = 1;
800 }
801
802 bt_mesh_cdb.iv_index = iv_index;
803
804 atomic_set_bit_to(bt_mesh_cdb.flags, BT_MESH_CDB_IVU_IN_PROGRESS,
805 iv_update);
806
807 if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
808 update_cdb_net_settings();
809 }
810 }
811
bt_mesh_cdb_subnet_alloc(uint16_t net_idx)812 struct bt_mesh_cdb_subnet *bt_mesh_cdb_subnet_alloc(uint16_t net_idx)
813 {
814 struct bt_mesh_cdb_subnet *sub;
815 int i;
816
817 if (bt_mesh_cdb_subnet_get(net_idx) != NULL) {
818 return NULL;
819 }
820
821 for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.subnets); ++i) {
822 sub = &bt_mesh_cdb.subnets[i];
823
824 if (sub->net_idx != BT_MESH_KEY_UNUSED) {
825 continue;
826 }
827
828 sub->net_idx = net_idx;
829
830 return sub;
831 }
832
833 return NULL;
834 }
835
bt_mesh_cdb_subnet_del(struct bt_mesh_cdb_subnet * sub,bool store)836 void bt_mesh_cdb_subnet_del(struct bt_mesh_cdb_subnet *sub, bool store)
837 {
838 LOG_DBG("NetIdx 0x%03x store %u", sub->net_idx, store);
839
840 if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) {
841 update_cdb_subnet_settings(sub, false);
842 }
843
844 sub->net_idx = BT_MESH_KEY_UNUSED;
845 bt_mesh_key_destroy(&sub->keys[0].net_key);
846 bt_mesh_key_destroy(&sub->keys[1].net_key);
847 memset(sub->keys, 0, sizeof(sub->keys));
848 }
849
bt_mesh_cdb_subnet_get(uint16_t net_idx)850 struct bt_mesh_cdb_subnet *bt_mesh_cdb_subnet_get(uint16_t net_idx)
851 {
852 int i;
853
854 for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.subnets); ++i) {
855 if (bt_mesh_cdb.subnets[i].net_idx == net_idx) {
856 return &bt_mesh_cdb.subnets[i];
857 }
858 }
859
860 return NULL;
861 }
862
bt_mesh_cdb_subnet_store(const struct bt_mesh_cdb_subnet * sub)863 void bt_mesh_cdb_subnet_store(const struct bt_mesh_cdb_subnet *sub)
864 {
865 if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
866 update_cdb_subnet_settings(sub, true);
867 }
868 }
869
bt_mesh_cdb_subnet_flags(const struct bt_mesh_cdb_subnet * sub)870 uint8_t bt_mesh_cdb_subnet_flags(const struct bt_mesh_cdb_subnet *sub)
871 {
872 uint8_t flags = 0x00;
873
874 if (sub && SUBNET_KEY_TX_IDX(sub)) {
875 flags |= BT_MESH_NET_FLAG_KR;
876 }
877
878 if (atomic_test_bit(bt_mesh_cdb.flags, BT_MESH_CDB_IVU_IN_PROGRESS)) {
879 flags |= BT_MESH_NET_FLAG_IVU;
880 }
881
882 return flags;
883 }
884
bt_mesh_cdb_subnet_key_import(struct bt_mesh_cdb_subnet * sub,int key_idx,const uint8_t in[16])885 int bt_mesh_cdb_subnet_key_import(struct bt_mesh_cdb_subnet *sub, int key_idx,
886 const uint8_t in[16])
887 {
888 if (!bt_mesh_key_compare(in, &sub->keys[key_idx].net_key)) {
889 return 0;
890 }
891
892 bt_mesh_key_destroy(&sub->keys[key_idx].net_key);
893
894 return bt_mesh_key_import(BT_MESH_KEY_TYPE_NET, in, &sub->keys[key_idx].net_key);
895 }
896
bt_mesh_cdb_subnet_key_export(const struct bt_mesh_cdb_subnet * sub,int key_idx,uint8_t out[16])897 int bt_mesh_cdb_subnet_key_export(const struct bt_mesh_cdb_subnet *sub, int key_idx,
898 uint8_t out[16])
899 {
900 return bt_mesh_key_export(out, &sub->keys[key_idx].net_key);
901 }
902
bt_mesh_cdb_node_alloc(const uint8_t uuid[16],uint16_t addr,uint8_t num_elem,uint16_t net_idx)903 struct bt_mesh_cdb_node *bt_mesh_cdb_node_alloc(const uint8_t uuid[16], uint16_t addr,
904 uint8_t num_elem, uint16_t net_idx)
905 {
906 int i;
907
908 addr = addr_assign(addr, num_elem);
909 if (addr == BT_MESH_ADDR_UNASSIGNED) {
910 return NULL;
911 }
912
913 for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.nodes); i++) {
914 struct bt_mesh_cdb_node *node = &bt_mesh_cdb.nodes[i];
915
916 if (node->addr == BT_MESH_ADDR_UNASSIGNED) {
917 memcpy(node->uuid, uuid, 16);
918 node->addr = addr;
919 node->num_elem = num_elem;
920 node->net_idx = net_idx;
921 atomic_set(node->flags, 0);
922 return node;
923 }
924 }
925
926 return NULL;
927 }
928
bt_mesh_cdb_free_addr_get(uint8_t num_elem)929 uint16_t bt_mesh_cdb_free_addr_get(uint8_t num_elem)
930 {
931 return find_lowest_free_addr(num_elem);
932 }
933
bt_mesh_cdb_node_del(struct bt_mesh_cdb_node * node,bool store)934 void bt_mesh_cdb_node_del(struct bt_mesh_cdb_node *node, bool store)
935 {
936 LOG_DBG("Node addr 0x%04x store %u", node->addr, store);
937
938 if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) {
939 update_cdb_node_settings(node, false);
940 }
941
942 if (store && node->addr + node->num_elem > bt_mesh_cdb.lowest_avail_addr) {
943 bt_mesh_cdb.lowest_avail_addr = node->addr + node->num_elem;
944
945 if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
946 update_cdb_net_settings();
947 }
948 }
949
950 node->addr = BT_MESH_ADDR_UNASSIGNED;
951 bt_mesh_key_destroy(&node->dev_key);
952 memset(&node->dev_key, 0, sizeof(node->dev_key));
953 }
954
bt_mesh_cdb_node_update(struct bt_mesh_cdb_node * node,uint16_t addr,uint8_t num_elem)955 void bt_mesh_cdb_node_update(struct bt_mesh_cdb_node *node, uint16_t addr,
956 uint8_t num_elem)
957 {
958 /* Address is used as a key to the nodes array. Remove the current entry first, then store
959 * new address.
960 */
961 if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
962 update_cdb_node_settings(node, false);
963 }
964
965 node->addr = addr;
966 node->num_elem = num_elem;
967
968 if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
969 update_cdb_node_settings(node, true);
970 }
971 }
972
bt_mesh_cdb_node_get(uint16_t addr)973 struct bt_mesh_cdb_node *bt_mesh_cdb_node_get(uint16_t addr)
974 {
975 int i;
976
977 for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.nodes); i++) {
978 struct bt_mesh_cdb_node *node = &bt_mesh_cdb.nodes[i];
979
980 if (addr >= node->addr &&
981 addr <= node->addr + node->num_elem - 1) {
982 return node;
983 }
984 }
985
986 return NULL;
987 }
988
bt_mesh_cdb_node_store(const struct bt_mesh_cdb_node * node)989 void bt_mesh_cdb_node_store(const struct bt_mesh_cdb_node *node)
990 {
991 if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
992 update_cdb_node_settings(node, true);
993 }
994 }
995
bt_mesh_cdb_node_foreach(bt_mesh_cdb_node_func_t func,void * user_data)996 void bt_mesh_cdb_node_foreach(bt_mesh_cdb_node_func_t func, void *user_data)
997 {
998 int i;
999
1000 for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.nodes); ++i) {
1001 if (bt_mesh_cdb.nodes[i].addr == BT_MESH_ADDR_UNASSIGNED) {
1002 continue;
1003 }
1004
1005 if (func(&bt_mesh_cdb.nodes[i], user_data) ==
1006 BT_MESH_CDB_ITER_STOP) {
1007 break;
1008 }
1009 }
1010 }
1011
bt_mesh_cdb_node_key_import(struct bt_mesh_cdb_node * node,const uint8_t in[16])1012 int bt_mesh_cdb_node_key_import(struct bt_mesh_cdb_node *node, const uint8_t in[16])
1013 {
1014 if (!bt_mesh_key_compare(in, &node->dev_key)) {
1015 return 0;
1016 }
1017
1018 bt_mesh_key_destroy(&node->dev_key);
1019
1020 return bt_mesh_key_import(BT_MESH_KEY_TYPE_DEV, in, &node->dev_key);
1021 }
1022
bt_mesh_cdb_node_key_export(const struct bt_mesh_cdb_node * node,uint8_t out[16])1023 int bt_mesh_cdb_node_key_export(const struct bt_mesh_cdb_node *node, uint8_t out[16])
1024 {
1025 return bt_mesh_key_export(out, &node->dev_key);
1026 }
1027
bt_mesh_cdb_app_key_alloc(uint16_t net_idx,uint16_t app_idx)1028 struct bt_mesh_cdb_app_key *bt_mesh_cdb_app_key_alloc(uint16_t net_idx, uint16_t app_idx)
1029 {
1030 struct bt_mesh_cdb_app_key *key;
1031 struct bt_mesh_cdb_app_key *vacant_key = NULL;
1032 int i;
1033
1034 for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.app_keys); ++i) {
1035 key = &bt_mesh_cdb.app_keys[i];
1036
1037 if (key->app_idx == app_idx) {
1038 return NULL;
1039 }
1040
1041 if (key->net_idx != BT_MESH_KEY_UNUSED || vacant_key) {
1042 continue;
1043 }
1044
1045 vacant_key = key;
1046 }
1047
1048 if (vacant_key) {
1049 vacant_key->net_idx = net_idx;
1050 vacant_key->app_idx = app_idx;
1051 }
1052
1053 return vacant_key;
1054 }
1055
bt_mesh_cdb_app_key_del(struct bt_mesh_cdb_app_key * key,bool store)1056 void bt_mesh_cdb_app_key_del(struct bt_mesh_cdb_app_key *key, bool store)
1057 {
1058 LOG_DBG("AppIdx 0x%03x store %u", key->app_idx, store);
1059
1060 if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) {
1061 update_cdb_app_key_settings(key, false);
1062 }
1063
1064 key->net_idx = BT_MESH_KEY_UNUSED;
1065 key->app_idx = BT_MESH_KEY_UNUSED;
1066 bt_mesh_key_destroy(&key->keys[0].app_key);
1067 bt_mesh_key_destroy(&key->keys[1].app_key);
1068 memset(key->keys, 0, sizeof(key->keys));
1069 }
1070
bt_mesh_cdb_app_key_get(uint16_t app_idx)1071 struct bt_mesh_cdb_app_key *bt_mesh_cdb_app_key_get(uint16_t app_idx)
1072 {
1073 int i;
1074
1075 for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.app_keys); i++) {
1076 struct bt_mesh_cdb_app_key *key = &bt_mesh_cdb.app_keys[i];
1077
1078 if (key->net_idx != BT_MESH_KEY_UNUSED &&
1079 key->app_idx == app_idx) {
1080 return key;
1081 }
1082 }
1083
1084 return NULL;
1085 }
1086
bt_mesh_cdb_app_key_store(const struct bt_mesh_cdb_app_key * key)1087 void bt_mesh_cdb_app_key_store(const struct bt_mesh_cdb_app_key *key)
1088 {
1089 if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
1090 update_cdb_app_key_settings(key, true);
1091 }
1092 }
1093
bt_mesh_cdb_app_key_import(struct bt_mesh_cdb_app_key * key,int key_idx,const uint8_t in[16])1094 int bt_mesh_cdb_app_key_import(struct bt_mesh_cdb_app_key *key, int key_idx, const uint8_t in[16])
1095 {
1096 if (!bt_mesh_key_compare(in, &key->keys[key_idx].app_key)) {
1097 return 0;
1098 }
1099
1100 bt_mesh_key_destroy(&key->keys[key_idx].app_key);
1101
1102 return bt_mesh_key_import(BT_MESH_KEY_TYPE_APP, in, &key->keys[key_idx].app_key);
1103 }
1104
bt_mesh_cdb_app_key_export(const struct bt_mesh_cdb_app_key * key,int key_idx,uint8_t out[16])1105 int bt_mesh_cdb_app_key_export(const struct bt_mesh_cdb_app_key *key, int key_idx, uint8_t out[16])
1106 {
1107 return bt_mesh_key_export(out, &key->keys[key_idx].app_key);
1108 }
1109
clear_cdb_net(void)1110 static void clear_cdb_net(void)
1111 {
1112 int err;
1113
1114 err = settings_delete("bt/mesh/cdb/Net");
1115 if (err) {
1116 LOG_ERR("Failed to clear Network");
1117 } else {
1118 LOG_DBG("Cleared Network");
1119 }
1120 }
1121
store_cdb_pending_net(void)1122 static void store_cdb_pending_net(void)
1123 {
1124 struct net_val net;
1125 int err;
1126
1127 LOG_DBG("");
1128
1129 net.iv.index = bt_mesh_cdb.iv_index;
1130 net.iv.update = atomic_test_bit(bt_mesh_cdb.flags,
1131 BT_MESH_CDB_IVU_IN_PROGRESS);
1132 net.lowest_avail_addr = bt_mesh_cdb.lowest_avail_addr;
1133
1134 err = settings_save_one("bt/mesh/cdb/Net", &net, sizeof(net));
1135 if (err) {
1136 LOG_ERR("Failed to store Network value");
1137 } else {
1138 LOG_DBG("Stored Network value");
1139 }
1140 }
1141
store_cdb_pending_nodes(void)1142 static void store_cdb_pending_nodes(void)
1143 {
1144 int i;
1145
1146 for (i = 0; i < ARRAY_SIZE(cdb_node_updates); ++i) {
1147 struct node_update *update = &cdb_node_updates[i];
1148 uint16_t addr;
1149
1150 if (update->addr == BT_MESH_ADDR_UNASSIGNED) {
1151 continue;
1152 }
1153
1154 addr = update->addr;
1155 update->addr = BT_MESH_ADDR_UNASSIGNED;
1156
1157 LOG_DBG("addr: 0x%04x, clear: %d", addr, update->clear);
1158
1159 if (update->clear) {
1160 clear_cdb_node(addr);
1161 } else {
1162 struct bt_mesh_cdb_node *node;
1163
1164 node = bt_mesh_cdb_node_get(addr);
1165 if (node) {
1166 store_cdb_node(node);
1167 } else {
1168 LOG_WRN("Node 0x%04x not found", addr);
1169 }
1170 }
1171 }
1172 }
1173
store_cdb_pending_keys(void)1174 static void store_cdb_pending_keys(void)
1175 {
1176 int i;
1177
1178 for (i = 0; i < ARRAY_SIZE(cdb_key_updates); i++) {
1179 struct key_update *update = &cdb_key_updates[i];
1180
1181 if (!update->valid) {
1182 continue;
1183 }
1184
1185 update->valid = 0U;
1186
1187 if (update->clear) {
1188 if (update->app_key) {
1189 clear_cdb_app_key(update->key_idx);
1190 } else {
1191 clear_cdb_subnet(update->key_idx);
1192 }
1193 } else {
1194 if (update->app_key) {
1195 struct bt_mesh_cdb_app_key *key;
1196
1197 key = bt_mesh_cdb_app_key_get(update->key_idx);
1198 if (key) {
1199 store_cdb_app_key(key);
1200 } else {
1201 LOG_WRN("AppKeyIndex 0x%03x not found", update->key_idx);
1202 }
1203 } else {
1204 struct bt_mesh_cdb_subnet *sub;
1205
1206 sub = bt_mesh_cdb_subnet_get(update->key_idx);
1207 if (sub) {
1208 store_cdb_subnet(sub);
1209 } else {
1210 LOG_WRN("NetKeyIndex 0x%03x not found", update->key_idx);
1211 }
1212 }
1213 }
1214 }
1215 }
1216
bt_mesh_cdb_pending_store(void)1217 void bt_mesh_cdb_pending_store(void)
1218 {
1219 if (atomic_test_and_clear_bit(bt_mesh_cdb.flags,
1220 BT_MESH_CDB_SUBNET_PENDING)) {
1221 if (atomic_test_bit(bt_mesh_cdb.flags,
1222 BT_MESH_CDB_VALID)) {
1223 store_cdb_pending_net();
1224 } else {
1225 clear_cdb_net();
1226 }
1227 }
1228
1229 if (atomic_test_and_clear_bit(bt_mesh_cdb.flags,
1230 BT_MESH_CDB_NODES_PENDING)) {
1231 store_cdb_pending_nodes();
1232 }
1233
1234 if (atomic_test_and_clear_bit(bt_mesh_cdb.flags,
1235 BT_MESH_CDB_KEYS_PENDING)) {
1236 store_cdb_pending_keys();
1237 }
1238 }
1239