• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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