1 /*
2  * Copyright (c) 2022 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/bluetooth/mesh.h>
8 #include <zephyr/sys/byteorder.h>
9 #include <stdlib.h>
10 
11 #include <zephyr/bluetooth/bluetooth.h>
12 #include <zephyr/bluetooth/hci.h>
13 #include <zephyr/bluetooth/uuid.h>
14 #include "access.h"
15 #include "cfg.h"
16 #include "crypto.h"
17 #include "mesh.h"
18 #include "net.h"
19 #include "proxy.h"
20 #include "settings.h"
21 
22 #include "common/bt_str.h"
23 
24 #include "host/hci_core.h"
25 
26 #define LOG_LEVEL CONFIG_BT_MESH_MODEL_LOG_LEVEL
27 #include <zephyr/logging/log.h>
28 LOG_MODULE_REGISTER(bt_mesh_solicitation);
29 
30 #if CONFIG_BT_MESH_OD_PRIV_PROXY_SRV
31 static struct srpl_entry {
32 	uint32_t sseq;
33 	uint16_t ssrc;
34 } sol_pdu_rpl[CONFIG_BT_MESH_PROXY_SRPL_SIZE];
35 
36 static ATOMIC_DEFINE(store, CONFIG_BT_MESH_PROXY_SRPL_SIZE);
37 static atomic_t clear;
38 #endif
39 #if CONFIG_BT_MESH_PROXY_SOLICITATION
40 static uint32_t sseq_out;
41 #endif
42 
43 #if CONFIG_BT_MESH_OD_PRIV_PROXY_SRV
srpl_find_by_addr(uint16_t ssrc)44 static struct srpl_entry *srpl_find_by_addr(uint16_t ssrc)
45 {
46 	int i;
47 
48 	for (i = 0; i < ARRAY_SIZE(sol_pdu_rpl); i++) {
49 		if (sol_pdu_rpl[i].ssrc == ssrc) {
50 			return &sol_pdu_rpl[i];
51 		}
52 	}
53 
54 	return NULL;
55 }
56 
srpl_entry_save(struct bt_mesh_subnet * sub,uint32_t sseq,uint16_t ssrc)57 static int srpl_entry_save(struct bt_mesh_subnet *sub, uint32_t sseq, uint16_t ssrc)
58 {
59 	struct srpl_entry *entry;
60 
61 	if (!BT_MESH_ADDR_IS_UNICAST(ssrc)) {
62 		LOG_DBG("Addr not in unicast range");
63 		return -EINVAL;
64 	}
65 
66 	entry = srpl_find_by_addr(ssrc);
67 	if (entry) {
68 		if (entry->sseq >= sseq) {
69 			LOG_WRN("Higher or equal SSEQ already saved for this SSRC");
70 			return -EALREADY;
71 		}
72 
73 	} else {
74 		entry = srpl_find_by_addr(BT_MESH_ADDR_UNASSIGNED);
75 		if (!entry) {
76 			/* No space to save new PDU in RPL for this SSRC
77 			 * and this PDU is first for this SSRC
78 			 */
79 			return -ENOMEM;
80 		}
81 	}
82 
83 	entry->sseq = sseq;
84 	entry->ssrc = ssrc;
85 
86 	LOG_DBG("Added: SSRC %d SSEQ %d to SRPL", entry->ssrc, entry->sseq);
87 
88 	if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
89 		atomic_set_bit(store, entry - &sol_pdu_rpl[0]);
90 		bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_SRPL_PENDING);
91 	}
92 
93 	return 0;
94 }
95 #endif
96 
bt_mesh_sseq_pending_store(void)97 void bt_mesh_sseq_pending_store(void)
98 {
99 #if CONFIG_BT_MESH_PROXY_SOLICITATION
100 	char *path = "bt/mesh/SSeq";
101 	int err;
102 
103 	if (sseq_out) {
104 		err = settings_save_one(path, &sseq_out, sizeof(sseq_out));
105 	} else {
106 		err = settings_delete(path);
107 	}
108 
109 	if (err) {
110 		LOG_ERR("Failed to %s SSeq %s value", (sseq_out == 0 ? "delete" : "store"), path);
111 	} else {
112 		LOG_DBG("%s %s value", (sseq_out == 0 ? "Deleted" : "Stored"), path);
113 	}
114 #endif
115 }
116 
117 #if CONFIG_BT_MESH_PROXY_SOLICITATION
sseq_set(const char * name,size_t len_rd,settings_read_cb read_cb,void * cb_arg)118 static int sseq_set(const char *name, size_t len_rd,
119 		    settings_read_cb read_cb, void *cb_arg)
120 {
121 	int err;
122 
123 	err = bt_mesh_settings_set(read_cb, cb_arg, &sseq_out, sizeof(sseq_out));
124 	if (err) {
125 		LOG_ERR("Failed to set \'sseq\'");
126 		return err;
127 	}
128 
129 	LOG_DBG("Restored SSeq value 0x%06x", sseq_out);
130 
131 	return 0;
132 }
133 
134 BT_MESH_SETTINGS_DEFINE(sseq, "SSeq", sseq_set);
135 #endif
136 
137 #if CONFIG_BT_MESH_OD_PRIV_PROXY_SRV
sol_pdu_decrypt(struct bt_mesh_subnet * sub,void * data)138 static bool sol_pdu_decrypt(struct bt_mesh_subnet *sub, void *data)
139 {
140 	struct net_buf_simple *in = data;
141 	struct net_buf_simple *out = NET_BUF_SIMPLE(17);
142 	int err, i;
143 	uint32_t sseq;
144 	uint16_t ssrc;
145 
146 	for (i = 0; i < ARRAY_SIZE(sub->keys); i++) {
147 		if (!sub->keys[i].valid) {
148 			LOG_ERR("invalid keys %d", i);
149 			continue;
150 		}
151 
152 		net_buf_simple_init(out, 0);
153 		net_buf_simple_add_mem(out, in->data, in->len);
154 
155 		err = bt_mesh_net_obfuscate(out->data, 0, &sub->keys[i].msg.privacy);
156 		if (err) {
157 			LOG_DBG("obfuscation err %d", err);
158 			continue;
159 		}
160 		err = bt_mesh_net_decrypt(&sub->keys[i].msg.enc, out,
161 					  0, BT_MESH_NONCE_SOLICITATION);
162 		if (!err) {
163 			LOG_DBG("Decrypted PDU %s", bt_hex(out->data, out->len));
164 			memcpy(&sseq, &out->data[2], 3);
165 			memcpy(&ssrc, &out->data[5], 2);
166 			err = srpl_entry_save(sub,
167 					     sys_be24_to_cpu(sseq),
168 					     sys_be16_to_cpu(ssrc));
169 			return err ? false : true;
170 		}
171 		LOG_DBG("decrypt err %d", err);
172 	}
173 
174 	return false;
175 }
176 #endif
177 
bt_mesh_sol_recv(struct net_buf_simple * buf,uint8_t uuid_list_len)178 void bt_mesh_sol_recv(struct net_buf_simple *buf, uint8_t uuid_list_len)
179 {
180 #if CONFIG_BT_MESH_OD_PRIV_PROXY_SRV
181 	uint8_t type;
182 	struct bt_mesh_subnet *sub;
183 	uint16_t uuid;
184 	uint8_t reported_len;
185 	uint8_t svc_data_type;
186 	bool sol_uuid_found = false;
187 	bool svc_data_found = false;
188 
189 	if (bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED ||
190 	    bt_mesh_priv_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED ||
191 	    bt_mesh_od_priv_proxy_get() == 0) {
192 		LOG_DBG("Not soliciting");
193 		return;
194 	}
195 
196 	/* Get rid of ad_type that was checked in bt_mesh_scan_cb */
197 	type = net_buf_simple_pull_u8(buf);
198 	if (type != BT_DATA_UUID16_SOME && type != BT_DATA_UUID16_ALL) {
199 		LOG_DBG("Invalid type 0x%x, expected 0x%x or 0x%x",
200 			type, BT_DATA_UUID16_SOME, BT_DATA_UUID16_ALL);
201 		return;
202 	}
203 
204 	if (buf->len < 24) {
205 		LOG_DBG("Invalid length (%u) Solicitation PDU", buf->len);
206 		return;
207 	}
208 
209 	while (uuid_list_len >= 2) {
210 		uuid = net_buf_simple_pull_le16(buf);
211 		if (uuid == BT_UUID_MESH_PROXY_SOLICITATION_VAL) {
212 			sol_uuid_found = true;
213 		}
214 		uuid_list_len -= 2;
215 	}
216 
217 	if (!sol_uuid_found) {
218 		LOG_DBG("No solicitation UUID found");
219 		return;
220 	}
221 
222 	while (buf->len >= 22) {
223 		reported_len = net_buf_simple_pull_u8(buf);
224 		svc_data_type = net_buf_simple_pull_u8(buf);
225 		uuid = net_buf_simple_pull_le16(buf);
226 
227 		if (reported_len == 21 && svc_data_type == BT_DATA_SVC_DATA16 &&
228 		    uuid == BT_UUID_MESH_PROXY_SOLICITATION_VAL) {
229 			svc_data_found = true;
230 			break;
231 		}
232 
233 		if (buf->len <= reported_len - 3) {
234 			LOG_DBG("Invalid length (%u) Solicitation PDU", buf->len);
235 			return;
236 		}
237 
238 		net_buf_simple_pull_mem(buf, reported_len - 3);
239 	}
240 
241 	if (!svc_data_found) {
242 		LOG_DBG("No solicitation service data found");
243 		return;
244 	}
245 
246 	type = net_buf_simple_pull_u8(buf);
247 	if (type != 0) {
248 		LOG_DBG("Invalid type %d, expected 0x00", type);
249 		return;
250 	}
251 
252 	sub = bt_mesh_subnet_find(sol_pdu_decrypt, (void *)buf);
253 	if (!sub) {
254 		LOG_DBG("Unable to find subnetwork for received solicitation PDU");
255 		return;
256 	}
257 
258 	LOG_DBG("Decrypted solicitation PDU for existing subnet");
259 
260 	sub->solicited = true;
261 	bt_mesh_adv_gatt_update();
262 #endif
263 }
264 
265 
bt_mesh_proxy_solicit(uint16_t net_idx)266 int bt_mesh_proxy_solicit(uint16_t net_idx)
267 {
268 #if CONFIG_BT_MESH_PROXY_SOLICITATION
269 	struct bt_mesh_subnet *sub;
270 
271 	sub = bt_mesh_subnet_get(net_idx);
272 	if (!sub) {
273 		LOG_ERR("No subnet with net_idx %d", net_idx);
274 		return -EINVAL;
275 	}
276 
277 	if (sub->sol_tx == true) {
278 		LOG_ERR("Solicitation already scheduled for this subnet");
279 		return -EALREADY;
280 	}
281 
282 	/* SSeq reached its maximum value */
283 	if (sseq_out > 0xFFFFFF) {
284 		LOG_ERR("SSeq out of range");
285 		return -EOVERFLOW;
286 	}
287 
288 	sub->sol_tx = true;
289 
290 	bt_mesh_adv_gatt_update();
291 	return 0;
292 #else
293 	return -ENOTSUP;
294 #endif
295 }
296 
297 #if CONFIG_BT_MESH_PROXY_SOLICITATION
sol_pdu_create(struct bt_mesh_subnet * sub,struct net_buf_simple * pdu)298 static int sol_pdu_create(struct bt_mesh_subnet *sub, struct net_buf_simple *pdu)
299 {
300 	int err;
301 
302 	net_buf_simple_add_u8(pdu, sub->keys[SUBNET_KEY_TX_IDX(sub)].msg.nid);
303 	/* CTL = 1, TTL = 0 */
304 	net_buf_simple_add_u8(pdu, 0x80);
305 	net_buf_simple_add_le24(pdu, sys_cpu_to_be24(sseq_out));
306 	net_buf_simple_add_le16(pdu, sys_cpu_to_be16(bt_mesh_primary_addr()));
307 	/* DST = 0x0000 */
308 	net_buf_simple_add_le16(pdu, 0x0000);
309 
310 	err = bt_mesh_net_encrypt(&sub->keys[SUBNET_KEY_TX_IDX(sub)].msg.enc,
311 				  pdu, 0, BT_MESH_NONCE_SOLICITATION);
312 
313 	if (err) {
314 		LOG_ERR("Encryption failed, err=%d", err);
315 		return err;
316 	}
317 
318 	err = bt_mesh_net_obfuscate(pdu->data, 0,
319 				    &sub->keys[SUBNET_KEY_TX_IDX(sub)].msg.privacy);
320 	if (err) {
321 		LOG_ERR("Obfuscation failed, err=%d", err);
322 		return err;
323 	}
324 
325 	net_buf_simple_push_u8(pdu, 0);
326 	net_buf_simple_push_le16(pdu, BT_UUID_MESH_PROXY_SOLICITATION_VAL);
327 
328 	return 0;
329 }
330 #endif
331 
332 #if CONFIG_BT_MESH_OD_PRIV_PROXY_SRV
srpl_set(const char * name,size_t len_rd,settings_read_cb read_cb,void * cb_arg)333 static int srpl_set(const char *name, size_t len_rd,
334 		   settings_read_cb read_cb, void *cb_arg)
335 {
336 	struct srpl_entry *entry;
337 	int err;
338 	uint16_t ssrc;
339 	uint32_t sseq;
340 
341 	if (!name) {
342 		LOG_ERR("Insufficient number of arguments");
343 		return -ENOENT;
344 	}
345 
346 	ssrc = strtol(name, NULL, 16);
347 	entry = srpl_find_by_addr(ssrc);
348 
349 	if (len_rd == 0) {
350 		LOG_DBG("val (null)");
351 		if (entry) {
352 			(void)memset(entry, 0, sizeof(*entry));
353 		} else {
354 			LOG_WRN("Unable to find RPL entry for 0x%04x", ssrc);
355 		}
356 
357 		return 0;
358 	}
359 
360 	if (!entry) {
361 		entry = srpl_find_by_addr(BT_MESH_ADDR_UNASSIGNED);
362 		if (!entry) {
363 			LOG_ERR("Unable to allocate SRPL entry for 0x%04x", ssrc);
364 			return -ENOMEM;
365 		}
366 	}
367 
368 	err = bt_mesh_settings_set(read_cb, cb_arg, &sseq, sizeof(sseq));
369 	if (err) {
370 		LOG_ERR("Failed to set \'sseq\'");
371 		return err;
372 	}
373 
374 	entry->ssrc = ssrc;
375 	entry->sseq = sseq;
376 
377 	LOG_DBG("SRPL entry for 0x%04x: Seq 0x%06x", entry->ssrc,
378 	       entry->sseq);
379 
380 	return 0;
381 }
382 
383 BT_MESH_SETTINGS_DEFINE(srpl, "SRPL", srpl_set);
384 #endif
385 
386 #if CONFIG_BT_MESH_OD_PRIV_PROXY_SRV
srpl_entry_clear(int i)387 static void srpl_entry_clear(int i)
388 {
389 	uint16_t addr = sol_pdu_rpl[i].ssrc;
390 
391 	LOG_DBG("Removing entry SSRC: %d, SSEQ: %d from RPL",
392 		sol_pdu_rpl[i].ssrc,
393 		sol_pdu_rpl[i].sseq);
394 	sol_pdu_rpl[i].ssrc = 0;
395 	sol_pdu_rpl[i].sseq = 0;
396 
397 	atomic_clear_bit(store, i);
398 
399 	if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
400 		char path[18];
401 
402 		snprintk(path, sizeof(path), "bt/mesh/SRPL/%x", addr);
403 
404 		settings_delete(path);
405 	}
406 }
407 
srpl_store(struct srpl_entry * entry)408 static void srpl_store(struct srpl_entry *entry)
409 {
410 	char path[18];
411 	int err;
412 
413 	LOG_DBG("src 0x%04x seq 0x%06x", entry->ssrc, entry->sseq);
414 
415 	snprintk(path, sizeof(path), "bt/mesh/SRPL/%x", entry->ssrc);
416 
417 	err = settings_save_one(path, &entry->sseq, sizeof(entry->sseq));
418 	if (err) {
419 		LOG_ERR("Failed to store RPL %s value", path);
420 	} else {
421 		LOG_DBG("Stored RPL %s value", path);
422 	}
423 }
424 #endif
425 
bt_mesh_srpl_pending_store(void)426 void bt_mesh_srpl_pending_store(void)
427 {
428 #if CONFIG_BT_MESH_OD_PRIV_PROXY_SRV
429 	bool clr;
430 
431 	clr = atomic_cas(&clear, 1, 0);
432 
433 	for (int i = 0; i < ARRAY_SIZE(sol_pdu_rpl); i++) {
434 		LOG_DBG("src 0x%04x seq 0x%06x", sol_pdu_rpl[i].ssrc, sol_pdu_rpl[i].sseq);
435 
436 		if (clr) {
437 			srpl_entry_clear(i);
438 		} else if (atomic_test_and_clear_bit(store, i)) {
439 			srpl_store(&sol_pdu_rpl[i]);
440 		}
441 	}
442 #endif
443 }
444 
bt_mesh_srpl_entry_clear(uint16_t addr)445 void bt_mesh_srpl_entry_clear(uint16_t addr)
446 {
447 #if CONFIG_BT_MESH_OD_PRIV_PROXY_SRV
448 	struct srpl_entry *entry;
449 
450 	if (!BT_MESH_ADDR_IS_UNICAST(addr)) {
451 		LOG_DBG("Addr not in unicast range");
452 		return;
453 	}
454 
455 	entry = srpl_find_by_addr(addr);
456 	if (!entry) {
457 		return;
458 	}
459 
460 	srpl_entry_clear(entry - &sol_pdu_rpl[0]);
461 #endif
462 }
463 
bt_mesh_sol_reset(void)464 void bt_mesh_sol_reset(void)
465 {
466 #if CONFIG_BT_MESH_PROXY_SOLICITATION
467 	sseq_out = 0;
468 
469 	if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
470 		bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_SSEQ_PENDING);
471 	}
472 #endif
473 
474 #if CONFIG_BT_MESH_OD_PRIV_PROXY_SRV
475 	if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
476 		(void)atomic_cas(&clear, 0, 1);
477 
478 		bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_SRPL_PENDING);
479 	}
480 #endif
481 }
482 
483 #if CONFIG_BT_MESH_PROXY_SOLICITATION
sol_subnet_find(struct bt_mesh_subnet * sub,void * cb_data)484 static bool sol_subnet_find(struct bt_mesh_subnet *sub, void *cb_data)
485 {
486 	return sub->sol_tx;
487 }
488 #endif
489 
bt_mesh_sol_send(void)490 int bt_mesh_sol_send(void)
491 {
492 #if CONFIG_BT_MESH_PROXY_SOLICITATION
493 	uint16_t adv_int;
494 	struct bt_mesh_subnet *sub;
495 	int err;
496 
497 	NET_BUF_SIMPLE_DEFINE(pdu, 20);
498 
499 	sub = bt_mesh_subnet_find(sol_subnet_find, NULL);
500 	if (!sub) {
501 		return -ENOENT;
502 	}
503 
504 	/* SSeq reached its maximum value */
505 	if (sseq_out > 0xFFFFFF) {
506 		LOG_ERR("SSeq out of range");
507 		sub->sol_tx = false;
508 		return -EOVERFLOW;
509 	}
510 
511 	net_buf_simple_init(&pdu, 3);
512 
513 	adv_int = BT_MESH_TRANSMIT_INT(CONFIG_BT_MESH_SOL_ADV_XMIT);
514 
515 	err = sol_pdu_create(sub, &pdu);
516 	if (err) {
517 		LOG_ERR("Failed to create Solicitation PDU, err=%d", err);
518 		return err;
519 	}
520 
521 	struct bt_data ad[] = {
522 		BT_DATA_BYTES(BT_DATA_FLAGS,
523 			      (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
524 		BT_DATA_BYTES(BT_DATA_UUID16_ALL,
525 			      BT_UUID_16_ENCODE(
526 				      BT_UUID_MESH_PROXY_SOLICITATION_VAL)),
527 		BT_DATA(BT_DATA_SVC_DATA16, pdu.data, pdu.size),
528 	};
529 
530 	err = bt_mesh_adv_bt_data_send(CONFIG_BT_MESH_SOL_ADV_XMIT,
531 				       adv_int, ad, 3);
532 	if (err) {
533 		LOG_ERR("Failed to advertise Solicitation PDU, err=%d", err);
534 
535 		sub->sol_tx = false;
536 
537 		return err;
538 	}
539 	sub->sol_tx = false;
540 
541 	sseq_out++;
542 
543 	if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
544 		bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_SSEQ_PENDING);
545 	}
546 
547 	return 0;
548 #else
549 	return -ENOTSUP;
550 #endif
551 }
552