Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a5238b88 authored by Hansong Zhang's avatar Hansong Zhang Committed by Automerger Merge Worker
Browse files

L2cap ERTM: Fix SDU segmentation am: 1cfed76e am: cab03d58

Change-Id: If9a1862615338f4e67513ad2073e2c9f15027bba
parents 1d770a00 cab03d58
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -99,6 +99,10 @@ class L2capMatchers(object):
    def IFrame(tx_seq=None, payload=None, f=None):
        return lambda packet: L2capMatchers._is_matching_information_frame(packet, tx_seq, payload, f)

    @staticmethod
    def IFrameStart(tx_seq=None, payload=None, f=None):
        return lambda packet: L2capMatchers._is_matching_information_start_frame(packet, tx_seq, payload, f)

    @staticmethod
    def Data(payload):
        return lambda packet: packet.GetPayload().GetBytes() == payload
@@ -159,6 +163,13 @@ class L2capMatchers(object):
            return None
        return l2cap_packets.EnhancedInformationFrameView(standard_frame)

    @staticmethod
    def _information_start_frame(packet):
        start_frame = L2capMatchers._information_frame(packet)
        if start_frame is None:
            return None
        return l2cap_packets.EnhancedInformationStartFrameView(start_frame)

    @staticmethod
    def _supervisory_frame(packet):
        standard_frame = l2cap_packets.StandardFrameView(packet)
@@ -179,6 +190,19 @@ class L2capMatchers(object):
            return False
        return True

    @staticmethod
    def _is_matching_information_start_frame(packet, tx_seq, payload, f):
        frame = L2capMatchers._information_start_frame(packet)
        if frame is None:
            return False
        if tx_seq is not None and frame.GetTxSeq() != tx_seq:
            return False
        if payload is not None and frame.GetPayload().GetBytes() != payload:
            return False
        if f is not None and frame.GetF() != f:
            return False
        return True

    @staticmethod
    def _is_matching_supervisory_frame(packet, req_seq, f, s, p):
        frame = L2capMatchers._supervisory_frame(packet)
+19 −3
Original line number Diff line number Diff line
@@ -210,7 +210,7 @@ class CertL2cap(Closable):
    def disable_fcs(self):
        self.support_fcs = False

    def turn_on_ertm(self, tx_window_size=10, max_transmit=20):
    def turn_on_ertm(self, tx_window_size=10, max_transmit=20, mps=1010):
        self.ertm_option = l2cap_packets.RetransmissionAndFlowControlConfigurationOption(
        )
        self.ertm_option.mode = l2cap_packets.RetransmissionAndFlowControlModeOption.ENHANCED_RETRANSMISSION
@@ -218,7 +218,7 @@ class CertL2cap(Closable):
        self.ertm_option.max_transmit = max_transmit
        self.ertm_option.retransmission_time_out = 2000
        self.ertm_option.monitor_time_out = 12000
        self.ertm_option.maximum_pdu_size = 1010
        self.ertm_option.maximum_pdu_size = mps

    def turn_on_fcs(self):
        self.fcs_option = l2cap_packets.FrameCheckSequenceOption()
@@ -385,7 +385,7 @@ class CertL2cap(Closable):
            l2cap_packets.ConfigurationResponseResult.UNACCEPTABLE_PARAMETERS)
        self.set_config_response_options([basic_option])

    def reply_with_max_transmit_one(self):
    def reply_ertm_with_max_transmit_one(self):
        mtu_opt = l2cap_packets.MtuConfigurationOption()
        mtu_opt.mtu = 123
        fcs_opt = l2cap_packets.FrameCheckSequenceOption()
@@ -401,6 +401,22 @@ class CertL2cap(Closable):

        self.set_config_response_options([mtu_opt, fcs_opt, rfc_opt])

    def reply_ertm_with_specified_mps(self, mps=1010):
        mtu_opt = l2cap_packets.MtuConfigurationOption()
        mtu_opt.mtu = 123
        fcs_opt = l2cap_packets.FrameCheckSequenceOption()
        fcs_opt.fcs_type = l2cap_packets.FcsType.NO_FCS
        rfc_opt = l2cap_packets.RetransmissionAndFlowControlConfigurationOption(
        )
        rfc_opt.mode = l2cap_packets.RetransmissionAndFlowControlModeOption.ENHANCED_RETRANSMISSION
        rfc_opt.tx_window_size = 10
        rfc_opt.max_transmit = 3
        rfc_opt.retransmission_time_out = 2000
        rfc_opt.monitor_time_out = 2000
        rfc_opt.maximum_pdu_size = mps

        self.set_config_response_options([mtu_opt, fcs_opt, rfc_opt])

    def _on_configuration_request_send_configuration_request_basic_mode(
            self, l2cap_control_view):
        configuration_request = l2cap_packets.ConfigurationRequestView(
+35 −2
Original line number Diff line number Diff line
@@ -616,7 +616,7 @@ class L2capTest(GdBaseTestClass):
        Verify the IUT will close the channel when the Monitor Timer expires.
        """
        self._setup_link_from_cert()
        self.cert_l2cap.reply_with_max_transmit_one()
        self.cert_l2cap.reply_ertm_with_max_transmit_one()
        self.cert_l2cap.turn_on_ertm(tx_window_size=1, max_transmit=1)

        (dut_channel, cert_channel) = self._open_channel(
@@ -631,7 +631,7 @@ class L2capTest(GdBaseTestClass):
        L2CAP/ERM/BV-12-C [I-Frame Transmissions Exceed MaxTransmit]
        """
        self._setup_link_from_cert()
        self.cert_l2cap.reply_with_max_transmit_one()
        self.cert_l2cap.reply_ertm_with_max_transmit_one()
        self.cert_l2cap.turn_on_ertm(tx_window_size=1, max_transmit=1)

        (dut_channel, cert_channel) = self._open_channel(
@@ -789,6 +789,39 @@ class L2capTest(GdBaseTestClass):
            f=Final.POLL_RESPONSE)
        assertThat(cert_channel).emitsNone(L2capMatchers.IFrame(tx_seq=0))

    @metadata(
        pts_test_id="L2CAP/ERM/BV-23-C",
        pts_test_name="Transmit I-Frames using SAR")
    def test_transmit_i_frames_using_sar(self):
        """
        Verify the IUT can send correctly formatted sequential I-frames with
        valid values for the enhanced control fields (SAR, F-bit, ReqSeq,
        TxSeq) when performing SAR.
        """
        self._setup_link_from_cert()
        self.cert_l2cap.reply_ertm_with_specified_mps(11)
        self.cert_l2cap.turn_on_ertm(tx_window_size=3, max_transmit=2, mps=11)

        (dut_channel, cert_channel) = self._open_channel(
            scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM)

        dut_channel.send(b'abcabcabc')
        # First IFrame should contain SDU size after control field
        assertThat(cert_channel).emits(
            L2capMatchers.IFrameStart(tx_seq=0, payload=b'abc'),
            L2capMatchers.IFrame(tx_seq=1, payload=b'abc'),
            L2capMatchers.IFrame(tx_seq=2, payload=b'abc')).inOrder()

        cert_channel.send_s_frame(
            req_seq=3, s=SupervisoryFunction.RECEIVER_READY)

        dut_channel.send(b'defdefdef')
        # First IFrame should contain SDU size after control field
        assertThat(cert_channel).emits(
            L2capMatchers.IFrameStart(tx_seq=3, payload=b'def'),
            L2capMatchers.IFrame(tx_seq=4, payload=b'def'),
            L2capMatchers.IFrame(tx_seq=5, payload=b'def')).inOrder()

    def test_sent_rej_lost(self):
        """
        L2CAP/ERM/BI-01-C [S-Frame [REJ] Lost or Corrupted]
+4 −1
Original line number Diff line number Diff line
@@ -795,7 +795,9 @@ struct ErtmController::impl {
void ErtmController::OnSdu(std::unique_ptr<packet::BasePacketBuilder> sdu) {
  auto sdu_size = sdu->size();
  std::vector<std::unique_ptr<packet::RawBuilder>> segments;
  packet::FragmentingInserter fragmenting_inserter(size_each_packet_, std::back_insert_iterator(segments));
  auto size_each_packet = (remote_mps_ - 4 /* basic L2CAP header */ - 2 /* SDU length */ - 2 /* Enhanced control */ -
                           (fcs_enabled_ ? 2 : 0));
  packet::FragmentingInserter fragmenting_inserter(size_each_packet, std::back_insert_iterator(segments));
  sdu->Serialize(fragmenting_inserter);
  fragmenting_inserter.finalize();
  if (segments.size() == 1) {
@@ -1011,6 +1013,7 @@ void ErtmController::SetRetransmissionAndFlowControlOptions(
  local_max_transmit_ = option.max_transmit_;
  local_retransmit_timeout_ms_ = option.retransmission_time_out_;
  local_monitor_timeout_ms_ = option.monitor_time_out_;
  remote_mps_ = option.maximum_pdu_size_;
}

void ErtmController::close_channel() {
+0 −3
Original line number Diff line number Diff line
@@ -72,9 +72,6 @@ class ErtmController : public DataController {
  uint16_t remote_tx_window_ = 10;
  uint16_t remote_mps_ = 1010;

  uint16_t size_each_packet_ =
      (remote_mps_ - 4 /* basic L2CAP header */ - 2 /* SDU length */ - 2 /* Extended control */ - 2 /* FCS */);

  class PacketViewForReassembly : public packet::PacketView<kLittleEndian> {
   public:
    PacketViewForReassembly(const PacketView& packetView) : PacketView(packetView) {}