From ac8f13004884a912d2dec9d17befc2a00a8f8148 Mon Sep 17 00:00:00 2001 From: Matthias Ringwald Date: Wed, 12 Jul 2017 21:52:48 +0200 Subject: [PATCH] l2cap-ertm: renegotiate basic mode if ERTM not requested --- src/l2cap.c | 90 +++++++++++++++++++++++++++++++++++++++-------------- src/l2cap.h | 28 +++++++++-------- 2 files changed, 82 insertions(+), 36 deletions(-) diff --git a/src/l2cap.c b/src/l2cap.c index 01a1cad0d..9b2408103 100644 --- a/src/l2cap.c +++ b/src/l2cap.c @@ -649,9 +649,9 @@ static uint16_t l2cap_setup_options(l2cap_channel_t * channel, uint8_t * config_ int send_retransmission_and_flow_control_option = 0; int options_size; #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE - if (channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION){ - send_retransmission_and_flow_control_option = 1; - } + // if (channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION){ + send_retransmission_and_flow_control_option = 1; + // } #endif if (send_retransmission_and_flow_control_option){ #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE @@ -849,13 +849,21 @@ static void l2cap_run(void){ channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP); } if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_INVALID){ + channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP); l2cap_send_signaling_packet(channel->con_handle, CONFIGURE_RESPONSE, channel->remote_sig_id, channel->remote_cid, flags, L2CAP_CONF_RESULT_UNKNOWN_OPTIONS, 0, NULL); - } else if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_MTU){ +#ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE + } else if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_REJECTED){ + channelStateVarClearFlag(channel,L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_REJECTED); + channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP); uint16_t options_size = l2cap_setup_options(channel, config_options); - l2cap_send_signaling_packet(channel->con_handle, CONFIGURE_RESPONSE, channel->remote_sig_id, channel->remote_cid, flags, 0, options_size, &config_options); + l2cap_send_signaling_packet(channel->con_handle, CONFIGURE_RESPONSE, channel->remote_sig_id, channel->remote_cid, flags, L2CAP_CONF_RESULT_UNACCEPTABLE_PARAMETERS, options_size, &config_options); +#endif + } else if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_MTU){ channelStateVarClearFlag(channel,L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_MTU); + uint16_t options_size = l2cap_setup_options(channel, config_options); + l2cap_send_signaling_packet(channel->con_handle, CONFIGURE_RESPONSE, channel->remote_sig_id, channel->remote_cid, flags, L2CAP_CONF_RESULT_SUCCESS, options_size, &config_options); } else { - l2cap_send_signaling_packet(channel->con_handle, CONFIGURE_RESPONSE, channel->remote_sig_id, channel->remote_cid, flags, 0, 0, NULL); + l2cap_send_signaling_packet(channel->con_handle, CONFIGURE_RESPONSE, channel->remote_sig_id, channel->remote_cid, flags, L2CAP_CONF_RESULT_SUCCESS, 0, NULL); } channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_CONT); } @@ -1596,15 +1604,41 @@ static void l2cap_signaling_handle_configure_request(l2cap_channel_t *channel, u #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE // Retransmission and Flow Control Option if (option_type == 4 && length == 9){ - if (channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION && channel->ertm_mandatory){ - // ertm mandatory, but remote doens't offer ERTM -> disconnect - l2cap_channel_mode_t mode = (l2cap_channel_mode_t) command[pos]; - if (mode != L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION){ - channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST; - } - } else { - // TODO store and evaluate configuration - channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_MTU); + l2cap_channel_mode_t mode = (l2cap_channel_mode_t) command[pos]; + switch(channel->mode){ + case L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION: + if (channel->ertm_mandatory){ + // ERTM mandatory, but remote doens't offer ERTM -> disconnect + if (mode != L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION){ + channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST; + } else { + // Both sides selected ERTM + // TODO store and evaluate configuration + channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_MTU); + } + } else { + // ERTM is optional + channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_MTU); + } + break; + case L2CAP_CHANNEL_MODE_BASIC: + switch (mode){ + case L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION: + // remote asks for ERTM, but we want basic mode. disconnect if this happens a second time + if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_BASIC_FALLBACK_TRIED){ + channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST; + } + channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_BASIC_FALLBACK_TRIED); + channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_REJECTED); + break; + default: // case L2CAP_CHANNEL_MODE_BASIC: + // TODO store and evaluate configuration + channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_MTU); + break; + } + break; + default: + break; } } #endif @@ -1631,15 +1665,25 @@ static void l2cap_signaling_handle_configure_response(l2cap_channel_t *channel, // Retransmission and Flow Control Option if (option_type == 4 && length == 9){ - if (channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION){ - if (channel->ertm_mandatory){ - // - } else { - // On 'Reject - Unacceptable Parameters', fall back to BASIC mode - if (result == 1){ - channel->mode = L2CAP_CHANNEL_MODE_BASIC; + switch (channel->mode){ + case L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION: + if (channel->ertm_mandatory){ + // ?? + } else { + // On 'Reject - Unacceptable Parameters' to our optional ERTM request, fall back to BASIC mode + if (result == L2CAP_CONF_RESULT_UNACCEPTABLE_PARAMETERS){ + channel->mode = L2CAP_CHANNEL_MODE_BASIC; + } } - } + break; + case L2CAP_CHANNEL_MODE_BASIC: + if (result == L2CAP_CONF_RESULT_UNACCEPTABLE_PARAMETERS){ + // On 'Reject - Unacceptable Parameters' to our Basic mode request, disconnect + channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST; + } + break; + default: + break; } } diff --git a/src/l2cap.h b/src/l2cap.h index f0013b943..637ee2b2a 100644 --- a/src/l2cap.h +++ b/src/l2cap.h @@ -97,19 +97,21 @@ typedef enum { } L2CAP_STATE; typedef enum { - L2CAP_CHANNEL_STATE_VAR_NONE = 0, - L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_REQ = 1 << 0, - L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_RSP = 1 << 1, - L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ = 1 << 2, - L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP = 1 << 3, - L2CAP_CHANNEL_STATE_VAR_SENT_CONF_REQ = 1 << 4, - L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP = 1 << 5, - L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_MTU = 1 << 6, // in CONF RSP, add MTU field - L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_CONT = 1 << 7, // in CONF RSP, set CONTINUE flag - L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_INVALID = 1 << 8, // in CONF RSP, send UNKNOWN OPTIONS - L2CAP_CHANNEL_STATE_VAR_SEND_CMD_REJ_UNKNOWN = 1 << 9, // send CMD_REJ with reason unknown - L2CAP_CHANNEL_STATE_VAR_SEND_CONN_RESP_PEND = 1 << 10, // send Connection Respond with pending - L2CAP_CHANNEL_STATE_VAR_INCOMING = 1 << 15, // channel is incoming + L2CAP_CHANNEL_STATE_VAR_NONE = 0, + L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_REQ = 1 << 0, + L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_RSP = 1 << 1, + L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ = 1 << 2, + L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP = 1 << 3, + L2CAP_CHANNEL_STATE_VAR_SENT_CONF_REQ = 1 << 4, + L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP = 1 << 5, + L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_MTU = 1 << 6, // in CONF RSP, add MTU field + L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_CONT = 1 << 7, // in CONF RSP, set CONTINUE flag + L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_INVALID = 1 << 8, // in CONF RSP, send UNKNOWN OPTIONS + L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_REJECTED = 1 << 9, // in CONF RSP, send Unacceptable Parameters (ERTM) + L2CAP_CHANNEL_STATE_VAR_BASIC_FALLBACK_TRIED = 1 << 10, // set when ERTM was requested but we want only Basic mode (ERM) + L2CAP_CHANNEL_STATE_VAR_SEND_CMD_REJ_UNKNOWN = 1 << 11, // send CMD_REJ with reason unknown + L2CAP_CHANNEL_STATE_VAR_SEND_CONN_RESP_PEND = 1 << 12, // send Connection Respond with pending + L2CAP_CHANNEL_STATE_VAR_INCOMING = 1 << 15, // channel is incoming } L2CAP_CHANNEL_STATE_VAR; // info regarding an actual connection