~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/sctp/stream.c

Version: ~ [ linux-5.8-rc4 ] ~ [ linux-5.7.7 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.50 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.131 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.187 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.229 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.229 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-or-later
  2 /* SCTP kernel implementation
  3  * (C) Copyright IBM Corp. 2001, 2004
  4  * Copyright (c) 1999-2000 Cisco, Inc.
  5  * Copyright (c) 1999-2001 Motorola, Inc.
  6  * Copyright (c) 2001 Intel Corp.
  7  *
  8  * This file is part of the SCTP kernel implementation
  9  *
 10  * This file contains sctp stream maniuplation primitives and helpers.
 11  *
 12  * Please send any bug reports or fixes you make to the
 13  * email address(es):
 14  *    lksctp developers <linux-sctp@vger.kernel.org>
 15  *
 16  * Written or modified by:
 17  *    Xin Long <lucien.xin@gmail.com>
 18  */
 19 
 20 #include <linux/list.h>
 21 #include <net/sctp/sctp.h>
 22 #include <net/sctp/sm.h>
 23 #include <net/sctp/stream_sched.h>
 24 
 25 /* Migrates chunks from stream queues to new stream queues if needed,
 26  * but not across associations. Also, removes those chunks to streams
 27  * higher than the new max.
 28  */
 29 static void sctp_stream_outq_migrate(struct sctp_stream *stream,
 30                                      struct sctp_stream *new, __u16 outcnt)
 31 {
 32         struct sctp_association *asoc;
 33         struct sctp_chunk *ch, *temp;
 34         struct sctp_outq *outq;
 35         int i;
 36 
 37         asoc = container_of(stream, struct sctp_association, stream);
 38         outq = &asoc->outqueue;
 39 
 40         list_for_each_entry_safe(ch, temp, &outq->out_chunk_list, list) {
 41                 __u16 sid = sctp_chunk_stream_no(ch);
 42 
 43                 if (sid < outcnt)
 44                         continue;
 45 
 46                 sctp_sched_dequeue_common(outq, ch);
 47                 /* No need to call dequeue_done here because
 48                  * the chunks are not scheduled by now.
 49                  */
 50 
 51                 /* Mark as failed send. */
 52                 sctp_chunk_fail(ch, (__force __u32)SCTP_ERROR_INV_STRM);
 53                 if (asoc->peer.prsctp_capable &&
 54                     SCTP_PR_PRIO_ENABLED(ch->sinfo.sinfo_flags))
 55                         asoc->sent_cnt_removable--;
 56 
 57                 sctp_chunk_free(ch);
 58         }
 59 
 60         if (new) {
 61                 /* Here we actually move the old ext stuff into the new
 62                  * buffer, because we want to keep it. Then
 63                  * sctp_stream_update will swap ->out pointers.
 64                  */
 65                 for (i = 0; i < outcnt; i++) {
 66                         kfree(SCTP_SO(new, i)->ext);
 67                         SCTP_SO(new, i)->ext = SCTP_SO(stream, i)->ext;
 68                         SCTP_SO(stream, i)->ext = NULL;
 69                 }
 70         }
 71 
 72         for (i = outcnt; i < stream->outcnt; i++) {
 73                 kfree(SCTP_SO(stream, i)->ext);
 74                 SCTP_SO(stream, i)->ext = NULL;
 75         }
 76 }
 77 
 78 static int sctp_stream_alloc_out(struct sctp_stream *stream, __u16 outcnt,
 79                                  gfp_t gfp)
 80 {
 81         int ret;
 82 
 83         if (outcnt <= stream->outcnt)
 84                 return 0;
 85 
 86         ret = genradix_prealloc(&stream->out, outcnt, gfp);
 87         if (ret)
 88                 return ret;
 89 
 90         stream->outcnt = outcnt;
 91         return 0;
 92 }
 93 
 94 static int sctp_stream_alloc_in(struct sctp_stream *stream, __u16 incnt,
 95                                 gfp_t gfp)
 96 {
 97         int ret;
 98 
 99         if (incnt <= stream->incnt)
100                 return 0;
101 
102         ret = genradix_prealloc(&stream->in, incnt, gfp);
103         if (ret)
104                 return ret;
105 
106         stream->incnt = incnt;
107         return 0;
108 }
109 
110 int sctp_stream_init(struct sctp_stream *stream, __u16 outcnt, __u16 incnt,
111                      gfp_t gfp)
112 {
113         struct sctp_sched_ops *sched = sctp_sched_ops_from_stream(stream);
114         int i, ret = 0;
115 
116         gfp |= __GFP_NOWARN;
117 
118         /* Initial stream->out size may be very big, so free it and alloc
119          * a new one with new outcnt to save memory if needed.
120          */
121         if (outcnt == stream->outcnt)
122                 goto in;
123 
124         /* Filter out chunks queued on streams that won't exist anymore */
125         sched->unsched_all(stream);
126         sctp_stream_outq_migrate(stream, NULL, outcnt);
127         sched->sched_all(stream);
128 
129         ret = sctp_stream_alloc_out(stream, outcnt, gfp);
130         if (ret)
131                 goto out;
132 
133         for (i = 0; i < stream->outcnt; i++)
134                 SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
135 
136 in:
137         sctp_stream_interleave_init(stream);
138         if (!incnt)
139                 goto out;
140 
141         ret = sctp_stream_alloc_in(stream, incnt, gfp);
142         if (ret) {
143                 sched->free(stream);
144                 genradix_free(&stream->out);
145                 stream->outcnt = 0;
146                 goto out;
147         }
148 
149 out:
150         return ret;
151 }
152 
153 int sctp_stream_init_ext(struct sctp_stream *stream, __u16 sid)
154 {
155         struct sctp_stream_out_ext *soute;
156         int ret;
157 
158         soute = kzalloc(sizeof(*soute), GFP_KERNEL);
159         if (!soute)
160                 return -ENOMEM;
161         SCTP_SO(stream, sid)->ext = soute;
162 
163         ret = sctp_sched_init_sid(stream, sid, GFP_KERNEL);
164         if (ret) {
165                 kfree(SCTP_SO(stream, sid)->ext);
166                 SCTP_SO(stream, sid)->ext = NULL;
167         }
168 
169         return ret;
170 }
171 
172 void sctp_stream_free(struct sctp_stream *stream)
173 {
174         struct sctp_sched_ops *sched = sctp_sched_ops_from_stream(stream);
175         int i;
176 
177         sched->free(stream);
178         for (i = 0; i < stream->outcnt; i++)
179                 kfree(SCTP_SO(stream, i)->ext);
180         genradix_free(&stream->out);
181         genradix_free(&stream->in);
182 }
183 
184 void sctp_stream_clear(struct sctp_stream *stream)
185 {
186         int i;
187 
188         for (i = 0; i < stream->outcnt; i++) {
189                 SCTP_SO(stream, i)->mid = 0;
190                 SCTP_SO(stream, i)->mid_uo = 0;
191         }
192 
193         for (i = 0; i < stream->incnt; i++)
194                 SCTP_SI(stream, i)->mid = 0;
195 }
196 
197 void sctp_stream_update(struct sctp_stream *stream, struct sctp_stream *new)
198 {
199         struct sctp_sched_ops *sched = sctp_sched_ops_from_stream(stream);
200 
201         sched->unsched_all(stream);
202         sctp_stream_outq_migrate(stream, new, new->outcnt);
203         sctp_stream_free(stream);
204 
205         stream->out = new->out;
206         stream->in  = new->in;
207         stream->outcnt = new->outcnt;
208         stream->incnt  = new->incnt;
209 
210         sched->sched_all(stream);
211 
212         new->out.tree.root = NULL;
213         new->in.tree.root  = NULL;
214         new->outcnt = 0;
215         new->incnt  = 0;
216 }
217 
218 static int sctp_send_reconf(struct sctp_association *asoc,
219                             struct sctp_chunk *chunk)
220 {
221         struct net *net = sock_net(asoc->base.sk);
222         int retval = 0;
223 
224         retval = sctp_primitive_RECONF(net, asoc, chunk);
225         if (retval)
226                 sctp_chunk_free(chunk);
227 
228         return retval;
229 }
230 
231 static bool sctp_stream_outq_is_empty(struct sctp_stream *stream,
232                                       __u16 str_nums, __be16 *str_list)
233 {
234         struct sctp_association *asoc;
235         __u16 i;
236 
237         asoc = container_of(stream, struct sctp_association, stream);
238         if (!asoc->outqueue.out_qlen)
239                 return true;
240 
241         if (!str_nums)
242                 return false;
243 
244         for (i = 0; i < str_nums; i++) {
245                 __u16 sid = ntohs(str_list[i]);
246 
247                 if (SCTP_SO(stream, sid)->ext &&
248                     !list_empty(&SCTP_SO(stream, sid)->ext->outq))
249                         return false;
250         }
251 
252         return true;
253 }
254 
255 int sctp_send_reset_streams(struct sctp_association *asoc,
256                             struct sctp_reset_streams *params)
257 {
258         struct sctp_stream *stream = &asoc->stream;
259         __u16 i, str_nums, *str_list;
260         struct sctp_chunk *chunk;
261         int retval = -EINVAL;
262         __be16 *nstr_list;
263         bool out, in;
264 
265         if (!asoc->peer.reconf_capable ||
266             !(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ)) {
267                 retval = -ENOPROTOOPT;
268                 goto out;
269         }
270 
271         if (asoc->strreset_outstanding) {
272                 retval = -EINPROGRESS;
273                 goto out;
274         }
275 
276         out = params->srs_flags & SCTP_STREAM_RESET_OUTGOING;
277         in  = params->srs_flags & SCTP_STREAM_RESET_INCOMING;
278         if (!out && !in)
279                 goto out;
280 
281         str_nums = params->srs_number_streams;
282         str_list = params->srs_stream_list;
283         if (str_nums) {
284                 int param_len = 0;
285 
286                 if (out) {
287                         for (i = 0; i < str_nums; i++)
288                                 if (str_list[i] >= stream->outcnt)
289                                         goto out;
290 
291                         param_len = str_nums * sizeof(__u16) +
292                                     sizeof(struct sctp_strreset_outreq);
293                 }
294 
295                 if (in) {
296                         for (i = 0; i < str_nums; i++)
297                                 if (str_list[i] >= stream->incnt)
298                                         goto out;
299 
300                         param_len += str_nums * sizeof(__u16) +
301                                      sizeof(struct sctp_strreset_inreq);
302                 }
303 
304                 if (param_len > SCTP_MAX_CHUNK_LEN -
305                                 sizeof(struct sctp_reconf_chunk))
306                         goto out;
307         }
308 
309         nstr_list = kcalloc(str_nums, sizeof(__be16), GFP_KERNEL);
310         if (!nstr_list) {
311                 retval = -ENOMEM;
312                 goto out;
313         }
314 
315         for (i = 0; i < str_nums; i++)
316                 nstr_list[i] = htons(str_list[i]);
317 
318         if (out && !sctp_stream_outq_is_empty(stream, str_nums, nstr_list)) {
319                 kfree(nstr_list);
320                 retval = -EAGAIN;
321                 goto out;
322         }
323 
324         chunk = sctp_make_strreset_req(asoc, str_nums, nstr_list, out, in);
325 
326         kfree(nstr_list);
327 
328         if (!chunk) {
329                 retval = -ENOMEM;
330                 goto out;
331         }
332 
333         if (out) {
334                 if (str_nums)
335                         for (i = 0; i < str_nums; i++)
336                                 SCTP_SO(stream, str_list[i])->state =
337                                                        SCTP_STREAM_CLOSED;
338                 else
339                         for (i = 0; i < stream->outcnt; i++)
340                                 SCTP_SO(stream, i)->state = SCTP_STREAM_CLOSED;
341         }
342 
343         asoc->strreset_chunk = chunk;
344         sctp_chunk_hold(asoc->strreset_chunk);
345 
346         retval = sctp_send_reconf(asoc, chunk);
347         if (retval) {
348                 sctp_chunk_put(asoc->strreset_chunk);
349                 asoc->strreset_chunk = NULL;
350                 if (!out)
351                         goto out;
352 
353                 if (str_nums)
354                         for (i = 0; i < str_nums; i++)
355                                 SCTP_SO(stream, str_list[i])->state =
356                                                        SCTP_STREAM_OPEN;
357                 else
358                         for (i = 0; i < stream->outcnt; i++)
359                                 SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
360 
361                 goto out;
362         }
363 
364         asoc->strreset_outstanding = out + in;
365 
366 out:
367         return retval;
368 }
369 
370 int sctp_send_reset_assoc(struct sctp_association *asoc)
371 {
372         struct sctp_stream *stream = &asoc->stream;
373         struct sctp_chunk *chunk = NULL;
374         int retval;
375         __u16 i;
376 
377         if (!asoc->peer.reconf_capable ||
378             !(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ))
379                 return -ENOPROTOOPT;
380 
381         if (asoc->strreset_outstanding)
382                 return -EINPROGRESS;
383 
384         if (!sctp_outq_is_empty(&asoc->outqueue))
385                 return -EAGAIN;
386 
387         chunk = sctp_make_strreset_tsnreq(asoc);
388         if (!chunk)
389                 return -ENOMEM;
390 
391         /* Block further xmit of data until this request is completed */
392         for (i = 0; i < stream->outcnt; i++)
393                 SCTP_SO(stream, i)->state = SCTP_STREAM_CLOSED;
394 
395         asoc->strreset_chunk = chunk;
396         sctp_chunk_hold(asoc->strreset_chunk);
397 
398         retval = sctp_send_reconf(asoc, chunk);
399         if (retval) {
400                 sctp_chunk_put(asoc->strreset_chunk);
401                 asoc->strreset_chunk = NULL;
402 
403                 for (i = 0; i < stream->outcnt; i++)
404                         SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
405 
406                 return retval;
407         }
408 
409         asoc->strreset_outstanding = 1;
410 
411         return 0;
412 }
413 
414 int sctp_send_add_streams(struct sctp_association *asoc,
415                           struct sctp_add_streams *params)
416 {
417         struct sctp_stream *stream = &asoc->stream;
418         struct sctp_chunk *chunk = NULL;
419         int retval;
420         __u32 outcnt, incnt;
421         __u16 out, in;
422 
423         if (!asoc->peer.reconf_capable ||
424             !(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ)) {
425                 retval = -ENOPROTOOPT;
426                 goto out;
427         }
428 
429         if (asoc->strreset_outstanding) {
430                 retval = -EINPROGRESS;
431                 goto out;
432         }
433 
434         out = params->sas_outstrms;
435         in  = params->sas_instrms;
436         outcnt = stream->outcnt + out;
437         incnt = stream->incnt + in;
438         if (outcnt > SCTP_MAX_STREAM || incnt > SCTP_MAX_STREAM ||
439             (!out && !in)) {
440                 retval = -EINVAL;
441                 goto out;
442         }
443 
444         if (out) {
445                 retval = sctp_stream_alloc_out(stream, outcnt, GFP_KERNEL);
446                 if (retval)
447                         goto out;
448         }
449 
450         chunk = sctp_make_strreset_addstrm(asoc, out, in);
451         if (!chunk) {
452                 retval = -ENOMEM;
453                 goto out;
454         }
455 
456         asoc->strreset_chunk = chunk;
457         sctp_chunk_hold(asoc->strreset_chunk);
458 
459         retval = sctp_send_reconf(asoc, chunk);
460         if (retval) {
461                 sctp_chunk_put(asoc->strreset_chunk);
462                 asoc->strreset_chunk = NULL;
463                 goto out;
464         }
465 
466         asoc->strreset_outstanding = !!out + !!in;
467 
468 out:
469         return retval;
470 }
471 
472 static struct sctp_paramhdr *sctp_chunk_lookup_strreset_param(
473                         struct sctp_association *asoc, __be32 resp_seq,
474                         __be16 type)
475 {
476         struct sctp_chunk *chunk = asoc->strreset_chunk;
477         struct sctp_reconf_chunk *hdr;
478         union sctp_params param;
479 
480         if (!chunk)
481                 return NULL;
482 
483         hdr = (struct sctp_reconf_chunk *)chunk->chunk_hdr;
484         sctp_walk_params(param, hdr, params) {
485                 /* sctp_strreset_tsnreq is actually the basic structure
486                  * of all stream reconf params, so it's safe to use it
487                  * to access request_seq.
488                  */
489                 struct sctp_strreset_tsnreq *req = param.v;
490 
491                 if ((!resp_seq || req->request_seq == resp_seq) &&
492                     (!type || type == req->param_hdr.type))
493                         return param.v;
494         }
495 
496         return NULL;
497 }
498 
499 static void sctp_update_strreset_result(struct sctp_association *asoc,
500                                         __u32 result)
501 {
502         asoc->strreset_result[1] = asoc->strreset_result[0];
503         asoc->strreset_result[0] = result;
504 }
505 
506 struct sctp_chunk *sctp_process_strreset_outreq(
507                                 struct sctp_association *asoc,
508                                 union sctp_params param,
509                                 struct sctp_ulpevent **evp)
510 {
511         struct sctp_strreset_outreq *outreq = param.v;
512         struct sctp_stream *stream = &asoc->stream;
513         __u32 result = SCTP_STRRESET_DENIED;
514         __be16 *str_p = NULL;
515         __u32 request_seq;
516         __u16 i, nums;
517 
518         request_seq = ntohl(outreq->request_seq);
519 
520         if (ntohl(outreq->send_reset_at_tsn) >
521             sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map)) {
522                 result = SCTP_STRRESET_IN_PROGRESS;
523                 goto err;
524         }
525 
526         if (TSN_lt(asoc->strreset_inseq, request_seq) ||
527             TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
528                 result = SCTP_STRRESET_ERR_BAD_SEQNO;
529                 goto err;
530         } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
531                 i = asoc->strreset_inseq - request_seq - 1;
532                 result = asoc->strreset_result[i];
533                 goto err;
534         }
535         asoc->strreset_inseq++;
536 
537         /* Check strreset_enable after inseq inc, as sender cannot tell
538          * the peer doesn't enable strreset after receiving response with
539          * result denied, as well as to keep consistent with bsd.
540          */
541         if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ))
542                 goto out;
543 
544         nums = (ntohs(param.p->length) - sizeof(*outreq)) / sizeof(__u16);
545         str_p = outreq->list_of_streams;
546         for (i = 0; i < nums; i++) {
547                 if (ntohs(str_p[i]) >= stream->incnt) {
548                         result = SCTP_STRRESET_ERR_WRONG_SSN;
549                         goto out;
550                 }
551         }
552 
553         if (asoc->strreset_chunk) {
554                 if (!sctp_chunk_lookup_strreset_param(
555                                 asoc, outreq->response_seq,
556                                 SCTP_PARAM_RESET_IN_REQUEST)) {
557                         /* same process with outstanding isn't 0 */
558                         result = SCTP_STRRESET_ERR_IN_PROGRESS;
559                         goto out;
560                 }
561 
562                 asoc->strreset_outstanding--;
563                 asoc->strreset_outseq++;
564 
565                 if (!asoc->strreset_outstanding) {
566                         struct sctp_transport *t;
567 
568                         t = asoc->strreset_chunk->transport;
569                         if (del_timer(&t->reconf_timer))
570                                 sctp_transport_put(t);
571 
572                         sctp_chunk_put(asoc->strreset_chunk);
573                         asoc->strreset_chunk = NULL;
574                 }
575         }
576 
577         if (nums)
578                 for (i = 0; i < nums; i++)
579                         SCTP_SI(stream, ntohs(str_p[i]))->mid = 0;
580         else
581                 for (i = 0; i < stream->incnt; i++)
582                         SCTP_SI(stream, i)->mid = 0;
583 
584         result = SCTP_STRRESET_PERFORMED;
585 
586         *evp = sctp_ulpevent_make_stream_reset_event(asoc,
587                 SCTP_STREAM_RESET_INCOMING_SSN, nums, str_p, GFP_ATOMIC);
588 
589 out:
590         sctp_update_strreset_result(asoc, result);
591 err:
592         return sctp_make_strreset_resp(asoc, result, request_seq);
593 }
594 
595 struct sctp_chunk *sctp_process_strreset_inreq(
596                                 struct sctp_association *asoc,
597                                 union sctp_params param,
598                                 struct sctp_ulpevent **evp)
599 {
600         struct sctp_strreset_inreq *inreq = param.v;
601         struct sctp_stream *stream = &asoc->stream;
602         __u32 result = SCTP_STRRESET_DENIED;
603         struct sctp_chunk *chunk = NULL;
604         __u32 request_seq;
605         __u16 i, nums;
606         __be16 *str_p;
607 
608         request_seq = ntohl(inreq->request_seq);
609         if (TSN_lt(asoc->strreset_inseq, request_seq) ||
610             TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
611                 result = SCTP_STRRESET_ERR_BAD_SEQNO;
612                 goto err;
613         } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
614                 i = asoc->strreset_inseq - request_seq - 1;
615                 result = asoc->strreset_result[i];
616                 if (result == SCTP_STRRESET_PERFORMED)
617                         return NULL;
618                 goto err;
619         }
620         asoc->strreset_inseq++;
621 
622         if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ))
623                 goto out;
624 
625         if (asoc->strreset_outstanding) {
626                 result = SCTP_STRRESET_ERR_IN_PROGRESS;
627                 goto out;
628         }
629 
630         nums = (ntohs(param.p->length) - sizeof(*inreq)) / sizeof(__u16);
631         str_p = inreq->list_of_streams;
632         for (i = 0; i < nums; i++) {
633                 if (ntohs(str_p[i]) >= stream->outcnt) {
634                         result = SCTP_STRRESET_ERR_WRONG_SSN;
635                         goto out;
636                 }
637         }
638 
639         if (!sctp_stream_outq_is_empty(stream, nums, str_p)) {
640                 result = SCTP_STRRESET_IN_PROGRESS;
641                 asoc->strreset_inseq--;
642                 goto err;
643         }
644 
645         chunk = sctp_make_strreset_req(asoc, nums, str_p, 1, 0);
646         if (!chunk)
647                 goto out;
648 
649         if (nums)
650                 for (i = 0; i < nums; i++)
651                         SCTP_SO(stream, ntohs(str_p[i]))->state =
652                                                SCTP_STREAM_CLOSED;
653         else
654                 for (i = 0; i < stream->outcnt; i++)
655                         SCTP_SO(stream, i)->state = SCTP_STREAM_CLOSED;
656 
657         asoc->strreset_chunk = chunk;
658         asoc->strreset_outstanding = 1;
659         sctp_chunk_hold(asoc->strreset_chunk);
660 
661         result = SCTP_STRRESET_PERFORMED;
662 
663 out:
664         sctp_update_strreset_result(asoc, result);
665 err:
666         if (!chunk)
667                 chunk =  sctp_make_strreset_resp(asoc, result, request_seq);
668 
669         return chunk;
670 }
671 
672 struct sctp_chunk *sctp_process_strreset_tsnreq(
673                                 struct sctp_association *asoc,
674                                 union sctp_params param,
675                                 struct sctp_ulpevent **evp)
676 {
677         __u32 init_tsn = 0, next_tsn = 0, max_tsn_seen;
678         struct sctp_strreset_tsnreq *tsnreq = param.v;
679         struct sctp_stream *stream = &asoc->stream;
680         __u32 result = SCTP_STRRESET_DENIED;
681         __u32 request_seq;
682         __u16 i;
683 
684         request_seq = ntohl(tsnreq->request_seq);
685         if (TSN_lt(asoc->strreset_inseq, request_seq) ||
686             TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
687                 result = SCTP_STRRESET_ERR_BAD_SEQNO;
688                 goto err;
689         } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
690                 i = asoc->strreset_inseq - request_seq - 1;
691                 result = asoc->strreset_result[i];
692                 if (result == SCTP_STRRESET_PERFORMED) {
693                         next_tsn = asoc->ctsn_ack_point + 1;
694                         init_tsn =
695                                 sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + 1;
696                 }
697                 goto err;
698         }
699 
700         if (!sctp_outq_is_empty(&asoc->outqueue)) {
701                 result = SCTP_STRRESET_IN_PROGRESS;
702                 goto err;
703         }
704 
705         asoc->strreset_inseq++;
706 
707         if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ))
708                 goto out;
709 
710         if (asoc->strreset_outstanding) {
711                 result = SCTP_STRRESET_ERR_IN_PROGRESS;
712                 goto out;
713         }
714 
715         /* G4: The same processing as though a FWD-TSN chunk (as defined in
716          *     [RFC3758]) with all streams affected and a new cumulative TSN
717          *     ACK of the Receiver's Next TSN minus 1 were received MUST be
718          *     performed.
719          */
720         max_tsn_seen = sctp_tsnmap_get_max_tsn_seen(&asoc->peer.tsn_map);
721         asoc->stream.si->report_ftsn(&asoc->ulpq, max_tsn_seen);
722 
723         /* G1: Compute an appropriate value for the Receiver's Next TSN -- the
724          *     TSN that the peer should use to send the next DATA chunk.  The
725          *     value SHOULD be the smallest TSN not acknowledged by the
726          *     receiver of the request plus 2^31.
727          */
728         init_tsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + (1 << 31);
729         sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL,
730                          init_tsn, GFP_ATOMIC);
731 
732         /* G3: The same processing as though a SACK chunk with no gap report
733          *     and a cumulative TSN ACK of the Sender's Next TSN minus 1 were
734          *     received MUST be performed.
735          */
736         sctp_outq_free(&asoc->outqueue);
737 
738         /* G2: Compute an appropriate value for the local endpoint's next TSN,
739          *     i.e., the next TSN assigned by the receiver of the SSN/TSN reset
740          *     chunk.  The value SHOULD be the highest TSN sent by the receiver
741          *     of the request plus 1.
742          */
743         next_tsn = asoc->next_tsn;
744         asoc->ctsn_ack_point = next_tsn - 1;
745         asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
746 
747         /* G5:  The next expected and outgoing SSNs MUST be reset to 0 for all
748          *      incoming and outgoing streams.
749          */
750         for (i = 0; i < stream->outcnt; i++) {
751                 SCTP_SO(stream, i)->mid = 0;
752                 SCTP_SO(stream, i)->mid_uo = 0;
753         }
754         for (i = 0; i < stream->incnt; i++)
755                 SCTP_SI(stream, i)->mid = 0;
756 
757         result = SCTP_STRRESET_PERFORMED;
758 
759         *evp = sctp_ulpevent_make_assoc_reset_event(asoc, 0, init_tsn,
760                                                     next_tsn, GFP_ATOMIC);
761 
762 out:
763         sctp_update_strreset_result(asoc, result);
764 err:
765         return sctp_make_strreset_tsnresp(asoc, result, request_seq,
766                                           next_tsn, init_tsn);
767 }
768 
769 struct sctp_chunk *sctp_process_strreset_addstrm_out(
770                                 struct sctp_association *asoc,
771                                 union sctp_params param,
772                                 struct sctp_ulpevent **evp)
773 {
774         struct sctp_strreset_addstrm *addstrm = param.v;
775         struct sctp_stream *stream = &asoc->stream;
776         __u32 result = SCTP_STRRESET_DENIED;
777         __u32 request_seq, incnt;
778         __u16 in, i;
779 
780         request_seq = ntohl(addstrm->request_seq);
781         if (TSN_lt(asoc->strreset_inseq, request_seq) ||
782             TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
783                 result = SCTP_STRRESET_ERR_BAD_SEQNO;
784                 goto err;
785         } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
786                 i = asoc->strreset_inseq - request_seq - 1;
787                 result = asoc->strreset_result[i];
788                 goto err;
789         }
790         asoc->strreset_inseq++;
791 
792         if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ))
793                 goto out;
794 
795         in = ntohs(addstrm->number_of_streams);
796         incnt = stream->incnt + in;
797         if (!in || incnt > SCTP_MAX_STREAM)
798                 goto out;
799 
800         if (sctp_stream_alloc_in(stream, incnt, GFP_ATOMIC))
801                 goto out;
802 
803         if (asoc->strreset_chunk) {
804                 if (!sctp_chunk_lookup_strreset_param(
805                         asoc, 0, SCTP_PARAM_RESET_ADD_IN_STREAMS)) {
806                         /* same process with outstanding isn't 0 */
807                         result = SCTP_STRRESET_ERR_IN_PROGRESS;
808                         goto out;
809                 }
810 
811                 asoc->strreset_outstanding--;
812                 asoc->strreset_outseq++;
813 
814                 if (!asoc->strreset_outstanding) {
815                         struct sctp_transport *t;
816 
817                         t = asoc->strreset_chunk->transport;
818                         if (del_timer(&t->reconf_timer))
819                                 sctp_transport_put(t);
820 
821                         sctp_chunk_put(asoc->strreset_chunk);
822                         asoc->strreset_chunk = NULL;
823                 }
824         }
825 
826         stream->incnt = incnt;
827 
828         result = SCTP_STRRESET_PERFORMED;
829 
830         *evp = sctp_ulpevent_make_stream_change_event(asoc,
831                 0, ntohs(addstrm->number_of_streams), 0, GFP_ATOMIC);
832 
833 out:
834         sctp_update_strreset_result(asoc, result);
835 err:
836         return sctp_make_strreset_resp(asoc, result, request_seq);
837 }
838 
839 struct sctp_chunk *sctp_process_strreset_addstrm_in(
840                                 struct sctp_association *asoc,
841                                 union sctp_params param,
842                                 struct sctp_ulpevent **evp)
843 {
844         struct sctp_strreset_addstrm *addstrm = param.v;
845         struct sctp_stream *stream = &asoc->stream;
846         __u32 result = SCTP_STRRESET_DENIED;
847         struct sctp_chunk *chunk = NULL;
848         __u32 request_seq, outcnt;
849         __u16 out, i;
850         int ret;
851 
852         request_seq = ntohl(addstrm->request_seq);
853         if (TSN_lt(asoc->strreset_inseq, request_seq) ||
854             TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
855                 result = SCTP_STRRESET_ERR_BAD_SEQNO;
856                 goto err;
857         } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
858                 i = asoc->strreset_inseq - request_seq - 1;
859                 result = asoc->strreset_result[i];
860                 if (result == SCTP_STRRESET_PERFORMED)
861                         return NULL;
862                 goto err;
863         }
864         asoc->strreset_inseq++;
865 
866         if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ))
867                 goto out;
868 
869         if (asoc->strreset_outstanding) {
870                 result = SCTP_STRRESET_ERR_IN_PROGRESS;
871                 goto out;
872         }
873 
874         out = ntohs(addstrm->number_of_streams);
875         outcnt = stream->outcnt + out;
876         if (!out || outcnt > SCTP_MAX_STREAM)
877                 goto out;
878 
879         ret = sctp_stream_alloc_out(stream, outcnt, GFP_ATOMIC);
880         if (ret)
881                 goto out;
882 
883         chunk = sctp_make_strreset_addstrm(asoc, out, 0);
884         if (!chunk)
885                 goto out;
886 
887         asoc->strreset_chunk = chunk;
888         asoc->strreset_outstanding = 1;
889         sctp_chunk_hold(asoc->strreset_chunk);
890 
891         stream->outcnt = outcnt;
892 
893         result = SCTP_STRRESET_PERFORMED;
894 
895 out:
896         sctp_update_strreset_result(asoc, result);
897 err:
898         if (!chunk)
899                 chunk = sctp_make_strreset_resp(asoc, result, request_seq);
900 
901         return chunk;
902 }
903 
904 struct sctp_chunk *sctp_process_strreset_resp(
905                                 struct sctp_association *asoc,
906                                 union sctp_params param,
907                                 struct sctp_ulpevent **evp)
908 {
909         struct sctp_stream *stream = &asoc->stream;
910         struct sctp_strreset_resp *resp = param.v;
911         struct sctp_transport *t;
912         __u16 i, nums, flags = 0;
913         struct sctp_paramhdr *req;
914         __u32 result;
915 
916         req = sctp_chunk_lookup_strreset_param(asoc, resp->response_seq, 0);
917         if (!req)
918                 return NULL;
919 
920         result = ntohl(resp->result);
921         if (result != SCTP_STRRESET_PERFORMED) {
922                 /* if in progress, do nothing but retransmit */
923                 if (result == SCTP_STRRESET_IN_PROGRESS)
924                         return NULL;
925                 else if (result == SCTP_STRRESET_DENIED)
926                         flags = SCTP_STREAM_RESET_DENIED;
927                 else
928                         flags = SCTP_STREAM_RESET_FAILED;
929         }
930 
931         if (req->type == SCTP_PARAM_RESET_OUT_REQUEST) {
932                 struct sctp_strreset_outreq *outreq;
933                 __be16 *str_p;
934 
935                 outreq = (struct sctp_strreset_outreq *)req;
936                 str_p = outreq->list_of_streams;
937                 nums = (ntohs(outreq->param_hdr.length) - sizeof(*outreq)) /
938                        sizeof(__u16);
939 
940                 if (result == SCTP_STRRESET_PERFORMED) {
941                         struct sctp_stream_out *sout;
942                         if (nums) {
943                                 for (i = 0; i < nums; i++) {
944                                         sout = SCTP_SO(stream, ntohs(str_p[i]));
945                                         sout->mid = 0;
946                                         sout->mid_uo = 0;
947                                 }
948                         } else {
949                                 for (i = 0; i < stream->outcnt; i++) {
950                                         sout = SCTP_SO(stream, i);
951                                         sout->mid = 0;
952                                         sout->mid_uo = 0;
953                                 }
954                         }
955                 }
956 
957                 flags |= SCTP_STREAM_RESET_OUTGOING_SSN;
958 
959                 for (i = 0; i < stream->outcnt; i++)
960                         SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
961 
962                 *evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
963                         nums, str_p, GFP_ATOMIC);
964         } else if (req->type == SCTP_PARAM_RESET_IN_REQUEST) {
965                 struct sctp_strreset_inreq *inreq;
966                 __be16 *str_p;
967 
968                 /* if the result is performed, it's impossible for inreq */
969                 if (result == SCTP_STRRESET_PERFORMED)
970                         return NULL;
971 
972                 inreq = (struct sctp_strreset_inreq *)req;
973                 str_p = inreq->list_of_streams;
974                 nums = (ntohs(inreq->param_hdr.length) - sizeof(*inreq)) /
975                        sizeof(__u16);
976 
977                 flags |= SCTP_STREAM_RESET_INCOMING_SSN;
978 
979                 *evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
980                         nums, str_p, GFP_ATOMIC);
981         } else if (req->type == SCTP_PARAM_RESET_TSN_REQUEST) {
982                 struct sctp_strreset_resptsn *resptsn;
983                 __u32 stsn, rtsn;
984 
985                 /* check for resptsn, as sctp_verify_reconf didn't do it*/
986                 if (ntohs(param.p->length) != sizeof(*resptsn))
987                         return NULL;
988 
989                 resptsn = (struct sctp_strreset_resptsn *)resp;
990                 stsn = ntohl(resptsn->senders_next_tsn);
991                 rtsn = ntohl(resptsn->receivers_next_tsn);
992 
993                 if (result == SCTP_STRRESET_PERFORMED) {
994                         __u32 mtsn = sctp_tsnmap_get_max_tsn_seen(
995                                                 &asoc->peer.tsn_map);
996                         LIST_HEAD(temp);
997 
998                         asoc->stream.si->report_ftsn(&asoc->ulpq, mtsn);
999 
1000                         sctp_tsnmap_init(&asoc->peer.tsn_map,
1001                                          SCTP_TSN_MAP_INITIAL,
1002                                          stsn, GFP_ATOMIC);
1003 
1004                         /* Clean up sacked and abandoned queues only. As the
1005                          * out_chunk_list may not be empty, splice it to temp,
1006                          * then get it back after sctp_outq_free is done.
1007                          */
1008                         list_splice_init(&asoc->outqueue.out_chunk_list, &temp);
1009                         sctp_outq_free(&asoc->outqueue);
1010                         list_splice_init(&temp, &asoc->outqueue.out_chunk_list);
1011 
1012                         asoc->next_tsn = rtsn;
1013                         asoc->ctsn_ack_point = asoc->next_tsn - 1;
1014                         asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
1015 
1016                         for (i = 0; i < stream->outcnt; i++) {
1017                                 SCTP_SO(stream, i)->mid = 0;
1018                                 SCTP_SO(stream, i)->mid_uo = 0;
1019                         }
1020                         for (i = 0; i < stream->incnt; i++)
1021                                 SCTP_SI(stream, i)->mid = 0;
1022                 }
1023 
1024                 for (i = 0; i < stream->outcnt; i++)
1025                         SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
1026 
1027                 *evp = sctp_ulpevent_make_assoc_reset_event(asoc, flags,
1028                         stsn, rtsn, GFP_ATOMIC);
1029         } else if (req->type == SCTP_PARAM_RESET_ADD_OUT_STREAMS) {
1030                 struct sctp_strreset_addstrm *addstrm;
1031                 __u16 number;
1032 
1033                 addstrm = (struct sctp_strreset_addstrm *)req;
1034                 nums = ntohs(addstrm->number_of_streams);
1035                 number = stream->outcnt - nums;
1036 
1037                 if (result == SCTP_STRRESET_PERFORMED)
1038                         for (i = number; i < stream->outcnt; i++)
1039                                 SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
1040                 else
1041                         stream->outcnt = number;
1042 
1043                 *evp = sctp_ulpevent_make_stream_change_event(asoc, flags,
1044                         0, nums, GFP_ATOMIC);
1045         } else if (req->type == SCTP_PARAM_RESET_ADD_IN_STREAMS) {
1046                 struct sctp_strreset_addstrm *addstrm;
1047 
1048                 /* if the result is performed, it's impossible for addstrm in
1049                  * request.
1050                  */
1051                 if (result == SCTP_STRRESET_PERFORMED)
1052                         return NULL;
1053 
1054                 addstrm = (struct sctp_strreset_addstrm *)req;
1055                 nums = ntohs(addstrm->number_of_streams);
1056 
1057                 *evp = sctp_ulpevent_make_stream_change_event(asoc, flags,
1058                         nums, 0, GFP_ATOMIC);
1059         }
1060 
1061         asoc->strreset_outstanding--;
1062         asoc->strreset_outseq++;
1063 
1064         /* remove everything for this reconf request */
1065         if (!asoc->strreset_outstanding) {
1066                 t = asoc->strreset_chunk->transport;
1067                 if (del_timer(&t->reconf_timer))
1068                         sctp_transport_put(t);
1069 
1070                 sctp_chunk_put(asoc->strreset_chunk);
1071                 asoc->strreset_chunk = NULL;
1072         }
1073 
1074         return NULL;
1075 }
1076 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp