1 /*
2 * Copyright (c) 2019 Tobias Svehagen
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "syscfg/syscfg.h"
8 #define MESH_LOG_MODULE BLE_MESH_PROV_LOG
9
10 #if MYNEWT_VAL(BLE_MESH_PROVISIONER)
11
12 #include "mesh/mesh.h"
13
14 #include "mesh_priv.h"
15 #include "net.h"
16 #include "access.h"
17 #include "settings.h"
18
19 /*
20 * Check if an address range from addr_start for addr_start + num_elem - 1 is
21 * free for use. When a conflict is found, next will be set to the next address
22 * available after the conflicting range and -EAGAIN will be returned.
23 */
addr_is_free(u16_t addr_start,u8_t num_elem,u16_t * next)24 static int addr_is_free(u16_t addr_start, u8_t num_elem, u16_t *next)
25 {
26 const struct bt_mesh_comp *comp = bt_mesh_comp_get();
27 u16_t addr_end = addr_start + num_elem - 1;
28 u16_t other_start, other_end;
29 int i;
30
31 if (comp == NULL) {
32 return -EINVAL;
33 }
34
35 if (!BT_MESH_ADDR_IS_UNICAST(addr_start) ||
36 !BT_MESH_ADDR_IS_UNICAST(addr_end) || num_elem == 0 || next == NULL) {
37 return -EINVAL;
38 }
39
40 other_start = bt_mesh_primary_addr();
41 other_end = other_start + comp->elem_count - 1;
42
43 /* Compare with local element addresses */
44 if (!(addr_end < other_start || addr_start > other_end)) {
45 *next = other_end + 1;
46 return -EAGAIN;
47 }
48
49 for (i = 0; i < ARRAY_SIZE(bt_mesh.nodes); i++) {
50 struct bt_mesh_node *node = &bt_mesh.nodes[i];
51
52 if (node->net_idx == BT_MESH_KEY_UNUSED) {
53 continue;
54 }
55
56 other_start = node->addr;
57 other_end = other_start + node->num_elem - 1;
58
59 if (!(addr_end < other_start || addr_start > other_end)) {
60 *next = other_end + 1;
61 return -EAGAIN;
62 }
63 }
64
65 return 0;
66 }
67
68 /*
69 * Find the lowest possible starting address that can fit num_elem elements. If
70 * a free address range cannot be found, BT_MESH_ADDR_UNASSIGNED will be
71 * returned. Otherwise the first address in the range is returned.
72 *
73 * NOTE: This is quite an ineffective algorithm as it might need to look
74 * through the array of nodes N+2 times. A more effective algorithm
75 * could be used if the nodes were stored in a sorted list.
76 */
find_lowest_free_addr(u8_t num_elem)77 static u16_t find_lowest_free_addr(u8_t num_elem)
78 {
79 u16_t addr = 1, next;
80 int err, i;
81
82 /*
83 * It takes a maximum of node count + 2 to find a free address if there
84 * is any. +1 for our own address and +1 for making sure that the
85 * address range is valid.
86 */
87 for (i = 0; i < ARRAY_SIZE(bt_mesh.nodes) + 2; ++i) { // 2:byte alignment
88 err = addr_is_free(addr, num_elem, &next);
89 if (err == 0) {
90 break;
91 } else if (err != -EAGAIN) {
92 addr = BT_MESH_ADDR_UNASSIGNED;
93 break;
94 }
95
96 addr = next;
97 }
98
99 return addr;
100 }
101
bt_mesh_node_find(u16_t addr)102 struct bt_mesh_node *bt_mesh_node_find(u16_t addr)
103 {
104 int i;
105
106 for (i = 0; i < ARRAY_SIZE(bt_mesh.nodes); i++) {
107 struct bt_mesh_node *node = &bt_mesh.nodes[i];
108
109 if (addr >= node->addr &&
110 addr <= node->addr + node->num_elem - 1) {
111 return node;
112 }
113 }
114
115 return NULL;
116 }
117
bt_mesh_node_alloc(u16_t addr,u8_t num_elem,u16_t net_idx)118 struct bt_mesh_node *bt_mesh_node_alloc(u16_t addr, u8_t num_elem,
119 u16_t net_idx)
120 {
121 int i;
122 BT_DBG("");
123
124 if (addr == BT_MESH_ADDR_UNASSIGNED) {
125 addr = find_lowest_free_addr(num_elem);
126 if (addr == BT_MESH_ADDR_UNASSIGNED) {
127 return NULL;
128 }
129 } else if (!addr_is_free(addr, num_elem, NULL)) {
130 return NULL;
131 }
132
133 for (i = 0; i < ARRAY_SIZE(bt_mesh.nodes); i++) {
134 struct bt_mesh_node *node = &bt_mesh.nodes[i];
135
136 if (node->addr == BT_MESH_ADDR_UNASSIGNED) {
137 node->addr = addr;
138 node->num_elem = num_elem;
139 node->net_idx = net_idx;
140 return node;
141 }
142 }
143
144 return NULL;
145 }
146
bt_mesh_node_del(struct bt_mesh_node * node,bool store)147 void bt_mesh_node_del(struct bt_mesh_node *node, bool store)
148 {
149 BT_DBG("Node addr 0x%04x store %u", node->addr, store);
150
151 if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) {
152 bt_mesh_clear_node(node);
153 }
154
155 node->addr = BT_MESH_ADDR_UNASSIGNED;
156 (void)memset(node->dev_key, 0, sizeof(node->dev_key));
157 }
158
159 #endif
160