l2cap: limit fragments by remote_mps, send first fragment fully

This commit is contained in:
Matthias Ringwald 2019-08-07 22:43:27 +02:00
parent 7261e5d87f
commit b90eac910b
2 changed files with 12 additions and 8 deletions

View File

@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- RFCOMM: limit RFCOMM MTU by local L2CAP MTU for outgoing connections (revelvant only for ERTM)
- POSIX, WICED, Windows, FreeRTOS: handle time_ms overrun after 49 days
- L2CAP ERTM: stop timers on disconnect
- L2CAP ERTM: fix sending of segmented SDUs
### Added
- btstack_run_loop_base: portable implementation of timer and data source managment as base for platform specific implementations

View File

@ -201,12 +201,13 @@ static int l2cap_ertm_can_store_packet_now(l2cap_channel_t * channel){
int num_free_tx_buffers = channel->num_tx_buffers - channel->num_stored_tx_frames;
// calculate num tx buffers for remote MTU
int num_tx_buffers_for_max_remote_mtu;
if (channel->remote_mtu <= channel->remote_mps){
uint16_t effective_mps = btstack_min(channel->remote_mps, channel->local_mps);
if (channel->remote_mtu <= effective_mps){
// MTU fits into single packet
num_tx_buffers_for_max_remote_mtu = 1;
} else {
// include SDU Length
num_tx_buffers_for_max_remote_mtu = (channel->remote_mtu + 2 + (channel->remote_mps - 1)) / channel->remote_mps;
num_tx_buffers_for_max_remote_mtu = (channel->remote_mtu + 2 + (effective_mps - 1)) / effective_mps;
}
log_debug("num_free_tx_buffers %u, num_tx_buffers_for_max_remote_mtu %u", num_free_tx_buffers, num_tx_buffers_for_max_remote_mtu);
return num_tx_buffers_for_max_remote_mtu <= num_free_tx_buffers;
@ -322,18 +323,18 @@ static void l2cap_ertm_store_fragment(l2cap_channel_t * channel, l2cap_segmentat
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 = sar;
tx_state->retry_count = 0;
uint8_t * tx_packet = &channel->tx_packets_data[index * channel->local_mps];
log_debug("index %u, mtu %u, packet tx %p", index, channel->local_mtu, tx_packet);
log_debug("index %u, local mps %u, remote mps %u, packet tx %p, len %u", index, channel->local_mps, channel->remote_mps, tx_packet, 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);
tx_state->len = pos + len;
// update
channel->num_stored_tx_frames++;
@ -356,20 +357,21 @@ static int l2cap_ertm_send(l2cap_channel_t * channel, uint8_t * data, uint16_t l
}
// check if it needs to get fragmented
if (len > channel->remote_mps){
uint16_t effective_mps = btstack_min(channel->remote_mps, channel->local_mps);
if (len > effective_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
chunk_len = effective_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;
chunk_len = effective_mps;
if (chunk_len >= len){
sar = L2CAP_SEGMENTATION_AND_REASSEMBLY_END_OF_L2CAP_SDU;
chunk_len = len;
@ -436,7 +438,8 @@ static uint16_t l2cap_setup_options_ertm_response(l2cap_channel_t * channel, uin
little_endian_store_16( config_options, pos, channel->local_monitor_timeout_ms);
pos += 2;
// less or equal to remote mps
little_endian_store_16( config_options, pos, btstack_min(channel->local_mps, channel->remote_mps));
uint16_t effective_mps = btstack_min(channel->remote_mps, channel->local_mps);
little_endian_store_16( config_options, pos, effective_mps);
pos += 2;
//
config_options[pos++] = L2CAP_CONFIG_OPTION_TYPE_MAX_TRANSMISSION_UNIT; // MTU