Loading system/gd/l2cap/classic/cert/cert_l2cap.py +40 −36 Original line number Diff line number Diff line Loading @@ -130,6 +130,9 @@ class CertL2cap(Closable): self.ertm_option = None self.fcs_option = None self.config_response_result = l2cap_packets.ConfigurationResponseResult.SUCCESS self.config_response_options = [] def close(self): self._acl_manager.close() safeClose(self._acl) Loading Loading @@ -230,12 +233,6 @@ class CertL2cap(Closable): def ignore_config_request(self): self.control_table[CommandCode.CONFIGURATION_REQUEST] = lambda _: True # more of a hack for the moment def reply_with_unacceptable_parameters(self): self.control_table[ CommandCode. CONFIGURATION_REQUEST] = self._on_configuration_request_unacceptable_parameters # more of a hack for the moment def reply_with_unknown_options_and_hint(self): self.control_table[ Loading @@ -248,12 +245,6 @@ class CertL2cap(Closable): CommandCode. CONNECTION_RESPONSE] = self._on_connection_response_configuration_request_with_continuation_flag # more of a hack for the moment def reply_with_basic_mode(self): self.control_table[ CommandCode. CONFIGURATION_REQUEST] = self._on_configuration_request_basic_mode # more of a hack for the moment def reply_with_nothing(self): self.control_table[ Loading @@ -267,6 +258,18 @@ class CertL2cap(Closable): CommandCode. CONFIGURATION_REQUEST] = self._on_configuration_request_send_configuration_request_basic_mode def set_config_response_result(self, result): """ Set the result for config response packet """ self.config_response_result = result def set_config_response_options(self, options): """ Set the options (list) for config response packet """ self.config_response_options = options def _on_connection_request_default(self, l2cap_control_view): pass Loading Loading @@ -357,16 +360,10 @@ class CertL2cap(Closable): dcid = configuration_request.GetDestinationCid() config_response = l2cap_packets.ConfigurationResponseBuilder( sid, self.scid_to_dcid.get(dcid, 0), l2cap_packets.Continuation.END, l2cap_packets.ConfigurationResponseResult.SUCCESS, []) self.config_response_result, self.config_response_options) self.control_channel.send(config_response) def _on_configuration_request_unacceptable_parameters( self, l2cap_control_view): configuration_request = l2cap_packets.ConfigurationRequestView( l2cap_control_view) sid = configuration_request.GetIdentifier() dcid = configuration_request.GetDestinationCid() def reply_with_unacceptable_parameters(self): mtu_opt = l2cap_packets.MtuConfigurationOption() mtu_opt.mtu = 123 fcs_opt = l2cap_packets.FrameCheckSequenceOption() Loading @@ -375,27 +372,34 @@ class CertL2cap(Closable): ) rfc_opt.mode = l2cap_packets.RetransmissionAndFlowControlModeOption.L2CAP_BASIC config_response = l2cap_packets.ConfigurationResponseBuilder( sid, self.scid_to_dcid.get(dcid, 0), l2cap_packets.Continuation.END, l2cap_packets.ConfigurationResponseResult.UNACCEPTABLE_PARAMETERS, [mtu_opt, fcs_opt, rfc_opt]) self.control_channel.send(config_response) def _on_configuration_request_basic_mode(self, l2cap_control_view): configuration_request = l2cap_packets.ConfigurationRequestView( l2cap_control_view) sid = configuration_request.GetIdentifier() dcid = configuration_request.GetDestinationCid() self.set_config_response_result( l2cap_packets.ConfigurationResponseResult.UNACCEPTABLE_PARAMETERS) self.set_config_response_options([mtu_opt, fcs_opt, rfc_opt]) def reply_with_basic_mode(self): basic_option = l2cap_packets.RetransmissionAndFlowControlConfigurationOption( ) basic_option.mode = l2cap_packets.RetransmissionAndFlowControlModeOption.L2CAP_BASIC config_response = l2cap_packets.ConfigurationResponseBuilder( sid, self.scid_to_dcid.get(dcid, 0), l2cap_packets.Continuation.END, l2cap_packets.ConfigurationResponseResult.UNACCEPTABLE_PARAMETERS, [basic_option]) self.control_channel.send(config_response) self.set_config_response_result( l2cap_packets.ConfigurationResponseResult.UNACCEPTABLE_PARAMETERS) self.set_config_response_options([basic_option]) def reply_with_max_transmit_one(self): mtu_opt = l2cap_packets.MtuConfigurationOption() mtu_opt.mtu = 123 fcs_opt = l2cap_packets.FrameCheckSequenceOption() fcs_opt.fcs_type = l2cap_packets.FcsType.DEFAULT rfc_opt = l2cap_packets.RetransmissionAndFlowControlConfigurationOption( ) rfc_opt.mode = l2cap_packets.RetransmissionAndFlowControlModeOption.ENHANCED_RETRANSMISSION rfc_opt.tx_window_size = 10 rfc_opt.max_transmit = 1 rfc_opt.retransmission_time_out = 10 rfc_opt.monitor_time_out = 10 rfc_opt.maximum_pdu_size = 1010 self.set_config_response_options([mtu_opt, fcs_opt, rfc_opt]) def _on_configuration_request_send_configuration_request_basic_mode( self, l2cap_control_view): Loading system/gd/l2cap/classic/cert/l2cap_test.py +14 −17 Original line number Diff line number Diff line Loading @@ -281,14 +281,12 @@ class L2capTest(GdBaseTestClass): Verify that the IUT responds to an echo request. """ self._setup_link_from_cert() asserts.skip("is echo without a channel supported?") echo_request = l2cap_packets.EchoRequestBuilder( 100, l2cap_packets.DisconnectionRequestBuilder(1, 2, 3)) echo_request_l2cap = l2cap_packets.BasicFrameBuilder(1, echo_request) self.cert_send_b_frame(echo_request_l2cap) self.cert_l2cap.get_control_channel().send(echo_request) assertThat(self.cert_channel).emits( assertThat(self.cert_l2cap.get_control_channel()).emits( L2capMatchers.PartialData(b"\x06\x01\x04\x00\x02\x00\x03\x00")) def test_reject_unknown_command(self): Loading @@ -297,8 +295,10 @@ class L2capTest(GdBaseTestClass): """ self._setup_link_from_cert() asserts.skip("need to use packet builders") invalid_command_packet = b"\x04\x00\x01\x00\xff\x01\x00\x00" asserts.skip("Need to use packet builders (RawBuilder)") # TODO(hsz): Use packet builders with opcode 0xff, sid 0x1, size 0x0 invalid_command_packet = b"\xff\x01\x00\x00" self.cert_l2cap.get_control_channel().send(invalid_command_packet) assertThat(self.cert_channel).emits(L2capMatchers.CommandReject()) Loading Loading @@ -619,34 +619,32 @@ class L2capTest(GdBaseTestClass): L2CAP/ERM/BV-11-C [S-Frame Transmissions Exceed MaxTransmit] Verify the IUT will close the channel when the Monitor Timer expires. """ asserts.skip("Need to configure DUT to have a shorter timer") self._setup_link_from_cert() self.cert_l2cap.turn_on_ertm() self.cert_l2cap.reply_with_max_transmit_one() self.cert_l2cap.turn_on_ertm(tx_window_size=1, max_transmit=1) (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') # Retransmission timer = 2, 20 * monitor timer = 360, so total timeout is 362 time.sleep(362) cert_channel.verify_disconnect_request() def test_i_frame_transmissions_exceed_max_transmit(self): """ L2CAP/ERM/BV-12-C [I-Frame Transmissions Exceed MaxTransmit] Verify the IUT will close the channel when it receives an S-frame [RR] with the final bit set that does not acknowledge the previous I-frame sent by the IUT. """ asserts.skip("Not working") self._setup_link_from_cert() self.cert_l2cap.turn_on_ertm() self.cert_l2cap.reply_with_max_transmit_one() self.cert_l2cap.turn_on_ertm(tx_window_size=1, max_transmit=1) (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0)) assertThat(cert_channel).emits( L2capMatchers.IFrame(tx_seq=0), L2capMatchers.SFrame(p=Poll.POLL)).inOrder() cert_channel.send_s_frame(req_seq=0, f=Final.POLL_RESPONSE) cert_channel.verify_disconnect_request() Loading Loading @@ -937,7 +935,7 @@ class L2capTest(GdBaseTestClass): Verify the IUT can accept a Configuration Request from the Lower Tester containing an F&EC option that specifies Enhanced Retransmission Mode. """ asserts.skip("Not working") asserts.skip("ConfigurationResponseView Not working") self._setup_link_from_cert() psm = 1 scid = 0x0101 Loading Loading @@ -969,7 +967,6 @@ class L2capTest(GdBaseTestClass): L2CAP/CMC/BI-01-C """ self._setup_link_from_cert() self.cert_l2cap.reply_with_nothing() self.cert_l2cap.reply_with_basic_mode() (dut_channel, cert_channel) = self._open_unvalidated_channel( scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) Loading system/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller.cc +6 −13 Original line number Diff line number Diff line Loading @@ -245,7 +245,7 @@ struct ErtmController::impl { void recv_rr(uint8_t req_seq, Poll p = Poll::NOT_SET, Final f = Final::NOT_SET) { if (rx_state_ == RxState::RECV) { if (p == Poll::NOT_SET && f == Final::NOT_SET && with_valid_req_seq_rr(req_seq) && with_valid_f_bit(f)) { if (p == Poll::NOT_SET && f == Final::NOT_SET && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) { pass_to_tx(req_seq, f); if (remote_busy() && unacked_frames_ > 0) { start_retrans_timer(); Loading @@ -264,7 +264,7 @@ struct ErtmController::impl { } else if (p == Poll::POLL && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) { pass_to_tx(req_seq, f); send_i_or_rr_or_rnr(Final::POLL_RESPONSE); } else if (with_invalid_req_seq_rr(req_seq)) { } else if (with_invalid_req_seq(req_seq)) { CloseChannel(); } } else if (rx_state_ == RxState::REJ_SENT) { Loading @@ -277,7 +277,7 @@ struct ErtmController::impl { rej_actioned_ = false; } send_pending_i_frames(); } else if (p == Poll::NOT_SET && f == Final::NOT_SET && with_valid_req_seq_rr(req_seq) && with_valid_f_bit(f)) { } else if (p == Poll::NOT_SET && f == Final::NOT_SET && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) { pass_to_tx(req_seq, f); if (remote_busy() and unacked_frames_ > 0) { start_retrans_timer(); Loading @@ -291,7 +291,7 @@ struct ErtmController::impl { } remote_busy_ = false; send_rr(Final::POLL_RESPONSE); } else if (with_invalid_req_seq_rr(req_seq)) { } else if (with_invalid_req_seq(req_seq)) { CloseChannel(); } } else if (rx_state_ == RxState::SREJ_SENT) { Loading Loading @@ -523,21 +523,13 @@ struct ErtmController::impl { } bool with_invalid_req_seq_retrans(uint8_t req_seq) { return req_seq < expected_ack_seq_ || req_seq >= next_tx_seq_; return req_seq < expected_ack_seq_ || req_seq > next_tx_seq_; } bool not_with_expected_tx_seq(uint8_t tx_seq) { return !with_invalid_tx_seq(tx_seq) && !with_expected_tx_seq(tx_seq); } bool with_valid_req_seq_rr(uint8_t req_seq) { return expected_ack_seq_ < req_seq && req_seq <= next_tx_seq_; } bool with_invalid_req_seq_rr(uint8_t req_seq) { return req_seq <= expected_ack_seq_ || req_seq > next_tx_seq_; } bool with_expected_tx_seq_srej() { // We don't support sending SREJ return false; Loading Loading @@ -614,6 +606,7 @@ struct ErtmController::impl { retry_i_frames_[i] = 0; } unacked_frames_ -= ((req_seq - expected_ack_seq_) + kMaxTxWin) % kMaxTxWin; expected_ack_seq_ = req_seq; if (unacked_frames_ == 0) { stop_retrans_timer(); } Loading Loading
system/gd/l2cap/classic/cert/cert_l2cap.py +40 −36 Original line number Diff line number Diff line Loading @@ -130,6 +130,9 @@ class CertL2cap(Closable): self.ertm_option = None self.fcs_option = None self.config_response_result = l2cap_packets.ConfigurationResponseResult.SUCCESS self.config_response_options = [] def close(self): self._acl_manager.close() safeClose(self._acl) Loading Loading @@ -230,12 +233,6 @@ class CertL2cap(Closable): def ignore_config_request(self): self.control_table[CommandCode.CONFIGURATION_REQUEST] = lambda _: True # more of a hack for the moment def reply_with_unacceptable_parameters(self): self.control_table[ CommandCode. CONFIGURATION_REQUEST] = self._on_configuration_request_unacceptable_parameters # more of a hack for the moment def reply_with_unknown_options_and_hint(self): self.control_table[ Loading @@ -248,12 +245,6 @@ class CertL2cap(Closable): CommandCode. CONNECTION_RESPONSE] = self._on_connection_response_configuration_request_with_continuation_flag # more of a hack for the moment def reply_with_basic_mode(self): self.control_table[ CommandCode. CONFIGURATION_REQUEST] = self._on_configuration_request_basic_mode # more of a hack for the moment def reply_with_nothing(self): self.control_table[ Loading @@ -267,6 +258,18 @@ class CertL2cap(Closable): CommandCode. CONFIGURATION_REQUEST] = self._on_configuration_request_send_configuration_request_basic_mode def set_config_response_result(self, result): """ Set the result for config response packet """ self.config_response_result = result def set_config_response_options(self, options): """ Set the options (list) for config response packet """ self.config_response_options = options def _on_connection_request_default(self, l2cap_control_view): pass Loading Loading @@ -357,16 +360,10 @@ class CertL2cap(Closable): dcid = configuration_request.GetDestinationCid() config_response = l2cap_packets.ConfigurationResponseBuilder( sid, self.scid_to_dcid.get(dcid, 0), l2cap_packets.Continuation.END, l2cap_packets.ConfigurationResponseResult.SUCCESS, []) self.config_response_result, self.config_response_options) self.control_channel.send(config_response) def _on_configuration_request_unacceptable_parameters( self, l2cap_control_view): configuration_request = l2cap_packets.ConfigurationRequestView( l2cap_control_view) sid = configuration_request.GetIdentifier() dcid = configuration_request.GetDestinationCid() def reply_with_unacceptable_parameters(self): mtu_opt = l2cap_packets.MtuConfigurationOption() mtu_opt.mtu = 123 fcs_opt = l2cap_packets.FrameCheckSequenceOption() Loading @@ -375,27 +372,34 @@ class CertL2cap(Closable): ) rfc_opt.mode = l2cap_packets.RetransmissionAndFlowControlModeOption.L2CAP_BASIC config_response = l2cap_packets.ConfigurationResponseBuilder( sid, self.scid_to_dcid.get(dcid, 0), l2cap_packets.Continuation.END, l2cap_packets.ConfigurationResponseResult.UNACCEPTABLE_PARAMETERS, [mtu_opt, fcs_opt, rfc_opt]) self.control_channel.send(config_response) def _on_configuration_request_basic_mode(self, l2cap_control_view): configuration_request = l2cap_packets.ConfigurationRequestView( l2cap_control_view) sid = configuration_request.GetIdentifier() dcid = configuration_request.GetDestinationCid() self.set_config_response_result( l2cap_packets.ConfigurationResponseResult.UNACCEPTABLE_PARAMETERS) self.set_config_response_options([mtu_opt, fcs_opt, rfc_opt]) def reply_with_basic_mode(self): basic_option = l2cap_packets.RetransmissionAndFlowControlConfigurationOption( ) basic_option.mode = l2cap_packets.RetransmissionAndFlowControlModeOption.L2CAP_BASIC config_response = l2cap_packets.ConfigurationResponseBuilder( sid, self.scid_to_dcid.get(dcid, 0), l2cap_packets.Continuation.END, l2cap_packets.ConfigurationResponseResult.UNACCEPTABLE_PARAMETERS, [basic_option]) self.control_channel.send(config_response) self.set_config_response_result( l2cap_packets.ConfigurationResponseResult.UNACCEPTABLE_PARAMETERS) self.set_config_response_options([basic_option]) def reply_with_max_transmit_one(self): mtu_opt = l2cap_packets.MtuConfigurationOption() mtu_opt.mtu = 123 fcs_opt = l2cap_packets.FrameCheckSequenceOption() fcs_opt.fcs_type = l2cap_packets.FcsType.DEFAULT rfc_opt = l2cap_packets.RetransmissionAndFlowControlConfigurationOption( ) rfc_opt.mode = l2cap_packets.RetransmissionAndFlowControlModeOption.ENHANCED_RETRANSMISSION rfc_opt.tx_window_size = 10 rfc_opt.max_transmit = 1 rfc_opt.retransmission_time_out = 10 rfc_opt.monitor_time_out = 10 rfc_opt.maximum_pdu_size = 1010 self.set_config_response_options([mtu_opt, fcs_opt, rfc_opt]) def _on_configuration_request_send_configuration_request_basic_mode( self, l2cap_control_view): Loading
system/gd/l2cap/classic/cert/l2cap_test.py +14 −17 Original line number Diff line number Diff line Loading @@ -281,14 +281,12 @@ class L2capTest(GdBaseTestClass): Verify that the IUT responds to an echo request. """ self._setup_link_from_cert() asserts.skip("is echo without a channel supported?") echo_request = l2cap_packets.EchoRequestBuilder( 100, l2cap_packets.DisconnectionRequestBuilder(1, 2, 3)) echo_request_l2cap = l2cap_packets.BasicFrameBuilder(1, echo_request) self.cert_send_b_frame(echo_request_l2cap) self.cert_l2cap.get_control_channel().send(echo_request) assertThat(self.cert_channel).emits( assertThat(self.cert_l2cap.get_control_channel()).emits( L2capMatchers.PartialData(b"\x06\x01\x04\x00\x02\x00\x03\x00")) def test_reject_unknown_command(self): Loading @@ -297,8 +295,10 @@ class L2capTest(GdBaseTestClass): """ self._setup_link_from_cert() asserts.skip("need to use packet builders") invalid_command_packet = b"\x04\x00\x01\x00\xff\x01\x00\x00" asserts.skip("Need to use packet builders (RawBuilder)") # TODO(hsz): Use packet builders with opcode 0xff, sid 0x1, size 0x0 invalid_command_packet = b"\xff\x01\x00\x00" self.cert_l2cap.get_control_channel().send(invalid_command_packet) assertThat(self.cert_channel).emits(L2capMatchers.CommandReject()) Loading Loading @@ -619,34 +619,32 @@ class L2capTest(GdBaseTestClass): L2CAP/ERM/BV-11-C [S-Frame Transmissions Exceed MaxTransmit] Verify the IUT will close the channel when the Monitor Timer expires. """ asserts.skip("Need to configure DUT to have a shorter timer") self._setup_link_from_cert() self.cert_l2cap.turn_on_ertm() self.cert_l2cap.reply_with_max_transmit_one() self.cert_l2cap.turn_on_ertm(tx_window_size=1, max_transmit=1) (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') # Retransmission timer = 2, 20 * monitor timer = 360, so total timeout is 362 time.sleep(362) cert_channel.verify_disconnect_request() def test_i_frame_transmissions_exceed_max_transmit(self): """ L2CAP/ERM/BV-12-C [I-Frame Transmissions Exceed MaxTransmit] Verify the IUT will close the channel when it receives an S-frame [RR] with the final bit set that does not acknowledge the previous I-frame sent by the IUT. """ asserts.skip("Not working") self._setup_link_from_cert() self.cert_l2cap.turn_on_ertm() self.cert_l2cap.reply_with_max_transmit_one() self.cert_l2cap.turn_on_ertm(tx_window_size=1, max_transmit=1) (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0)) assertThat(cert_channel).emits( L2capMatchers.IFrame(tx_seq=0), L2capMatchers.SFrame(p=Poll.POLL)).inOrder() cert_channel.send_s_frame(req_seq=0, f=Final.POLL_RESPONSE) cert_channel.verify_disconnect_request() Loading Loading @@ -937,7 +935,7 @@ class L2capTest(GdBaseTestClass): Verify the IUT can accept a Configuration Request from the Lower Tester containing an F&EC option that specifies Enhanced Retransmission Mode. """ asserts.skip("Not working") asserts.skip("ConfigurationResponseView Not working") self._setup_link_from_cert() psm = 1 scid = 0x0101 Loading Loading @@ -969,7 +967,6 @@ class L2capTest(GdBaseTestClass): L2CAP/CMC/BI-01-C """ self._setup_link_from_cert() self.cert_l2cap.reply_with_nothing() self.cert_l2cap.reply_with_basic_mode() (dut_channel, cert_channel) = self._open_unvalidated_channel( scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) Loading
system/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller.cc +6 −13 Original line number Diff line number Diff line Loading @@ -245,7 +245,7 @@ struct ErtmController::impl { void recv_rr(uint8_t req_seq, Poll p = Poll::NOT_SET, Final f = Final::NOT_SET) { if (rx_state_ == RxState::RECV) { if (p == Poll::NOT_SET && f == Final::NOT_SET && with_valid_req_seq_rr(req_seq) && with_valid_f_bit(f)) { if (p == Poll::NOT_SET && f == Final::NOT_SET && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) { pass_to_tx(req_seq, f); if (remote_busy() && unacked_frames_ > 0) { start_retrans_timer(); Loading @@ -264,7 +264,7 @@ struct ErtmController::impl { } else if (p == Poll::POLL && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) { pass_to_tx(req_seq, f); send_i_or_rr_or_rnr(Final::POLL_RESPONSE); } else if (with_invalid_req_seq_rr(req_seq)) { } else if (with_invalid_req_seq(req_seq)) { CloseChannel(); } } else if (rx_state_ == RxState::REJ_SENT) { Loading @@ -277,7 +277,7 @@ struct ErtmController::impl { rej_actioned_ = false; } send_pending_i_frames(); } else if (p == Poll::NOT_SET && f == Final::NOT_SET && with_valid_req_seq_rr(req_seq) && with_valid_f_bit(f)) { } else if (p == Poll::NOT_SET && f == Final::NOT_SET && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) { pass_to_tx(req_seq, f); if (remote_busy() and unacked_frames_ > 0) { start_retrans_timer(); Loading @@ -291,7 +291,7 @@ struct ErtmController::impl { } remote_busy_ = false; send_rr(Final::POLL_RESPONSE); } else if (with_invalid_req_seq_rr(req_seq)) { } else if (with_invalid_req_seq(req_seq)) { CloseChannel(); } } else if (rx_state_ == RxState::SREJ_SENT) { Loading Loading @@ -523,21 +523,13 @@ struct ErtmController::impl { } bool with_invalid_req_seq_retrans(uint8_t req_seq) { return req_seq < expected_ack_seq_ || req_seq >= next_tx_seq_; return req_seq < expected_ack_seq_ || req_seq > next_tx_seq_; } bool not_with_expected_tx_seq(uint8_t tx_seq) { return !with_invalid_tx_seq(tx_seq) && !with_expected_tx_seq(tx_seq); } bool with_valid_req_seq_rr(uint8_t req_seq) { return expected_ack_seq_ < req_seq && req_seq <= next_tx_seq_; } bool with_invalid_req_seq_rr(uint8_t req_seq) { return req_seq <= expected_ack_seq_ || req_seq > next_tx_seq_; } bool with_expected_tx_seq_srej() { // We don't support sending SREJ return false; Loading Loading @@ -614,6 +606,7 @@ struct ErtmController::impl { retry_i_frames_[i] = 0; } unacked_frames_ -= ((req_seq - expected_ack_seq_) + kMaxTxWin) % kMaxTxWin; expected_ack_seq_ = req_seq; if (unacked_frames_ == 0) { stop_retrans_timer(); } Loading