Merge tag 'pm-5.2-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
[linux-block.git] / net / sctp / stream_interleave.c
CommitLineData
0c3f6f65
XL
1/* SCTP kernel implementation
2 * (C) Copyright Red Hat Inc. 2017
3 *
4 * This file is part of the SCTP kernel implementation
5 *
fae8b6f4
XL
6 * These functions implement sctp stream message interleaving, mostly
7 * including I-DATA and I-FORWARD-TSN chunks process.
0c3f6f65
XL
8 *
9 * This SCTP implementation is free software;
10 * you can redistribute it and/or modify it under the terms of
11 * the GNU General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
13 * any later version.
14 *
15 * This SCTP implementation is distributed in the hope that it
16 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
17 * ************************
18 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 * See the GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with GNU CC; see the file COPYING. If not, see
23 * <http://www.gnu.org/licenses/>.
24 *
25 * Please send any bug reports or fixes you make to the
26 * email addresched(es):
27 * lksctp developers <linux-sctp@vger.kernel.org>
28 *
29 * Written or modified by:
30 * Xin Long <lucien.xin@gmail.com>
31 */
32
bd4d627d 33#include <net/busy_poll.h>
0c3f6f65
XL
34#include <net/sctp/sctp.h>
35#include <net/sctp/sm.h>
bd4d627d 36#include <net/sctp/ulpevent.h>
0c3f6f65
XL
37#include <linux/sctp.h>
38
39static struct sctp_chunk *sctp_make_idatafrag_empty(
40 const struct sctp_association *asoc,
41 const struct sctp_sndrcvinfo *sinfo,
42 int len, __u8 flags, gfp_t gfp)
43{
44 struct sctp_chunk *retval;
45 struct sctp_idatahdr dp;
46
47 memset(&dp, 0, sizeof(dp));
48 dp.stream = htons(sinfo->sinfo_stream);
49
50 if (sinfo->sinfo_flags & SCTP_UNORDERED)
51 flags |= SCTP_DATA_UNORDERED;
52
53 retval = sctp_make_idata(asoc, flags, sizeof(dp) + len, gfp);
54 if (!retval)
55 return NULL;
56
57 retval->subh.idata_hdr = sctp_addto_chunk(retval, sizeof(dp), &dp);
58 memcpy(&retval->sinfo, sinfo, sizeof(struct sctp_sndrcvinfo));
59
60 return retval;
61}
62
668c9beb
XL
63static void sctp_chunk_assign_mid(struct sctp_chunk *chunk)
64{
65 struct sctp_stream *stream;
66 struct sctp_chunk *lchunk;
67 __u32 cfsn = 0;
68 __u16 sid;
69
70 if (chunk->has_mid)
71 return;
72
73 sid = sctp_chunk_stream_no(chunk);
74 stream = &chunk->asoc->stream;
75
76 list_for_each_entry(lchunk, &chunk->msg->chunks, frag_list) {
77 struct sctp_idatahdr *hdr;
13228238 78 __u32 mid;
668c9beb
XL
79
80 lchunk->has_mid = 1;
81
668c9beb
XL
82 hdr = lchunk->subh.idata_hdr;
83
84 if (lchunk->chunk_hdr->flags & SCTP_DATA_FIRST_FRAG)
85 hdr->ppid = lchunk->sinfo.sinfo_ppid;
86 else
87 hdr->fsn = htonl(cfsn++);
88
13228238
XL
89 if (lchunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) {
90 mid = lchunk->chunk_hdr->flags & SCTP_DATA_LAST_FRAG ?
91 sctp_mid_uo_next(stream, out, sid) :
92 sctp_mid_uo_peek(stream, out, sid);
93 } else {
94 mid = lchunk->chunk_hdr->flags & SCTP_DATA_LAST_FRAG ?
95 sctp_mid_next(stream, out, sid) :
96 sctp_mid_peek(stream, out, sid);
97 }
98 hdr->mid = htonl(mid);
668c9beb
XL
99 }
100}
101
9d4ceaf1
XL
102static bool sctp_validate_data(struct sctp_chunk *chunk)
103{
2075e50c 104 struct sctp_stream *stream;
9d4ceaf1
XL
105 __u16 sid, ssn;
106
107 if (chunk->chunk_hdr->type != SCTP_CID_DATA)
108 return false;
109
110 if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
111 return true;
112
113 stream = &chunk->asoc->stream;
114 sid = sctp_chunk_stream_no(chunk);
115 ssn = ntohs(chunk->subh.data_hdr->ssn);
116
117 return !SSN_lt(ssn, sctp_ssn_peek(stream, in, sid));
118}
119
120static bool sctp_validate_idata(struct sctp_chunk *chunk)
121{
122 struct sctp_stream *stream;
123 __u32 mid;
124 __u16 sid;
125
126 if (chunk->chunk_hdr->type != SCTP_CID_I_DATA)
127 return false;
128
129 if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
130 return true;
131
132 stream = &chunk->asoc->stream;
133 sid = sctp_chunk_stream_no(chunk);
134 mid = ntohl(chunk->subh.idata_hdr->mid);
135
136 return !MID_lt(mid, sctp_mid_peek(stream, in, sid));
137}
138
bd4d627d
XL
139static void sctp_intl_store_reasm(struct sctp_ulpq *ulpq,
140 struct sctp_ulpevent *event)
141{
142 struct sctp_ulpevent *cevent;
348bbc25 143 struct sk_buff *pos, *loc;
bd4d627d
XL
144
145 pos = skb_peek_tail(&ulpq->reasm);
146 if (!pos) {
147 __skb_queue_tail(&ulpq->reasm, sctp_event2skb(event));
148 return;
149 }
150
151 cevent = sctp_skb2event(pos);
152
153 if (event->stream == cevent->stream &&
154 event->mid == cevent->mid &&
155 (cevent->msg_flags & SCTP_DATA_FIRST_FRAG ||
156 (!(event->msg_flags & SCTP_DATA_FIRST_FRAG) &&
157 event->fsn > cevent->fsn))) {
158 __skb_queue_tail(&ulpq->reasm, sctp_event2skb(event));
159 return;
160 }
161
162 if ((event->stream == cevent->stream &&
163 MID_lt(cevent->mid, event->mid)) ||
164 event->stream > cevent->stream) {
165 __skb_queue_tail(&ulpq->reasm, sctp_event2skb(event));
166 return;
167 }
168
348bbc25 169 loc = NULL;
bd4d627d
XL
170 skb_queue_walk(&ulpq->reasm, pos) {
171 cevent = sctp_skb2event(pos);
172
173 if (event->stream < cevent->stream ||
174 (event->stream == cevent->stream &&
348bbc25
DM
175 MID_lt(event->mid, cevent->mid))) {
176 loc = pos;
bd4d627d 177 break;
348bbc25 178 }
bd4d627d
XL
179 if (event->stream == cevent->stream &&
180 event->mid == cevent->mid &&
181 !(cevent->msg_flags & SCTP_DATA_FIRST_FRAG) &&
182 (event->msg_flags & SCTP_DATA_FIRST_FRAG ||
348bbc25
DM
183 event->fsn < cevent->fsn)) {
184 loc = pos;
bd4d627d 185 break;
348bbc25 186 }
bd4d627d
XL
187 }
188
348bbc25
DM
189 if (!loc)
190 __skb_queue_tail(&ulpq->reasm, sctp_event2skb(event));
191 else
192 __skb_queue_before(&ulpq->reasm, loc, sctp_event2skb(event));
bd4d627d
XL
193}
194
195static struct sctp_ulpevent *sctp_intl_retrieve_partial(
196 struct sctp_ulpq *ulpq,
197 struct sctp_ulpevent *event)
198{
199 struct sk_buff *first_frag = NULL;
200 struct sk_buff *last_frag = NULL;
201 struct sctp_ulpevent *retval;
202 struct sctp_stream_in *sin;
203 struct sk_buff *pos;
204 __u32 next_fsn = 0;
205 int is_last = 0;
206
05364ca0 207 sin = sctp_stream_in(&ulpq->asoc->stream, event->stream);
bd4d627d
XL
208
209 skb_queue_walk(&ulpq->reasm, pos) {
210 struct sctp_ulpevent *cevent = sctp_skb2event(pos);
211
212 if (cevent->stream < event->stream)
213 continue;
214
215 if (cevent->stream > event->stream ||
216 cevent->mid != sin->mid)
217 break;
218
219 switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) {
220 case SCTP_DATA_FIRST_FRAG:
221 goto out;
222 case SCTP_DATA_MIDDLE_FRAG:
223 if (!first_frag) {
224 if (cevent->fsn == sin->fsn) {
225 first_frag = pos;
226 last_frag = pos;
227 next_fsn = cevent->fsn + 1;
228 }
229 } else if (cevent->fsn == next_fsn) {
230 last_frag = pos;
231 next_fsn++;
232 } else {
233 goto out;
234 }
235 break;
236 case SCTP_DATA_LAST_FRAG:
237 if (!first_frag) {
238 if (cevent->fsn == sin->fsn) {
239 first_frag = pos;
240 last_frag = pos;
241 next_fsn = 0;
242 is_last = 1;
243 }
244 } else if (cevent->fsn == next_fsn) {
245 last_frag = pos;
246 next_fsn = 0;
247 is_last = 1;
248 }
249 goto out;
250 default:
251 goto out;
252 }
253 }
254
255out:
256 if (!first_frag)
257 return NULL;
258
259 retval = sctp_make_reassembled_event(sock_net(ulpq->asoc->base.sk),
260 &ulpq->reasm, first_frag,
261 last_frag);
262 if (retval) {
263 sin->fsn = next_fsn;
264 if (is_last) {
265 retval->msg_flags |= MSG_EOR;
266 sin->pd_mode = 0;
267 }
268 }
269
270 return retval;
271}
272
273static struct sctp_ulpevent *sctp_intl_retrieve_reassembled(
274 struct sctp_ulpq *ulpq,
275 struct sctp_ulpevent *event)
276{
277 struct sctp_association *asoc = ulpq->asoc;
278 struct sk_buff *pos, *first_frag = NULL;
279 struct sctp_ulpevent *retval = NULL;
280 struct sk_buff *pd_first = NULL;
281 struct sk_buff *pd_last = NULL;
282 struct sctp_stream_in *sin;
283 __u32 next_fsn = 0;
284 __u32 pd_point = 0;
285 __u32 pd_len = 0;
286 __u32 mid = 0;
287
05364ca0 288 sin = sctp_stream_in(&ulpq->asoc->stream, event->stream);
bd4d627d
XL
289
290 skb_queue_walk(&ulpq->reasm, pos) {
291 struct sctp_ulpevent *cevent = sctp_skb2event(pos);
292
293 if (cevent->stream < event->stream)
294 continue;
295 if (cevent->stream > event->stream)
296 break;
297
298 if (MID_lt(cevent->mid, event->mid))
299 continue;
300 if (MID_lt(event->mid, cevent->mid))
301 break;
302
303 switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) {
304 case SCTP_DATA_FIRST_FRAG:
305 if (cevent->mid == sin->mid) {
306 pd_first = pos;
307 pd_last = pos;
308 pd_len = pos->len;
309 }
310
311 first_frag = pos;
312 next_fsn = 0;
313 mid = cevent->mid;
314 break;
315
316 case SCTP_DATA_MIDDLE_FRAG:
317 if (first_frag && cevent->mid == mid &&
318 cevent->fsn == next_fsn) {
319 next_fsn++;
320 if (pd_first) {
321 pd_last = pos;
322 pd_len += pos->len;
323 }
324 } else {
325 first_frag = NULL;
326 }
327 break;
328
329 case SCTP_DATA_LAST_FRAG:
330 if (first_frag && cevent->mid == mid &&
331 cevent->fsn == next_fsn)
332 goto found;
333 else
334 first_frag = NULL;
335 break;
336 }
337 }
338
339 if (!pd_first)
340 goto out;
341
342 pd_point = sctp_sk(asoc->base.sk)->pd_point;
343 if (pd_point && pd_point <= pd_len) {
344 retval = sctp_make_reassembled_event(sock_net(asoc->base.sk),
345 &ulpq->reasm,
346 pd_first, pd_last);
347 if (retval) {
348 sin->fsn = next_fsn;
349 sin->pd_mode = 1;
350 }
351 }
352 goto out;
353
354found:
355 retval = sctp_make_reassembled_event(sock_net(asoc->base.sk),
356 &ulpq->reasm,
357 first_frag, pos);
358 if (retval)
359 retval->msg_flags |= MSG_EOR;
360
361out:
362 return retval;
363}
364
365static struct sctp_ulpevent *sctp_intl_reasm(struct sctp_ulpq *ulpq,
366 struct sctp_ulpevent *event)
367{
368 struct sctp_ulpevent *retval = NULL;
369 struct sctp_stream_in *sin;
370
371 if (SCTP_DATA_NOT_FRAG == (event->msg_flags & SCTP_DATA_FRAG_MASK)) {
372 event->msg_flags |= MSG_EOR;
373 return event;
374 }
375
376 sctp_intl_store_reasm(ulpq, event);
377
05364ca0 378 sin = sctp_stream_in(&ulpq->asoc->stream, event->stream);
bd4d627d
XL
379 if (sin->pd_mode && event->mid == sin->mid &&
380 event->fsn == sin->fsn)
381 retval = sctp_intl_retrieve_partial(ulpq, event);
382
383 if (!retval)
384 retval = sctp_intl_retrieve_reassembled(ulpq, event);
385
386 return retval;
387}
388
389static void sctp_intl_store_ordered(struct sctp_ulpq *ulpq,
390 struct sctp_ulpevent *event)
391{
392 struct sctp_ulpevent *cevent;
e15e067d 393 struct sk_buff *pos, *loc;
bd4d627d
XL
394
395 pos = skb_peek_tail(&ulpq->lobby);
396 if (!pos) {
397 __skb_queue_tail(&ulpq->lobby, sctp_event2skb(event));
398 return;
399 }
400
401 cevent = (struct sctp_ulpevent *)pos->cb;
402 if (event->stream == cevent->stream &&
403 MID_lt(cevent->mid, event->mid)) {
404 __skb_queue_tail(&ulpq->lobby, sctp_event2skb(event));
405 return;
406 }
407
408 if (event->stream > cevent->stream) {
409 __skb_queue_tail(&ulpq->lobby, sctp_event2skb(event));
410 return;
411 }
412
e15e067d 413 loc = NULL;
bd4d627d
XL
414 skb_queue_walk(&ulpq->lobby, pos) {
415 cevent = (struct sctp_ulpevent *)pos->cb;
416
e15e067d
DM
417 if (cevent->stream > event->stream) {
418 loc = pos;
bd4d627d 419 break;
e15e067d 420 }
bd4d627d 421 if (cevent->stream == event->stream &&
e15e067d
DM
422 MID_lt(event->mid, cevent->mid)) {
423 loc = pos;
bd4d627d 424 break;
e15e067d 425 }
bd4d627d
XL
426 }
427
e15e067d
DM
428 if (!loc)
429 __skb_queue_tail(&ulpq->lobby, sctp_event2skb(event));
430 else
431 __skb_queue_before(&ulpq->lobby, loc, sctp_event2skb(event));
bd4d627d
XL
432}
433
434static void sctp_intl_retrieve_ordered(struct sctp_ulpq *ulpq,
435 struct sctp_ulpevent *event)
436{
437 struct sk_buff_head *event_list;
438 struct sctp_stream *stream;
439 struct sk_buff *pos, *tmp;
440 __u16 sid = event->stream;
441
442 stream = &ulpq->asoc->stream;
443 event_list = (struct sk_buff_head *)sctp_event2skb(event)->prev;
444
445 sctp_skb_for_each(pos, &ulpq->lobby, tmp) {
446 struct sctp_ulpevent *cevent = (struct sctp_ulpevent *)pos->cb;
447
448 if (cevent->stream > sid)
449 break;
450
451 if (cevent->stream < sid)
452 continue;
453
454 if (cevent->mid != sctp_mid_peek(stream, in, sid))
455 break;
456
457 sctp_mid_next(stream, in, sid);
458
459 __skb_unlink(pos, &ulpq->lobby);
460
461 __skb_queue_tail(event_list, pos);
462 }
463}
464
465static struct sctp_ulpevent *sctp_intl_order(struct sctp_ulpq *ulpq,
466 struct sctp_ulpevent *event)
467{
468 struct sctp_stream *stream;
469 __u16 sid;
470
bd4d627d
XL
471 stream = &ulpq->asoc->stream;
472 sid = event->stream;
473
474 if (event->mid != sctp_mid_peek(stream, in, sid)) {
475 sctp_intl_store_ordered(ulpq, event);
476 return NULL;
477 }
478
479 sctp_mid_next(stream, in, sid);
480
481 sctp_intl_retrieve_ordered(ulpq, event);
482
483 return event;
484}
485
486static int sctp_enqueue_event(struct sctp_ulpq *ulpq,
178ca044 487 struct sk_buff_head *skb_list)
bd4d627d 488{
bd4d627d
XL
489 struct sock *sk = ulpq->asoc->base.sk;
490 struct sctp_sock *sp = sctp_sk(sk);
178ca044
DM
491 struct sctp_ulpevent *event;
492 struct sk_buff *skb;
bd4d627d 493
178ca044
DM
494 skb = __skb_peek(skb_list);
495 event = sctp_skb2event(skb);
bd4d627d
XL
496
497 if (sk->sk_shutdown & RCV_SHUTDOWN &&
498 (sk->sk_shutdown & SEND_SHUTDOWN ||
499 !sctp_ulpevent_is_notification(event)))
500 goto out_free;
501
502 if (!sctp_ulpevent_is_notification(event)) {
503 sk_mark_napi_id(sk, skb);
504 sk_incoming_cpu_update(sk);
505 }
506
a1e3a059 507 if (!sctp_ulpevent_is_enabled(event, ulpq->asoc->subscribe))
bd4d627d
XL
508 goto out_free;
509
510 if (skb_list)
511 skb_queue_splice_tail_init(skb_list,
512 &sk->sk_receive_queue);
513 else
514 __skb_queue_tail(&sk->sk_receive_queue, skb);
515
516 if (!sp->data_ready_signalled) {
517 sp->data_ready_signalled = 1;
518 sk->sk_data_ready(sk);
519 }
520
521 return 1;
522
523out_free:
524 if (skb_list)
525 sctp_queue_purge_ulpevents(skb_list);
526 else
527 sctp_ulpevent_free(event);
528
529 return 0;
530}
531
13228238
XL
532static void sctp_intl_store_reasm_uo(struct sctp_ulpq *ulpq,
533 struct sctp_ulpevent *event)
534{
535 struct sctp_ulpevent *cevent;
536 struct sk_buff *pos;
537
538 pos = skb_peek_tail(&ulpq->reasm_uo);
539 if (!pos) {
540 __skb_queue_tail(&ulpq->reasm_uo, sctp_event2skb(event));
541 return;
542 }
543
544 cevent = sctp_skb2event(pos);
545
546 if (event->stream == cevent->stream &&
547 event->mid == cevent->mid &&
548 (cevent->msg_flags & SCTP_DATA_FIRST_FRAG ||
549 (!(event->msg_flags & SCTP_DATA_FIRST_FRAG) &&
550 event->fsn > cevent->fsn))) {
551 __skb_queue_tail(&ulpq->reasm_uo, sctp_event2skb(event));
552 return;
553 }
554
555 if ((event->stream == cevent->stream &&
556 MID_lt(cevent->mid, event->mid)) ||
557 event->stream > cevent->stream) {
558 __skb_queue_tail(&ulpq->reasm_uo, sctp_event2skb(event));
559 return;
560 }
561
562 skb_queue_walk(&ulpq->reasm_uo, pos) {
563 cevent = sctp_skb2event(pos);
564
565 if (event->stream < cevent->stream ||
566 (event->stream == cevent->stream &&
567 MID_lt(event->mid, cevent->mid)))
568 break;
569
570 if (event->stream == cevent->stream &&
571 event->mid == cevent->mid &&
572 !(cevent->msg_flags & SCTP_DATA_FIRST_FRAG) &&
573 (event->msg_flags & SCTP_DATA_FIRST_FRAG ||
574 event->fsn < cevent->fsn))
575 break;
576 }
577
578 __skb_queue_before(&ulpq->reasm_uo, pos, sctp_event2skb(event));
579}
580
581static struct sctp_ulpevent *sctp_intl_retrieve_partial_uo(
582 struct sctp_ulpq *ulpq,
583 struct sctp_ulpevent *event)
584{
585 struct sk_buff *first_frag = NULL;
586 struct sk_buff *last_frag = NULL;
587 struct sctp_ulpevent *retval;
588 struct sctp_stream_in *sin;
589 struct sk_buff *pos;
590 __u32 next_fsn = 0;
591 int is_last = 0;
592
05364ca0 593 sin = sctp_stream_in(&ulpq->asoc->stream, event->stream);
13228238
XL
594
595 skb_queue_walk(&ulpq->reasm_uo, pos) {
596 struct sctp_ulpevent *cevent = sctp_skb2event(pos);
597
598 if (cevent->stream < event->stream)
599 continue;
600 if (cevent->stream > event->stream)
601 break;
602
603 if (MID_lt(cevent->mid, sin->mid_uo))
604 continue;
605 if (MID_lt(sin->mid_uo, cevent->mid))
606 break;
607
608 switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) {
609 case SCTP_DATA_FIRST_FRAG:
610 goto out;
611 case SCTP_DATA_MIDDLE_FRAG:
612 if (!first_frag) {
613 if (cevent->fsn == sin->fsn_uo) {
614 first_frag = pos;
615 last_frag = pos;
616 next_fsn = cevent->fsn + 1;
617 }
618 } else if (cevent->fsn == next_fsn) {
619 last_frag = pos;
620 next_fsn++;
621 } else {
622 goto out;
623 }
624 break;
625 case SCTP_DATA_LAST_FRAG:
626 if (!first_frag) {
627 if (cevent->fsn == sin->fsn_uo) {
628 first_frag = pos;
629 last_frag = pos;
630 next_fsn = 0;
631 is_last = 1;
632 }
633 } else if (cevent->fsn == next_fsn) {
634 last_frag = pos;
635 next_fsn = 0;
636 is_last = 1;
637 }
638 goto out;
639 default:
640 goto out;
641 }
642 }
643
644out:
645 if (!first_frag)
646 return NULL;
647
648 retval = sctp_make_reassembled_event(sock_net(ulpq->asoc->base.sk),
649 &ulpq->reasm_uo, first_frag,
650 last_frag);
651 if (retval) {
652 sin->fsn_uo = next_fsn;
653 if (is_last) {
654 retval->msg_flags |= MSG_EOR;
655 sin->pd_mode_uo = 0;
656 }
657 }
658
659 return retval;
660}
661
662static struct sctp_ulpevent *sctp_intl_retrieve_reassembled_uo(
663 struct sctp_ulpq *ulpq,
664 struct sctp_ulpevent *event)
665{
666 struct sctp_association *asoc = ulpq->asoc;
667 struct sk_buff *pos, *first_frag = NULL;
668 struct sctp_ulpevent *retval = NULL;
669 struct sk_buff *pd_first = NULL;
670 struct sk_buff *pd_last = NULL;
671 struct sctp_stream_in *sin;
672 __u32 next_fsn = 0;
673 __u32 pd_point = 0;
674 __u32 pd_len = 0;
675 __u32 mid = 0;
676
05364ca0 677 sin = sctp_stream_in(&ulpq->asoc->stream, event->stream);
13228238
XL
678
679 skb_queue_walk(&ulpq->reasm_uo, pos) {
680 struct sctp_ulpevent *cevent = sctp_skb2event(pos);
681
682 if (cevent->stream < event->stream)
683 continue;
684 if (cevent->stream > event->stream)
685 break;
686
687 if (MID_lt(cevent->mid, event->mid))
688 continue;
689 if (MID_lt(event->mid, cevent->mid))
690 break;
691
692 switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) {
693 case SCTP_DATA_FIRST_FRAG:
694 if (!sin->pd_mode_uo) {
695 sin->mid_uo = cevent->mid;
696 pd_first = pos;
697 pd_last = pos;
698 pd_len = pos->len;
699 }
700
701 first_frag = pos;
702 next_fsn = 0;
703 mid = cevent->mid;
704 break;
705
706 case SCTP_DATA_MIDDLE_FRAG:
707 if (first_frag && cevent->mid == mid &&
708 cevent->fsn == next_fsn) {
709 next_fsn++;
710 if (pd_first) {
711 pd_last = pos;
712 pd_len += pos->len;
713 }
714 } else {
715 first_frag = NULL;
716 }
717 break;
718
719 case SCTP_DATA_LAST_FRAG:
720 if (first_frag && cevent->mid == mid &&
721 cevent->fsn == next_fsn)
722 goto found;
723 else
724 first_frag = NULL;
725 break;
726 }
727 }
728
729 if (!pd_first)
730 goto out;
731
732 pd_point = sctp_sk(asoc->base.sk)->pd_point;
733 if (pd_point && pd_point <= pd_len) {
734 retval = sctp_make_reassembled_event(sock_net(asoc->base.sk),
735 &ulpq->reasm_uo,
736 pd_first, pd_last);
737 if (retval) {
738 sin->fsn_uo = next_fsn;
739 sin->pd_mode_uo = 1;
740 }
741 }
742 goto out;
743
744found:
745 retval = sctp_make_reassembled_event(sock_net(asoc->base.sk),
746 &ulpq->reasm_uo,
747 first_frag, pos);
748 if (retval)
749 retval->msg_flags |= MSG_EOR;
750
751out:
752 return retval;
753}
754
755static struct sctp_ulpevent *sctp_intl_reasm_uo(struct sctp_ulpq *ulpq,
756 struct sctp_ulpevent *event)
757{
758 struct sctp_ulpevent *retval = NULL;
759 struct sctp_stream_in *sin;
760
761 if (SCTP_DATA_NOT_FRAG == (event->msg_flags & SCTP_DATA_FRAG_MASK)) {
762 event->msg_flags |= MSG_EOR;
763 return event;
764 }
765
766 sctp_intl_store_reasm_uo(ulpq, event);
767
05364ca0 768 sin = sctp_stream_in(&ulpq->asoc->stream, event->stream);
13228238
XL
769 if (sin->pd_mode_uo && event->mid == sin->mid_uo &&
770 event->fsn == sin->fsn_uo)
771 retval = sctp_intl_retrieve_partial_uo(ulpq, event);
772
773 if (!retval)
774 retval = sctp_intl_retrieve_reassembled_uo(ulpq, event);
775
776 return retval;
777}
778
779static struct sctp_ulpevent *sctp_intl_retrieve_first_uo(struct sctp_ulpq *ulpq)
780{
781 struct sctp_stream_in *csin, *sin = NULL;
782 struct sk_buff *first_frag = NULL;
783 struct sk_buff *last_frag = NULL;
784 struct sctp_ulpevent *retval;
785 struct sk_buff *pos;
786 __u32 next_fsn = 0;
787 __u16 sid = 0;
788
789 skb_queue_walk(&ulpq->reasm_uo, pos) {
790 struct sctp_ulpevent *cevent = sctp_skb2event(pos);
791
05364ca0 792 csin = sctp_stream_in(&ulpq->asoc->stream, cevent->stream);
13228238
XL
793 if (csin->pd_mode_uo)
794 continue;
795
796 switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) {
797 case SCTP_DATA_FIRST_FRAG:
798 if (first_frag)
799 goto out;
800 first_frag = pos;
801 last_frag = pos;
802 next_fsn = 0;
803 sin = csin;
804 sid = cevent->stream;
805 sin->mid_uo = cevent->mid;
806 break;
807 case SCTP_DATA_MIDDLE_FRAG:
808 if (!first_frag)
809 break;
810 if (cevent->stream == sid &&
811 cevent->mid == sin->mid_uo &&
812 cevent->fsn == next_fsn) {
813 next_fsn++;
814 last_frag = pos;
815 } else {
816 goto out;
817 }
818 break;
819 case SCTP_DATA_LAST_FRAG:
820 if (first_frag)
821 goto out;
822 break;
823 default:
824 break;
825 }
826 }
827
828 if (!first_frag)
829 return NULL;
830
831out:
832 retval = sctp_make_reassembled_event(sock_net(ulpq->asoc->base.sk),
833 &ulpq->reasm_uo, first_frag,
834 last_frag);
835 if (retval) {
836 sin->fsn_uo = next_fsn;
837 sin->pd_mode_uo = 1;
838 }
839
840 return retval;
841}
842
bd4d627d
XL
843static int sctp_ulpevent_idata(struct sctp_ulpq *ulpq,
844 struct sctp_chunk *chunk, gfp_t gfp)
845{
846 struct sctp_ulpevent *event;
847 struct sk_buff_head temp;
848 int event_eor = 0;
849
850 event = sctp_ulpevent_make_rcvmsg(chunk->asoc, chunk, gfp);
851 if (!event)
852 return -ENOMEM;
853
854 event->mid = ntohl(chunk->subh.idata_hdr->mid);
855 if (event->msg_flags & SCTP_DATA_FIRST_FRAG)
856 event->ppid = chunk->subh.idata_hdr->ppid;
857 else
858 event->fsn = ntohl(chunk->subh.idata_hdr->fsn);
859
13228238
XL
860 if (!(event->msg_flags & SCTP_DATA_UNORDERED)) {
861 event = sctp_intl_reasm(ulpq, event);
178ca044 862 if (event) {
13228238
XL
863 skb_queue_head_init(&temp);
864 __skb_queue_tail(&temp, sctp_event2skb(event));
bd4d627d 865
178ca044
DM
866 if (event->msg_flags & MSG_EOR)
867 event = sctp_intl_order(ulpq, event);
13228238
XL
868 }
869 } else {
870 event = sctp_intl_reasm_uo(ulpq, event);
178ca044
DM
871 if (event) {
872 skb_queue_head_init(&temp);
873 __skb_queue_tail(&temp, sctp_event2skb(event));
874 }
bd4d627d
XL
875 }
876
877 if (event) {
878 event_eor = (event->msg_flags & MSG_EOR) ? 1 : 0;
178ca044 879 sctp_enqueue_event(ulpq, &temp);
bd4d627d
XL
880 }
881
882 return event_eor;
883}
884
94014e8d
XL
885static struct sctp_ulpevent *sctp_intl_retrieve_first(struct sctp_ulpq *ulpq)
886{
887 struct sctp_stream_in *csin, *sin = NULL;
888 struct sk_buff *first_frag = NULL;
889 struct sk_buff *last_frag = NULL;
890 struct sctp_ulpevent *retval;
891 struct sk_buff *pos;
892 __u32 next_fsn = 0;
893 __u16 sid = 0;
894
895 skb_queue_walk(&ulpq->reasm, pos) {
896 struct sctp_ulpevent *cevent = sctp_skb2event(pos);
897
05364ca0 898 csin = sctp_stream_in(&ulpq->asoc->stream, cevent->stream);
94014e8d
XL
899 if (csin->pd_mode)
900 continue;
901
902 switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) {
903 case SCTP_DATA_FIRST_FRAG:
904 if (first_frag)
905 goto out;
906 if (cevent->mid == csin->mid) {
907 first_frag = pos;
908 last_frag = pos;
909 next_fsn = 0;
910 sin = csin;
911 sid = cevent->stream;
912 }
913 break;
914 case SCTP_DATA_MIDDLE_FRAG:
915 if (!first_frag)
916 break;
917 if (cevent->stream == sid &&
918 cevent->mid == sin->mid &&
919 cevent->fsn == next_fsn) {
920 next_fsn++;
921 last_frag = pos;
922 } else {
923 goto out;
924 }
925 break;
926 case SCTP_DATA_LAST_FRAG:
927 if (first_frag)
928 goto out;
929 break;
930 default:
931 break;
932 }
933 }
934
935 if (!first_frag)
936 return NULL;
937
938out:
939 retval = sctp_make_reassembled_event(sock_net(ulpq->asoc->base.sk),
940 &ulpq->reasm, first_frag,
941 last_frag);
942 if (retval) {
943 sin->fsn = next_fsn;
944 sin->pd_mode = 1;
945 }
946
947 return retval;
948}
949
950static void sctp_intl_start_pd(struct sctp_ulpq *ulpq, gfp_t gfp)
951{
952 struct sctp_ulpevent *event;
178ca044 953 struct sk_buff_head temp;
94014e8d 954
13228238
XL
955 if (!skb_queue_empty(&ulpq->reasm)) {
956 do {
957 event = sctp_intl_retrieve_first(ulpq);
178ca044
DM
958 if (event) {
959 skb_queue_head_init(&temp);
960 __skb_queue_tail(&temp, sctp_event2skb(event));
961 sctp_enqueue_event(ulpq, &temp);
962 }
13228238
XL
963 } while (event);
964 }
94014e8d 965
13228238
XL
966 if (!skb_queue_empty(&ulpq->reasm_uo)) {
967 do {
968 event = sctp_intl_retrieve_first_uo(ulpq);
178ca044
DM
969 if (event) {
970 skb_queue_head_init(&temp);
971 __skb_queue_tail(&temp, sctp_event2skb(event));
972 sctp_enqueue_event(ulpq, &temp);
973 }
13228238
XL
974 } while (event);
975 }
94014e8d
XL
976}
977
978static void sctp_renege_events(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
979 gfp_t gfp)
980{
981 struct sctp_association *asoc = ulpq->asoc;
982 __u32 freed = 0;
983 __u16 needed;
984
fb234035
XL
985 needed = ntohs(chunk->chunk_hdr->length) -
986 sizeof(struct sctp_idata_chunk);
94014e8d
XL
987
988 if (skb_queue_empty(&asoc->base.sk->sk_receive_queue)) {
989 freed = sctp_ulpq_renege_list(ulpq, &ulpq->lobby, needed);
990 if (freed < needed)
991 freed += sctp_ulpq_renege_list(ulpq, &ulpq->reasm,
992 needed);
13228238
XL
993 if (freed < needed)
994 freed += sctp_ulpq_renege_list(ulpq, &ulpq->reasm_uo,
995 needed);
94014e8d
XL
996 }
997
9ab2323c
XL
998 if (freed >= needed && sctp_ulpevent_idata(ulpq, chunk, gfp) <= 0)
999 sctp_intl_start_pd(ulpq, gfp);
94014e8d
XL
1000
1001 sk_mem_reclaim(asoc->base.sk);
1002}
1003
65f5e357
XL
1004static void sctp_intl_stream_abort_pd(struct sctp_ulpq *ulpq, __u16 sid,
1005 __u32 mid, __u16 flags, gfp_t gfp)
1006{
1007 struct sock *sk = ulpq->asoc->base.sk;
1008 struct sctp_ulpevent *ev = NULL;
1009
a1e3a059 1010 if (!sctp_ulpevent_type_enabled(ulpq->asoc->subscribe,
2cc0eeb6 1011 SCTP_PARTIAL_DELIVERY_EVENT))
65f5e357
XL
1012 return;
1013
1014 ev = sctp_ulpevent_make_pdapi(ulpq->asoc, SCTP_PARTIAL_DELIVERY_ABORTED,
1015 sid, mid, flags, gfp);
1016 if (ev) {
a1e3a059
XL
1017 struct sctp_sock *sp = sctp_sk(sk);
1018
65f5e357
XL
1019 __skb_queue_tail(&sk->sk_receive_queue, sctp_event2skb(ev));
1020
2cc0eeb6
XL
1021 if (!sp->data_ready_signalled) {
1022 sp->data_ready_signalled = 1;
65f5e357
XL
1023 sk->sk_data_ready(sk);
1024 }
1025 }
1026}
1027
1028static void sctp_intl_reap_ordered(struct sctp_ulpq *ulpq, __u16 sid)
1029{
1030 struct sctp_stream *stream = &ulpq->asoc->stream;
1031 struct sctp_ulpevent *cevent, *event = NULL;
1032 struct sk_buff_head *lobby = &ulpq->lobby;
1033 struct sk_buff *pos, *tmp;
1034 struct sk_buff_head temp;
1035 __u16 csid;
1036 __u32 cmid;
1037
1038 skb_queue_head_init(&temp);
1039 sctp_skb_for_each(pos, lobby, tmp) {
1040 cevent = (struct sctp_ulpevent *)pos->cb;
1041 csid = cevent->stream;
1042 cmid = cevent->mid;
1043
1044 if (csid > sid)
1045 break;
1046
1047 if (csid < sid)
1048 continue;
1049
1050 if (!MID_lt(cmid, sctp_mid_peek(stream, in, csid)))
1051 break;
1052
1053 __skb_unlink(pos, lobby);
1054 if (!event)
1055 event = sctp_skb2event(pos);
1056
1057 __skb_queue_tail(&temp, pos);
1058 }
1059
1060 if (!event && pos != (struct sk_buff *)lobby) {
1061 cevent = (struct sctp_ulpevent *)pos->cb;
1062 csid = cevent->stream;
1063 cmid = cevent->mid;
1064
1065 if (csid == sid && cmid == sctp_mid_peek(stream, in, csid)) {
1066 sctp_mid_next(stream, in, csid);
1067 __skb_unlink(pos, lobby);
1068 __skb_queue_tail(&temp, pos);
1069 event = sctp_skb2event(pos);
1070 }
1071 }
1072
1073 if (event) {
1074 sctp_intl_retrieve_ordered(ulpq, event);
178ca044 1075 sctp_enqueue_event(ulpq, &temp);
65f5e357
XL
1076 }
1077}
1078
1079static void sctp_intl_abort_pd(struct sctp_ulpq *ulpq, gfp_t gfp)
1080{
1081 struct sctp_stream *stream = &ulpq->asoc->stream;
1082 __u16 sid;
1083
1084 for (sid = 0; sid < stream->incnt; sid++) {
05364ca0 1085 struct sctp_stream_in *sin = SCTP_SI(stream, sid);
65f5e357
XL
1086 __u32 mid;
1087
13228238
XL
1088 if (sin->pd_mode_uo) {
1089 sin->pd_mode_uo = 0;
1090
1091 mid = sin->mid_uo;
1092 sctp_intl_stream_abort_pd(ulpq, sid, mid, 0x1, gfp);
1093 }
1094
65f5e357
XL
1095 if (sin->pd_mode) {
1096 sin->pd_mode = 0;
1097
1098 mid = sin->mid;
1099 sctp_intl_stream_abort_pd(ulpq, sid, mid, 0, gfp);
1100 sctp_mid_skip(stream, in, sid, mid);
1101
1102 sctp_intl_reap_ordered(ulpq, sid);
1103 }
1104 }
1105
1106 /* intl abort pd happens only when all data needs to be cleaned */
1107 sctp_ulpq_flush(ulpq);
1108}
1109
8e0c3b73
XL
1110static inline int sctp_get_skip_pos(struct sctp_ifwdtsn_skip *skiplist,
1111 int nskips, __be16 stream, __u8 flags)
1112{
1113 int i;
1114
1115 for (i = 0; i < nskips; i++)
1116 if (skiplist[i].stream == stream &&
1117 skiplist[i].flags == flags)
1118 return i;
1119
1120 return i;
1121}
1122
1123#define SCTP_FTSN_U_BIT 0x1
1124static void sctp_generate_iftsn(struct sctp_outq *q, __u32 ctsn)
1125{
1126 struct sctp_ifwdtsn_skip ftsn_skip_arr[10];
1127 struct sctp_association *asoc = q->asoc;
1128 struct sctp_chunk *ftsn_chunk = NULL;
1129 struct list_head *lchunk, *temp;
1130 int nskips = 0, skip_pos;
1131 struct sctp_chunk *chunk;
1132 __u32 tsn;
1133
1134 if (!asoc->peer.prsctp_capable)
1135 return;
1136
1137 if (TSN_lt(asoc->adv_peer_ack_point, ctsn))
1138 asoc->adv_peer_ack_point = ctsn;
1139
1140 list_for_each_safe(lchunk, temp, &q->abandoned) {
1141 chunk = list_entry(lchunk, struct sctp_chunk, transmitted_list);
1142 tsn = ntohl(chunk->subh.data_hdr->tsn);
1143
1144 if (TSN_lte(tsn, ctsn)) {
1145 list_del_init(lchunk);
1146 sctp_chunk_free(chunk);
1147 } else if (TSN_lte(tsn, asoc->adv_peer_ack_point + 1)) {
1148 __be16 sid = chunk->subh.idata_hdr->stream;
1149 __be32 mid = chunk->subh.idata_hdr->mid;
1150 __u8 flags = 0;
1151
1152 if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
1153 flags |= SCTP_FTSN_U_BIT;
1154
1155 asoc->adv_peer_ack_point = tsn;
1156 skip_pos = sctp_get_skip_pos(&ftsn_skip_arr[0], nskips,
1157 sid, flags);
1158 ftsn_skip_arr[skip_pos].stream = sid;
1159 ftsn_skip_arr[skip_pos].reserved = 0;
1160 ftsn_skip_arr[skip_pos].flags = flags;
1161 ftsn_skip_arr[skip_pos].mid = mid;
1162 if (skip_pos == nskips)
1163 nskips++;
1164 if (nskips == 10)
1165 break;
1166 } else {
1167 break;
1168 }
1169 }
1170
1171 if (asoc->adv_peer_ack_point > ctsn)
1172 ftsn_chunk = sctp_make_ifwdtsn(asoc, asoc->adv_peer_ack_point,
1173 nskips, &ftsn_skip_arr[0]);
1174
1175 if (ftsn_chunk) {
1176 list_add_tail(&ftsn_chunk->list, &q->control_chunk_list);
1177 SCTP_INC_STATS(sock_net(asoc->base.sk), SCTP_MIB_OUTCTRLCHUNKS);
1178 }
1179}
1180
0fc2ea92
XL
1181#define _sctp_walk_ifwdtsn(pos, chunk, end) \
1182 for (pos = chunk->subh.ifwdtsn_hdr->skip; \
1183 (void *)pos < (void *)chunk->subh.ifwdtsn_hdr->skip + (end); pos++)
1184
1185#define sctp_walk_ifwdtsn(pos, ch) \
1186 _sctp_walk_ifwdtsn((pos), (ch), ntohs((ch)->chunk_hdr->length) - \
1187 sizeof(struct sctp_ifwdtsn_chunk))
1188
1189static bool sctp_validate_fwdtsn(struct sctp_chunk *chunk)
1190{
1191 struct sctp_fwdtsn_skip *skip;
1192 __u16 incnt;
1193
1194 if (chunk->chunk_hdr->type != SCTP_CID_FWD_TSN)
1195 return false;
1196
1197 incnt = chunk->asoc->stream.incnt;
1198 sctp_walk_fwdtsn(skip, chunk)
1199 if (ntohs(skip->stream) >= incnt)
1200 return false;
1201
1202 return true;
1203}
1204
1205static bool sctp_validate_iftsn(struct sctp_chunk *chunk)
1206{
1207 struct sctp_ifwdtsn_skip *skip;
1208 __u16 incnt;
1209
1210 if (chunk->chunk_hdr->type != SCTP_CID_I_FWD_TSN)
1211 return false;
1212
1213 incnt = chunk->asoc->stream.incnt;
1214 sctp_walk_ifwdtsn(skip, chunk)
1215 if (ntohs(skip->stream) >= incnt)
1216 return false;
1217
1218 return true;
1219}
1220
47b20a88
XL
1221static void sctp_report_fwdtsn(struct sctp_ulpq *ulpq, __u32 ftsn)
1222{
1223 /* Move the Cumulattive TSN Ack ahead. */
1224 sctp_tsnmap_skip(&ulpq->asoc->peer.tsn_map, ftsn);
1225 /* purge the fragmentation queue */
1226 sctp_ulpq_reasm_flushtsn(ulpq, ftsn);
1227 /* Abort any in progress partial delivery. */
1228 sctp_ulpq_abort_pd(ulpq, GFP_ATOMIC);
1229}
1230
1231static void sctp_intl_reasm_flushtsn(struct sctp_ulpq *ulpq, __u32 ftsn)
1232{
1233 struct sk_buff *pos, *tmp;
1234
1235 skb_queue_walk_safe(&ulpq->reasm, pos, tmp) {
1236 struct sctp_ulpevent *event = sctp_skb2event(pos);
1237 __u32 tsn = event->tsn;
1238
1239 if (TSN_lte(tsn, ftsn)) {
1240 __skb_unlink(pos, &ulpq->reasm);
1241 sctp_ulpevent_free(event);
1242 }
1243 }
1244
1245 skb_queue_walk_safe(&ulpq->reasm_uo, pos, tmp) {
1246 struct sctp_ulpevent *event = sctp_skb2event(pos);
1247 __u32 tsn = event->tsn;
1248
1249 if (TSN_lte(tsn, ftsn)) {
1250 __skb_unlink(pos, &ulpq->reasm_uo);
1251 sctp_ulpevent_free(event);
1252 }
1253 }
1254}
1255
1256static void sctp_report_iftsn(struct sctp_ulpq *ulpq, __u32 ftsn)
1257{
1258 /* Move the Cumulattive TSN Ack ahead. */
1259 sctp_tsnmap_skip(&ulpq->asoc->peer.tsn_map, ftsn);
1260 /* purge the fragmentation queue */
1261 sctp_intl_reasm_flushtsn(ulpq, ftsn);
1262 /* abort only when it's for all data */
1263 if (ftsn == sctp_tsnmap_get_max_tsn_seen(&ulpq->asoc->peer.tsn_map))
1264 sctp_intl_abort_pd(ulpq, GFP_ATOMIC);
1265}
1266
de60fe91
XL
1267static void sctp_handle_fwdtsn(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk)
1268{
1269 struct sctp_fwdtsn_skip *skip;
1270
1271 /* Walk through all the skipped SSNs */
1272 sctp_walk_fwdtsn(skip, chunk)
1273 sctp_ulpq_skip(ulpq, ntohs(skip->stream), ntohs(skip->ssn));
1274}
1275
1276static void sctp_intl_skip(struct sctp_ulpq *ulpq, __u16 sid, __u32 mid,
1277 __u8 flags)
1278{
05364ca0 1279 struct sctp_stream_in *sin = sctp_stream_in(&ulpq->asoc->stream, sid);
de60fe91
XL
1280 struct sctp_stream *stream = &ulpq->asoc->stream;
1281
1282 if (flags & SCTP_FTSN_U_BIT) {
1283 if (sin->pd_mode_uo && MID_lt(sin->mid_uo, mid)) {
1284 sin->pd_mode_uo = 0;
1285 sctp_intl_stream_abort_pd(ulpq, sid, mid, 0x1,
1286 GFP_ATOMIC);
1287 }
1288 return;
1289 }
1290
1291 if (MID_lt(mid, sctp_mid_peek(stream, in, sid)))
1292 return;
1293
1294 if (sin->pd_mode) {
1295 sin->pd_mode = 0;
1296 sctp_intl_stream_abort_pd(ulpq, sid, mid, 0x0, GFP_ATOMIC);
1297 }
1298
1299 sctp_mid_skip(stream, in, sid, mid);
1300
1301 sctp_intl_reap_ordered(ulpq, sid);
1302}
1303
1304static void sctp_handle_iftsn(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk)
1305{
1306 struct sctp_ifwdtsn_skip *skip;
1307
1308 /* Walk through all the skipped MIDs and abort stream pd if possible */
1309 sctp_walk_ifwdtsn(skip, chunk)
1310 sctp_intl_skip(ulpq, ntohs(skip->stream),
1311 ntohl(skip->mid), skip->flags);
1312}
1313
5e8f641d
DM
1314static int do_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event)
1315{
1316 struct sk_buff_head temp;
1317
1318 skb_queue_head_init(&temp);
1319 __skb_queue_tail(&temp, sctp_event2skb(event));
013b96ec 1320 return sctp_ulpq_tail_event(ulpq, &temp);
5e8f641d
DM
1321}
1322
0c3f6f65
XL
1323static struct sctp_stream_interleave sctp_stream_interleave_0 = {
1324 .data_chunk_len = sizeof(struct sctp_data_chunk),
0fc2ea92 1325 .ftsn_chunk_len = sizeof(struct sctp_fwdtsn_chunk),
0c3f6f65
XL
1326 /* DATA process functions */
1327 .make_datafrag = sctp_make_datafrag_empty,
668c9beb 1328 .assign_number = sctp_chunk_assign_ssn,
9d4ceaf1 1329 .validate_data = sctp_validate_data,
bd4d627d 1330 .ulpevent_data = sctp_ulpq_tail_data,
5e8f641d 1331 .enqueue_event = do_ulpq_tail_event,
94014e8d 1332 .renege_events = sctp_ulpq_renege,
be4e0ce1 1333 .start_pd = sctp_ulpq_partial_delivery,
65f5e357 1334 .abort_pd = sctp_ulpq_abort_pd,
8e0c3b73
XL
1335 /* FORWARD-TSN process functions */
1336 .generate_ftsn = sctp_generate_fwdtsn,
0fc2ea92 1337 .validate_ftsn = sctp_validate_fwdtsn,
47b20a88 1338 .report_ftsn = sctp_report_fwdtsn,
de60fe91 1339 .handle_ftsn = sctp_handle_fwdtsn,
0c3f6f65
XL
1340};
1341
178ca044
DM
1342static int do_sctp_enqueue_event(struct sctp_ulpq *ulpq,
1343 struct sctp_ulpevent *event)
1344{
1345 struct sk_buff_head temp;
1346
1347 skb_queue_head_init(&temp);
1348 __skb_queue_tail(&temp, sctp_event2skb(event));
1349 return sctp_enqueue_event(ulpq, &temp);
1350}
1351
0c3f6f65
XL
1352static struct sctp_stream_interleave sctp_stream_interleave_1 = {
1353 .data_chunk_len = sizeof(struct sctp_idata_chunk),
0fc2ea92 1354 .ftsn_chunk_len = sizeof(struct sctp_ifwdtsn_chunk),
0c3f6f65
XL
1355 /* I-DATA process functions */
1356 .make_datafrag = sctp_make_idatafrag_empty,
668c9beb 1357 .assign_number = sctp_chunk_assign_mid,
9d4ceaf1 1358 .validate_data = sctp_validate_idata,
bd4d627d 1359 .ulpevent_data = sctp_ulpevent_idata,
178ca044 1360 .enqueue_event = do_sctp_enqueue_event,
94014e8d 1361 .renege_events = sctp_renege_events,
be4e0ce1 1362 .start_pd = sctp_intl_start_pd,
65f5e357 1363 .abort_pd = sctp_intl_abort_pd,
8e0c3b73
XL
1364 /* I-FORWARD-TSN process functions */
1365 .generate_ftsn = sctp_generate_iftsn,
0fc2ea92 1366 .validate_ftsn = sctp_validate_iftsn,
47b20a88 1367 .report_ftsn = sctp_report_iftsn,
de60fe91 1368 .handle_ftsn = sctp_handle_iftsn,
0c3f6f65
XL
1369};
1370
1371void sctp_stream_interleave_init(struct sctp_stream *stream)
1372{
1373 struct sctp_association *asoc;
1374
1375 asoc = container_of(stream, struct sctp_association, stream);
1376 stream->si = asoc->intl_enable ? &sctp_stream_interleave_1
1377 : &sctp_stream_interleave_0;
1378}