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

Commit 6c5ebfe3 authored by Hansong Zhang's avatar Hansong Zhang
Browse files

L2CAP: Fix dynamic channel refcount and ERTM timeout

Added a simple PTS Transmit I-frames and S-Frame Transmissions
Exceed MaxTransmit to verify ERTM DataController could correctly close
the channel on error.

Test: run_cert.sh
Bug: 145006212
Bug: 141557006
Change-Id: Ic6e58cb7022b0df1b7d7eaefff2168b0044b6ec3
parent a1fb9564
Loading
Loading
Loading
Loading
+14 −4
Original line number Diff line number Diff line
@@ -164,10 +164,10 @@ class L2capClassicModuleCertService : public L2capClassicModuleCert::Service {
    if (request->retransmission_config().mode() == ChannelRetransmissionFlowControlMode::ERTM) {
      auto option = std::make_unique<RetransmissionAndFlowControlConfigurationOption>();
      option->mode_ = RetransmissionAndFlowControlModeOption::ENHANCED_RETRANSMISSION;
      option->tx_window_size_ = 10;
      option->max_transmit_ = 20;
      option->retransmission_time_out_ = 2000;
      option->monitor_time_out_ = 12000;
      option->tx_window_size_ = 5;
      option->max_transmit_ = 1;
      option->retransmission_time_out_ = 1000;
      option->monitor_time_out_ = 2000;
      option->maximum_pdu_size_ = 1010;
      config.push_back(std::move(option));
    }
@@ -407,6 +407,16 @@ class L2capClassicModuleCertService : public L2capClassicModuleCert::Service {
        LogEvent(response);
        break;
      }
      case CommandCode::DISCONNECTION_REQUEST: {
        DisconnectionRequestView view = DisconnectionRequestView::Create(control_view);
        ASSERT(view.IsValid());
        FetchL2capLogResponse response;
        response.mutable_disconnection_request()->set_signal_id(control_view.GetIdentifier());
        response.mutable_disconnection_request()->set_dcid(view.GetDestinationCid());
        response.mutable_disconnection_request()->set_scid(view.GetSourceCid());
        LogEvent(response);
        break;
      }
      case CommandCode::DISCONNECTION_RESPONSE: {
        DisconnectionResponseView view = DisconnectionResponseView::Create(control_view);
        ASSERT(view.IsValid());
+53 −0
Original line number Diff line number Diff line
@@ -142,6 +142,7 @@ class SimpleL2capTest(GdBaseTestClass):
            self.cert_device.l2cap.SendConfigurationResponse(l2cap_cert_pb2.ConfigurationResponse(
                scid=dcid,
                signal_id=log.signal_id,
                retransmission_config=l2cap_cert_pb2.ChannelRetransmissionFlowControlConfig(mode=self.retransmission_mode)
                ))
        log_event_handler.on(is_configuration_request, handle_configuration_request)

@@ -404,3 +405,55 @@ class SimpleL2capTest(GdBaseTestClass):
        assert info_response[0][0] == signal_id
        assert info_response[0][1] == expected_log_type
        assert info_response[0][2] | expected_mask == expected_mask

    def test_transmit_i_frames(self):
        """
        L2CAP/ERM/BV-01-C [Transmit I-frames]
        """
        self.retransmission_mode = l2cap_cert_pb2.ChannelRetransmissionFlowControlMode.ERTM
        self.device_under_test.l2cap.RegisterChannel(l2cap_facade_pb2.RegisterChannelRequest(channel=2))
        self.device_under_test.l2cap.SetDynamicChannel(l2cap_facade_pb2.SetEnableDynamicChannelRequest(psm=0x33, retransmission_mode=l2cap_facade_pb2.RetransmissionFlowControlMode.ERTM))
        self._setup_link()
        scid = 0x0101
        self._open_channel(scid=scid)
        self.device_under_test.l2cap.SendDynamicChannelPacket(l2cap_facade_pb2.DynamicChannelPacket(psm=0x33, payload=b'abc'))
        self.cert_device.l2cap.SendSFrame(l2cap_cert_pb2.SFrame(channel=self.scid_dcid_map[scid], req_seq=1, s=0))
        self.device_under_test.l2cap.SendDynamicChannelPacket(l2cap_facade_pb2.DynamicChannelPacket(psm=0x33, payload=b'abc'))
        self.cert_device.l2cap.SendSFrame(l2cap_cert_pb2.SFrame(channel=self.scid_dcid_map[scid], req_seq=2, s=0))
        self.device_under_test.l2cap.SendDynamicChannelPacket(l2cap_facade_pb2.DynamicChannelPacket(psm=0x33, payload=b'abc'))
        self.cert_device.l2cap.SendSFrame(l2cap_cert_pb2.SFrame(channel=self.scid_dcid_map[scid], req_seq=3, s=0))
        data_received = []
        event_handler = EventHandler()
        def on_data_received(log):
            log = log.data_packet
            data_received.append((log.channel, log.payload))
        event_handler.on(lambda log : log.HasField("data_packet"), on_data_received)
        logs = self.cert_device.l2cap.FetchL2capLog(l2cap_cert_pb2.FetchL2capLogRequest())
        event_handler.execute(logs)
        assert len(data_received) == 3

    def test_s_frame_transmissions_exceed_max_transmit(self):
        """
        L2CAP/ERM/BV-11-C [S-Frame Transmissions Exceed MaxTransmit]
        """
        self.retransmission_mode = l2cap_cert_pb2.ChannelRetransmissionFlowControlMode.ERTM
        self.device_under_test.l2cap.RegisterChannel(l2cap_facade_pb2.RegisterChannelRequest(channel=2))
        self.device_under_test.l2cap.SetDynamicChannel(l2cap_facade_pb2.SetEnableDynamicChannelRequest(psm=0x33, retransmission_mode=l2cap_facade_pb2.RetransmissionFlowControlMode.ERTM))
        self._setup_link()
        scid = 0x0101
        self._open_channel(scid=scid)
        self.device_under_test.l2cap.SendDynamicChannelPacket(l2cap_facade_pb2.DynamicChannelPacket(psm=0x33, payload=b'abc'))
        # Retransmission timer = 1, 1 * monitor timer = 2, so total timeout is 3
        time.sleep(4)
        disconnect_request = []
        event_handler = EventHandler()

        def on_disconnect_req(log):
            log = log.disconnection_request
            disconnect_request.append((log.dcid, log.scid))
        event_handler.on(is_disconnection_request, on_disconnect_req)

        logs = self.cert_device.l2cap.FetchL2capLog(l2cap_cert_pb2.FetchL2capLogRequest())
        event_handler.execute(logs)
        assert len(disconnect_request) == 1, "No disconnect request received"
        assert disconnect_request[0] == (scid, self.scid_dcid_map[scid]), "Incorrect disconnect request received: scid %r, dcid %r" % (disconnect_request[0][0], disconnect_request[0][1])
+3 −0
Original line number Diff line number Diff line
@@ -92,6 +92,7 @@ std::shared_ptr<l2cap::internal::DynamicChannelImpl> Link::AllocateDynamicChanne
  auto channel = dynamic_channel_allocator_.AllocateChannel(psm, remote_cid, security_policy);
  if (channel != nullptr) {
    data_pipeline_manager_.AttachChannel(channel->GetCid(), channel);
    RefreshRefCount();
  }
  channel->local_initiated_ = false;
  return channel;
@@ -102,6 +103,7 @@ std::shared_ptr<l2cap::internal::DynamicChannelImpl> Link::AllocateReservedDynam
  auto channel = dynamic_channel_allocator_.AllocateReservedChannel(reserved_cid, psm, remote_cid, security_policy);
  if (channel != nullptr) {
    data_pipeline_manager_.AttachChannel(channel->GetCid(), channel);
    RefreshRefCount();
  }
  channel->local_initiated_ = true;
  return channel;
@@ -119,6 +121,7 @@ void Link::FreeDynamicChannel(Cid cid) {
  }
  data_pipeline_manager_.DetachChannel(cid);
  dynamic_channel_allocator_.FreeChannel(cid);
  RefreshRefCount();
}

void Link::RefreshRefCount() {
+1 −1
Original line number Diff line number Diff line
@@ -154,7 +154,7 @@ struct ErtmController::impl {
      send_rr_or_rnr(Poll::POLL);
      // send rr or rnr(p=1)
      retry_count_ = 1;
      start_retrans_timer();
      start_monitor_timer();
      tx_state_ = TxState::WAIT_F;
    }
  }