Re: [PATCH net 1/1] sctp: stream: rebind out_curr when updating streams
Xin Long <[email protected]> Wed, 27 May 2026 17:53:12 -0400
| Newsgroups | org.kernel.vger.linux-sctp,org.kernel.vger.netdev |
|---|---|
| Message-ID | <CADvbK_eOSCO6760yYbSVyn7eCo5a78jMjMomocbR+z4Nqcd=6g@mail.gmail.com> |
On Wed, May 27, 2026 at 1:28 AM Ren Wei <[email protected]> wrote: > > From: Yuqi Xu <[email protected]> > > sctp_stream_update() replaces the outbound stream table while > out_curr may still point to the current stream selected for an > unfinished fragmented message. > > Remember the current stream id before freeing the old table and > rebind out_curr after the new table is installed. If that stream > no longer exists, clear the cached pointer instead. > > This keeps the scheduler cursor valid across stream table > replacement without losing the current stream when it still > survives the update. > > Fixes: 5bbbbe32a431 ("sctp: introduce stream scheduler foundations") > Cc: [email protected] > Reported-by: Yuan Tan <[email protected]> > Reported-by: Yifan Wu <[email protected]> > Reported-by: Juefei Pu <[email protected]> > Reported-by: Zhengchuan Liang <[email protected]> > Reported-by: Xin Liu <[email protected]> > Assisted-by: Codex:GPT-5.4 > Signed-off-by: Yuqi Xu <[email protected]> > Signed-off-by: Ren Wei <[email protected]> > --- > net/sctp/stream.c | 11 +++++++++++ > 1 file changed, 11 insertions(+) > > diff --git a/net/sctp/stream.c b/net/sctp/stream.c > index c2247793c88b..fcb6c688f61d 100644 > --- a/net/sctp/stream.c > +++ b/net/sctp/stream.c > @@ -208,6 +208,16 @@ void sctp_stream_clear(struct sctp_stream *stream) > void sctp_stream_update(struct sctp_stream *stream, struct sctp_stream *new) > { > const struct sctp_sched_ops *sched = sctp_sched_ops_from_stream(stream); > + __u16 sid = SCTP_MAX_STREAM; > + > + /* Preserve the current stream if its sid survives the table swap. */ > + if (stream->out_curr) { > + for (sid = 0; sid < stream->outcnt; sid++) > + if (SCTP_SO(stream, sid) == stream->out_curr) > + break; > + if (sid == stream->outcnt) > + sid = SCTP_MAX_STREAM; > + } > > sched->unsched_all(stream); > sctp_stream_outq_migrate(stream, new, new->outcnt); > @@ -217,6 +227,7 @@ void sctp_stream_update(struct sctp_stream *stream, struct sctp_stream *new) > stream->in = new->in; > stream->outcnt = new->outcnt; > stream->incnt = new->incnt; > + stream->out_curr = sid < stream->outcnt ? SCTP_SO(stream, sid) : NULL; > > sched->sched_all(stream); > Thanks for the report and patch. sctp_stream_update() is only called in COOKIE_WAIT state, where stream->out_curr is expected to be NULL, since no user data should have been sent at or before this state unless the state transitioned backward. However, there is a corner case in sctp_sf_do_5_2_6_stale(): when a Stale Cookie ERROR is received, the association may move from COOKIE_ECHOED back to COOKIE_WAIT. If data was already bundled with COOKIE-ECHO to send out, this issue can be triggered. Updating stream->out_curr here is not a proper fix here, as any transmitted data would also remain in the retransmit queue. Since this restarts the handshake, negotiated parameters may change, so previously queued/sent data should be dropped. So you can fix it by purging the outqueue in sctp_sf_do_5_2_6_stale() like: diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 8e89a870780c..9b23c11cbb9e 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -2598,11 +2598,7 @@ static enum sctp_disposition sctp_sf_do_5_2_6_stale( */ sctp_add_cmd_sf(commands, SCTP_CMD_DEL_NON_PRIMARY, SCTP_NULL()); - /* If we've sent any data bundled with COOKIE-ECHO we will need to - * resend - */ - sctp_add_cmd_sf(commands, SCTP_CMD_T1_RETRAN, - SCTP_TRANSPORT(asoc->peer.primary_path)); + sctp_add_cmd_sf(commands, SCTP_CMD_PURGE_OUTQUEUE, SCTP_NULL()); /* Cast away the const modifier, as we want to just * rerun it through as a sideffect. The userspace would rely on SCTP_SEND_FAILED_EVENT to get notified. Thanks.