1 /*
2  * Copyright (c) 2017 Intel Corporation
3  * Copyright (c) 2023 Nordic Semiconductor ASA
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <zephyr/kernel.h>
9 #include <errno.h>
10 #include <string.h>
11 #include <stdlib.h>
12 
13 #include <zephyr/settings/settings.h>
14 #include <zephyr/net/buf.h>
15 
16 #include <zephyr/bluetooth/mesh.h>
17 
18 #include "common/bt_str.h"
19 
20 #include "va.h"
21 #include "foundation.h"
22 #include "msg.h"
23 #include "net.h"
24 #include "crypto.h"
25 #include "settings.h"
26 
27 #define LOG_LEVEL CONFIG_BT_MESH_TRANS_LOG_LEVEL
28 #include <zephyr/logging/log.h>
29 LOG_MODULE_REGISTER(bt_mesh_va);
30 
31 static struct bt_mesh_va virtual_addrs[CONFIG_BT_MESH_LABEL_COUNT];
32 
33 /* Virtual Address information for persistent storage. */
34 struct va_val {
35 	uint16_t ref;
36 	uint16_t addr;
37 	uint8_t uuid[16];
38 } __packed;
39 
va_store(struct bt_mesh_va * store)40 static void va_store(struct bt_mesh_va *store)
41 {
42 	store->changed = 1U;
43 
44 	if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
45 		bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_VA_PENDING);
46 	}
47 }
48 
bt_mesh_va_add(const uint8_t uuid[16],const struct bt_mesh_va ** entry)49 uint8_t bt_mesh_va_add(const uint8_t uuid[16], const struct bt_mesh_va **entry)
50 {
51 	struct bt_mesh_va *va = NULL;
52 	int err;
53 
54 	for (int i = 0; i < ARRAY_SIZE(virtual_addrs); i++) {
55 		if (!virtual_addrs[i].ref) {
56 			if (!va) {
57 				va = &virtual_addrs[i];
58 			}
59 
60 			continue;
61 		}
62 
63 		if (!memcmp(uuid, virtual_addrs[i].uuid,
64 			    ARRAY_SIZE(virtual_addrs[i].uuid))) {
65 			if (entry) {
66 				*entry = &virtual_addrs[i];
67 			}
68 			virtual_addrs[i].ref++;
69 			va_store(&virtual_addrs[i]);
70 			return STATUS_SUCCESS;
71 		}
72 	}
73 
74 	if (!va) {
75 		return STATUS_INSUFF_RESOURCES;
76 	}
77 
78 	memcpy(va->uuid, uuid, ARRAY_SIZE(va->uuid));
79 	err = bt_mesh_virtual_addr(uuid, &va->addr);
80 	if (err) {
81 		va->addr = BT_MESH_ADDR_UNASSIGNED;
82 		return STATUS_UNSPECIFIED;
83 	}
84 
85 	va->ref = 1;
86 	va_store(va);
87 
88 	if (entry) {
89 		*entry = va;
90 	}
91 
92 	return STATUS_SUCCESS;
93 }
94 
bt_mesh_va_del(const uint8_t * uuid)95 uint8_t bt_mesh_va_del(const uint8_t *uuid)
96 {
97 	struct bt_mesh_va *va;
98 
99 	if (CONFIG_BT_MESH_LABEL_COUNT == 0) {
100 		return STATUS_CANNOT_REMOVE;
101 	}
102 
103 	va = CONTAINER_OF(uuid, struct bt_mesh_va, uuid[0]);
104 
105 	if (!PART_OF_ARRAY(virtual_addrs, va) || va->ref == 0) {
106 		return STATUS_CANNOT_REMOVE;
107 	}
108 
109 	va->ref--;
110 	va_store(va);
111 
112 	return STATUS_SUCCESS;
113 }
114 
bt_mesh_va_uuid_get(uint16_t addr,const uint8_t * uuid,uint16_t * retaddr)115 const uint8_t *bt_mesh_va_uuid_get(uint16_t addr, const uint8_t *uuid, uint16_t *retaddr)
116 {
117 	int i = 0;
118 
119 	if (CONFIG_BT_MESH_LABEL_COUNT == 0) {
120 		return NULL;
121 	}
122 
123 	if (uuid != NULL) {
124 		struct bt_mesh_va *va;
125 
126 		va = CONTAINER_OF(uuid, struct bt_mesh_va, uuid[0]);
127 		i = ARRAY_INDEX(virtual_addrs, va);
128 	}
129 
130 	for (; i < ARRAY_SIZE(virtual_addrs); i++) {
131 		if (virtual_addrs[i].ref &&
132 		    (virtual_addrs[i].addr == addr || addr == BT_MESH_ADDR_UNASSIGNED)) {
133 			if (!uuid) {
134 				LOG_DBG("Found Label UUID for 0x%04x: %s", addr,
135 					bt_hex(virtual_addrs[i].uuid, 16));
136 
137 				if (retaddr) {
138 					*retaddr = virtual_addrs[i].addr;
139 				}
140 
141 				return virtual_addrs[i].uuid;
142 			} else if (uuid == virtual_addrs[i].uuid) {
143 				uuid = NULL;
144 			}
145 		}
146 	}
147 
148 	LOG_WRN("No matching Label UUID for 0x%04x", addr);
149 
150 	return NULL;
151 }
152 
bt_mesh_va_collision_check(uint16_t addr)153 bool bt_mesh_va_collision_check(uint16_t addr)
154 {
155 	size_t count = 0;
156 	const uint8_t *uuid = NULL;
157 
158 	do {
159 		uuid = bt_mesh_va_uuid_get(addr, uuid, NULL);
160 	} while (uuid && ++count);
161 
162 	return count > 1;
163 }
164 
bt_mesh_va_find(const uint8_t * uuid)165 const struct bt_mesh_va *bt_mesh_va_find(const uint8_t *uuid)
166 {
167 	int i;
168 
169 	for (i = 0; i < ARRAY_SIZE(virtual_addrs); i++) {
170 		if (virtual_addrs[i].ref && !memcmp(virtual_addrs[i].uuid, uuid, 16)) {
171 			return &virtual_addrs[i];
172 		}
173 	}
174 
175 	return NULL;
176 }
177 
va_get_by_idx(uint16_t index)178 static struct bt_mesh_va *va_get_by_idx(uint16_t index)
179 {
180 	if (index >= ARRAY_SIZE(virtual_addrs)) {
181 		return NULL;
182 	}
183 
184 	return &virtual_addrs[index];
185 }
186 
bt_mesh_va_get_uuid_by_idx(uint16_t idx)187 const uint8_t *bt_mesh_va_get_uuid_by_idx(uint16_t idx)
188 {
189 	struct bt_mesh_va *va;
190 
191 	va = va_get_by_idx(idx);
192 	return (va && va->ref > 0) ? va->uuid : NULL;
193 }
194 
bt_mesh_va_get_idx_by_uuid(const uint8_t * uuid,uint16_t * uuidx)195 int bt_mesh_va_get_idx_by_uuid(const uint8_t *uuid, uint16_t *uuidx)
196 {
197 	struct bt_mesh_va *va;
198 
199 	if (CONFIG_BT_MESH_LABEL_COUNT == 0) {
200 		return -ENOENT;
201 	}
202 
203 	va = CONTAINER_OF(uuid, struct bt_mesh_va, uuid[0]);
204 
205 	if (!PART_OF_ARRAY(virtual_addrs, va) || va->ref == 0) {
206 		return -ENOENT;
207 	}
208 
209 	*uuidx = ARRAY_INDEX(virtual_addrs, va);
210 	return 0;
211 }
212 
213 #if CONFIG_BT_MESH_LABEL_COUNT > 0
va_set(const char * name,size_t len_rd,settings_read_cb read_cb,void * cb_arg)214 static int va_set(const char *name, size_t len_rd,
215 		  settings_read_cb read_cb, void *cb_arg)
216 {
217 	struct va_val va;
218 	struct bt_mesh_va *lab;
219 	uint16_t index;
220 	int err;
221 
222 	if (!name) {
223 		LOG_ERR("Insufficient number of arguments");
224 		return -ENOENT;
225 	}
226 
227 	index = strtol(name, NULL, 16);
228 
229 	if (len_rd == 0) {
230 		LOG_WRN("Mesh Virtual Address length = 0");
231 		return 0;
232 	}
233 
234 	err = bt_mesh_settings_set(read_cb, cb_arg, &va, sizeof(va));
235 	if (err) {
236 		LOG_ERR("Failed to set \'virtual address\'");
237 		return err;
238 	}
239 
240 	if (va.ref == 0) {
241 		LOG_WRN("Ignore Mesh Virtual Address ref = 0");
242 		return 0;
243 	}
244 
245 	lab = va_get_by_idx(index);
246 	if (lab == NULL) {
247 		LOG_WRN("Out of labels buffers");
248 		return -ENOBUFS;
249 	}
250 
251 	memcpy(lab->uuid, va.uuid, 16);
252 	lab->addr = va.addr;
253 	lab->ref = va.ref;
254 
255 	LOG_DBG("Restored Virtual Address, addr 0x%04x ref 0x%04x", lab->addr, lab->ref);
256 
257 	return 0;
258 }
259 
260 BT_MESH_SETTINGS_DEFINE(va, "Va", va_set);
261 
262 #define IS_VA_DEL(_label)	((_label)->ref == 0)
bt_mesh_va_pending_store(void)263 void bt_mesh_va_pending_store(void)
264 {
265 	struct bt_mesh_va *lab;
266 	struct va_val va;
267 	char path[18];
268 	uint16_t i;
269 	int err;
270 
271 	for (i = 0; (lab = va_get_by_idx(i)) != NULL; i++) {
272 		if (!lab->changed) {
273 			continue;
274 		}
275 
276 		lab->changed = 0U;
277 
278 		snprintk(path, sizeof(path), "bt/mesh/Va/%x", i);
279 
280 		if (IS_VA_DEL(lab)) {
281 			err = settings_delete(path);
282 		} else {
283 			va.ref = lab->ref;
284 			va.addr = lab->addr;
285 			memcpy(va.uuid, lab->uuid, 16);
286 
287 			err = settings_save_one(path, &va, sizeof(va));
288 		}
289 
290 		if (err) {
291 			LOG_ERR("Failed to %s %s value (err %d)",
292 				IS_VA_DEL(lab) ? "delete" : "store", path, err);
293 		} else {
294 			LOG_DBG("%s %s value", IS_VA_DEL(lab) ? "Deleted" : "Stored", path);
295 		}
296 	}
297 }
298 #else
bt_mesh_va_pending_store(void)299 void bt_mesh_va_pending_store(void)
300 {
301 	/* Do nothing. */
302 }
303 #endif /* CONFIG_BT_MESH_LABEL_COUNT > 0 */
304 
bt_mesh_va_clear(void)305 void bt_mesh_va_clear(void)
306 {
307 	int i;
308 
309 	if (CONFIG_BT_MESH_LABEL_COUNT == 0) {
310 		return;
311 	}
312 
313 	for (i = 0; i < ARRAY_SIZE(virtual_addrs); i++) {
314 		if (virtual_addrs[i].ref) {
315 			virtual_addrs[i].ref = 0U;
316 			virtual_addrs[i].changed = 1U;
317 		}
318 	}
319 
320 	if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
321 		bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_VA_PENDING);
322 	}
323 }
324