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