1 /* 2 * Copyright (C) 2018 BlueKitchen GmbH 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the copyright holders nor the names of 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 4. Any redistribution, use, or modification is done solely for 17 * personal benefit and not for any commercial purpose or for 18 * monetary gain. 19 * 20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24 * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * Please inquire about commercial licensing options at 34 * [email protected] 35 * 36 */ 37 38 #define __BTSTACK_FILE__ "mesh_network.c" 39 40 #include <stdint.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include "mesh/beacon.h" 45 #include "provisioning.h" 46 #include "provisioning_device.h" 47 #include "mesh_keys.h" 48 #include "btstack_util.h" 49 #include "btstack_memory.h" 50 51 #ifdef ENABLE_MESH_ADV_BEARER 52 #include "mesh/adv_bearer.h" 53 #endif 54 55 #ifdef ENABLE_MESH_GATT_BEARER 56 #include "mesh/gatt_bearer.h" 57 #endif 58 59 // configuration 60 #define MESH_NETWORK_CACHE_SIZE 2 61 // #define ENABLE_MESH_RELAY 62 63 // debug config 64 // #define LOG_NETWORK 65 66 // structs 67 68 // globals 69 70 static uint32_t global_iv_index; 71 static uint16_t mesh_network_primary_address; 72 static uint16_t mesh_network_num_elements; 73 static void (*mesh_network_higher_layer_handler)(mesh_network_callback_type_t callback_type, mesh_network_pdu_t * network_pdu); 74 static void (*mesh_network_proxy_message_handler)(mesh_network_callback_type_t callback_type, mesh_network_pdu_t * network_pdu); 75 76 // shared send/receive crypto 77 static int mesh_crypto_active; 78 79 // crypto requests 80 static union { 81 btstack_crypto_ccm_t ccm; 82 btstack_crypto_aes128_t aes128; 83 } mesh_network_crypto_request; 84 85 static const mesh_network_key_t * current_network_key; 86 87 // PECB calculation 88 static uint8_t encryption_block[16]; 89 static uint8_t obfuscation_block[16]; 90 91 // Network Nonce 92 static uint8_t network_nonce[13]; 93 94 // INCOMING // 95 96 // unprocessed network pdu - added by mesh_network_pdus_received_message 97 static btstack_linked_list_t network_pdus_received; 98 99 // in validation 100 static mesh_network_pdu_t * network_pdu_in_validation; 101 static mesh_network_key_iterator_t validation_network_key_it; 102 103 // OUTGOING // 104 105 // Network PDUs queued by mesh_network_send 106 static btstack_linked_list_t network_pdus_queued; 107 108 // Network PDUs ready to send 109 static btstack_linked_list_t network_pdus_outgoing; 110 111 // Network PDU ready to send via gatt/adv bearer 112 static mesh_network_pdu_t * actual_bearer_network_pdu; 113 114 // mesh network cache - we use 32-bit 'hashes' 115 static uint32_t mesh_network_cache[MESH_NETWORK_CACHE_SIZE]; 116 static int mesh_network_cache_index; 117 118 // prototypes 119 120 static void mesh_network_run(void); 121 static void process_network_pdu_validate(mesh_network_pdu_t * network_pdu); 122 123 // network caching 124 static uint32_t mesh_network_cache_hash(mesh_network_pdu_t * network_pdu){ 125 // - The SEQ field is a 24-bit integer that when combined with the IV Index, 126 // shall be a unique value for each new Network PDU originated by this node (=> SRC) 127 // - IV updates only rarely 128 // => 16 bit SRC, 1 bit IVI, 15 bit SEQ 129 uint8_t ivi = network_pdu->data[0] >> 7; 130 uint16_t seq = big_endian_read_16(network_pdu->data, 3); 131 uint16_t src = big_endian_read_16(network_pdu->data, 5); 132 return (src << 16) | (ivi << 15) | (seq & 0x7fff); 133 } 134 135 static int mesh_network_cache_find(uint32_t hash){ 136 int i; 137 for (i = 0; i < MESH_NETWORK_CACHE_SIZE; i++) { 138 if (mesh_network_cache[i] == hash) { 139 return 1; 140 } 141 } 142 return 0; 143 } 144 145 static void mesh_network_cache_add(uint32_t hash){ 146 mesh_network_cache[mesh_network_cache_index++] = hash; 147 if (mesh_network_cache_index >= MESH_NETWORK_CACHE_SIZE){ 148 mesh_network_cache_index = 0; 149 } 150 } 151 152 // common helper 153 int mesh_network_address_unicast(uint16_t addr){ 154 return addr < 0x8000; 155 } 156 157 int mesh_network_address_virtual(uint16_t addr){ 158 return (addr & 0xC000) == 0x8000; // 0b10xx xxxx xxxx xxxx 159 } 160 161 int mesh_network_address_group(uint16_t addr){ 162 return (addr & 0xC000) == 0xC000; // 0b11xx xxxx xxxx xxxx 163 } 164 165 int mesh_network_address_all_proxies(uint16_t addr){ 166 return addr == MESH_ADDRESS_ALL_PROXIES; 167 } 168 169 int mesh_network_address_all_nodes(uint16_t addr){ 170 return addr == MESH_ADDRESS_ALL_NODES; 171 } 172 173 int mesh_network_address_all_friends(uint16_t addr){ 174 return addr == MESH_ADDRESS_ALL_FRIENDS; 175 } 176 177 int mesh_network_address_all_relays(uint16_t addr){ 178 return addr == MESH_ADDRESS_ALL_RELAYS; 179 } 180 181 int mesh_network_addresses_valid(uint8_t ctl, uint16_t src, uint16_t dst){ 182 // printf("CTL: %u\n", ctl); 183 // printf("SRC: %04x\n", src); 184 // printf("DST: %04x\n", dst); 185 if (src == 0){ 186 // printf("SRC Unassigned Addr -> ignore\n"); 187 return 0; 188 } 189 if ((src & 0xC000) == 0x8000){ 190 // printf("SRC Virtual Addr -> ignore\n"); 191 return 0; 192 } 193 if ((src & 0xC000) == 0xC000){ 194 // printf("SRC Group Addr -> ignore\n"); 195 return 0; 196 } 197 if (dst == 0){ 198 // printf("DST Unassigned Addr -> ignore\n"); 199 return 0; 200 } 201 if ( ((dst & 0xC000) == 0x8000) && (ctl == 1)){ 202 // printf("DST Virtual Addr in CONTROL -> ignore\n"); 203 return 0; 204 } 205 if ( (0xFF00 <= dst) && (dst <= 0xfffb) && (ctl == 0) ){ 206 // printf("DST RFU Group Addr in MESSAGE -> ignore\n"); 207 return 0; 208 } 209 // printf("SRC + DST Addr valid\n"); 210 return 1; 211 } 212 213 static void mesh_network_create_nonce(uint8_t * nonce, const mesh_network_pdu_t * pdu, uint32_t iv_index){ 214 unsigned int pos = 0; 215 nonce[pos++] = 0x0; // Network Nonce 216 memcpy(&nonce[pos], &pdu->data[1], 6); 217 pos += 6; 218 big_endian_store_16(nonce, pos, 0); 219 pos += 2; 220 big_endian_store_32(nonce, pos, iv_index); 221 } 222 223 static void mesh_proxy_create_nonce(uint8_t * nonce, const mesh_network_pdu_t * pdu, uint32_t iv_index){ 224 unsigned int pos = 0; 225 nonce[pos++] = 0x3; // Proxy Nonce 226 nonce[pos++] = 0; 227 memcpy(&nonce[pos], &pdu->data[2], 5); 228 pos += 5; 229 big_endian_store_16(nonce, pos, 0); 230 pos += 2; 231 big_endian_store_32(nonce, pos, iv_index); 232 } 233 234 // NID/IVI | obfuscated (CTL/TTL, SEQ (24), SRC (16) ), encrypted ( DST(16), TransportPDU), MIC(32 or 64) 235 236 static void mesh_network_send_d(mesh_network_pdu_t * network_pdu){ 237 238 #ifdef LOG_NETWORK 239 printf("TX-D-NetworkPDU (%p): ", network_pdu); 240 printf_hexdump(network_pdu->data, network_pdu->len); 241 #endif 242 243 // add to queue 244 btstack_linked_list_add_tail(&network_pdus_outgoing, (btstack_linked_item_t *) network_pdu); 245 246 // go 247 mesh_network_run(); 248 } 249 250 // new 251 static void mesh_network_send_c(void *arg){ 252 mesh_network_pdu_t * network_pdu = (mesh_network_pdu_t *) arg; 253 254 // obfuscate 255 unsigned int i; 256 for (i=0;i<6;i++){ 257 network_pdu->data[1+i] ^= obfuscation_block[i]; 258 } 259 260 #ifdef LOG_NETWORK 261 printf("TX-C-NetworkPDU (%p): ", network_pdu); 262 printf_hexdump(network_pdu->data, network_pdu->len); 263 #endif 264 265 // crypto done 266 mesh_crypto_active = 0; 267 268 // done 269 (network_pdu->callback)(network_pdu); 270 } 271 272 static void mesh_network_send_b(void *arg){ 273 mesh_network_pdu_t * network_pdu = (mesh_network_pdu_t *) arg; 274 275 uint32_t iv_index = global_iv_index; 276 277 // store NetMIC 278 uint8_t net_mic[8]; 279 btstack_crypto_ccm_get_authentication_value(&mesh_network_crypto_request.ccm, net_mic); 280 281 // store MIC 282 uint8_t net_mic_len = network_pdu->data[1] & 0x80 ? 8 : 4; 283 memcpy(&network_pdu->data[network_pdu->len], net_mic, net_mic_len); 284 network_pdu->len += net_mic_len; 285 286 #ifdef LOG_NETWORK 287 printf("TX-B-NetworkPDU (%p): ", network_pdu); 288 printf_hexdump(network_pdu->data, network_pdu->len); 289 #endif 290 291 // calc PECB 292 memset(encryption_block, 0, 5); 293 big_endian_store_32(encryption_block, 5, iv_index); 294 memcpy(&encryption_block[9], &network_pdu->data[7], 7); 295 btstack_crypto_aes128_encrypt(&mesh_network_crypto_request.aes128, current_network_key->privacy_key, encryption_block, obfuscation_block, &mesh_network_send_c, network_pdu); 296 } 297 298 static void mesh_network_send_a(mesh_network_pdu_t * network_pdu){ 299 300 mesh_crypto_active = 1; 301 302 // lookup network by netkey_index 303 current_network_key = mesh_network_key_list_get(network_pdu->netkey_index); 304 if (!current_network_key) { 305 mesh_crypto_active = 0; 306 // notify upper layer 307 (*mesh_network_higher_layer_handler)(MESH_NETWORK_PDU_SENT, network_pdu); 308 // run again 309 mesh_network_run(); 310 return; 311 } 312 313 // get network nonce 314 if (network_pdu->flags & 1){ 315 mesh_proxy_create_nonce(network_nonce, network_pdu, global_iv_index); 316 #ifdef LOG_NETWORK 317 printf("TX-ProxyNonce: "); 318 printf_hexdump(network_nonce, 13); 319 #endif 320 } else { 321 mesh_network_create_nonce(network_nonce, network_pdu, global_iv_index); 322 #ifdef LOG_NETWORK 323 printf("TX-NetworkNonce: "); 324 printf_hexdump(network_nonce, 13); 325 #endif 326 } 327 328 #ifdef LOG_NETWORK 329 printf("TX-EncryptionKey: "); 330 printf_hexdump(current_network_key->encryption_key, 16); 331 #endif 332 333 // start ccm 334 uint8_t cypher_len = network_pdu->len - 7; 335 uint8_t net_mic_len = network_pdu->data[1] & 0x80 ? 8 : 4; 336 btstack_crypto_ccm_init(&mesh_network_crypto_request.ccm, current_network_key->encryption_key, network_nonce, cypher_len, 0, net_mic_len); 337 btstack_crypto_ccm_encrypt_block(&mesh_network_crypto_request.ccm, cypher_len, &network_pdu->data[7], &network_pdu->data[7], &mesh_network_send_b, network_pdu); 338 } 339 340 void mesh_network_message_processed_by_higher_layer(mesh_network_pdu_t * network_pdu){ 341 #ifdef ENABLE_MESH_RELAY 342 uint8_t ctl_ttl = network_pdu->data[1]; 343 uint8_t ctl = ctl_ttl >> 7; 344 uint8_t ttl = ctl_ttl & 0x7f; 345 uint8_t net_mic_len = (ctl_ttl & 0x80) ? 8 : 4; 346 uint16_t src = big_endian_read_16(network_pdu->data, 5); 347 348 // check if address matches elements on our node and TTL >= 2 349 if (((src < mesh_network_primary_address) || (src > (mesh_network_primary_address + mesh_network_num_elements))) && (ttl >= 2)){ 350 // prepare pdu for resending 351 network_pdu->len -= net_mic_len; 352 network_pdu->data[1] = (ctl << 7) | (ttl - 1); 353 354 // queue up 355 network_pdu->callback = &mesh_network_send_d; 356 btstack_linked_list_add_tail(&network_pdus_queued, (btstack_linked_item_t *) network_pdu); 357 358 // go 359 mesh_network_run(); 360 361 return; 362 } 363 #endif 364 btstack_memory_mesh_network_pdu_free(network_pdu); 365 } 366 367 static void process_network_pdu_done(void){ 368 btstack_memory_mesh_network_pdu_free(network_pdu_in_validation); 369 network_pdu_in_validation = NULL; 370 mesh_crypto_active = 0; 371 372 mesh_network_run(); 373 } 374 375 static void process_network_pdu_validate_d(void * arg){ 376 mesh_network_pdu_t * network_pdu = (mesh_network_pdu_t *) arg; 377 378 uint8_t ctl_ttl = network_pdu->data[1]; 379 uint8_t ctl = ctl_ttl >> 7; 380 uint8_t net_mic_len = (ctl_ttl & 0x80) ? 8 : 4; 381 382 // store NetMIC 383 uint8_t net_mic[8]; 384 btstack_crypto_ccm_get_authentication_value(&mesh_network_crypto_request.ccm, net_mic); 385 #ifdef LOG_NETWORK 386 printf("RX-NetMIC: "); 387 printf_hexdump(net_mic, net_mic_len); 388 #endif 389 // store in pdu 390 memcpy(&network_pdu->data[network_pdu->len-net_mic_len], net_mic, net_mic_len); 391 392 #ifdef LOG_NETWORK 393 uint8_t cypher_len = network_pdu->len - 9 - net_mic_len; 394 printf("RX-Decrypted DST/TransportPDU: "); 395 printf_hexdump(&network_pdu->data[7], 2 + cypher_len); 396 397 printf("RX-Decrypted: "); 398 printf_hexdump(network_pdu->data, network_pdu->len); 399 #endif 400 401 // validate network mic 402 if (memcmp(net_mic, &network_pdu_in_validation->data[network_pdu->len-net_mic_len], net_mic_len) != 0){ 403 // fail 404 printf("RX-NetMIC mismatch, try next key\n"); 405 process_network_pdu_validate(network_pdu); 406 return; 407 } 408 409 // remove NetMIC from payload 410 network_pdu->len -= net_mic_len; 411 412 #ifdef LOG_NETWORK 413 // match 414 printf("RX-NetMIC matches\n"); 415 printf("RX-TTL: 0x%02x\n", network_pdu->data[1] & 0x7f); 416 #endif 417 418 // set netkey_index 419 network_pdu->netkey_index = current_network_key->netkey_index; 420 421 if (network_pdu->flags & 1){ 422 423 // no additional checks for proxy messages 424 (*mesh_network_proxy_message_handler)(MESH_NETWORK_PDU_RECEIVED, network_pdu); 425 426 } else { 427 428 // validate src/dest addresses 429 uint16_t src = big_endian_read_16(network_pdu->data, 5); 430 uint16_t dst = big_endian_read_16(network_pdu->data, 7); 431 int valid = mesh_network_addresses_valid(ctl, src, dst); 432 if (!valid){ 433 printf("RX Address invalid\n"); 434 btstack_memory_mesh_network_pdu_free(network_pdu); 435 process_network_pdu_done(); 436 return; 437 } 438 439 // check cache 440 uint32_t hash = mesh_network_cache_hash(network_pdu); 441 #ifdef LOG_NETWORK 442 printf("RX-Hash: %08x\n", hash); 443 #endif 444 if (mesh_network_cache_find(hash)){ 445 // found in cache, drop 446 printf("Found in cache -> drop packet\n"); 447 btstack_memory_mesh_network_pdu_free(network_pdu); 448 process_network_pdu_done(); 449 return; 450 } 451 452 // store in network cache 453 mesh_network_cache_add(hash); 454 455 // forward to lower transport layer. message is freed by call to mesh_network_message_processed_by_upper_layer 456 (*mesh_network_higher_layer_handler)(MESH_NETWORK_PDU_RECEIVED, network_pdu); 457 } 458 459 // done 460 process_network_pdu_done(); 461 } 462 463 static uint32_t iv_index_for_pdu(const mesh_network_pdu_t * network_pdu){ 464 // get IV Index and IVI 465 uint32_t iv_index = global_iv_index; 466 int ivi = network_pdu->data[0] >> 7; 467 468 // if least significant bit differs, use previous IV Index 469 if ((iv_index & 1 ) ^ ivi){ 470 iv_index--; 471 #ifdef LOG_NETWORK 472 printf("RX-IV: IVI indicates previous IV index, using 0x%08x\n", iv_index); 473 #endif 474 } 475 return iv_index; 476 } 477 478 static void process_network_pdu_validate_b(void * arg){ 479 mesh_network_pdu_t * network_pdu = (mesh_network_pdu_t *) arg; 480 481 #ifdef LOG_NETWORK 482 printf("RX-PECB: "); 483 printf_hexdump(obfuscation_block, 6); 484 #endif 485 486 // de-obfuscate 487 unsigned int i; 488 for (i=0;i<6;i++){ 489 network_pdu->data[1+i] = network_pdu_in_validation->data[1+i] ^ obfuscation_block[i]; 490 } 491 492 uint32_t iv_index = iv_index_for_pdu(network_pdu); 493 494 if (network_pdu->flags & 1){ 495 // create network nonce 496 mesh_proxy_create_nonce(network_nonce, network_pdu, iv_index); 497 #ifdef LOG_NETWORK 498 printf("RX-Proxy Nonce: "); 499 printf_hexdump(network_nonce, 13); 500 #endif 501 } else { 502 // create network nonce 503 mesh_network_create_nonce(network_nonce, network_pdu, iv_index); 504 #ifdef LOG_NETWORK 505 printf("RX-Network Nonce: "); 506 printf_hexdump(network_nonce, 13); 507 #endif 508 } 509 510 // 511 uint8_t ctl_ttl = network_pdu->data[1]; 512 uint8_t net_mic_len = (ctl_ttl & 0x80) ? 8 : 4; 513 uint8_t cypher_len = network_pdu->len - 7 - net_mic_len; 514 515 #ifdef LOG_NETWORK 516 printf("RX-Cyper len %u, mic len %u\n", cypher_len, net_mic_len); 517 518 printf("RX-Encryption Key: "); 519 printf_hexdump(current_network_key->encryption_key, 16); 520 521 #endif 522 523 btstack_crypto_ccm_init(&mesh_network_crypto_request.ccm, current_network_key->encryption_key, network_nonce, cypher_len, 0, net_mic_len); 524 btstack_crypto_ccm_decrypt_block(&mesh_network_crypto_request.ccm, cypher_len, &network_pdu_in_validation->data[7], &network_pdu->data[7], &process_network_pdu_validate_d, network_pdu); 525 } 526 527 static void process_network_pdu_validate(mesh_network_pdu_t * network_pdu){ 528 if (!mesh_network_key_nid_iterator_has_more(&validation_network_key_it)){ 529 printf("No valid network key found\n"); 530 btstack_memory_mesh_network_pdu_free(network_pdu); 531 process_network_pdu_done(); 532 return; 533 } 534 535 current_network_key = mesh_network_key_nid_iterator_get_next(&validation_network_key_it); 536 537 // calc PECB 538 uint32_t iv_index = iv_index_for_pdu(network_pdu); 539 memset(encryption_block, 0, 5); 540 big_endian_store_32(encryption_block, 5, iv_index); 541 memcpy(&encryption_block[9], &network_pdu_in_validation->data[7], 7); 542 btstack_crypto_aes128_encrypt(&mesh_network_crypto_request.aes128, current_network_key->privacy_key, encryption_block, obfuscation_block, &process_network_pdu_validate_b, network_pdu); 543 } 544 545 546 static void process_network_pdu(mesh_network_pdu_t * network_pdu){ 547 // 548 uint8_t nid_ivi = network_pdu_in_validation->data[0]; 549 550 // setup pdu object 551 network_pdu->data[0] = nid_ivi; 552 network_pdu->len = network_pdu_in_validation->len; 553 network_pdu->flags = network_pdu_in_validation->flags; 554 555 // init provisioning data iterator 556 uint8_t nid = nid_ivi & 0x7f; 557 // uint8_t iv_index = network_pdu_data[0] >> 7; 558 mesh_network_key_nid_iterator_init(&validation_network_key_it, nid); 559 560 process_network_pdu_validate(network_pdu); 561 } 562 563 // static void mesh_network_encrypt_and_obfuscate(mesh_network_pdu_t * network_pdu, void (*callback)(mesh_network_pdu_t * network_pdu)){ 564 // network_pdu->callback = callback; 565 // } 566 567 static void mesh_network_run(void){ 568 if (!btstack_linked_list_empty(&network_pdus_outgoing)){ 569 actual_bearer_network_pdu = (mesh_network_pdu_t *) btstack_linked_list_pop(&network_pdus_outgoing); 570 571 int send_to_next_bearer = 1; 572 #ifdef ENABLE_MESH_GATT_BEARER 573 // request to send via gatt 574 if (send_to_next_bearer){ 575 send_to_next_bearer = 0; 576 gatt_bearer_request_can_send_now_for_mesh_network_pdu(); 577 } 578 #endif 579 #ifdef ENABLE_MESH_ADV_BEARER 580 // request to send via adv 581 if (send_to_next_bearer){ 582 send_to_next_bearer = 0; 583 adv_bearer_request_can_send_now_for_mesh_message(); 584 } 585 #endif 586 if (send_to_next_bearer == 1){ 587 // TODO: notify done 588 } 589 } 590 591 if (mesh_crypto_active) return; 592 593 if (!btstack_linked_list_empty(&network_pdus_received)){ 594 mesh_network_pdu_t * decode_pdu = mesh_network_pdu_get(); 595 if (!decode_pdu) return; 596 // get encoded network pdu and start processing 597 mesh_crypto_active = 1; 598 network_pdu_in_validation = (mesh_network_pdu_t *) btstack_linked_list_pop(&network_pdus_received); 599 process_network_pdu(decode_pdu); 600 return; 601 } 602 603 if (!btstack_linked_list_empty(&network_pdus_queued)){ 604 // get queued network pdu and start processing 605 mesh_network_pdu_t * network_pdu = (mesh_network_pdu_t *) btstack_linked_list_pop(&network_pdus_queued); 606 mesh_network_send_a(network_pdu); 607 return; 608 } 609 } 610 611 #ifdef ENABLE_MESH_ADV_BEARER 612 static void mesh_adv_message_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 613 mesh_network_pdu_t * network_pdu; 614 615 switch (packet_type){ 616 case MESH_NETWORK_PACKET: 617 // check len. minimal transport PDU len = 1, 32 bit NetMIC -> 13 bytes 618 if (size < 13) break; 619 620 #ifdef LOG_NETWORK 621 printf("received mesh message (len %u): ", size); 622 printf_hexdump(packet, size); 623 #endif 624 mesh_network_received_message(packet, size); 625 break; 626 627 case HCI_EVENT_PACKET: 628 switch(packet[0]){ 629 case HCI_EVENT_MESH_META: 630 switch(packet[2]){ 631 case MESH_SUBEVENT_CAN_SEND_NOW: 632 if (actual_bearer_network_pdu == NULL) break; 633 #ifdef LOG_NETWORK 634 printf("TX-E-NetworkPDU (%p): ", actual_bearer_network_pdu); 635 printf_hexdump(actual_bearer_network_pdu->data, actual_bearer_network_pdu->len); 636 #endif 637 adv_bearer_send_mesh_message(actual_bearer_network_pdu->data, actual_bearer_network_pdu->len); 638 network_pdu = actual_bearer_network_pdu; 639 actual_bearer_network_pdu = NULL; 640 641 // notify upper layer 642 (*mesh_network_higher_layer_handler)(MESH_NETWORK_PDU_SENT, network_pdu); 643 644 // check if more to send 645 mesh_network_run(); 646 break; 647 default: 648 break; 649 } 650 break; 651 default: 652 break; 653 } 654 break; 655 } 656 } 657 #endif 658 659 void mesh_gatt_handle_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 660 #ifdef ENABLE_MESH_GATT_BEARER 661 mesh_network_pdu_t * network_pdu; 662 switch (packet_type){ 663 case HCI_EVENT_PACKET: 664 switch(packet[0]){ 665 case HCI_EVENT_MESH_META: 666 switch(packet[2]){ 667 case MESH_SUBEVENT_CAN_SEND_NOW: 668 if (actual_bearer_network_pdu == NULL) break; 669 #ifdef LOG_NETWORK 670 printf("G-TX-E-NetworkPDU (%p): ", actual_bearer_network_pdu); 671 printf_hexdump(actual_bearer_network_pdu->data, actual_bearer_network_pdu->len); 672 #endif 673 gatt_bearer_send_mesh_network_pdu(actual_bearer_network_pdu->data, actual_bearer_network_pdu->len); 674 break; 675 676 case MESH_SUBEVENT_MESSAGE_SENT: 677 if (actual_bearer_network_pdu == NULL) break; 678 #ifdef ENABLE_MESH_ADV_BEARER 679 // request to send via adv bearer 680 adv_bearer_request_can_send_now_for_mesh_message(); 681 break; 682 #else 683 // notify upper layer 684 network_pdu = actual_bearer_network_pdu; 685 actual_bearer_network_pdu = NULL; 686 (*mesh_network_higher_layer_handler)(MESH_NETWORK_PDU_SENT, network_pdu); 687 #endif 688 break; 689 default: 690 break; 691 } 692 break; 693 default: 694 break; 695 } 696 break; 697 } 698 #endif 699 } 700 701 void mesh_network_init(void){ 702 #ifdef ENABLE_MESH_ADV_BEARER 703 adv_bearer_register_for_mesh_message(&mesh_adv_message_handler); 704 #endif 705 } 706 707 void mesh_network_set_higher_layer_handler(void (*packet_handler)(mesh_network_callback_type_t callback_type, mesh_network_pdu_t * network_pdu)){ 708 mesh_network_higher_layer_handler = packet_handler; 709 } 710 711 void mesh_network_set_proxy_message_handler(void (*packet_handler)(mesh_network_callback_type_t callback_type, mesh_network_pdu_t * network_pdu)){ 712 mesh_network_proxy_message_handler = packet_handler; 713 } 714 715 void mesh_network_set_primary_element_address(uint16_t addr){ 716 mesh_network_primary_address = addr; 717 mesh_network_num_elements = 1; 718 } 719 720 void mesh_network_received_message(const uint8_t * pdu_data, uint8_t pdu_len){ 721 // verify len 722 if (pdu_len > 29) return; 723 724 // allocate network_pdu 725 mesh_network_pdu_t * network_pdu = mesh_network_pdu_get(); 726 if (!network_pdu) return; 727 728 // store data 729 memcpy(network_pdu->data, pdu_data, pdu_len); 730 network_pdu->len = pdu_len; 731 network_pdu->flags = 0; // Network PDU 732 733 // add to list and go 734 btstack_linked_list_add_tail(&network_pdus_received, (btstack_linked_item_t *) network_pdu); 735 mesh_network_run(); 736 737 } 738 739 void mesh_network_process_proxy_message(const uint8_t * pdu_data, uint8_t pdu_len){ 740 // verify len 741 if (pdu_len > 29) return; 742 743 // allocate network_pdu 744 mesh_network_pdu_t * network_pdu = mesh_network_pdu_get(); 745 if (!network_pdu) return; 746 747 // store data 748 memcpy(network_pdu->data, pdu_data, pdu_len); 749 network_pdu->len = pdu_len; 750 network_pdu->flags = 1; // Network PDU 751 752 // add to list and go 753 btstack_linked_list_add_tail(&network_pdus_received, (btstack_linked_item_t *) network_pdu); 754 mesh_network_run(); 755 } 756 757 void mesh_network_send_pdu(mesh_network_pdu_t * network_pdu){ 758 #ifdef LOG_NETWORK 759 printf("TX-A-NetworkPDU (%p): ", network_pdu); 760 printf_hexdump(network_pdu->data, network_pdu->len); 761 #endif 762 763 if (network_pdu->len > 29){ 764 printf("too long, %u\n", network_pdu->len); 765 return; 766 } 767 768 // setup callback 769 network_pdu->callback = &mesh_network_send_d; 770 network_pdu->flags = 0; 771 772 // queue up 773 btstack_linked_list_add_tail(&network_pdus_queued, (btstack_linked_item_t *) network_pdu); 774 775 // go 776 mesh_network_run(); 777 } 778 779 void mesh_network_encrypt_proxy_message(mesh_network_pdu_t * network_pdu, void (* callback)(mesh_network_pdu_t * callback)){ 780 printf("ProxyPDU(unencrypted): "); 781 printf_hexdump(network_pdu->data, network_pdu->len); 782 783 // setup callback 784 network_pdu->callback = callback; 785 network_pdu->flags = 1; 786 787 // queue up 788 btstack_linked_list_add_tail(&network_pdus_queued, (btstack_linked_item_t *) network_pdu); 789 790 // go 791 mesh_network_run(); 792 } 793 794 /* 795 * @brief Setup network pdu header 796 * @param netkey_index 797 * @param ctl 798 * @param ttl 799 * @param seq 800 * @param dest 801 */ 802 void mesh_network_setup_pdu(mesh_network_pdu_t * network_pdu, uint16_t netkey_index, uint8_t nid, uint8_t ctl, uint8_t ttl, uint32_t seq, uint16_t src, uint16_t dest, const uint8_t * transport_pdu_data, uint8_t transport_pdu_len){ 803 memset(network_pdu, 0, sizeof(mesh_network_pdu_t)); 804 // set netkey_index 805 network_pdu->netkey_index = netkey_index; 806 // setup header 807 network_pdu->data[network_pdu->len++] = (global_iv_index << 7) | nid; 808 uint8_t ctl_ttl = (ctl << 7) | (ttl & 0x7f); 809 network_pdu->data[network_pdu->len++] = ctl_ttl; 810 big_endian_store_24(network_pdu->data, 2, seq); 811 network_pdu->len += 3; 812 big_endian_store_16(network_pdu->data, network_pdu->len, src); 813 network_pdu->len += 2; 814 big_endian_store_16(network_pdu->data, network_pdu->len, dest); 815 network_pdu->len += 2; 816 memcpy(&network_pdu->data[network_pdu->len], transport_pdu_data, transport_pdu_len); 817 network_pdu->len += transport_pdu_len; 818 } 819 820 /* 821 * @brief Setup network pdu header 822 * @param netkey_index 823 * @param ctl 824 * @param ttl 825 * @param seq 826 * @param dest 827 */ 828 void mesh_network_setup_pdu_header(mesh_network_pdu_t * network_pdu, uint16_t netkey_index, uint8_t nid, uint8_t ctl, uint8_t ttl, uint32_t seq, uint16_t src, uint16_t dest){ 829 // set netkey_index 830 network_pdu->netkey_index = netkey_index; 831 // setup header 832 network_pdu->data[0] = (global_iv_index << 7) | nid; 833 uint8_t ctl_ttl = (ctl << 7) | (ttl & 0x7f); 834 network_pdu->data[1] = ctl_ttl; 835 big_endian_store_24(network_pdu->data, 2, seq); 836 big_endian_store_16(network_pdu->data, 5, src); 837 big_endian_store_16(network_pdu->data, 7, dest); 838 } 839 840 void mesh_set_iv_index(uint32_t iv_index){ 841 global_iv_index = iv_index; 842 } 843 844 uint32_t mesh_get_iv_index(void){ 845 return global_iv_index; 846 } 847 848 // Network PDU Getter 849 uint8_t mesh_network_nid(mesh_network_pdu_t * network_pdu){ 850 return network_pdu->data[0] & 0x7f; 851 } 852 uint16_t mesh_network_control(mesh_network_pdu_t * network_pdu){ 853 return network_pdu->data[1] & 0x80; 854 } 855 uint8_t mesh_network_ttl(mesh_network_pdu_t * network_pdu){ 856 return network_pdu->data[1] & 0x7f; 857 } 858 uint32_t mesh_network_seq(mesh_network_pdu_t * network_pdu){ 859 return big_endian_read_24(network_pdu->data, 2); 860 } 861 uint16_t mesh_network_src(mesh_network_pdu_t * network_pdu){ 862 return big_endian_read_16(network_pdu->data, 5); 863 } 864 uint16_t mesh_network_dst(mesh_network_pdu_t * network_pdu){ 865 return big_endian_read_16(network_pdu->data, 7); 866 } 867 int mesh_network_segmented(mesh_network_pdu_t * network_pdu){ 868 return network_pdu->data[9] & 0x80; 869 } 870 uint8_t * mesh_network_pdu_data(mesh_network_pdu_t * network_pdu){ 871 return &network_pdu->data[9]; 872 } 873 uint8_t mesh_network_pdu_len(mesh_network_pdu_t * network_pdu){ 874 return network_pdu->len - 9; 875 } 876 877 static void mesh_network_dump_network_pdu(mesh_network_pdu_t * network_pdu){ 878 if (network_pdu){ 879 printf("- %p: ", network_pdu); printf_hexdump(network_pdu->data, network_pdu->len); 880 } 881 } 882 static void mesh_network_dump_network_pdus(const char * name, btstack_linked_list_t * list){ 883 printf("List: %s:\n", name); 884 btstack_linked_list_iterator_t it; 885 btstack_linked_list_iterator_init(&it, list); 886 while (btstack_linked_list_iterator_has_next(&it)){ 887 mesh_network_pdu_t * network_pdu = (mesh_network_pdu_t*) btstack_linked_list_iterator_next(&it); 888 mesh_network_dump_network_pdu(network_pdu); 889 } 890 } 891 static void mesh_network_reset_network_pdus(btstack_linked_list_t * list){ 892 while (!btstack_linked_list_empty(list)){ 893 mesh_network_pdu_t * pdu = (mesh_network_pdu_t *) btstack_linked_list_pop(list); 894 btstack_memory_mesh_network_pdu_free(pdu); 895 } 896 } 897 void mesh_network_dump(void){ 898 mesh_network_dump_network_pdus("network_pdus_received", &network_pdus_received); 899 mesh_network_dump_network_pdus("network_pdus_queued", &network_pdus_queued); 900 mesh_network_dump_network_pdus("network_pdus_outgoing", &network_pdus_outgoing); 901 printf("network_pdu_in_validation: \n"); 902 mesh_network_dump_network_pdu(network_pdu_in_validation); 903 } 904 void mesh_network_reset(void){ 905 mesh_network_reset_network_pdus(&network_pdus_received); 906 mesh_network_reset_network_pdus(&network_pdus_queued); 907 mesh_network_reset_network_pdus(&network_pdus_outgoing); 908 } 909 910 // buffer pool 911 mesh_network_pdu_t * mesh_network_pdu_get(void){ 912 mesh_network_pdu_t * network_pdu = btstack_memory_mesh_network_pdu_get(); 913 if (network_pdu) { 914 memset(network_pdu, 0, sizeof(mesh_network_pdu_t)); 915 network_pdu->pdu_header.pdu_type = MESH_PDU_TYPE_NETWORK; 916 } 917 return network_pdu; 918 } 919 920 void mesh_network_pdu_free(mesh_network_pdu_t * network_pdu){ 921 btstack_memory_mesh_network_pdu_free(network_pdu); 922 } 923