aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXin Long <lucien.xin@gmail.com>2017-11-25 08:05:33 -0500
committerDavid S. Miller <davem@davemloft.net>2017-11-27 10:38:45 -0500
commitd570a59c5b5f8fb3b65fa7b15ddb205a1d55f8d0 (patch)
tree05de6eecbd673697e82e6dbaa6fd256384a8cb3d
parent3aa623da789ff6edf789b5655debf33f50b3a9b2 (diff)
sctp: only allow the out stream reset when the stream outq is empty
Now the out stream reset in sctp stream reconf could be done even if the stream outq is not empty. It means that users can not be sure since which msg the new ssn will be used. To make this more synchronous, it shouldn't allow to do out stream reset until these chunks in unsent outq all are sent out. This patch checks the corresponding stream outqs when sending and processing the request . If any of them has unsent chunks in outq, it will return -EAGAIN instead or send SCTP_STRRESET_IN_PROGRESS back to the sender. Fixes: 7f9d68ac944e ("sctp: implement sender-side procedures for SSN Reset Request Parameter") Suggested-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> Signed-off-by: Xin Long <lucien.xin@gmail.com> Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/sctp/stream.c35
1 files changed, 35 insertions, 0 deletions
diff --git a/net/sctp/stream.c b/net/sctp/stream.c
index 09c797a10aaa..b20903712d67 100644
--- a/net/sctp/stream.c
+++ b/net/sctp/stream.c
@@ -254,6 +254,30 @@ static int sctp_send_reconf(struct sctp_association *asoc,
254 return retval; 254 return retval;
255} 255}
256 256
257static bool sctp_stream_outq_is_empty(struct sctp_stream *stream,
258 __u16 str_nums, __be16 *str_list)
259{
260 struct sctp_association *asoc;
261 __u16 i;
262
263 asoc = container_of(stream, struct sctp_association, stream);
264 if (!asoc->outqueue.out_qlen)
265 return true;
266
267 if (!str_nums)
268 return false;
269
270 for (i = 0; i < str_nums; i++) {
271 __u16 sid = ntohs(str_list[i]);
272
273 if (stream->out[sid].ext &&
274 !list_empty(&stream->out[sid].ext->outq))
275 return false;
276 }
277
278 return true;
279}
280
257int sctp_send_reset_streams(struct sctp_association *asoc, 281int sctp_send_reset_streams(struct sctp_association *asoc,
258 struct sctp_reset_streams *params) 282 struct sctp_reset_streams *params)
259{ 283{
@@ -317,6 +341,11 @@ int sctp_send_reset_streams(struct sctp_association *asoc,
317 for (i = 0; i < str_nums; i++) 341 for (i = 0; i < str_nums; i++)
318 nstr_list[i] = htons(str_list[i]); 342 nstr_list[i] = htons(str_list[i]);
319 343
344 if (out && !sctp_stream_outq_is_empty(stream, str_nums, nstr_list)) {
345 retval = -EAGAIN;
346 goto out;
347 }
348
320 chunk = sctp_make_strreset_req(asoc, str_nums, nstr_list, out, in); 349 chunk = sctp_make_strreset_req(asoc, str_nums, nstr_list, out, in);
321 350
322 kfree(nstr_list); 351 kfree(nstr_list);
@@ -636,6 +665,12 @@ struct sctp_chunk *sctp_process_strreset_inreq(
636 } 665 }
637 } 666 }
638 667
668 if (!sctp_stream_outq_is_empty(stream, nums, str_p)) {
669 result = SCTP_STRRESET_IN_PROGRESS;
670 asoc->strreset_inseq--;
671 goto err;
672 }
673
639 chunk = sctp_make_strreset_req(asoc, nums, str_p, 1, 0); 674 chunk = sctp_make_strreset_req(asoc, nums, str_p, 1, 0);
640 if (!chunk) 675 if (!chunk)
641 goto out; 676 goto out;