From 2a8034828ba4f0655ca425141e0c43a2e59b1421 Mon Sep 17 00:00:00 2001 From: Matthias Ringwald Date: Wed, 3 Apr 2019 16:46:44 +0200 Subject: [PATCH] mesh: sort mesh_transprot into lower and upper transport --- test/mesh/mesh_message_test.c | 4 +- test/mesh/mesh_proxy_server.c | 2 +- test/mesh/mesh_transport.c | 1427 +++++++++++++++++---------------- test/mesh/mesh_transport.h | 8 +- 4 files changed, 736 insertions(+), 705 deletions(-) diff --git a/test/mesh/mesh_message_test.c b/test/mesh/mesh_message_test.c index 400f56abb..5b8b1ce4e 100644 --- a/test/mesh/mesh_message_test.c +++ b/test/mesh/mesh_message_test.c @@ -146,7 +146,7 @@ static void test_lower_transport_callback_handler(mesh_network_callback_type_t c break; case MESH_NETWORK_PDU_SENT: printf("test MESH_NETWORK_PDU_SENT\n"); - mesh_lower_transport_received_mesage(MESH_NETWORK_PDU_SENT, network_pdu); + mesh_lower_transport_received_message(MESH_NETWORK_PDU_SENT, network_pdu); break; default: break; @@ -241,7 +241,7 @@ void test_receive_network_pdus(int count, char ** network_pdus, char ** lower_tr CHECK_EQUAL_ARRAY(transport_pdu_data, lower_transport_pdu, transport_pdu_len); // forward to mesh_transport - mesh_lower_transport_received_mesage(MESH_NETWORK_PDU_RECEIVED, received_network_pdu); + mesh_lower_transport_received_message(MESH_NETWORK_PDU_RECEIVED, received_network_pdu); // done received_network_pdu = NULL; diff --git a/test/mesh/mesh_proxy_server.c b/test/mesh/mesh_proxy_server.c index fcc2cd078..503d028f1 100644 --- a/test/mesh/mesh_proxy_server.c +++ b/test/mesh/mesh_proxy_server.c @@ -448,7 +448,7 @@ void proxy_configuration_message_handler(mesh_network_callback_type_t callback_t uint8_t ttl = 0; uint16_t src = primary_element_address; uint16_t dest = 0; // unassigned address - uint32_t seq = mesh_upper_transport_next_seq(); + uint32_t seq = mesh_lower_transport_next_seq(); uint8_t nid = mesh_network_nid(received_network_pdu); uint16_t netkey_index = received_network_pdu->netkey_index; printf("netkey index 0x%02x\n", netkey_index); diff --git a/test/mesh/mesh_transport.c b/test/mesh/mesh_transport.c index c8b4193af..c74db6e01 100644 --- a/test/mesh/mesh_transport.c +++ b/test/mesh/mesh_transport.c @@ -56,6 +56,589 @@ static void mesh_print_hex(const char * name, const uint8_t * data, uint16_t len // printf("%20s: 0x%x", name, (int) value); // } +// utility + +// Transport PDU Getter +static uint16_t mesh_transport_nid(mesh_transport_pdu_t * transport_pdu){ + return transport_pdu->network_header[0] & 0x7f; +} +static uint16_t mesh_transport_ctl(mesh_transport_pdu_t * transport_pdu){ + return transport_pdu->network_header[1] >> 7; +} +static uint16_t mesh_transport_ttl(mesh_transport_pdu_t * transport_pdu){ + return transport_pdu->network_header[1] & 0x7f; +} +static uint32_t mesh_transport_seq(mesh_transport_pdu_t * transport_pdu){ + return big_endian_read_24(transport_pdu->network_header, 2); +} +static uint32_t mesh_transport_seq_zero(mesh_transport_pdu_t * transport_pdu){ + return transport_pdu->seq_zero; +} +static uint16_t mesh_transport_src(mesh_transport_pdu_t * transport_pdu){ + return big_endian_read_16(transport_pdu->network_header, 5); +} +static uint16_t mesh_transport_dst(mesh_transport_pdu_t * transport_pdu){ + return big_endian_read_16(transport_pdu->network_header, 7); +} +static void mesh_transport_set_nid_ivi(mesh_transport_pdu_t * transport_pdu, uint8_t nid_ivi){ + transport_pdu->network_header[0] = nid_ivi; +} +static void mesh_transport_set_ctl_ttl(mesh_transport_pdu_t * transport_pdu, uint8_t ctl_ttl){ + transport_pdu->network_header[1] = ctl_ttl; +} +static void mesh_transport_set_seq(mesh_transport_pdu_t * transport_pdu, uint32_t seq){ + big_endian_store_24(transport_pdu->network_header, 2, seq); +} +static void mesh_transport_set_src(mesh_transport_pdu_t * transport_pdu, uint16_t src){ + big_endian_store_16(transport_pdu->network_header, 5, src); +} +static void mesh_transport_set_dest(mesh_transport_pdu_t * transport_pdu, uint16_t dest){ + big_endian_store_16(transport_pdu->network_header, 7, dest); +} + +// lower transport + +// prototypes + +static void mesh_transport_run(void); +static void mesh_lower_transport_abort_transmission(void); +static void mesh_lower_transport_run(void); + +// temp prototypes upper transport +static void mesh_upper_unsegmented_control_message_received(mesh_network_pdu_t * network_pdu); +static void mesh_upper_segmented_message_received(mesh_transport_pdu_t * transport_pdu); + +// state +static int lower_transport_retry_count; + +static uint32_t lower_transport_seq; + +// lower transport incoming +static btstack_linked_list_t lower_transport_incoming; + +static mesh_transport_pdu_t * lower_transport_outgoing_pdu; +static mesh_network_pdu_t * lower_transport_outgoing_segment; +static uint16_t lower_transport_outgoing_seg_o; + +// helper network layer, temp +static uint8_t mesh_network_send(uint16_t netkey_index, uint8_t ctl, uint8_t ttl, uint32_t seq, uint16_t src, uint16_t dest, const uint8_t * transport_pdu_data, uint8_t transport_pdu_len){ + + // "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." + // if (ttl <= 1) return 0; + + // TODO: check transport_pdu_len depending on ctl + + // lookup network by netkey_index + const mesh_network_key_t * network_key = mesh_network_key_list_get(netkey_index); + if (!network_key) return 0; + + // allocate network_pdu + mesh_network_pdu_t * network_pdu = btstack_memory_mesh_network_pdu_get(); + if (!network_pdu) return 0; + + // setup network_pdu + mesh_network_setup_pdu(network_pdu, netkey_index, network_key->nid, ctl, ttl, seq, src, dest, transport_pdu_data, transport_pdu_len); + + // send network_pdu + mesh_network_send_pdu(network_pdu); + return 0; +} + +static void mesh_lower_transport_process_unsegmented_control_message(mesh_network_pdu_t *network_pdu){ + uint8_t * lower_transport_pdu = mesh_network_pdu_data(network_pdu); + uint8_t opcode = lower_transport_pdu[0]; + printf("Unsegmented Control message, outgoing message %p, opcode %x\n", lower_transport_outgoing_pdu, opcode); + uint16_t seq_zero_pdu; + uint16_t seq_zero_out; + uint32_t block_ack; + switch (opcode){ + case 0: + if (lower_transport_outgoing_pdu == NULL) break; + seq_zero_pdu = big_endian_read_16(lower_transport_pdu, 1) >> 2; + seq_zero_out = mesh_transport_seq(lower_transport_outgoing_pdu) & 0x1fff; + block_ack = big_endian_read_32(lower_transport_pdu, 3); + printf("[+] Segment Acknowledgment message with seq_zero %06x, block_ack %08x - outgoing seq %06x, block_ack %08x\n", + seq_zero_pdu, block_ack, seq_zero_out, lower_transport_outgoing_pdu->block_ack); + if (block_ack == 0){ + // If a Segment Acknowledgment message with the BlockAck field set to 0x00000000 is received, + // then the Upper Transport PDU shall be immediately cancelled and the higher layers shall be notified that + // the Upper Transport PDU has been cancelled. + printf("[+] Block Ack == 0 => Abort\n"); + mesh_lower_transport_abort_transmission(); + break; + } + if (seq_zero_pdu != seq_zero_out){ + printf("[!] Seq Zero doesn't match\n"); + break; + } + lower_transport_outgoing_pdu->block_ack &= ~block_ack; + printf("[+] Updated block_ack %08x\n", lower_transport_outgoing_pdu->block_ack); + if (lower_transport_outgoing_pdu->block_ack == 0){ + printf("[+] Sent complete\n"); + mesh_lower_transport_abort_transmission(); + } + break; + default: + mesh_upper_unsegmented_control_message_received(network_pdu); + break; + } +} + +// ack / incomplete message + +static void mesh_lower_transport_setup_segmented_acknowledge_message(uint8_t * data, uint8_t obo, uint16_t seq_zero, uint32_t block_ack){ + // printf("ACK Upper Transport, seq_zero %x\n", seq_zero); + data[0] = 0; // SEG = 0, Opcode = 0 + big_endian_store_16( data, 1, (obo << 15) | (seq_zero << 2) | 0); // OBO, SeqZero, RFU + big_endian_store_32( data, 3, block_ack); + mesh_print_hex("ACK Upper Transport", data, 7); +} + +static void mesh_lower_transport_send_ack(uint16_t netkey_index, uint8_t ttl, uint16_t dest, uint16_t seq_zero, uint32_t block_ack){ + // setup ack message + uint8_t ack_msg[7]; + mesh_lower_transport_setup_segmented_acknowledge_message(ack_msg, 0, seq_zero, block_ack); + // send ack + int i; + for (i=0;i<1;i++){ + mesh_network_send(netkey_index, 1, ttl, mesh_lower_transport_next_seq(), primary_element_address, dest, ack_msg, sizeof(ack_msg)); + } +} + +static void mesh_lower_transport_send_ack_for_transport_pdu(mesh_transport_pdu_t *transport_pdu){ + uint16_t seq_zero = mesh_transport_seq_zero(transport_pdu); + uint8_t ttl = mesh_transport_ttl(transport_pdu); + uint16_t dest = mesh_transport_src(transport_pdu); + uint16_t netkey_index = transport_pdu->netkey_index; + printf("mesh_transport_send_ack_for_transport_pdu %p with netkey_index %x, TTL = %u, SeqZero = %x, SRC = %x, DST = %x\n", + transport_pdu, netkey_index, ttl, seq_zero, primary_element_address, dest); + mesh_lower_transport_send_ack(netkey_index, ttl, dest, seq_zero, transport_pdu->block_ack); +} + +static void mesh_lower_transport_send_ack_for_network_pdu(mesh_network_pdu_t *network_pdu, uint16_t seq_zero, uint32_t block_ack) { + uint8_t ttl = mesh_network_ttl(network_pdu); + uint16_t dest = mesh_network_src(network_pdu); + uint16_t netkey_index = network_pdu->netkey_index; + printf("mesh_transport_send_ack_for_network_pdu %p with netkey_index %x, TTL = %u, SeqZero = %x, SRC = %x, DST = %x\n", + network_pdu, netkey_index, ttl, seq_zero, primary_element_address, dest); + mesh_lower_transport_send_ack(netkey_index, ttl, dest, seq_zero, block_ack); +} + +static void mesh_lower_transport_stop_acknowledgment_timer(mesh_transport_pdu_t *transport_pdu){ + if (!transport_pdu->acknowledgement_timer_active) return; + transport_pdu->acknowledgement_timer_active = 0; + btstack_run_loop_remove_timer(&transport_pdu->acknowledgement_timer); +} + +static void mesh_lower_transport_stop_incomplete_timer(mesh_transport_pdu_t *transport_pdu){ + if (!transport_pdu->incomplete_timer_active) return; + transport_pdu->incomplete_timer_active = 0; + btstack_run_loop_remove_timer(&transport_pdu->incomplete_timer); +} + +// stops timers and updates reassembly engine +static void mesh_lower_transport_segmented_message_complete(mesh_transport_pdu_t *transport_pdu){ + // set flag + transport_pdu->message_complete = 1; + // stop timers + mesh_lower_transport_stop_acknowledgment_timer(transport_pdu); + mesh_lower_transport_stop_incomplete_timer(transport_pdu); + // stop reassembly + mesh_peer_t * peer = mesh_peer_for_addr(mesh_transport_src(transport_pdu)); + if (peer){ + peer->transport_pdu = NULL; + } +} + +static void mesh_lower_transport_rx_ack_timeout(btstack_timer_source_t *ts){ + mesh_transport_pdu_t * transport_pdu = (mesh_transport_pdu_t *) btstack_run_loop_get_timer_context(ts); + printf("ACK: acknowledgement timer fired for %p, send ACK\n", transport_pdu); + transport_pdu->acknowledgement_timer_active = 0; + mesh_lower_transport_send_ack_for_transport_pdu(transport_pdu); +} + +static void mesh_lower_transport_rx_incomplete_timeout(btstack_timer_source_t *ts){ + mesh_transport_pdu_t * transport_pdu = (mesh_transport_pdu_t *) btstack_run_loop_get_timer_context(ts); + printf("mesh_transport_rx_incomplete_timeout for %p - give up\n", transport_pdu); + mesh_lower_transport_segmented_message_complete(transport_pdu); + // free message + btstack_memory_mesh_transport_pdu_free(transport_pdu); +} + +static void mesh_lower_transport_start_acknowledgment_timer(mesh_transport_pdu_t *transport_pdu, uint32_t timeout, + void (*callback)(btstack_timer_source_t *ts)){ + printf("ACK: start ack timer for %p, timeout %u ms\n", transport_pdu, (int) timeout); + btstack_run_loop_set_timer(&transport_pdu->acknowledgement_timer, timeout); + btstack_run_loop_set_timer_handler(&transport_pdu->acknowledgement_timer, callback); + btstack_run_loop_set_timer_context(&transport_pdu->acknowledgement_timer, transport_pdu); + btstack_run_loop_add_timer(&transport_pdu->acknowledgement_timer); + transport_pdu->acknowledgement_timer_active = 1; +} + +static void mesh_lower_transport_restart_incomplete_timer(mesh_transport_pdu_t *transport_pdu, uint32_t timeout, + void (*callback)(btstack_timer_source_t *ts)){ + printf("RX-(re)start incomplete timer for %p, timeout %u ms\n", transport_pdu, (int) timeout); + if (transport_pdu->incomplete_timer_active){ + btstack_run_loop_remove_timer(&transport_pdu->incomplete_timer); + } + btstack_run_loop_set_timer(&transport_pdu->incomplete_timer, timeout); + btstack_run_loop_set_timer_handler(&transport_pdu->incomplete_timer, callback); + btstack_run_loop_set_timer_context(&transport_pdu->incomplete_timer, transport_pdu); + btstack_run_loop_add_timer(&transport_pdu->incomplete_timer); + transport_pdu->incomplete_timer_active = 1; +} + +// abort outgoing transmission +static void mesh_lower_transport_abort_transmission(void){ + // stop ack timers + mesh_lower_transport_stop_acknowledgment_timer(lower_transport_outgoing_pdu); + // free pdus + btstack_memory_mesh_transport_pdu_free(lower_transport_outgoing_pdu); + lower_transport_outgoing_pdu = NULL; + btstack_memory_mesh_network_pdu_free(lower_transport_outgoing_segment); + lower_transport_outgoing_segment = NULL; +} + +static mesh_transport_pdu_t * mesh_lower_transport_pdu_for_segmented_message(mesh_network_pdu_t *network_pdu){ + uint16_t src = mesh_network_src(network_pdu); + uint16_t seq_zero = ( big_endian_read_16(mesh_network_pdu_data(network_pdu), 1) >> 2) & 0x1fff; + printf("mesh_transport_pdu_for_segmented_message: seq_zero %x\n", seq_zero); + mesh_peer_t * peer = mesh_peer_for_addr(src); + if (!peer) { + return NULL; + } + printf("mesh_seq_zero_validate(%x, %x) -- last (%x, %x)\n", src, seq_zero, peer->address, peer->seq_zero); + + // reception of transport message ongoing + if (peer->transport_pdu){ + // check if segment for same seq zero + uint16_t active_seq_zero = mesh_transport_seq_zero(peer->transport_pdu); + if (active_seq_zero == seq_zero) { + printf("mesh_transport_pdu_for_segmented_message: segment for current transport pdu with SeqZero %x\n", active_seq_zero); + return peer->transport_pdu; + } else { + // seq zero differs from current transport pdu, but current pdu is not complete + printf("mesh_transport_pdu_for_segmented_message: drop segment. current transport pdu SeqZero %x, now %x\n", active_seq_zero, seq_zero); + return NULL; + } + } + + // send ACK if segment for previously completed transport pdu (no ongoing reception, block ack is cleared) + if ((seq_zero == peer->seq_zero) && (peer->block_ack != 0)){ + printf("mesh_transport_pdu_for_segmented_message: segment for last completed message. send ack\n"); + mesh_lower_transport_send_ack_for_network_pdu(network_pdu, seq_zero, peer->block_ack); + return NULL; + } + + // reconstruct lowest 24 bit of SeqAuth + uint32_t seq = mesh_network_seq(network_pdu); + uint32_t seq_auth = (seq & 0xffe000) | seq_zero; + if (seq_auth > seq){ + seq_auth -= 0x2000; + } + + // no transport pdu active, check if seq zero is new + if (seq_auth > peer->seq_auth){ + mesh_transport_pdu_t * pdu = btstack_memory_mesh_transport_pdu_get(); + if (!pdu) return NULL; + + // cache network pdu header + memcpy(pdu->network_header, network_pdu->data, 9); + // store lower 24 bit of SeqAuth for App / Device Nonce + big_endian_store_24(pdu->network_header, 2, seq_auth); + + // store meta data in new pdu + pdu->netkey_index = network_pdu->netkey_index; + pdu->block_ack = 0; + pdu->acknowledgement_timer_active = 0; + pdu->message_complete = 0; + pdu->seq_zero = seq_zero; + + // update peer info + peer->transport_pdu = pdu; + peer->seq_zero = seq_zero; + peer->seq_auth = seq_auth; + peer->block_ack = 0; + + printf("mesh_transport_pdu_for_segmented_message: setup transport pdu %p for src %x, seq %06x, seq_zero %x\n", pdu, src, mesh_transport_seq(pdu), seq_zero); + + return peer->transport_pdu; + } else { + // seq zero differs from current transport pdu + printf("mesh_transport_pdu_for_segmented_message: drop segment for old seq %x\n", seq_zero); + return NULL; + } +} + +static void mesh_lower_transport_process_segment( mesh_transport_pdu_t * transport_pdu, mesh_network_pdu_t * network_pdu){ + + uint8_t * lower_transport_pdu = mesh_network_pdu_data(network_pdu); + uint8_t lower_transport_pdu_len = mesh_network_pdu_len(network_pdu); + + // get akf_aid & transmic + transport_pdu->akf_aid = lower_transport_pdu[0]; + transport_pdu->transmic_len = lower_transport_pdu[1] & 0x80 ? 8 : 4; + + // get seq_zero + uint16_t seq_zero = ( big_endian_read_16(lower_transport_pdu, 1) >> 2) & 0x1fff; + + // get seg fields + uint8_t seg_o = ( big_endian_read_16(lower_transport_pdu, 2) >> 5) & 0x001f; + uint8_t seg_n = lower_transport_pdu[3] & 0x1f; + uint8_t segment_len = lower_transport_pdu_len - 4; + uint8_t * segment_data = &lower_transport_pdu[4]; + + printf("mesh_lower_transport_process_segment: seq zero %04x, seg_o %02x, seg_n %02x, transmic len: %u\n", seq_zero, seg_o, seg_n, transport_pdu->transmic_len * 8); + mesh_print_hex("Segment", segment_data, segment_len); + + // store segment + memcpy(&transport_pdu->data[seg_o * 12], segment_data, 12); + // mark as received + transport_pdu->block_ack |= (1< store len + if (seg_o == seg_n){ + transport_pdu->len = (seg_n * 12) + segment_len; + printf("Assembled payload len %u\n", transport_pdu->len); + } + + // check for complete + int i; + for (i=0;i<=seg_n;i++){ + if ( (transport_pdu->block_ack & (1<data, transport_pdu->len); + + // mark as done + mesh_lower_transport_segmented_message_complete(transport_pdu); + + // store block ack in peer info + mesh_peer_t * peer = mesh_peer_for_addr(mesh_transport_src(transport_pdu)); + // TODO: check if NULL check can be removed + if (peer){ + peer->block_ack = transport_pdu->block_ack; + } + + // send ack + mesh_lower_transport_send_ack_for_transport_pdu(transport_pdu); + + // forward to upper transport + mesh_upper_segmented_message_received(transport_pdu); +} + +static void mesh_lower_transport_network_pdu_sent(mesh_network_pdu_t *network_pdu); + +static void mesh_lower_transport_tx_ack_timeout(btstack_timer_source_t * ts); + +void mesh_lower_transport_received_message(mesh_network_callback_type_t callback_type, mesh_network_pdu_t *network_pdu){ + mesh_peer_t * peer; + uint16_t src; + uint16_t seq; + switch (callback_type){ + case MESH_NETWORK_PDU_RECEIVED: + src = mesh_network_src(network_pdu); + seq = mesh_network_seq(network_pdu); + peer = mesh_peer_for_addr(src); + printf("Transport: received message. SRC %x, SEQ %x\n", src, seq); + // validate seq + if (peer && seq > peer->seq){ + // track seq + peer->seq = seq; + // add to list and go + btstack_linked_list_add_tail(&lower_transport_incoming, (btstack_linked_item_t *) network_pdu); + mesh_transport_run(); + } else { + // drop packet + printf("Transport: drop packet - src/seq auth failed\n"); + mesh_network_message_processed_by_higher_layer(network_pdu); + } + break; + case MESH_NETWORK_PDU_SENT: + mesh_lower_transport_network_pdu_sent(network_pdu); + break; + default: + break; + } +} + +static void mesh_lower_transport_setup_segment(mesh_transport_pdu_t *transport_pdu, uint8_t seg_o, mesh_network_pdu_t *network_pdu){ + + int ctl = mesh_transport_ctl(transport_pdu); + uint16_t max_segment_len = ctl ? 8 : 12; // control 8 bytes (64 bit NetMic), access 12 bytes (32 bit NetMIC) + + uint32_t seq = mesh_lower_transport_next_seq(); + uint16_t seq_zero = mesh_transport_seq(transport_pdu) & 0x01fff; + uint8_t seg_n = (transport_pdu->len - 1) / max_segment_len; + uint8_t szmic = ((!ctl) && (transport_pdu->transmic_len == 8)) ? 1 : 0; // only 1 for access messages with 64 bit TransMIC + uint8_t nid = mesh_transport_nid(transport_pdu); + uint8_t ttl = mesh_transport_ttl(transport_pdu); + uint16_t src = mesh_transport_src(transport_pdu); + uint16_t dest = mesh_transport_dst(transport_pdu); + + // current segment. + uint16_t seg_offset = seg_o * max_segment_len; + + uint8_t lower_transport_pdu_data[16]; + lower_transport_pdu_data[0] = 0x80 | transport_pdu->akf_aid; + big_endian_store_24(lower_transport_pdu_data, 1, (szmic << 23) | (seq_zero << 10) | (seg_o << 5) | seg_n); + uint16_t segment_len = btstack_min(transport_pdu->len - seg_offset, max_segment_len); + memcpy(&lower_transport_pdu_data[4], &transport_pdu->data[seg_offset], segment_len); + uint16_t lower_transport_pdu_len = 4 + segment_len; + + mesh_network_setup_pdu(network_pdu, transport_pdu->netkey_index, nid, 0, ttl, seq, src, dest, lower_transport_pdu_data, lower_transport_pdu_len); +} + +static void mesh_lower_transport_send_next_segment(void){ + if (!lower_transport_outgoing_pdu) return; + + int ctl = mesh_transport_ctl(lower_transport_outgoing_pdu); + uint16_t max_segment_len = ctl ? 8 : 12; // control 8 bytes (64 bit NetMic), access 12 bytes (32 bit NetMIC) + uint8_t seg_n = (lower_transport_outgoing_pdu->len - 1) / max_segment_len; + + // find next unacknowledged segement + while ((lower_transport_outgoing_seg_o <= seg_n) && ((lower_transport_outgoing_pdu->block_ack & (1 << lower_transport_outgoing_seg_o)) == 0)){ + lower_transport_outgoing_seg_o++; + } + + if (lower_transport_outgoing_seg_o > seg_n){ + printf("[+] Upper transport, send segmented pdu complete (dst %x)\n", mesh_transport_dst(lower_transport_outgoing_pdu)); + lower_transport_outgoing_seg_o = 0; + + // done for unicast, ack timer already set, too + if (mesh_network_address_unicast(mesh_transport_dst(lower_transport_outgoing_pdu))) return; + + // done, more? + if (lower_transport_retry_count == 0){ + printf("[+] Upper transport, message unacknowledged -> free\n"); + // note: same as in seg ack handling code + btstack_memory_mesh_transport_pdu_free(lower_transport_outgoing_pdu); + lower_transport_outgoing_pdu = NULL; + btstack_memory_mesh_network_pdu_free(lower_transport_outgoing_segment); + lower_transport_outgoing_segment = NULL; + return; + } + + // start retry + printf("[+] Upper transport, message unacknowledged retry count %u\n", lower_transport_retry_count); + lower_transport_retry_count--; + } + + if (mesh_network_address_unicast(mesh_transport_dst(lower_transport_outgoing_pdu))){ + // restart acknowledgment timer for unicast dst + // - "This timer shall be set to a minimum of 200 + 50 * TTL milliseconds." + if (lower_transport_outgoing_pdu->acknowledgement_timer_active){ + btstack_run_loop_remove_timer(&lower_transport_outgoing_pdu->incomplete_timer); + lower_transport_outgoing_pdu->acknowledgement_timer_active = 0; + } + uint32_t timeout = 200 + 50 * mesh_transport_ttl(lower_transport_outgoing_pdu); + mesh_lower_transport_start_acknowledgment_timer(lower_transport_outgoing_pdu, timeout, + &mesh_lower_transport_tx_ack_timeout); + } + + mesh_lower_transport_setup_segment(lower_transport_outgoing_pdu, lower_transport_outgoing_seg_o, + lower_transport_outgoing_segment); + + printf("[+] Upper transport, send segmented pdu: seg_o %x, seg_n %x\n", lower_transport_outgoing_seg_o, seg_n); + mesh_print_hex("LowerTransportPDU", lower_transport_outgoing_segment->data, lower_transport_outgoing_segment->len); + + // next segment + lower_transport_outgoing_seg_o++; + + // send network pdu + mesh_network_send_pdu(lower_transport_outgoing_segment); +} + +static void mesh_lower_transport_network_pdu_sent(mesh_network_pdu_t *network_pdu){ + if (lower_transport_outgoing_segment == network_pdu){ + mesh_lower_transport_send_next_segment(); + } else { + btstack_memory_mesh_network_pdu_free(network_pdu); + } +} + +static void mesh_lower_transport_send_segmented_pdu_once(mesh_transport_pdu_t *transport_pdu){ + + if (lower_transport_retry_count == 0){ + printf("[!] Upper transport, send segmented pdu failed, retries exhausted\n"); + return; + } + + // chop into chunks + printf("[+] Upper transport, send segmented pdu (retry count %u)\n", lower_transport_retry_count); + lower_transport_retry_count--; + + // allocate network_pdu + mesh_network_pdu_t * network_pdu = btstack_memory_mesh_network_pdu_get(); + if (!network_pdu) return; + + // setup + lower_transport_outgoing_pdu = transport_pdu; + lower_transport_outgoing_segment = network_pdu; + lower_transport_outgoing_seg_o = 0; + + // setup block ack - set bit for segment to send, clear on ack + int ctl = mesh_transport_ctl(lower_transport_outgoing_pdu); + uint16_t max_segment_len = ctl ? 8 : 12; // control 8 bytes (64 bit NetMic), access 12 bytes (32 bit NetMIC) + uint8_t seg_n = (lower_transport_outgoing_pdu->len - 1) / max_segment_len; + if (seg_n == 31){ + transport_pdu->block_ack = -1; + } else { + transport_pdu->block_ack = (1 << (seg_n+1)) - 1; + } + + // start sending + mesh_lower_transport_send_next_segment(); +} + +void mesh_lower_transport_send_segmented_pdu(mesh_transport_pdu_t *transport_pdu){ + lower_transport_retry_count = 2; + mesh_lower_transport_send_segmented_pdu_once(transport_pdu); +} + +static void mesh_lower_transport_tx_ack_timeout(btstack_timer_source_t * ts){ + mesh_transport_pdu_t * transport_pdu = (mesh_transport_pdu_t *) btstack_run_loop_get_timer_context(ts); + printf("[+] Lower transport, acknowledgement timer fired for %p\n", transport_pdu); + transport_pdu->acknowledgement_timer_active = 0; + lower_transport_outgoing_seg_o = 0; + mesh_lower_transport_send_next_segment(); +} + +uint32_t mesh_lower_transport_next_seq(void){ + return lower_transport_seq++; +} + +static uint32_t mesh_lower_transport_peek_seq(void){ + return lower_transport_seq; +} + +static void mesh_lower_transport_dump_network_pdus(const char *name, btstack_linked_list_t *list){ + printf("List: %s:\n", name); + btstack_linked_list_iterator_t it; + btstack_linked_list_iterator_init(&it, list); + while (btstack_linked_list_iterator_has_next(&it)){ + mesh_network_pdu_t * network_pdu = (mesh_network_pdu_t*) btstack_linked_list_iterator_next(&it); + printf("- %p: ", network_pdu); printf_hexdump(network_pdu->data, network_pdu->len); + } +} +static void mesh_lower_transport_reset_network_pdus(btstack_linked_list_t *list){ + while (!btstack_linked_list_empty(list)){ + mesh_network_pdu_t * pdu = (mesh_network_pdu_t *) btstack_linked_list_pop(list); + btstack_memory_mesh_network_pdu_free(pdu); + } +} + +void mesh_lower_transport_dump(void){ + // static btstack_linked_list_t upper_transport_control; + // static btstack_linked_list_t upper_transport_access; + mesh_lower_transport_dump_network_pdus("lower_transport_incoming", &lower_transport_incoming); +} + +void mesh_lower_transport_reset(void){ + // static btstack_linked_list_t upper_transport_control; + // static btstack_linked_list_t upper_transport_access; + mesh_lower_transport_reset_network_pdus(&lower_transport_incoming); +} + // application key list typedef struct { @@ -75,7 +658,7 @@ typedef struct { // app_key uint8_t key[16]; - + // application key flag, 0 for device key uint8_t akf; @@ -93,54 +676,9 @@ static mesh_transport_key_t test_application_key; static mesh_transport_key_t mesh_transport_device_key; static mesh_virtual_address_t test_virtual_address; -void mesh_application_key_set(uint16_t appkey_index, uint8_t aid, const uint8_t * application_key){ - test_application_key.index = appkey_index; - test_application_key.aid = aid; - test_application_key.akf = 1; - memcpy(test_application_key.key, application_key, 16); -} - -void mesh_transport_set_device_key(const uint8_t * device_key){ - mesh_transport_device_key.index = MESH_DEVICE_KEY_INDEX; - mesh_transport_device_key.aid = 0; - mesh_transport_device_key.akf = 0; - memcpy(mesh_transport_device_key.key, device_key, 16); -} - -static void mesh_virtual_address_run(void){ -} - -uint16_t mesh_virtual_address_register(uint8_t * label_uuid, uint16_t hash){ - // TODO:: check if already exists - // TODO: calc hash - test_virtual_address.hash = hash; - memcpy(test_virtual_address.label_uuid, label_uuid, 16); - test_virtual_address.pseudo_dst = 0x8000; - mesh_virtual_address_run(); - return test_virtual_address.pseudo_dst; -} - -void mesh_virtual_address_unregister(uint16_t pseudo_dst){ -} - -static mesh_virtual_address_t * mesh_virtual_address_for_pseudo_dst(uint16_t pseudo_dst){ - if (test_virtual_address.pseudo_dst == pseudo_dst){ - return &test_virtual_address; - } - return NULL; -} - -static const mesh_transport_key_t * mesh_transport_key_get(uint16_t appkey_index){ - if (appkey_index == MESH_DEVICE_KEY_INDEX){ - return &mesh_transport_device_key; - } - if (appkey_index != test_application_key.index) return NULL; - return &test_application_key; -} - // mesh network key iterator static void mesh_transport_key_iterator_init(mesh_transport_key_iterator_t * it, uint16_t dst, uint8_t akf, uint8_t aid){ - it->dst = dst; + it->dst = dst; it->aid = aid; it->akf = akf; it->first = 1; @@ -169,36 +707,57 @@ static const mesh_transport_key_t * mesh_transport_key_iterator_get_next(mesh_tr } } -// helper network layer, temp -static uint8_t mesh_network_send(uint16_t netkey_index, uint8_t ctl, uint8_t ttl, uint32_t seq, uint16_t src, uint16_t dest, const uint8_t * transport_pdu_data, uint8_t transport_pdu_len){ - - // "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." - // if (ttl <= 1) return 0; - - // TODO: check transport_pdu_len depending on ctl - - // lookup network by netkey_index - const mesh_network_key_t * network_key = mesh_network_key_list_get(netkey_index); - if (!network_key) return 0; - - // allocate network_pdu - mesh_network_pdu_t * network_pdu = btstack_memory_mesh_network_pdu_get(); - if (!network_pdu) return 0; - - // setup network_pdu - mesh_network_setup_pdu(network_pdu, netkey_index, network_key->nid, ctl, ttl, seq, src, dest, transport_pdu_data, transport_pdu_len); - - // send network_pdu - mesh_network_send_pdu(network_pdu); - return 0; +void mesh_application_key_set(uint16_t appkey_index, uint8_t aid, const uint8_t * application_key){ + test_application_key.index = appkey_index; + test_application_key.aid = aid; + test_application_key.akf = 1; + memcpy(test_application_key.key, application_key, 16); } +void mesh_transport_set_device_key(const uint8_t * device_key){ + mesh_transport_device_key.index = MESH_DEVICE_KEY_INDEX; + mesh_transport_device_key.aid = 0; + mesh_transport_device_key.akf = 0; + memcpy(mesh_transport_device_key.key, device_key, 16); +} + +static const mesh_transport_key_t * mesh_transport_key_get(uint16_t appkey_index){ + if (appkey_index == MESH_DEVICE_KEY_INDEX){ + return &mesh_transport_device_key; + } + if (appkey_index != test_application_key.index) return NULL; + return &test_application_key; +} + +static void mesh_virtual_address_run(void){ +} + +uint16_t mesh_virtual_address_register(uint8_t * label_uuid, uint16_t hash){ + // TODO:: check if already exists + // TODO: calc hash + test_virtual_address.hash = hash; + memcpy(test_virtual_address.label_uuid, label_uuid, 16); + test_virtual_address.pseudo_dst = 0x8000; + mesh_virtual_address_run(); + return test_virtual_address.pseudo_dst; +} + +void mesh_virtual_address_unregister(uint16_t pseudo_dst){ +} + +static mesh_virtual_address_t * mesh_virtual_address_for_pseudo_dst(uint16_t pseudo_dst){ + if (test_virtual_address.pseudo_dst == pseudo_dst){ + return &test_virtual_address; + } + return NULL; +} + +// UPPER TRANSPORT + // stub lower transport -static void mesh_lower_transport_run(void); static void mesh_upper_transport_validate_unsegmented_message(mesh_network_pdu_t * network_pdu); static void mesh_upper_transport_validate_segmented_message(mesh_transport_pdu_t * transport_pdu); -static void mesh_transport_abort_transmission(void); static int mesh_transport_crypto_active; static mesh_network_pdu_t * network_pdu_in_validation; @@ -211,8 +770,6 @@ static mesh_transport_key_iterator_t mesh_transport_key_it; static void (*mesh_access_unsegmented_handler)(mesh_network_pdu_t * network_pdu); static void (*mesh_access_segmented_handler)(mesh_transport_pdu_t * transport_pdu); -// lower transport incoming -static btstack_linked_list_t lower_transport_incoming; // upper transport segmented access messages (to validate) static btstack_linked_list_t upper_transport_access; // upper transport segmented control messages (to process) @@ -220,11 +777,28 @@ static btstack_linked_list_t upper_transport_control; // access segmented access messages (to process) // static btstack_linked_list_t access_incoming; -static mesh_transport_pdu_t * upper_transport_outgoing_pdu; -static mesh_network_pdu_t * upper_transport_outgoing_segment; -static uint16_t upper_transport_outgoing_seg_o; -static uint32_t upper_transport_seq; +static void mesh_upper_unsegmented_control_message_received(mesh_network_pdu_t * network_pdu){ + uint8_t * lower_transport_pdu = mesh_network_pdu_data(network_pdu); + uint8_t opcode = lower_transport_pdu[0]; + if (mesh_access_unsegmented_handler){ + mesh_access_unsegmented_handler(network_pdu); + } else { + printf("[!] Unhandled Control message with opcode %02x\n", opcode); + } +} + +static void mesh_upper_transport_process_unsegmented_message_done(mesh_network_pdu_t *network_pdu){ + mesh_transport_crypto_active = 0; + mesh_network_message_processed_by_higher_layer(network_pdu_in_validation); + mesh_transport_run(); +} + +static void mesh_upper_transport_process_segmented_message_done(mesh_transport_pdu_t *transport_pdu){ + mesh_transport_crypto_active = 0; + btstack_memory_mesh_transport_pdu_free(transport_pdu); + mesh_transport_run(); +} static uint32_t iv_index_for_ivi_nid(uint8_t ivi_nid){ // get IV Index and IVI @@ -274,100 +848,6 @@ static void transport_segmented_setup_device_nonce(uint8_t * nonce, const mesh_t mesh_print_hex("DeviceNonce", nonce, 13); } -// Transport PDU Getter -static uint16_t mesh_transport_nid(mesh_transport_pdu_t * transport_pdu){ - return transport_pdu->network_header[0] & 0x7f; -} -static uint16_t mesh_transport_ctl(mesh_transport_pdu_t * transport_pdu){ - return transport_pdu->network_header[1] >> 7; -} -static uint16_t mesh_transport_ttl(mesh_transport_pdu_t * transport_pdu){ - return transport_pdu->network_header[1] & 0x7f; -} -static uint32_t mesh_transport_seq(mesh_transport_pdu_t * transport_pdu){ - return big_endian_read_24(transport_pdu->network_header, 2); -} -static uint32_t mesh_transport_seq_zero(mesh_transport_pdu_t * transport_pdu){ - return transport_pdu->seq_zero; -} -static uint16_t mesh_transport_src(mesh_transport_pdu_t * transport_pdu){ - return big_endian_read_16(transport_pdu->network_header, 5); -} -static uint16_t mesh_transport_dst(mesh_transport_pdu_t * transport_pdu){ - return big_endian_read_16(transport_pdu->network_header, 7); -} -static void mesh_transport_set_nid_ivi(mesh_transport_pdu_t * transport_pdu, uint8_t nid_ivi){ - transport_pdu->network_header[0] = nid_ivi; -} -static void mesh_transport_set_ctl_ttl(mesh_transport_pdu_t * transport_pdu, uint8_t ctl_ttl){ - transport_pdu->network_header[1] = ctl_ttl; -} -static void mesh_transport_set_seq(mesh_transport_pdu_t * transport_pdu, uint32_t seq){ - big_endian_store_24(transport_pdu->network_header, 2, seq); -} -static void mesh_transport_set_src(mesh_transport_pdu_t * transport_pdu, uint16_t src){ - big_endian_store_16(transport_pdu->network_header, 5, src); -} -static void mesh_transport_set_dest(mesh_transport_pdu_t * transport_pdu, uint16_t dest){ - big_endian_store_16(transport_pdu->network_header, 7, dest); -} - -static void mesh_transport_process_unsegmented_control_message(mesh_network_pdu_t * network_pdu){ - uint8_t * lower_transport_pdu = mesh_network_pdu_data(network_pdu); - uint8_t opcode = lower_transport_pdu[0]; - printf("Unsegmented Control message, outgoing message %p, opcode %x\n", upper_transport_outgoing_pdu, opcode); - uint16_t seq_zero_pdu; - uint16_t seq_zero_out; - uint32_t block_ack; - switch (opcode){ - case 0: - if (upper_transport_outgoing_pdu == NULL) break; - seq_zero_pdu = big_endian_read_16(lower_transport_pdu, 1) >> 2; - seq_zero_out = mesh_transport_seq(upper_transport_outgoing_pdu) & 0x1fff; - block_ack = big_endian_read_32(lower_transport_pdu, 3); - printf("[+] Segment Acknowledgment message with seq_zero %06x, block_ack %08x - outgoing seq %06x, block_ack %08x\n", - seq_zero_pdu, block_ack, seq_zero_out, upper_transport_outgoing_pdu->block_ack); - if (block_ack == 0){ - // If a Segment Acknowledgment message with the BlockAck field set to 0x00000000 is received, - // then the Upper Transport PDU shall be immediately cancelled and the higher layers shall be notified that - // the Upper Transport PDU has been cancelled. - printf("[+] Block Ack == 0 => Abort\n"); - mesh_transport_abort_transmission(); - break; - } - if (seq_zero_pdu != seq_zero_out){ - printf("[!] Seq Zero doesn't match\n"); - break; - } - upper_transport_outgoing_pdu->block_ack &= ~block_ack; - printf("[+] Updated block_ack %08x\n", upper_transport_outgoing_pdu->block_ack); - if (upper_transport_outgoing_pdu->block_ack == 0){ - printf("[+] Sent complete\n"); - mesh_transport_abort_transmission(); - } - break; - default: - if (mesh_access_unsegmented_handler){ - mesh_access_unsegmented_handler(network_pdu); - } else { - printf("[!] Unhandled Control message with opcode %02x\n", opcode); - } - break; - } -} - -static void mesh_lower_transport_process_unsegmented_message_done(mesh_network_pdu_t * network_pdu){ - mesh_transport_crypto_active = 0; - mesh_network_message_processed_by_higher_layer(network_pdu_in_validation); - mesh_lower_transport_run(); -} - -static void mesh_lower_transport_process_segmented_message_done(mesh_transport_pdu_t * transport_pdu){ - mesh_transport_crypto_active = 0; - btstack_memory_mesh_transport_pdu_free(transport_pdu); - mesh_lower_transport_run(); -} - static void mesh_upper_transport_validate_unsegmented_message_ccm(void * arg){ mesh_network_pdu_t * network_pdu = (mesh_network_pdu_t *) arg; @@ -405,7 +885,7 @@ static void mesh_upper_transport_validate_unsegmented_message_ccm(void * arg){ printf("\n"); // done - mesh_lower_transport_process_unsegmented_message_done(network_pdu); + mesh_upper_transport_process_unsegmented_message_done(network_pdu); } else { uint8_t afk = lower_transport_pdu[0] & 0x40; if (afk){ @@ -414,7 +894,7 @@ static void mesh_upper_transport_validate_unsegmented_message_ccm(void * arg){ } else { printf("TransMIC does not match device key, done\n"); // done - mesh_lower_transport_process_unsegmented_message_done(network_pdu); + mesh_upper_transport_process_unsegmented_message_done(network_pdu); } } } @@ -453,7 +933,7 @@ static void mesh_upper_transport_validate_segmented_message_ccm(void * arg){ printf("\n"); // done - mesh_lower_transport_process_segmented_message_done(transport_pdu); + mesh_upper_transport_process_segmented_message_done(transport_pdu); } else { uint8_t akf = transport_pdu->akf_aid & 0x40; if (akf){ @@ -462,7 +942,7 @@ static void mesh_upper_transport_validate_segmented_message_ccm(void * arg){ } else { printf("TransMIC does not match device key, done\n"); // done - mesh_lower_transport_process_segmented_message_done(transport_pdu); + mesh_upper_transport_process_segmented_message_done(transport_pdu); } } } @@ -489,7 +969,7 @@ static void mesh_upper_transport_validate_unsegmented_message(mesh_network_pdu_t if (!mesh_transport_key_iterator_has_more(&mesh_transport_key_it)){ printf("No valid transport key found\n"); - mesh_lower_transport_process_unsegmented_message_done(network_pdu); + mesh_upper_transport_process_unsegmented_message_done(network_pdu); return; } const mesh_transport_key_t * message_key = mesh_transport_key_iterator_get_next(&mesh_transport_key_it); @@ -534,7 +1014,7 @@ static void mesh_upper_transport_validate_segmented_message(mesh_transport_pdu_t if (!mesh_transport_key_iterator_has_more(&mesh_transport_key_it)){ printf("No valid transport key found\n"); - mesh_lower_transport_process_segmented_message_done(transport_pdu); + mesh_upper_transport_process_segmented_message_done(transport_pdu); return; } const mesh_transport_key_t * message_key = mesh_transport_key_iterator_get_next(&mesh_transport_key_it); @@ -566,8 +1046,7 @@ static void mesh_upper_transport_validate_segmented_message(mesh_transport_pdu_t } } - -static void mesh_lower_transport_process_unsegmented_access_message(mesh_network_pdu_t * network_pdu){ +static void mesh_upper_transport_process_unsegmented_access_message(mesh_network_pdu_t *network_pdu){ // copy original pdu network_pdu->len = network_pdu_in_validation->len; memcpy(network_pdu->data, network_pdu_in_validation->data, network_pdu->len); @@ -587,7 +1066,6 @@ static void mesh_lower_transport_process_unsegmented_access_message(mesh_network mesh_upper_transport_validate_unsegmented_message(network_pdu); } - static void mesh_upper_transport_process_message(mesh_transport_pdu_t * transport_pdu){ // copy original pdu transport_pdu->len = transport_pdu_in_validation->len; @@ -608,244 +1086,8 @@ static void mesh_upper_transport_process_message(mesh_transport_pdu_t * transpor mesh_upper_transport_validate_segmented_message(transport_pdu); } -// ack / incomplete message - -static void mesh_lower_transport_setup_segmented_acknowledge_message(uint8_t * data, uint8_t obo, uint16_t seq_zero, uint32_t block_ack){ - // printf("ACK Upper Transport, seq_zero %x\n", seq_zero); - data[0] = 0; // SEG = 0, Opcode = 0 - big_endian_store_16( data, 1, (obo << 15) | (seq_zero << 2) | 0); // OBO, SeqZero, RFU - big_endian_store_32( data, 3, block_ack); - mesh_print_hex("ACK Upper Transport", data, 7); -} - -static void mesh_transport_send_ack(uint16_t netkey_index, uint8_t ttl, uint16_t dest, uint16_t seq_zero, uint32_t block_ack){ - // setup ack message - uint8_t ack_msg[7]; - mesh_lower_transport_setup_segmented_acknowledge_message(ack_msg, 0, seq_zero, block_ack); - // send ack - int i; - for (i=0;i<1;i++){ - mesh_network_send(netkey_index, 1, ttl, mesh_upper_transport_next_seq(), primary_element_address, dest, ack_msg, sizeof(ack_msg)); - } -} - -static void mesh_transport_send_ack_for_transport_pdu(mesh_transport_pdu_t *transport_pdu){ - uint16_t seq_zero = mesh_transport_seq_zero(transport_pdu); - uint8_t ttl = mesh_transport_ttl(transport_pdu); - uint16_t dest = mesh_transport_src(transport_pdu); - uint16_t netkey_index = transport_pdu->netkey_index; - printf("mesh_transport_send_ack_for_transport_pdu %p with netkey_index %x, TTL = %u, SeqZero = %x, SRC = %x, DST = %x\n", - transport_pdu, netkey_index, ttl, seq_zero, primary_element_address, dest); - mesh_transport_send_ack(netkey_index, ttl, dest, seq_zero, transport_pdu->block_ack); -} - -static void mesh_transport_send_ack_for_network_pdu(mesh_network_pdu_t *network_pdu, uint16_t seq_zero, uint32_t block_ack) { - uint8_t ttl = mesh_network_ttl(network_pdu); - uint16_t dest = mesh_network_src(network_pdu); - uint16_t netkey_index = network_pdu->netkey_index; - printf("mesh_transport_send_ack_for_network_pdu %p with netkey_index %x, TTL = %u, SeqZero = %x, SRC = %x, DST = %x\n", - network_pdu, netkey_index, ttl, seq_zero, primary_element_address, dest); - mesh_transport_send_ack(netkey_index, ttl, dest, seq_zero, block_ack); -} - -static void mesh_transport_stop_acknowledgment_timer(mesh_transport_pdu_t * transport_pdu){ - if (!transport_pdu->acknowledgement_timer_active) return; - transport_pdu->acknowledgement_timer_active = 0; - btstack_run_loop_remove_timer(&transport_pdu->acknowledgement_timer); -} - -static void mesh_transport_stop_incomplete_timer(mesh_transport_pdu_t * transport_pdu){ - if (!transport_pdu->incomplete_timer_active) return; - transport_pdu->incomplete_timer_active = 0; - btstack_run_loop_remove_timer(&transport_pdu->incomplete_timer); -} - -// stops timers and updates reassembly engine -static void mesh_transport_segmented_message_complete(mesh_transport_pdu_t * transport_pdu){ - // set flag - transport_pdu->message_complete = 1; - // stop timers - mesh_transport_stop_acknowledgment_timer(transport_pdu); - mesh_transport_stop_incomplete_timer(transport_pdu); - // stop reassembly - mesh_peer_t * peer = mesh_peer_for_addr(mesh_transport_src(transport_pdu)); - if (peer){ - peer->transport_pdu = NULL; - } -} - -static void mesh_transport_rx_ack_timeout(btstack_timer_source_t * ts){ - mesh_transport_pdu_t * transport_pdu = (mesh_transport_pdu_t *) btstack_run_loop_get_timer_context(ts); - printf("ACK: acknowledgement timer fired for %p, send ACK\n", transport_pdu); - transport_pdu->acknowledgement_timer_active = 0; - mesh_transport_send_ack_for_transport_pdu(transport_pdu); -} - -static void mesh_transport_rx_incomplete_timeout(btstack_timer_source_t * ts){ - mesh_transport_pdu_t * transport_pdu = (mesh_transport_pdu_t *) btstack_run_loop_get_timer_context(ts); - printf("mesh_transport_rx_incomplete_timeout for %p - give up\n", transport_pdu); - mesh_transport_segmented_message_complete(transport_pdu); - // free message - btstack_memory_mesh_transport_pdu_free(transport_pdu); -} - -static void mesh_transport_start_acknowledgment_timer(mesh_transport_pdu_t * transport_pdu, uint32_t timeout, void (*callback)(btstack_timer_source_t * ts)){ - printf("ACK: start ack timer for %p, timeout %u ms\n", transport_pdu, (int) timeout); - btstack_run_loop_set_timer(&transport_pdu->acknowledgement_timer, timeout); - btstack_run_loop_set_timer_handler(&transport_pdu->acknowledgement_timer, callback); - btstack_run_loop_set_timer_context(&transport_pdu->acknowledgement_timer, transport_pdu); - btstack_run_loop_add_timer(&transport_pdu->acknowledgement_timer); - transport_pdu->acknowledgement_timer_active = 1; -} - -static void mesh_transport_restart_incomplete_timer(mesh_transport_pdu_t * transport_pdu, uint32_t timeout, void (*callback)(btstack_timer_source_t * ts)){ - printf("RX-(re)start incomplete timer for %p, timeout %u ms\n", transport_pdu, (int) timeout); - if (transport_pdu->incomplete_timer_active){ - btstack_run_loop_remove_timer(&transport_pdu->incomplete_timer); - } - btstack_run_loop_set_timer(&transport_pdu->incomplete_timer, timeout); - btstack_run_loop_set_timer_handler(&transport_pdu->incomplete_timer, callback); - btstack_run_loop_set_timer_context(&transport_pdu->incomplete_timer, transport_pdu); - btstack_run_loop_add_timer(&transport_pdu->incomplete_timer); - transport_pdu->incomplete_timer_active = 1; -} - -// abort outgoing transmission -static void mesh_transport_abort_transmission(void){ - // stop ack timers - mesh_transport_stop_acknowledgment_timer(upper_transport_outgoing_pdu); - // free pdus - btstack_memory_mesh_transport_pdu_free(upper_transport_outgoing_pdu); - upper_transport_outgoing_pdu = NULL; - btstack_memory_mesh_network_pdu_free(upper_transport_outgoing_segment); - upper_transport_outgoing_segment = NULL; -} - -static mesh_transport_pdu_t * mesh_transport_pdu_for_segmented_message(mesh_network_pdu_t * network_pdu){ - uint16_t src = mesh_network_src(network_pdu); - uint16_t seq_zero = ( big_endian_read_16(mesh_network_pdu_data(network_pdu), 1) >> 2) & 0x1fff; - printf("mesh_transport_pdu_for_segmented_message: seq_zero %x\n", seq_zero); - mesh_peer_t * peer = mesh_peer_for_addr(src); - if (!peer) { - return NULL; - } - printf("mesh_seq_zero_validate(%x, %x) -- last (%x, %x)\n", src, seq_zero, peer->address, peer->seq_zero); - - // reception of transport message ongoing - if (peer->transport_pdu){ - // check if segment for same seq zero - uint16_t active_seq_zero = mesh_transport_seq_zero(peer->transport_pdu); - if (active_seq_zero == seq_zero) { - printf("mesh_transport_pdu_for_segmented_message: segment for current transport pdu with SeqZero %x\n", active_seq_zero); - return peer->transport_pdu; - } else { - // seq zero differs from current transport pdu, but current pdu is not complete - printf("mesh_transport_pdu_for_segmented_message: drop segment. current transport pdu SeqZero %x, now %x\n", active_seq_zero, seq_zero); - return NULL; - } - } - - // send ACK if segment for previously completed transport pdu (no ongoing reception, block ack is cleared) - if ((seq_zero == peer->seq_zero) && (peer->block_ack != 0)){ - printf("mesh_transport_pdu_for_segmented_message: segment for last completed message. send ack\n"); - mesh_transport_send_ack_for_network_pdu(network_pdu, seq_zero, peer->block_ack); - return NULL; - } - - // reconstruct lowest 24 bit of SeqAuth - uint32_t seq = mesh_network_seq(network_pdu); - uint32_t seq_auth = (seq & 0xffe000) | seq_zero; - if (seq_auth > seq){ - seq_auth -= 0x2000; - } - - // no transport pdu active, check if seq zero is new - if (seq_auth > peer->seq_auth){ - mesh_transport_pdu_t * pdu = btstack_memory_mesh_transport_pdu_get(); - if (!pdu) return NULL; - - // cache network pdu header - memcpy(pdu->network_header, network_pdu->data, 9); - // store lower 24 bit of SeqAuth for App / Device Nonce - big_endian_store_24(pdu->network_header, 2, seq_auth); - - // store meta data in new pdu - pdu->netkey_index = network_pdu->netkey_index; - pdu->block_ack = 0; - pdu->acknowledgement_timer_active = 0; - pdu->message_complete = 0; - pdu->seq_zero = seq_zero; - - // update peer info - peer->transport_pdu = pdu; - peer->seq_zero = seq_zero; - peer->seq_auth = seq_auth; - peer->block_ack = 0; - - printf("mesh_transport_pdu_for_segmented_message: setup transport pdu %p for src %x, seq %06x, seq_zero %x\n", pdu, src, mesh_transport_seq(pdu), seq_zero); - - return peer->transport_pdu; - } else { - // seq zero differs from current transport pdu - printf("mesh_transport_pdu_for_segmented_message: drop segment for old seq %x\n", seq_zero); - return NULL; - } -} - -static void mesh_lower_transport_process_segment( mesh_transport_pdu_t * transport_pdu, mesh_network_pdu_t * network_pdu){ - - uint8_t * lower_transport_pdu = mesh_network_pdu_data(network_pdu); - uint8_t lower_transport_pdu_len = mesh_network_pdu_len(network_pdu); - - // get akf_aid & transmic - transport_pdu->akf_aid = lower_transport_pdu[0]; - transport_pdu->transmic_len = lower_transport_pdu[1] & 0x80 ? 8 : 4; - - // get seq_zero - uint16_t seq_zero = ( big_endian_read_16(lower_transport_pdu, 1) >> 2) & 0x1fff; - - // get seg fields - uint8_t seg_o = ( big_endian_read_16(lower_transport_pdu, 2) >> 5) & 0x001f; - uint8_t seg_n = lower_transport_pdu[3] & 0x1f; - uint8_t segment_len = lower_transport_pdu_len - 4; - uint8_t * segment_data = &lower_transport_pdu[4]; - - printf("mesh_lower_transport_process_segment: seq zero %04x, seg_o %02x, seg_n %02x, transmic len: %u\n", seq_zero, seg_o, seg_n, transport_pdu->transmic_len * 8); - mesh_print_hex("Segment", segment_data, segment_len); - - // store segment - memcpy(&transport_pdu->data[seg_o * 12], segment_data, 12); - // mark as received - transport_pdu->block_ack |= (1< store len - if (seg_o == seg_n){ - transport_pdu->len = (seg_n * 12) + segment_len; - printf("Assembled payload len %u\n", transport_pdu->len); - } - - // check for complete - int i; - for (i=0;i<=seg_n;i++){ - if ( (transport_pdu->block_ack & (1<data, transport_pdu->len); - - // mark as done - mesh_transport_segmented_message_complete(transport_pdu); - - // store block ack in peer info - mesh_peer_t * peer = mesh_peer_for_addr(mesh_transport_src(transport_pdu)); - // TODO: check if NULL check can be removed - if (peer){ - peer->block_ack = transport_pdu->block_ack; - } - - // send ack - mesh_transport_send_ack_for_transport_pdu(transport_pdu); - - // forward to upper transport - uint8_t ctl = mesh_network_control(network_pdu); +static void mesh_upper_segmented_message_received(mesh_transport_pdu_t * transport_pdu){ + uint8_t ctl = mesh_transport_ctl(transport_pdu); if (ctl){ printf("Store Reassembled Control Message for processing\n"); btstack_linked_list_add_tail(&upper_transport_control, (btstack_linked_item_t*) transport_pdu); @@ -855,252 +1097,6 @@ static void mesh_lower_transport_process_segment( mesh_transport_pdu_t * transpo } } -static void mesh_lower_transport_run(void){ - while(1){ - int done = 1; - - if (mesh_transport_crypto_active) return; - - if (!btstack_linked_list_empty(&lower_transport_incoming)){ - done = 0; - // peek at next message - mesh_network_pdu_t * network_pdu = (mesh_network_pdu_t *) btstack_linked_list_get_first_item(&lower_transport_incoming); - // segmented? - if (mesh_network_segmented(network_pdu)){ - mesh_transport_pdu_t * transport_pdu = mesh_transport_pdu_for_segmented_message(network_pdu); - if (!transport_pdu) return; - (void) btstack_linked_list_pop(&lower_transport_incoming); - // start acknowledgment timer if inactive - if (transport_pdu->acknowledgement_timer_active == 0){ - // - "The acknowledgment timer shall be set to a minimum of 150 + 50 * TTL milliseconds" - uint32_t timeout = 150 + 50 * mesh_network_ttl(network_pdu); - mesh_transport_start_acknowledgment_timer(transport_pdu, timeout, &mesh_transport_rx_ack_timeout); - } - // restart incomplete timer - mesh_transport_restart_incomplete_timer(transport_pdu, 10000, &mesh_transport_rx_incomplete_timeout); - mesh_lower_transport_process_segment(transport_pdu, network_pdu); - mesh_network_message_processed_by_higher_layer(network_pdu); - } else { - // control? - if (mesh_network_control(network_pdu)){ - // unsegmented control message (not encrypted) - (void) btstack_linked_list_pop(&lower_transport_incoming); - mesh_transport_process_unsegmented_control_message(network_pdu); - mesh_network_message_processed_by_higher_layer(network_pdu); - } else { - // unsegmented access message (encrypted) - mesh_network_pdu_t * decode_pdu = btstack_memory_mesh_network_pdu_get(); - if (!decode_pdu) return; - // get encoded network pdu and start processing - network_pdu_in_validation = network_pdu; - (void) btstack_linked_list_pop(&lower_transport_incoming); - mesh_lower_transport_process_unsegmented_access_message(decode_pdu); - } - } - } - - if (!btstack_linked_list_empty(&upper_transport_access)){ - // peek at next message - mesh_transport_pdu_t * transport_pdu = (mesh_transport_pdu_t *) btstack_linked_list_get_first_item(&upper_transport_access); - mesh_transport_pdu_t * decode_pdu = btstack_memory_mesh_transport_pdu_get(); - if (!decode_pdu) return; - // get encoded transport pdu and start processing - transport_pdu_in_validation = transport_pdu; - (void) btstack_linked_list_pop(&upper_transport_access); - mesh_upper_transport_process_message(decode_pdu); - } - - if (done) return; - } -} - -static void mesh_upper_transport_network_pdu_sent(mesh_network_pdu_t * network_pdu); - -void mesh_lower_transport_received_mesage(mesh_network_callback_type_t callback_type, mesh_network_pdu_t * network_pdu){ - mesh_peer_t * peer; - uint16_t src; - uint16_t seq; - switch (callback_type){ - case MESH_NETWORK_PDU_RECEIVED: - src = mesh_network_src(network_pdu); - seq = mesh_network_seq(network_pdu); - peer = mesh_peer_for_addr(src); - printf("Transport: received message. SRC %x, SEQ %x\n", src, seq); - // validate seq - if (peer && seq > peer->seq){ - // track seq - peer->seq = seq; - // add to list and go - btstack_linked_list_add_tail(&lower_transport_incoming, (btstack_linked_item_t *) network_pdu); - mesh_lower_transport_run(); - } else { - // drop packet - printf("Transport: drop packet - src/seq auth failed\n"); - mesh_network_message_processed_by_higher_layer(network_pdu); - } - break; - case MESH_NETWORK_PDU_SENT: - mesh_upper_transport_network_pdu_sent(network_pdu); - break; - default: - break; - } -} - -// UPPER TRANSPORT - -static void mesh_transport_tx_ack_timeout(btstack_timer_source_t * ts); - -static int mesh_upper_transport_retry_count; - -uint32_t mesh_upper_transport_next_seq(void){ - return upper_transport_seq++; -} - -static uint32_t mesh_upper_transport_peek_seq(void){ - return upper_transport_seq; -} - -static void mesh_upper_transport_setup_segment(mesh_transport_pdu_t * transport_pdu, uint8_t seg_o, mesh_network_pdu_t * network_pdu){ - - int ctl = mesh_transport_ctl(transport_pdu); - uint16_t max_segment_len = ctl ? 8 : 12; // control 8 bytes (64 bit NetMic), access 12 bytes (32 bit NetMIC) - - uint32_t seq = mesh_upper_transport_next_seq(); - uint16_t seq_zero = mesh_transport_seq(transport_pdu) & 0x01fff; - uint8_t seg_n = (transport_pdu->len - 1) / max_segment_len; - uint8_t szmic = ((!ctl) && (transport_pdu->transmic_len == 8)) ? 1 : 0; // only 1 for access messages with 64 bit TransMIC - uint8_t nid = mesh_transport_nid(transport_pdu); - uint8_t ttl = mesh_transport_ttl(transport_pdu); - uint16_t src = mesh_transport_src(transport_pdu); - uint16_t dest = mesh_transport_dst(transport_pdu); - - // current segment. - uint16_t seg_offset = seg_o * max_segment_len; - - uint8_t lower_transport_pdu_data[16]; - lower_transport_pdu_data[0] = 0x80 | transport_pdu->akf_aid; - big_endian_store_24(lower_transport_pdu_data, 1, (szmic << 23) | (seq_zero << 10) | (seg_o << 5) | seg_n); - uint16_t segment_len = btstack_min(transport_pdu->len - seg_offset, max_segment_len); - memcpy(&lower_transport_pdu_data[4], &transport_pdu->data[seg_offset], segment_len); - uint16_t lower_transport_pdu_len = 4 + segment_len; - - mesh_network_setup_pdu(network_pdu, transport_pdu->netkey_index, nid, 0, ttl, seq, src, dest, lower_transport_pdu_data, lower_transport_pdu_len); -} - -static void mesh_upper_transport_send_next_segment(void){ - if (!upper_transport_outgoing_pdu) return; - - int ctl = mesh_transport_ctl(upper_transport_outgoing_pdu); - uint16_t max_segment_len = ctl ? 8 : 12; // control 8 bytes (64 bit NetMic), access 12 bytes (32 bit NetMIC) - uint8_t seg_n = (upper_transport_outgoing_pdu->len - 1) / max_segment_len; - - // find next unacknowledged segement - while ((upper_transport_outgoing_seg_o <= seg_n) && ((upper_transport_outgoing_pdu->block_ack & (1 << upper_transport_outgoing_seg_o)) == 0)){ - upper_transport_outgoing_seg_o++; - } - - if (upper_transport_outgoing_seg_o > seg_n){ - printf("[+] Upper transport, send segmented pdu complete (dst %x)\n", mesh_transport_dst(upper_transport_outgoing_pdu)); - upper_transport_outgoing_seg_o = 0; - - // done for unicast, ack timer already set, too - if (mesh_network_address_unicast(mesh_transport_dst(upper_transport_outgoing_pdu))) return; - - // done, more? - if (mesh_upper_transport_retry_count == 0){ - printf("[+] Upper transport, message unacknowledged -> free\n"); - // note: same as in seg ack handling code - btstack_memory_mesh_transport_pdu_free(upper_transport_outgoing_pdu); - upper_transport_outgoing_pdu = NULL; - btstack_memory_mesh_network_pdu_free(upper_transport_outgoing_segment); - upper_transport_outgoing_segment = NULL; - return; - } - - // start retry - printf("[+] Upper transport, message unacknowledged retry count %u\n", mesh_upper_transport_retry_count); - mesh_upper_transport_retry_count--; - } - - if (mesh_network_address_unicast(mesh_transport_dst(upper_transport_outgoing_pdu))){ - // restart acknowledgment timer for unicast dst - // - "This timer shall be set to a minimum of 200 + 50 * TTL milliseconds." - if (upper_transport_outgoing_pdu->acknowledgement_timer_active){ - btstack_run_loop_remove_timer(&upper_transport_outgoing_pdu->incomplete_timer); - upper_transport_outgoing_pdu->acknowledgement_timer_active = 0; - } - uint32_t timeout = 200 + 50 * mesh_transport_ttl(upper_transport_outgoing_pdu); - mesh_transport_start_acknowledgment_timer(upper_transport_outgoing_pdu, timeout, &mesh_transport_tx_ack_timeout); - } - - mesh_upper_transport_setup_segment(upper_transport_outgoing_pdu, upper_transport_outgoing_seg_o, upper_transport_outgoing_segment); - - printf("[+] Upper transport, send segmented pdu: seg_o %x, seg_n %x\n", upper_transport_outgoing_seg_o, seg_n); - mesh_print_hex("LowerTransportPDU", upper_transport_outgoing_segment->data, upper_transport_outgoing_segment->len); - - // next segment - upper_transport_outgoing_seg_o++; - - // send network pdu - mesh_network_send_pdu(upper_transport_outgoing_segment); -} - -static void mesh_upper_transport_network_pdu_sent(mesh_network_pdu_t * network_pdu){ - if (upper_transport_outgoing_segment == network_pdu){ - mesh_upper_transport_send_next_segment(); - } else { - btstack_memory_mesh_network_pdu_free(network_pdu); - } -} - -static void mesh_upper_transport_send_segmented_pdu_once(mesh_transport_pdu_t * transport_pdu){ - - if (mesh_upper_transport_retry_count == 0){ - printf("[!] Upper transport, send segmented pdu failed, retries exhausted\n"); - return; - } - - // chop into chunks - printf("[+] Upper transport, send segmented pdu (retry count %u)\n", mesh_upper_transport_retry_count); - mesh_upper_transport_retry_count--; - - // allocate network_pdu - mesh_network_pdu_t * network_pdu = btstack_memory_mesh_network_pdu_get(); - if (!network_pdu) return; - - // setup - upper_transport_outgoing_pdu = transport_pdu; - upper_transport_outgoing_segment = network_pdu; - upper_transport_outgoing_seg_o = 0; - - // setup block ack - set bit for segment to send, clear on ack - int ctl = mesh_transport_ctl(upper_transport_outgoing_pdu); - uint16_t max_segment_len = ctl ? 8 : 12; // control 8 bytes (64 bit NetMic), access 12 bytes (32 bit NetMIC) - uint8_t seg_n = (upper_transport_outgoing_pdu->len - 1) / max_segment_len; - if (seg_n == 31){ - transport_pdu->block_ack = -1; - } else { - transport_pdu->block_ack = (1 << (seg_n+1)) - 1; - } - - // start sending - mesh_upper_transport_send_next_segment(); -} - -void mesh_upper_transport_send_segmented_pdu(mesh_transport_pdu_t * transport_pdu){ - mesh_upper_transport_retry_count = 2; - mesh_upper_transport_send_segmented_pdu_once(transport_pdu); -} - -static void mesh_transport_tx_ack_timeout(btstack_timer_source_t * ts){ - mesh_transport_pdu_t * transport_pdu = (mesh_transport_pdu_t *) btstack_run_loop_get_timer_context(ts); - printf("[+] Upper transport, acknowledgement timer fired for %p\n", transport_pdu); - transport_pdu->acknowledgement_timer_active = 0; - upper_transport_outgoing_seg_o = 0; - mesh_upper_transport_send_next_segment(); -} - static void mesh_upper_transport_send_unsegmented_access_pdu_ccm(void * arg){ mesh_transport_crypto_active = 0; @@ -1125,7 +1121,7 @@ static void mesh_upper_transport_send_segmented_access_pdu_ccm(void * arg){ btstack_crypto_ccm_get_authentication_value(&ccm, &transport_pdu->data[transport_pdu->len]); mesh_print_hex("TransMIC", &transport_pdu->data[transport_pdu->len], transport_pdu->transmic_len); transport_pdu->len += transport_pdu->transmic_len; - mesh_upper_transport_send_segmented_pdu(transport_pdu); + mesh_lower_transport_send_segmented_pdu(transport_pdu); } uint8_t mesh_upper_transport_setup_unsegmented_control_pdu(mesh_network_pdu_t * network_pdu, uint16_t netkey_index, uint8_t ttl, uint16_t src, uint16_t dest, uint8_t opcode, @@ -1146,7 +1142,7 @@ uint8_t mesh_upper_transport_setup_unsegmented_control_pdu(mesh_network_pdu_t * mesh_print_hex("LowerTransportPDU", transport_pdu_data, transport_pdu_len); // setup network_pdu - mesh_network_setup_pdu(network_pdu, netkey_index, network_key->nid, 1, ttl, mesh_upper_transport_next_seq(), src, dest, transport_pdu_data, transport_pdu_len); + mesh_network_setup_pdu(network_pdu, netkey_index, network_key->nid, 1, ttl, mesh_lower_transport_next_seq(), src, dest, transport_pdu_data, transport_pdu_len); return 0; } @@ -1162,7 +1158,7 @@ uint8_t mesh_upper_transport_setup_segmented_control_pdu(mesh_transport_pdu_t * const mesh_network_key_t * network_key = mesh_network_key_list_get(netkey_index); if (!network_key) return 1; - uint32_t seq = mesh_upper_transport_peek_seq(); + uint32_t seq = mesh_lower_transport_peek_seq(); memcpy(transport_pdu->data, control_pdu_data, control_pdu_len); transport_pdu->len = control_pdu_len; @@ -1181,7 +1177,7 @@ uint8_t mesh_upper_transport_setup_segmented_control_pdu(mesh_transport_pdu_t * uint8_t mesh_upper_transport_setup_unsegmented_access_pdu(mesh_network_pdu_t * network_pdu, uint16_t netkey_index, uint16_t appkey_index, uint8_t ttl, uint16_t src, uint16_t dest, const uint8_t * access_pdu_data, uint8_t access_pdu_len){ - uint32_t seq = mesh_upper_transport_peek_seq(); + uint32_t seq = mesh_lower_transport_peek_seq(); printf("[+] Upper transport, setup unsegmented Access PDU - seq %06x\n", seq); mesh_print_hex("Access Payload", access_pdu_data, access_pdu_len); @@ -1205,7 +1201,7 @@ uint8_t mesh_upper_transport_setup_unsegmented_access_pdu(mesh_network_pdu_t * n uint16_t transport_pdu_len = access_pdu_len + 1; // setup network_pdu - mesh_network_setup_pdu(network_pdu, netkey_index, network_key->nid, 0, ttl, mesh_upper_transport_next_seq(), src, dest, transport_pdu_data, transport_pdu_len); + mesh_network_setup_pdu(network_pdu, netkey_index, network_key->nid, 0, ttl, mesh_lower_transport_next_seq(), src, dest, transport_pdu_data, transport_pdu_len); network_pdu->appkey_index = appkey_index; return 0; } @@ -1213,7 +1209,7 @@ uint8_t mesh_upper_transport_setup_unsegmented_access_pdu(mesh_network_pdu_t * n uint8_t mesh_upper_transport_setup_segmented_access_pdu(mesh_transport_pdu_t * transport_pdu, uint16_t netkey_index, uint16_t appkey_index, uint8_t ttl, uint16_t src, uint16_t dest, uint8_t szmic, const uint8_t * access_pdu_data, uint8_t access_pdu_len){ - uint32_t seq = mesh_upper_transport_peek_seq(); + uint32_t seq = mesh_lower_transport_peek_seq(); printf("[+] Upper transport, setup segmented Access PDU - seq %06x, szmic %u, iv_index %08x\n", seq, szmic, mesh_get_iv_index()); mesh_print_hex("Access Payload", access_pdu_data, access_pdu_len); @@ -1255,7 +1251,7 @@ void mesh_upper_transport_send_unsegmented_control_pdu(mesh_network_pdu_t * netw } void mesh_upper_transport_send_segmented_control_pdu(mesh_transport_pdu_t * transport_pdu){ - mesh_upper_transport_send_segmented_pdu(transport_pdu); + mesh_lower_transport_send_segmented_pdu(transport_pdu); } void mesh_upper_transport_send_unsegmented_access_pdu_digest(void * arg){ @@ -1364,7 +1360,7 @@ void mesh_upper_transport_set_primary_element_address(uint16_t unicast_address){ } void mesh_upper_transport_set_seq(uint32_t seq){ - upper_transport_seq = seq; + lower_transport_seq = seq; } void mesh_upper_transport_register_unsegemented_message_handler(void (*callback)(mesh_network_pdu_t * network_pdu)){ @@ -1374,32 +1370,67 @@ void mesh_upper_transport_register_segemented_message_handler(void (*callback)(m mesh_access_segmented_handler = callback; } -static void mesh_transport_dump_network_pdus(const char * name, btstack_linked_list_t * list){ - printf("List: %s:\n", name); - btstack_linked_list_iterator_t it; - btstack_linked_list_iterator_init(&it, list); - while (btstack_linked_list_iterator_has_next(&it)){ - mesh_network_pdu_t * network_pdu = (mesh_network_pdu_t*) btstack_linked_list_iterator_next(&it); - printf("- %p: ", network_pdu); printf_hexdump(network_pdu->data, network_pdu->len); - } -} -static void mesh_transport_reset_network_pdus(btstack_linked_list_t * list){ - while (!btstack_linked_list_empty(list)){ - mesh_network_pdu_t * pdu = (mesh_network_pdu_t *) btstack_linked_list_pop(list); - btstack_memory_mesh_network_pdu_free(pdu); - } -} -void mesh_transport_dump(void){ - // static btstack_linked_list_t upper_transport_control; - // static btstack_linked_list_t upper_transport_access; - mesh_transport_dump_network_pdus("lower_transport_incoming", &lower_transport_incoming); -} -void mesh_transport_reset(void){ - // static btstack_linked_list_t upper_transport_control; - // static btstack_linked_list_t upper_transport_access; - mesh_transport_reset_network_pdus(&lower_transport_incoming); +void mesh_transport_init(){ + mesh_network_set_higher_layer_handler(&mesh_lower_transport_received_message); } -void mesh_transport_init(){ - mesh_network_set_higher_layer_handler(&mesh_lower_transport_received_mesage); +static void mesh_transport_run(void){ + while(1){ + int done = 1; + + if (mesh_transport_crypto_active) return; + + if (!btstack_linked_list_empty(&lower_transport_incoming)){ + done = 0; + // peek at next message + mesh_network_pdu_t * network_pdu = (mesh_network_pdu_t *) btstack_linked_list_get_first_item(&lower_transport_incoming); + // segmented? + if (mesh_network_segmented(network_pdu)){ + mesh_transport_pdu_t * transport_pdu = mesh_lower_transport_pdu_for_segmented_message(network_pdu); + if (!transport_pdu) return; + (void) btstack_linked_list_pop(&lower_transport_incoming); + // start acknowledgment timer if inactive + if (transport_pdu->acknowledgement_timer_active == 0){ + // - "The acknowledgment timer shall be set to a minimum of 150 + 50 * TTL milliseconds" + uint32_t timeout = 150 + 50 * mesh_network_ttl(network_pdu); + mesh_lower_transport_start_acknowledgment_timer(transport_pdu, timeout, + &mesh_lower_transport_rx_ack_timeout); + } + // restart incomplete timer + mesh_lower_transport_restart_incomplete_timer(transport_pdu, 10000, + &mesh_lower_transport_rx_incomplete_timeout); + mesh_lower_transport_process_segment(transport_pdu, network_pdu); + mesh_network_message_processed_by_higher_layer(network_pdu); + } else { + // control? + if (mesh_network_control(network_pdu)){ + // unsegmented control message (not encrypted) + (void) btstack_linked_list_pop(&lower_transport_incoming); + mesh_lower_transport_process_unsegmented_control_message(network_pdu); + mesh_network_message_processed_by_higher_layer(network_pdu); + } else { + // unsegmented access message (encrypted) + mesh_network_pdu_t * decode_pdu = btstack_memory_mesh_network_pdu_get(); + if (!decode_pdu) return; + // get encoded network pdu and start processing + network_pdu_in_validation = network_pdu; + (void) btstack_linked_list_pop(&lower_transport_incoming); + mesh_upper_transport_process_unsegmented_access_message(decode_pdu); + } + } + } + + if (!btstack_linked_list_empty(&upper_transport_access)){ + // peek at next message + mesh_transport_pdu_t * transport_pdu = (mesh_transport_pdu_t *) btstack_linked_list_get_first_item(&upper_transport_access); + mesh_transport_pdu_t * decode_pdu = btstack_memory_mesh_transport_pdu_get(); + if (!decode_pdu) return; + // get encoded transport pdu and start processing + transport_pdu_in_validation = transport_pdu; + (void) btstack_linked_list_pop(&upper_transport_access); + mesh_upper_transport_process_message(decode_pdu); + } + + if (done) return; + } } diff --git a/test/mesh/mesh_transport.h b/test/mesh/mesh_transport.h index e4390242c..a44d66f9c 100644 --- a/test/mesh/mesh_transport.h +++ b/test/mesh/mesh_transport.h @@ -53,7 +53,7 @@ void mesh_transport_init(); void mesh_upper_transport_set_seq(uint32_t seq); -uint32_t mesh_upper_transport_next_seq(void); +uint32_t mesh_lower_transport_next_seq(void); void mesh_upper_transport_set_primary_element_address(uint16_t primary_element_address); @@ -108,9 +108,9 @@ uint16_t mesh_virtual_address_register(uint8_t * label_uuid, uint16_t hash); void mesh_virtual_address_unregister(uint16_t pseudo_dst); // test -void mesh_lower_transport_received_mesage(mesh_network_callback_type_t callback_type, mesh_network_pdu_t * network_pdu); -void mesh_transport_dump(void); -void mesh_transport_reset(void); +void mesh_lower_transport_received_message(mesh_network_callback_type_t callback_type, mesh_network_pdu_t *network_pdu); +void mesh_lower_transport_dump(void); +void mesh_lower_transport_reset(void); void mesh_seq_auth_reset(void); #ifdef __cplusplus