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