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