l2cap: extract l2cap_acl_classic_handler_for_channel

This commit is contained in:
Matthias Ringwald 2020-01-13 17:21:10 +01:00
parent a3b9c6207b
commit 0b667d4199

View File

@ -3277,6 +3277,207 @@ static int l2cap_le_signaling_handler_dispatch(hci_con_handle_t handle, uint8_t
}
#endif
#ifdef ENABLE_CLASSIC
static void l2cap_acl_classic_handler_for_channel(l2cap_channel_t * l2cap_channel, uint8_t * packet, uint16_t size){
#ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
if (l2cap_channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION){
int fcs_size = l2cap_channel->fcs_option ? 2 : 0;
// assert control + FCS fields are inside
if (size < COMPLETE_L2CAP_HEADER+2+fcs_size) return;
if (l2cap_channel->fcs_option){
// verify FCS (required if one side requested it)
uint16_t fcs_calculated = crc16_calc(&packet[4], size - (4+2));
uint16_t fcs_packet = little_endian_read_16(packet, size-2);
#ifdef L2CAP_ERTM_SIMULATE_FCS_ERROR_INTERVAL
// simulate fcs error
static int counter = 0;
if (++counter == L2CAP_ERTM_SIMULATE_FCS_ERROR_INTERVAL) {
log_info("Simulate fcs error");
fcs_calculated++;
counter = 0;
}
#endif
if (fcs_calculated == fcs_packet){
log_info("Packet FCS 0x%04x verified", fcs_packet);
} else {
log_error("FCS mismatch! Packet 0x%04x, calculated 0x%04x", fcs_packet, fcs_calculated);
// ERTM State Machine in Bluetooth Spec does not handle 'I-Frame with invalid FCS'
return;
}
}
// switch on packet type
uint16_t control = little_endian_read_16(packet, COMPLETE_L2CAP_HEADER);
uint8_t req_seq = (control >> 8) & 0x3f;
int final = (control >> 7) & 0x01;
if (control & 1){
// S-Frame
int poll = (control >> 4) & 0x01;
l2cap_supervisory_function_t s = (l2cap_supervisory_function_t) ((control >> 2) & 0x03);
log_info("Control: 0x%04x => Supervisory function %u, ReqSeq %02u", control, (int) s, req_seq);
l2cap_ertm_tx_packet_state_t * tx_state;
switch (s){
case L2CAP_SUPERVISORY_FUNCTION_RR_RECEIVER_READY:
log_info("L2CAP_SUPERVISORY_FUNCTION_RR_RECEIVER_READY");
l2cap_ertm_process_req_seq(l2cap_channel, req_seq);
if (poll && final){
// S-frames shall not be transmitted with both the F-bit and the P-bit set to 1 at the same time.
log_error("P=F=1 in S-Frame");
break;
}
if (poll){
// check if we did request selective retransmission before <==> we have stored SDU segments
int i;
int num_stored_out_of_order_packets = 0;
for (i=0;i<l2cap_channel->num_rx_buffers;i++){
int index = l2cap_channel->rx_store_index + i;
if (index >= l2cap_channel->num_rx_buffers){
index -= l2cap_channel->num_rx_buffers;
}
l2cap_ertm_rx_packet_state_t * rx_state = &l2cap_channel->rx_packets_state[index];
if (!rx_state->valid) continue;
num_stored_out_of_order_packets++;
}
if (num_stored_out_of_order_packets){
l2cap_channel->send_supervisor_frame_selective_reject = 1;
} else {
l2cap_channel->send_supervisor_frame_receiver_ready = 1;
}
l2cap_channel->set_final_bit_after_packet_with_poll_bit_set = 1;
}
if (final){
// Stop-MonitorTimer
l2cap_ertm_stop_monitor_timer(l2cap_channel);
// If UnackedFrames > 0 then Start-RetransTimer
if (l2cap_channel->unacked_frames){
l2cap_ertm_start_retransmission_timer(l2cap_channel);
}
// final bit set <- response to RR with poll bit set. All not acknowledged packets need to be retransmitted
l2cap_ertm_retransmit_unacknowleded_frames(l2cap_channel);
}
break;
case L2CAP_SUPERVISORY_FUNCTION_REJ_REJECT:
log_info("L2CAP_SUPERVISORY_FUNCTION_REJ_REJECT");
l2cap_ertm_process_req_seq(l2cap_channel, req_seq);
// restart transmittion from last unacknowledted packet (earlier packets already freed in l2cap_ertm_process_req_seq)
l2cap_ertm_retransmit_unacknowleded_frames(l2cap_channel);
break;
case L2CAP_SUPERVISORY_FUNCTION_RNR_RECEIVER_NOT_READY:
log_error("L2CAP_SUPERVISORY_FUNCTION_RNR_RECEIVER_NOT_READY");
break;
case L2CAP_SUPERVISORY_FUNCTION_SREJ_SELECTIVE_REJECT:
log_info("L2CAP_SUPERVISORY_FUNCTION_SREJ_SELECTIVE_REJECT");
if (poll){
l2cap_ertm_process_req_seq(l2cap_channel, req_seq);
}
// find requested i-frame
tx_state = l2cap_ertm_get_tx_state(l2cap_channel, req_seq);
if (tx_state){
log_info("Retransmission for tx_seq %u requested", req_seq);
l2cap_channel->set_final_bit_after_packet_with_poll_bit_set = poll;
tx_state->retransmission_requested = 1;
l2cap_channel->srej_active = 1;
}
break;
default:
break;
}
} else {
// I-Frame
// get control
l2cap_segmentation_and_reassembly_t sar = (l2cap_segmentation_and_reassembly_t) (control >> 14);
uint8_t tx_seq = (control >> 1) & 0x3f;
log_info("Control: 0x%04x => SAR %u, ReqSeq %02u, R?, TxSeq %02u", control, (int) sar, req_seq, tx_seq);
log_info("SAR: pos %u", l2cap_channel->reassembly_pos);
log_info("State: expected_tx_seq %02u, req_seq %02u", l2cap_channel->expected_tx_seq, l2cap_channel->req_seq);
l2cap_ertm_process_req_seq(l2cap_channel, req_seq);
if (final){
// final bit set <- response to RR with poll bit set. All not acknowledged packets need to be retransmitted
l2cap_ertm_retransmit_unacknowleded_frames(l2cap_channel);
}
// get SDU
const uint8_t * payload_data = &packet[COMPLETE_L2CAP_HEADER+2];
uint16_t payload_len = size-(COMPLETE_L2CAP_HEADER+2+fcs_size);
// assert SDU size is smaller or equal to our buffers
uint16_t max_payload_size = 0;
switch (sar){
case L2CAP_SEGMENTATION_AND_REASSEMBLY_UNSEGMENTED_L2CAP_SDU:
case L2CAP_SEGMENTATION_AND_REASSEMBLY_START_OF_L2CAP_SDU:
// SDU Length + MPS
max_payload_size = l2cap_channel->local_mps + 2;
break;
case L2CAP_SEGMENTATION_AND_REASSEMBLY_CONTINUATION_OF_L2CAP_SDU:
case L2CAP_SEGMENTATION_AND_REASSEMBLY_END_OF_L2CAP_SDU:
max_payload_size = l2cap_channel->local_mps;
break;
}
if (payload_len > max_payload_size){
log_info("payload len %u > max payload %u -> drop packet", payload_len, max_payload_size);
return;
}
// check ordering
if (l2cap_channel->expected_tx_seq == tx_seq){
log_info("Received expected frame with TxSeq == ExpectedTxSeq == %02u", tx_seq);
l2cap_channel->expected_tx_seq = l2cap_next_ertm_seq_nr(l2cap_channel->expected_tx_seq);
l2cap_channel->req_seq = l2cap_channel->expected_tx_seq;
// process SDU
l2cap_ertm_handle_in_sequence_sdu(l2cap_channel, sar, payload_data, payload_len);
// process stored segments
while (true){
int index = l2cap_channel->rx_store_index;
l2cap_ertm_rx_packet_state_t * rx_state = &l2cap_channel->rx_packets_state[index];
if (!rx_state->valid) break;
log_info("Processing stored frame with TxSeq == ExpectedTxSeq == %02u", l2cap_channel->expected_tx_seq);
l2cap_channel->expected_tx_seq = l2cap_next_ertm_seq_nr(l2cap_channel->expected_tx_seq);
l2cap_channel->req_seq = l2cap_channel->expected_tx_seq;
rx_state->valid = 0;
l2cap_ertm_handle_in_sequence_sdu(l2cap_channel, rx_state->sar, &l2cap_channel->rx_packets_data[index], rx_state->len);
// update rx store index
index++;
if (index >= l2cap_channel->num_rx_buffers){
index = 0;
}
l2cap_channel->rx_store_index = index;
}
//
l2cap_channel->send_supervisor_frame_receiver_ready = 1;
} else {
int delta = (tx_seq - l2cap_channel->expected_tx_seq) & 0x3f;
if (delta < 2){
// store segment
l2cap_ertm_handle_out_of_sequence_sdu(l2cap_channel, sar, delta, payload_data, payload_len);
log_info("Received unexpected frame TxSeq %u but expected %u -> send S-SREJ", tx_seq, l2cap_channel->expected_tx_seq);
l2cap_channel->send_supervisor_frame_selective_reject = 1;
} else {
log_info("Received unexpected frame TxSeq %u but expected %u -> send S-REJ", tx_seq, l2cap_channel->expected_tx_seq);
l2cap_channel->send_supervisor_frame_reject = 1;
}
}
}
return;
}
#endif
l2cap_dispatch_to_channel(l2cap_channel, L2CAP_DATA_PACKET, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
}
#endif
static void l2cap_acl_classic_handler(hci_con_handle_t handle, uint8_t *packet, uint16_t size){
#ifdef ENABLE_CLASSIC
l2cap_channel_t * l2cap_channel;
@ -3313,201 +3514,7 @@ static void l2cap_acl_classic_handler(hci_con_handle_t handle, uint8_t *packet,
// Find channel for this channel_id and connection handle
l2cap_channel = l2cap_get_channel_for_local_cid(channel_id);
if (l2cap_channel) {
#ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
if (l2cap_channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION){
int fcs_size = l2cap_channel->fcs_option ? 2 : 0;
// assert control + FCS fields are inside
if (size < COMPLETE_L2CAP_HEADER+2+fcs_size) break;
if (l2cap_channel->fcs_option){
// verify FCS (required if one side requested it)
uint16_t fcs_calculated = crc16_calc(&packet[4], size - (4+2));
uint16_t fcs_packet = little_endian_read_16(packet, size-2);
#ifdef L2CAP_ERTM_SIMULATE_FCS_ERROR_INTERVAL
// simulate fcs error
static int counter = 0;
if (++counter == L2CAP_ERTM_SIMULATE_FCS_ERROR_INTERVAL) {
log_info("Simulate fcs error");
fcs_calculated++;
counter = 0;
}
#endif
if (fcs_calculated == fcs_packet){
log_info("Packet FCS 0x%04x verified", fcs_packet);
} else {
log_error("FCS mismatch! Packet 0x%04x, calculated 0x%04x", fcs_packet, fcs_calculated);
// ERTM State Machine in Bluetooth Spec does not handle 'I-Frame with invalid FCS'
break;
}
}
// switch on packet type
uint16_t control = little_endian_read_16(packet, COMPLETE_L2CAP_HEADER);
uint8_t req_seq = (control >> 8) & 0x3f;
int final = (control >> 7) & 0x01;
if (control & 1){
// S-Frame
int poll = (control >> 4) & 0x01;
l2cap_supervisory_function_t s = (l2cap_supervisory_function_t) ((control >> 2) & 0x03);
log_info("Control: 0x%04x => Supervisory function %u, ReqSeq %02u", control, (int) s, req_seq);
l2cap_ertm_tx_packet_state_t * tx_state;
switch (s){
case L2CAP_SUPERVISORY_FUNCTION_RR_RECEIVER_READY:
log_info("L2CAP_SUPERVISORY_FUNCTION_RR_RECEIVER_READY");
l2cap_ertm_process_req_seq(l2cap_channel, req_seq);
if (poll && final){
// S-frames shall not be transmitted with both the F-bit and the P-bit set to 1 at the same time.
log_error("P=F=1 in S-Frame");
break;
}
if (poll){
// check if we did request selective retransmission before <==> we have stored SDU segments
int i;
int num_stored_out_of_order_packets = 0;
for (i=0;i<l2cap_channel->num_rx_buffers;i++){
int index = l2cap_channel->rx_store_index + i;
if (index >= l2cap_channel->num_rx_buffers){
index -= l2cap_channel->num_rx_buffers;
}
l2cap_ertm_rx_packet_state_t * rx_state = &l2cap_channel->rx_packets_state[index];
if (!rx_state->valid) continue;
num_stored_out_of_order_packets++;
}
if (num_stored_out_of_order_packets){
l2cap_channel->send_supervisor_frame_selective_reject = 1;
} else {
l2cap_channel->send_supervisor_frame_receiver_ready = 1;
}
l2cap_channel->set_final_bit_after_packet_with_poll_bit_set = 1;
}
if (final){
// Stop-MonitorTimer
l2cap_ertm_stop_monitor_timer(l2cap_channel);
// If UnackedFrames > 0 then Start-RetransTimer
if (l2cap_channel->unacked_frames){
l2cap_ertm_start_retransmission_timer(l2cap_channel);
}
// final bit set <- response to RR with poll bit set. All not acknowledged packets need to be retransmitted
l2cap_ertm_retransmit_unacknowleded_frames(l2cap_channel);
}
break;
case L2CAP_SUPERVISORY_FUNCTION_REJ_REJECT:
log_info("L2CAP_SUPERVISORY_FUNCTION_REJ_REJECT");
l2cap_ertm_process_req_seq(l2cap_channel, req_seq);
// restart transmittion from last unacknowledted packet (earlier packets already freed in l2cap_ertm_process_req_seq)
l2cap_ertm_retransmit_unacknowleded_frames(l2cap_channel);
break;
case L2CAP_SUPERVISORY_FUNCTION_RNR_RECEIVER_NOT_READY:
log_error("L2CAP_SUPERVISORY_FUNCTION_RNR_RECEIVER_NOT_READY");
break;
case L2CAP_SUPERVISORY_FUNCTION_SREJ_SELECTIVE_REJECT:
log_info("L2CAP_SUPERVISORY_FUNCTION_SREJ_SELECTIVE_REJECT");
if (poll){
l2cap_ertm_process_req_seq(l2cap_channel, req_seq);
}
// find requested i-frame
tx_state = l2cap_ertm_get_tx_state(l2cap_channel, req_seq);
if (tx_state){
log_info("Retransmission for tx_seq %u requested", req_seq);
l2cap_channel->set_final_bit_after_packet_with_poll_bit_set = poll;
tx_state->retransmission_requested = 1;
l2cap_channel->srej_active = 1;
}
break;
default:
break;
}
} else {
// I-Frame
// get control
l2cap_segmentation_and_reassembly_t sar = (l2cap_segmentation_and_reassembly_t) (control >> 14);
uint8_t tx_seq = (control >> 1) & 0x3f;
log_info("Control: 0x%04x => SAR %u, ReqSeq %02u, R?, TxSeq %02u", control, (int) sar, req_seq, tx_seq);
log_info("SAR: pos %u", l2cap_channel->reassembly_pos);
log_info("State: expected_tx_seq %02u, req_seq %02u", l2cap_channel->expected_tx_seq, l2cap_channel->req_seq);
l2cap_ertm_process_req_seq(l2cap_channel, req_seq);
if (final){
// final bit set <- response to RR with poll bit set. All not acknowledged packets need to be retransmitted
l2cap_ertm_retransmit_unacknowleded_frames(l2cap_channel);
}
// get SDU
const uint8_t * payload_data = &packet[COMPLETE_L2CAP_HEADER+2];
uint16_t payload_len = size-(COMPLETE_L2CAP_HEADER+2+fcs_size);
// assert SDU size is smaller or equal to our buffers
uint16_t max_payload_size = 0;
switch (sar){
case L2CAP_SEGMENTATION_AND_REASSEMBLY_UNSEGMENTED_L2CAP_SDU:
case L2CAP_SEGMENTATION_AND_REASSEMBLY_START_OF_L2CAP_SDU:
// SDU Length + MPS
max_payload_size = l2cap_channel->local_mps + 2;
break;
case L2CAP_SEGMENTATION_AND_REASSEMBLY_CONTINUATION_OF_L2CAP_SDU:
case L2CAP_SEGMENTATION_AND_REASSEMBLY_END_OF_L2CAP_SDU:
max_payload_size = l2cap_channel->local_mps;
break;
}
if (payload_len > max_payload_size){
log_info("payload len %u > max payload %u -> drop packet", payload_len, max_payload_size);
break;
}
// check ordering
if (l2cap_channel->expected_tx_seq == tx_seq){
log_info("Received expected frame with TxSeq == ExpectedTxSeq == %02u", tx_seq);
l2cap_channel->expected_tx_seq = l2cap_next_ertm_seq_nr(l2cap_channel->expected_tx_seq);
l2cap_channel->req_seq = l2cap_channel->expected_tx_seq;
// process SDU
l2cap_ertm_handle_in_sequence_sdu(l2cap_channel, sar, payload_data, payload_len);
// process stored segments
while (true){
int index = l2cap_channel->rx_store_index;
l2cap_ertm_rx_packet_state_t * rx_state = &l2cap_channel->rx_packets_state[index];
if (!rx_state->valid) break;
log_info("Processing stored frame with TxSeq == ExpectedTxSeq == %02u", l2cap_channel->expected_tx_seq);
l2cap_channel->expected_tx_seq = l2cap_next_ertm_seq_nr(l2cap_channel->expected_tx_seq);
l2cap_channel->req_seq = l2cap_channel->expected_tx_seq;
rx_state->valid = 0;
l2cap_ertm_handle_in_sequence_sdu(l2cap_channel, rx_state->sar, &l2cap_channel->rx_packets_data[index], rx_state->len);
// update rx store index
index++;
if (index >= l2cap_channel->num_rx_buffers){
index = 0;
}
l2cap_channel->rx_store_index = index;
}
//
l2cap_channel->send_supervisor_frame_receiver_ready = 1;
} else {
int delta = (tx_seq - l2cap_channel->expected_tx_seq) & 0x3f;
if (delta < 2){
// store segment
l2cap_ertm_handle_out_of_sequence_sdu(l2cap_channel, sar, delta, payload_data, payload_len);
log_info("Received unexpected frame TxSeq %u but expected %u -> send S-SREJ", tx_seq, l2cap_channel->expected_tx_seq);
l2cap_channel->send_supervisor_frame_selective_reject = 1;
} else {
log_info("Received unexpected frame TxSeq %u but expected %u -> send S-REJ", tx_seq, l2cap_channel->expected_tx_seq);
l2cap_channel->send_supervisor_frame_reject = 1;
}
}
}
break;
}
#endif
l2cap_dispatch_to_channel(l2cap_channel, L2CAP_DATA_PACKET, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
l2cap_acl_classic_handler_for_channel(l2cap_channel, packet, size);
}
break;
}