blob: 3ac47e78c01330fdcbaef601a1e4c9e5780a5d4e [file] [log] [blame]
Xin Long0c3f6f62017-12-08 21:04:01 +08001/* SCTP kernel implementation
2 * (C) Copyright Red Hat Inc. 2017
3 *
4 * This file is part of the SCTP kernel implementation
5 *
6 * These functions manipulate sctp stream queue/scheduling.
7 *
8 * This SCTP implementation is free software;
9 * you can redistribute it and/or modify it under the terms of
10 * the GNU General Public License as published by
11 * the Free Software Foundation; either version 2, or (at your option)
12 * any later version.
13 *
14 * This SCTP implementation is distributed in the hope that it
15 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
16 * ************************
17 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 * See the GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with GNU CC; see the file COPYING. If not, see
22 * <http://www.gnu.org/licenses/>.
23 *
24 * Please send any bug reports or fixes you make to the
25 * email addresched(es):
26 * lksctp developers <linux-sctp@vger.kernel.org>
27 *
28 * Written or modified by:
29 * Xin Long <lucien.xin@gmail.com>
30 */
31
32#include <net/sctp/sctp.h>
33#include <net/sctp/sm.h>
34#include <linux/sctp.h>
35
36static struct sctp_chunk *sctp_make_idatafrag_empty(
37 const struct sctp_association *asoc,
38 const struct sctp_sndrcvinfo *sinfo,
39 int len, __u8 flags, gfp_t gfp)
40{
41 struct sctp_chunk *retval;
42 struct sctp_idatahdr dp;
43
44 memset(&dp, 0, sizeof(dp));
45 dp.stream = htons(sinfo->sinfo_stream);
46
47 if (sinfo->sinfo_flags & SCTP_UNORDERED)
48 flags |= SCTP_DATA_UNORDERED;
49
50 retval = sctp_make_idata(asoc, flags, sizeof(dp) + len, gfp);
51 if (!retval)
52 return NULL;
53
54 retval->subh.idata_hdr = sctp_addto_chunk(retval, sizeof(dp), &dp);
55 memcpy(&retval->sinfo, sinfo, sizeof(struct sctp_sndrcvinfo));
56
57 return retval;
58}
59
Xin Long668c9be2017-12-08 21:04:02 +080060static void sctp_chunk_assign_mid(struct sctp_chunk *chunk)
61{
62 struct sctp_stream *stream;
63 struct sctp_chunk *lchunk;
64 __u32 cfsn = 0;
65 __u16 sid;
66
67 if (chunk->has_mid)
68 return;
69
70 sid = sctp_chunk_stream_no(chunk);
71 stream = &chunk->asoc->stream;
72
73 list_for_each_entry(lchunk, &chunk->msg->chunks, frag_list) {
74 struct sctp_idatahdr *hdr;
75
76 lchunk->has_mid = 1;
77
78 if (lchunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
79 continue;
80
81 hdr = lchunk->subh.idata_hdr;
82
83 if (lchunk->chunk_hdr->flags & SCTP_DATA_FIRST_FRAG)
84 hdr->ppid = lchunk->sinfo.sinfo_ppid;
85 else
86 hdr->fsn = htonl(cfsn++);
87
88 if (lchunk->chunk_hdr->flags & SCTP_DATA_LAST_FRAG)
89 hdr->mid = htonl(sctp_mid_next(stream, out, sid));
90 else
91 hdr->mid = htonl(sctp_mid_peek(stream, out, sid));
92 }
93}
94
Xin Long0c3f6f62017-12-08 21:04:01 +080095static struct sctp_stream_interleave sctp_stream_interleave_0 = {
96 .data_chunk_len = sizeof(struct sctp_data_chunk),
97 /* DATA process functions */
98 .make_datafrag = sctp_make_datafrag_empty,
Xin Long668c9be2017-12-08 21:04:02 +080099 .assign_number = sctp_chunk_assign_ssn,
Xin Long0c3f6f62017-12-08 21:04:01 +0800100};
101
102static struct sctp_stream_interleave sctp_stream_interleave_1 = {
103 .data_chunk_len = sizeof(struct sctp_idata_chunk),
104 /* I-DATA process functions */
105 .make_datafrag = sctp_make_idatafrag_empty,
Xin Long668c9be2017-12-08 21:04:02 +0800106 .assign_number = sctp_chunk_assign_mid,
Xin Long0c3f6f62017-12-08 21:04:01 +0800107};
108
109void sctp_stream_interleave_init(struct sctp_stream *stream)
110{
111 struct sctp_association *asoc;
112
113 asoc = container_of(stream, struct sctp_association, stream);
114 stream->si = asoc->intl_enable ? &sctp_stream_interleave_1
115 : &sctp_stream_interleave_0;
116}