From 7bebc11caa16629f324bc36b07bbc5bd432baae9 Mon Sep 17 00:00:00 2001 From: Matthias Ringwald Date: Fri, 21 Jul 2017 18:33:27 +0200 Subject: [PATCH] l2cap-ertm: fragment outgoing data into tx buffers --- src/l2cap.c | 56 ++++++++++++++++++++++++++++++++++++------- test/pts/l2cap_test.c | 9 +++++-- 2 files changed, 54 insertions(+), 11 deletions(-) diff --git a/src/l2cap.c b/src/l2cap.c index f47056844..94447a4b1 100644 --- a/src/l2cap.c +++ b/src/l2cap.c @@ -625,24 +625,24 @@ static int l2cap_ertm_send_information_frame(l2cap_channel_t * channel, int inde // send return l2cap_send_prepared(channel->local_cid, 2 + tx_state->len); } -static int l2cap_ertm_send(l2cap_channel_t * channel, uint8_t * data, uint16_t len){ - if (len > channel->remote_mtu){ - log_error("l2cap_send cid 0x%02x, data length exceeds remote MTU.", channel->local_cid); - return L2CAP_DATA_LEN_EXCEEDS_REMOTE_MTU; - } - // TODO: fragment if neccessary - // store int tx packet bufferx +static void l2cap_ertm_store_fragment(l2cap_channel_t * channel, l2cap_segmentation_and_reassembly_t sar, uint16_t sdu_length, uint8_t * data, uint16_t len){ + // get next index for storing packets int index = channel->tx_write_index; l2cap_ertm_tx_packet_state_t * tx_state = &channel->tx_packets_state[index]; tx_state->tx_seq = channel->next_tx_seq; tx_state->len = len; - tx_state->sar = L2CAP_SEGMENTATION_AND_REASSEMBLY_UNSEGMENTED_L2CAP_SDU; + tx_state->sar = sar; tx_state->retry_count = 0; uint8_t * tx_packet = &channel->tx_packets_data[index * channel->local_mtu]; - memcpy(&tx_packet[0], data, len); + int pos = 0; + if (sar == L2CAP_SEGMENTATION_AND_REASSEMBLY_START_OF_L2CAP_SDU){ + little_endian_store_16(tx_packet, 0, sdu_length); + pos += 2; + } + memcpy(&tx_packet[pos], data, len); // update channel->next_tx_seq = l2cap_next_ertm_seq_nr(channel->next_tx_seq); @@ -653,6 +653,44 @@ static int l2cap_ertm_send(l2cap_channel_t * channel, uint8_t * data, uint16_t l btstack_run_loop_set_timer_context(&tx_state->retransmission_timer, channel); btstack_run_loop_set_timer(&tx_state->retransmission_timer, channel->local_retransmission_timeout_ms); btstack_run_loop_add_timer(&tx_state->retransmission_timer); +} + +static int l2cap_ertm_send(l2cap_channel_t * channel, uint8_t * data, uint16_t len){ + if (len > channel->remote_mtu){ + log_error("l2cap_send cid 0x%02x, data length exceeds remote MTU.", channel->local_cid); + return L2CAP_DATA_LEN_EXCEEDS_REMOTE_MTU; + } + + // check if it needs to get fragmented + if (len > channel->remote_mps){ + // fragmentation needed. + l2cap_segmentation_and_reassembly_t sar = L2CAP_SEGMENTATION_AND_REASSEMBLY_START_OF_L2CAP_SDU; + int chunk_len; + while (len){ + switch (sar){ + case L2CAP_SEGMENTATION_AND_REASSEMBLY_START_OF_L2CAP_SDU: + chunk_len = channel->remote_mps - 2; // sdu_length + l2cap_ertm_store_fragment(channel, sar, len, data, chunk_len); + len -= chunk_len; + sar = L2CAP_SEGMENTATION_AND_REASSEMBLY_CONTINUATION_OF_L2CAP_SDU; + break; + case L2CAP_SEGMENTATION_AND_REASSEMBLY_CONTINUATION_OF_L2CAP_SDU: + chunk_len = channel->remote_mps; + if (chunk_len >= len){ + sar = L2CAP_SEGMENTATION_AND_REASSEMBLY_END_OF_L2CAP_SDU; + chunk_len = len; + } + l2cap_ertm_store_fragment(channel, sar, len, data, chunk_len); + len -= chunk_len; + break; + default: + break; + } + } + + } else { + l2cap_ertm_store_fragment(channel, L2CAP_SEGMENTATION_AND_REASSEMBLY_UNSEGMENTED_L2CAP_SDU, 0, data, len); + } // try to send l2cap_run(); diff --git a/test/pts/l2cap_test.c b/test/pts/l2cap_test.c index a0c33ab4c..c7d0d700c 100644 --- a/test/pts/l2cap_test.c +++ b/test/pts/l2cap_test.c @@ -141,7 +141,8 @@ static void show_usage(void){ printf("\n--- CLI for L2CAP TEST ---\n"); printf("L2CAP Channel Mode %s\n", l2cap_ertm ? "Enahnced Retransmission" : "Basic"); printf("c - create connection to SDP at addr %s\n", bd_addr_to_str(remote)); - printf("s - send data\n"); + printf("s - send some data\n"); + printf("S - send more data\n"); printf("p - send echo request\n"); printf("e - optional ERTM mode\n"); printf("E - mandatory ERTM mode\n"); @@ -172,9 +173,13 @@ static void stdin_process(char buffer){ l2cap_ertm_set_ready(local_cid); break; case 's': - printf("Send L2CAP Data\n"); + printf("Send some L2CAP Data\n"); l2cap_send(local_cid, (uint8_t *) "0123456789", 10); break; + case 'S': + printf("Send more L2CAP Data\n"); + l2cap_send(local_cid, (uint8_t *) "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789", 100); + break; case 'd': printf("L2CAP Channel Closed\n"); l2cap_disconnect(local_cid, 0);