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