From db55d2e9b3eb0840f425c7f1c66381dbac4aee4d Mon Sep 17 00:00:00 2001 From: Matthias Ringwald Date: Tue, 18 Jul 2017 11:12:44 +0200 Subject: [PATCH] l2cap-ertm: disconnect l2cap after monitor timeout and rety count has reached max transmit --- src/l2cap.c | 58 +++++++++++++++++++++++++++++++++---------- src/l2cap.h | 3 ++- test/pts/l2cap_test.c | 5 ++-- 3 files changed, 50 insertions(+), 16 deletions(-) diff --git a/src/l2cap.c b/src/l2cap.c index db721e1d6..1075b5169 100644 --- a/src/l2cap.c +++ b/src/l2cap.c @@ -569,16 +569,52 @@ static void l2cap_ertm_next_tx_write_index(l2cap_channel_t * channel){ if (channel->tx_write_index < channel->num_tx_buffers) return; channel->tx_write_index = 0; } -static void l2cap_ertm_retransmission_timeout_callback(btstack_timer_source_t * ts){ - log_info("l2cap_ertm_retransmission_timeout_callback"); - l2cap_channel_t * channel = (l2cap_channel_t *) btstack_run_loop_get_timer_context(ts); - channel->send_supervisor_frame_receiver_ready_poll = 1; - l2cap_run(); -} static void l2cap_ertm_monitor_timeout_callback(btstack_timer_source_t * ts){ log_info("l2cap_ertm_monitor_timeout_callback"); - l2cap_channel_t * channel = (l2cap_channel_t *) btstack_run_loop_get_timer_context(ts); - channel->send_supervisor_frame_receiver_ready_poll = 1; + l2cap_channel_t * l2cap_channel = (l2cap_channel_t *) btstack_run_loop_get_timer_context(ts); + + // TODO: we assume that it's the oldest packet + l2cap_ertm_tx_packet_state_t * tx_state; + tx_state = &l2cap_channel->tx_packets_state[l2cap_channel->tx_read_index]; + + // check retry count + if (tx_state->retry_count < l2cap_channel->remote_max_transmit){ + // increment retry count + tx_state->retry_count++; + + // start monitor timer + btstack_run_loop_set_timer_handler(&tx_state->monitor_timer, &l2cap_ertm_monitor_timeout_callback); + btstack_run_loop_set_timer_context(&tx_state->monitor_timer, l2cap_channel); + btstack_run_loop_set_timer(&tx_state->monitor_timer, l2cap_channel->local_monitor_timeout_ms); + btstack_run_loop_add_timer(&tx_state->monitor_timer); + + // send RR/P=1 + l2cap_channel->send_supervisor_frame_receiver_ready_poll = 1; + } else { + log_info("Monitor timer expired & retry count >= max transmit -> disconnect"); + l2cap_channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST; + } + l2cap_run(); +} +static void l2cap_ertm_retransmission_timeout_callback(btstack_timer_source_t * ts){ + log_info("l2cap_ertm_retransmission_timeout_callback"); + l2cap_channel_t * l2cap_channel = (l2cap_channel_t *) btstack_run_loop_get_timer_context(ts); + + // TODO: we assume that it's the oldest packet + l2cap_ertm_tx_packet_state_t * tx_state; + tx_state = &l2cap_channel->tx_packets_state[l2cap_channel->tx_read_index]; + + // set retry count = 1 + tx_state->retry_count = 1; + + // start monitor timer + btstack_run_loop_set_timer_handler(&tx_state->monitor_timer, &l2cap_ertm_monitor_timeout_callback); + btstack_run_loop_set_timer_context(&tx_state->monitor_timer, l2cap_channel); + btstack_run_loop_set_timer(&tx_state->monitor_timer, l2cap_channel->local_monitor_timeout_ms); + btstack_run_loop_add_timer(&tx_state->monitor_timer); + + // send RR/P=1 + l2cap_channel->send_supervisor_frame_receiver_ready_poll = 1; l2cap_run(); } static int l2cap_ertm_send_information_frame(l2cap_channel_t * channel, int index){ @@ -603,6 +639,7 @@ static int l2cap_ertm_send(l2cap_channel_t * channel, uint8_t * data, uint16_t l 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->retry_count = 0; memcpy(&channel->tx_packets_data[index * channel->local_mtu], data, len); // update channel->next_tx_seq = l2cap_next_ertm_seq_nr(channel->next_tx_seq); @@ -612,11 +649,6 @@ 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); - // set monitor timer - btstack_run_loop_set_timer_handler(&tx_state->monitor_timer, &l2cap_ertm_monitor_timeout_callback); - btstack_run_loop_set_timer_context(&tx_state->monitor_timer, channel); - btstack_run_loop_set_timer(&tx_state->monitor_timer, channel->local_monitor_timeout_ms); - btstack_run_loop_add_timer(&tx_state->monitor_timer); // try to send l2cap_run(); return 0; diff --git a/src/l2cap.h b/src/l2cap.h index 2b62340d0..c6a07688b 100644 --- a/src/l2cap.h +++ b/src/l2cap.h @@ -124,8 +124,9 @@ typedef struct { typedef struct { btstack_timer_source_t retransmission_timer; btstack_timer_source_t monitor_timer; - uint8_t tx_seq; uint16_t len; + uint8_t tx_seq; + uint8_t retry_count; } l2cap_ertm_tx_packet_state_t; diff --git a/test/pts/l2cap_test.c b/test/pts/l2cap_test.c index 7b061878c..8868c331c 100644 --- a/test/pts/l2cap_test.c +++ b/test/pts/l2cap_test.c @@ -69,6 +69,7 @@ static uint16_t handle; static uint16_t local_cid; static int l2cap_ertm; static int l2cap_ertm_mandatory; +static int l2cap_max_transmit = 2; // some tests require > 1 static btstack_packet_callback_registration_t hci_event_callback_registration; static uint8_t ertm_buffer[10000]; @@ -113,7 +114,7 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack uint16_t l2cap_cid = little_endian_read_16(packet, 12); if (l2cap_ertm){ printf("L2CAP Accepting incoming connection request in ERTM\n"); - l2cap_accept_ertm_connection(l2cap_cid, l2cap_ertm_mandatory, 1, 2000, 12000, 4, 4, ertm_buffer, sizeof(ertm_buffer)); + l2cap_accept_ertm_connection(l2cap_cid, l2cap_ertm_mandatory, l2cap_max_transmit, 2000, 12000, 4, 4, ertm_buffer, sizeof(ertm_buffer)); } else { printf("L2CAP Accepting incoming connection request in Basic Mode\n"); l2cap_accept_connection(l2cap_cid); @@ -156,7 +157,7 @@ static void stdin_process(char buffer){ case 'c': printf("Creating L2CAP Connection to %s, PSM SDP\n", bd_addr_to_str(remote)); if (l2cap_ertm){ - l2cap_create_ertm_channel(packet_handler, remote, BLUETOOTH_PROTOCOL_SDP, l2cap_ertm_mandatory, 1, 2000, 12000, 4, 4, ertm_buffer, sizeof(ertm_buffer), &local_cid); + l2cap_create_ertm_channel(packet_handler, remote, BLUETOOTH_PROTOCOL_SDP, l2cap_ertm_mandatory, l2cap_max_transmit, 2000, 12000, 4, 4, ertm_buffer, sizeof(ertm_buffer), &local_cid); } else { l2cap_create_channel(packet_handler, remote, BLUETOOTH_PROTOCOL_SDP, 100, &local_cid); }