xref: /btstack/src/mesh/mesh_network.c (revision ec22fe67074f83705da0b0e7c37d040b29524f0f)
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 & MESH_NETWORK_PDU_FLAGS_PROXY_CONFIGURATION){
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 #ifdef ENABLE_MESH_RELAY
352 static void mesh_network_relay_message(mesh_network_pdu_t * network_pdu){
353     uint8_t ctl     = ctl_ttl >> 7;
354     uint8_t net_mic_len = (ctl_ttl & 0x80) ? 8 : 4;
355     // prepare pdu for resending
356     network_pdu->len    -= net_mic_len;
357     network_pdu->data[1] = (ctl << 7) | (ttl - 1);
358     network_pdu->flags |= MESH_NETWORK_PDU_FLAGS_RELAY;
359     // queue up
360     network_pdu->callback = &mesh_network_send_d;
361     btstack_linked_list_add_tail(&network_pdus_queued, (btstack_linked_item_t *) network_pdu);
362 }
363 #endif
364 
365 void mesh_network_message_processed_by_higher_layer(mesh_network_pdu_t * network_pdu){
366 #ifdef ENABLE_MESH_RELAY
367     if (mesh_foundation_relay_get() != 0){
368         uint8_t ctl_ttl = network_pdu->data[1];
369         uint8_t ttl     = ctl_ttl & 0x7f;
370         uint16_t src    = big_endian_read_16(network_pdu->data, 5);
371 
372         // check if address matches elements on our node and TTL >= 2
373         if (((src < mesh_network_primary_address) || (src > (mesh_network_primary_address + mesh_network_num_elements))) && (ttl >= 2)){
374             mesh_network_relay_message(network_pdu);
375 
376             // go
377             mesh_network_run();
378 
379             return;
380         }
381     }
382 #endif
383     btstack_memory_mesh_network_pdu_free(network_pdu);
384 }
385 
386 static void process_network_pdu_done(void){
387     btstack_memory_mesh_network_pdu_free(network_pdu_in_validation);
388     network_pdu_in_validation = NULL;
389     mesh_crypto_active = 0;
390 
391     mesh_network_run();
392 }
393 
394 static void process_network_pdu_validate_d(void * arg){
395     mesh_network_pdu_t * network_pdu = (mesh_network_pdu_t *) arg;
396 
397     uint8_t ctl_ttl     = network_pdu->data[1];
398     uint8_t ctl         = ctl_ttl >> 7;
399     uint8_t net_mic_len = (ctl_ttl & 0x80) ? 8 : 4;
400 
401     // store NetMIC
402     uint8_t net_mic[8];
403     btstack_crypto_ccm_get_authentication_value(&mesh_network_crypto_request.ccm, net_mic);
404 #ifdef LOG_NETWORK
405     printf("RX-NetMIC: ");
406     printf_hexdump(net_mic, net_mic_len);
407 #endif
408     // store in pdu
409     memcpy(&network_pdu->data[network_pdu->len-net_mic_len], net_mic, net_mic_len);
410 
411 #ifdef LOG_NETWORK
412     uint8_t cypher_len  = network_pdu->len - 9 - net_mic_len;
413     printf("RX-Decrypted DST/TransportPDU: ");
414     printf_hexdump(&network_pdu->data[7], 2 + cypher_len);
415 
416     printf("RX-Decrypted: ");
417     printf_hexdump(network_pdu->data, network_pdu->len);
418 #endif
419 
420     // validate network mic
421     if (memcmp(net_mic, &network_pdu_in_validation->data[network_pdu->len-net_mic_len], net_mic_len) != 0){
422         // fail
423         printf("RX-NetMIC mismatch, try next key\n");
424         process_network_pdu_validate(network_pdu);
425         return;
426     }
427 
428     // remove NetMIC from payload
429     network_pdu->len -= net_mic_len;
430 
431 #ifdef LOG_NETWORK
432     // match
433     printf("RX-NetMIC matches\n");
434     printf("RX-TTL: 0x%02x\n", network_pdu->data[1] & 0x7f);
435 #endif
436 
437     // set netkey_index
438     network_pdu->netkey_index = current_network_key->netkey_index;
439 
440     if (network_pdu->flags & MESH_NETWORK_PDU_FLAGS_PROXY_CONFIGURATION){
441 
442         // no additional checks for proxy messages
443         (*mesh_network_proxy_message_handler)(MESH_NETWORK_PDU_RECEIVED, network_pdu);
444 
445     } else {
446 
447         // validate src/dest addresses
448         uint16_t src = big_endian_read_16(network_pdu->data, 5);
449         uint16_t dst = big_endian_read_16(network_pdu->data, 7);
450         int valid = mesh_network_addresses_valid(ctl, src, dst);
451         if (!valid){
452             printf("RX Address invalid\n");
453             btstack_memory_mesh_network_pdu_free(network_pdu);
454             process_network_pdu_done();
455             return;
456         }
457 
458         // check cache
459         uint32_t hash = mesh_network_cache_hash(network_pdu);
460 #ifdef LOG_NETWORK
461         printf("RX-Hash: %08x\n", hash);
462 #endif
463         if (mesh_network_cache_find(hash)){
464             // found in cache, drop
465             printf("Found in cache -> drop packet\n");
466             btstack_memory_mesh_network_pdu_free(network_pdu);
467             process_network_pdu_done();
468             return;
469         }
470 
471         // store in network cache
472         mesh_network_cache_add(hash);
473 
474         // forward to lower transport layer. message is freed by call to mesh_network_message_processed_by_upper_layer
475         (*mesh_network_higher_layer_handler)(MESH_NETWORK_PDU_RECEIVED, network_pdu);
476     }
477 
478     // done
479     process_network_pdu_done();
480 }
481 
482 static uint32_t iv_index_for_pdu(const mesh_network_pdu_t * network_pdu){
483     // get IV Index and IVI
484     uint32_t iv_index = global_iv_index;
485     int ivi = network_pdu->data[0] >> 7;
486 
487     // if least significant bit differs, use previous IV Index
488     if ((iv_index & 1 ) ^ ivi){
489         iv_index--;
490 #ifdef LOG_NETWORK
491         printf("RX-IV: IVI indicates previous IV index, using 0x%08x\n", iv_index);
492 #endif
493     }
494     return iv_index;
495 }
496 
497 static void process_network_pdu_validate_b(void * arg){
498     mesh_network_pdu_t * network_pdu = (mesh_network_pdu_t *) arg;
499 
500 #ifdef LOG_NETWORK
501     printf("RX-PECB: ");
502     printf_hexdump(obfuscation_block, 6);
503 #endif
504 
505     // de-obfuscate
506     unsigned int i;
507     for (i=0;i<6;i++){
508         network_pdu->data[1+i] = network_pdu_in_validation->data[1+i] ^ obfuscation_block[i];
509     }
510 
511     uint32_t iv_index = iv_index_for_pdu(network_pdu);
512 
513     if (network_pdu->flags & MESH_NETWORK_PDU_FLAGS_PROXY_CONFIGURATION){
514         // create network nonce
515         mesh_proxy_create_nonce(network_nonce, network_pdu, iv_index);
516 #ifdef LOG_NETWORK
517         printf("RX-Proxy Nonce: ");
518         printf_hexdump(network_nonce, 13);
519 #endif
520     } else {
521         // create network nonce
522         mesh_network_create_nonce(network_nonce, network_pdu, iv_index);
523 #ifdef LOG_NETWORK
524         printf("RX-Network Nonce: ");
525         printf_hexdump(network_nonce, 13);
526 #endif
527     }
528 
529     //
530     uint8_t ctl_ttl     = network_pdu->data[1];
531     uint8_t net_mic_len = (ctl_ttl & 0x80) ? 8 : 4;
532     uint8_t cypher_len  = network_pdu->len - 7 - net_mic_len;
533 
534 #ifdef LOG_NETWORK
535     printf("RX-Cyper len %u, mic len %u\n", cypher_len, net_mic_len);
536 
537     printf("RX-Encryption Key: ");
538     printf_hexdump(current_network_key->encryption_key, 16);
539 
540 #endif
541 
542     btstack_crypto_ccm_init(&mesh_network_crypto_request.ccm, current_network_key->encryption_key, network_nonce, cypher_len, 0, net_mic_len);
543     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);
544 }
545 
546 static void process_network_pdu_validate(mesh_network_pdu_t * network_pdu){
547     if (!mesh_network_key_nid_iterator_has_more(&validation_network_key_it)){
548         printf("No valid network key found\n");
549         btstack_memory_mesh_network_pdu_free(network_pdu);
550         process_network_pdu_done();
551         return;
552     }
553 
554     current_network_key = mesh_network_key_nid_iterator_get_next(&validation_network_key_it);
555 
556     // calc PECB
557     uint32_t iv_index = iv_index_for_pdu(network_pdu);
558     memset(encryption_block, 0, 5);
559     big_endian_store_32(encryption_block, 5, iv_index);
560     memcpy(&encryption_block[9], &network_pdu_in_validation->data[7], 7);
561     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);
562 }
563 
564 
565 static void process_network_pdu(mesh_network_pdu_t * network_pdu){
566     //
567     uint8_t nid_ivi = network_pdu_in_validation->data[0];
568 
569     // setup pdu object
570     network_pdu->data[0] = nid_ivi;
571     network_pdu->len     = network_pdu_in_validation->len;
572     network_pdu->flags   = network_pdu_in_validation->flags;
573 
574     // init provisioning data iterator
575     uint8_t nid = nid_ivi & 0x7f;
576     // uint8_t iv_index = network_pdu_data[0] >> 7;
577     mesh_network_key_nid_iterator_init(&validation_network_key_it, nid);
578 
579     process_network_pdu_validate(network_pdu);
580 }
581 
582 // static void mesh_network_encrypt_and_obfuscate(mesh_network_pdu_t * network_pdu, void (*callback)(mesh_network_pdu_t * network_pdu)){
583 //     network_pdu->callback = callback;
584 // }
585 
586 static void mesh_network_run(void){
587     if (!btstack_linked_list_empty(&network_pdus_outgoing)){
588         mesh_network_pdu_t * network_pdu = (mesh_network_pdu_t *) btstack_linked_list_pop(&network_pdus_outgoing);
589 
590 #ifdef ENABLE_MESH_GATT_BEARER
591         // request to send via gatt
592         printf("mesh_network_run: pdu %p, proxy %u, con handle %4x\n", network_pdu, mesh_foundation_gatt_proxy_get(), gatt_bearer_con_handle);
593         if (network_pdu != NULL && mesh_foundation_gatt_proxy_get() != 0 && gatt_bearer_con_handle != HCI_CON_HANDLE_INVALID){
594             gatt_bearer_network_pdu = network_pdu;
595             network_pdu = NULL;
596             gatt_bearer_request_can_send_now_for_network_pdu();
597         }
598 #endif
599 #ifdef ENABLE_MESH_ADV_BEARER
600          // request to send via adv
601         if (network_pdu != NULL){
602             adv_bearer_network_pdu = network_pdu;
603             network_pdu = NULL;
604             adv_bearer_request_can_send_now_for_network_pdu();
605         }
606 #endif
607         if (network_pdu !=  NULL){
608             // notify upper layer
609             (*mesh_network_higher_layer_handler)(MESH_NETWORK_PDU_SENT, network_pdu);
610         }
611     }
612 
613     if (mesh_crypto_active) return;
614 
615     if (!btstack_linked_list_empty(&network_pdus_received)){
616         mesh_network_pdu_t * decode_pdu = mesh_network_pdu_get();
617         if (!decode_pdu) return;
618         // get encoded network pdu and start processing
619         mesh_crypto_active = 1;
620         network_pdu_in_validation = (mesh_network_pdu_t *) btstack_linked_list_pop(&network_pdus_received);
621         process_network_pdu(decode_pdu);
622         return;
623     }
624 
625     if (!btstack_linked_list_empty(&network_pdus_queued)){
626         // get queued network pdu and start processing
627         mesh_network_pdu_t * network_pdu = (mesh_network_pdu_t *) btstack_linked_list_pop(&network_pdus_queued);
628         mesh_network_send_a(network_pdu);
629         return;
630     }
631 }
632 
633 #ifdef ENABLE_MESH_ADV_BEARER
634 static void mesh_adv_bearer_handle_network_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
635     mesh_network_pdu_t * network_pdu;
636 
637     switch (packet_type){
638         case MESH_NETWORK_PACKET:
639             // check len. minimal transport PDU len = 1, 32 bit NetMIC -> 13 bytes
640             if (size < 13) break;
641 
642 #ifdef LOG_NETWORK
643             printf("received network pdu from adv (len %u): ", size);
644             printf_hexdump(packet, size);
645 #endif
646             mesh_network_received_message(packet, size, 0);
647             break;
648 
649         case HCI_EVENT_PACKET:
650             switch(packet[0]){
651                 case HCI_EVENT_MESH_META:
652                     switch(packet[2]){
653                         case MESH_SUBEVENT_CAN_SEND_NOW:
654                             if (adv_bearer_network_pdu == NULL) break;
655 #ifdef LOG_NETWORK
656                             printf("TX-E-NetworkPDU (%p): ", adv_bearer_network_pdu);
657                             printf_hexdump(adv_bearer_network_pdu->data, adv_bearer_network_pdu->len);
658 #endif
659                             adv_bearer_send_network_pdu(adv_bearer_network_pdu->data, adv_bearer_network_pdu->len);
660                             network_pdu = adv_bearer_network_pdu;
661                             adv_bearer_network_pdu = NULL;
662 
663                             // notify upper layer
664                             (*mesh_network_higher_layer_handler)(MESH_NETWORK_PDU_SENT, network_pdu);
665 
666                             // check if more to send
667                             mesh_network_run();
668                             break;
669                         default:
670                             break;
671                     }
672                     break;
673                 default:
674                     break;
675             }
676             break;
677     }
678 }
679 #endif
680 
681 #ifdef ENABLE_MESH_GATT_BEARER
682 static void mesh_network_gatt_bearer_outgoing_complete(void){
683 
684     if (gatt_bearer_network_pdu == NULL) return;
685 
686 #ifdef ENABLE_MESH_ADV_BEARER
687     // forward to adv bearer
688     adv_bearer_network_pdu = gatt_bearer_network_pdu;
689     gatt_bearer_network_pdu = NULL;
690     adv_bearer_request_can_send_now_for_network_pdu();
691     return;
692 #endif
693 
694     // done, notify upper layer
695      mesh_network_pdu_t * network_pdu = gatt_bearer_network_pdu;
696     gatt_bearer_network_pdu = NULL;
697     (*mesh_network_higher_layer_handler)(MESH_NETWORK_PDU_SENT, network_pdu);
698 }
699 
700 static void mesh_network_gatt_bearer_handle_network_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
701     switch (packet_type){
702         case MESH_PROXY_DATA_PACKET:
703             if (mesh_foundation_gatt_proxy_get() == 0) break;
704 #ifdef LOG_NETWORK
705             printf("received network pdu from gatt (len %u): ", size);
706             printf_hexdump(packet, size);
707 #endif
708             mesh_network_received_message(packet, size, MESH_NETWORK_PDU_FLAGS_GATT_BEARER);
709             break;
710         case HCI_EVENT_PACKET:
711             switch (hci_event_packet_get_type(packet)){
712                 case HCI_EVENT_MESH_META:
713                     switch (hci_event_mesh_meta_get_subevent_code(packet)){
714                         case MESH_SUBEVENT_PROXY_CONNECTED:
715                             gatt_bearer_con_handle = mesh_subevent_proxy_connected_get_con_handle(packet);
716                             break;
717                         case MESH_SUBEVENT_PROXY_DISCONNECTED:
718                             gatt_bearer_con_handle = HCI_CON_HANDLE_INVALID;
719                             mesh_network_gatt_bearer_outgoing_complete();
720                             break;
721                         case MESH_SUBEVENT_CAN_SEND_NOW:
722                             if (gatt_bearer_network_pdu == NULL) break;
723 #ifdef LOG_NETWORK
724                             printf("G-TX-E-NetworkPDU (%p): ", gatt_bearer_network_pdu);
725                             printf_hexdump(gatt_bearer_network_pdu->data, gatt_bearer_network_pdu->len);
726 #endif
727                             gatt_bearer_send_network_pdu(gatt_bearer_network_pdu->data, gatt_bearer_network_pdu->len);
728                             break;
729 
730                         case MESH_SUBEVENT_MESSAGE_SENT:
731                             mesh_network_gatt_bearer_outgoing_complete();
732                             break;
733                         default:
734                             break;
735                     }
736                     break;
737                 default:
738                     break;
739             }
740             break;
741         default:
742             break;
743     }
744 }
745 #endif
746 
747 void mesh_network_init(void){
748 #ifdef ENABLE_MESH_ADV_BEARER
749     adv_bearer_register_for_network_pdu(&mesh_adv_bearer_handle_network_event);
750 #endif
751 #ifdef ENABLE_MESH_GATT_BEARER
752     gatt_bearer_register_for_network_pdu(&mesh_network_gatt_bearer_handle_network_event);
753     gatt_bearer_con_handle = HCI_CON_HANDLE_INVALID;
754 #endif
755 }
756 
757 void mesh_network_set_higher_layer_handler(void (*packet_handler)(mesh_network_callback_type_t callback_type, mesh_network_pdu_t * network_pdu)){
758     mesh_network_higher_layer_handler = packet_handler;
759 }
760 
761 void mesh_network_set_proxy_message_handler(void (*packet_handler)(mesh_network_callback_type_t callback_type, mesh_network_pdu_t * network_pdu)){
762     mesh_network_proxy_message_handler = packet_handler;
763 }
764 
765 void mesh_network_set_primary_element_address(uint16_t addr){
766     mesh_network_primary_address = addr;
767     mesh_network_num_elements = 1;
768 }
769 
770 void mesh_network_received_message(const uint8_t * pdu_data, uint8_t pdu_len, uint8_t flags){
771     // verify len
772     if (pdu_len > 29) return;
773 
774     // allocate network_pdu
775     mesh_network_pdu_t * network_pdu = mesh_network_pdu_get();
776     if (!network_pdu) return;
777 
778     // store data
779     memcpy(network_pdu->data, pdu_data, pdu_len);
780     network_pdu->len = pdu_len;
781     network_pdu->flags = flags;
782 
783     // add to list and go
784     btstack_linked_list_add_tail(&network_pdus_received, (btstack_linked_item_t *) network_pdu);
785     mesh_network_run();
786 
787 }
788 
789 void mesh_network_process_proxy_configuration_message(const uint8_t * pdu_data, uint8_t pdu_len){
790     // verify len
791     if (pdu_len > 29) return;
792 
793     // allocate network_pdu
794     mesh_network_pdu_t * network_pdu = mesh_network_pdu_get();
795     if (!network_pdu) return;
796 
797     // store data
798     memcpy(network_pdu->data, pdu_data, pdu_len);
799     network_pdu->len = pdu_len;
800     network_pdu->flags = MESH_NETWORK_PDU_FLAGS_PROXY_CONFIGURATION; // Network PDU
801 
802     // add to list and go
803     btstack_linked_list_add_tail(&network_pdus_received, (btstack_linked_item_t *) network_pdu);
804     mesh_network_run();
805 }
806 
807 void mesh_network_send_pdu(mesh_network_pdu_t * network_pdu){
808 #ifdef LOG_NETWORK
809     printf("TX-A-NetworkPDU (%p): ", network_pdu);
810     printf_hexdump(network_pdu->data, network_pdu->len);
811 #endif
812 
813     if (network_pdu->len > 29){
814         printf("too long, %u\n", network_pdu->len);
815         return;
816     }
817 
818     // setup callback
819     network_pdu->callback = &mesh_network_send_d;
820     network_pdu->flags    = 0;
821 
822     // queue up
823     btstack_linked_list_add_tail(&network_pdus_queued, (btstack_linked_item_t *) network_pdu);
824 
825     // go
826     mesh_network_run();
827 }
828 
829 void mesh_network_encrypt_proxy_configuration_message(mesh_network_pdu_t * network_pdu, void (* callback)(mesh_network_pdu_t * callback)){
830     printf("ProxyPDU(unencrypted): ");
831     printf_hexdump(network_pdu->data, network_pdu->len);
832 
833     // setup callback
834     network_pdu->callback = callback;
835     network_pdu->flags    = MESH_NETWORK_PDU_FLAGS_PROXY_CONFIGURATION;
836 
837     // queue up
838     btstack_linked_list_add_tail(&network_pdus_queued, (btstack_linked_item_t *) network_pdu);
839 
840     // go
841     mesh_network_run();
842 }
843 
844 /*
845  * @brief Setup network pdu header
846  * @param netkey_index
847  * @param ctl
848  * @param ttl
849  * @param seq
850  * @param dest
851  */
852 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){
853     memset(network_pdu, 0, sizeof(mesh_network_pdu_t));
854     // set netkey_index
855     network_pdu->netkey_index = netkey_index;
856     // setup header
857     network_pdu->data[network_pdu->len++] = (global_iv_index << 7) |  nid;
858     uint8_t ctl_ttl = (ctl << 7) | (ttl & 0x7f);
859     network_pdu->data[network_pdu->len++] = ctl_ttl;
860     big_endian_store_24(network_pdu->data, 2, seq);
861     network_pdu->len += 3;
862     big_endian_store_16(network_pdu->data, network_pdu->len, src);
863     network_pdu->len += 2;
864     big_endian_store_16(network_pdu->data, network_pdu->len, dest);
865     network_pdu->len += 2;
866     memcpy(&network_pdu->data[network_pdu->len], transport_pdu_data, transport_pdu_len);
867     network_pdu->len += transport_pdu_len;
868 }
869 
870 /*
871  * @brief Setup network pdu header
872  * @param netkey_index
873  * @param ctl
874  * @param ttl
875  * @param seq
876  * @param dest
877  */
878 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){
879     // set netkey_index
880     network_pdu->netkey_index = netkey_index;
881     // setup header
882     network_pdu->data[0] = (global_iv_index << 7) |  nid;
883     uint8_t ctl_ttl = (ctl << 7) | (ttl & 0x7f);
884     network_pdu->data[1] = ctl_ttl;
885     big_endian_store_24(network_pdu->data, 2, seq);
886     big_endian_store_16(network_pdu->data, 5, src);
887     big_endian_store_16(network_pdu->data, 7, dest);
888 }
889 
890 void mesh_set_iv_index(uint32_t iv_index){
891     global_iv_index = iv_index;
892 }
893 
894 uint32_t mesh_get_iv_index(void){
895     return  global_iv_index;
896 }
897 
898 // Network PDU Getter
899 uint8_t  mesh_network_nid(mesh_network_pdu_t * network_pdu){
900     return network_pdu->data[0] & 0x7f;
901 }
902 uint16_t mesh_network_control(mesh_network_pdu_t * network_pdu){
903     return network_pdu->data[1] & 0x80;
904 }
905 uint8_t mesh_network_ttl(mesh_network_pdu_t * network_pdu){
906     return network_pdu->data[1] & 0x7f;
907 }
908 uint32_t mesh_network_seq(mesh_network_pdu_t * network_pdu){
909     return big_endian_read_24(network_pdu->data, 2);
910 }
911 uint16_t mesh_network_src(mesh_network_pdu_t * network_pdu){
912     return big_endian_read_16(network_pdu->data, 5);
913 }
914 uint16_t mesh_network_dst(mesh_network_pdu_t * network_pdu){
915     return big_endian_read_16(network_pdu->data, 7);
916 }
917 int mesh_network_segmented(mesh_network_pdu_t * network_pdu){
918     return network_pdu->data[9] & 0x80;
919 }
920 uint8_t * mesh_network_pdu_data(mesh_network_pdu_t * network_pdu){
921     return &network_pdu->data[9];
922 }
923 uint8_t   mesh_network_pdu_len(mesh_network_pdu_t * network_pdu){
924     return network_pdu->len - 9;
925 }
926 
927 static void mesh_network_dump_network_pdu(mesh_network_pdu_t * network_pdu){
928     if (network_pdu){
929         printf("- %p: ", network_pdu); printf_hexdump(network_pdu->data, network_pdu->len);
930     }
931 }
932 static void mesh_network_dump_network_pdus(const char * name, btstack_linked_list_t * list){
933     printf("List: %s:\n", name);
934     btstack_linked_list_iterator_t it;
935     btstack_linked_list_iterator_init(&it, list);
936     while (btstack_linked_list_iterator_has_next(&it)){
937         mesh_network_pdu_t * network_pdu = (mesh_network_pdu_t*) btstack_linked_list_iterator_next(&it);
938         mesh_network_dump_network_pdu(network_pdu);
939     }
940 }
941 static void mesh_network_reset_network_pdus(btstack_linked_list_t * list){
942     while (!btstack_linked_list_empty(list)){
943         mesh_network_pdu_t * pdu = (mesh_network_pdu_t *) btstack_linked_list_pop(list);
944         btstack_memory_mesh_network_pdu_free(pdu);
945     }
946 }
947 void mesh_network_dump(void){
948     mesh_network_dump_network_pdus("network_pdus_received", &network_pdus_received);
949     mesh_network_dump_network_pdus("network_pdus_queued", &network_pdus_queued);
950     mesh_network_dump_network_pdus("network_pdus_outgoing", &network_pdus_outgoing);
951     printf("network_pdu_in_validation: \n");
952     mesh_network_dump_network_pdu(network_pdu_in_validation);
953 }
954 void mesh_network_reset(void){
955     mesh_network_reset_network_pdus(&network_pdus_received);
956     mesh_network_reset_network_pdus(&network_pdus_queued);
957     mesh_network_reset_network_pdus(&network_pdus_outgoing);
958 }
959 
960 // buffer pool
961 mesh_network_pdu_t * mesh_network_pdu_get(void){
962     mesh_network_pdu_t * network_pdu = btstack_memory_mesh_network_pdu_get();
963     if (network_pdu) {
964         memset(network_pdu, 0, sizeof(mesh_network_pdu_t));
965         network_pdu->pdu_header.pdu_type = MESH_PDU_TYPE_NETWORK;
966     }
967     return network_pdu;
968 }
969 
970 void mesh_network_pdu_free(mesh_network_pdu_t * network_pdu){
971     btstack_memory_mesh_network_pdu_free(network_pdu);
972 }
973