xref: /btstack/src/mesh/mesh_lower_transport.c (revision cd5f23a3250874824c01a2b3326a9522fea3f99f)
1 /*
2  * Copyright (C) 2014 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_lower_transport.c"
39 
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <btstack.h>
44 
45 #include "btstack_memory.h"
46 #include "btstack_util.h"
47 #include "btstack_bool.h"
48 
49 #include "mesh/beacon.h"
50 #include "mesh/mesh_iv_index_seq_number.h"
51 #include "mesh/mesh_lower_transport.h"
52 #include "mesh/mesh_node.h"
53 #include "mesh/mesh_peer.h"
54 
55 #define LOG_LOWER_TRANSPORT
56 
57 // prototypes
58 static void mesh_lower_transport_run(void);
59 static void mesh_lower_transport_outgoing_complete(mesh_segmented_pdu_t * segmented_pdu, mesh_transport_status_t status);
60 static void mesh_lower_transport_outgoing_segment_transmission_timeout(btstack_timer_source_t * ts);
61 
62 
63 // lower transport outgoing state
64 
65 // queued mesh_segmented_pdu_t or mesh_network_pdu_t
66 static btstack_linked_list_t lower_transport_outgoing_ready;
67 
68 // mesh_segmented_pdu_t to unicast address, segment transmission timer is active
69 static btstack_linked_list_t lower_transport_outgoing_waiting;
70 
71 // active outgoing segmented message
72 static mesh_segmented_pdu_t * lower_transport_outgoing_message;
73 // index of outgoing segment
74 static uint16_t               lower_transport_outgoing_seg_o;
75 // network pdu with outgoing segment
76 static mesh_network_pdu_t   * lower_transport_outgoing_segment;
77 // segment currently queued at network layer (only valid for lower_transport_outgoing_message)
78 static bool                    lower_transport_outgoing_segment_at_network_layer;
79 // transmission timeout occurred (while outgoing segment queued at network layer)
80 static bool                    lower_transport_outgoing_transmission_timeout;
81 // transmission completed fully ack'ed (while outgoing segment queued at network layer)
82 static bool                    lower_transport_outgoing_transmission_complete;
83 // transmission aborted by remote (while outgoing segment queued at network layer)
84 static bool                    lower_transport_outgoing_transmission_aborted;
85 
86 // active outgoing unsegmented message
87 static mesh_network_pdu_t *   lower_transport_outgoing_network_pdu;
88 
89 // deliver to higher layer
90 static void (*higher_layer_handler)( mesh_transport_callback_type_t callback_type, mesh_transport_status_t status, mesh_pdu_t * pdu);
91 static mesh_pdu_t * mesh_lower_transport_higher_layer_pdu;
92 static btstack_linked_list_t mesh_lower_transport_queued_for_higher_layer;
93 
94 static void mesh_print_hex(const char * name, const uint8_t * data, uint16_t len){
95     printf("%-20s ", name);
96     printf_hexdump(data, len);
97 }
98 
99 // utility
100 
101 mesh_segmented_pdu_t * mesh_segmented_pdu_get(void){
102     mesh_segmented_pdu_t * message_pdu = btstack_memory_mesh_segmented_pdu_get();
103     if (message_pdu){
104         message_pdu->pdu_header.pdu_type = MESH_PDU_TYPE_SEGMENTED;
105     }
106     return message_pdu;
107 }
108 
109 void mesh_segmented_pdu_free(mesh_segmented_pdu_t * message_pdu){
110     while (message_pdu->segments){
111         mesh_network_pdu_t * segment = (mesh_network_pdu_t *) btstack_linked_list_pop(&message_pdu->segments);
112         mesh_network_pdu_free(segment);
113     }
114     btstack_memory_mesh_segmented_pdu_free(message_pdu);
115 }
116 
117 // INCOMING //
118 
119 static void mesh_lower_transport_incoming_deliver_to_higher_layer(void){
120     if (mesh_lower_transport_higher_layer_pdu == NULL && !btstack_linked_list_empty(&mesh_lower_transport_queued_for_higher_layer)){
121         mesh_pdu_t * pdu = (mesh_pdu_t *) btstack_linked_list_pop(&mesh_lower_transport_queued_for_higher_layer);
122 
123         switch (pdu->pdu_type){
124             case MESH_PDU_TYPE_NETWORK:
125                 // unsegmented pdu
126                 mesh_lower_transport_higher_layer_pdu = (mesh_pdu_t *) pdu;
127                 pdu->pdu_type = MESH_PDU_TYPE_UNSEGMENTED;
128                 break;
129             case MESH_PDU_TYPE_SEGMENTED:
130                 // segmented control or access pdu
131                 mesh_lower_transport_higher_layer_pdu = pdu;
132                 break;
133             default:
134                 btstack_assert(false);
135                 break;
136         }
137         higher_layer_handler(MESH_TRANSPORT_PDU_RECEIVED, MESH_TRANSPORT_STATUS_SUCCESS, mesh_lower_transport_higher_layer_pdu);
138     }
139 }
140 
141 static void mesh_lower_transport_incoming_queue_for_higher_layer(mesh_pdu_t * pdu){
142     btstack_linked_list_add_tail(&mesh_lower_transport_queued_for_higher_layer, (btstack_linked_item_t *) pdu);
143     mesh_lower_transport_incoming_deliver_to_higher_layer();
144 }
145 
146 static void mesh_lower_transport_incoming_setup_acknowledge_message(uint8_t * data, uint8_t obo, uint16_t seq_zero, uint32_t block_ack){
147     // printf("ACK Upper Transport, seq_zero %x\n", seq_zero);
148     data[0] = 0;    // SEG = 0, Opcode = 0
149     big_endian_store_16( data, 1, (obo << 15) | (seq_zero << 2) | 0);    // OBO, SeqZero, RFU
150     big_endian_store_32( data, 3, block_ack);
151 #ifdef LOG_LOWER_TRANSPORT
152     mesh_print_hex("ACK Upper Transport", data, 7);
153 #endif
154 }
155 
156 static void mesh_lower_transport_incoming_send_ack(uint16_t netkey_index, uint8_t ttl, uint16_t dest, uint16_t seq_zero, uint32_t block_ack){
157     // setup ack message
158     uint8_t  ack_msg[7];
159     mesh_lower_transport_incoming_setup_acknowledge_message(ack_msg, 0, seq_zero, block_ack);
160     //
161     // "3.4.5.2: The output filter of the interface connected to advertising or GATT bearers shall drop all messages with TTL value set to 1."
162     // if (ttl <= 1) return 0;
163 
164     // TODO: check transport_pdu_len depending on ctl
165 
166     // lookup network by netkey_index
167     const mesh_network_key_t * network_key = mesh_network_key_list_get(netkey_index);
168     if (!network_key) return;
169 
170     // allocate network_pdu
171     mesh_network_pdu_t * network_pdu = mesh_network_pdu_get();
172     if (!network_pdu) return;
173 
174     // setup network_pdu
175     network_pdu->pdu_header.pdu_type = MESH_PDU_TYPE_SEGMENT_ACKNOWLEDGMENT;
176     mesh_network_setup_pdu(network_pdu, netkey_index, network_key->nid, 1, ttl, mesh_sequence_number_next(), mesh_node_get_primary_element_address(), dest, ack_msg, sizeof(ack_msg));
177 
178     // send network_pdu
179     mesh_network_send_pdu(network_pdu);
180 }
181 
182 static void mesh_lower_transport_incoming_send_ack_for_segmented_pdu(mesh_segmented_pdu_t * segmented_pdu){
183     uint16_t seq_zero = segmented_pdu->seq & 0x1fff;
184     uint8_t  ttl = segmented_pdu->ctl_ttl & 0x7f;
185     uint16_t dest = segmented_pdu->src;
186     uint16_t netkey_index = segmented_pdu->netkey_index;
187 #ifdef LOG_LOWER_TRANSPORT
188     printf("mesh_transport_send_ack_for_transport_pdu %p with netkey_index %x, TTL = %u, SeqZero = %x, SRC = %x, DST = %x\n",
189            segmented_pdu, netkey_index, ttl, seq_zero, mesh_node_get_primary_element_address(), dest);
190 #endif
191     mesh_lower_transport_incoming_send_ack(netkey_index, ttl, dest, seq_zero, segmented_pdu->block_ack);
192 }
193 
194 static void mesh_lower_transport_incoming_send_ack_for_network_pdu(mesh_network_pdu_t *network_pdu, uint16_t seq_zero, uint32_t block_ack) {
195     uint8_t ttl = mesh_network_ttl(network_pdu);
196     uint16_t dest = mesh_network_src(network_pdu);
197     uint16_t netkey_index = network_pdu->netkey_index;
198 #ifdef LOG_LOWER_TRANSPORT
199     printf("mesh_transport_send_ack_for_network_pdu %p with netkey_index %x, TTL = %u, SeqZero = %x, SRC = %x, DST = %x\n",
200            network_pdu, netkey_index, ttl, seq_zero, mesh_node_get_primary_element_address(), dest);
201 #endif
202     mesh_lower_transport_incoming_send_ack(netkey_index, ttl, dest, seq_zero, block_ack);
203 }
204 
205 static void mesh_lower_transport_incoming_stop_acknowledgment_timer(mesh_segmented_pdu_t *segmented_pdu){
206     if ((segmented_pdu->flags & MESH_TRANSPORT_FLAG_ACK_TIMER) == 0) return;
207     segmented_pdu->flags &= ~MESH_TRANSPORT_FLAG_ACK_TIMER;
208     btstack_run_loop_remove_timer(&segmented_pdu->acknowledgement_timer);
209 }
210 
211 static void mesh_lower_transport_incoming_stop_incomplete_timer(mesh_segmented_pdu_t *segmented_pdu){
212     if ((segmented_pdu->flags & MESH_TRANSPORT_FLAG_INCOMPLETE_TIMER) == 0) return;
213     segmented_pdu->flags &= ~MESH_TRANSPORT_FLAG_INCOMPLETE_TIMER;
214     btstack_run_loop_remove_timer(&segmented_pdu->incomplete_timer);
215 }
216 
217 static void mesh_lower_transport_incoming_segmented_message_complete(mesh_segmented_pdu_t * segmented_pdu){
218     // stop timers
219     mesh_lower_transport_incoming_stop_acknowledgment_timer(segmented_pdu);
220     mesh_lower_transport_incoming_stop_incomplete_timer(segmented_pdu);
221     // stop reassembly
222     mesh_peer_t * peer = mesh_peer_for_addr(segmented_pdu->src);
223     if (peer){
224         peer->message_pdu = NULL;
225     }
226 }
227 
228 static void mesh_lower_transport_incoming_ack_timeout(btstack_timer_source_t *ts){
229     mesh_segmented_pdu_t * segmented_pdu = (mesh_segmented_pdu_t *) btstack_run_loop_get_timer_context(ts);
230 #ifdef LOG_LOWER_TRANSPORT
231     printf("ACK: acknowledgement timer fired for %p, send ACK\n", segmented_pdu);
232 #endif
233     segmented_pdu->flags &= ~MESH_TRANSPORT_FLAG_ACK_TIMER;
234     mesh_lower_transport_incoming_send_ack_for_segmented_pdu(segmented_pdu);
235 }
236 
237 static void mesh_lower_transport_incoming_incomplete_timeout(btstack_timer_source_t *ts){
238     mesh_segmented_pdu_t * segmented_pdu = (mesh_segmented_pdu_t *) btstack_run_loop_get_timer_context(ts);
239 #ifdef LOG_LOWER_TRANSPORT
240     printf("mesh_lower_transport_incoming_incomplete_timeout for %p - give up\n", segmented_pdu);
241 #endif
242     mesh_lower_transport_incoming_segmented_message_complete(segmented_pdu);
243     // free message
244     mesh_segmented_pdu_free(segmented_pdu);
245 }
246 
247 static void mesh_lower_transport_incoming_start_acknowledgment_timer(mesh_segmented_pdu_t * segmented_pdu, uint32_t timeout){
248 #ifdef LOG_LOWER_TRANSPORT
249     printf("ACK: start rx ack timer for %p, timeout %u ms\n", segmented_pdu, (int) timeout);
250 #endif
251     btstack_run_loop_set_timer(&segmented_pdu->acknowledgement_timer, timeout);
252     btstack_run_loop_set_timer_handler(&segmented_pdu->acknowledgement_timer, &mesh_lower_transport_incoming_ack_timeout);
253     btstack_run_loop_set_timer_context(&segmented_pdu->acknowledgement_timer, segmented_pdu);
254     btstack_run_loop_add_timer(&segmented_pdu->acknowledgement_timer);
255     segmented_pdu->flags |= MESH_TRANSPORT_FLAG_ACK_TIMER;
256 }
257 
258 static void mesh_lower_transport_incoming_restart_incomplete_timer(mesh_segmented_pdu_t * segmented_pdu, uint32_t timeout,
259                                                                    void (*callback)(btstack_timer_source_t *ts)){
260 #ifdef LOG_LOWER_TRANSPORT
261     printf("RX-(re)start incomplete timer for %p, timeout %u ms\n", segmented_pdu, (int) timeout);
262 #endif
263     if ((segmented_pdu->flags & MESH_TRANSPORT_FLAG_INCOMPLETE_TIMER) != 0){
264         btstack_run_loop_remove_timer(&segmented_pdu->incomplete_timer);
265     }
266     btstack_run_loop_set_timer(&segmented_pdu->incomplete_timer, timeout);
267     btstack_run_loop_set_timer_handler(&segmented_pdu->incomplete_timer, callback);
268     btstack_run_loop_set_timer_context(&segmented_pdu->incomplete_timer, segmented_pdu);
269     btstack_run_loop_add_timer(&segmented_pdu->incomplete_timer);
270     segmented_pdu->flags |= MESH_TRANSPORT_FLAG_INCOMPLETE_TIMER;
271 }
272 
273 static mesh_segmented_pdu_t * mesh_lower_transport_incoming_pdu_for_segmented_message(mesh_network_pdu_t *network_pdu){
274     uint16_t src = mesh_network_src(network_pdu);
275     uint16_t seq_zero = ( big_endian_read_16(mesh_network_pdu_data(network_pdu), 1) >> 2) & 0x1fff;
276 #ifdef LOG_LOWER_TRANSPORT
277     printf("mesh_transport_pdu_for_segmented_message: seq_zero %x\n", seq_zero);
278 #endif
279     mesh_peer_t * peer = mesh_peer_for_addr(src);
280     if (!peer) {
281         return NULL;
282     }
283 #ifdef LOG_LOWER_TRANSPORT
284     printf("mesh_seq_zero_validate(%x, %x) -- last (%x, %x)\n", src, seq_zero, peer->address, peer->seq_zero);
285 #endif
286 
287     // reception of transport message ongoing
288     if (peer->message_pdu){
289         // check if segment for same seq zero
290         uint16_t active_seq_zero = peer->message_pdu->seq & 0x1fff;
291         if (active_seq_zero == seq_zero) {
292 #ifdef LOG_LOWER_TRANSPORT
293             printf("mesh_transport_pdu_for_segmented_message: segment for current transport pdu with SeqZero %x\n", active_seq_zero);
294 #endif
295             return peer->message_pdu;
296         } else {
297             // seq zero differs from current transport pdu, but current pdu is not complete
298 #ifdef LOG_LOWER_TRANSPORT
299             printf("mesh_transport_pdu_for_segmented_message: drop segment. current transport pdu SeqZero %x, now %x\n", active_seq_zero, seq_zero);
300 #endif
301             return NULL;
302         }
303     }
304 
305     // send ACK if segment for previously completed transport pdu (no ongoing reception, block ack is cleared)
306     if ((seq_zero == peer->seq_zero) && (peer->block_ack != 0)){
307 #ifdef LOG_LOWER_TRANSPORT
308         printf("mesh_transport_pdu_for_segmented_message: segment for last completed message. send ack\n");
309 #endif
310         mesh_lower_transport_incoming_send_ack_for_network_pdu(network_pdu, seq_zero, peer->block_ack);
311         return NULL;
312     }
313 
314     // reconstruct lowest 24 bit of SeqAuth
315     uint32_t seq = mesh_network_seq(network_pdu);
316     uint32_t seq_auth = (seq & 0xffe000) | seq_zero;
317     if (seq_auth > seq){
318         seq_auth -= 0x2000;
319     }
320 
321     // no transport pdu active, check new message: seq auth is greater OR seq auth is same but no segments
322     if (seq_auth > peer->seq_auth || (seq_auth == peer->seq_auth && peer->block_ack == 0)){
323         mesh_segmented_pdu_t * pdu = mesh_segmented_pdu_get();
324         if (!pdu) return NULL;
325 
326         // cache network pdu header
327         pdu->ivi_nid = network_pdu->data[0];
328         pdu->ctl_ttl = network_pdu->data[1];
329         pdu->src = big_endian_read_16(network_pdu->data, 5);
330         pdu->dst = big_endian_read_16(network_pdu->data, 7);
331         // store lower 24 bit of SeqAuth for App / Device Nonce
332         pdu->seq = seq_auth;
333 
334         // get akf_aid & transmic
335         pdu->akf_aid_control = network_pdu->data[9] & 0x7f;
336         if ((network_pdu->data[10] & 0x80) != 0){
337             pdu->flags |= MESH_TRANSPORT_FLAG_TRANSMIC_64;
338         }
339 
340         // store meta data in new pdu
341         pdu->netkey_index = network_pdu->netkey_index;
342         pdu->block_ack = 0;
343         pdu->flags &= ~MESH_TRANSPORT_FLAG_ACK_TIMER;
344 
345         // update peer info
346         peer->message_pdu   = pdu;
347         peer->seq_zero      = seq_zero;
348         peer->seq_auth      = seq_auth;
349         peer->block_ack     = 0;
350 
351 #ifdef LOG_LOWER_TRANSPORT
352         printf("mesh_transport_pdu_for_segmented_message: setup transport pdu %p for src %x, seq %06x, seq_zero %x\n", pdu, src,
353                pdu->seq, seq_zero);
354 #endif
355         return peer->message_pdu;
356     }  else {
357         // seq zero differs from current transport pdu
358 #ifdef LOG_LOWER_TRANSPORT
359         printf("mesh_transport_pdu_for_segmented_message: drop segment for old seq %x\n", seq_zero);
360 #endif
361         return NULL;
362     }
363 }
364 
365 static void mesh_lower_transport_incoming_process_segment(mesh_segmented_pdu_t * message_pdu, mesh_network_pdu_t * network_pdu){
366 
367     uint8_t * lower_transport_pdu     = mesh_network_pdu_data(network_pdu);
368     uint8_t   lower_transport_pdu_len = mesh_network_pdu_len(network_pdu);
369 
370     // get seq_zero
371     uint16_t seq_zero =  ( big_endian_read_16(lower_transport_pdu, 1) >> 2) & 0x1fff;
372 
373     // get seg fields
374     uint8_t  seg_o    =  ( big_endian_read_16(lower_transport_pdu, 2) >> 5) & 0x001f;
375     uint8_t  seg_n    =  lower_transport_pdu[3] & 0x1f;
376     uint8_t   segment_len  =  lower_transport_pdu_len - 4;
377     uint8_t * segment_data = &lower_transport_pdu[4];
378 
379 #ifdef LOG_LOWER_TRANSPORT
380     uint8_t transmic_len = ((message_pdu->flags & MESH_TRANSPORT_FLAG_TRANSMIC_64) != 0) ? 64 : 32;
381     printf("mesh_lower_transport_incoming_process_segment: seq zero %04x, seg_o %02x, seg_n %02x, transmic len: %u bit\n", seq_zero, seg_o, seg_n, transmic_len);
382     mesh_print_hex("Segment", segment_data, segment_len);
383 #endif
384 
385     // drop if already stored
386     if ((message_pdu->block_ack & (1<<seg_o)) != 0){
387         mesh_network_message_processed_by_higher_layer(network_pdu);
388         return;
389     }
390 
391     // mark as received
392     message_pdu->block_ack |= (1<<seg_o);
393 
394     // store segment
395     uint8_t max_segment_len = mesh_network_control(network_pdu) ? 8 : 12;
396     mesh_network_pdu_t * latest_segment = (mesh_network_pdu_t *) btstack_linked_list_get_first_item(&message_pdu->segments);
397     if ((latest_segment != NULL) && ((MESH_NETWORK_PAYLOAD_MAX - latest_segment->len) > (max_segment_len  + 1))){
398         // store in last added segment if there is enough space available
399         latest_segment->data[latest_segment->len++] = seg_o;
400         (void) memcpy(&latest_segment->data[latest_segment->len], &lower_transport_pdu[4], segment_len);
401         latest_segment->len += segment_len;
402         // free buffer
403         mesh_network_message_processed_by_higher_layer(network_pdu);
404     } else {
405         // move to beginning
406         network_pdu->data[0] = seg_o;
407         uint8_t i;
408         for (i=0;i<segment_len;i++){
409             network_pdu->data[1+i] = network_pdu->data[13+i];
410         }
411         network_pdu->len = 1 + segment_len;
412         // add this buffer
413         btstack_linked_list_add(&message_pdu->segments, (btstack_linked_item_t *) network_pdu);
414     }
415 
416     // last segment -> store len
417     if (seg_o == seg_n){
418         message_pdu->len = (seg_n * max_segment_len) + segment_len;
419 #ifdef LOG_LOWER_TRANSPORT
420         printf("Assembled payload len %u\n", message_pdu->len);
421 #endif
422     }
423 
424     // check for complete
425     int i;
426     for (i=0;i<=seg_n;i++){
427         if ( (message_pdu->block_ack & (1<<i)) == 0) return;
428     }
429 
430     // store block ack in peer info
431     mesh_peer_t * peer = mesh_peer_for_addr(message_pdu->src);
432     // TODO: check if NULL check can be removed
433     if (peer){
434         peer->block_ack = message_pdu->block_ack;
435     }
436 
437     // send ack
438     mesh_lower_transport_incoming_send_ack_for_segmented_pdu(message_pdu);
439 
440     // forward to upper transport
441     mesh_lower_transport_incoming_queue_for_higher_layer((mesh_pdu_t *) message_pdu);
442 
443     // mark as done
444     mesh_lower_transport_incoming_segmented_message_complete(message_pdu);
445 }
446 
447 void mesh_lower_transport_message_processed_by_higher_layer(mesh_pdu_t * pdu){
448     btstack_assert(pdu == mesh_lower_transport_higher_layer_pdu);
449     mesh_lower_transport_higher_layer_pdu = NULL;
450     mesh_network_pdu_t * network_pdu;
451     switch (pdu->pdu_type){
452         case MESH_PDU_TYPE_SEGMENTED:
453             // free segments
454             mesh_segmented_pdu_free((mesh_segmented_pdu_t *) pdu);
455             break;
456         case MESH_PDU_TYPE_UNSEGMENTED:
457             network_pdu = (mesh_network_pdu_t *) pdu;
458             mesh_network_message_processed_by_higher_layer(network_pdu);
459             break;
460         default:
461             btstack_assert(0);
462             break;
463     }
464     mesh_lower_transport_incoming_deliver_to_higher_layer();
465 }
466 
467 // OUTGOING //
468 
469 static void mesh_lower_transport_outgoing_setup_block_ack(mesh_segmented_pdu_t *message_pdu){
470     // setup block ack - set bit for segment to send, will be cleared on ack
471     int      ctl = message_pdu->ctl_ttl >> 7;
472     uint16_t max_segment_len = ctl ? 8 : 12;    // control 8 bytes (64 bit NetMic), access 12 bytes (32 bit NetMIC)
473     uint8_t  seg_n = (message_pdu->len - 1) / max_segment_len;
474     if (seg_n < 31){
475         message_pdu->block_ack = (1 << (seg_n+1)) - 1;
476     } else {
477         message_pdu->block_ack = 0xffffffff;
478     }
479 }
480 
481 static mesh_segmented_pdu_t * mesh_lower_transport_outgoing_message_for_dst(uint16_t dst){
482     if (lower_transport_outgoing_message != NULL && lower_transport_outgoing_message->dst == dst){
483         return lower_transport_outgoing_message;
484     }
485     return NULL;
486 }
487 
488 static void mesh_lower_transport_outgoing_process_segment_acknowledgement_message(mesh_network_pdu_t *network_pdu){
489     mesh_segmented_pdu_t * segmented_pdu = mesh_lower_transport_outgoing_message_for_dst( mesh_network_src(network_pdu));
490     if (segmented_pdu == NULL) return;
491 
492     uint8_t * lower_transport_pdu     = mesh_network_pdu_data(network_pdu);
493     uint16_t seq_zero_pdu = big_endian_read_16(lower_transport_pdu, 1) >> 2;
494     uint16_t seq_zero_out = lower_transport_outgoing_message->seq & 0x1fff;
495     uint32_t block_ack = big_endian_read_32(lower_transport_pdu, 3);
496 
497 #ifdef LOG_LOWER_TRANSPORT
498     printf("[+] Segment Acknowledgment message with seq_zero %06x, block_ack %08x - outgoing seq %06x, block_ack %08x\n",
499            seq_zero_pdu, block_ack, seq_zero_out, segmented_pdu->block_ack);
500 #endif
501 
502     if (block_ack == 0){
503         // If a Segment Acknowledgment message with the BlockAck field set to 0x00000000 is received,
504         // then the Upper Transport PDU shall be immediately cancelled and the higher layers shall be notified that
505         // the Upper Transport PDU has been cancelled.
506 #ifdef LOG_LOWER_TRANSPORT
507         printf("[+] Block Ack == 0 => Abort\n");
508 #endif
509         // current?
510         if ((lower_transport_outgoing_message == segmented_pdu) && lower_transport_outgoing_segment_at_network_layer){
511             lower_transport_outgoing_transmission_aborted = true;
512         } else {
513             mesh_lower_transport_outgoing_complete(segmented_pdu, MESH_TRANSPORT_STATUS_SEND_ABORT_BY_REMOTE);
514         }
515         return;
516     }
517     if (seq_zero_pdu != seq_zero_out){
518 
519 #ifdef LOG_LOWER_TRANSPORT
520         printf("[!] Seq Zero doesn't match\n");
521 #endif
522         return;
523     }
524 
525     segmented_pdu->block_ack &= ~block_ack;
526 #ifdef LOG_LOWER_TRANSPORT
527     printf("[+] Updated block_ack %08x\n", segmented_pdu->block_ack);
528 #endif
529 
530     if (segmented_pdu->block_ack == 0){
531 #ifdef LOG_LOWER_TRANSPORT
532         printf("[+] Sent complete\n");
533 #endif
534 
535         if ((lower_transport_outgoing_message == segmented_pdu) && lower_transport_outgoing_segment_at_network_layer){
536             lower_transport_outgoing_transmission_complete = true;
537         } else {
538             mesh_lower_transport_outgoing_complete(segmented_pdu, MESH_TRANSPORT_STATUS_SUCCESS);
539         }
540     }
541 }
542 
543 static void mesh_lower_transport_outgoing_stop_acknowledgment_timer(mesh_segmented_pdu_t *segmented_pdu){
544     if ((segmented_pdu->flags & MESH_TRANSPORT_FLAG_ACK_TIMER) == 0) return;
545     segmented_pdu->flags &= ~MESH_TRANSPORT_FLAG_ACK_TIMER;
546     btstack_run_loop_remove_timer(&segmented_pdu->acknowledgement_timer);
547 }
548 
549 static void mesh_lower_transport_outgoing_restart_segment_transmission_timer(mesh_segmented_pdu_t *segmented_pdu){
550     // restart segment transmission timer for unicast dst
551     // - "This timer shall be set to a minimum of 200 + 50 * TTL milliseconds."
552     uint32_t timeout = 200 + 50 * (segmented_pdu->ctl_ttl & 0x7f);
553     if ((segmented_pdu->flags & MESH_TRANSPORT_FLAG_ACK_TIMER) != 0){
554         btstack_run_loop_remove_timer(&lower_transport_outgoing_message->acknowledgement_timer);
555     }
556 
557 #ifdef LOG_LOWER_TRANSPORT
558     printf("[+] Lower transport, segmented pdu %p, seq %06x: setup transmission timeout %u ms\n", segmented_pdu,
559            segmented_pdu->seq, (int) timeout);
560 #endif
561 
562     btstack_run_loop_set_timer(&segmented_pdu->acknowledgement_timer, timeout);
563     btstack_run_loop_set_timer_handler(&segmented_pdu->acknowledgement_timer, &mesh_lower_transport_outgoing_segment_transmission_timeout);
564     btstack_run_loop_set_timer_context(&segmented_pdu->acknowledgement_timer, lower_transport_outgoing_message);
565     btstack_run_loop_add_timer(&segmented_pdu->acknowledgement_timer);
566     segmented_pdu->flags |= MESH_TRANSPORT_FLAG_ACK_TIMER;
567 }
568 
569 static void mesh_lower_transport_outgoing_complete(mesh_segmented_pdu_t * segmented_pdu, mesh_transport_status_t status){
570     btstack_assert(segmented_pdu != NULL);
571 #ifdef LOG_LOWER_TRANSPORT
572     printf("[+] outgoing_complete %p, ack timer active %u, incomplete active %u\n", segmented_pdu,
573            ((segmented_pdu->flags & MESH_TRANSPORT_FLAG_ACK_TIMER) != 0), ((segmented_pdu->flags & MESH_TRANSPORT_FLAG_INCOMPLETE_TIMER) != 0));
574 #endif
575     // stop timers
576     mesh_lower_transport_outgoing_stop_acknowledgment_timer(segmented_pdu);
577 
578     // remove from lists
579     if (lower_transport_outgoing_message == segmented_pdu){
580         lower_transport_outgoing_message = NULL;
581     } else {
582         btstack_linked_list_remove(&lower_transport_outgoing_waiting, (btstack_linked_item_t *) segmented_pdu);
583         btstack_linked_list_remove(&lower_transport_outgoing_ready, (btstack_linked_item_t *) segmented_pdu);
584     }
585 
586     // notify upper transport
587     higher_layer_handler(MESH_TRANSPORT_PDU_SENT, status, (mesh_pdu_t *) segmented_pdu);
588 }
589 
590 static void mesh_lower_transport_outgoing_setup_segment(mesh_segmented_pdu_t *message_pdu, uint8_t seg_o, mesh_network_pdu_t *network_pdu){
591 
592     int ctl = message_pdu->ctl_ttl >> 7;
593     uint16_t max_segment_len = ctl ? 8 : 12;    // control 8 bytes (64 bit NetMic), access 12 bytes (32 bit NetMIC)
594 
595     // use seq number from transport pdu once if MESH_TRANSPORT_FLAG_SEQ_RESERVED (to allow reserving seq number in upper transport while using all seq numbers)
596     uint32_t seq;
597     if ((message_pdu->flags & MESH_TRANSPORT_FLAG_SEQ_RESERVED) != 0){
598         message_pdu->flags &= ~(MESH_TRANSPORT_FLAG_SEQ_RESERVED);
599         seq = message_pdu->seq;
600     } else {
601         seq = mesh_sequence_number_next();
602     }
603     uint16_t seq_zero = message_pdu->seq & 0x01fff;
604     uint8_t  seg_n    = (message_pdu->len - 1) / max_segment_len;
605     uint8_t  szmic    = ((message_pdu->flags & MESH_TRANSPORT_FLAG_TRANSMIC_64) != 0) ? 1 : 0;
606     uint8_t  nid      = message_pdu->ivi_nid & 0x7f;
607     uint8_t  ttl      = message_pdu->ctl_ttl & 0x7f;
608     uint16_t src      = message_pdu->src;
609     uint16_t dest     = message_pdu->dst;
610 
611     // only 1 for access messages with 64 bit TransMIC
612     btstack_assert((szmic == 0) || !ctl);
613 
614     // current segment.
615     uint16_t seg_offset = seg_o * max_segment_len;
616 
617     uint8_t lower_transport_pdu_data[16];
618     lower_transport_pdu_data[0] = 0x80 | message_pdu->akf_aid_control;
619     big_endian_store_24(lower_transport_pdu_data, 1, (szmic << 23) | (seq_zero << 10) | (seg_o << 5) | seg_n);
620     uint16_t segment_len = btstack_min(message_pdu->len - seg_offset, max_segment_len);
621 
622     uint16_t lower_transport_pdu_len = 4 + segment_len;
623 
624     // find network-pdu with chunk for seg_offset
625     mesh_network_pdu_t * chunk = (mesh_network_pdu_t *) lower_transport_outgoing_message->segments;
626     uint16_t chunk_start = 0;
627     while ((chunk_start + MESH_NETWORK_PAYLOAD_MAX) <= seg_offset){
628         chunk = (mesh_network_pdu_t *) chunk->pdu_header.item.next;
629         chunk_start += MESH_NETWORK_PAYLOAD_MAX;
630     }
631     // first part
632     uint16_t chunk_offset = seg_offset - chunk_start;
633     uint16_t bytes_to_copy = btstack_min(MESH_NETWORK_PAYLOAD_MAX - chunk_offset, segment_len);
634     (void)memcpy(&lower_transport_pdu_data[4],
635                  &chunk->data[chunk_offset], bytes_to_copy);
636     segment_len -= bytes_to_copy;
637     // second part
638     if (segment_len > 0){
639         chunk = (mesh_network_pdu_t *) chunk->pdu_header.item.next;
640         (void)memcpy(&lower_transport_pdu_data[4+bytes_to_copy],
641                      &chunk->data[0], segment_len);
642     }
643 
644     mesh_network_setup_pdu(network_pdu, message_pdu->netkey_index, nid, 0, ttl, seq, src, dest, lower_transport_pdu_data, lower_transport_pdu_len);
645 }
646 
647 static void mesh_lower_transport_outgoing_send_next_segment(void){
648     btstack_assert(lower_transport_outgoing_message != NULL);
649 
650 #ifdef LOG_LOWER_TRANSPORT
651     printf("[+] Lower Transport, segmented pdu %p, seq %06x: send next segment\n", lower_transport_outgoing_message,
652            lower_transport_outgoing_message->seq);
653 #endif
654 
655     int ctl = lower_transport_outgoing_message->ctl_ttl >> 7;
656     uint16_t max_segment_len = ctl ? 8 : 12;    // control 8 bytes (64 bit NetMic), access 12 bytes (32 bit NetMIC)
657     uint8_t  seg_n = (lower_transport_outgoing_message->len - 1) / max_segment_len;
658 
659     // find next unacknowledged segment
660     while ((lower_transport_outgoing_seg_o <= seg_n) && ((lower_transport_outgoing_message->block_ack & (1 << lower_transport_outgoing_seg_o)) == 0)){
661         lower_transport_outgoing_seg_o++;
662     }
663 
664     if (lower_transport_outgoing_seg_o > seg_n){
665 #ifdef LOG_LOWER_TRANSPORT
666         printf("[+] Lower Transport, segmented pdu %p, seq %06x: send complete (dst %x)\n", lower_transport_outgoing_message,
667                lower_transport_outgoing_message->seq,
668                lower_transport_outgoing_message->dst);
669 #endif
670         lower_transport_outgoing_seg_o   = 0;
671 
672         // done for unicast, ack timer already set, too
673         if (mesh_network_address_unicast(lower_transport_outgoing_message->dst)) {
674             btstack_linked_list_add(&lower_transport_outgoing_waiting, (btstack_linked_item_t *) lower_transport_outgoing_message);
675             lower_transport_outgoing_message = NULL;
676             return;
677         }
678 
679         // done for group/virtual, no more retries?
680         if (lower_transport_outgoing_message->retry_count == 0){
681 #ifdef LOG_LOWER_TRANSPORT
682             printf("[+] Lower Transport, message unacknowledged -> free\n");
683 #endif
684             // notify upper transport
685             mesh_lower_transport_outgoing_complete(lower_transport_outgoing_message, MESH_TRANSPORT_STATUS_SUCCESS);
686             return;
687         }
688 
689         // re-queue mssage
690 #ifdef LOG_LOWER_TRANSPORT
691         printf("[+] Lower Transport, message unacknowledged retry count %u\n", lower_transport_outgoing_message->retry_count);
692 #endif
693         lower_transport_outgoing_message->retry_count--;
694         btstack_linked_list_add(&lower_transport_outgoing_ready, (btstack_linked_item_t *) lower_transport_outgoing_message);
695         lower_transport_outgoing_message = NULL;
696         mesh_lower_transport_run();
697         return;
698     }
699 
700     // restart segment transmission timer for unicast dst
701     if (mesh_network_address_unicast(lower_transport_outgoing_message->dst)){
702         mesh_lower_transport_outgoing_restart_segment_transmission_timer(lower_transport_outgoing_message);
703     }
704 
705     mesh_lower_transport_outgoing_setup_segment(lower_transport_outgoing_message, lower_transport_outgoing_seg_o,
706                                                 lower_transport_outgoing_segment);
707 
708 #ifdef LOG_LOWER_TRANSPORT
709     printf("[+] Lower Transport, segmented pdu %p, seq %06x: send seg_o %x, seg_n %x\n", lower_transport_outgoing_message,
710            lower_transport_outgoing_message->seq, lower_transport_outgoing_seg_o, seg_n);
711     mesh_print_hex("LowerTransportPDU", &lower_transport_outgoing_segment->data[9], lower_transport_outgoing_segment->len-9);
712 #endif
713 
714     // next segment
715     lower_transport_outgoing_seg_o++;
716 
717     // send network pdu
718     lower_transport_outgoing_segment_at_network_layer = true;
719     mesh_network_send_pdu(lower_transport_outgoing_segment);
720 }
721 
722 static void mesh_lower_transport_outgoing_setup_sending_segmented_pdus(mesh_segmented_pdu_t *segmented_pdu) {
723     printf("[+] Lower Transport, segmented pdu %p, seq %06x: send retry count %u\n", segmented_pdu, segmented_pdu->seq, segmented_pdu->retry_count);
724 
725     segmented_pdu->retry_count--;
726     lower_transport_outgoing_seg_o   = 0;
727     lower_transport_outgoing_transmission_timeout  = false;
728     lower_transport_outgoing_transmission_complete = false;
729     lower_transport_outgoing_transmission_aborted  = false;
730 
731     lower_transport_outgoing_message = segmented_pdu;
732 }
733 
734 static void mesh_lower_transport_outgoing_segment_transmission_fired(mesh_segmented_pdu_t *segmented_pdu) {
735     // once more?
736     if (segmented_pdu->retry_count == 0){
737         printf("[!] Lower transport, segmented pdu %p, seq %06x: send failed, retries exhausted\n", segmented_pdu,
738                segmented_pdu->seq);
739         mesh_lower_transport_outgoing_complete(segmented_pdu, MESH_TRANSPORT_STATUS_SEND_FAILED);
740         return;
741     }
742 
743 #ifdef LOG_LOWER_TRANSPORT
744     printf("[+] Lower transport, segmented pdu %p, seq %06x: transmission fired\n", segmented_pdu, segmented_pdu->seq);
745 #endif
746 
747     // re-queue message for sending remaining segments
748     if (lower_transport_outgoing_message == segmented_pdu){
749         lower_transport_outgoing_message = NULL;
750     } else {
751         btstack_linked_list_remove(&lower_transport_outgoing_waiting, (btstack_linked_item_t *) segmented_pdu);
752     }
753     btstack_linked_list_add_tail(&lower_transport_outgoing_ready, (btstack_linked_item_t *) segmented_pdu);
754 
755     // continue
756     mesh_lower_transport_run();
757 }
758 
759 static void mesh_lower_transport_outgoing_segment_transmission_timeout(btstack_timer_source_t * ts){
760     mesh_segmented_pdu_t * segmented_pdu = (mesh_segmented_pdu_t *) btstack_run_loop_get_timer_context(ts);
761 #ifdef LOG_LOWER_TRANSPORT
762     printf("[+] Lower transport, segmented pdu %p, seq %06x: transmission timer fired\n", segmented_pdu,
763            segmented_pdu->seq);
764 #endif
765     segmented_pdu->flags &= ~MESH_TRANSPORT_FLAG_ACK_TIMER;
766 
767     if ((segmented_pdu == lower_transport_outgoing_message) && lower_transport_outgoing_segment_at_network_layer){
768         lower_transport_outgoing_transmission_timeout = true;
769     } else {
770         mesh_lower_transport_outgoing_segment_transmission_fired(segmented_pdu);
771     }
772 }
773 
774 // GENERAL //
775 
776 static void mesh_lower_transport_network_pdu_sent(mesh_network_pdu_t *network_pdu){
777     // figure out what pdu was sent
778 
779     // Segment Acknowledgment message sent by us?
780     if (network_pdu->pdu_header.pdu_type == MESH_PDU_TYPE_SEGMENT_ACKNOWLEDGMENT){
781         btstack_memory_mesh_network_pdu_free(network_pdu);
782         return;
783     }
784 
785     // single segment?
786     if (lower_transport_outgoing_segment == network_pdu){
787         btstack_assert(lower_transport_outgoing_message != NULL);
788 
789         // of segmented message
790 #ifdef LOG_LOWER_TRANSPORT
791         printf("[+] Lower transport, segmented pdu %p, seq %06x: network pdu %p sent\n", lower_transport_outgoing_message,
792                lower_transport_outgoing_message->seq, network_pdu);
793 #endif
794 
795         lower_transport_outgoing_segment_at_network_layer = false;
796         if (lower_transport_outgoing_transmission_complete){
797             // handle success
798             lower_transport_outgoing_transmission_complete = false;
799             lower_transport_outgoing_transmission_timeout  = false;
800             mesh_lower_transport_outgoing_complete(lower_transport_outgoing_message, MESH_TRANSPORT_STATUS_SUCCESS);
801             return;
802         }
803         if (lower_transport_outgoing_transmission_aborted){
804             // handle abort
805             lower_transport_outgoing_transmission_complete = false;
806             lower_transport_outgoing_transmission_timeout  = false;
807             mesh_lower_transport_outgoing_complete(lower_transport_outgoing_message, MESH_TRANSPORT_STATUS_SEND_ABORT_BY_REMOTE);
808             return;
809         }
810         if (lower_transport_outgoing_transmission_timeout){
811             // handle timeout
812             lower_transport_outgoing_transmission_timeout = false;
813             mesh_lower_transport_outgoing_segment_transmission_fired(lower_transport_outgoing_message);
814             return;
815         }
816 
817         // send next segment
818         mesh_lower_transport_outgoing_send_next_segment();
819         return;
820     }
821 
822     // other
823     higher_layer_handler(MESH_TRANSPORT_PDU_SENT, MESH_TRANSPORT_STATUS_SUCCESS, (mesh_pdu_t *) network_pdu);
824 }
825 
826 static void mesh_lower_transport_process_unsegmented_control_message(mesh_network_pdu_t *network_pdu){
827     uint8_t * lower_transport_pdu     = mesh_network_pdu_data(network_pdu);
828     uint8_t  opcode = lower_transport_pdu[0];
829 
830 #ifdef LOG_LOWER_TRANSPORT
831     printf("Unsegmented Control message, outgoing message %p, opcode %x\n", lower_transport_outgoing_message, opcode);
832 #endif
833 
834     switch (opcode){
835         case 0:
836             mesh_lower_transport_outgoing_process_segment_acknowledgement_message(network_pdu);
837             mesh_network_message_processed_by_higher_layer(network_pdu);
838             break;
839         default:
840             mesh_lower_transport_incoming_queue_for_higher_layer((mesh_pdu_t *) network_pdu);
841             break;
842     }
843 }
844 
845 static void mesh_lower_transport_process_network_pdu(mesh_network_pdu_t *network_pdu) {// segmented?
846     if (mesh_network_segmented(network_pdu)){
847         mesh_segmented_pdu_t * message_pdu = mesh_lower_transport_incoming_pdu_for_segmented_message(network_pdu);
848         if (message_pdu) {
849             // start acknowledgment timer if inactive
850             if ((message_pdu->flags & MESH_TRANSPORT_FLAG_ACK_TIMER) == 0){
851                 // - "The acknowledgment timer shall be set to a minimum of 150 + 50 * TTL milliseconds"
852                 uint32_t timeout = 150 + 50 * mesh_network_ttl(network_pdu);
853                 mesh_lower_transport_incoming_start_acknowledgment_timer(message_pdu, timeout);
854             }
855             // restart incomplete timer
856             mesh_lower_transport_incoming_restart_incomplete_timer(message_pdu, 10000,
857                                                                    &mesh_lower_transport_incoming_incomplete_timeout);
858             mesh_lower_transport_incoming_process_segment(message_pdu, network_pdu);
859         } else {
860             mesh_network_message_processed_by_higher_layer(network_pdu);
861         }
862     } else {
863         // control?
864         if (mesh_network_control(network_pdu)){
865             // unsegmented control message (not encrypted)
866             mesh_lower_transport_process_unsegmented_control_message(network_pdu);
867         } else {
868             // unsegmented access message (encrypted)
869             mesh_lower_transport_incoming_queue_for_higher_layer((mesh_pdu_t *) network_pdu);
870         }
871     }
872 }
873 
874 void mesh_lower_transport_received_message(mesh_network_callback_type_t callback_type, mesh_network_pdu_t *network_pdu){
875     mesh_peer_t * peer;
876     uint16_t src;
877     uint16_t seq;
878     switch (callback_type){
879         case MESH_NETWORK_PDU_RECEIVED:
880             src = mesh_network_src(network_pdu);
881             seq = mesh_network_seq(network_pdu);
882             peer = mesh_peer_for_addr(src);
883 #ifdef LOG_LOWER_TRANSPORT
884             printf("Transport: received message. SRC %x, SEQ %x\n", src, seq);
885 #endif
886             // validate seq
887             if (peer && seq > peer->seq){
888                 // track seq
889                 peer->seq = seq;
890                 // process
891                 mesh_lower_transport_process_network_pdu(network_pdu);
892                 mesh_lower_transport_run();
893             } else {
894                 // drop packet
895 #ifdef LOG_LOWER_TRANSPORT
896                 printf("Transport: drop packet - src/seq auth failed\n");
897 #endif
898                 mesh_network_message_processed_by_higher_layer(network_pdu);
899             }
900             break;
901         case MESH_NETWORK_PDU_SENT:
902             mesh_lower_transport_network_pdu_sent(network_pdu);
903             break;
904         default:
905             break;
906     }
907 }
908 
909 static void mesh_lower_transport_run(void){
910 
911     // check if outgoing segmented pdu is active
912     if (lower_transport_outgoing_message) return;
913 
914     while(!btstack_linked_list_empty(&lower_transport_outgoing_ready)) {
915         // get next message
916         mesh_segmented_pdu_t   * message_pdu;
917         mesh_pdu_t * pdu = (mesh_pdu_t *) btstack_linked_list_pop(&lower_transport_outgoing_ready);
918         switch (pdu->pdu_type) {
919             case MESH_PDU_TYPE_UPPER_UNSEGMENTED_ACCESS:
920             case MESH_PDU_TYPE_UPPER_UNSEGMENTED_CONTROL:
921                 printf("[+] Lower transport, unsegmented pdu, sending now %p\n", pdu);
922                 lower_transport_outgoing_network_pdu = (mesh_network_pdu_t *) pdu;
923                 mesh_network_send_pdu(lower_transport_outgoing_network_pdu);
924                 break;
925             case MESH_PDU_TYPE_SEGMENTED:
926                 message_pdu = (mesh_segmented_pdu_t *) pdu;
927                 //
928                 printf("[+] Lower transport, segmented pdu %p, seq %06x: run start sending now\n", message_pdu,
929                        message_pdu->seq);
930                 // start sending segmented pdu
931                 mesh_lower_transport_outgoing_setup_sending_segmented_pdus(message_pdu);
932                 mesh_lower_transport_outgoing_send_next_segment();
933                 break;
934             default:
935                 btstack_assert(false);
936                 break;
937         }
938     }
939 }
940 
941 void mesh_lower_transport_send_pdu(mesh_pdu_t *pdu){
942     mesh_segmented_pdu_t * segmented_pdu;
943     switch (pdu->pdu_type){
944         case MESH_PDU_TYPE_UPPER_UNSEGMENTED_ACCESS:
945         case MESH_PDU_TYPE_UPPER_UNSEGMENTED_CONTROL:
946             btstack_assert(((mesh_network_pdu_t *) pdu)->len >= 9);
947             break;
948         case MESH_PDU_TYPE_SEGMENTED:
949             // set num retries, set of segments to send
950             segmented_pdu = (mesh_segmented_pdu_t *) pdu;
951             segmented_pdu->retry_count = 3;
952             mesh_lower_transport_outgoing_setup_block_ack(segmented_pdu);
953             break;
954         default:
955             btstack_assert(false);
956             break;
957     }
958     btstack_linked_list_add_tail(&lower_transport_outgoing_ready, (btstack_linked_item_t*) pdu);
959     mesh_lower_transport_run();
960 }
961 
962 void mesh_lower_transport_dump_network_pdus(const char *name, btstack_linked_list_t *list){
963     printf("List: %s:\n", name);
964     btstack_linked_list_iterator_t it;
965     btstack_linked_list_iterator_init(&it, list);
966     while (btstack_linked_list_iterator_has_next(&it)){
967         mesh_network_pdu_t * network_pdu = (mesh_network_pdu_t*) btstack_linked_list_iterator_next(&it);
968         printf("- %p: ", network_pdu); printf_hexdump(network_pdu->data, network_pdu->len);
969     }
970 }
971 
972 void mesh_lower_transport_reset_network_pdus(btstack_linked_list_t *list){
973     while (!btstack_linked_list_empty(list)){
974         mesh_network_pdu_t * pdu = (mesh_network_pdu_t *) btstack_linked_list_pop(list);
975         btstack_memory_mesh_network_pdu_free(pdu);
976     }
977 }
978 
979 bool mesh_lower_transport_can_send_to_dest(uint16_t dest){
980     UNUSED(dest);
981     // check current
982     uint16_t num_messages = 0;
983     if (lower_transport_outgoing_message != NULL) {
984         if (lower_transport_outgoing_message->dst == dest) {
985             return false;
986         }
987         num_messages++;
988     }
989     // check waiting
990     btstack_linked_list_iterator_t it;
991     btstack_linked_list_iterator_init(&it, &lower_transport_outgoing_waiting);
992     while (btstack_linked_list_iterator_has_next(&it)){
993         mesh_segmented_pdu_t * segmented_pdu = (mesh_segmented_pdu_t *) btstack_linked_list_iterator_next(&it);
994         num_messages++;
995         if (segmented_pdu->dst == dest){
996             return false;
997         }
998     }
999 #ifdef MAX_NR_MESH_OUTGOING_SEGMENTED_MESSAGES
1000     // limit number of parallel outgoing messages if configured
1001     if (num_messages >= MAX_NR_MESH_OUTGOING_SEGMENTED_MESSAGES) return false;
1002 #endif
1003     return true;
1004 }
1005 
1006 void mesh_lower_transport_reserve_slot(void){
1007 }
1008 
1009 void mesh_lower_transport_reset(void){
1010     if (lower_transport_outgoing_message){
1011         while (!btstack_linked_list_empty(&lower_transport_outgoing_message->segments)){
1012             mesh_network_pdu_t * network_pdu = (mesh_network_pdu_t *) btstack_linked_list_pop(&lower_transport_outgoing_message->segments);
1013             mesh_network_pdu_free(network_pdu);
1014         }
1015         lower_transport_outgoing_message = NULL;
1016     }
1017     while (!btstack_linked_list_empty(&lower_transport_outgoing_waiting)){
1018         mesh_segmented_pdu_t * segmented_pdu = (mesh_segmented_pdu_t *) btstack_linked_list_pop(&lower_transport_outgoing_waiting);
1019         btstack_memory_mesh_segmented_pdu_free(segmented_pdu);
1020     }
1021     mesh_network_pdu_free(lower_transport_outgoing_segment);
1022     lower_transport_outgoing_segment_at_network_layer = false;
1023     lower_transport_outgoing_segment = NULL;
1024 }
1025 
1026 void mesh_lower_transport_init(){
1027     // register with network layer
1028     mesh_network_set_higher_layer_handler(&mesh_lower_transport_received_message);
1029     // allocate network_pdu for segmentation
1030     lower_transport_outgoing_segment_at_network_layer = false;
1031     lower_transport_outgoing_segment = mesh_network_pdu_get();
1032 }
1033 
1034 void mesh_lower_transport_set_higher_layer_handler(void (*pdu_handler)( mesh_transport_callback_type_t callback_type, mesh_transport_status_t status, mesh_pdu_t * pdu)){
1035     higher_layer_handler = pdu_handler;
1036 }
1037