18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* SCTP kernel implementation 38c2ecf20Sopenharmony_ci * (C) Copyright Red Hat Inc. 2017 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This file is part of the SCTP kernel implementation 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * These functions implement sctp stream message interleaving, mostly 88c2ecf20Sopenharmony_ci * including I-DATA and I-FORWARD-TSN chunks process. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Please send any bug reports or fixes you make to the 118c2ecf20Sopenharmony_ci * email addresched(es): 128c2ecf20Sopenharmony_ci * lksctp developers <linux-sctp@vger.kernel.org> 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Written or modified by: 158c2ecf20Sopenharmony_ci * Xin Long <lucien.xin@gmail.com> 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <net/busy_poll.h> 198c2ecf20Sopenharmony_ci#include <net/sctp/sctp.h> 208c2ecf20Sopenharmony_ci#include <net/sctp/sm.h> 218c2ecf20Sopenharmony_ci#include <net/sctp/ulpevent.h> 228c2ecf20Sopenharmony_ci#include <linux/sctp.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic struct sctp_chunk *sctp_make_idatafrag_empty( 258c2ecf20Sopenharmony_ci const struct sctp_association *asoc, 268c2ecf20Sopenharmony_ci const struct sctp_sndrcvinfo *sinfo, 278c2ecf20Sopenharmony_ci int len, __u8 flags, gfp_t gfp) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci struct sctp_chunk *retval; 308c2ecf20Sopenharmony_ci struct sctp_idatahdr dp; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci memset(&dp, 0, sizeof(dp)); 338c2ecf20Sopenharmony_ci dp.stream = htons(sinfo->sinfo_stream); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci if (sinfo->sinfo_flags & SCTP_UNORDERED) 368c2ecf20Sopenharmony_ci flags |= SCTP_DATA_UNORDERED; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci retval = sctp_make_idata(asoc, flags, sizeof(dp) + len, gfp); 398c2ecf20Sopenharmony_ci if (!retval) 408c2ecf20Sopenharmony_ci return NULL; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci retval->subh.idata_hdr = sctp_addto_chunk(retval, sizeof(dp), &dp); 438c2ecf20Sopenharmony_ci memcpy(&retval->sinfo, sinfo, sizeof(struct sctp_sndrcvinfo)); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci return retval; 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic void sctp_chunk_assign_mid(struct sctp_chunk *chunk) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci struct sctp_stream *stream; 518c2ecf20Sopenharmony_ci struct sctp_chunk *lchunk; 528c2ecf20Sopenharmony_ci __u32 cfsn = 0; 538c2ecf20Sopenharmony_ci __u16 sid; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci if (chunk->has_mid) 568c2ecf20Sopenharmony_ci return; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci sid = sctp_chunk_stream_no(chunk); 598c2ecf20Sopenharmony_ci stream = &chunk->asoc->stream; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci list_for_each_entry(lchunk, &chunk->msg->chunks, frag_list) { 628c2ecf20Sopenharmony_ci struct sctp_idatahdr *hdr; 638c2ecf20Sopenharmony_ci __u32 mid; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci lchunk->has_mid = 1; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci hdr = lchunk->subh.idata_hdr; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (lchunk->chunk_hdr->flags & SCTP_DATA_FIRST_FRAG) 708c2ecf20Sopenharmony_ci hdr->ppid = lchunk->sinfo.sinfo_ppid; 718c2ecf20Sopenharmony_ci else 728c2ecf20Sopenharmony_ci hdr->fsn = htonl(cfsn++); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci if (lchunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) { 758c2ecf20Sopenharmony_ci mid = lchunk->chunk_hdr->flags & SCTP_DATA_LAST_FRAG ? 768c2ecf20Sopenharmony_ci sctp_mid_uo_next(stream, out, sid) : 778c2ecf20Sopenharmony_ci sctp_mid_uo_peek(stream, out, sid); 788c2ecf20Sopenharmony_ci } else { 798c2ecf20Sopenharmony_ci mid = lchunk->chunk_hdr->flags & SCTP_DATA_LAST_FRAG ? 808c2ecf20Sopenharmony_ci sctp_mid_next(stream, out, sid) : 818c2ecf20Sopenharmony_ci sctp_mid_peek(stream, out, sid); 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci hdr->mid = htonl(mid); 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic bool sctp_validate_data(struct sctp_chunk *chunk) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci struct sctp_stream *stream; 908c2ecf20Sopenharmony_ci __u16 sid, ssn; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci if (chunk->chunk_hdr->type != SCTP_CID_DATA) 938c2ecf20Sopenharmony_ci return false; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) 968c2ecf20Sopenharmony_ci return true; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci stream = &chunk->asoc->stream; 998c2ecf20Sopenharmony_ci sid = sctp_chunk_stream_no(chunk); 1008c2ecf20Sopenharmony_ci ssn = ntohs(chunk->subh.data_hdr->ssn); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci return !SSN_lt(ssn, sctp_ssn_peek(stream, in, sid)); 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic bool sctp_validate_idata(struct sctp_chunk *chunk) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci struct sctp_stream *stream; 1088c2ecf20Sopenharmony_ci __u32 mid; 1098c2ecf20Sopenharmony_ci __u16 sid; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (chunk->chunk_hdr->type != SCTP_CID_I_DATA) 1128c2ecf20Sopenharmony_ci return false; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) 1158c2ecf20Sopenharmony_ci return true; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci stream = &chunk->asoc->stream; 1188c2ecf20Sopenharmony_ci sid = sctp_chunk_stream_no(chunk); 1198c2ecf20Sopenharmony_ci mid = ntohl(chunk->subh.idata_hdr->mid); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci return !MID_lt(mid, sctp_mid_peek(stream, in, sid)); 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic void sctp_intl_store_reasm(struct sctp_ulpq *ulpq, 1258c2ecf20Sopenharmony_ci struct sctp_ulpevent *event) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci struct sctp_ulpevent *cevent; 1288c2ecf20Sopenharmony_ci struct sk_buff *pos, *loc; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci pos = skb_peek_tail(&ulpq->reasm); 1318c2ecf20Sopenharmony_ci if (!pos) { 1328c2ecf20Sopenharmony_ci __skb_queue_tail(&ulpq->reasm, sctp_event2skb(event)); 1338c2ecf20Sopenharmony_ci return; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci cevent = sctp_skb2event(pos); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (event->stream == cevent->stream && 1398c2ecf20Sopenharmony_ci event->mid == cevent->mid && 1408c2ecf20Sopenharmony_ci (cevent->msg_flags & SCTP_DATA_FIRST_FRAG || 1418c2ecf20Sopenharmony_ci (!(event->msg_flags & SCTP_DATA_FIRST_FRAG) && 1428c2ecf20Sopenharmony_ci event->fsn > cevent->fsn))) { 1438c2ecf20Sopenharmony_ci __skb_queue_tail(&ulpq->reasm, sctp_event2skb(event)); 1448c2ecf20Sopenharmony_ci return; 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci if ((event->stream == cevent->stream && 1488c2ecf20Sopenharmony_ci MID_lt(cevent->mid, event->mid)) || 1498c2ecf20Sopenharmony_ci event->stream > cevent->stream) { 1508c2ecf20Sopenharmony_ci __skb_queue_tail(&ulpq->reasm, sctp_event2skb(event)); 1518c2ecf20Sopenharmony_ci return; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci loc = NULL; 1558c2ecf20Sopenharmony_ci skb_queue_walk(&ulpq->reasm, pos) { 1568c2ecf20Sopenharmony_ci cevent = sctp_skb2event(pos); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (event->stream < cevent->stream || 1598c2ecf20Sopenharmony_ci (event->stream == cevent->stream && 1608c2ecf20Sopenharmony_ci MID_lt(event->mid, cevent->mid))) { 1618c2ecf20Sopenharmony_ci loc = pos; 1628c2ecf20Sopenharmony_ci break; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci if (event->stream == cevent->stream && 1658c2ecf20Sopenharmony_ci event->mid == cevent->mid && 1668c2ecf20Sopenharmony_ci !(cevent->msg_flags & SCTP_DATA_FIRST_FRAG) && 1678c2ecf20Sopenharmony_ci (event->msg_flags & SCTP_DATA_FIRST_FRAG || 1688c2ecf20Sopenharmony_ci event->fsn < cevent->fsn)) { 1698c2ecf20Sopenharmony_ci loc = pos; 1708c2ecf20Sopenharmony_ci break; 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (!loc) 1758c2ecf20Sopenharmony_ci __skb_queue_tail(&ulpq->reasm, sctp_event2skb(event)); 1768c2ecf20Sopenharmony_ci else 1778c2ecf20Sopenharmony_ci __skb_queue_before(&ulpq->reasm, loc, sctp_event2skb(event)); 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic struct sctp_ulpevent *sctp_intl_retrieve_partial( 1818c2ecf20Sopenharmony_ci struct sctp_ulpq *ulpq, 1828c2ecf20Sopenharmony_ci struct sctp_ulpevent *event) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci struct sk_buff *first_frag = NULL; 1858c2ecf20Sopenharmony_ci struct sk_buff *last_frag = NULL; 1868c2ecf20Sopenharmony_ci struct sctp_ulpevent *retval; 1878c2ecf20Sopenharmony_ci struct sctp_stream_in *sin; 1888c2ecf20Sopenharmony_ci struct sk_buff *pos; 1898c2ecf20Sopenharmony_ci __u32 next_fsn = 0; 1908c2ecf20Sopenharmony_ci int is_last = 0; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci sin = sctp_stream_in(&ulpq->asoc->stream, event->stream); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci skb_queue_walk(&ulpq->reasm, pos) { 1958c2ecf20Sopenharmony_ci struct sctp_ulpevent *cevent = sctp_skb2event(pos); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci if (cevent->stream < event->stream) 1988c2ecf20Sopenharmony_ci continue; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (cevent->stream > event->stream || 2018c2ecf20Sopenharmony_ci cevent->mid != sin->mid) 2028c2ecf20Sopenharmony_ci break; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) { 2058c2ecf20Sopenharmony_ci case SCTP_DATA_FIRST_FRAG: 2068c2ecf20Sopenharmony_ci goto out; 2078c2ecf20Sopenharmony_ci case SCTP_DATA_MIDDLE_FRAG: 2088c2ecf20Sopenharmony_ci if (!first_frag) { 2098c2ecf20Sopenharmony_ci if (cevent->fsn == sin->fsn) { 2108c2ecf20Sopenharmony_ci first_frag = pos; 2118c2ecf20Sopenharmony_ci last_frag = pos; 2128c2ecf20Sopenharmony_ci next_fsn = cevent->fsn + 1; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci } else if (cevent->fsn == next_fsn) { 2158c2ecf20Sopenharmony_ci last_frag = pos; 2168c2ecf20Sopenharmony_ci next_fsn++; 2178c2ecf20Sopenharmony_ci } else { 2188c2ecf20Sopenharmony_ci goto out; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci break; 2218c2ecf20Sopenharmony_ci case SCTP_DATA_LAST_FRAG: 2228c2ecf20Sopenharmony_ci if (!first_frag) { 2238c2ecf20Sopenharmony_ci if (cevent->fsn == sin->fsn) { 2248c2ecf20Sopenharmony_ci first_frag = pos; 2258c2ecf20Sopenharmony_ci last_frag = pos; 2268c2ecf20Sopenharmony_ci next_fsn = 0; 2278c2ecf20Sopenharmony_ci is_last = 1; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci } else if (cevent->fsn == next_fsn) { 2308c2ecf20Sopenharmony_ci last_frag = pos; 2318c2ecf20Sopenharmony_ci next_fsn = 0; 2328c2ecf20Sopenharmony_ci is_last = 1; 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci goto out; 2358c2ecf20Sopenharmony_ci default: 2368c2ecf20Sopenharmony_ci goto out; 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ciout: 2418c2ecf20Sopenharmony_ci if (!first_frag) 2428c2ecf20Sopenharmony_ci return NULL; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci retval = sctp_make_reassembled_event(ulpq->asoc->base.net, &ulpq->reasm, 2458c2ecf20Sopenharmony_ci first_frag, last_frag); 2468c2ecf20Sopenharmony_ci if (retval) { 2478c2ecf20Sopenharmony_ci sin->fsn = next_fsn; 2488c2ecf20Sopenharmony_ci if (is_last) { 2498c2ecf20Sopenharmony_ci retval->msg_flags |= MSG_EOR; 2508c2ecf20Sopenharmony_ci sin->pd_mode = 0; 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci return retval; 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic struct sctp_ulpevent *sctp_intl_retrieve_reassembled( 2588c2ecf20Sopenharmony_ci struct sctp_ulpq *ulpq, 2598c2ecf20Sopenharmony_ci struct sctp_ulpevent *event) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci struct sctp_association *asoc = ulpq->asoc; 2628c2ecf20Sopenharmony_ci struct sk_buff *pos, *first_frag = NULL; 2638c2ecf20Sopenharmony_ci struct sctp_ulpevent *retval = NULL; 2648c2ecf20Sopenharmony_ci struct sk_buff *pd_first = NULL; 2658c2ecf20Sopenharmony_ci struct sk_buff *pd_last = NULL; 2668c2ecf20Sopenharmony_ci struct sctp_stream_in *sin; 2678c2ecf20Sopenharmony_ci __u32 next_fsn = 0; 2688c2ecf20Sopenharmony_ci __u32 pd_point = 0; 2698c2ecf20Sopenharmony_ci __u32 pd_len = 0; 2708c2ecf20Sopenharmony_ci __u32 mid = 0; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci sin = sctp_stream_in(&ulpq->asoc->stream, event->stream); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci skb_queue_walk(&ulpq->reasm, pos) { 2758c2ecf20Sopenharmony_ci struct sctp_ulpevent *cevent = sctp_skb2event(pos); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (cevent->stream < event->stream) 2788c2ecf20Sopenharmony_ci continue; 2798c2ecf20Sopenharmony_ci if (cevent->stream > event->stream) 2808c2ecf20Sopenharmony_ci break; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci if (MID_lt(cevent->mid, event->mid)) 2838c2ecf20Sopenharmony_ci continue; 2848c2ecf20Sopenharmony_ci if (MID_lt(event->mid, cevent->mid)) 2858c2ecf20Sopenharmony_ci break; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) { 2888c2ecf20Sopenharmony_ci case SCTP_DATA_FIRST_FRAG: 2898c2ecf20Sopenharmony_ci if (cevent->mid == sin->mid) { 2908c2ecf20Sopenharmony_ci pd_first = pos; 2918c2ecf20Sopenharmony_ci pd_last = pos; 2928c2ecf20Sopenharmony_ci pd_len = pos->len; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci first_frag = pos; 2968c2ecf20Sopenharmony_ci next_fsn = 0; 2978c2ecf20Sopenharmony_ci mid = cevent->mid; 2988c2ecf20Sopenharmony_ci break; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci case SCTP_DATA_MIDDLE_FRAG: 3018c2ecf20Sopenharmony_ci if (first_frag && cevent->mid == mid && 3028c2ecf20Sopenharmony_ci cevent->fsn == next_fsn) { 3038c2ecf20Sopenharmony_ci next_fsn++; 3048c2ecf20Sopenharmony_ci if (pd_first) { 3058c2ecf20Sopenharmony_ci pd_last = pos; 3068c2ecf20Sopenharmony_ci pd_len += pos->len; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci } else { 3098c2ecf20Sopenharmony_ci first_frag = NULL; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci break; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci case SCTP_DATA_LAST_FRAG: 3148c2ecf20Sopenharmony_ci if (first_frag && cevent->mid == mid && 3158c2ecf20Sopenharmony_ci cevent->fsn == next_fsn) 3168c2ecf20Sopenharmony_ci goto found; 3178c2ecf20Sopenharmony_ci else 3188c2ecf20Sopenharmony_ci first_frag = NULL; 3198c2ecf20Sopenharmony_ci break; 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci if (!pd_first) 3248c2ecf20Sopenharmony_ci goto out; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci pd_point = sctp_sk(asoc->base.sk)->pd_point; 3278c2ecf20Sopenharmony_ci if (pd_point && pd_point <= pd_len) { 3288c2ecf20Sopenharmony_ci retval = sctp_make_reassembled_event(asoc->base.net, 3298c2ecf20Sopenharmony_ci &ulpq->reasm, 3308c2ecf20Sopenharmony_ci pd_first, pd_last); 3318c2ecf20Sopenharmony_ci if (retval) { 3328c2ecf20Sopenharmony_ci sin->fsn = next_fsn; 3338c2ecf20Sopenharmony_ci sin->pd_mode = 1; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci goto out; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cifound: 3398c2ecf20Sopenharmony_ci retval = sctp_make_reassembled_event(asoc->base.net, &ulpq->reasm, 3408c2ecf20Sopenharmony_ci first_frag, pos); 3418c2ecf20Sopenharmony_ci if (retval) 3428c2ecf20Sopenharmony_ci retval->msg_flags |= MSG_EOR; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ciout: 3458c2ecf20Sopenharmony_ci return retval; 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic struct sctp_ulpevent *sctp_intl_reasm(struct sctp_ulpq *ulpq, 3498c2ecf20Sopenharmony_ci struct sctp_ulpevent *event) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci struct sctp_ulpevent *retval = NULL; 3528c2ecf20Sopenharmony_ci struct sctp_stream_in *sin; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci if (SCTP_DATA_NOT_FRAG == (event->msg_flags & SCTP_DATA_FRAG_MASK)) { 3558c2ecf20Sopenharmony_ci event->msg_flags |= MSG_EOR; 3568c2ecf20Sopenharmony_ci return event; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci sctp_intl_store_reasm(ulpq, event); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci sin = sctp_stream_in(&ulpq->asoc->stream, event->stream); 3628c2ecf20Sopenharmony_ci if (sin->pd_mode && event->mid == sin->mid && 3638c2ecf20Sopenharmony_ci event->fsn == sin->fsn) 3648c2ecf20Sopenharmony_ci retval = sctp_intl_retrieve_partial(ulpq, event); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci if (!retval) 3678c2ecf20Sopenharmony_ci retval = sctp_intl_retrieve_reassembled(ulpq, event); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci return retval; 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cistatic void sctp_intl_store_ordered(struct sctp_ulpq *ulpq, 3738c2ecf20Sopenharmony_ci struct sctp_ulpevent *event) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci struct sctp_ulpevent *cevent; 3768c2ecf20Sopenharmony_ci struct sk_buff *pos, *loc; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci pos = skb_peek_tail(&ulpq->lobby); 3798c2ecf20Sopenharmony_ci if (!pos) { 3808c2ecf20Sopenharmony_ci __skb_queue_tail(&ulpq->lobby, sctp_event2skb(event)); 3818c2ecf20Sopenharmony_ci return; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci cevent = (struct sctp_ulpevent *)pos->cb; 3858c2ecf20Sopenharmony_ci if (event->stream == cevent->stream && 3868c2ecf20Sopenharmony_ci MID_lt(cevent->mid, event->mid)) { 3878c2ecf20Sopenharmony_ci __skb_queue_tail(&ulpq->lobby, sctp_event2skb(event)); 3888c2ecf20Sopenharmony_ci return; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci if (event->stream > cevent->stream) { 3928c2ecf20Sopenharmony_ci __skb_queue_tail(&ulpq->lobby, sctp_event2skb(event)); 3938c2ecf20Sopenharmony_ci return; 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci loc = NULL; 3978c2ecf20Sopenharmony_ci skb_queue_walk(&ulpq->lobby, pos) { 3988c2ecf20Sopenharmony_ci cevent = (struct sctp_ulpevent *)pos->cb; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if (cevent->stream > event->stream) { 4018c2ecf20Sopenharmony_ci loc = pos; 4028c2ecf20Sopenharmony_ci break; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci if (cevent->stream == event->stream && 4058c2ecf20Sopenharmony_ci MID_lt(event->mid, cevent->mid)) { 4068c2ecf20Sopenharmony_ci loc = pos; 4078c2ecf20Sopenharmony_ci break; 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (!loc) 4128c2ecf20Sopenharmony_ci __skb_queue_tail(&ulpq->lobby, sctp_event2skb(event)); 4138c2ecf20Sopenharmony_ci else 4148c2ecf20Sopenharmony_ci __skb_queue_before(&ulpq->lobby, loc, sctp_event2skb(event)); 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic void sctp_intl_retrieve_ordered(struct sctp_ulpq *ulpq, 4188c2ecf20Sopenharmony_ci struct sctp_ulpevent *event) 4198c2ecf20Sopenharmony_ci{ 4208c2ecf20Sopenharmony_ci struct sk_buff_head *event_list; 4218c2ecf20Sopenharmony_ci struct sctp_stream *stream; 4228c2ecf20Sopenharmony_ci struct sk_buff *pos, *tmp; 4238c2ecf20Sopenharmony_ci __u16 sid = event->stream; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci stream = &ulpq->asoc->stream; 4268c2ecf20Sopenharmony_ci event_list = (struct sk_buff_head *)sctp_event2skb(event)->prev; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci sctp_skb_for_each(pos, &ulpq->lobby, tmp) { 4298c2ecf20Sopenharmony_ci struct sctp_ulpevent *cevent = (struct sctp_ulpevent *)pos->cb; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (cevent->stream > sid) 4328c2ecf20Sopenharmony_ci break; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci if (cevent->stream < sid) 4358c2ecf20Sopenharmony_ci continue; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (cevent->mid != sctp_mid_peek(stream, in, sid)) 4388c2ecf20Sopenharmony_ci break; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci sctp_mid_next(stream, in, sid); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci __skb_unlink(pos, &ulpq->lobby); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci __skb_queue_tail(event_list, pos); 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistatic struct sctp_ulpevent *sctp_intl_order(struct sctp_ulpq *ulpq, 4498c2ecf20Sopenharmony_ci struct sctp_ulpevent *event) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci struct sctp_stream *stream; 4528c2ecf20Sopenharmony_ci __u16 sid; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci stream = &ulpq->asoc->stream; 4558c2ecf20Sopenharmony_ci sid = event->stream; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci if (event->mid != sctp_mid_peek(stream, in, sid)) { 4588c2ecf20Sopenharmony_ci sctp_intl_store_ordered(ulpq, event); 4598c2ecf20Sopenharmony_ci return NULL; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci sctp_mid_next(stream, in, sid); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci sctp_intl_retrieve_ordered(ulpq, event); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci return event; 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cistatic int sctp_enqueue_event(struct sctp_ulpq *ulpq, 4708c2ecf20Sopenharmony_ci struct sk_buff_head *skb_list) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci struct sock *sk = ulpq->asoc->base.sk; 4738c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 4748c2ecf20Sopenharmony_ci struct sctp_ulpevent *event; 4758c2ecf20Sopenharmony_ci struct sk_buff *skb; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci skb = __skb_peek(skb_list); 4788c2ecf20Sopenharmony_ci event = sctp_skb2event(skb); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci if (sk->sk_shutdown & RCV_SHUTDOWN && 4818c2ecf20Sopenharmony_ci (sk->sk_shutdown & SEND_SHUTDOWN || 4828c2ecf20Sopenharmony_ci !sctp_ulpevent_is_notification(event))) 4838c2ecf20Sopenharmony_ci goto out_free; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci if (!sctp_ulpevent_is_notification(event)) { 4868c2ecf20Sopenharmony_ci sk_mark_napi_id(sk, skb); 4878c2ecf20Sopenharmony_ci sk_incoming_cpu_update(sk); 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (!sctp_ulpevent_is_enabled(event, ulpq->asoc->subscribe)) 4918c2ecf20Sopenharmony_ci goto out_free; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci if (skb_list) 4948c2ecf20Sopenharmony_ci skb_queue_splice_tail_init(skb_list, 4958c2ecf20Sopenharmony_ci &sk->sk_receive_queue); 4968c2ecf20Sopenharmony_ci else 4978c2ecf20Sopenharmony_ci __skb_queue_tail(&sk->sk_receive_queue, skb); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci if (!sp->data_ready_signalled) { 5008c2ecf20Sopenharmony_ci sp->data_ready_signalled = 1; 5018c2ecf20Sopenharmony_ci sk->sk_data_ready(sk); 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci return 1; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ciout_free: 5078c2ecf20Sopenharmony_ci if (skb_list) 5088c2ecf20Sopenharmony_ci sctp_queue_purge_ulpevents(skb_list); 5098c2ecf20Sopenharmony_ci else 5108c2ecf20Sopenharmony_ci sctp_ulpevent_free(event); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci return 0; 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_cistatic void sctp_intl_store_reasm_uo(struct sctp_ulpq *ulpq, 5168c2ecf20Sopenharmony_ci struct sctp_ulpevent *event) 5178c2ecf20Sopenharmony_ci{ 5188c2ecf20Sopenharmony_ci struct sctp_ulpevent *cevent; 5198c2ecf20Sopenharmony_ci struct sk_buff *pos; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci pos = skb_peek_tail(&ulpq->reasm_uo); 5228c2ecf20Sopenharmony_ci if (!pos) { 5238c2ecf20Sopenharmony_ci __skb_queue_tail(&ulpq->reasm_uo, sctp_event2skb(event)); 5248c2ecf20Sopenharmony_ci return; 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci cevent = sctp_skb2event(pos); 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci if (event->stream == cevent->stream && 5308c2ecf20Sopenharmony_ci event->mid == cevent->mid && 5318c2ecf20Sopenharmony_ci (cevent->msg_flags & SCTP_DATA_FIRST_FRAG || 5328c2ecf20Sopenharmony_ci (!(event->msg_flags & SCTP_DATA_FIRST_FRAG) && 5338c2ecf20Sopenharmony_ci event->fsn > cevent->fsn))) { 5348c2ecf20Sopenharmony_ci __skb_queue_tail(&ulpq->reasm_uo, sctp_event2skb(event)); 5358c2ecf20Sopenharmony_ci return; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci if ((event->stream == cevent->stream && 5398c2ecf20Sopenharmony_ci MID_lt(cevent->mid, event->mid)) || 5408c2ecf20Sopenharmony_ci event->stream > cevent->stream) { 5418c2ecf20Sopenharmony_ci __skb_queue_tail(&ulpq->reasm_uo, sctp_event2skb(event)); 5428c2ecf20Sopenharmony_ci return; 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci skb_queue_walk(&ulpq->reasm_uo, pos) { 5468c2ecf20Sopenharmony_ci cevent = sctp_skb2event(pos); 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci if (event->stream < cevent->stream || 5498c2ecf20Sopenharmony_ci (event->stream == cevent->stream && 5508c2ecf20Sopenharmony_ci MID_lt(event->mid, cevent->mid))) 5518c2ecf20Sopenharmony_ci break; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci if (event->stream == cevent->stream && 5548c2ecf20Sopenharmony_ci event->mid == cevent->mid && 5558c2ecf20Sopenharmony_ci !(cevent->msg_flags & SCTP_DATA_FIRST_FRAG) && 5568c2ecf20Sopenharmony_ci (event->msg_flags & SCTP_DATA_FIRST_FRAG || 5578c2ecf20Sopenharmony_ci event->fsn < cevent->fsn)) 5588c2ecf20Sopenharmony_ci break; 5598c2ecf20Sopenharmony_ci } 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci __skb_queue_before(&ulpq->reasm_uo, pos, sctp_event2skb(event)); 5628c2ecf20Sopenharmony_ci} 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_cistatic struct sctp_ulpevent *sctp_intl_retrieve_partial_uo( 5658c2ecf20Sopenharmony_ci struct sctp_ulpq *ulpq, 5668c2ecf20Sopenharmony_ci struct sctp_ulpevent *event) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci struct sk_buff *first_frag = NULL; 5698c2ecf20Sopenharmony_ci struct sk_buff *last_frag = NULL; 5708c2ecf20Sopenharmony_ci struct sctp_ulpevent *retval; 5718c2ecf20Sopenharmony_ci struct sctp_stream_in *sin; 5728c2ecf20Sopenharmony_ci struct sk_buff *pos; 5738c2ecf20Sopenharmony_ci __u32 next_fsn = 0; 5748c2ecf20Sopenharmony_ci int is_last = 0; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci sin = sctp_stream_in(&ulpq->asoc->stream, event->stream); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci skb_queue_walk(&ulpq->reasm_uo, pos) { 5798c2ecf20Sopenharmony_ci struct sctp_ulpevent *cevent = sctp_skb2event(pos); 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci if (cevent->stream < event->stream) 5828c2ecf20Sopenharmony_ci continue; 5838c2ecf20Sopenharmony_ci if (cevent->stream > event->stream) 5848c2ecf20Sopenharmony_ci break; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci if (MID_lt(cevent->mid, sin->mid_uo)) 5878c2ecf20Sopenharmony_ci continue; 5888c2ecf20Sopenharmony_ci if (MID_lt(sin->mid_uo, cevent->mid)) 5898c2ecf20Sopenharmony_ci break; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) { 5928c2ecf20Sopenharmony_ci case SCTP_DATA_FIRST_FRAG: 5938c2ecf20Sopenharmony_ci goto out; 5948c2ecf20Sopenharmony_ci case SCTP_DATA_MIDDLE_FRAG: 5958c2ecf20Sopenharmony_ci if (!first_frag) { 5968c2ecf20Sopenharmony_ci if (cevent->fsn == sin->fsn_uo) { 5978c2ecf20Sopenharmony_ci first_frag = pos; 5988c2ecf20Sopenharmony_ci last_frag = pos; 5998c2ecf20Sopenharmony_ci next_fsn = cevent->fsn + 1; 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci } else if (cevent->fsn == next_fsn) { 6028c2ecf20Sopenharmony_ci last_frag = pos; 6038c2ecf20Sopenharmony_ci next_fsn++; 6048c2ecf20Sopenharmony_ci } else { 6058c2ecf20Sopenharmony_ci goto out; 6068c2ecf20Sopenharmony_ci } 6078c2ecf20Sopenharmony_ci break; 6088c2ecf20Sopenharmony_ci case SCTP_DATA_LAST_FRAG: 6098c2ecf20Sopenharmony_ci if (!first_frag) { 6108c2ecf20Sopenharmony_ci if (cevent->fsn == sin->fsn_uo) { 6118c2ecf20Sopenharmony_ci first_frag = pos; 6128c2ecf20Sopenharmony_ci last_frag = pos; 6138c2ecf20Sopenharmony_ci next_fsn = 0; 6148c2ecf20Sopenharmony_ci is_last = 1; 6158c2ecf20Sopenharmony_ci } 6168c2ecf20Sopenharmony_ci } else if (cevent->fsn == next_fsn) { 6178c2ecf20Sopenharmony_ci last_frag = pos; 6188c2ecf20Sopenharmony_ci next_fsn = 0; 6198c2ecf20Sopenharmony_ci is_last = 1; 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci goto out; 6228c2ecf20Sopenharmony_ci default: 6238c2ecf20Sopenharmony_ci goto out; 6248c2ecf20Sopenharmony_ci } 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ciout: 6288c2ecf20Sopenharmony_ci if (!first_frag) 6298c2ecf20Sopenharmony_ci return NULL; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci retval = sctp_make_reassembled_event(ulpq->asoc->base.net, 6328c2ecf20Sopenharmony_ci &ulpq->reasm_uo, first_frag, 6338c2ecf20Sopenharmony_ci last_frag); 6348c2ecf20Sopenharmony_ci if (retval) { 6358c2ecf20Sopenharmony_ci sin->fsn_uo = next_fsn; 6368c2ecf20Sopenharmony_ci if (is_last) { 6378c2ecf20Sopenharmony_ci retval->msg_flags |= MSG_EOR; 6388c2ecf20Sopenharmony_ci sin->pd_mode_uo = 0; 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci } 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci return retval; 6438c2ecf20Sopenharmony_ci} 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_cistatic struct sctp_ulpevent *sctp_intl_retrieve_reassembled_uo( 6468c2ecf20Sopenharmony_ci struct sctp_ulpq *ulpq, 6478c2ecf20Sopenharmony_ci struct sctp_ulpevent *event) 6488c2ecf20Sopenharmony_ci{ 6498c2ecf20Sopenharmony_ci struct sctp_association *asoc = ulpq->asoc; 6508c2ecf20Sopenharmony_ci struct sk_buff *pos, *first_frag = NULL; 6518c2ecf20Sopenharmony_ci struct sctp_ulpevent *retval = NULL; 6528c2ecf20Sopenharmony_ci struct sk_buff *pd_first = NULL; 6538c2ecf20Sopenharmony_ci struct sk_buff *pd_last = NULL; 6548c2ecf20Sopenharmony_ci struct sctp_stream_in *sin; 6558c2ecf20Sopenharmony_ci __u32 next_fsn = 0; 6568c2ecf20Sopenharmony_ci __u32 pd_point = 0; 6578c2ecf20Sopenharmony_ci __u32 pd_len = 0; 6588c2ecf20Sopenharmony_ci __u32 mid = 0; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci sin = sctp_stream_in(&ulpq->asoc->stream, event->stream); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci skb_queue_walk(&ulpq->reasm_uo, pos) { 6638c2ecf20Sopenharmony_ci struct sctp_ulpevent *cevent = sctp_skb2event(pos); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci if (cevent->stream < event->stream) 6668c2ecf20Sopenharmony_ci continue; 6678c2ecf20Sopenharmony_ci if (cevent->stream > event->stream) 6688c2ecf20Sopenharmony_ci break; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci if (MID_lt(cevent->mid, event->mid)) 6718c2ecf20Sopenharmony_ci continue; 6728c2ecf20Sopenharmony_ci if (MID_lt(event->mid, cevent->mid)) 6738c2ecf20Sopenharmony_ci break; 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) { 6768c2ecf20Sopenharmony_ci case SCTP_DATA_FIRST_FRAG: 6778c2ecf20Sopenharmony_ci if (!sin->pd_mode_uo) { 6788c2ecf20Sopenharmony_ci sin->mid_uo = cevent->mid; 6798c2ecf20Sopenharmony_ci pd_first = pos; 6808c2ecf20Sopenharmony_ci pd_last = pos; 6818c2ecf20Sopenharmony_ci pd_len = pos->len; 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci first_frag = pos; 6858c2ecf20Sopenharmony_ci next_fsn = 0; 6868c2ecf20Sopenharmony_ci mid = cevent->mid; 6878c2ecf20Sopenharmony_ci break; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci case SCTP_DATA_MIDDLE_FRAG: 6908c2ecf20Sopenharmony_ci if (first_frag && cevent->mid == mid && 6918c2ecf20Sopenharmony_ci cevent->fsn == next_fsn) { 6928c2ecf20Sopenharmony_ci next_fsn++; 6938c2ecf20Sopenharmony_ci if (pd_first) { 6948c2ecf20Sopenharmony_ci pd_last = pos; 6958c2ecf20Sopenharmony_ci pd_len += pos->len; 6968c2ecf20Sopenharmony_ci } 6978c2ecf20Sopenharmony_ci } else { 6988c2ecf20Sopenharmony_ci first_frag = NULL; 6998c2ecf20Sopenharmony_ci } 7008c2ecf20Sopenharmony_ci break; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci case SCTP_DATA_LAST_FRAG: 7038c2ecf20Sopenharmony_ci if (first_frag && cevent->mid == mid && 7048c2ecf20Sopenharmony_ci cevent->fsn == next_fsn) 7058c2ecf20Sopenharmony_ci goto found; 7068c2ecf20Sopenharmony_ci else 7078c2ecf20Sopenharmony_ci first_frag = NULL; 7088c2ecf20Sopenharmony_ci break; 7098c2ecf20Sopenharmony_ci } 7108c2ecf20Sopenharmony_ci } 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci if (!pd_first) 7138c2ecf20Sopenharmony_ci goto out; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci pd_point = sctp_sk(asoc->base.sk)->pd_point; 7168c2ecf20Sopenharmony_ci if (pd_point && pd_point <= pd_len) { 7178c2ecf20Sopenharmony_ci retval = sctp_make_reassembled_event(asoc->base.net, 7188c2ecf20Sopenharmony_ci &ulpq->reasm_uo, 7198c2ecf20Sopenharmony_ci pd_first, pd_last); 7208c2ecf20Sopenharmony_ci if (retval) { 7218c2ecf20Sopenharmony_ci sin->fsn_uo = next_fsn; 7228c2ecf20Sopenharmony_ci sin->pd_mode_uo = 1; 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci goto out; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_cifound: 7288c2ecf20Sopenharmony_ci retval = sctp_make_reassembled_event(asoc->base.net, &ulpq->reasm_uo, 7298c2ecf20Sopenharmony_ci first_frag, pos); 7308c2ecf20Sopenharmony_ci if (retval) 7318c2ecf20Sopenharmony_ci retval->msg_flags |= MSG_EOR; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ciout: 7348c2ecf20Sopenharmony_ci return retval; 7358c2ecf20Sopenharmony_ci} 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_cistatic struct sctp_ulpevent *sctp_intl_reasm_uo(struct sctp_ulpq *ulpq, 7388c2ecf20Sopenharmony_ci struct sctp_ulpevent *event) 7398c2ecf20Sopenharmony_ci{ 7408c2ecf20Sopenharmony_ci struct sctp_ulpevent *retval = NULL; 7418c2ecf20Sopenharmony_ci struct sctp_stream_in *sin; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci if (SCTP_DATA_NOT_FRAG == (event->msg_flags & SCTP_DATA_FRAG_MASK)) { 7448c2ecf20Sopenharmony_ci event->msg_flags |= MSG_EOR; 7458c2ecf20Sopenharmony_ci return event; 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci sctp_intl_store_reasm_uo(ulpq, event); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci sin = sctp_stream_in(&ulpq->asoc->stream, event->stream); 7518c2ecf20Sopenharmony_ci if (sin->pd_mode_uo && event->mid == sin->mid_uo && 7528c2ecf20Sopenharmony_ci event->fsn == sin->fsn_uo) 7538c2ecf20Sopenharmony_ci retval = sctp_intl_retrieve_partial_uo(ulpq, event); 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci if (!retval) 7568c2ecf20Sopenharmony_ci retval = sctp_intl_retrieve_reassembled_uo(ulpq, event); 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci return retval; 7598c2ecf20Sopenharmony_ci} 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_cistatic struct sctp_ulpevent *sctp_intl_retrieve_first_uo(struct sctp_ulpq *ulpq) 7628c2ecf20Sopenharmony_ci{ 7638c2ecf20Sopenharmony_ci struct sctp_stream_in *csin, *sin = NULL; 7648c2ecf20Sopenharmony_ci struct sk_buff *first_frag = NULL; 7658c2ecf20Sopenharmony_ci struct sk_buff *last_frag = NULL; 7668c2ecf20Sopenharmony_ci struct sctp_ulpevent *retval; 7678c2ecf20Sopenharmony_ci struct sk_buff *pos; 7688c2ecf20Sopenharmony_ci __u32 next_fsn = 0; 7698c2ecf20Sopenharmony_ci __u16 sid = 0; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci skb_queue_walk(&ulpq->reasm_uo, pos) { 7728c2ecf20Sopenharmony_ci struct sctp_ulpevent *cevent = sctp_skb2event(pos); 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci csin = sctp_stream_in(&ulpq->asoc->stream, cevent->stream); 7758c2ecf20Sopenharmony_ci if (csin->pd_mode_uo) 7768c2ecf20Sopenharmony_ci continue; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) { 7798c2ecf20Sopenharmony_ci case SCTP_DATA_FIRST_FRAG: 7808c2ecf20Sopenharmony_ci if (first_frag) 7818c2ecf20Sopenharmony_ci goto out; 7828c2ecf20Sopenharmony_ci first_frag = pos; 7838c2ecf20Sopenharmony_ci last_frag = pos; 7848c2ecf20Sopenharmony_ci next_fsn = 0; 7858c2ecf20Sopenharmony_ci sin = csin; 7868c2ecf20Sopenharmony_ci sid = cevent->stream; 7878c2ecf20Sopenharmony_ci sin->mid_uo = cevent->mid; 7888c2ecf20Sopenharmony_ci break; 7898c2ecf20Sopenharmony_ci case SCTP_DATA_MIDDLE_FRAG: 7908c2ecf20Sopenharmony_ci if (!first_frag) 7918c2ecf20Sopenharmony_ci break; 7928c2ecf20Sopenharmony_ci if (cevent->stream == sid && 7938c2ecf20Sopenharmony_ci cevent->mid == sin->mid_uo && 7948c2ecf20Sopenharmony_ci cevent->fsn == next_fsn) { 7958c2ecf20Sopenharmony_ci next_fsn++; 7968c2ecf20Sopenharmony_ci last_frag = pos; 7978c2ecf20Sopenharmony_ci } else { 7988c2ecf20Sopenharmony_ci goto out; 7998c2ecf20Sopenharmony_ci } 8008c2ecf20Sopenharmony_ci break; 8018c2ecf20Sopenharmony_ci case SCTP_DATA_LAST_FRAG: 8028c2ecf20Sopenharmony_ci if (first_frag) 8038c2ecf20Sopenharmony_ci goto out; 8048c2ecf20Sopenharmony_ci break; 8058c2ecf20Sopenharmony_ci default: 8068c2ecf20Sopenharmony_ci break; 8078c2ecf20Sopenharmony_ci } 8088c2ecf20Sopenharmony_ci } 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci if (!first_frag) 8118c2ecf20Sopenharmony_ci return NULL; 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ciout: 8148c2ecf20Sopenharmony_ci retval = sctp_make_reassembled_event(ulpq->asoc->base.net, 8158c2ecf20Sopenharmony_ci &ulpq->reasm_uo, first_frag, 8168c2ecf20Sopenharmony_ci last_frag); 8178c2ecf20Sopenharmony_ci if (retval) { 8188c2ecf20Sopenharmony_ci sin->fsn_uo = next_fsn; 8198c2ecf20Sopenharmony_ci sin->pd_mode_uo = 1; 8208c2ecf20Sopenharmony_ci } 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci return retval; 8238c2ecf20Sopenharmony_ci} 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_cistatic int sctp_ulpevent_idata(struct sctp_ulpq *ulpq, 8268c2ecf20Sopenharmony_ci struct sctp_chunk *chunk, gfp_t gfp) 8278c2ecf20Sopenharmony_ci{ 8288c2ecf20Sopenharmony_ci struct sctp_ulpevent *event; 8298c2ecf20Sopenharmony_ci struct sk_buff_head temp; 8308c2ecf20Sopenharmony_ci int event_eor = 0; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci event = sctp_ulpevent_make_rcvmsg(chunk->asoc, chunk, gfp); 8338c2ecf20Sopenharmony_ci if (!event) 8348c2ecf20Sopenharmony_ci return -ENOMEM; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci event->mid = ntohl(chunk->subh.idata_hdr->mid); 8378c2ecf20Sopenharmony_ci if (event->msg_flags & SCTP_DATA_FIRST_FRAG) 8388c2ecf20Sopenharmony_ci event->ppid = chunk->subh.idata_hdr->ppid; 8398c2ecf20Sopenharmony_ci else 8408c2ecf20Sopenharmony_ci event->fsn = ntohl(chunk->subh.idata_hdr->fsn); 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci if (!(event->msg_flags & SCTP_DATA_UNORDERED)) { 8438c2ecf20Sopenharmony_ci event = sctp_intl_reasm(ulpq, event); 8448c2ecf20Sopenharmony_ci if (event) { 8458c2ecf20Sopenharmony_ci skb_queue_head_init(&temp); 8468c2ecf20Sopenharmony_ci __skb_queue_tail(&temp, sctp_event2skb(event)); 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci if (event->msg_flags & MSG_EOR) 8498c2ecf20Sopenharmony_ci event = sctp_intl_order(ulpq, event); 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci } else { 8528c2ecf20Sopenharmony_ci event = sctp_intl_reasm_uo(ulpq, event); 8538c2ecf20Sopenharmony_ci if (event) { 8548c2ecf20Sopenharmony_ci skb_queue_head_init(&temp); 8558c2ecf20Sopenharmony_ci __skb_queue_tail(&temp, sctp_event2skb(event)); 8568c2ecf20Sopenharmony_ci } 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci if (event) { 8608c2ecf20Sopenharmony_ci event_eor = (event->msg_flags & MSG_EOR) ? 1 : 0; 8618c2ecf20Sopenharmony_ci sctp_enqueue_event(ulpq, &temp); 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci return event_eor; 8658c2ecf20Sopenharmony_ci} 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_cistatic struct sctp_ulpevent *sctp_intl_retrieve_first(struct sctp_ulpq *ulpq) 8688c2ecf20Sopenharmony_ci{ 8698c2ecf20Sopenharmony_ci struct sctp_stream_in *csin, *sin = NULL; 8708c2ecf20Sopenharmony_ci struct sk_buff *first_frag = NULL; 8718c2ecf20Sopenharmony_ci struct sk_buff *last_frag = NULL; 8728c2ecf20Sopenharmony_ci struct sctp_ulpevent *retval; 8738c2ecf20Sopenharmony_ci struct sk_buff *pos; 8748c2ecf20Sopenharmony_ci __u32 next_fsn = 0; 8758c2ecf20Sopenharmony_ci __u16 sid = 0; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci skb_queue_walk(&ulpq->reasm, pos) { 8788c2ecf20Sopenharmony_ci struct sctp_ulpevent *cevent = sctp_skb2event(pos); 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci csin = sctp_stream_in(&ulpq->asoc->stream, cevent->stream); 8818c2ecf20Sopenharmony_ci if (csin->pd_mode) 8828c2ecf20Sopenharmony_ci continue; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) { 8858c2ecf20Sopenharmony_ci case SCTP_DATA_FIRST_FRAG: 8868c2ecf20Sopenharmony_ci if (first_frag) 8878c2ecf20Sopenharmony_ci goto out; 8888c2ecf20Sopenharmony_ci if (cevent->mid == csin->mid) { 8898c2ecf20Sopenharmony_ci first_frag = pos; 8908c2ecf20Sopenharmony_ci last_frag = pos; 8918c2ecf20Sopenharmony_ci next_fsn = 0; 8928c2ecf20Sopenharmony_ci sin = csin; 8938c2ecf20Sopenharmony_ci sid = cevent->stream; 8948c2ecf20Sopenharmony_ci } 8958c2ecf20Sopenharmony_ci break; 8968c2ecf20Sopenharmony_ci case SCTP_DATA_MIDDLE_FRAG: 8978c2ecf20Sopenharmony_ci if (!first_frag) 8988c2ecf20Sopenharmony_ci break; 8998c2ecf20Sopenharmony_ci if (cevent->stream == sid && 9008c2ecf20Sopenharmony_ci cevent->mid == sin->mid && 9018c2ecf20Sopenharmony_ci cevent->fsn == next_fsn) { 9028c2ecf20Sopenharmony_ci next_fsn++; 9038c2ecf20Sopenharmony_ci last_frag = pos; 9048c2ecf20Sopenharmony_ci } else { 9058c2ecf20Sopenharmony_ci goto out; 9068c2ecf20Sopenharmony_ci } 9078c2ecf20Sopenharmony_ci break; 9088c2ecf20Sopenharmony_ci case SCTP_DATA_LAST_FRAG: 9098c2ecf20Sopenharmony_ci if (first_frag) 9108c2ecf20Sopenharmony_ci goto out; 9118c2ecf20Sopenharmony_ci break; 9128c2ecf20Sopenharmony_ci default: 9138c2ecf20Sopenharmony_ci break; 9148c2ecf20Sopenharmony_ci } 9158c2ecf20Sopenharmony_ci } 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci if (!first_frag) 9188c2ecf20Sopenharmony_ci return NULL; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ciout: 9218c2ecf20Sopenharmony_ci retval = sctp_make_reassembled_event(ulpq->asoc->base.net, 9228c2ecf20Sopenharmony_ci &ulpq->reasm, first_frag, 9238c2ecf20Sopenharmony_ci last_frag); 9248c2ecf20Sopenharmony_ci if (retval) { 9258c2ecf20Sopenharmony_ci sin->fsn = next_fsn; 9268c2ecf20Sopenharmony_ci sin->pd_mode = 1; 9278c2ecf20Sopenharmony_ci } 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci return retval; 9308c2ecf20Sopenharmony_ci} 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_cistatic void sctp_intl_start_pd(struct sctp_ulpq *ulpq, gfp_t gfp) 9338c2ecf20Sopenharmony_ci{ 9348c2ecf20Sopenharmony_ci struct sctp_ulpevent *event; 9358c2ecf20Sopenharmony_ci struct sk_buff_head temp; 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci if (!skb_queue_empty(&ulpq->reasm)) { 9388c2ecf20Sopenharmony_ci do { 9398c2ecf20Sopenharmony_ci event = sctp_intl_retrieve_first(ulpq); 9408c2ecf20Sopenharmony_ci if (event) { 9418c2ecf20Sopenharmony_ci skb_queue_head_init(&temp); 9428c2ecf20Sopenharmony_ci __skb_queue_tail(&temp, sctp_event2skb(event)); 9438c2ecf20Sopenharmony_ci sctp_enqueue_event(ulpq, &temp); 9448c2ecf20Sopenharmony_ci } 9458c2ecf20Sopenharmony_ci } while (event); 9468c2ecf20Sopenharmony_ci } 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci if (!skb_queue_empty(&ulpq->reasm_uo)) { 9498c2ecf20Sopenharmony_ci do { 9508c2ecf20Sopenharmony_ci event = sctp_intl_retrieve_first_uo(ulpq); 9518c2ecf20Sopenharmony_ci if (event) { 9528c2ecf20Sopenharmony_ci skb_queue_head_init(&temp); 9538c2ecf20Sopenharmony_ci __skb_queue_tail(&temp, sctp_event2skb(event)); 9548c2ecf20Sopenharmony_ci sctp_enqueue_event(ulpq, &temp); 9558c2ecf20Sopenharmony_ci } 9568c2ecf20Sopenharmony_ci } while (event); 9578c2ecf20Sopenharmony_ci } 9588c2ecf20Sopenharmony_ci} 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_cistatic void sctp_renege_events(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk, 9618c2ecf20Sopenharmony_ci gfp_t gfp) 9628c2ecf20Sopenharmony_ci{ 9638c2ecf20Sopenharmony_ci struct sctp_association *asoc = ulpq->asoc; 9648c2ecf20Sopenharmony_ci __u32 freed = 0; 9658c2ecf20Sopenharmony_ci __u16 needed; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci needed = ntohs(chunk->chunk_hdr->length) - 9688c2ecf20Sopenharmony_ci sizeof(struct sctp_idata_chunk); 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci if (skb_queue_empty(&asoc->base.sk->sk_receive_queue)) { 9718c2ecf20Sopenharmony_ci freed = sctp_ulpq_renege_list(ulpq, &ulpq->lobby, needed); 9728c2ecf20Sopenharmony_ci if (freed < needed) 9738c2ecf20Sopenharmony_ci freed += sctp_ulpq_renege_list(ulpq, &ulpq->reasm, 9748c2ecf20Sopenharmony_ci needed); 9758c2ecf20Sopenharmony_ci if (freed < needed) 9768c2ecf20Sopenharmony_ci freed += sctp_ulpq_renege_list(ulpq, &ulpq->reasm_uo, 9778c2ecf20Sopenharmony_ci needed); 9788c2ecf20Sopenharmony_ci } 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci if (freed >= needed && sctp_ulpevent_idata(ulpq, chunk, gfp) <= 0) 9818c2ecf20Sopenharmony_ci sctp_intl_start_pd(ulpq, gfp); 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci sk_mem_reclaim(asoc->base.sk); 9848c2ecf20Sopenharmony_ci} 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_cistatic void sctp_intl_stream_abort_pd(struct sctp_ulpq *ulpq, __u16 sid, 9878c2ecf20Sopenharmony_ci __u32 mid, __u16 flags, gfp_t gfp) 9888c2ecf20Sopenharmony_ci{ 9898c2ecf20Sopenharmony_ci struct sock *sk = ulpq->asoc->base.sk; 9908c2ecf20Sopenharmony_ci struct sctp_ulpevent *ev = NULL; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci if (!sctp_ulpevent_type_enabled(ulpq->asoc->subscribe, 9938c2ecf20Sopenharmony_ci SCTP_PARTIAL_DELIVERY_EVENT)) 9948c2ecf20Sopenharmony_ci return; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci ev = sctp_ulpevent_make_pdapi(ulpq->asoc, SCTP_PARTIAL_DELIVERY_ABORTED, 9978c2ecf20Sopenharmony_ci sid, mid, flags, gfp); 9988c2ecf20Sopenharmony_ci if (ev) { 9998c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci __skb_queue_tail(&sk->sk_receive_queue, sctp_event2skb(ev)); 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci if (!sp->data_ready_signalled) { 10048c2ecf20Sopenharmony_ci sp->data_ready_signalled = 1; 10058c2ecf20Sopenharmony_ci sk->sk_data_ready(sk); 10068c2ecf20Sopenharmony_ci } 10078c2ecf20Sopenharmony_ci } 10088c2ecf20Sopenharmony_ci} 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_cistatic void sctp_intl_reap_ordered(struct sctp_ulpq *ulpq, __u16 sid) 10118c2ecf20Sopenharmony_ci{ 10128c2ecf20Sopenharmony_ci struct sctp_stream *stream = &ulpq->asoc->stream; 10138c2ecf20Sopenharmony_ci struct sctp_ulpevent *cevent, *event = NULL; 10148c2ecf20Sopenharmony_ci struct sk_buff_head *lobby = &ulpq->lobby; 10158c2ecf20Sopenharmony_ci struct sk_buff *pos, *tmp; 10168c2ecf20Sopenharmony_ci struct sk_buff_head temp; 10178c2ecf20Sopenharmony_ci __u16 csid; 10188c2ecf20Sopenharmony_ci __u32 cmid; 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci skb_queue_head_init(&temp); 10218c2ecf20Sopenharmony_ci sctp_skb_for_each(pos, lobby, tmp) { 10228c2ecf20Sopenharmony_ci cevent = (struct sctp_ulpevent *)pos->cb; 10238c2ecf20Sopenharmony_ci csid = cevent->stream; 10248c2ecf20Sopenharmony_ci cmid = cevent->mid; 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci if (csid > sid) 10278c2ecf20Sopenharmony_ci break; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci if (csid < sid) 10308c2ecf20Sopenharmony_ci continue; 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci if (!MID_lt(cmid, sctp_mid_peek(stream, in, csid))) 10338c2ecf20Sopenharmony_ci break; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci __skb_unlink(pos, lobby); 10368c2ecf20Sopenharmony_ci if (!event) 10378c2ecf20Sopenharmony_ci event = sctp_skb2event(pos); 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci __skb_queue_tail(&temp, pos); 10408c2ecf20Sopenharmony_ci } 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci if (!event && pos != (struct sk_buff *)lobby) { 10438c2ecf20Sopenharmony_ci cevent = (struct sctp_ulpevent *)pos->cb; 10448c2ecf20Sopenharmony_ci csid = cevent->stream; 10458c2ecf20Sopenharmony_ci cmid = cevent->mid; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci if (csid == sid && cmid == sctp_mid_peek(stream, in, csid)) { 10488c2ecf20Sopenharmony_ci sctp_mid_next(stream, in, csid); 10498c2ecf20Sopenharmony_ci __skb_unlink(pos, lobby); 10508c2ecf20Sopenharmony_ci __skb_queue_tail(&temp, pos); 10518c2ecf20Sopenharmony_ci event = sctp_skb2event(pos); 10528c2ecf20Sopenharmony_ci } 10538c2ecf20Sopenharmony_ci } 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci if (event) { 10568c2ecf20Sopenharmony_ci sctp_intl_retrieve_ordered(ulpq, event); 10578c2ecf20Sopenharmony_ci sctp_enqueue_event(ulpq, &temp); 10588c2ecf20Sopenharmony_ci } 10598c2ecf20Sopenharmony_ci} 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_cistatic void sctp_intl_abort_pd(struct sctp_ulpq *ulpq, gfp_t gfp) 10628c2ecf20Sopenharmony_ci{ 10638c2ecf20Sopenharmony_ci struct sctp_stream *stream = &ulpq->asoc->stream; 10648c2ecf20Sopenharmony_ci __u16 sid; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci for (sid = 0; sid < stream->incnt; sid++) { 10678c2ecf20Sopenharmony_ci struct sctp_stream_in *sin = SCTP_SI(stream, sid); 10688c2ecf20Sopenharmony_ci __u32 mid; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci if (sin->pd_mode_uo) { 10718c2ecf20Sopenharmony_ci sin->pd_mode_uo = 0; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci mid = sin->mid_uo; 10748c2ecf20Sopenharmony_ci sctp_intl_stream_abort_pd(ulpq, sid, mid, 0x1, gfp); 10758c2ecf20Sopenharmony_ci } 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci if (sin->pd_mode) { 10788c2ecf20Sopenharmony_ci sin->pd_mode = 0; 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci mid = sin->mid; 10818c2ecf20Sopenharmony_ci sctp_intl_stream_abort_pd(ulpq, sid, mid, 0, gfp); 10828c2ecf20Sopenharmony_ci sctp_mid_skip(stream, in, sid, mid); 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci sctp_intl_reap_ordered(ulpq, sid); 10858c2ecf20Sopenharmony_ci } 10868c2ecf20Sopenharmony_ci } 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci /* intl abort pd happens only when all data needs to be cleaned */ 10898c2ecf20Sopenharmony_ci sctp_ulpq_flush(ulpq); 10908c2ecf20Sopenharmony_ci} 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_cistatic inline int sctp_get_skip_pos(struct sctp_ifwdtsn_skip *skiplist, 10938c2ecf20Sopenharmony_ci int nskips, __be16 stream, __u8 flags) 10948c2ecf20Sopenharmony_ci{ 10958c2ecf20Sopenharmony_ci int i; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci for (i = 0; i < nskips; i++) 10988c2ecf20Sopenharmony_ci if (skiplist[i].stream == stream && 10998c2ecf20Sopenharmony_ci skiplist[i].flags == flags) 11008c2ecf20Sopenharmony_ci return i; 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci return i; 11038c2ecf20Sopenharmony_ci} 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci#define SCTP_FTSN_U_BIT 0x1 11068c2ecf20Sopenharmony_cistatic void sctp_generate_iftsn(struct sctp_outq *q, __u32 ctsn) 11078c2ecf20Sopenharmony_ci{ 11088c2ecf20Sopenharmony_ci struct sctp_ifwdtsn_skip ftsn_skip_arr[10]; 11098c2ecf20Sopenharmony_ci struct sctp_association *asoc = q->asoc; 11108c2ecf20Sopenharmony_ci struct sctp_chunk *ftsn_chunk = NULL; 11118c2ecf20Sopenharmony_ci struct list_head *lchunk, *temp; 11128c2ecf20Sopenharmony_ci int nskips = 0, skip_pos; 11138c2ecf20Sopenharmony_ci struct sctp_chunk *chunk; 11148c2ecf20Sopenharmony_ci __u32 tsn; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci if (!asoc->peer.prsctp_capable) 11178c2ecf20Sopenharmony_ci return; 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci if (TSN_lt(asoc->adv_peer_ack_point, ctsn)) 11208c2ecf20Sopenharmony_ci asoc->adv_peer_ack_point = ctsn; 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci list_for_each_safe(lchunk, temp, &q->abandoned) { 11238c2ecf20Sopenharmony_ci chunk = list_entry(lchunk, struct sctp_chunk, transmitted_list); 11248c2ecf20Sopenharmony_ci tsn = ntohl(chunk->subh.data_hdr->tsn); 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci if (TSN_lte(tsn, ctsn)) { 11278c2ecf20Sopenharmony_ci list_del_init(lchunk); 11288c2ecf20Sopenharmony_ci sctp_chunk_free(chunk); 11298c2ecf20Sopenharmony_ci } else if (TSN_lte(tsn, asoc->adv_peer_ack_point + 1)) { 11308c2ecf20Sopenharmony_ci __be16 sid = chunk->subh.idata_hdr->stream; 11318c2ecf20Sopenharmony_ci __be32 mid = chunk->subh.idata_hdr->mid; 11328c2ecf20Sopenharmony_ci __u8 flags = 0; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) 11358c2ecf20Sopenharmony_ci flags |= SCTP_FTSN_U_BIT; 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci asoc->adv_peer_ack_point = tsn; 11388c2ecf20Sopenharmony_ci skip_pos = sctp_get_skip_pos(&ftsn_skip_arr[0], nskips, 11398c2ecf20Sopenharmony_ci sid, flags); 11408c2ecf20Sopenharmony_ci ftsn_skip_arr[skip_pos].stream = sid; 11418c2ecf20Sopenharmony_ci ftsn_skip_arr[skip_pos].reserved = 0; 11428c2ecf20Sopenharmony_ci ftsn_skip_arr[skip_pos].flags = flags; 11438c2ecf20Sopenharmony_ci ftsn_skip_arr[skip_pos].mid = mid; 11448c2ecf20Sopenharmony_ci if (skip_pos == nskips) 11458c2ecf20Sopenharmony_ci nskips++; 11468c2ecf20Sopenharmony_ci if (nskips == 10) 11478c2ecf20Sopenharmony_ci break; 11488c2ecf20Sopenharmony_ci } else { 11498c2ecf20Sopenharmony_ci break; 11508c2ecf20Sopenharmony_ci } 11518c2ecf20Sopenharmony_ci } 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci if (asoc->adv_peer_ack_point > ctsn) 11548c2ecf20Sopenharmony_ci ftsn_chunk = sctp_make_ifwdtsn(asoc, asoc->adv_peer_ack_point, 11558c2ecf20Sopenharmony_ci nskips, &ftsn_skip_arr[0]); 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci if (ftsn_chunk) { 11588c2ecf20Sopenharmony_ci list_add_tail(&ftsn_chunk->list, &q->control_chunk_list); 11598c2ecf20Sopenharmony_ci SCTP_INC_STATS(asoc->base.net, SCTP_MIB_OUTCTRLCHUNKS); 11608c2ecf20Sopenharmony_ci } 11618c2ecf20Sopenharmony_ci} 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci#define _sctp_walk_ifwdtsn(pos, chunk, end) \ 11648c2ecf20Sopenharmony_ci for (pos = chunk->subh.ifwdtsn_hdr->skip; \ 11658c2ecf20Sopenharmony_ci (void *)pos <= (void *)chunk->subh.ifwdtsn_hdr->skip + (end) - \ 11668c2ecf20Sopenharmony_ci sizeof(struct sctp_ifwdtsn_skip); pos++) 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci#define sctp_walk_ifwdtsn(pos, ch) \ 11698c2ecf20Sopenharmony_ci _sctp_walk_ifwdtsn((pos), (ch), ntohs((ch)->chunk_hdr->length) - \ 11708c2ecf20Sopenharmony_ci sizeof(struct sctp_ifwdtsn_chunk)) 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_cistatic bool sctp_validate_fwdtsn(struct sctp_chunk *chunk) 11738c2ecf20Sopenharmony_ci{ 11748c2ecf20Sopenharmony_ci struct sctp_fwdtsn_skip *skip; 11758c2ecf20Sopenharmony_ci __u16 incnt; 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci if (chunk->chunk_hdr->type != SCTP_CID_FWD_TSN) 11788c2ecf20Sopenharmony_ci return false; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci incnt = chunk->asoc->stream.incnt; 11818c2ecf20Sopenharmony_ci sctp_walk_fwdtsn(skip, chunk) 11828c2ecf20Sopenharmony_ci if (ntohs(skip->stream) >= incnt) 11838c2ecf20Sopenharmony_ci return false; 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci return true; 11868c2ecf20Sopenharmony_ci} 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_cistatic bool sctp_validate_iftsn(struct sctp_chunk *chunk) 11898c2ecf20Sopenharmony_ci{ 11908c2ecf20Sopenharmony_ci struct sctp_ifwdtsn_skip *skip; 11918c2ecf20Sopenharmony_ci __u16 incnt; 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci if (chunk->chunk_hdr->type != SCTP_CID_I_FWD_TSN) 11948c2ecf20Sopenharmony_ci return false; 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci incnt = chunk->asoc->stream.incnt; 11978c2ecf20Sopenharmony_ci sctp_walk_ifwdtsn(skip, chunk) 11988c2ecf20Sopenharmony_ci if (ntohs(skip->stream) >= incnt) 11998c2ecf20Sopenharmony_ci return false; 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci return true; 12028c2ecf20Sopenharmony_ci} 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_cistatic void sctp_report_fwdtsn(struct sctp_ulpq *ulpq, __u32 ftsn) 12058c2ecf20Sopenharmony_ci{ 12068c2ecf20Sopenharmony_ci /* Move the Cumulattive TSN Ack ahead. */ 12078c2ecf20Sopenharmony_ci sctp_tsnmap_skip(&ulpq->asoc->peer.tsn_map, ftsn); 12088c2ecf20Sopenharmony_ci /* purge the fragmentation queue */ 12098c2ecf20Sopenharmony_ci sctp_ulpq_reasm_flushtsn(ulpq, ftsn); 12108c2ecf20Sopenharmony_ci /* Abort any in progress partial delivery. */ 12118c2ecf20Sopenharmony_ci sctp_ulpq_abort_pd(ulpq, GFP_ATOMIC); 12128c2ecf20Sopenharmony_ci} 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_cistatic void sctp_intl_reasm_flushtsn(struct sctp_ulpq *ulpq, __u32 ftsn) 12158c2ecf20Sopenharmony_ci{ 12168c2ecf20Sopenharmony_ci struct sk_buff *pos, *tmp; 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci skb_queue_walk_safe(&ulpq->reasm, pos, tmp) { 12198c2ecf20Sopenharmony_ci struct sctp_ulpevent *event = sctp_skb2event(pos); 12208c2ecf20Sopenharmony_ci __u32 tsn = event->tsn; 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci if (TSN_lte(tsn, ftsn)) { 12238c2ecf20Sopenharmony_ci __skb_unlink(pos, &ulpq->reasm); 12248c2ecf20Sopenharmony_ci sctp_ulpevent_free(event); 12258c2ecf20Sopenharmony_ci } 12268c2ecf20Sopenharmony_ci } 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci skb_queue_walk_safe(&ulpq->reasm_uo, pos, tmp) { 12298c2ecf20Sopenharmony_ci struct sctp_ulpevent *event = sctp_skb2event(pos); 12308c2ecf20Sopenharmony_ci __u32 tsn = event->tsn; 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci if (TSN_lte(tsn, ftsn)) { 12338c2ecf20Sopenharmony_ci __skb_unlink(pos, &ulpq->reasm_uo); 12348c2ecf20Sopenharmony_ci sctp_ulpevent_free(event); 12358c2ecf20Sopenharmony_ci } 12368c2ecf20Sopenharmony_ci } 12378c2ecf20Sopenharmony_ci} 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_cistatic void sctp_report_iftsn(struct sctp_ulpq *ulpq, __u32 ftsn) 12408c2ecf20Sopenharmony_ci{ 12418c2ecf20Sopenharmony_ci /* Move the Cumulattive TSN Ack ahead. */ 12428c2ecf20Sopenharmony_ci sctp_tsnmap_skip(&ulpq->asoc->peer.tsn_map, ftsn); 12438c2ecf20Sopenharmony_ci /* purge the fragmentation queue */ 12448c2ecf20Sopenharmony_ci sctp_intl_reasm_flushtsn(ulpq, ftsn); 12458c2ecf20Sopenharmony_ci /* abort only when it's for all data */ 12468c2ecf20Sopenharmony_ci if (ftsn == sctp_tsnmap_get_max_tsn_seen(&ulpq->asoc->peer.tsn_map)) 12478c2ecf20Sopenharmony_ci sctp_intl_abort_pd(ulpq, GFP_ATOMIC); 12488c2ecf20Sopenharmony_ci} 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_cistatic void sctp_handle_fwdtsn(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk) 12518c2ecf20Sopenharmony_ci{ 12528c2ecf20Sopenharmony_ci struct sctp_fwdtsn_skip *skip; 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci /* Walk through all the skipped SSNs */ 12558c2ecf20Sopenharmony_ci sctp_walk_fwdtsn(skip, chunk) 12568c2ecf20Sopenharmony_ci sctp_ulpq_skip(ulpq, ntohs(skip->stream), ntohs(skip->ssn)); 12578c2ecf20Sopenharmony_ci} 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_cistatic void sctp_intl_skip(struct sctp_ulpq *ulpq, __u16 sid, __u32 mid, 12608c2ecf20Sopenharmony_ci __u8 flags) 12618c2ecf20Sopenharmony_ci{ 12628c2ecf20Sopenharmony_ci struct sctp_stream_in *sin = sctp_stream_in(&ulpq->asoc->stream, sid); 12638c2ecf20Sopenharmony_ci struct sctp_stream *stream = &ulpq->asoc->stream; 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci if (flags & SCTP_FTSN_U_BIT) { 12668c2ecf20Sopenharmony_ci if (sin->pd_mode_uo && MID_lt(sin->mid_uo, mid)) { 12678c2ecf20Sopenharmony_ci sin->pd_mode_uo = 0; 12688c2ecf20Sopenharmony_ci sctp_intl_stream_abort_pd(ulpq, sid, mid, 0x1, 12698c2ecf20Sopenharmony_ci GFP_ATOMIC); 12708c2ecf20Sopenharmony_ci } 12718c2ecf20Sopenharmony_ci return; 12728c2ecf20Sopenharmony_ci } 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci if (MID_lt(mid, sctp_mid_peek(stream, in, sid))) 12758c2ecf20Sopenharmony_ci return; 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci if (sin->pd_mode) { 12788c2ecf20Sopenharmony_ci sin->pd_mode = 0; 12798c2ecf20Sopenharmony_ci sctp_intl_stream_abort_pd(ulpq, sid, mid, 0x0, GFP_ATOMIC); 12808c2ecf20Sopenharmony_ci } 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci sctp_mid_skip(stream, in, sid, mid); 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci sctp_intl_reap_ordered(ulpq, sid); 12858c2ecf20Sopenharmony_ci} 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_cistatic void sctp_handle_iftsn(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk) 12888c2ecf20Sopenharmony_ci{ 12898c2ecf20Sopenharmony_ci struct sctp_ifwdtsn_skip *skip; 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci /* Walk through all the skipped MIDs and abort stream pd if possible */ 12928c2ecf20Sopenharmony_ci sctp_walk_ifwdtsn(skip, chunk) 12938c2ecf20Sopenharmony_ci sctp_intl_skip(ulpq, ntohs(skip->stream), 12948c2ecf20Sopenharmony_ci ntohl(skip->mid), skip->flags); 12958c2ecf20Sopenharmony_ci} 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_cistatic int do_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event) 12988c2ecf20Sopenharmony_ci{ 12998c2ecf20Sopenharmony_ci struct sk_buff_head temp; 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci skb_queue_head_init(&temp); 13028c2ecf20Sopenharmony_ci __skb_queue_tail(&temp, sctp_event2skb(event)); 13038c2ecf20Sopenharmony_ci return sctp_ulpq_tail_event(ulpq, &temp); 13048c2ecf20Sopenharmony_ci} 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_cistatic struct sctp_stream_interleave sctp_stream_interleave_0 = { 13078c2ecf20Sopenharmony_ci .data_chunk_len = sizeof(struct sctp_data_chunk), 13088c2ecf20Sopenharmony_ci .ftsn_chunk_len = sizeof(struct sctp_fwdtsn_chunk), 13098c2ecf20Sopenharmony_ci /* DATA process functions */ 13108c2ecf20Sopenharmony_ci .make_datafrag = sctp_make_datafrag_empty, 13118c2ecf20Sopenharmony_ci .assign_number = sctp_chunk_assign_ssn, 13128c2ecf20Sopenharmony_ci .validate_data = sctp_validate_data, 13138c2ecf20Sopenharmony_ci .ulpevent_data = sctp_ulpq_tail_data, 13148c2ecf20Sopenharmony_ci .enqueue_event = do_ulpq_tail_event, 13158c2ecf20Sopenharmony_ci .renege_events = sctp_ulpq_renege, 13168c2ecf20Sopenharmony_ci .start_pd = sctp_ulpq_partial_delivery, 13178c2ecf20Sopenharmony_ci .abort_pd = sctp_ulpq_abort_pd, 13188c2ecf20Sopenharmony_ci /* FORWARD-TSN process functions */ 13198c2ecf20Sopenharmony_ci .generate_ftsn = sctp_generate_fwdtsn, 13208c2ecf20Sopenharmony_ci .validate_ftsn = sctp_validate_fwdtsn, 13218c2ecf20Sopenharmony_ci .report_ftsn = sctp_report_fwdtsn, 13228c2ecf20Sopenharmony_ci .handle_ftsn = sctp_handle_fwdtsn, 13238c2ecf20Sopenharmony_ci}; 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_cistatic int do_sctp_enqueue_event(struct sctp_ulpq *ulpq, 13268c2ecf20Sopenharmony_ci struct sctp_ulpevent *event) 13278c2ecf20Sopenharmony_ci{ 13288c2ecf20Sopenharmony_ci struct sk_buff_head temp; 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci skb_queue_head_init(&temp); 13318c2ecf20Sopenharmony_ci __skb_queue_tail(&temp, sctp_event2skb(event)); 13328c2ecf20Sopenharmony_ci return sctp_enqueue_event(ulpq, &temp); 13338c2ecf20Sopenharmony_ci} 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_cistatic struct sctp_stream_interleave sctp_stream_interleave_1 = { 13368c2ecf20Sopenharmony_ci .data_chunk_len = sizeof(struct sctp_idata_chunk), 13378c2ecf20Sopenharmony_ci .ftsn_chunk_len = sizeof(struct sctp_ifwdtsn_chunk), 13388c2ecf20Sopenharmony_ci /* I-DATA process functions */ 13398c2ecf20Sopenharmony_ci .make_datafrag = sctp_make_idatafrag_empty, 13408c2ecf20Sopenharmony_ci .assign_number = sctp_chunk_assign_mid, 13418c2ecf20Sopenharmony_ci .validate_data = sctp_validate_idata, 13428c2ecf20Sopenharmony_ci .ulpevent_data = sctp_ulpevent_idata, 13438c2ecf20Sopenharmony_ci .enqueue_event = do_sctp_enqueue_event, 13448c2ecf20Sopenharmony_ci .renege_events = sctp_renege_events, 13458c2ecf20Sopenharmony_ci .start_pd = sctp_intl_start_pd, 13468c2ecf20Sopenharmony_ci .abort_pd = sctp_intl_abort_pd, 13478c2ecf20Sopenharmony_ci /* I-FORWARD-TSN process functions */ 13488c2ecf20Sopenharmony_ci .generate_ftsn = sctp_generate_iftsn, 13498c2ecf20Sopenharmony_ci .validate_ftsn = sctp_validate_iftsn, 13508c2ecf20Sopenharmony_ci .report_ftsn = sctp_report_iftsn, 13518c2ecf20Sopenharmony_ci .handle_ftsn = sctp_handle_iftsn, 13528c2ecf20Sopenharmony_ci}; 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_civoid sctp_stream_interleave_init(struct sctp_stream *stream) 13558c2ecf20Sopenharmony_ci{ 13568c2ecf20Sopenharmony_ci struct sctp_association *asoc; 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci asoc = container_of(stream, struct sctp_association, stream); 13598c2ecf20Sopenharmony_ci stream->si = asoc->peer.intl_capable ? &sctp_stream_interleave_1 13608c2ecf20Sopenharmony_ci : &sctp_stream_interleave_0; 13618c2ecf20Sopenharmony_ci} 1362