dcsctp: Defer all streams when resetting with empty stream list Per RFC 6525 Section 5.2.2 (E3), an Outgoing SSN Reset Request parameter with an empty list of stream numbers indicates that all incoming streams shall be reset. When entering deferred reset processing with an empty stream list, ReassemblyQueue::Add must defer incoming data for all streams with a higher TSN than the last assigned. Bug: webrtc:568271571 Change-Id: I150e54f852ae3f35e9a61a1134bdf0f917c7e2e0 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/506921 Reviewed-by: Danil Chapovalov <danilchap@webrtc.org> Commit-Queue: Victor Boivie <boivie@webrtc.org> Cr-Commit-Position: refs/heads/main@{#48775}
diff --git a/net/dcsctp/rx/reassembly_queue.cc b/net/dcsctp/rx/reassembly_queue.cc index f671bdc..c31da47 100644 --- a/net/dcsctp/rx/reassembly_queue.cc +++ b/net/dcsctp/rx/reassembly_queue.cc
@@ -85,7 +85,8 @@ // buffer chunks until it's exited. if (deferred_reset_streams_.has_value() && unwrapped_tsn > deferred_reset_streams_->sender_last_assigned_tsn && - deferred_reset_streams_->streams.contains(data.stream_id)) { + (deferred_reset_streams_->streams.empty() || + deferred_reset_streams_->streams.contains(data.stream_id))) { RTC_DLOG(LS_VERBOSE) << log_prefix_ << "Deferring chunk with tsn=" << *tsn << ", sid=" << *data.stream_id << " until tsn="
diff --git a/net/dcsctp/socket/stream_reset_handler_test.cc b/net/dcsctp/socket/stream_reset_handler_test.cc index cff6005..d1c63f8 100644 --- a/net/dcsctp/socket/stream_reset_handler_test.cc +++ b/net/dcsctp/socket/stream_reset_handler_test.cc
@@ -429,6 +429,64 @@ EXPECT_FALSE(reasm_->HasMessages()); } +TEST_F(StreamResetHandlerTest, ResetAllStreamsDeferred) { + // Per RFC 6525 Section 4.1 / 5.2.2 (E3), an empty list of stream numbers in + // an Outgoing SSN Reset Request parameter indicates that all streams shall be + // reset. + + // TSN 10 (SSN 0) is received and delivered, advancing Stream 1's expected SSN + // to 1. + data_tracker_->Observe(TSN(10)); + reasm_->Add(TSN(10), gen_.Ordered({1, 2, 3, 4}, "BE", + {.stream_id = StreamID(1), + .mid = MID(0), + .ppid = PPID(1001)})); + EXPECT_THAT(reasm_->GetNextMessage(), + Optional(SctpMessageIs(StreamID(1), PPID(1001), kShortPayload))); + + // Receive a reset request for ALL streams (`stream_ids = {}`) with + // `sender_last_assigned_tsn = 11`. Since TSN 11 has not arrived yet, this + // enters deferred reset processing. + Parameters::Builder builder; + builder.Add(OutgoingSSNResetRequestParameter( + ReconfigRequestSN(10), ReconfigRequestSN(3), TSN(11), {})); + EXPECT_THAT(HandleAndCatchResponse(ReConfigChunk(builder.Build())), + ElementsAre(Property(&ReconfigurationResponseParameter::result, + ResponseResult::kInProgress))); + + // Post-reset message TSN 12 (SSN 0) arrives BEFORE TSN 11. Because it has + // TSN > 11, it must be deferred until the stream reset is performed. + data_tracker_->Observe(TSN(12)); + reasm_->Add(TSN(12), gen_.Ordered({1, 2, 3, 4}, "BE", + {.stream_id = StreamID(1), + .mid = MID(0), + .ppid = PPID(1003)})); + EXPECT_FALSE(reasm_->HasMessages()); + + // Now the delayed pre-reset TSN 11 (SSN 1) arrives and is delivered. + data_tracker_->Observe(TSN(11)); + reasm_->Add(TSN(11), gen_.Ordered({1, 2, 3, 4}, "BE", + {.stream_id = StreamID(1), + .mid = MID(1), + .ppid = PPID(1002)})); + EXPECT_THAT(reasm_->GetNextMessage(), + Optional(SctpMessageIs(StreamID(1), PPID(1002), kShortPayload))); + + // Peer retransmits the reset request now that TSN 11 has been received. + builder.Add(OutgoingSSNResetRequestParameter( + ReconfigRequestSN(10), ReconfigRequestSN(3), TSN(11), {})); + EXPECT_CALL(callbacks_, OnIncomingStreamsReset(IsEmpty())); + EXPECT_THAT(HandleAndCatchResponse(ReConfigChunk(builder.Build())), + ElementsAre(Property(&ReconfigurationResponseParameter::result, + ResponseResult::kSuccessPerformed))); + + // The deferred post-reset message (TSN 12, SSN 0) should now be reassembled + // and delivered. + EXPECT_THAT(reasm_->GetNextMessage(), + Optional(SctpMessageIs(StreamID(1), PPID(1003), kShortPayload))); + EXPECT_FALSE(reasm_->HasMessages()); +} + TEST_F(StreamResetHandlerTest, ResetStreamsDefersForwardTsn) { // This test verifies that FORWARD-TSNs are deferred if they want to move // the cumulative ack TSN point past sender's last assigned TSN.