Blame view

net/sctp/sm_make_chunk.c 115 KB
60c778b25   Vlad Yasevich   [SCTP]: Stop clai...
1
  /* SCTP kernel implementation
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
   * (C) Copyright IBM Corp. 2001, 2004
   * Copyright (c) 1999-2000 Cisco, Inc.
   * Copyright (c) 1999-2001 Motorola, Inc.
   * Copyright (c) 2001-2002 Intel Corp.
   *
60c778b25   Vlad Yasevich   [SCTP]: Stop clai...
7
   * This file is part of the SCTP kernel implementation
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
9
10
11
12
   *
   * These functions work with the state functions in sctp_sm_statefuns.c
   * to implement the state operations.  These functions implement the
   * steps which require modifying existing data structures.
   *
60c778b25   Vlad Yasevich   [SCTP]: Stop clai...
13
   * This SCTP implementation is free software;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
16
17
18
   * you can redistribute it and/or modify it under the terms of
   * the GNU General Public License as published by
   * the Free Software Foundation; either version 2, or (at your option)
   * any later version.
   *
60c778b25   Vlad Yasevich   [SCTP]: Stop clai...
19
   * This SCTP implementation is distributed in the hope that it
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
22
23
24
25
   * will be useful, but WITHOUT ANY WARRANTY; without even the implied
   *                 ************************
   * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
   * See the GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
4b2f13a25   Jeff Kirsher   sctp: Fix FSF add...
26
27
   * along with GNU CC; see the file COPYING.  If not, see
   * <http://www.gnu.org/licenses/>.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
30
   *
   * Please send any bug reports or fixes you make to the
   * email address(es):
91705c61b   Daniel Borkmann   net: sctp: trivia...
31
   *    lksctp developers <linux-sctp@vger.kernel.org>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
34
35
36
37
38
39
40
41
42
43
   * Written or modified by:
   *    La Monte H.P. Yarroll <piggy@acm.org>
   *    Karl Knutson          <karl@athena.chicago.il.us>
   *    C. Robin              <chris@hundredacre.ac.uk>
   *    Jon Grimm             <jgrimm@us.ibm.com>
   *    Xingang Guo           <xingang.guo@intel.com>
   *    Dajiang Zhang	    <dajiang.zhang@nokia.com>
   *    Sridhar Samudrala	    <sri@us.ibm.com>
   *    Daisy Chang	    <daisyc@us.ibm.com>
   *    Ardelle Fan	    <ardelle.fan@intel.com>
   *    Kevin Gao             <kevin.gao@intel.com>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
   */
145ce502e   Joe Perches   net/sctp: Use pr_...
45
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
5821c7697   Herbert Xu   sctp: Use shash
46
  #include <crypto/hash.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
48
49
50
51
52
  #include <linux/types.h>
  #include <linux/kernel.h>
  #include <linux/ip.h>
  #include <linux/ipv6.h>
  #include <linux/net.h>
  #include <linux/inet.h>
ebc3bbcfc   Christian Borntraeger   Fix sctp compile
53
  #include <linux/scatterlist.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
54
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
57
58
59
60
  #include <net/sock.h>
  
  #include <linux/skbuff.h>
  #include <linux/random.h>	/* for get_random_bytes */
  #include <net/sctp/sctp.h>
  #include <net/sctp/sm.h>
072017b41   Vlad Yasevich   net: sctp: Add ru...
61
  static struct sctp_chunk *sctp_make_control(const struct sctp_association *asoc,
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
62
63
  					    __u8 type, __u8 flags, int paylen,
  					    gfp_t gfp);
072017b41   Vlad Yasevich   net: sctp: Add ru...
64
  static struct sctp_chunk *sctp_make_data(const struct sctp_association *asoc,
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
65
  					 __u8 flags, int paylen, gfp_t gfp);
072017b41   Vlad Yasevich   net: sctp: Add ru...
66
  static struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc,
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
67
68
  					   __u8 type, __u8 flags, int paylen,
  					   gfp_t gfp);
f48ef4c7f   Xin Long   sctp: remove the ...
69
70
  static struct sctp_cookie_param *sctp_pack_cookie(
  					const struct sctp_endpoint *ep,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
73
74
75
76
77
  					const struct sctp_association *asoc,
  					const struct sctp_chunk *init_chunk,
  					int *cookie_len,
  					const __u8 *raw_addrs, int addrs_len);
  static int sctp_process_param(struct sctp_association *asoc,
  			      union sctp_params param,
  			      const union sctp_addr *peer_addr,
dd0fc66fb   Al Viro   [PATCH] gfp flags...
78
  			      gfp_t gfp);
8ee4be37e   Vlad Yasevich   SCTP: Fix the sup...
79
80
  static void *sctp_addto_param(struct sctp_chunk *chunk, int len,
  			      const void *data);
6daaf0de2   stephen hemminger   sctp: make sctp_a...
81
82
  static void  *sctp_addto_chunk_fixed(struct sctp_chunk *, int len,
  				     const void *data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83

072017b41   Vlad Yasevich   net: sctp: Add ru...
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
  /* Control chunk destructor */
  static void sctp_control_release_owner(struct sk_buff *skb)
  {
  	/*TODO: do memory release */
  }
  
  static void sctp_control_set_owner_w(struct sctp_chunk *chunk)
  {
  	struct sctp_association *asoc = chunk->asoc;
  	struct sk_buff *skb = chunk->skb;
  
  	/* TODO: properly account for control chunks.
  	 * To do it right we'll need:
  	 *  1) endpoint if association isn't known.
  	 *  2) proper memory accounting.
  	 *
  	 *  For now don't do anything for now.
  	 */
  	skb->sk = asoc ? asoc->base.sk : NULL;
  	skb->destructor = sctp_control_release_owner;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
106
107
  /* What was the inbound interface for this chunk? */
  int sctp_chunk_iif(const struct sctp_chunk *chunk)
  {
e7487c86d   Marcelo Ricardo Leitner   sctp: avoid ident...
108
  	struct sk_buff *skb = chunk->skb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109

e7487c86d   Marcelo Ricardo Leitner   sctp: avoid ident...
110
  	return SCTP_INPUT_CB(skb)->af->skb_iif(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
111
112
113
114
115
116
117
118
119
  }
  
  /* RFC 2960 3.3.2 Initiation (INIT) (1)
   *
   * Note 2: The ECN capable field is reserved for future use of
   * Explicit Congestion Notification.
   */
  static const struct sctp_paramhdr ecap_param = {
  	SCTP_PARAM_ECN_CAPABLE,
09640e636   Harvey Harrison   net: replace uses...
120
  	cpu_to_be16(sizeof(struct sctp_paramhdr)),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
122
123
  };
  static const struct sctp_paramhdr prsctp_param = {
  	SCTP_PARAM_FWD_TSN_SUPPORT,
09640e636   Harvey Harrison   net: replace uses...
124
  	cpu_to_be16(sizeof(struct sctp_paramhdr)),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
  };
5fa782c2f   Neil Horman   sctp: Fix skb_ove...
126
  /* A helper to initialize an op error inside a
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
128
129
   * provided chunk, as most cause codes will be embedded inside an
   * abort chunk.
   */
327c0dab8   Xin Long   sctp: fix some in...
130
131
  void sctp_init_cause(struct sctp_chunk *chunk, __be16 cause_code,
  		     size_t paylen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
  {
d8238d9da   Xin Long   sctp: remove the ...
133
  	struct sctp_errhdr err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
  	__u16 len;
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
135
  	/* Cause code constants are now defined in network order.  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
  	err.cause = cause_code;
d8238d9da   Xin Long   sctp: remove the ...
137
  	len = sizeof(err) + paylen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138
  	err.length  = htons(len);
d8238d9da   Xin Long   sctp: remove the ...
139
  	chunk->subh.err_hdr = sctp_addto_chunk(chunk, sizeof(err), &err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
  }
5fa782c2f   Neil Horman   sctp: Fix skb_ove...
141
142
143
144
145
  /* A helper to initialize an op error inside a
   * provided chunk, as most cause codes will be embedded inside an
   * abort chunk.  Differs from sctp_init_cause in that it won't oops
   * if there isn't enough space in the op error chunk
   */
db28aafad   Ioan Orghici   sctp: fix sparse ...
146
  static int sctp_init_cause_fixed(struct sctp_chunk *chunk, __be16 cause_code,
327c0dab8   Xin Long   sctp: fix some in...
147
  				 size_t paylen)
5fa782c2f   Neil Horman   sctp: Fix skb_ove...
148
  {
d8238d9da   Xin Long   sctp: remove the ...
149
  	struct sctp_errhdr err;
5fa782c2f   Neil Horman   sctp: Fix skb_ove...
150
151
152
153
  	__u16 len;
  
  	/* Cause code constants are now defined in network order.  */
  	err.cause = cause_code;
d8238d9da   Xin Long   sctp: remove the ...
154
  	len = sizeof(err) + paylen;
5fa782c2f   Neil Horman   sctp: Fix skb_ove...
155
  	err.length  = htons(len);
2e3219b5c   Wei Yongjun   sctp: fix append ...
156
  	if (skb_tailroom(chunk->skb) < len)
5fa782c2f   Neil Horman   sctp: Fix skb_ove...
157
  		return -ENOSPC;
d8238d9da   Xin Long   sctp: remove the ...
158
159
  
  	chunk->subh.err_hdr = sctp_addto_chunk_fixed(chunk, sizeof(err), &err);
5fa782c2f   Neil Horman   sctp: Fix skb_ove...
160
161
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
  /* 3.3.2 Initiation (INIT) (1)
   *
   * This chunk is used to initiate a SCTP association between two
   * endpoints. The format of the INIT chunk is shown below:
   *
   *     0                   1                   2                   3
   *     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *    |   Type = 1    |  Chunk Flags  |      Chunk Length             |
   *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *    |                         Initiate Tag                          |
   *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *    |           Advertised Receiver Window Credit (a_rwnd)          |
   *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *    |  Number of Outbound Streams   |  Number of Inbound Streams    |
   *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *    |                          Initial TSN                          |
   *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *    \                                                               \
   *    /              Optional/Variable-Length Parameters              /
   *    \                                                               \
   *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *
   *
   * The INIT chunk contains the following parameters. Unless otherwise
   * noted, each parameter MUST only be included once in the INIT chunk.
   *
   * Fixed Parameters                     Status
   * ----------------------------------------------
   * Initiate Tag                        Mandatory
   * Advertised Receiver Window Credit   Mandatory
   * Number of Outbound Streams          Mandatory
   * Number of Inbound Streams           Mandatory
   * Initial TSN                         Mandatory
   *
   * Variable Parameters                  Status     Type Value
   * -------------------------------------------------------------
   * IPv4 Address (Note 1)               Optional    5
   * IPv6 Address (Note 1)               Optional    6
   * Cookie Preservative                 Optional    9
   * Reserved for ECN Capable (Note 2)   Optional    32768 (0x8000)
   * Host Name Address (Note 3)          Optional    11
   * Supported Address Types (Note 4)    Optional    12
   */
  struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
327c0dab8   Xin Long   sctp: fix some in...
207
208
  				  const struct sctp_bind_addr *bp,
  				  gfp_t gfp, int vparam_len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
209
  {
e1fc3b14f   Eric W. Biederman   sctp: Make sysctl...
210
  	struct net *net = sock_net(asoc->base.sk);
327c0dab8   Xin Long   sctp: fix some in...
211
212
213
214
215
  	struct sctp_supported_ext_param ext_param;
  	struct sctp_adaptation_ind_param aiparam;
  	struct sctp_paramhdr *auth_chunks = NULL;
  	struct sctp_paramhdr *auth_hmacs = NULL;
  	struct sctp_supported_addrs_param sat;
b14878ccb   Vlad Yasevich   net: sctp: cache ...
216
  	struct sctp_endpoint *ep = asoc->ep;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
218
  	struct sctp_chunk *retval = NULL;
  	int num_types, addrs_len = 0;
327c0dab8   Xin Long   sctp: fix some in...
219
220
  	struct sctp_inithdr init;
  	union sctp_params addrs;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
  	struct sctp_sock *sp;
327c0dab8   Xin Long   sctp: fix some in...
222
223
  	__u8 extensions[4];
  	size_t chunksize;
3dbe86566   Al Viro   [SCTP]: Annotate ...
224
  	__be16 types[2];
131a47e31   Vlad Yasevich   [SCTP]: Implement...
225
  	int num_ext = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
228
229
230
231
  
  	/* RFC 2960 3.3.2 Initiation (INIT) (1)
  	 *
  	 * Note 1: The INIT chunks can contain multiple addresses that
  	 * can be IPv4 and/or IPv6 in any combination.
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
233
234
235
236
237
238
239
240
241
242
243
244
  
  	/* Convert the provided bind address list to raw format. */
  	addrs = sctp_bind_addrs_to_raw(bp, &addrs_len, gfp);
  
  	init.init_tag		   = htonl(asoc->c.my_vtag);
  	init.a_rwnd		   = htonl(asoc->rwnd);
  	init.num_outbound_streams  = htons(asoc->c.sinit_num_ostreams);
  	init.num_inbound_streams   = htons(asoc->c.sinit_max_instreams);
  	init.initial_tsn	   = htonl(asoc->c.initial_tsn);
  
  	/* How many address types are needed? */
  	sp = sctp_sk(asoc->base.sk);
  	num_types = sp->pf->supported_addrs(sp, types);
a8170c35e   Wei Yongjun   sctp: fix to calc...
245
  	chunksize = sizeof(init) + addrs_len;
e2f036a97   Marcelo Ricardo Leitner   sctp: rename WORD...
246
  	chunksize += SCTP_PAD4(SCTP_SAT_LEN(num_types));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
  	chunksize += sizeof(ecap_param);
8ee4be37e   Vlad Yasevich   SCTP: Fix the sup...
248

28aa4c26f   Xin Long   sctp: add SCTP_PR...
249
  	if (asoc->prsctp_enable)
036b579b1   Vlad Yasevich   [SCTP]: Add back ...
250
  		chunksize += sizeof(prsctp_param);
131a47e31   Vlad Yasevich   [SCTP]: Implement...
251
252
253
254
  	/* ADDIP: Section 4.2.7:
  	 *  An implementation supporting this extension [ADDIP] MUST list
  	 *  the ASCONF,the ASCONF-ACK, and the AUTH  chunks in its INIT and
  	 *  INIT-ACK parameters.
131a47e31   Vlad Yasevich   [SCTP]: Implement...
255
  	 */
e1fc3b14f   Eric W. Biederman   sctp: Make sysctl...
256
  	if (net->sctp.addip_enable) {
131a47e31   Vlad Yasevich   [SCTP]: Implement...
257
258
259
260
  		extensions[num_ext] = SCTP_CID_ASCONF;
  		extensions[num_ext+1] = SCTP_CID_ASCONF_ACK;
  		num_ext += 2;
  	}
c28445c3c   Xin Long   sctp: add reconf_...
261
262
263
264
  	if (asoc->reconf_enable) {
  		extensions[num_ext] = SCTP_CID_RECONF;
  		num_ext += 1;
  	}
6fc791ee6   malc   sctp: add Adaptat...
265
266
  	if (sp->adaptation_ind)
  		chunksize += sizeof(aiparam);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
267
  	chunksize += vparam_len;
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
268
  	/* Account for AUTH related parameters */
b14878ccb   Vlad Yasevich   net: sctp: cache ...
269
  	if (ep->auth_enable) {
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
270
271
272
273
  		/* Add random parameter length*/
  		chunksize += sizeof(asoc->c.auth_random);
  
  		/* Add HMACS parameter length if any were defined */
3c9187049   Xin Long   sctp: remove the ...
274
  		auth_hmacs = (struct sctp_paramhdr *)asoc->c.auth_hmacs;
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
275
  		if (auth_hmacs->length)
e2f036a97   Marcelo Ricardo Leitner   sctp: rename WORD...
276
  			chunksize += SCTP_PAD4(ntohs(auth_hmacs->length));
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
277
278
279
280
  		else
  			auth_hmacs = NULL;
  
  		/* Add CHUNKS parameter length */
3c9187049   Xin Long   sctp: remove the ...
281
  		auth_chunks = (struct sctp_paramhdr *)asoc->c.auth_chunks;
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
282
  		if (auth_chunks->length)
e2f036a97   Marcelo Ricardo Leitner   sctp: rename WORD...
283
  			chunksize += SCTP_PAD4(ntohs(auth_chunks->length));
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
284
  		else
9baffaa68   Vlad Yasevich   SCTP: Fix SCTP-AU...
285
  			auth_chunks = NULL;
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
286
287
288
289
  
  		extensions[num_ext] = SCTP_CID_AUTH;
  		num_ext += 1;
  	}
131a47e31   Vlad Yasevich   [SCTP]: Implement...
290
291
  	/* If we have any extensions to report, account for that */
  	if (num_ext)
15328d9fe   Xin Long   sctp: remove the ...
292
  		chunksize += SCTP_PAD4(sizeof(ext_param) + num_ext);
131a47e31   Vlad Yasevich   [SCTP]: Implement...
293

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
295
296
297
298
299
300
301
302
303
304
  	/* RFC 2960 3.3.2 Initiation (INIT) (1)
  	 *
  	 * Note 3: An INIT chunk MUST NOT contain more than one Host
  	 * Name address parameter. Moreover, the sender of the INIT
  	 * MUST NOT combine any other address types with the Host Name
  	 * address in the INIT. The receiver of INIT MUST ignore any
  	 * other address types if the Host Name address parameter is
  	 * present in the received INIT chunk.
  	 *
  	 * PLEASE DO NOT FIXME [This version does not support Host Name.]
  	 */
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
305
  	retval = sctp_make_control(asoc, SCTP_CID_INIT, 0, chunksize, gfp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
  	if (!retval)
  		goto nodata;
  
  	retval->subh.init_hdr =
  		sctp_addto_chunk(retval, sizeof(init), &init);
  	retval->param_hdr.v =
  		sctp_addto_chunk(retval, addrs_len, addrs.v);
  
  	/* RFC 2960 3.3.2 Initiation (INIT) (1)
  	 *
  	 * Note 4: This parameter, when present, specifies all the
  	 * address types the sending endpoint can support. The absence
  	 * of this parameter indicates that the sending endpoint can
  	 * support any address type.
  	 */
  	sat.param_hdr.type = SCTP_PARAM_SUPPORTED_ADDRESS_TYPES;
  	sat.param_hdr.length = htons(SCTP_SAT_LEN(num_types));
  	sctp_addto_chunk(retval, sizeof(sat), &sat);
  	sctp_addto_chunk(retval, num_types * sizeof(__u16), &types);
  
  	sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param);
131a47e31   Vlad Yasevich   [SCTP]: Implement...
327

7aa1b54b7   Joe Perches   [SCTP]: Spelling ...
328
  	/* Add the supported extensions parameter.  Be nice and add this
131a47e31   Vlad Yasevich   [SCTP]: Implement...
329
330
331
332
  	 * fist before addiding the parameters for the extensions themselves
  	 */
  	if (num_ext) {
  		ext_param.param_hdr.type = SCTP_PARAM_SUPPORTED_EXT;
15328d9fe   Xin Long   sctp: remove the ...
333
334
  		ext_param.param_hdr.length = htons(sizeof(ext_param) + num_ext);
  		sctp_addto_chunk(retval, sizeof(ext_param), &ext_param);
8ee4be37e   Vlad Yasevich   SCTP: Fix the sup...
335
  		sctp_addto_param(retval, num_ext, extensions);
131a47e31   Vlad Yasevich   [SCTP]: Implement...
336
  	}
28aa4c26f   Xin Long   sctp: add SCTP_PR...
337
  	if (asoc->prsctp_enable)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338
  		sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param);
131a47e31   Vlad Yasevich   [SCTP]: Implement...
339

6fc791ee6   malc   sctp: add Adaptat...
340
341
342
343
344
345
  	if (sp->adaptation_ind) {
  		aiparam.param_hdr.type = SCTP_PARAM_ADAPTATION_LAYER_IND;
  		aiparam.param_hdr.length = htons(sizeof(aiparam));
  		aiparam.adaptation_ind = htonl(sp->adaptation_ind);
  		sctp_addto_chunk(retval, sizeof(aiparam), &aiparam);
  	}
131a47e31   Vlad Yasevich   [SCTP]: Implement...
346

730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
347
  	/* Add SCTP-AUTH chunks to the parameter list */
b14878ccb   Vlad Yasevich   net: sctp: cache ...
348
  	if (ep->auth_enable) {
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
349
350
351
352
353
354
355
356
357
  		sctp_addto_chunk(retval, sizeof(asoc->c.auth_random),
  				 asoc->c.auth_random);
  		if (auth_hmacs)
  			sctp_addto_chunk(retval, ntohs(auth_hmacs->length),
  					auth_hmacs);
  		if (auth_chunks)
  			sctp_addto_chunk(retval, ntohs(auth_chunks->length),
  					auth_chunks);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
  nodata:
a51482bde   Jesper Juhl   [NET]: kfree cleanup
359
  	kfree(addrs.v);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360
361
362
363
  	return retval;
  }
  
  struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
327c0dab8   Xin Long   sctp: fix some in...
364
365
  				      const struct sctp_chunk *chunk,
  				      gfp_t gfp, int unkparam_len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
  {
327c0dab8   Xin Long   sctp: fix some in...
367
368
369
370
371
372
373
  	struct sctp_supported_ext_param ext_param;
  	struct sctp_adaptation_ind_param aiparam;
  	struct sctp_paramhdr *auth_chunks = NULL;
  	struct sctp_paramhdr *auth_random = NULL;
  	struct sctp_paramhdr *auth_hmacs = NULL;
  	struct sctp_chunk *retval = NULL;
  	struct sctp_cookie_param *cookie;
4ae70c084   Xin Long   sctp: remove the ...
374
  	struct sctp_inithdr initack;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375
  	union sctp_params addrs;
6fc791ee6   malc   sctp: add Adaptat...
376
  	struct sctp_sock *sp;
327c0dab8   Xin Long   sctp: fix some in...
377
  	__u8 extensions[4];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378
  	size_t chunksize;
131a47e31   Vlad Yasevich   [SCTP]: Implement...
379
  	int num_ext = 0;
327c0dab8   Xin Long   sctp: fix some in...
380
381
  	int cookie_len;
  	int addrs_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
  
  	/* Note: there may be no addresses to embed. */
  	addrs = sctp_bind_addrs_to_raw(&asoc->base.bind_addr, &addrs_len, gfp);
  
  	initack.init_tag	        = htonl(asoc->c.my_vtag);
  	initack.a_rwnd			= htonl(asoc->rwnd);
  	initack.num_outbound_streams	= htons(asoc->c.sinit_num_ostreams);
  	initack.num_inbound_streams	= htons(asoc->c.sinit_max_instreams);
  	initack.initial_tsn		= htonl(asoc->c.initial_tsn);
  
  	/* FIXME:  We really ought to build the cookie right
  	 * into the packet instead of allocating more fresh memory.
  	 */
  	cookie = sctp_pack_cookie(asoc->ep, asoc, chunk, &cookie_len,
  				  addrs.v, addrs_len);
  	if (!cookie)
  		goto nomem_cookie;
  
  	/* Calculate the total size of allocation, include the reserved
  	 * space for reporting unknown parameters if it is specified.
  	 */
6fc791ee6   malc   sctp: add Adaptat...
403
  	sp = sctp_sk(asoc->base.sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
  	chunksize = sizeof(initack) + addrs_len + cookie_len + unkparam_len;
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
405
  	/* Tell peer that we'll do ECN only if peer advertised such cap.  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
406
407
  	if (asoc->peer.ecn_capable)
  		chunksize += sizeof(ecap_param);
5ffad5ace   Wei Yongjun   sctp: fix to indi...
408
  	if (asoc->peer.prsctp_capable)
036b579b1   Vlad Yasevich   [SCTP]: Add back ...
409
  		chunksize += sizeof(prsctp_param);
5ffad5ace   Wei Yongjun   sctp: fix to indi...
410
  	if (asoc->peer.asconf_capable) {
131a47e31   Vlad Yasevich   [SCTP]: Implement...
411
412
413
414
  		extensions[num_ext] = SCTP_CID_ASCONF;
  		extensions[num_ext+1] = SCTP_CID_ASCONF_ACK;
  		num_ext += 2;
  	}
c28445c3c   Xin Long   sctp: add reconf_...
415
416
417
418
  	if (asoc->peer.reconf_capable) {
  		extensions[num_ext] = SCTP_CID_RECONF;
  		num_ext += 1;
  	}
6fc791ee6   malc   sctp: add Adaptat...
419
420
  	if (sp->adaptation_ind)
  		chunksize += sizeof(aiparam);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421

730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
422
  	if (asoc->peer.auth_capable) {
3c9187049   Xin Long   sctp: remove the ...
423
  		auth_random = (struct sctp_paramhdr *)asoc->c.auth_random;
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
424
  		chunksize += ntohs(auth_random->length);
3c9187049   Xin Long   sctp: remove the ...
425
  		auth_hmacs = (struct sctp_paramhdr *)asoc->c.auth_hmacs;
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
426
  		if (auth_hmacs->length)
e2f036a97   Marcelo Ricardo Leitner   sctp: rename WORD...
427
  			chunksize += SCTP_PAD4(ntohs(auth_hmacs->length));
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
428
429
  		else
  			auth_hmacs = NULL;
3c9187049   Xin Long   sctp: remove the ...
430
  		auth_chunks = (struct sctp_paramhdr *)asoc->c.auth_chunks;
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
431
  		if (auth_chunks->length)
e2f036a97   Marcelo Ricardo Leitner   sctp: rename WORD...
432
  			chunksize += SCTP_PAD4(ntohs(auth_chunks->length));
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
433
434
435
436
437
438
  		else
  			auth_chunks = NULL;
  
  		extensions[num_ext] = SCTP_CID_AUTH;
  		num_ext += 1;
  	}
8ee4be37e   Vlad Yasevich   SCTP: Fix the sup...
439
  	if (num_ext)
15328d9fe   Xin Long   sctp: remove the ...
440
  		chunksize += SCTP_PAD4(sizeof(ext_param) + num_ext);
8ee4be37e   Vlad Yasevich   SCTP: Fix the sup...
441

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
  	/* Now allocate and fill out the chunk.  */
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
443
  	retval = sctp_make_control(asoc, SCTP_CID_INIT_ACK, 0, chunksize, gfp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
444
445
  	if (!retval)
  		goto nomem_chunk;
b99a4d53a   Dan Carpenter   sctp: cleanup: re...
446
447
448
449
450
451
452
453
  	/* RFC 2960 6.4 Multi-homed SCTP Endpoints
  	 *
  	 * An endpoint SHOULD transmit reply chunks (e.g., SACK,
  	 * HEARTBEAT ACK, * etc.) to the same destination transport
  	 * address from which it received the DATA or control chunk
  	 * to which it is replying.
  	 *
  	 * [INIT ACK back to where the INIT came from.]
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454
455
  	 */
  	retval->transport = chunk->transport;
b99a4d53a   Dan Carpenter   sctp: cleanup: re...
456

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457
458
459
460
461
462
  	retval->subh.init_hdr =
  		sctp_addto_chunk(retval, sizeof(initack), &initack);
  	retval->param_hdr.v = sctp_addto_chunk(retval, addrs_len, addrs.v);
  	sctp_addto_chunk(retval, cookie_len, cookie);
  	if (asoc->peer.ecn_capable)
  		sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param);
131a47e31   Vlad Yasevich   [SCTP]: Implement...
463
464
  	if (num_ext) {
  		ext_param.param_hdr.type = SCTP_PARAM_SUPPORTED_EXT;
15328d9fe   Xin Long   sctp: remove the ...
465
466
  		ext_param.param_hdr.length = htons(sizeof(ext_param) + num_ext);
  		sctp_addto_chunk(retval, sizeof(ext_param), &ext_param);
8ee4be37e   Vlad Yasevich   SCTP: Fix the sup...
467
  		sctp_addto_param(retval, num_ext, extensions);
131a47e31   Vlad Yasevich   [SCTP]: Implement...
468
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
470
  	if (asoc->peer.prsctp_capable)
  		sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param);
6fc791ee6   malc   sctp: add Adaptat...
471
472
473
474
475
476
  	if (sp->adaptation_ind) {
  		aiparam.param_hdr.type = SCTP_PARAM_ADAPTATION_LAYER_IND;
  		aiparam.param_hdr.length = htons(sizeof(aiparam));
  		aiparam.adaptation_ind = htonl(sp->adaptation_ind);
  		sctp_addto_chunk(retval, sizeof(aiparam), &aiparam);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477

730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
478
479
480
481
482
483
484
485
486
487
  	if (asoc->peer.auth_capable) {
  		sctp_addto_chunk(retval, ntohs(auth_random->length),
  				 auth_random);
  		if (auth_hmacs)
  			sctp_addto_chunk(retval, ntohs(auth_hmacs->length),
  					auth_hmacs);
  		if (auth_chunks)
  			sctp_addto_chunk(retval, ntohs(auth_chunks->length),
  					auth_chunks);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
488
489
  	/* We need to remove the const qualifier at this point.  */
  	retval->asoc = (struct sctp_association *) asoc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
491
492
  nomem_chunk:
  	kfree(cookie);
  nomem_cookie:
a51482bde   Jesper Juhl   [NET]: kfree cleanup
493
  	kfree(addrs.v);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
  	return retval;
  }
  
  /* 3.3.11 Cookie Echo (COOKIE ECHO) (10):
   *
   * This chunk is used only during the initialization of an association.
   * It is sent by the initiator of an association to its peer to complete
   * the initialization process. This chunk MUST precede any DATA chunk
   * sent within the association, but MAY be bundled with one or more DATA
   * chunks in the same packet.
   *
   *      0                   1                   2                   3
   *      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *     |   Type = 10   |Chunk  Flags   |         Length                |
   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *     /                     Cookie                                    /
   *     \                                                               \
   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *
   * Chunk Flags: 8 bit
   *
   *   Set to zero on transmit and ignored on receipt.
   *
   * Length: 16 bits (unsigned integer)
   *
   *   Set to the size of the chunk in bytes, including the 4 bytes of
   *   the chunk header and the size of the Cookie.
   *
   * Cookie: variable size
   *
   *   This field must contain the exact cookie received in the
   *   State Cookie parameter from the previous INIT ACK.
   *
   *   An implementation SHOULD make the cookie as small as possible
   *   to insure interoperability.
   */
  struct sctp_chunk *sctp_make_cookie_echo(const struct sctp_association *asoc,
327c0dab8   Xin Long   sctp: fix some in...
532
  					 const struct sctp_chunk *chunk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
534
  {
  	struct sctp_chunk *retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
  	int cookie_len;
327c0dab8   Xin Long   sctp: fix some in...
536
  	void *cookie;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
538
539
540
541
  
  	cookie = asoc->peer.cookie;
  	cookie_len = asoc->peer.cookie_len;
  
  	/* Build a cookie echo chunk.  */
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
542
543
  	retval = sctp_make_control(asoc, SCTP_CID_COOKIE_ECHO, 0,
  				   cookie_len, GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
  	if (!retval)
  		goto nodata;
  	retval->subh.cookie_hdr =
  		sctp_addto_chunk(retval, cookie_len, cookie);
  
  	/* RFC 2960 6.4 Multi-homed SCTP Endpoints
  	 *
  	 * An endpoint SHOULD transmit reply chunks (e.g., SACK,
  	 * HEARTBEAT ACK, * etc.) to the same destination transport
  	 * address from which it * received the DATA or control chunk
  	 * to which it is replying.
  	 *
  	 * [COOKIE ECHO back to where the INIT ACK came from.]
  	 */
  	if (chunk)
  		retval->transport = chunk->transport;
  
  nodata:
  	return retval;
  }
  
  /* 3.3.12 Cookie Acknowledgement (COOKIE ACK) (11):
   *
   * This chunk is used only during the initialization of an
   * association.  It is used to acknowledge the receipt of a COOKIE
   * ECHO chunk.  This chunk MUST precede any DATA or SACK chunk sent
   * within the association, but MAY be bundled with one or more DATA
   * chunks or SACK chunk in the same SCTP packet.
   *
   *      0                   1                   2                   3
   *      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *     |   Type = 11   |Chunk  Flags   |     Length = 4                |
   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *
   * Chunk Flags: 8 bits
   *
   *   Set to zero on transmit and ignored on receipt.
   */
  struct sctp_chunk *sctp_make_cookie_ack(const struct sctp_association *asoc,
327c0dab8   Xin Long   sctp: fix some in...
584
  					const struct sctp_chunk *chunk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
586
  {
  	struct sctp_chunk *retval;
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
587
  	retval = sctp_make_control(asoc, SCTP_CID_COOKIE_ACK, 0, 0, GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
  
  	/* RFC 2960 6.4 Multi-homed SCTP Endpoints
  	 *
  	 * An endpoint SHOULD transmit reply chunks (e.g., SACK,
  	 * HEARTBEAT ACK, * etc.) to the same destination transport
  	 * address from which it * received the DATA or control chunk
  	 * to which it is replying.
  	 *
  	 * [COOKIE ACK back to where the COOKIE ECHO came from.]
  	 */
  	if (retval && chunk)
  		retval->transport = chunk->transport;
  
  	return retval;
  }
  
  /*
   *  Appendix A: Explicit Congestion Notification:
   *  CWR:
   *
   *  RFC 2481 details a specific bit for a sender to send in the header of
   *  its next outbound TCP segment to indicate to its peer that it has
   *  reduced its congestion window.  This is termed the CWR bit.  For
   *  SCTP the same indication is made by including the CWR chunk.
   *  This chunk contains one data element, i.e. the TSN number that
   *  was sent in the ECNE chunk.  This element represents the lowest
   *  TSN number in the datagram that was originally marked with the
   *  CE bit.
   *
   *     0                   1                   2                   3
   *     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *    | Chunk Type=13 | Flags=00000000|    Chunk Length = 8           |
   *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *    |                      Lowest TSN Number                        |
   *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *
   *     Note: The CWR is considered a Control chunk.
   */
  struct sctp_chunk *sctp_make_cwr(const struct sctp_association *asoc,
327c0dab8   Xin Long   sctp: fix some in...
628
629
  				 const __u32 lowest_tsn,
  				 const struct sctp_chunk *chunk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
631
  {
  	struct sctp_chunk *retval;
65f771054   Xin Long   sctp: remove the ...
632
  	struct sctp_cwrhdr cwr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
633
634
  
  	cwr.lowest_tsn = htonl(lowest_tsn);
072017b41   Vlad Yasevich   net: sctp: Add ru...
635
  	retval = sctp_make_control(asoc, SCTP_CID_ECN_CWR, 0,
65f771054   Xin Long   sctp: remove the ...
636
  				   sizeof(cwr), GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
  
  	if (!retval)
  		goto nodata;
  
  	retval->subh.ecn_cwr_hdr =
  		sctp_addto_chunk(retval, sizeof(cwr), &cwr);
  
  	/* RFC 2960 6.4 Multi-homed SCTP Endpoints
  	 *
  	 * An endpoint SHOULD transmit reply chunks (e.g., SACK,
  	 * HEARTBEAT ACK, * etc.) to the same destination transport
  	 * address from which it * received the DATA or control chunk
  	 * to which it is replying.
  	 *
  	 * [Report a reduced congestion window back to where the ECNE
  	 * came from.]
  	 */
  	if (chunk)
  		retval->transport = chunk->transport;
  
  nodata:
  	return retval;
  }
  
  /* Make an ECNE chunk.  This is a congestion experienced report.  */
  struct sctp_chunk *sctp_make_ecne(const struct sctp_association *asoc,
327c0dab8   Xin Long   sctp: fix some in...
663
  				  const __u32 lowest_tsn)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
665
  {
  	struct sctp_chunk *retval;
1fb6d83bd   Xin Long   sctp: remove the ...
666
  	struct sctp_ecnehdr ecne;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667
668
  
  	ecne.lowest_tsn = htonl(lowest_tsn);
072017b41   Vlad Yasevich   net: sctp: Add ru...
669
  	retval = sctp_make_control(asoc, SCTP_CID_ECN_ECNE, 0,
1fb6d83bd   Xin Long   sctp: remove the ...
670
  				   sizeof(ecne), GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671
672
673
674
675
676
677
678
679
680
681
682
683
  	if (!retval)
  		goto nodata;
  	retval->subh.ecne_hdr =
  		sctp_addto_chunk(retval, sizeof(ecne), &ecne);
  
  nodata:
  	return retval;
  }
  
  /* Make a DATA chunk for the given association from the provided
   * parameters.  However, do not populate the data payload.
   */
  struct sctp_chunk *sctp_make_datafrag_empty(struct sctp_association *asoc,
327c0dab8   Xin Long   sctp: fix some in...
684
685
686
  					    const struct sctp_sndrcvinfo *sinfo,
  					    int data_len, __u8 flags, __u16 ssn,
  					    gfp_t gfp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
687
688
689
690
691
692
693
694
695
696
697
698
699
  {
  	struct sctp_chunk *retval;
  	struct sctp_datahdr dp;
  	int chunk_len;
  
  	/* We assign the TSN as LATE as possible, not here when
  	 * creating the chunk.
  	 */
  	dp.tsn = 0;
  	dp.stream = htons(sinfo->sinfo_stream);
  	dp.ppid   = sinfo->sinfo_ppid;
  
  	/* Set the flags for an unordered send.  */
eaa5c54db   Ivan Skytte Jorgensen   [SCTP] Rename SCT...
700
  	if (sinfo->sinfo_flags & SCTP_UNORDERED) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
701
702
703
704
705
706
  		flags |= SCTP_DATA_UNORDERED;
  		dp.ssn = 0;
  	} else
  		dp.ssn = htons(ssn);
  
  	chunk_len = sizeof(dp) + data_len;
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
707
  	retval = sctp_make_data(asoc, flags, chunk_len, gfp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
  	if (!retval)
  		goto nodata;
  
  	retval->subh.data_hdr = sctp_addto_chunk(retval, sizeof(dp), &dp);
  	memcpy(&retval->sinfo, sinfo, sizeof(struct sctp_sndrcvinfo));
  
  nodata:
  	return retval;
  }
  
  /* Create a selective ackowledgement (SACK) for the given
   * association.  This reports on which TSN's we've seen to date,
   * including duplicates and gaps.
   */
  struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
724
  	struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
327c0dab8   Xin Long   sctp: fix some in...
725
  	struct sctp_association *aptr = (struct sctp_association *)asoc;
02015180e   Vlad Yasevich   sctp: shrink sctp...
726
  	struct sctp_gap_ack_block gabs[SCTP_MAX_GABS];
327c0dab8   Xin Long   sctp: fix some in...
727
  	__u16 num_gabs, num_dup_tsns;
4244854d2   Neil Horman   sctp: be more res...
728
  	struct sctp_transport *trans;
327c0dab8   Xin Long   sctp: fix some in...
729
730
731
732
  	struct sctp_chunk *retval;
  	struct sctp_sackhdr sack;
  	__u32 ctsn;
  	int len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
733

02015180e   Vlad Yasevich   sctp: shrink sctp...
734
  	memset(gabs, 0, sizeof(gabs));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
735
  	ctsn = sctp_tsnmap_get_ctsn(map);
bb33381d0   Daniel Borkmann   net: sctp: rework...
736
737
738
  
  	pr_debug("%s: sackCTSNAck sent:0x%x
  ", __func__, ctsn);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
739
740
  
  	/* How much room is needed in the chunk? */
02015180e   Vlad Yasevich   sctp: shrink sctp...
741
  	num_gabs = sctp_tsnmap_num_gabs(map, gabs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
742
743
744
745
746
747
748
749
750
751
752
753
754
  	num_dup_tsns = sctp_tsnmap_num_dups(map);
  
  	/* Initialize the SACK header.  */
  	sack.cum_tsn_ack	    = htonl(ctsn);
  	sack.a_rwnd 		    = htonl(asoc->a_rwnd);
  	sack.num_gap_ack_blocks     = htons(num_gabs);
  	sack.num_dup_tsns           = htons(num_dup_tsns);
  
  	len = sizeof(sack)
  		+ sizeof(struct sctp_gap_ack_block) * num_gabs
  		+ sizeof(__u32) * num_dup_tsns;
  
  	/* Create the chunk.  */
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
755
  	retval = sctp_make_control(asoc, SCTP_CID_SACK, 0, len, GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
  	if (!retval)
  		goto nodata;
  
  	/* RFC 2960 6.4 Multi-homed SCTP Endpoints
  	 *
  	 * An endpoint SHOULD transmit reply chunks (e.g., SACK,
  	 * HEARTBEAT ACK, etc.) to the same destination transport
  	 * address from which it received the DATA or control chunk to
  	 * which it is replying.  This rule should also be followed if
  	 * the endpoint is bundling DATA chunks together with the
  	 * reply chunk.
  	 *
  	 * However, when acknowledging multiple DATA chunks received
  	 * in packets from different source addresses in a single
  	 * SACK, the SACK chunk may be transmitted to one of the
  	 * destination transport addresses from which the DATA or
  	 * control chunks being acknowledged were received.
  	 *
  	 * [BUG:  We do not implement the following paragraph.
  	 * Perhaps we should remember the last transport we used for a
  	 * SACK and avoid that (if possible) if we have seen any
  	 * duplicates. --piggy]
  	 *
  	 * When a receiver of a duplicate DATA chunk sends a SACK to a
  	 * multi- homed endpoint it MAY be beneficial to vary the
  	 * destination address and not use the source address of the
  	 * DATA chunk.  The reason being that receiving a duplicate
  	 * from a multi-homed endpoint might indicate that the return
  	 * path (as specified in the source address of the DATA chunk)
  	 * for the SACK is broken.
  	 *
  	 * [Send to the address from which we last received a DATA chunk.]
  	 */
  	retval->transport = asoc->peer.last_data_from;
  
  	retval->subh.sack_hdr =
  		sctp_addto_chunk(retval, sizeof(sack), &sack);
  
  	/* Add the gap ack block information.   */
  	if (num_gabs)
  		sctp_addto_chunk(retval, sizeof(__u32) * num_gabs,
02015180e   Vlad Yasevich   sctp: shrink sctp...
797
  				 gabs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
798
799
  
  	/* Add the duplicate TSN information.  */
196d67593   Michele Baldessari   sctp: Add support...
800
801
  	if (num_dup_tsns) {
  		aptr->stats.idupchunks += num_dup_tsns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802
803
  		sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
  				 sctp_tsnmap_get_dups(map));
196d67593   Michele Baldessari   sctp: Add support...
804
  	}
4244854d2   Neil Horman   sctp: be more res...
805
806
807
808
809
810
811
812
813
814
815
816
817
818
  	/* Once we have a sack generated, check to see what our sack
  	 * generation is, if its 0, reset the transports to 0, and reset
  	 * the association generation to 1
  	 *
  	 * The idea is that zero is never used as a valid generation for the
  	 * association so no transport will match after a wrap event like this,
  	 * Until the next sack
  	 */
  	if (++aptr->peer.sack_generation == 0) {
  		list_for_each_entry(trans, &asoc->peer.transport_addr_list,
  				    transports)
  			trans->sack_generation = 0;
  		aptr->peer.sack_generation = 1;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
819
820
821
822
823
824
825
826
  nodata:
  	return retval;
  }
  
  /* Make a SHUTDOWN chunk. */
  struct sctp_chunk *sctp_make_shutdown(const struct sctp_association *asoc,
  				      const struct sctp_chunk *chunk)
  {
e61e4055b   Xin Long   sctp: remove the ...
827
  	struct sctp_shutdownhdr shut;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
828
  	struct sctp_chunk *retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829
830
831
832
  	__u32 ctsn;
  
  	ctsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map);
  	shut.cum_tsn_ack = htonl(ctsn);
072017b41   Vlad Yasevich   net: sctp: Add ru...
833
  	retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN, 0,
e61e4055b   Xin Long   sctp: remove the ...
834
  				   sizeof(shut), GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
835
836
837
838
839
840
841
842
843
844
845
846
847
  	if (!retval)
  		goto nodata;
  
  	retval->subh.shutdown_hdr =
  		sctp_addto_chunk(retval, sizeof(shut), &shut);
  
  	if (chunk)
  		retval->transport = chunk->transport;
  nodata:
  	return retval;
  }
  
  struct sctp_chunk *sctp_make_shutdown_ack(const struct sctp_association *asoc,
327c0dab8   Xin Long   sctp: fix some in...
848
  					  const struct sctp_chunk *chunk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
849
850
  {
  	struct sctp_chunk *retval;
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
851
852
  	retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN_ACK, 0, 0,
  				   GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
  
  	/* RFC 2960 6.4 Multi-homed SCTP Endpoints
  	 *
  	 * An endpoint SHOULD transmit reply chunks (e.g., SACK,
  	 * HEARTBEAT ACK, * etc.) to the same destination transport
  	 * address from which it * received the DATA or control chunk
  	 * to which it is replying.
  	 *
  	 * [ACK back to where the SHUTDOWN came from.]
  	 */
  	if (retval && chunk)
  		retval->transport = chunk->transport;
  
  	return retval;
  }
  
  struct sctp_chunk *sctp_make_shutdown_complete(
327c0dab8   Xin Long   sctp: fix some in...
870
871
  					const struct sctp_association *asoc,
  					const struct sctp_chunk *chunk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
872
873
874
  {
  	struct sctp_chunk *retval;
  	__u8 flags = 0;
047a2428a   Jerome Forissier   [SCTP] Implement ...
875
876
877
  	/* Set the T-bit if we have no association (vtag will be
  	 * reflected)
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
878
  	flags |= asoc ? 0 : SCTP_CHUNK_FLAG_T;
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
879
880
  	retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN_COMPLETE, flags,
  				   0, GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
881
882
883
884
885
886
887
888
889
890
891
892
893
  
  	/* RFC 2960 6.4 Multi-homed SCTP Endpoints
  	 *
  	 * An endpoint SHOULD transmit reply chunks (e.g., SACK,
  	 * HEARTBEAT ACK, * etc.) to the same destination transport
  	 * address from which it * received the DATA or control chunk
  	 * to which it is replying.
  	 *
  	 * [Report SHUTDOWN COMPLETE back to where the SHUTDOWN ACK
  	 * came from.]
  	 */
  	if (retval && chunk)
  		retval->transport = chunk->transport;
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
894
  	return retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
895
896
897
  }
  
  /* Create an ABORT.  Note that we set the T bit if we have no
047a2428a   Jerome Forissier   [SCTP] Implement ...
898
   * association, except when responding to an INIT (sctpimpguide 2.41).
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
899
900
   */
  struct sctp_chunk *sctp_make_abort(const struct sctp_association *asoc,
327c0dab8   Xin Long   sctp: fix some in...
901
902
  				   const struct sctp_chunk *chunk,
  				   const size_t hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
903
904
905
  {
  	struct sctp_chunk *retval;
  	__u8 flags = 0;
047a2428a   Jerome Forissier   [SCTP] Implement ...
906
907
908
909
910
911
912
913
914
915
  	/* Set the T-bit if we have no association and 'chunk' is not
  	 * an INIT (vtag will be reflected).
  	 */
  	if (!asoc) {
  		if (chunk && chunk->chunk_hdr &&
  		    chunk->chunk_hdr->type == SCTP_CID_INIT)
  			flags = 0;
  		else
  			flags = SCTP_CHUNK_FLAG_T;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
916

cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
917
918
  	retval = sctp_make_control(asoc, SCTP_CID_ABORT, flags, hint,
  				   GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
  
  	/* RFC 2960 6.4 Multi-homed SCTP Endpoints
  	 *
  	 * An endpoint SHOULD transmit reply chunks (e.g., SACK,
  	 * HEARTBEAT ACK, * etc.) to the same destination transport
  	 * address from which it * received the DATA or control chunk
  	 * to which it is replying.
  	 *
  	 * [ABORT back to where the offender came from.]
  	 */
  	if (retval && chunk)
  		retval->transport = chunk->transport;
  
  	return retval;
  }
  
  /* Helper to create ABORT with a NO_USER_DATA error.  */
  struct sctp_chunk *sctp_make_abort_no_data(
327c0dab8   Xin Long   sctp: fix some in...
937
938
939
  					const struct sctp_association *asoc,
  					const struct sctp_chunk *chunk,
  					__u32 tsn)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
940
941
  {
  	struct sctp_chunk *retval;
9f81bcd94   Al Viro   [SCTP]: More triv...
942
  	__be32 payload;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
943

d8238d9da   Xin Long   sctp: remove the ...
944
945
  	retval = sctp_make_abort(asoc, chunk,
  				 sizeof(struct sctp_errhdr) + sizeof(tsn));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
946
947
948
949
950
951
  
  	if (!retval)
  		goto no_mem;
  
  	/* Put the tsn back into network byte order.  */
  	payload = htonl(tsn);
00f1c2df2   Wei Yongjun   SCTP: Fix to enco...
952
953
  	sctp_init_cause(retval, SCTP_ERROR_NO_DATA, sizeof(payload));
  	sctp_addto_chunk(retval, sizeof(payload), (const void *)&payload);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
  
  	/* RFC 2960 6.4 Multi-homed SCTP Endpoints
  	 *
  	 * An endpoint SHOULD transmit reply chunks (e.g., SACK,
  	 * HEARTBEAT ACK, * etc.) to the same destination transport
  	 * address from which it * received the DATA or control chunk
  	 * to which it is replying.
  	 *
  	 * [ABORT back to where the offender came from.]
  	 */
  	if (chunk)
  		retval->transport = chunk->transport;
  
  no_mem:
  	return retval;
  }
  
  /* Helper to create ABORT with a SCTP_ERROR_USER_ABORT error.  */
  struct sctp_chunk *sctp_make_abort_user(const struct sctp_association *asoc,
6ce8e9ce5   Al Viro   new helper: memcp...
973
  					struct msghdr *msg,
c164a9ba0   Sridhar Samudrala   Fix sctp privileg...
974
  					size_t paylen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
975
976
  {
  	struct sctp_chunk *retval;
c164a9ba0   Sridhar Samudrala   Fix sctp privileg...
977
978
  	void *payload = NULL;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
979

d8238d9da   Xin Long   sctp: remove the ...
980
981
  	retval = sctp_make_abort(asoc, NULL,
  				 sizeof(struct sctp_errhdr) + paylen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
982
983
984
985
986
  	if (!retval)
  		goto err_chunk;
  
  	if (paylen) {
  		/* Put the msg_iov together into payload.  */
c164a9ba0   Sridhar Samudrala   Fix sctp privileg...
987
  		payload = kmalloc(paylen, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
988
989
  		if (!payload)
  			goto err_payload;
c164a9ba0   Sridhar Samudrala   Fix sctp privileg...
990

6ce8e9ce5   Al Viro   new helper: memcp...
991
  		err = memcpy_from_msg(payload, msg, paylen);
c164a9ba0   Sridhar Samudrala   Fix sctp privileg...
992
993
  		if (err < 0)
  			goto err_copy;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
994
  	}
00f1c2df2   Wei Yongjun   SCTP: Fix to enco...
995
996
  	sctp_init_cause(retval, SCTP_ERROR_USER_ABORT, paylen);
  	sctp_addto_chunk(retval, paylen, payload);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
  
  	if (paylen)
  		kfree(payload);
  
  	return retval;
  
  err_copy:
  	kfree(payload);
  err_payload:
  	sctp_chunk_free(retval);
  	retval = NULL;
  err_chunk:
  	return retval;
  }
5c94bf86c   Adrian Bunk   [SCTP]: Make sctp...
1011
1012
1013
1014
1015
1016
  /* Append bytes to the end of a parameter.  Will panic if chunk is not big
   * enough.
   */
  static void *sctp_addto_param(struct sctp_chunk *chunk, int len,
  			      const void *data)
  {
5c94bf86c   Adrian Bunk   [SCTP]: Make sctp...
1017
  	int chunklen = ntohs(chunk->chunk_hdr->length);
327c0dab8   Xin Long   sctp: fix some in...
1018
  	void *target;
5c94bf86c   Adrian Bunk   [SCTP]: Make sctp...
1019
1020
  
  	target = skb_put(chunk->skb, len);
6383cfb3e   Vlad Yasevich   sctp: Fix malform...
1021
1022
1023
1024
  	if (data)
  		memcpy(target, data, len);
  	else
  		memset(target, 0, len);
5c94bf86c   Adrian Bunk   [SCTP]: Make sctp...
1025
1026
1027
1028
1029
1030
1031
  
  	/* Adjust the chunk length field.  */
  	chunk->chunk_hdr->length = htons(chunklen + len);
  	chunk->chunk_end = skb_tail_pointer(chunk->skb);
  
  	return target;
  }
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
1032
  /* Make an ABORT chunk with a PROTOCOL VIOLATION cause code. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1033
  struct sctp_chunk *sctp_make_abort_violation(
327c0dab8   Xin Long   sctp: fix some in...
1034
1035
1036
1037
  					const struct sctp_association *asoc,
  					const struct sctp_chunk *chunk,
  					const __u8 *payload,
  					const size_t paylen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1038
1039
1040
  {
  	struct sctp_chunk  *retval;
  	struct sctp_paramhdr phdr;
d8238d9da   Xin Long   sctp: remove the ...
1041
1042
  	retval = sctp_make_abort(asoc, chunk, sizeof(struct sctp_errhdr) +
  					      paylen + sizeof(phdr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1043
1044
  	if (!retval)
  		goto end;
3c9187049   Xin Long   sctp: remove the ...
1045
1046
  	sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION, paylen +
  							    sizeof(phdr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1047
1048
1049
  
  	phdr.type = htons(chunk->chunk_hdr->type);
  	phdr.length = chunk->chunk_hdr->length;
00f1c2df2   Wei Yongjun   SCTP: Fix to enco...
1050
  	sctp_addto_chunk(retval, paylen, payload);
3c9187049   Xin Long   sctp: remove the ...
1051
  	sctp_addto_param(retval, sizeof(phdr), &phdr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1052
1053
1054
1055
  
  end:
  	return retval;
  }
ba0166708   Wei Yongjun   sctp: Fix kernel ...
1056
  struct sctp_chunk *sctp_make_violation_paramlen(
327c0dab8   Xin Long   sctp: fix some in...
1057
1058
1059
  					const struct sctp_association *asoc,
  					const struct sctp_chunk *chunk,
  					struct sctp_paramhdr *param)
ba0166708   Wei Yongjun   sctp: Fix kernel ...
1060
  {
ba0166708   Wei Yongjun   sctp: Fix kernel ...
1061
  	static const char error[] = "The following parameter had invalid length:";
d8238d9da   Xin Long   sctp: remove the ...
1062
  	size_t payload_len = sizeof(error) + sizeof(struct sctp_errhdr) +
3c9187049   Xin Long   sctp: remove the ...
1063
  			     sizeof(*param);
327c0dab8   Xin Long   sctp: fix some in...
1064
  	struct sctp_chunk *retval;
ba0166708   Wei Yongjun   sctp: Fix kernel ...
1065
1066
1067
1068
1069
1070
  
  	retval = sctp_make_abort(asoc, chunk, payload_len);
  	if (!retval)
  		goto nodata;
  
  	sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION,
3c9187049   Xin Long   sctp: remove the ...
1071
  			sizeof(error) + sizeof(*param));
ba0166708   Wei Yongjun   sctp: Fix kernel ...
1072
  	sctp_addto_chunk(retval, sizeof(error), error);
3c9187049   Xin Long   sctp: remove the ...
1073
  	sctp_addto_param(retval, sizeof(*param), param);
ba0166708   Wei Yongjun   sctp: Fix kernel ...
1074
1075
1076
1077
  
  nodata:
  	return retval;
  }
de4594a51   Neil Horman   sctp: send abort ...
1078
  struct sctp_chunk *sctp_make_violation_max_retrans(
327c0dab8   Xin Long   sctp: fix some in...
1079
1080
  					const struct sctp_association *asoc,
  					const struct sctp_chunk *chunk)
de4594a51   Neil Horman   sctp: send abort ...
1081
  {
de4594a51   Neil Horman   sctp: send abort ...
1082
  	static const char error[] = "Association exceeded its max_retans count";
d8238d9da   Xin Long   sctp: remove the ...
1083
  	size_t payload_len = sizeof(error) + sizeof(struct sctp_errhdr);
327c0dab8   Xin Long   sctp: fix some in...
1084
  	struct sctp_chunk *retval;
de4594a51   Neil Horman   sctp: send abort ...
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
  
  	retval = sctp_make_abort(asoc, chunk, payload_len);
  	if (!retval)
  		goto nodata;
  
  	sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION, sizeof(error));
  	sctp_addto_chunk(retval, sizeof(error), error);
  
  nodata:
  	return retval;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1096
1097
  /* Make a HEARTBEAT chunk.  */
  struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc,
edf903f83   Xin Long   sctp: remove the ...
1098
  				       const struct sctp_transport *transport)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1099
  {
edf903f83   Xin Long   sctp: remove the ...
1100
  	struct sctp_sender_hb_info hbinfo;
92c73af58   Wei Yongjun   sctp: make heartb...
1101
  	struct sctp_chunk *retval;
92c73af58   Wei Yongjun   sctp: make heartb...
1102

cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
1103
1104
  	retval = sctp_make_control(asoc, SCTP_CID_HEARTBEAT, 0,
  				   sizeof(hbinfo), GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1105
1106
1107
  
  	if (!retval)
  		goto nodata;
92c73af58   Wei Yongjun   sctp: make heartb...
1108
  	hbinfo.param_hdr.type = SCTP_PARAM_HEARTBEAT_INFO;
edf903f83   Xin Long   sctp: remove the ...
1109
  	hbinfo.param_hdr.length = htons(sizeof(hbinfo));
92c73af58   Wei Yongjun   sctp: make heartb...
1110
1111
1112
  	hbinfo.daddr = transport->ipaddr;
  	hbinfo.sent_at = jiffies;
  	hbinfo.hb_nonce = transport->hb_nonce;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1113
1114
1115
1116
  	/* Cast away the 'const', as this is just telling the chunk
  	 * what transport it belongs to.
  	 */
  	retval->transport = (struct sctp_transport *) transport;
92c73af58   Wei Yongjun   sctp: make heartb...
1117
1118
  	retval->subh.hbs_hdr = sctp_addto_chunk(retval, sizeof(hbinfo),
  						&hbinfo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1119
1120
1121
1122
1123
1124
  
  nodata:
  	return retval;
  }
  
  struct sctp_chunk *sctp_make_heartbeat_ack(const struct sctp_association *asoc,
327c0dab8   Xin Long   sctp: fix some in...
1125
1126
1127
  					   const struct sctp_chunk *chunk,
  					   const void *payload,
  					   const size_t paylen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1128
1129
  {
  	struct sctp_chunk *retval;
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
1130
1131
  	retval  = sctp_make_control(asoc, SCTP_CID_HEARTBEAT_ACK, 0, paylen,
  				    GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
  	if (!retval)
  		goto nodata;
  
  	retval->subh.hbs_hdr = sctp_addto_chunk(retval, paylen, payload);
  
  	/* RFC 2960 6.4 Multi-homed SCTP Endpoints
  	 *
  	 * An endpoint SHOULD transmit reply chunks (e.g., SACK,
  	 * HEARTBEAT ACK, * etc.) to the same destination transport
  	 * address from which it * received the DATA or control chunk
  	 * to which it is replying.
  	 *
  	 * [HBACK back to where the HEARTBEAT came from.]
  	 */
  	if (chunk)
  		retval->transport = chunk->transport;
  
  nodata:
  	return retval;
  }
  
  /* Create an Operation Error chunk with the specified space reserved.
   * This routine can be used for containing multiple causes in the chunk.
   */
  static struct sctp_chunk *sctp_make_op_error_space(
327c0dab8   Xin Long   sctp: fix some in...
1157
1158
1159
  					const struct sctp_association *asoc,
  					const struct sctp_chunk *chunk,
  					size_t size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1160
1161
  {
  	struct sctp_chunk *retval;
072017b41   Vlad Yasevich   net: sctp: Add ru...
1162
  	retval = sctp_make_control(asoc, SCTP_CID_ERROR, 0,
d8238d9da   Xin Long   sctp: remove the ...
1163
1164
  				   sizeof(struct sctp_errhdr) + size,
  				   GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
  	if (!retval)
  		goto nodata;
  
  	/* RFC 2960 6.4 Multi-homed SCTP Endpoints
  	 *
  	 * An endpoint SHOULD transmit reply chunks (e.g., SACK,
  	 * HEARTBEAT ACK, etc.) to the same destination transport
  	 * address from which it received the DATA or control chunk
  	 * to which it is replying.
  	 *
  	 */
  	if (chunk)
  		retval->transport = chunk->transport;
  
  nodata:
  	return retval;
  }
5fa782c2f   Neil Horman   sctp: Fix skb_ove...
1182
1183
1184
1185
  /* Create an Operation Error chunk of a fixed size,
   * specifically, max(asoc->pathmtu, SCTP_DEFAULT_MAXSEGMENT)
   * This is a helper function to allocate an error chunk for
   * for those invalid parameter codes in which we may not want
d82603c6d   Jorrit Schippers   treewide: Replace...
1186
   * to report all the errors, if the incoming chunk is large
5fa782c2f   Neil Horman   sctp: Fix skb_ove...
1187
1188
   */
  static inline struct sctp_chunk *sctp_make_op_error_fixed(
327c0dab8   Xin Long   sctp: fix some in...
1189
1190
  					const struct sctp_association *asoc,
  					const struct sctp_chunk *chunk)
5fa782c2f   Neil Horman   sctp: Fix skb_ove...
1191
1192
1193
1194
1195
1196
1197
1198
  {
  	size_t size = asoc ? asoc->pathmtu : 0;
  
  	if (!size)
  		size = SCTP_DEFAULT_MAXSEGMENT;
  
  	return sctp_make_op_error_space(asoc, chunk, size);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1199
1200
  /* Create an Operation Error chunk.  */
  struct sctp_chunk *sctp_make_op_error(const struct sctp_association *asoc,
327c0dab8   Xin Long   sctp: fix some in...
1201
1202
1203
  				      const struct sctp_chunk *chunk,
  				      __be16 cause_code, const void *payload,
  				      size_t paylen, size_t reserve_tail)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1204
1205
  {
  	struct sctp_chunk *retval;
6383cfb3e   Vlad Yasevich   sctp: Fix malform...
1206
  	retval = sctp_make_op_error_space(asoc, chunk, paylen + reserve_tail);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1207
1208
  	if (!retval)
  		goto nodata;
6383cfb3e   Vlad Yasevich   sctp: Fix malform...
1209
  	sctp_init_cause(retval, cause_code, paylen + reserve_tail);
00f1c2df2   Wei Yongjun   SCTP: Fix to enco...
1210
  	sctp_addto_chunk(retval, paylen, payload);
6383cfb3e   Vlad Yasevich   sctp: Fix malform...
1211
1212
  	if (reserve_tail)
  		sctp_addto_param(retval, reserve_tail, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1213
1214
1215
1216
  
  nodata:
  	return retval;
  }
4cd57c807   Vlad Yasevich   [SCTP]: Enable th...
1217
1218
  struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc)
  {
4cd57c807   Vlad Yasevich   [SCTP]: Enable th...
1219
  	struct sctp_authhdr auth_hdr;
327c0dab8   Xin Long   sctp: fix some in...
1220
1221
  	struct sctp_hmac *hmac_desc;
  	struct sctp_chunk *retval;
4cd57c807   Vlad Yasevich   [SCTP]: Enable th...
1222
1223
1224
1225
1226
1227
  	__u8 *hmac;
  
  	/* Get the first hmac that the peer told us to use */
  	hmac_desc = sctp_auth_asoc_get_hmac(asoc);
  	if (unlikely(!hmac_desc))
  		return NULL;
072017b41   Vlad Yasevich   net: sctp: Add ru...
1228
  	retval = sctp_make_control(asoc, SCTP_CID_AUTH, 0,
96f7ef4d5   Xin Long   sctp: remove the ...
1229
1230
  				   hmac_desc->hmac_len + sizeof(auth_hdr),
  				   GFP_ATOMIC);
4cd57c807   Vlad Yasevich   [SCTP]: Enable th...
1231
1232
1233
1234
1235
  	if (!retval)
  		return NULL;
  
  	auth_hdr.hmac_id = htons(hmac_desc->hmac_id);
  	auth_hdr.shkey_id = htons(asoc->active_key_id);
96f7ef4d5   Xin Long   sctp: remove the ...
1236
1237
  	retval->subh.auth_hdr = sctp_addto_chunk(retval, sizeof(auth_hdr),
  						 &auth_hdr);
4cd57c807   Vlad Yasevich   [SCTP]: Enable th...
1238

aa9f979c4   Johannes Berg   networking: use s...
1239
  	hmac = skb_put_zero(retval->skb, hmac_desc->hmac_len);
4cd57c807   Vlad Yasevich   [SCTP]: Enable th...
1240
1241
1242
1243
1244
1245
1246
1247
  
  	/* Adjust the chunk header to include the empty MAC */
  	retval->chunk_hdr->length =
  		htons(ntohs(retval->chunk_hdr->length) + hmac_desc->hmac_len);
  	retval->chunk_end = skb_tail_pointer(retval->skb);
  
  	return retval;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1248
1249
1250
1251
1252
1253
  /********************************************************************
   * 2nd Level Abstractions
   ********************************************************************/
  
  /* Turn an skb into a chunk.
   * FIXME: Eventually move the structure directly inside the skb->cb[].
3dc0a548a   wangweidong   sctp: remove the ...
1254
1255
1256
1257
1258
1259
1260
   *
   * sctpimpguide-05.txt Section 2.8.2
   * M1) Each time a new DATA chunk is transmitted
   * set the 'TSN.Missing.Report' count for that TSN to 0. The
   * 'TSN.Missing.Report' count will be used to determine missing chunks
   * and when to fast retransmit.
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1261
1262
   */
  struct sctp_chunk *sctp_chunkify(struct sk_buff *skb,
327c0dab8   Xin Long   sctp: fix some in...
1263
1264
  				 const struct sctp_association *asoc,
  				 struct sock *sk, gfp_t gfp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1265
1266
  {
  	struct sctp_chunk *retval;
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
1267
  	retval = kmem_cache_zalloc(sctp_chunk_cachep, gfp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1268
1269
1270
  
  	if (!retval)
  		goto nodata;
bb33381d0   Daniel Borkmann   net: sctp: rework...
1271
1272
1273
  	if (!sk)
  		pr_debug("%s: chunkifying skb:%p w/o an sk
  ", __func__, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1274

79af02c25   David S. Miller   [SCTP]: Use struc...
1275
  	INIT_LIST_HEAD(&retval->list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1276
1277
  	retval->skb		= skb;
  	retval->asoc		= (struct sctp_association *)asoc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1278
  	retval->singleton	= 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1279

3dc0a548a   wangweidong   sctp: remove the ...
1280
  	retval->fast_retransmit = SCTP_CAN_FRTX;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1281
1282
1283
1284
1285
  
  	/* Polish the bead hole.  */
  	INIT_LIST_HEAD(&retval->transmitted_list);
  	INIT_LIST_HEAD(&retval->frag_list);
  	SCTP_DBG_OBJCNT_INC(chunk);
e7f027961   Reshetova, Elena   net, sctp: conver...
1286
  	refcount_set(&retval->refcnt, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1287
1288
1289
1290
1291
1292
1293
1294
1295
  
  nodata:
  	return retval;
  }
  
  /* Set chunk->source and dest based on the IP header in chunk->skb.  */
  void sctp_init_addrs(struct sctp_chunk *chunk, union sctp_addr *src,
  		     union sctp_addr *dest)
  {
f235fca38   Al Viro   [SCTP]: sctp_init...
1296
  	memcpy(&chunk->source, src, sizeof(union sctp_addr));
16b0a0303   Al Viro   [SCTP]: Switch sc...
1297
  	memcpy(&chunk->dest, dest, sizeof(union sctp_addr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1298
1299
1300
1301
1302
1303
1304
  }
  
  /* Extract the source address from a chunk.  */
  const union sctp_addr *sctp_source(const struct sctp_chunk *chunk)
  {
  	/* If we have a known transport, use that.  */
  	if (chunk->transport) {
6a1e5f335   Al Viro   [SCTP]: sctp_proc...
1305
  		return &chunk->transport->ipaddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1306
1307
  	} else {
  		/* Otherwise, extract it from the IP header.  */
6a1e5f335   Al Viro   [SCTP]: sctp_proc...
1308
  		return &chunk->source;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1309
1310
1311
1312
1313
1314
  	}
  }
  
  /* Create a new chunk, setting the type and flags headers from the
   * arguments, reserving enough space for a 'paylen' byte payload.
   */
072017b41   Vlad Yasevich   net: sctp: Add ru...
1315
  static struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc,
327c0dab8   Xin Long   sctp: fix some in...
1316
1317
  					   __u8 type, __u8 flags, int paylen,
  					   gfp_t gfp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1318
  {
922dbc5be   Xin Long   sctp: remove the ...
1319
  	struct sctp_chunkhdr *chunk_hdr;
327c0dab8   Xin Long   sctp: fix some in...
1320
  	struct sctp_chunk *retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1321
1322
  	struct sk_buff *skb;
  	struct sock *sk;
1fc74a57a   Alexey Kodanev   sctp: verify size...
1323
1324
1325
1326
1327
  	int chunklen;
  
  	chunklen = SCTP_PAD4(sizeof(*chunk_hdr) + paylen);
  	if (chunklen > SCTP_MAX_CHUNK_LEN)
  		goto nodata;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1328
1329
  
  	/* No need to allocate LL here, as this is only a chunk. */
1fc74a57a   Alexey Kodanev   sctp: verify size...
1330
  	skb = alloc_skb(chunklen, gfp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1331
1332
1333
1334
  	if (!skb)
  		goto nodata;
  
  	/* Make room for the chunk header.  */
922dbc5be   Xin Long   sctp: remove the ...
1335
  	chunk_hdr = (struct sctp_chunkhdr *)skb_put(skb, sizeof(*chunk_hdr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1336
1337
  	chunk_hdr->type	  = type;
  	chunk_hdr->flags  = flags;
922dbc5be   Xin Long   sctp: remove the ...
1338
  	chunk_hdr->length = htons(sizeof(*chunk_hdr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1339
1340
  
  	sk = asoc ? asoc->base.sk : NULL;
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
1341
  	retval = sctp_chunkify(skb, asoc, sk, gfp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1342
1343
1344
1345
1346
1347
  	if (!retval) {
  		kfree_skb(skb);
  		goto nodata;
  	}
  
  	retval->chunk_hdr = chunk_hdr;
922dbc5be   Xin Long   sctp: remove the ...
1348
  	retval->chunk_end = ((__u8 *)chunk_hdr) + sizeof(*chunk_hdr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1349

4cd57c807   Vlad Yasevich   [SCTP]: Enable th...
1350
1351
1352
  	/* Determine if the chunk needs to be authenticated */
  	if (sctp_auth_send_cid(type, asoc))
  		retval->auth = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1353
1354
1355
1356
  	return retval;
  nodata:
  	return NULL;
  }
072017b41   Vlad Yasevich   net: sctp: Add ru...
1357
  static struct sctp_chunk *sctp_make_data(const struct sctp_association *asoc,
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
1358
  					 __u8 flags, int paylen, gfp_t gfp)
072017b41   Vlad Yasevich   net: sctp: Add ru...
1359
  {
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
1360
  	return _sctp_make_chunk(asoc, SCTP_CID_DATA, flags, paylen, gfp);
072017b41   Vlad Yasevich   net: sctp: Add ru...
1361
1362
1363
  }
  
  static struct sctp_chunk *sctp_make_control(const struct sctp_association *asoc,
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
1364
1365
  					    __u8 type, __u8 flags, int paylen,
  					    gfp_t gfp)
072017b41   Vlad Yasevich   net: sctp: Add ru...
1366
  {
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
1367
  	struct sctp_chunk *chunk;
072017b41   Vlad Yasevich   net: sctp: Add ru...
1368

cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
1369
  	chunk = _sctp_make_chunk(asoc, type, flags, paylen, gfp);
072017b41   Vlad Yasevich   net: sctp: Add ru...
1370
1371
1372
1373
1374
  	if (chunk)
  		sctp_control_set_owner_w(chunk);
  
  	return chunk;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1375
1376
1377
1378
  
  /* Release the memory occupied by a chunk.  */
  static void sctp_chunk_destroy(struct sctp_chunk *chunk)
  {
a08de64d0   Vlad Yasevich   [SCTP]: Update AS...
1379
1380
  	BUG_ON(!list_empty(&chunk->list));
  	list_del_init(&chunk->transmitted_list);
c485658ba   Daniel Borkmann   net: sctp: fix sk...
1381
1382
  	consume_skb(chunk->skb);
  	consume_skb(chunk->auth_chunk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1383
1384
1385
1386
1387
1388
1389
1390
  
  	SCTP_DBG_OBJCNT_DEC(chunk);
  	kmem_cache_free(sctp_chunk_cachep, chunk);
  }
  
  /* Possibly, free the chunk.  */
  void sctp_chunk_free(struct sctp_chunk *chunk)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
  	/* Release our reference on the message tracker. */
  	if (chunk->msg)
  		sctp_datamsg_put(chunk->msg);
  
  	sctp_chunk_put(chunk);
  }
  
  /* Grab a reference to the chunk. */
  void sctp_chunk_hold(struct sctp_chunk *ch)
  {
e7f027961   Reshetova, Elena   net, sctp: conver...
1401
  	refcount_inc(&ch->refcnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1402
1403
1404
1405
1406
  }
  
  /* Release a reference to the chunk. */
  void sctp_chunk_put(struct sctp_chunk *ch)
  {
e7f027961   Reshetova, Elena   net, sctp: conver...
1407
  	if (refcount_dec_and_test(&ch->refcnt))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1408
1409
1410
1411
1412
1413
1414
1415
  		sctp_chunk_destroy(ch);
  }
  
  /* Append bytes to the end of a chunk.  Will panic if chunk is not big
   * enough.
   */
  void *sctp_addto_chunk(struct sctp_chunk *chunk, int len, const void *data)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1416
  	int chunklen = ntohs(chunk->chunk_hdr->length);
e2f036a97   Marcelo Ricardo Leitner   sctp: rename WORD...
1417
  	int padlen = SCTP_PAD4(chunklen) - chunklen;
327c0dab8   Xin Long   sctp: fix some in...
1418
  	void *target;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1419

b952f4dff   yuan linyu   net: manual clean...
1420
  	skb_put_zero(chunk->skb, padlen);
59ae1d127   Johannes Berg   networking: intro...
1421
  	target = skb_put_data(chunk->skb, data, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1422
1423
1424
  
  	/* Adjust the chunk length field.  */
  	chunk->chunk_hdr->length = htons(chunklen + padlen + len);
27a884dc3   Arnaldo Carvalho de Melo   [SK_BUFF]: Conver...
1425
  	chunk->chunk_end = skb_tail_pointer(chunk->skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1426
1427
1428
  
  	return target;
  }
5fa782c2f   Neil Horman   sctp: Fix skb_ove...
1429
1430
1431
  /* Append bytes to the end of a chunk. Returns NULL if there isn't sufficient
   * space in the chunk
   */
6daaf0de2   stephen hemminger   sctp: make sctp_a...
1432
1433
  static void *sctp_addto_chunk_fixed(struct sctp_chunk *chunk,
  				    int len, const void *data)
5fa782c2f   Neil Horman   sctp: Fix skb_ove...
1434
  {
2e3219b5c   Wei Yongjun   sctp: fix append ...
1435
  	if (skb_tailroom(chunk->skb) >= len)
5fa782c2f   Neil Horman   sctp: Fix skb_ove...
1436
1437
1438
1439
  		return sctp_addto_chunk(chunk, len, data);
  	else
  		return NULL;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1440
1441
1442
1443
  /* Append bytes from user space to the end of a chunk.  Will panic if
   * chunk is not big enough.
   * Returns a kernel err value.
   */
e0eb093e7   Al Viro   switch sctp_user_...
1444
1445
  int sctp_user_addto_chunk(struct sctp_chunk *chunk, int len,
  			  struct iov_iter *from)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1446
  {
e0eb093e7   Al Viro   switch sctp_user_...
1447
  	void *target;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1448
1449
1450
1451
1452
  
  	/* Make room in chunk for data.  */
  	target = skb_put(chunk->skb, len);
  
  	/* Copy data (whole iovec) into chunk */
3b6d4dbf0   Al Viro   sctp: switch to c...
1453
  	if (!copy_from_iter_full(target, len, from))
e0eb093e7   Al Viro   switch sctp_user_...
1454
  		return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1455
1456
1457
1458
  
  	/* Adjust the chunk length field.  */
  	chunk->chunk_hdr->length =
  		htons(ntohs(chunk->chunk_hdr->length) + len);
27a884dc3   Arnaldo Carvalho de Melo   [SK_BUFF]: Conver...
1459
  	chunk->chunk_end = skb_tail_pointer(chunk->skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1460

e0eb093e7   Al Viro   switch sctp_user_...
1461
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1462
1463
1464
1465
1466
1467
1468
  }
  
  /* Helper function to assign a TSN if needed.  This assumes that both
   * the data_hdr and association have already been assigned.
   */
  void sctp_chunk_assign_ssn(struct sctp_chunk *chunk)
  {
ab3e5e7b6   Vlad Yasevich   SCTP: Assign stre...
1469
  	struct sctp_stream *stream;
327c0dab8   Xin Long   sctp: fix some in...
1470
1471
1472
  	struct sctp_chunk *lchunk;
  	struct sctp_datamsg *msg;
  	__u16 ssn, sid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1473
1474
1475
  
  	if (chunk->has_ssn)
  		return;
ab3e5e7b6   Vlad Yasevich   SCTP: Assign stre...
1476
1477
  	/* All fragments will be on the same stream */
  	sid = ntohs(chunk->subh.data_hdr->stream);
cee360ab4   Xin Long   sctp: define the ...
1478
  	stream = &chunk->asoc->stream;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1479

ab3e5e7b6   Vlad Yasevich   SCTP: Assign stre...
1480
1481
1482
1483
1484
1485
1486
1487
1488
  	/* Now assign the sequence number to the entire message.
  	 * All fragments must have the same stream sequence number.
  	 */
  	msg = chunk->msg;
  	list_for_each_entry(lchunk, &msg->chunks, frag_list) {
  		if (lchunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) {
  			ssn = 0;
  		} else {
  			if (lchunk->chunk_hdr->flags & SCTP_DATA_LAST_FRAG)
a83863174   Xin Long   sctp: prepare aso...
1489
  				ssn = sctp_ssn_next(stream, out, sid);
ab3e5e7b6   Vlad Yasevich   SCTP: Assign stre...
1490
  			else
a83863174   Xin Long   sctp: prepare aso...
1491
  				ssn = sctp_ssn_peek(stream, out, sid);
ab3e5e7b6   Vlad Yasevich   SCTP: Assign stre...
1492
1493
1494
1495
1496
  		}
  
  		lchunk->subh.data_hdr->ssn = htons(ssn);
  		lchunk->has_ssn = 1;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
  }
  
  /* Helper function to assign a TSN if needed.  This assumes that both
   * the data_hdr and association have already been assigned.
   */
  void sctp_chunk_assign_tsn(struct sctp_chunk *chunk)
  {
  	if (!chunk->has_tsn) {
  		/* This is the last possible instant to
  		 * assign a TSN.
  		 */
  		chunk->subh.data_hdr->tsn =
  			htonl(sctp_association_get_next_tsn(chunk->asoc));
  		chunk->has_tsn = 1;
  	}
  }
  
  /* Create a CLOSED association to use with an incoming packet.  */
  struct sctp_association *sctp_make_temp_asoc(const struct sctp_endpoint *ep,
327c0dab8   Xin Long   sctp: fix some in...
1516
1517
  					     struct sctp_chunk *chunk,
  					     gfp_t gfp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1518
1519
  {
  	struct sctp_association *asoc;
1c662018d   Xin Long   sctp: remove the ...
1520
  	enum sctp_scope scope;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1521
  	struct sk_buff *skb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1522
1523
1524
1525
1526
1527
1528
1529
1530
  
  	/* Create the bare association.  */
  	scope = sctp_scope(sctp_source(chunk));
  	asoc = sctp_association_new(ep, ep->base.sk, scope, gfp);
  	if (!asoc)
  		goto nodata;
  	asoc->temp = 1;
  	skb = chunk->skb;
  	/* Create an entry for the source address of the packet.  */
e7487c86d   Marcelo Ricardo Leitner   sctp: avoid ident...
1531
  	SCTP_INPUT_CB(skb)->af->from_skb(&asoc->c.peer_addr, skb, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1532
1533
  nodata:
  	return asoc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1534
1535
1536
1537
1538
  }
  
  /* Build a cookie representing asoc.
   * This INCLUDES the param header needed to put the cookie in the INIT ACK.
   */
f48ef4c7f   Xin Long   sctp: remove the ...
1539
1540
1541
1542
  static struct sctp_cookie_param *sctp_pack_cookie(
  					const struct sctp_endpoint *ep,
  					const struct sctp_association *asoc,
  					const struct sctp_chunk *init_chunk,
327c0dab8   Xin Long   sctp: fix some in...
1543
1544
  					int *cookie_len, const __u8 *raw_addrs,
  					int addrs_len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1545
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1546
  	struct sctp_signed_cookie *cookie;
f48ef4c7f   Xin Long   sctp: remove the ...
1547
  	struct sctp_cookie_param *retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1548
  	int headersize, bodysize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1549

9834a2bb4   Vlad Yasevich   [SCTP]: Fix sctp_...
1550
1551
1552
  	/* Header size is static data prior to the actual cookie, including
  	 * any padding.
  	 */
3c9187049   Xin Long   sctp: remove the ...
1553
  	headersize = sizeof(struct sctp_paramhdr) +
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
1554
  		     (sizeof(struct sctp_signed_cookie) -
9834a2bb4   Vlad Yasevich   [SCTP]: Fix sctp_...
1555
  		      sizeof(struct sctp_cookie));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
  	bodysize = sizeof(struct sctp_cookie)
  		+ ntohs(init_chunk->chunk_hdr->length) + addrs_len;
  
  	/* Pad out the cookie to a multiple to make the signature
  	 * functions simpler to write.
  	 */
  	if (bodysize % SCTP_COOKIE_MULTIPLE)
  		bodysize += SCTP_COOKIE_MULTIPLE
  			- (bodysize % SCTP_COOKIE_MULTIPLE);
  	*cookie_len = headersize + bodysize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1566
1567
1568
  	/* Clear this memory since we are sending this data structure
  	 * out on the network.
  	 */
af997d8c9   Arnaldo Carvalho de Melo   [SCTP]: Use kzall...
1569
1570
1571
  	retval = kzalloc(*cookie_len, GFP_ATOMIC);
  	if (!retval)
  		goto nodata;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
  	cookie = (struct sctp_signed_cookie *) retval->body;
  
  	/* Set up the parameter header.  */
  	retval->p.type = SCTP_PARAM_STATE_COOKIE;
  	retval->p.length = htons(*cookie_len);
  
  	/* Copy the cookie part of the association itself.  */
  	cookie->c = asoc->c;
  	/* Save the raw address list length in the cookie. */
  	cookie->c.raw_addr_list_len = addrs_len;
  
  	/* Remember PR-SCTP capability. */
  	cookie->c.prsctp_capable = asoc->peer.prsctp_capable;
0f3fffd8a   Ivan Skytte Jorgensen   [SCTP]: Fix typo ...
1585
1586
  	/* Save adaptation indication in the cookie. */
  	cookie->c.adaptation_ind = asoc->peer.adaptation_ind;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1587
1588
  
  	/* Set an expiration time for the cookie.  */
52db882f3   Daniel Borkmann   net: sctp: migrat...
1589
  	cookie->c.expiration = ktime_add(asoc->cookie_life,
cb5e173ed   Marcelo Ricardo Leitner   sctp: use the sam...
1590
  					 ktime_get_real());
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1591
1592
1593
1594
1595
1596
1597
1598
  
  	/* Copy the peer's init packet.  */
  	memcpy(&cookie->c.peer_init[0], init_chunk->chunk_hdr,
  	       ntohs(init_chunk->chunk_hdr->length));
  
  	/* Copy the raw local address list of the association. */
  	memcpy((__u8 *)&cookie->c.peer_init[0] +
  	       ntohs(init_chunk->chunk_hdr->length), raw_addrs, addrs_len);
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
1599
  	if (sctp_sk(ep->base.sk)->hmac) {
5821c7697   Herbert Xu   sctp: Use shash
1600
1601
  		SHASH_DESC_ON_STACK(desc, sctp_sk(ep->base.sk)->hmac);
  		int err;
1b489e11d   Herbert Xu   [SCTP]: Use HMAC ...
1602

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1603
  		/* Sign the message.  */
5821c7697   Herbert Xu   sctp: Use shash
1604
1605
1606
1607
1608
1609
1610
1611
1612
  		desc->tfm = sctp_sk(ep->base.sk)->hmac;
  		desc->flags = 0;
  
  		err = crypto_shash_setkey(desc->tfm, ep->secret_key,
  					  sizeof(ep->secret_key)) ?:
  		      crypto_shash_digest(desc, (u8 *)&cookie->c, bodysize,
  					  cookie->signature);
  		shash_desc_zero(desc);
  		if (err)
1b489e11d   Herbert Xu   [SCTP]: Use HMAC ...
1613
  			goto free_cookie;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1614
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1615
  	return retval;
1b489e11d   Herbert Xu   [SCTP]: Use HMAC ...
1616
1617
1618
1619
1620
1621
  
  free_cookie:
  	kfree(retval);
  nodata:
  	*cookie_len = 0;
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1622
1623
1624
1625
  }
  
  /* Unpack the cookie from COOKIE ECHO chunk, recreating the association.  */
  struct sctp_association *sctp_unpack_cookie(
327c0dab8   Xin Long   sctp: fix some in...
1626
1627
1628
1629
  					const struct sctp_endpoint *ep,
  					const struct sctp_association *asoc,
  					struct sctp_chunk *chunk, gfp_t gfp,
  					int *error, struct sctp_chunk **errp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1630
1631
  {
  	struct sctp_association *retval = NULL;
327c0dab8   Xin Long   sctp: fix some in...
1632
  	int headersize, bodysize, fixed_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1633
  	struct sctp_signed_cookie *cookie;
327c0dab8   Xin Long   sctp: fix some in...
1634
  	struct sk_buff *skb = chunk->skb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1635
  	struct sctp_cookie *bear_cookie;
313e7b4d2   Vlad Yasevich   [SCTP]: Fix machi...
1636
  	__u8 *digest = ep->digest;
1c662018d   Xin Long   sctp: remove the ...
1637
  	enum sctp_scope scope;
327c0dab8   Xin Long   sctp: fix some in...
1638
  	unsigned int len;
52db882f3   Daniel Borkmann   net: sctp: migrat...
1639
  	ktime_t kt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1640

9834a2bb4   Vlad Yasevich   [SCTP]: Fix sctp_...
1641
1642
1643
  	/* Header size is static data prior to the actual cookie, including
  	 * any padding.
  	 */
922dbc5be   Xin Long   sctp: remove the ...
1644
  	headersize = sizeof(struct sctp_chunkhdr) +
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
1645
  		     (sizeof(struct sctp_signed_cookie) -
9834a2bb4   Vlad Yasevich   [SCTP]: Fix sctp_...
1646
  		      sizeof(struct sctp_cookie));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
  	bodysize = ntohs(chunk->chunk_hdr->length) - headersize;
  	fixed_size = headersize + sizeof(struct sctp_cookie);
  
  	/* Verify that the chunk looks like it even has a cookie.
  	 * There must be enough room for our cookie and our peer's
  	 * INIT chunk.
  	 */
  	len = ntohs(chunk->chunk_hdr->length);
  	if (len < fixed_size + sizeof(struct sctp_chunkhdr))
  		goto malformed;
  
  	/* Verify that the cookie has been padded out. */
  	if (bodysize % SCTP_COOKIE_MULTIPLE)
  		goto malformed;
  
  	/* Process the cookie.  */
  	cookie = chunk->subh.cookie_hdr;
  	bear_cookie = &cookie->c;
  
  	if (!sctp_sk(ep->base.sk)->hmac)
  		goto no_hmac;
  
  	/* Check the signature.  */
5821c7697   Herbert Xu   sctp: Use shash
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
  	{
  		SHASH_DESC_ON_STACK(desc, sctp_sk(ep->base.sk)->hmac);
  		int err;
  
  		desc->tfm = sctp_sk(ep->base.sk)->hmac;
  		desc->flags = 0;
  
  		err = crypto_shash_setkey(desc->tfm, ep->secret_key,
  					  sizeof(ep->secret_key)) ?:
  		      crypto_shash_digest(desc, (u8 *)bear_cookie, bodysize,
  					  digest);
  		shash_desc_zero(desc);
  
  		if (err) {
  			*error = -SCTP_IERROR_NOMEM;
  			goto fail;
  		}
1b489e11d   Herbert Xu   [SCTP]: Use HMAC ...
1687
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1688
1689
  
  	if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) {
570617e79   Daniel Borkmann   net: sctp: remove...
1690
1691
  		*error = -SCTP_IERROR_BAD_SIG;
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
  	}
  
  no_hmac:
  	/* IG Section 2.35.2:
  	 *  3) Compare the port numbers and the verification tag contained
  	 *     within the COOKIE ECHO chunk to the actual port numbers and the
  	 *     verification tag within the SCTP common header of the received
  	 *     packet. If these values do not match the packet MUST be silently
  	 *     discarded,
  	 */
  	if (ntohl(chunk->sctp_hdr->vtag) != bear_cookie->my_vtag) {
  		*error = -SCTP_IERROR_BAD_TAG;
  		goto fail;
  	}
9b1dfad01   Al Viro   [SCTP]: Switch sc...
1706
  	if (chunk->sctp_hdr->source != bear_cookie->peer_addr.v4.sin_port ||
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1707
1708
1709
1710
1711
1712
1713
1714
  	    ntohs(chunk->sctp_hdr->dest) != bear_cookie->my_port) {
  		*error = -SCTP_IERROR_BAD_PORTS;
  		goto fail;
  	}
  
  	/* Check to see if the cookie is stale.  If there is already
  	 * an association, there is no need to check cookie's expiration
  	 * for init collision case of lost COOKIE ACK.
f236218b7   Vlad Yasevich   [SCTP]: Do not ti...
1715
1716
1717
1718
  	 * If skb has been timestamped, then use the stamp, otherwise
  	 * use current time.  This introduces a small possibility that
  	 * that a cookie may be considered expired, but his would only slow
  	 * down the new association establishment instead of every packet.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1719
  	 */
f236218b7   Vlad Yasevich   [SCTP]: Do not ti...
1720
  	if (sock_flag(ep->base.sk, SOCK_TIMESTAMP))
52db882f3   Daniel Borkmann   net: sctp: migrat...
1721
  		kt = skb_get_ktime(skb);
f236218b7   Vlad Yasevich   [SCTP]: Do not ti...
1722
  	else
cb5e173ed   Marcelo Ricardo Leitner   sctp: use the sam...
1723
  		kt = ktime_get_real();
f236218b7   Vlad Yasevich   [SCTP]: Do not ti...
1724

67cb9366f   Daniel Borkmann   ktime: add ktime_...
1725
  	if (!asoc && ktime_before(bear_cookie->expiration, kt)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
  		/*
  		 * Section 3.3.10.3 Stale Cookie Error (3)
  		 *
  		 * Cause of error
  		 * ---------------
  		 * Stale Cookie Error:  Indicates the receipt of a valid State
  		 * Cookie that has expired.
  		 */
  		len = ntohs(chunk->chunk_hdr->length);
  		*errp = sctp_make_op_error_space(asoc, chunk, len);
  		if (*errp) {
52db882f3   Daniel Borkmann   net: sctp: migrat...
1737
  			suseconds_t usecs = ktime_to_us(ktime_sub(kt, bear_cookie->expiration));
34bcca283   Al Viro   [SCTP]: Even more...
1738
  			__be32 n = htonl(usecs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1739

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1740
  			sctp_init_cause(*errp, SCTP_ERROR_STALE_COOKIE,
00f1c2df2   Wei Yongjun   SCTP: Fix to enco...
1741
1742
  					sizeof(n));
  			sctp_addto_chunk(*errp, sizeof(n), &n);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
  			*error = -SCTP_IERROR_STALE_COOKIE;
  		} else
  			*error = -SCTP_IERROR_NOMEM;
  
  		goto fail;
  	}
  
  	/* Make a new base association.  */
  	scope = sctp_scope(sctp_source(chunk));
  	retval = sctp_association_new(ep, ep->base.sk, scope, gfp);
  	if (!retval) {
  		*error = -SCTP_IERROR_NOMEM;
  		goto fail;
  	}
  
  	/* Set up our peer's port number.  */
  	retval->peer.port = ntohs(chunk->sctp_hdr->source);
  
  	/* Populate the association from the cookie.  */
  	memcpy(&retval->c, bear_cookie, sizeof(*bear_cookie));
  
  	if (sctp_assoc_set_bind_addr_from_cookie(retval, bear_cookie,
  						 GFP_ATOMIC) < 0) {
  		*error = -SCTP_IERROR_NOMEM;
  		goto fail;
  	}
  
  	/* Also, add the destination address. */
  	if (list_empty(&retval->base.bind_addr.address_list)) {
f57d96b2e   Vlad Yasevich   [SCTP]: Change us...
1772
  		sctp_add_bind_addr(&retval->base.bind_addr, &chunk->dest,
133800d1f   Marcelo Ricardo Leitner   sctp: fix copying...
1773
1774
  				   sizeof(chunk->dest), SCTP_ADDR_SRC,
  				   GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1775
1776
1777
1778
1779
  	}
  
  	retval->next_tsn = retval->c.initial_tsn;
  	retval->ctsn_ack_point = retval->next_tsn - 1;
  	retval->addip_serial = retval->c.initial_tsn;
cc16f00f6   Xin Long   sctp: add support...
1780
  	retval->strreset_outseq = retval->c.initial_tsn;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1781
1782
  	retval->adv_peer_ack_point = retval->ctsn_ack_point;
  	retval->peer.prsctp_capable = retval->c.prsctp_capable;
0f3fffd8a   Ivan Skytte Jorgensen   [SCTP]: Fix typo ...
1783
  	retval->peer.adaptation_ind = retval->c.adaptation_ind;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
  
  	/* The INIT stuff will be done by the side effects.  */
  	return retval;
  
  fail:
  	if (retval)
  		sctp_association_free(retval);
  
  	return NULL;
  
  malformed:
  	/* Yikes!  The packet is either corrupt or deliberately
  	 * malformed.
  	 */
  	*error = -SCTP_IERROR_MALFORMED;
  	goto fail;
  }
  
  /********************************************************************
   * 3rd Level Abstractions
   ********************************************************************/
  
  struct __sctp_missing {
9f81bcd94   Al Viro   [SCTP]: More triv...
1807
1808
  	__be32 num_missing;
  	__be16 type;
bc10502db   Eric Dumazet   net: use __packed...
1809
  }  __packed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1810
1811
1812
1813
1814
  
  /*
   * Report a missing mandatory parameter.
   */
  static int sctp_process_missing_param(const struct sctp_association *asoc,
34b4e29b3   Xin Long   sctp: remove the ...
1815
  				      enum sctp_param paramtype,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1816
1817
1818
1819
1820
  				      struct sctp_chunk *chunk,
  				      struct sctp_chunk **errp)
  {
  	struct __sctp_missing report;
  	__u16 len;
e2f036a97   Marcelo Ricardo Leitner   sctp: rename WORD...
1821
  	len = SCTP_PAD4(sizeof(report));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
  
  	/* Make an ERROR chunk, preparing enough room for
  	 * returning multiple unknown parameters.
  	 */
  	if (!*errp)
  		*errp = sctp_make_op_error_space(asoc, chunk, len);
  
  	if (*errp) {
  		report.num_missing = htonl(1);
  		report.type = paramtype;
ebdfcad4d   Vlad Yasevich   [SCTP]: Set corre...
1832
  		sctp_init_cause(*errp, SCTP_ERROR_MISS_PARAM,
00f1c2df2   Wei Yongjun   SCTP: Fix to enco...
1833
1834
  				sizeof(report));
  		sctp_addto_chunk(*errp, sizeof(report), &report);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
  	}
  
  	/* Stop processing this chunk. */
  	return 0;
  }
  
  /* Report an Invalid Mandatory Parameter.  */
  static int sctp_process_inv_mandatory(const struct sctp_association *asoc,
  				      struct sctp_chunk *chunk,
  				      struct sctp_chunk **errp)
  {
  	/* Invalid Mandatory Parameter Error has no payload. */
  
  	if (!*errp)
  		*errp = sctp_make_op_error_space(asoc, chunk, 0);
  
  	if (*errp)
00f1c2df2   Wei Yongjun   SCTP: Fix to enco...
1852
  		sctp_init_cause(*errp, SCTP_ERROR_INV_PARAM, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
  
  	/* Stop processing this chunk. */
  	return 0;
  }
  
  static int sctp_process_inv_paramlength(const struct sctp_association *asoc,
  					struct sctp_paramhdr *param,
  					const struct sctp_chunk *chunk,
  					struct sctp_chunk **errp)
  {
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
1863
1864
1865
1866
1867
  	/* This is a fatal error.  Any accumulated non-fatal errors are
  	 * not reported.
  	 */
  	if (*errp)
  		sctp_chunk_free(*errp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1868
  	/* Create an error chunk and fill it in with our payload. */
ba0166708   Wei Yongjun   sctp: Fix kernel ...
1869
  	*errp = sctp_make_violation_paramlen(asoc, chunk, param);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
  
  	return 0;
  }
  
  
  /* Do not attempt to handle the HOST_NAME parm.  However, do
   * send back an indicator to the peer.
   */
  static int sctp_process_hn_param(const struct sctp_association *asoc,
  				 union sctp_params param,
  				 struct sctp_chunk *chunk,
  				 struct sctp_chunk **errp)
  {
  	__u16 len = ntohs(param.p->length);
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
1884
1885
1886
1887
1888
1889
1890
1891
1892
  	/* Processing of the HOST_NAME parameter will generate an
  	 * ABORT.  If we've accumulated any non-fatal errors, they
  	 * would be unrecognized parameters and we should not include
  	 * them in the ABORT.
  	 */
  	if (*errp)
  		sctp_chunk_free(*errp);
  
  	*errp = sctp_make_op_error_space(asoc, chunk, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1893

00f1c2df2   Wei Yongjun   SCTP: Fix to enco...
1894
1895
1896
1897
  	if (*errp) {
  		sctp_init_cause(*errp, SCTP_ERROR_DNS_FAILED, len);
  		sctp_addto_chunk(*errp, len, param.v);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1898
1899
1900
1901
  
  	/* Stop processing this chunk. */
  	return 0;
  }
f53b5b097   Eric W. Biederman   sctp: Push struct...
1902
  static int sctp_verify_ext_param(struct net *net, union sctp_params param)
d67011913   Vlad Yasevich   [SCTP]: Follow Ad...
1903
  {
3c9187049   Xin Long   sctp: remove the ...
1904
  	__u16 num_ext = ntohs(param.p->length) - sizeof(struct sctp_paramhdr);
d67011913   Vlad Yasevich   [SCTP]: Follow Ad...
1905
  	int have_asconf = 0;
327c0dab8   Xin Long   sctp: fix some in...
1906
  	int have_auth = 0;
d67011913   Vlad Yasevich   [SCTP]: Follow Ad...
1907
1908
1909
1910
  	int i;
  
  	for (i = 0; i < num_ext; i++) {
  		switch (param.ext->chunks[i]) {
f7010e614   wangweidong   sctp: fix checkpa...
1911
1912
1913
1914
1915
1916
1917
  		case SCTP_CID_AUTH:
  			have_auth = 1;
  			break;
  		case SCTP_CID_ASCONF:
  		case SCTP_CID_ASCONF_ACK:
  			have_asconf = 1;
  			break;
d67011913   Vlad Yasevich   [SCTP]: Follow Ad...
1918
1919
1920
1921
1922
1923
1924
1925
  		}
  	}
  
  	/* ADD-IP Security: The draft requires us to ABORT or ignore the
  	 * INIT/INIT-ACK if ADD-IP is listed, but AUTH is not.  Do this
  	 * only if ADD-IP is turned on and we are not backward-compatible
  	 * mode.
  	 */
e1fc3b14f   Eric W. Biederman   sctp: Make sysctl...
1926
  	if (net->sctp.addip_noauth)
d67011913   Vlad Yasevich   [SCTP]: Follow Ad...
1927
  		return 1;
e1fc3b14f   Eric W. Biederman   sctp: Make sysctl...
1928
  	if (net->sctp.addip_enable && !have_auth && have_asconf)
d67011913   Vlad Yasevich   [SCTP]: Follow Ad...
1929
1930
1931
1932
  		return 0;
  
  	return 1;
  }
131a47e31   Vlad Yasevich   [SCTP]: Implement...
1933
  static void sctp_process_ext_param(struct sctp_association *asoc,
327c0dab8   Xin Long   sctp: fix some in...
1934
  				   union sctp_params param)
131a47e31   Vlad Yasevich   [SCTP]: Implement...
1935
  {
3c9187049   Xin Long   sctp: remove the ...
1936
  	__u16 num_ext = ntohs(param.p->length) - sizeof(struct sctp_paramhdr);
327c0dab8   Xin Long   sctp: fix some in...
1937
  	struct net *net = sock_net(asoc->base.sk);
131a47e31   Vlad Yasevich   [SCTP]: Implement...
1938
1939
1940
1941
  	int i;
  
  	for (i = 0; i < num_ext; i++) {
  		switch (param.ext->chunks[i]) {
c28445c3c   Xin Long   sctp: add reconf_...
1942
1943
1944
1945
1946
  		case SCTP_CID_RECONF:
  			if (asoc->reconf_enable &&
  			    !asoc->peer.reconf_capable)
  				asoc->peer.reconf_capable = 1;
  			break;
f7010e614   wangweidong   sctp: fix checkpa...
1947
  		case SCTP_CID_FWD_TSN:
28aa4c26f   Xin Long   sctp: add SCTP_PR...
1948
1949
  			if (asoc->prsctp_enable && !asoc->peer.prsctp_capable)
  				asoc->peer.prsctp_capable = 1;
f7010e614   wangweidong   sctp: fix checkpa...
1950
1951
1952
1953
1954
  			break;
  		case SCTP_CID_AUTH:
  			/* if the peer reports AUTH, assume that he
  			 * supports AUTH.
  			 */
b14878ccb   Vlad Yasevich   net: sctp: cache ...
1955
  			if (asoc->ep->auth_enable)
f7010e614   wangweidong   sctp: fix checkpa...
1956
1957
1958
1959
1960
1961
1962
1963
1964
  				asoc->peer.auth_capable = 1;
  			break;
  		case SCTP_CID_ASCONF:
  		case SCTP_CID_ASCONF_ACK:
  			if (net->sctp.addip_enable)
  				asoc->peer.asconf_capable = 1;
  			break;
  		default:
  			break;
131a47e31   Vlad Yasevich   [SCTP]: Implement...
1965
1966
1967
  		}
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1968
1969
1970
1971
1972
1973
1974
  /* RFC 3.2.1 & the Implementers Guide 2.2.
   *
   * The Parameter Types are encoded such that the
   * highest-order two bits specify the action that must be
   * taken if the processing endpoint does not recognize the
   * Parameter Type.
   *
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
1975
1976
   * 00 - Stop processing this parameter; do not process any further
   * 	parameters within this chunk
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1977
   *
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
1978
1979
1980
   * 01 - Stop processing this parameter, do not process any further
   *	parameters within this chunk, and report the unrecognized
   *	parameter in an 'Unrecognized Parameter' ERROR chunk.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1981
1982
1983
1984
1985
   *
   * 10 - Skip this parameter and continue processing.
   *
   * 11 - Skip this parameter and continue processing but
   *	report the unrecognized parameter in an
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
1986
   *	'Unrecognized Parameter' ERROR chunk.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1987
1988
   *
   * Return value:
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
1989
1990
1991
   * 	SCTP_IERROR_NO_ERROR - continue with the chunk
   * 	SCTP_IERROR_ERROR    - stop and report an error.
   * 	SCTP_IERROR_NOMEME   - out of memory.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1992
   */
4785c7ae1   Xin Long   sctp: remove the ...
1993
1994
1995
1996
1997
  static enum sctp_ierror sctp_process_unk_param(
  					const struct sctp_association *asoc,
  					union sctp_params param,
  					struct sctp_chunk *chunk,
  					struct sctp_chunk **errp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1998
  {
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
1999
  	int retval = SCTP_IERROR_NO_ERROR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2000
2001
2002
  
  	switch (param.p->type & SCTP_PARAM_ACTION_MASK) {
  	case SCTP_PARAM_ACTION_DISCARD:
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
2003
  		retval =  SCTP_IERROR_ERROR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2004
2005
2006
  		break;
  	case SCTP_PARAM_ACTION_SKIP:
  		break;
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
2007
2008
2009
  	case SCTP_PARAM_ACTION_DISCARD_ERR:
  		retval =  SCTP_IERROR_ERROR;
  		/* Fall through */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2010
2011
2012
2013
2014
  	case SCTP_PARAM_ACTION_SKIP_ERR:
  		/* Make an ERROR chunk, preparing enough room for
  		 * returning multiple unknown parameters.
  		 */
  		if (NULL == *errp)
5fa782c2f   Neil Horman   sctp: Fix skb_ove...
2015
  			*errp = sctp_make_op_error_fixed(asoc, chunk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2016
2017
  
  		if (*errp) {
2205a6ea9   Jiri Bohac   sctp: fix reporti...
2018
  			if (!sctp_init_cause_fixed(*errp, SCTP_ERROR_UNKNOWN_PARAM,
e2f036a97   Marcelo Ricardo Leitner   sctp: rename WORD...
2019
  					SCTP_PAD4(ntohs(param.p->length))))
2205a6ea9   Jiri Bohac   sctp: fix reporti...
2020
  				sctp_addto_chunk_fixed(*errp,
e2f036a97   Marcelo Ricardo Leitner   sctp: rename WORD...
2021
  						SCTP_PAD4(ntohs(param.p->length)),
2205a6ea9   Jiri Bohac   sctp: fix reporti...
2022
  						param.v);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2023
2024
2025
2026
2027
2028
  		} else {
  			/* If there is no memory for generating the ERROR
  			 * report as specified, an ABORT will be triggered
  			 * to the peer and the association won't be
  			 * established.
  			 */
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
2029
  			retval = SCTP_IERROR_NOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2030
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2031
2032
2033
2034
2035
2036
2037
  		break;
  	default:
  		break;
  	}
  
  	return retval;
  }
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
2038
  /* Verify variable length parameters
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2039
   * Return values:
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
2040
2041
2042
2043
   * 	SCTP_IERROR_ABORT - trigger an ABORT
   * 	SCTP_IERROR_NOMEM - out of memory (abort)
   *	SCTP_IERROR_ERROR - stop processing, trigger an ERROR
   * 	SCTP_IERROR_NO_ERROR - continue with the chunk
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2044
   */
4785c7ae1   Xin Long   sctp: remove the ...
2045
2046
2047
2048
2049
2050
2051
  static enum sctp_ierror sctp_verify_param(struct net *net,
  					  const struct sctp_endpoint *ep,
  					  const struct sctp_association *asoc,
  					  union sctp_params param,
  					  enum sctp_cid cid,
  					  struct sctp_chunk *chunk,
  					  struct sctp_chunk **err_chunk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2052
  {
72da7b386   Wei Yongjun   [SCTP]: Add check...
2053
  	struct sctp_hmac_algo_param *hmacs;
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
2054
  	int retval = SCTP_IERROR_NO_ERROR;
72da7b386   Wei Yongjun   [SCTP]: Add check...
2055
2056
  	__u16 n_elt, id = 0;
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
  
  	/* FIXME - This routine is not looking at each parameter per the
  	 * chunk type, i.e., unrecognized parameters should be further
  	 * identified based on the chunk id.
  	 */
  
  	switch (param.p->type) {
  	case SCTP_PARAM_IPV4_ADDRESS:
  	case SCTP_PARAM_IPV6_ADDRESS:
  	case SCTP_PARAM_COOKIE_PRESERVATIVE:
  	case SCTP_PARAM_SUPPORTED_ADDRESS_TYPES:
  	case SCTP_PARAM_STATE_COOKIE:
  	case SCTP_PARAM_HEARTBEAT_INFO:
  	case SCTP_PARAM_UNRECOGNIZED_PARAMETERS:
  	case SCTP_PARAM_ECN_CAPABLE:
0f3fffd8a   Ivan Skytte Jorgensen   [SCTP]: Fix typo ...
2072
  	case SCTP_PARAM_ADAPTATION_LAYER_IND:
d67011913   Vlad Yasevich   [SCTP]: Follow Ad...
2073
  		break;
131a47e31   Vlad Yasevich   [SCTP]: Implement...
2074
  	case SCTP_PARAM_SUPPORTED_EXT:
f53b5b097   Eric W. Biederman   sctp: Push struct...
2075
  		if (!sctp_verify_ext_param(net, param))
d67011913   Vlad Yasevich   [SCTP]: Follow Ad...
2076
  			return SCTP_IERROR_ABORT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2077
  		break;
d6de30975   Vlad Yasevich   [SCTP]: Add the h...
2078
  	case SCTP_PARAM_SET_PRIMARY:
e1fc3b14f   Eric W. Biederman   sctp: Make sysctl...
2079
  		if (net->sctp.addip_enable)
d6de30975   Vlad Yasevich   [SCTP]: Add the h...
2080
2081
  			break;
  		goto fallthrough;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2082
2083
  	case SCTP_PARAM_HOST_NAME_ADDRESS:
  		/* Tell the peer, we won't support this param.  */
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
2084
2085
2086
  		sctp_process_hn_param(asoc, param, chunk, err_chunk);
  		retval = SCTP_IERROR_ABORT;
  		break;
131a47e31   Vlad Yasevich   [SCTP]: Implement...
2087

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2088
  	case SCTP_PARAM_FWD_TSN_SUPPORT:
28aa4c26f   Xin Long   sctp: add SCTP_PR...
2089
  		if (ep->prsctp_enable)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2090
  			break;
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
2091
2092
2093
  		goto fallthrough;
  
  	case SCTP_PARAM_RANDOM:
b14878ccb   Vlad Yasevich   net: sctp: cache ...
2094
  		if (!ep->auth_enable)
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
2095
2096
2097
2098
2099
2100
2101
2102
  			goto fallthrough;
  
  		/* SCTP-AUTH: Secion 6.1
  		 * If the random number is not 32 byte long the association
  		 * MUST be aborted.  The ABORT chunk SHOULD contain the error
  		 * cause 'Protocol Violation'.
  		 */
  		if (SCTP_AUTH_RANDOM_LENGTH !=
3c9187049   Xin Long   sctp: remove the ...
2103
  			ntohs(param.p->length) - sizeof(struct sctp_paramhdr)) {
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
2104
  			sctp_process_inv_paramlength(asoc, param.p,
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
2105
  							chunk, err_chunk);
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
2106
2107
  			retval = SCTP_IERROR_ABORT;
  		}
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
2108
2109
2110
  		break;
  
  	case SCTP_PARAM_CHUNKS:
b14878ccb   Vlad Yasevich   net: sctp: cache ...
2111
  		if (!ep->auth_enable)
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
2112
2113
2114
2115
2116
2117
2118
  			goto fallthrough;
  
  		/* SCTP-AUTH: Section 3.2
  		 * The CHUNKS parameter MUST be included once in the INIT or
  		 *  INIT-ACK chunk if the sender wants to receive authenticated
  		 *  chunks.  Its maximum length is 260 bytes.
  		 */
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
2119
2120
2121
2122
2123
  		if (260 < ntohs(param.p->length)) {
  			sctp_process_inv_paramlength(asoc, param.p,
  						     chunk, err_chunk);
  			retval = SCTP_IERROR_ABORT;
  		}
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
2124
2125
2126
  		break;
  
  	case SCTP_PARAM_HMAC_ALGO:
b14878ccb   Vlad Yasevich   net: sctp: cache ...
2127
  		if (!ep->auth_enable)
72da7b386   Wei Yongjun   [SCTP]: Add check...
2128
2129
2130
  			goto fallthrough;
  
  		hmacs = (struct sctp_hmac_algo_param *)param.p;
3c9187049   Xin Long   sctp: remove the ...
2131
2132
  		n_elt = (ntohs(param.p->length) -
  			 sizeof(struct sctp_paramhdr)) >> 1;
72da7b386   Wei Yongjun   [SCTP]: Add check...
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
  
  		/* SCTP-AUTH: Section 6.1
  		 * The HMAC algorithm based on SHA-1 MUST be supported and
  		 * included in the HMAC-ALGO parameter.
  		 */
  		for (i = 0; i < n_elt; i++) {
  			id = ntohs(hmacs->hmac_ids[i]);
  
  			if (id == SCTP_AUTH_HMAC_ID_SHA1)
  				break;
  		}
  
  		if (id != SCTP_AUTH_HMAC_ID_SHA1) {
  			sctp_process_inv_paramlength(asoc, param.p, chunk,
  						     err_chunk);
  			retval = SCTP_IERROR_ABORT;
  		}
  		break;
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
2151
  fallthrough:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2152
  	default:
bb33381d0   Daniel Borkmann   net: sctp: rework...
2153
2154
2155
  		pr_debug("%s: unrecognized param:%d for chunk:%d
  ",
  			 __func__, ntohs(param.p->type), cid);
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
2156
  		retval = sctp_process_unk_param(asoc, param, chunk, err_chunk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2157
2158
2159
2160
2161
2162
  		break;
  	}
  	return retval;
  }
  
  /* Verify the INIT packet before we process it.  */
b14878ccb   Vlad Yasevich   net: sctp: cache ...
2163
  int sctp_verify_init(struct net *net, const struct sctp_endpoint *ep,
6d85e68f4   Xin Long   sctp: remove the ...
2164
  		     const struct sctp_association *asoc, enum sctp_cid cid,
01a992bea   Xin Long   sctp: remove the ...
2165
2166
  		     struct sctp_init_chunk *peer_init,
  		     struct sctp_chunk *chunk, struct sctp_chunk **errp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2167
2168
  {
  	union sctp_params param;
7613f5fe1   Daniel Borkmann   net: sctp: sctp_v...
2169
  	bool has_cookie = false;
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
2170
  	int result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2171

7613f5fe1   Daniel Borkmann   net: sctp: sctp_v...
2172
2173
2174
2175
2176
2177
2178
2179
  	/* Check for missing mandatory parameters. Note: Initial TSN is
  	 * also mandatory, but is not checked here since the valid range
  	 * is 0..2**32-1. RFC4960, section 3.3.3.
  	 */
  	if (peer_init->init_hdr.num_outbound_streams == 0 ||
  	    peer_init->init_hdr.num_inbound_streams == 0 ||
  	    peer_init->init_hdr.init_tag == 0 ||
  	    ntohl(peer_init->init_hdr.a_rwnd) < SCTP_DEFAULT_MINWINDOW)
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
2180
  		return sctp_process_inv_mandatory(asoc, chunk, errp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2181

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2182
  	sctp_walk_params(param, peer_init, init_hdr.params) {
7613f5fe1   Daniel Borkmann   net: sctp: sctp_v...
2183
2184
2185
  		if (param.p->type == SCTP_PARAM_STATE_COOKIE)
  			has_cookie = true;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2186
2187
2188
2189
2190
2191
2192
2193
  
  	/* There is a possibility that a parameter length was bad and
  	 * in that case we would have stoped walking the parameters.
  	 * The current param.p would point at the bad one.
  	 * Current consensus on the mailing list is to generate a PROTOCOL
  	 * VIOLATION error.  We build the ERROR chunk here and let the normal
  	 * error handling code build and send the packet.
  	 */
26ac8e5fe   wangweidong   sctp: fix checkpa...
2194
  	if (param.v != (void *)chunk->chunk_end)
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
2195
  		return sctp_process_inv_paramlength(asoc, param.p, chunk, errp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2196
2197
2198
2199
  
  	/* The only missing mandatory param possible today is
  	 * the state cookie for an INIT-ACK chunk.
  	 */
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
2200
2201
2202
  	if ((SCTP_CID_INIT_ACK == cid) && !has_cookie)
  		return sctp_process_missing_param(asoc, SCTP_PARAM_STATE_COOKIE,
  						  chunk, errp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2203

7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
2204
  	/* Verify all the variable length parameters */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2205
  	sctp_walk_params(param, peer_init, init_hdr.params) {
b14878ccb   Vlad Yasevich   net: sctp: cache ...
2206
2207
  		result = sctp_verify_param(net, ep, asoc, param, cid,
  					   chunk, errp);
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
2208
  		switch (result) {
f7010e614   wangweidong   sctp: fix checkpa...
2209
2210
2211
2212
2213
2214
2215
2216
  		case SCTP_IERROR_ABORT:
  		case SCTP_IERROR_NOMEM:
  			return 0;
  		case SCTP_IERROR_ERROR:
  			return 1;
  		case SCTP_IERROR_NO_ERROR:
  		default:
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
  		}
  
  	} /* for (loop through all parameters) */
  
  	return 1;
  }
  
  /* Unpack the parameters in an INIT packet into an association.
   * Returns 0 on failure, else success.
   * FIXME:  This is an association method.
   */
de6becdc0   Wei Yongjun   sctp: fix to chec...
2228
  int sctp_process_init(struct sctp_association *asoc, struct sctp_chunk *chunk,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2229
  		      const union sctp_addr *peer_addr,
01a992bea   Xin Long   sctp: remove the ...
2230
  		      struct sctp_init_chunk *peer_init, gfp_t gfp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2231
  {
e1fc3b14f   Eric W. Biederman   sctp: Make sysctl...
2232
  	struct net *net = sock_net(asoc->base.sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2233
2234
  	struct sctp_transport *transport;
  	struct list_head *pos, *temp;
327c0dab8   Xin Long   sctp: fix some in...
2235
  	union sctp_params param;
de6becdc0   Wei Yongjun   sctp: fix to chec...
2236
  	union sctp_addr addr;
327c0dab8   Xin Long   sctp: fix some in...
2237
  	struct sctp_af *af;
de6becdc0   Wei Yongjun   sctp: fix to chec...
2238
  	int src_match = 0;
327c0dab8   Xin Long   sctp: fix some in...
2239
  	char *cookie;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
  
  	/* We must include the address that the INIT packet came from.
  	 * This is the only address that matters for an INIT packet.
  	 * When processing a COOKIE ECHO, we retrieve the from address
  	 * of the INIT from the cookie.
  	 */
  
  	/* This implementation defaults to making the first transport
  	 * added as the primary transport.  The source address seems to
  	 * be a a better choice than any of the embedded addresses.
  	 */
cb3f837ba   wangweidong   sctp: fix checkpa...
2251
  	if (!sctp_assoc_add_peer(asoc, peer_addr, gfp, SCTP_ACTIVE))
de6becdc0   Wei Yongjun   sctp: fix to chec...
2252
2253
2254
2255
  		goto nomem;
  
  	if (sctp_cmp_addr_exact(sctp_source(chunk), peer_addr))
  		src_match = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2256
2257
  
  	/* Process the initialization parameters.  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2258
  	sctp_walk_params(param, peer_init, init_hdr.params) {
de6becdc0   Wei Yongjun   sctp: fix to chec...
2259
2260
2261
2262
2263
2264
2265
2266
  		if (!src_match && (param.p->type == SCTP_PARAM_IPV4_ADDRESS ||
  		    param.p->type == SCTP_PARAM_IPV6_ADDRESS)) {
  			af = sctp_get_af_specific(param_type2af(param.p->type));
  			af->from_addr_param(&addr, param.addr,
  					    chunk->sctp_hdr->source, 0);
  			if (sctp_cmp_addr_exact(sctp_source(chunk), &addr))
  				src_match = 1;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2267
2268
  
  		if (!sctp_process_param(asoc, param, peer_addr, gfp))
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
2269
  			goto clean_up;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2270
  	}
de6becdc0   Wei Yongjun   sctp: fix to chec...
2271
2272
2273
  	/* source address of chunk may not match any valid address */
  	if (!src_match)
  		goto clean_up;
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
2274
2275
2276
2277
2278
2279
  	/* AUTH: After processing the parameters, make sure that we
  	 * have all the required info to potentially do authentications.
  	 */
  	if (asoc->peer.auth_capable && (!asoc->peer.peer_random ||
  					!asoc->peer.peer_hmacs))
  		asoc->peer.auth_capable = 0;
d67011913   Vlad Yasevich   [SCTP]: Follow Ad...
2280
2281
2282
2283
2284
  	/* In a non-backward compatible mode, if the peer claims
  	 * support for ADD-IP but not AUTH,  the ADD-IP spec states
  	 * that we MUST ABORT the association. Section 6.  The section
  	 * also give us an option to silently ignore the packet, which
  	 * is what we'll do here.
6b2f9cb64   Vlad Yasevich   [SCTP]: Tie ADD-I...
2285
  	 */
e1fc3b14f   Eric W. Biederman   sctp: Make sysctl...
2286
  	if (!net->sctp.addip_noauth &&
73d9c4fd1   Vlad Yasevich   SCTP: Allow ADD_I...
2287
  	     (asoc->peer.asconf_capable && !asoc->peer.auth_capable)) {
6b2f9cb64   Vlad Yasevich   [SCTP]: Tie ADD-I...
2288
2289
2290
  		asoc->peer.addip_disabled_mask |= (SCTP_PARAM_ADD_IP |
  						  SCTP_PARAM_DEL_IP |
  						  SCTP_PARAM_SET_PRIMARY);
88799fe5e   Vlad Yasevich   SCTP: Correctly d...
2291
  		asoc->peer.asconf_capable = 0;
d67011913   Vlad Yasevich   [SCTP]: Follow Ad...
2292
  		goto clean_up;
6b2f9cb64   Vlad Yasevich   [SCTP]: Tie ADD-I...
2293
  	}
3f7a87d2f   Frank Filz   [SCTP] sctp_conne...
2294
2295
2296
2297
2298
2299
2300
  	/* Walk list of transports, removing transports in the UNKNOWN state. */
  	list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
  		transport = list_entry(pos, struct sctp_transport, transports);
  		if (transport->state == SCTP_UNKNOWN) {
  			sctp_assoc_rm_peer(asoc, transport);
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
  	/* The fixed INIT headers are always in network byte
  	 * order.
  	 */
  	asoc->peer.i.init_tag =
  		ntohl(peer_init->init_hdr.init_tag);
  	asoc->peer.i.a_rwnd =
  		ntohl(peer_init->init_hdr.a_rwnd);
  	asoc->peer.i.num_outbound_streams =
  		ntohs(peer_init->init_hdr.num_outbound_streams);
  	asoc->peer.i.num_inbound_streams =
  		ntohs(peer_init->init_hdr.num_inbound_streams);
  	asoc->peer.i.initial_tsn =
  		ntohl(peer_init->init_hdr.initial_tsn);
cc16f00f6   Xin Long   sctp: add support...
2314
  	asoc->strreset_inseq = asoc->peer.i.initial_tsn;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
  	/* Apply the upper bounds for output streams based on peer's
  	 * number of inbound streams.
  	 */
  	if (asoc->c.sinit_num_ostreams  >
  	    ntohs(peer_init->init_hdr.num_inbound_streams)) {
  		asoc->c.sinit_num_ostreams =
  			ntohs(peer_init->init_hdr.num_inbound_streams);
  	}
  
  	if (asoc->c.sinit_max_instreams >
  	    ntohs(peer_init->init_hdr.num_outbound_streams)) {
  		asoc->c.sinit_max_instreams =
  			ntohs(peer_init->init_hdr.num_outbound_streams);
  	}
  
  	/* Copy Initiation tag from INIT to VT_peer in cookie.   */
  	asoc->c.peer_vtag = asoc->peer.i.init_tag;
  
  	/* Peer Rwnd   : Current calculated value of the peer's rwnd.  */
  	asoc->peer.rwnd = asoc->peer.i.a_rwnd;
  
  	/* Copy cookie in case we need to resend COOKIE-ECHO. */
  	cookie = asoc->peer.cookie;
  	if (cookie) {
af997d8c9   Arnaldo Carvalho de Melo   [SCTP]: Use kzall...
2339
  		asoc->peer.cookie = kmemdup(cookie, asoc->peer.cookie_len, gfp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2340
2341
  		if (!asoc->peer.cookie)
  			goto clean_up;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2342
2343
2344
2345
2346
2347
  	}
  
  	/* RFC 2960 7.2.1 The initial value of ssthresh MAY be arbitrarily
  	 * high (for example, implementations MAY use the size of the receiver
  	 * advertised window).
  	 */
9dbc15f05   Robert P. J. Day   [SCTP]: "list_for...
2348
2349
  	list_for_each_entry(transport, &asoc->peer.transport_addr_list,
  			transports) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2350
2351
2352
2353
  		transport->ssthresh = asoc->peer.i.a_rwnd;
  	}
  
  	/* Set up the TSN tracking pieces.  */
8e1ee18c3   Vlad Yasevich   sctp: Rework the ...
2354
2355
2356
  	if (!sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL,
  				asoc->peer.i.initial_tsn, gfp))
  		goto clean_up;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2357
2358
2359
2360
2361
2362
2363
2364
  
  	/* RFC 2960 6.5 Stream Identifier and Stream Sequence Number
  	 *
  	 * The stream sequence number in all the streams shall start
  	 * from 0 when the association is established.  Also, when the
  	 * stream sequence number reaches the value 65535 the next
  	 * stream sequence number shall be set to 0.
  	 */
ff356414d   Xin Long   sctp: merge sctp_...
2365
2366
  	if (sctp_stream_init(&asoc->stream, asoc->c.sinit_num_ostreams,
  			     asoc->c.sinit_max_instreams, gfp))
7e0629776   Xin Long   sctp: set new_aso...
2367
  		goto clean_up;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2368

7e0629776   Xin Long   sctp: set new_aso...
2369
2370
  	if (!asoc->temp && sctp_assoc_set_id(asoc, gfp))
  		goto clean_up;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
  
  	/* ADDIP Section 4.1 ASCONF Chunk Procedures
  	 *
  	 * When an endpoint has an ASCONF signaled change to be sent to the
  	 * remote endpoint it should do the following:
  	 * ...
  	 * A2) A serial number should be assigned to the Chunk. The serial
  	 * number should be a monotonically increasing number. All serial
  	 * numbers are defined to be initialized at the start of the
  	 * association to the same value as the Initial TSN.
  	 */
  	asoc->peer.addip_serial = asoc->peer.i.initial_tsn - 1;
  	return 1;
  
  clean_up:
  	/* Release the transport structures. */
  	list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
  		transport = list_entry(pos, struct sctp_transport, transports);
add52379d   Vlad Yasevich   sctp: Fix oops wh...
2389
2390
  		if (transport->state != SCTP_ACTIVE)
  			sctp_assoc_rm_peer(asoc, transport);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2391
  	}
3f7a87d2f   Frank Filz   [SCTP] sctp_conne...
2392

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
  nomem:
  	return 0;
  }
  
  
  /* Update asoc with the option described in param.
   *
   * RFC2960 3.3.2.1 Optional/Variable Length Parameters in INIT
   *
   * asoc is the association to update.
   * param is the variable length parameter to use for update.
   * cid tells us if this is an INIT, INIT ACK or COOKIE ECHO.
   * If the current packet is an INIT we want to minimize the amount of
   * work we do.  In particular, we should not build transport
   * structures for the addresses.
   */
  static int sctp_process_param(struct sctp_association *asoc,
  			      union sctp_params param,
  			      const union sctp_addr *peer_addr,
dd0fc66fb   Al Viro   [PATCH] gfp flags...
2412
  			      gfp_t gfp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2413
  {
e7ff4a703   Eric W. Biederman   sctp: Push struct...
2414
  	struct net *net = sock_net(asoc->base.sk);
327c0dab8   Xin Long   sctp: fix some in...
2415
  	struct sctp_endpoint *ep = asoc->ep;
d6de30975   Vlad Yasevich   [SCTP]: Add the h...
2416
2417
  	union sctp_addr_param *addr_param;
  	struct sctp_transport *t;
327c0dab8   Xin Long   sctp: fix some in...
2418
2419
2420
2421
2422
2423
  	enum sctp_scope scope;
  	union sctp_addr addr;
  	struct sctp_af *af;
  	int retval = 1, i;
  	u32 stale;
  	__u16 sat;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2424
2425
2426
2427
2428
2429
2430
2431
2432
  
  	/* We maintain all INIT parameters in network byte order all the
  	 * time.  This allows us to not worry about whether the parameters
  	 * came from a fresh INIT, and INIT ACK, or were stored in a cookie.
  	 */
  	switch (param.p->type) {
  	case SCTP_PARAM_IPV6_ADDRESS:
  		if (PF_INET6 != asoc->base.sk->sk_family)
  			break;
7dab83de5   Vlad Yasevich   sctp: Support ipv...
2433
  		goto do_addr_param;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2434
  	case SCTP_PARAM_IPV4_ADDRESS:
7dab83de5   Vlad Yasevich   sctp: Support ipv...
2435
2436
2437
2438
  		/* v4 addresses are not allowed on v6-only socket */
  		if (ipv6_only_sock(asoc->base.sk))
  			break;
  do_addr_param:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2439
  		af = sctp_get_af_specific(param_type2af(param.p->type));
dd86d136f   Al Viro   [SCTP]: Switch ->...
2440
  		af->from_addr_param(&addr, param.addr, htons(asoc->peer.port), 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2441
  		scope = sctp_scope(peer_addr);
e7ff4a703   Eric W. Biederman   sctp: Push struct...
2442
  		if (sctp_in_scope(net, &addr, scope))
dd86d136f   Al Viro   [SCTP]: Switch ->...
2443
  			if (!sctp_assoc_add_peer(asoc, &addr, gfp, SCTP_UNCONFIRMED))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2444
2445
2446
2447
  				return 0;
  		break;
  
  	case SCTP_PARAM_COOKIE_PRESERVATIVE:
e1fc3b14f   Eric W. Biederman   sctp: Make sysctl...
2448
  		if (!net->sctp.cookie_preserve_enable)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2449
2450
2451
2452
2453
2454
2455
  			break;
  
  		stale = ntohl(param.life->lifespan_increment);
  
  		/* Suggested Cookie Life span increment's unit is msec,
  		 * (1/1000sec).
  		 */
52db882f3   Daniel Borkmann   net: sctp: migrat...
2456
  		asoc->cookie_life = ktime_add_ms(asoc->cookie_life, stale);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2457
2458
2459
  		break;
  
  	case SCTP_PARAM_HOST_NAME_ADDRESS:
bb33381d0   Daniel Borkmann   net: sctp: rework...
2460
2461
  		pr_debug("%s: unimplemented SCTP_HOST_NAME_ADDRESS
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2462
2463
2464
2465
2466
2467
2468
2469
  		break;
  
  	case SCTP_PARAM_SUPPORTED_ADDRESS_TYPES:
  		/* Turn off the default values first so we'll know which
  		 * ones are really set by the peer.
  		 */
  		asoc->peer.ipv4_address = 0;
  		asoc->peer.ipv6_address = 0;
140ee9603   Gui Jianfeng   SCTP: Fix chunk p...
2470
2471
2472
2473
2474
2475
2476
  		/* Assume that peer supports the address family
  		 * by which it sends a packet.
  		 */
  		if (peer_addr->sa.sa_family == AF_INET6)
  			asoc->peer.ipv6_address = 1;
  		else if (peer_addr->sa.sa_family == AF_INET)
  			asoc->peer.ipv4_address = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2477
  		/* Cycle through address types; avoid divide by 0. */
3c9187049   Xin Long   sctp: remove the ...
2478
  		sat = ntohs(param.p->length) - sizeof(struct sctp_paramhdr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
  		if (sat)
  			sat /= sizeof(__u16);
  
  		for (i = 0; i < sat; ++i) {
  			switch (param.sat->types[i]) {
  			case SCTP_PARAM_IPV4_ADDRESS:
  				asoc->peer.ipv4_address = 1;
  				break;
  
  			case SCTP_PARAM_IPV6_ADDRESS:
6e40a915d   Wei Yongjun   sctp: Do not enab...
2489
2490
  				if (PF_INET6 == asoc->base.sk->sk_family)
  					asoc->peer.ipv6_address = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2491
2492
2493
2494
2495
2496
2497
2498
  				break;
  
  			case SCTP_PARAM_HOST_NAME_ADDRESS:
  				asoc->peer.hostname_address = 1;
  				break;
  
  			default: /* Just ignore anything else.  */
  				break;
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
2499
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2500
2501
2502
2503
2504
  		}
  		break;
  
  	case SCTP_PARAM_STATE_COOKIE:
  		asoc->peer.cookie_len =
3c9187049   Xin Long   sctp: remove the ...
2505
  			ntohs(param.p->length) - sizeof(struct sctp_paramhdr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
  		asoc->peer.cookie = param.cookie->body;
  		break;
  
  	case SCTP_PARAM_HEARTBEAT_INFO:
  		/* Would be odd to receive, but it causes no problems. */
  		break;
  
  	case SCTP_PARAM_UNRECOGNIZED_PARAMETERS:
  		/* Rejected during verify stage. */
  		break;
  
  	case SCTP_PARAM_ECN_CAPABLE:
  		asoc->peer.ecn_capable = 1;
  		break;
0f3fffd8a   Ivan Skytte Jorgensen   [SCTP]: Fix typo ...
2520
  	case SCTP_PARAM_ADAPTATION_LAYER_IND:
e69c4e0f1   Vlad Yasevich   sctp: correctly s...
2521
  		asoc->peer.adaptation_ind = ntohl(param.aind->adaptation_ind);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2522
  		break;
d6de30975   Vlad Yasevich   [SCTP]: Add the h...
2523
  	case SCTP_PARAM_SET_PRIMARY:
e1fc3b14f   Eric W. Biederman   sctp: Make sysctl...
2524
  		if (!net->sctp.addip_enable)
0ef46e285   Vlad Yasevich   sctp: do not enab...
2525
  			goto fall_through;
8b32f2348   Xin Long   sctp: remove the ...
2526
  		addr_param = param.v + sizeof(struct sctp_addip_param);
d6de30975   Vlad Yasevich   [SCTP]: Add the h...
2527

cfbf654ef   Saran Maruti Ramanara   net: sctp: fix pa...
2528
  		af = sctp_get_af_specific(param_type2af(addr_param->p.type));
e40607cbe   Daniel Borkmann   net: sctp: fix NU...
2529
2530
  		if (af == NULL)
  			break;
d6de30975   Vlad Yasevich   [SCTP]: Add the h...
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
  		af->from_addr_param(&addr, addr_param,
  				    htons(asoc->peer.port), 0);
  
  		/* if the address is invalid, we can't process it.
  		 * XXX: see spec for what to do.
  		 */
  		if (!af->addr_valid(&addr, NULL, NULL))
  			break;
  
  		t = sctp_assoc_lookup_paddr(asoc, &addr);
  		if (!t)
  			break;
  
  		sctp_assoc_set_primary(asoc, t);
  		break;
131a47e31   Vlad Yasevich   [SCTP]: Implement...
2546
2547
2548
  	case SCTP_PARAM_SUPPORTED_EXT:
  		sctp_process_ext_param(asoc, param);
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2549
  	case SCTP_PARAM_FWD_TSN_SUPPORT:
28aa4c26f   Xin Long   sctp: add SCTP_PR...
2550
  		if (asoc->prsctp_enable) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2551
2552
2553
  			asoc->peer.prsctp_capable = 1;
  			break;
  		}
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
2554
  		/* Fall Through */
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
2555
2556
2557
  		goto fall_through;
  
  	case SCTP_PARAM_RANDOM:
b14878ccb   Vlad Yasevich   net: sctp: cache ...
2558
  		if (!ep->auth_enable)
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
  			goto fall_through;
  
  		/* Save peer's random parameter */
  		asoc->peer.peer_random = kmemdup(param.p,
  					    ntohs(param.p->length), gfp);
  		if (!asoc->peer.peer_random) {
  			retval = 0;
  			break;
  		}
  		break;
  
  	case SCTP_PARAM_HMAC_ALGO:
b14878ccb   Vlad Yasevich   net: sctp: cache ...
2571
  		if (!ep->auth_enable)
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
  			goto fall_through;
  
  		/* Save peer's HMAC list */
  		asoc->peer.peer_hmacs = kmemdup(param.p,
  					    ntohs(param.p->length), gfp);
  		if (!asoc->peer.peer_hmacs) {
  			retval = 0;
  			break;
  		}
  
  		/* Set the default HMAC the peer requested*/
  		sctp_auth_asoc_set_default_hmac(asoc, param.hmac_algo);
  		break;
  
  	case SCTP_PARAM_CHUNKS:
b14878ccb   Vlad Yasevich   net: sctp: cache ...
2587
  		if (!ep->auth_enable)
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
2588
2589
2590
2591
2592
2593
2594
2595
  			goto fall_through;
  
  		asoc->peer.peer_chunks = kmemdup(param.p,
  					    ntohs(param.p->length), gfp);
  		if (!asoc->peer.peer_chunks)
  			retval = 0;
  		break;
  fall_through:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2596
2597
2598
2599
2600
2601
  	default:
  		/* Any unrecognized parameters should have been caught
  		 * and handled by sctp_verify_param() which should be
  		 * called prior to this routine.  Simply log the error
  		 * here.
  		 */
bb33381d0   Daniel Borkmann   net: sctp: rework...
2602
2603
2604
  		pr_debug("%s: ignoring param:%d for association:%p.
  ",
  			 __func__, ntohs(param.p->type), asoc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2605
  		break;
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
2606
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
  
  	return retval;
  }
  
  /* Select a new verification tag.  */
  __u32 sctp_generate_tag(const struct sctp_endpoint *ep)
  {
  	/* I believe that this random number generator complies with RFC1750.
  	 * A tag of 0 is reserved for special cases (e.g. INIT).
  	 */
  	__u32 x;
  
  	do {
  		get_random_bytes(&x, sizeof(__u32));
  	} while (x == 0);
  
  	return x;
  }
  
  /* Select an initial TSN to send during startup.  */
  __u32 sctp_generate_tsn(const struct sctp_endpoint *ep)
  {
  	__u32 retval;
  
  	get_random_bytes(&retval, sizeof(__u32));
  	return retval;
  }
  
  /*
   * ADDIP 3.1.1 Address Configuration Change Chunk (ASCONF)
   *      0                   1                   2                   3
   *      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *     | Type = 0xC1   |  Chunk Flags  |      Chunk Length             |
   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *     |                       Serial Number                           |
   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *     |                    Address Parameter                          |
   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *     |                     ASCONF Parameter #1                       |
   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *     \                                                               \
   *     /                             ....                              /
   *     \                                                               \
   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *     |                     ASCONF Parameter #N                       |
   *      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
2655
   * Address Parameter and other parameter will not be wrapped in this function
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2656
2657
2658
2659
2660
   */
  static struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,
  					   union sctp_addr *addr,
  					   int vparam_len)
  {
65205cc46   Xin Long   sctp: remove the ...
2661
  	struct sctp_addiphdr asconf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
  	struct sctp_chunk *retval;
  	int length = sizeof(asconf) + vparam_len;
  	union sctp_addr_param addrparam;
  	int addrlen;
  	struct sctp_af *af = sctp_get_af_specific(addr->v4.sin_family);
  
  	addrlen = af->to_addr_param(addr, &addrparam);
  	if (!addrlen)
  		return NULL;
  	length += addrlen;
  
  	/* Create the chunk.  */
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
2674
2675
  	retval = sctp_make_control(asoc, SCTP_CID_ASCONF, 0, length,
  				   GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
  	if (!retval)
  		return NULL;
  
  	asconf.serial = htonl(asoc->addip_serial++);
  
  	retval->subh.addip_hdr =
  		sctp_addto_chunk(retval, sizeof(asconf), &asconf);
  	retval->param_hdr.v =
  		sctp_addto_chunk(retval, addrlen, &addrparam);
  
  	return retval;
  }
  
  /* ADDIP
   * 3.2.1 Add IP Address
   * 	0                   1                   2                   3
   * 	0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *     |        Type = 0xC001          |    Length = Variable          |
   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *     |               ASCONF-Request Correlation ID                   |
   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *     |                       Address Parameter                       |
   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *
   * 3.2.2 Delete IP Address
   * 	0                   1                   2                   3
   * 	0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *     |        Type = 0xC002          |    Length = Variable          |
   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *     |               ASCONF-Request Correlation ID                   |
   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *     |                       Address Parameter                       |
   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *
   */
  struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc,
327c0dab8   Xin Long   sctp: fix some in...
2714
2715
2716
  					      union sctp_addr *laddr,
  					      struct sockaddr *addrs,
  					      int addrcnt, __be16 flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2717
  {
327c0dab8   Xin Long   sctp: fix some in...
2718
  	union sctp_addr_param addr_param;
8b32f2348   Xin Long   sctp: remove the ...
2719
  	struct sctp_addip_param	param;
327c0dab8   Xin Long   sctp: fix some in...
2720
2721
2722
2723
2724
2725
2726
2727
  	int paramlen = sizeof(param);
  	struct sctp_chunk *retval;
  	int addr_param_len = 0;
  	union sctp_addr *addr;
  	int totallen = 0, i;
  	int del_pickup = 0;
  	struct sctp_af *af;
  	void *addr_buf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2728
2729
2730
2731
  
  	/* Get total length of all the address parameters. */
  	addr_buf = addrs;
  	for (i = 0; i < addrcnt; i++) {
ea1107338   Joe Perches   net: Remove casts...
2732
  		addr = addr_buf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2733
2734
2735
2736
2737
2738
2739
  		af = sctp_get_af_specific(addr->v4.sin_family);
  		addr_param_len = af->to_addr_param(addr, &addr_param);
  
  		totallen += paramlen;
  		totallen += addr_param_len;
  
  		addr_buf += af->sockaddr_len;
8a07eb0a5   Michio Honda   sctp: Add ASCONF ...
2740
2741
2742
2743
2744
  		if (asoc->asconf_addr_del_pending && !del_pickup) {
  			/* reuse the parameter length from the same scope one */
  			totallen += paramlen;
  			totallen += addr_param_len;
  			del_pickup = 1;
bb33381d0   Daniel Borkmann   net: sctp: rework...
2745
2746
2747
2748
2749
  
  			pr_debug("%s: picked same-scope del_pending addr, "
  				 "totallen for all addresses is %d
  ",
  				 __func__, totallen);
8a07eb0a5   Michio Honda   sctp: Add ASCONF ...
2750
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
  	}
  
  	/* Create an asconf chunk with the required length. */
  	retval = sctp_make_asconf(asoc, laddr, totallen);
  	if (!retval)
  		return NULL;
  
  	/* Add the address parameters to the asconf chunk. */
  	addr_buf = addrs;
  	for (i = 0; i < addrcnt; i++) {
ea1107338   Joe Perches   net: Remove casts...
2761
  		addr = addr_buf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2762
2763
2764
2765
  		af = sctp_get_af_specific(addr->v4.sin_family);
  		addr_param_len = af->to_addr_param(addr, &addr_param);
  		param.param_hdr.type = flags;
  		param.param_hdr.length = htons(paramlen + addr_param_len);
978aa0474   Xin Long   sctp: fix some ty...
2766
  		param.crr_id = htonl(i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2767
2768
2769
2770
2771
2772
  
  		sctp_addto_chunk(retval, paramlen, &param);
  		sctp_addto_chunk(retval, addr_param_len, &addr_param);
  
  		addr_buf += af->sockaddr_len;
  	}
8a07eb0a5   Michio Honda   sctp: Add ASCONF ...
2773
2774
2775
2776
2777
2778
  	if (flags == SCTP_PARAM_ADD_IP && del_pickup) {
  		addr = asoc->asconf_addr_del_pending;
  		af = sctp_get_af_specific(addr->v4.sin_family);
  		addr_param_len = af->to_addr_param(addr, &addr_param);
  		param.param_hdr.type = SCTP_PARAM_DEL_IP;
  		param.param_hdr.length = htons(paramlen + addr_param_len);
978aa0474   Xin Long   sctp: fix some ty...
2779
  		param.crr_id = htonl(i);
8a07eb0a5   Michio Honda   sctp: Add ASCONF ...
2780
2781
2782
2783
  
  		sctp_addto_chunk(retval, paramlen, &param);
  		sctp_addto_chunk(retval, addr_param_len, &addr_param);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
  	return retval;
  }
  
  /* ADDIP
   * 3.2.4 Set Primary IP Address
   *	0                   1                   2                   3
   *	0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *     |        Type =0xC004           |    Length = Variable          |
   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *     |               ASCONF-Request Correlation ID                   |
   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *     |                       Address Parameter                       |
   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
2799
   * Create an ASCONF chunk with Set Primary IP address parameter.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2800
2801
2802
2803
   */
  struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc,
  					     union sctp_addr *addr)
  {
327c0dab8   Xin Long   sctp: fix some in...
2804
2805
  	struct sctp_af *af = sctp_get_af_specific(addr->v4.sin_family);
  	union sctp_addr_param addrparam;
8b32f2348   Xin Long   sctp: remove the ...
2806
  	struct sctp_addip_param	param;
327c0dab8   Xin Long   sctp: fix some in...
2807
2808
2809
  	struct sctp_chunk *retval;
  	int len = sizeof(param);
  	int addrlen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
  
  	addrlen = af->to_addr_param(addr, &addrparam);
  	if (!addrlen)
  		return NULL;
  	len += addrlen;
  
  	/* Create the chunk and make asconf header. */
  	retval = sctp_make_asconf(asoc, addr, len);
  	if (!retval)
  		return NULL;
  
  	param.param_hdr.type = SCTP_PARAM_SET_PRIMARY;
  	param.param_hdr.length = htons(len);
  	param.crr_id = 0;
  
  	sctp_addto_chunk(retval, sizeof(param), &param);
  	sctp_addto_chunk(retval, addrlen, &addrparam);
  
  	return retval;
  }
  
  /* ADDIP 3.1.2 Address Configuration Acknowledgement Chunk (ASCONF-ACK)
   *      0                   1                   2                   3
   *      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *     | Type = 0x80   |  Chunk Flags  |      Chunk Length             |
   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *     |                       Serial Number                           |
   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *     |                 ASCONF Parameter Response#1                   |
   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *     \                                                               \
   *     /                             ....                              /
   *     \                                                               \
   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *     |                 ASCONF Parameter Response#N                   |
   *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
2848
   * Create an ASCONF_ACK chunk with enough space for the parameter responses.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2849
2850
2851
2852
   */
  static struct sctp_chunk *sctp_make_asconf_ack(const struct sctp_association *asoc,
  					       __u32 serial, int vparam_len)
  {
327c0dab8   Xin Long   sctp: fix some in...
2853
2854
2855
  	struct sctp_addiphdr asconf;
  	struct sctp_chunk *retval;
  	int length = sizeof(asconf) + vparam_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2856
2857
  
  	/* Create the chunk.  */
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
2858
2859
  	retval = sctp_make_control(asoc, SCTP_CID_ASCONF_ACK, 0, length,
  				   GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
  	if (!retval)
  		return NULL;
  
  	asconf.serial = htonl(serial);
  
  	retval->subh.addip_hdr =
  		sctp_addto_chunk(retval, sizeof(asconf), &asconf);
  
  	return retval;
  }
  
  /* Add response parameters to an ASCONF_ACK chunk. */
9f81bcd94   Al Viro   [SCTP]: More triv...
2872
  static void sctp_add_asconf_response(struct sctp_chunk *chunk, __be32 crr_id,
8b32f2348   Xin Long   sctp: remove the ...
2873
2874
  				     __be16 err_code,
  				     struct sctp_addip_param *asconf_param)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2875
  {
8b32f2348   Xin Long   sctp: remove the ...
2876
  	struct sctp_addip_param ack_param;
327c0dab8   Xin Long   sctp: fix some in...
2877
2878
2879
2880
  	struct sctp_errhdr err_param;
  	int asconf_param_len = 0;
  	int err_param_len = 0;
  	__be16 response_type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
  
  	if (SCTP_ERROR_NO_ERROR == err_code) {
  		response_type = SCTP_PARAM_SUCCESS_REPORT;
  	} else {
  		response_type = SCTP_PARAM_ERR_CAUSE;
  		err_param_len = sizeof(err_param);
  		if (asconf_param)
  			asconf_param_len =
  				 ntohs(asconf_param->param_hdr.length);
  	}
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
2891
  	/* Add Success Indication or Error Cause Indication parameter. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
  	ack_param.param_hdr.type = response_type;
  	ack_param.param_hdr.length = htons(sizeof(ack_param) +
  					   err_param_len +
  					   asconf_param_len);
  	ack_param.crr_id = crr_id;
  	sctp_addto_chunk(chunk, sizeof(ack_param), &ack_param);
  
  	if (SCTP_ERROR_NO_ERROR == err_code)
  		return;
  
  	/* Add Error Cause parameter. */
  	err_param.cause = err_code;
  	err_param.length = htons(err_param_len + asconf_param_len);
  	sctp_addto_chunk(chunk, err_param_len, &err_param);
  
  	/* Add the failed TLV copied from ASCONF chunk. */
  	if (asconf_param)
  		sctp_addto_chunk(chunk, asconf_param_len, asconf_param);
  }
  
  /* Process a asconf parameter. */
dbc16db1e   Al Viro   [SCTP]: Trivial s...
2913
  static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
8b32f2348   Xin Long   sctp: remove the ...
2914
2915
  					struct sctp_chunk *asconf,
  					struct sctp_addip_param *asconf_param)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2916
  {
327c0dab8   Xin Long   sctp: fix some in...
2917
  	union sctp_addr_param *addr_param;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2918
  	struct sctp_transport *peer;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2919
  	union sctp_addr	addr;
327c0dab8   Xin Long   sctp: fix some in...
2920
  	struct sctp_af *af;
5f242a13e   Al Viro   [SCTP]: Switch ->...
2921

8b32f2348   Xin Long   sctp: remove the ...
2922
  	addr_param = (void *)asconf_param + sizeof(*asconf_param);
c1cc678ad   Patrick McHardy   sctp: Fix use of ...
2923

44e65c1ef   Wei Yongjun   sctp: check the u...
2924
2925
2926
2927
  	if (asconf_param->param_hdr.type != SCTP_PARAM_ADD_IP &&
  	    asconf_param->param_hdr.type != SCTP_PARAM_DEL_IP &&
  	    asconf_param->param_hdr.type != SCTP_PARAM_SET_PRIMARY)
  		return SCTP_ERROR_UNKNOWN_PARAM;
6a435732a   Shan Wei   sctp: use common ...
2928
  	switch (addr_param->p.type) {
c4492586a   Wei Yongjun   sctp: Add address...
2929
2930
  	case SCTP_PARAM_IPV6_ADDRESS:
  		if (!asoc->peer.ipv6_address)
945e5abce   Wei Yongjun   sctp: fix the err...
2931
  			return SCTP_ERROR_DNS_FAILED;
c4492586a   Wei Yongjun   sctp: Add address...
2932
2933
2934
  		break;
  	case SCTP_PARAM_IPV4_ADDRESS:
  		if (!asoc->peer.ipv4_address)
945e5abce   Wei Yongjun   sctp: fix the err...
2935
  			return SCTP_ERROR_DNS_FAILED;
c4492586a   Wei Yongjun   sctp: Add address...
2936
2937
  		break;
  	default:
945e5abce   Wei Yongjun   sctp: fix the err...
2938
  		return SCTP_ERROR_DNS_FAILED;
c4492586a   Wei Yongjun   sctp: Add address...
2939
  	}
6a435732a   Shan Wei   sctp: use common ...
2940
  	af = sctp_get_af_specific(param_type2af(addr_param->p.type));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2941
  	if (unlikely(!af))
945e5abce   Wei Yongjun   sctp: fix the err...
2942
  		return SCTP_ERROR_DNS_FAILED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2943

dd86d136f   Al Viro   [SCTP]: Switch ->...
2944
  	af->from_addr_param(&addr, addr_param, htons(asoc->peer.port), 0);
42e30bf34   Vlad Yasevich   [SCTP]: Handle th...
2945
2946
2947
2948
2949
2950
2951
  
  	/* ADDIP 4.2.1  This parameter MUST NOT contain a broadcast
  	 * or multicast address.
  	 * (note: wildcard is permitted and requires special handling so
  	 *  make sure we check for that)
  	 */
  	if (!af->is_any(&addr) && !af->addr_valid(&addr, NULL, asconf->skb))
945e5abce   Wei Yongjun   sctp: fix the err...
2952
  		return SCTP_ERROR_DNS_FAILED;
42e30bf34   Vlad Yasevich   [SCTP]: Handle th...
2953

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2954
2955
  	switch (asconf_param->param_hdr.type) {
  	case SCTP_PARAM_ADD_IP:
42e30bf34   Vlad Yasevich   [SCTP]: Handle th...
2956
2957
2958
2959
2960
2961
  		/* Section 4.2.1:
  		 * If the address 0.0.0.0 or ::0 is provided, the source
  		 * address of the packet MUST be added.
  		 */
  		if (af->is_any(&addr))
  			memcpy(&addr, &asconf->source, sizeof(addr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2962
  		/* ADDIP 4.3 D9) If an endpoint receives an ADD IP address
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
2963
2964
2965
2966
2967
  		 * request and does not have the local resources to add this
  		 * new address to the association, it MUST return an Error
  		 * Cause TLV set to the new error code 'Operation Refused
  		 * Due to Resource Shortage'.
  		 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2968

dd86d136f   Al Viro   [SCTP]: Switch ->...
2969
  		peer = sctp_assoc_add_peer(asoc, &addr, GFP_ATOMIC, SCTP_UNCONFIRMED);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2970
2971
2972
2973
  		if (!peer)
  			return SCTP_ERROR_RSRC_LOW;
  
  		/* Start the heartbeat timer. */
ba6f5e33b   Marcelo Ricardo Leitner   sctp: avoid refre...
2974
  		sctp_transport_reset_hb_timer(peer);
6af29ccc2   Michio Honda   sctp: Bundle HEAE...
2975
  		asoc->new_transport = peer;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2976
2977
2978
  		break;
  	case SCTP_PARAM_DEL_IP:
  		/* ADDIP 4.3 D7) If a request is received to delete the
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
2979
2980
2981
2982
  		 * last remaining IP address of a peer endpoint, the receiver
  		 * MUST send an Error Cause TLV with the error cause set to the
  		 * new error code 'Request to Delete Last Remaining IP Address'.
  		 */
42e30bf34   Vlad Yasevich   [SCTP]: Handle th...
2983
  		if (asoc->peer.transport_count == 1)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2984
2985
2986
2987
2988
2989
2990
2991
2992
  			return SCTP_ERROR_DEL_LAST_IP;
  
  		/* ADDIP 4.3 D8) If a request is received to delete an IP
  		 * address which is also the source address of the IP packet
  		 * which contained the ASCONF chunk, the receiver MUST reject
  		 * this request. To reject the request the receiver MUST send
  		 * an Error Cause TLV set to the new error code 'Request to
  		 * Delete Source IP Address'
  		 */
b1364104e   Michio Honda   sctp: Add ADD/DEL...
2993
  		if (sctp_cmp_addr_exact(&asconf->source, &addr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2994
  			return SCTP_ERROR_DEL_SRC_IP;
42e30bf34   Vlad Yasevich   [SCTP]: Handle th...
2995
2996
2997
2998
2999
3000
3001
3002
3003
  		/* Section 4.2.2
  		 * If the address 0.0.0.0 or ::0 is provided, all
  		 * addresses of the peer except	the source address of the
  		 * packet MUST be deleted.
  		 */
  		if (af->is_any(&addr)) {
  			sctp_assoc_set_primary(asoc, asconf->transport);
  			sctp_assoc_del_nonprimary_peers(asoc,
  							asconf->transport);
7c5a94618   lucien   sctp: ASCONF-ACK ...
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
  			return SCTP_ERROR_NO_ERROR;
  		}
  
  		/* If the address is not part of the association, the
  		 * ASCONF-ACK with Error Cause Indication Parameter
  		 * which including cause of Unresolvable Address should
  		 * be sent.
  		 */
  		peer = sctp_assoc_lookup_paddr(asoc, &addr);
  		if (!peer)
  			return SCTP_ERROR_DNS_FAILED;
  
  		sctp_assoc_rm_peer(asoc, peer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3017
3018
  		break;
  	case SCTP_PARAM_SET_PRIMARY:
42e30bf34   Vlad Yasevich   [SCTP]: Handle th...
3019
3020
3021
3022
3023
3024
3025
  		/* ADDIP Section 4.2.4
  		 * If the address 0.0.0.0 or ::0 is provided, the receiver
  		 * MAY mark the source address of the packet as its
  		 * primary.
  		 */
  		if (af->is_any(&addr))
  			memcpy(&addr.v4, sctp_source(asconf), sizeof(addr));
dd86d136f   Al Viro   [SCTP]: Switch ->...
3026
  		peer = sctp_assoc_lookup_paddr(asoc, &addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3027
  		if (!peer)
945e5abce   Wei Yongjun   sctp: fix the err...
3028
  			return SCTP_ERROR_DNS_FAILED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3029
3030
3031
  
  		sctp_assoc_set_primary(asoc, peer);
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3032
3033
3034
3035
  	}
  
  	return SCTP_ERROR_NO_ERROR;
  }
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3036
3037
3038
3039
3040
  /* Verify the ASCONF packet before we process it. */
  bool sctp_verify_asconf(const struct sctp_association *asoc,
  			struct sctp_chunk *chunk, bool addr_param_needed,
  			struct sctp_paramhdr **errp)
  {
68d754694   Xin Long   sctp: remove the ...
3041
  	struct sctp_addip_chunk *addip;
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3042
  	bool addr_param_seen = false;
327c0dab8   Xin Long   sctp: fix some in...
3043
  	union sctp_params param;
6f4c618dd   Wei Yongjun   SCTP : Add paramt...
3044

68d754694   Xin Long   sctp: remove the ...
3045
  	addip = (struct sctp_addip_chunk *)chunk->chunk_hdr;
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3046
3047
  	sctp_walk_params(param, addip, addip_hdr.params) {
  		size_t length = ntohs(param.p->length);
6f4c618dd   Wei Yongjun   SCTP : Add paramt...
3048

9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3049
  		*errp = param.p;
6f4c618dd   Wei Yongjun   SCTP : Add paramt...
3050
  		switch (param.p->type) {
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3051
3052
3053
  		case SCTP_PARAM_ERR_CAUSE:
  			break;
  		case SCTP_PARAM_IPV4_ADDRESS:
a38905e6a   Xin Long   sctp: remove the ...
3054
  			if (length != sizeof(struct sctp_ipv4addr_param))
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3055
  				return false;
ce7b4ccc4   lucien   sctp: asconf's pr...
3056
3057
3058
3059
3060
  			/* ensure there is only one addr param and it's in the
  			 * beginning of addip_hdr params, or we reject it.
  			 */
  			if (param.v != addip->addip_hdr.params)
  				return false;
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3061
3062
3063
  			addr_param_seen = true;
  			break;
  		case SCTP_PARAM_IPV6_ADDRESS:
00987cc07   Xin Long   sctp: remove the ...
3064
  			if (length != sizeof(struct sctp_ipv6addr_param))
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3065
  				return false;
ce7b4ccc4   lucien   sctp: asconf's pr...
3066
3067
  			if (param.v != addip->addip_hdr.params)
  				return false;
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3068
3069
  			addr_param_seen = true;
  			break;
6f4c618dd   Wei Yongjun   SCTP : Add paramt...
3070
3071
3072
  		case SCTP_PARAM_ADD_IP:
  		case SCTP_PARAM_DEL_IP:
  		case SCTP_PARAM_SET_PRIMARY:
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3073
3074
3075
3076
  			/* In ASCONF chunks, these need to be first. */
  			if (addr_param_needed && !addr_param_seen)
  				return false;
  			length = ntohs(param.addip->param_hdr.length);
8b32f2348   Xin Long   sctp: remove the ...
3077
  			if (length < sizeof(struct sctp_addip_param) +
3c9187049   Xin Long   sctp: remove the ...
3078
  				     sizeof(**errp))
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3079
  				return false;
6f4c618dd   Wei Yongjun   SCTP : Add paramt...
3080
3081
3082
  			break;
  		case SCTP_PARAM_SUCCESS_REPORT:
  		case SCTP_PARAM_ADAPTATION_LAYER_IND:
8b32f2348   Xin Long   sctp: remove the ...
3083
  			if (length != sizeof(struct sctp_addip_param))
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3084
  				return false;
6f4c618dd   Wei Yongjun   SCTP : Add paramt...
3085
3086
  			break;
  		default:
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3087
3088
  			/* This is unkown to us, reject! */
  			return false;
6f4c618dd   Wei Yongjun   SCTP : Add paramt...
3089
  		}
6f4c618dd   Wei Yongjun   SCTP : Add paramt...
3090
  	}
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3091
3092
3093
3094
3095
3096
3097
  	/* Remaining sanity checks. */
  	if (addr_param_needed && !addr_param_seen)
  		return false;
  	if (!addr_param_needed && addr_param_seen)
  		return false;
  	if (param.v != chunk->chunk_end)
  		return false;
6f4c618dd   Wei Yongjun   SCTP : Add paramt...
3098

9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3099
  	return true;
6f4c618dd   Wei Yongjun   SCTP : Add paramt...
3100
  }
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
3101
  /* Process an incoming ASCONF chunk with the next expected serial no. and
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3102
3103
3104
3105
3106
   * return an ASCONF_ACK chunk to be sent in response.
   */
  struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
  				       struct sctp_chunk *asconf)
  {
327c0dab8   Xin Long   sctp: fix some in...
3107
  	union sctp_addr_param *addr_param;
68d754694   Xin Long   sctp: remove the ...
3108
  	struct sctp_addip_chunk *addip;
327c0dab8   Xin Long   sctp: fix some in...
3109
  	struct sctp_chunk *asconf_ack;
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3110
  	bool all_param_pass = true;
327c0dab8   Xin Long   sctp: fix some in...
3111
3112
  	struct sctp_addiphdr *hdr;
  	int length = 0, chunk_len;
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3113
  	union sctp_params param;
327c0dab8   Xin Long   sctp: fix some in...
3114
3115
  	__be16 err_code;
  	__u32 serial;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3116

68d754694   Xin Long   sctp: remove the ...
3117
  	addip = (struct sctp_addip_chunk *)asconf->chunk_hdr;
922dbc5be   Xin Long   sctp: remove the ...
3118
3119
  	chunk_len = ntohs(asconf->chunk_hdr->length) -
  		    sizeof(struct sctp_chunkhdr);
65205cc46   Xin Long   sctp: remove the ...
3120
  	hdr = (struct sctp_addiphdr *)asconf->skb->data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3121
  	serial = ntohl(hdr->serial);
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
3122
  	/* Skip the addiphdr and store a pointer to address parameter.  */
65205cc46   Xin Long   sctp: remove the ...
3123
  	length = sizeof(*hdr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3124
3125
3126
3127
  	addr_param = (union sctp_addr_param *)(asconf->skb->data + length);
  	chunk_len -= length;
  
  	/* Skip the address parameter and store a pointer to the first
7aa1b54b7   Joe Perches   [SCTP]: Spelling ...
3128
  	 * asconf parameter.
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
3129
  	 */
6a435732a   Shan Wei   sctp: use common ...
3130
  	length = ntohs(addr_param->p.length);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3131
  	chunk_len -= length;
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
3132
  	/* create an ASCONF_ACK chunk.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3133
  	 * Based on the definitions of parameters, we know that the size of
2cab86bee   Wei Yongjun   sctp: malloc enou...
3134
  	 * ASCONF_ACK parameters are less than or equal to the fourfold of ASCONF
7aa1b54b7   Joe Perches   [SCTP]: Spelling ...
3135
  	 * parameters.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3136
  	 */
2cab86bee   Wei Yongjun   sctp: malloc enou...
3137
  	asconf_ack = sctp_make_asconf_ack(asoc, serial, chunk_len * 4);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3138
3139
3140
3141
  	if (!asconf_ack)
  		goto done;
  
  	/* Process the TLVs contained within the ASCONF chunk. */
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3142
3143
3144
3145
3146
  	sctp_walk_params(param, addip, addip_hdr.params) {
  		/* Skip preceeding address parameters. */
  		if (param.p->type == SCTP_PARAM_IPV4_ADDRESS ||
  		    param.p->type == SCTP_PARAM_IPV6_ADDRESS)
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3147
  		err_code = sctp_process_asconf_param(asoc, asconf,
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3148
  						     param.addip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3149
3150
3151
3152
3153
3154
3155
  		/* ADDIP 4.1 A7)
  		 * If an error response is received for a TLV parameter,
  		 * all TLVs with no response before the failed TLV are
  		 * considered successful if not reported.  All TLVs after
  		 * the failed response are considered unsuccessful unless
  		 * a specific success indication is present for the parameter.
  		 */
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3156
3157
  		if (err_code != SCTP_ERROR_NO_ERROR)
  			all_param_pass = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3158
  		if (!all_param_pass)
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3159
3160
  			sctp_add_asconf_response(asconf_ack, param.addip->crr_id,
  						 err_code, param.addip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3161
3162
3163
3164
  
  		/* ADDIP 4.3 D11) When an endpoint receiving an ASCONF to add
  		 * an IP address sends an 'Out of Resource' in its response, it
  		 * MUST also fail any subsequent add or delete requests bundled
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
3165
  		 * in the ASCONF.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3166
  		 */
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3167
  		if (err_code == SCTP_ERROR_RSRC_LOW)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3168
  			goto done;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3169
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3170
3171
3172
3173
  done:
  	asoc->peer.addip_serial++;
  
  	/* If we are sending a new ASCONF_ACK hold a reference to it in assoc
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
3174
  	 * after freeing the reference to old asconf ack if any.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3175
3176
  	 */
  	if (asconf_ack) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3177
  		sctp_chunk_hold(asconf_ack);
a08de64d0   Vlad Yasevich   [SCTP]: Update AS...
3178
3179
  		list_add_tail(&asconf_ack->transmitted_list,
  			      &asoc->asconf_ack_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3180
3181
3182
3183
3184
3185
  	}
  
  	return asconf_ack;
  }
  
  /* Process a asconf parameter that is successfully acked. */
425e0f685   Wei Yongjun   sctp: avoid overw...
3186
  static void sctp_asconf_param_success(struct sctp_association *asoc,
8b32f2348   Xin Long   sctp: remove the ...
3187
  				      struct sctp_addip_param *asconf_param)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3188
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3189
3190
  	struct sctp_bind_addr *bp = &asoc->base.bind_addr;
  	union sctp_addr_param *addr_param;
dc022a987   Sridhar Samudrala   [SCTP]: ADDIP: Do...
3191
  	struct sctp_sockaddr_entry *saddr;
327c0dab8   Xin Long   sctp: fix some in...
3192
3193
3194
  	struct sctp_transport *transport;
  	union sctp_addr	addr;
  	struct sctp_af *af;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3195

8b32f2348   Xin Long   sctp: remove the ...
3196
  	addr_param = (void *)asconf_param + sizeof(*asconf_param);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3197
3198
  
  	/* We have checked the packet before, so we do not check again.	*/
6a435732a   Shan Wei   sctp: use common ...
3199
  	af = sctp_get_af_specific(param_type2af(addr_param->p.type));
dd86d136f   Al Viro   [SCTP]: Switch ->...
3200
  	af->from_addr_param(&addr, addr_param, htons(bp->port), 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3201
3202
3203
  
  	switch (asconf_param->param_hdr.type) {
  	case SCTP_PARAM_ADD_IP:
559cf710b   Vlad Yasevich   [SCTP]: Convert b...
3204
3205
3206
  		/* This is always done in BH context with a socket lock
  		 * held, so the list can not change.
  		 */
0ed90fb0f   Vlad Yasevich   SCTP: Update RCU ...
3207
  		local_bh_disable();
559cf710b   Vlad Yasevich   [SCTP]: Convert b...
3208
  		list_for_each_entry(saddr, &bp->address_list, list) {
dd86d136f   Al Viro   [SCTP]: Switch ->...
3209
  			if (sctp_cmp_addr_exact(&saddr->a, &addr))
f57d96b2e   Vlad Yasevich   [SCTP]: Change us...
3210
  				saddr->state = SCTP_ADDR_SRC;
dc022a987   Sridhar Samudrala   [SCTP]: ADDIP: Do...
3211
  		}
0ed90fb0f   Vlad Yasevich   SCTP: Update RCU ...
3212
  		local_bh_enable();
3cd9749c0   Wei Yongjun   sctp: update the ...
3213
3214
  		list_for_each_entry(transport, &asoc->peer.transport_addr_list,
  				transports) {
c86a773c7   Julian Anastasov   sctp: add dst_pen...
3215
  			sctp_transport_dst_release(transport);
3cd9749c0   Wei Yongjun   sctp: update the ...
3216
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3217
3218
  		break;
  	case SCTP_PARAM_DEL_IP:
0ed90fb0f   Vlad Yasevich   SCTP: Update RCU ...
3219
  		local_bh_disable();
425e0f685   Wei Yongjun   sctp: avoid overw...
3220
  		sctp_del_bind_addr(bp, &addr);
8a07eb0a5   Michio Honda   sctp: Add ASCONF ...
3221
3222
3223
3224
3225
  		if (asoc->asconf_addr_del_pending != NULL &&
  		    sctp_cmp_addr_exact(asoc->asconf_addr_del_pending, &addr)) {
  			kfree(asoc->asconf_addr_del_pending);
  			asoc->asconf_addr_del_pending = NULL;
  		}
0ed90fb0f   Vlad Yasevich   SCTP: Update RCU ...
3226
  		local_bh_enable();
9dbc15f05   Robert P. J. Day   [SCTP]: "list_for...
3227
3228
  		list_for_each_entry(transport, &asoc->peer.transport_addr_list,
  				transports) {
c86a773c7   Julian Anastasov   sctp: add dst_pen...
3229
  			sctp_transport_dst_release(transport);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3230
3231
3232
3233
3234
  		}
  		break;
  	default:
  		break;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3235
3236
3237
3238
  }
  
  /* Get the corresponding ASCONF response error code from the ASCONF_ACK chunk
   * for the given asconf parameter.  If there is no response for this parameter,
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
3239
   * return the error code based on the third argument 'no_err'.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3240
3241
3242
3243
3244
3245
   * ADDIP 4.1
   * A7) If an error response is received for a TLV parameter, all TLVs with no
   * response before the failed TLV are considered successful if not reported.
   * All TLVs after the failed response are considered unsuccessful unless a
   * specific success indication is present for the parameter.
   */
dbc16db1e   Al Viro   [SCTP]: Trivial s...
3246
  static __be16 sctp_get_asconf_response(struct sctp_chunk *asconf_ack,
8b32f2348   Xin Long   sctp: remove the ...
3247
3248
  				       struct sctp_addip_param *asconf_param,
  				       int no_err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3249
  {
8b32f2348   Xin Long   sctp: remove the ...
3250
  	struct sctp_addip_param	*asconf_ack_param;
327c0dab8   Xin Long   sctp: fix some in...
3251
3252
3253
3254
  	struct sctp_errhdr *err_param;
  	int asconf_ack_len;
  	__be16 err_code;
  	int length;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3255
3256
3257
3258
3259
  
  	if (no_err)
  		err_code = SCTP_ERROR_NO_ERROR;
  	else
  		err_code = SCTP_ERROR_REQ_REFUSED;
f3830ccc2   Wei Yongjun   SCTP : Fix to pro...
3260
  	asconf_ack_len = ntohs(asconf_ack->chunk_hdr->length) -
922dbc5be   Xin Long   sctp: remove the ...
3261
  			 sizeof(struct sctp_chunkhdr);
f3830ccc2   Wei Yongjun   SCTP : Fix to pro...
3262

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3263
3264
  	/* Skip the addiphdr from the asconf_ack chunk and store a pointer to
  	 * the first asconf_ack parameter.
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
3265
  	 */
65205cc46   Xin Long   sctp: remove the ...
3266
  	length = sizeof(struct sctp_addiphdr);
8b32f2348   Xin Long   sctp: remove the ...
3267
3268
  	asconf_ack_param = (struct sctp_addip_param *)(asconf_ack->skb->data +
  						       length);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3269
3270
3271
3272
  	asconf_ack_len -= length;
  
  	while (asconf_ack_len > 0) {
  		if (asconf_ack_param->crr_id == asconf_param->crr_id) {
cb3f837ba   wangweidong   sctp: fix checkpa...
3273
  			switch (asconf_ack_param->param_hdr.type) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3274
3275
3276
  			case SCTP_PARAM_SUCCESS_REPORT:
  				return SCTP_ERROR_NO_ERROR;
  			case SCTP_PARAM_ERR_CAUSE:
8b32f2348   Xin Long   sctp: remove the ...
3277
  				length = sizeof(*asconf_ack_param);
ea1107338   Joe Perches   net: Remove casts...
3278
  				err_param = (void *)asconf_ack_param + length;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
  				asconf_ack_len -= length;
  				if (asconf_ack_len > 0)
  					return err_param->cause;
  				else
  					return SCTP_ERROR_INV_PARAM;
  				break;
  			default:
  				return SCTP_ERROR_INV_PARAM;
  			}
  		}
  
  		length = ntohs(asconf_ack_param->param_hdr.length);
ea1107338   Joe Perches   net: Remove casts...
3291
  		asconf_ack_param = (void *)asconf_ack_param + length;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
  		asconf_ack_len -= length;
  	}
  
  	return err_code;
  }
  
  /* Process an incoming ASCONF_ACK chunk against the cached last ASCONF chunk. */
  int sctp_process_asconf_ack(struct sctp_association *asoc,
  			    struct sctp_chunk *asconf_ack)
  {
327c0dab8   Xin Long   sctp: fix some in...
3302
3303
3304
3305
3306
3307
3308
3309
3310
  	struct sctp_chunk *asconf = asoc->addip_last_asconf;
  	struct sctp_addip_param *asconf_param;
  	__be16 err_code = SCTP_ERROR_NO_ERROR;
  	union sctp_addr_param *addr_param;
  	int asconf_len = asconf->skb->len;
  	int all_param_pass = 0;
  	int length = 0;
  	int no_err = 1;
  	int retval = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3311
3312
3313
  
  	/* Skip the chunkhdr and addiphdr from the last asconf sent and store
  	 * a pointer to address parameter.
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
3314
  	 */
68d754694   Xin Long   sctp: remove the ...
3315
  	length = sizeof(struct sctp_addip_chunk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3316
3317
3318
3319
  	addr_param = (union sctp_addr_param *)(asconf->skb->data + length);
  	asconf_len -= length;
  
  	/* Skip the address parameter in the last asconf sent and store a
7aa1b54b7   Joe Perches   [SCTP]: Spelling ...
3320
  	 * pointer to the first asconf parameter.
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
3321
  	 */
6a435732a   Shan Wei   sctp: use common ...
3322
  	length = ntohs(addr_param->p.length);
ea1107338   Joe Perches   net: Remove casts...
3323
  	asconf_param = (void *)addr_param + length;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3324
3325
3326
3327
3328
3329
3330
  	asconf_len -= length;
  
  	/* ADDIP 4.1
  	 * A8) If there is no response(s) to specific TLV parameter(s), and no
  	 * failures are indicated, then all request(s) are considered
  	 * successful.
  	 */
65205cc46   Xin Long   sctp: remove the ...
3331
  	if (asconf_ack->skb->len == sizeof(struct sctp_addiphdr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
  		all_param_pass = 1;
  
  	/* Process the TLVs contained in the last sent ASCONF chunk. */
  	while (asconf_len > 0) {
  		if (all_param_pass)
  			err_code = SCTP_ERROR_NO_ERROR;
  		else {
  			err_code = sctp_get_asconf_response(asconf_ack,
  							    asconf_param,
  							    no_err);
  			if (no_err && (SCTP_ERROR_NO_ERROR != err_code))
  				no_err = 0;
  		}
  
  		switch (err_code) {
  		case SCTP_ERROR_NO_ERROR:
425e0f685   Wei Yongjun   sctp: avoid overw...
3348
  			sctp_asconf_param_success(asoc, asconf_param);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3349
3350
3351
3352
3353
  			break;
  
  		case SCTP_ERROR_RSRC_LOW:
  			retval = 1;
  			break;
a987f762c   Wei Yongjun   sctp: fix report ...
3354
  		case SCTP_ERROR_UNKNOWN_PARAM:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3355
3356
  			/* Disable sending this type of asconf parameter in
  			 * future.
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
3357
  			 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
  			asoc->peer.addip_disabled_mask |=
  				asconf_param->param_hdr.type;
  			break;
  
  		case SCTP_ERROR_REQ_REFUSED:
  		case SCTP_ERROR_DEL_LAST_IP:
  		case SCTP_ERROR_DEL_SRC_IP:
  		default:
  			 break;
  		}
  
  		/* Skip the processed asconf parameter and move to the next
  		 * one.
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
3371
  		 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3372
  		length = ntohs(asconf_param->param_hdr.length);
ea1107338   Joe Perches   net: Remove casts...
3373
  		asconf_param = (void *)asconf_param + length;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3374
3375
  		asconf_len -= length;
  	}
ddc4bbee6   Michio Honda   sctp: fasthandoff...
3376
  	if (no_err && asoc->src_out_of_asoc_ok) {
8a07eb0a5   Michio Honda   sctp: Add ASCONF ...
3377
  		asoc->src_out_of_asoc_ok = 0;
ddc4bbee6   Michio Honda   sctp: fasthandoff...
3378
3379
  		sctp_transport_immediate_rtx(asoc->peer.primary_path);
  	}
8a07eb0a5   Michio Honda   sctp: Add ASCONF ...
3380

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3381
  	/* Free the cached last sent asconf chunk. */
5f9646c3d   Vlad Yasevich   [SCTP]: Make sure...
3382
  	list_del_init(&asconf->transmitted_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3383
3384
  	sctp_chunk_free(asconf);
  	asoc->addip_last_asconf = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3385
3386
  	return retval;
  }
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
3387
  /* Make a FWD TSN chunk. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3388
3389
3390
3391
3392
  struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc,
  				    __u32 new_cum_tsn, size_t nstreams,
  				    struct sctp_fwdtsn_skip *skiplist)
  {
  	struct sctp_chunk *retval = NULL;
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
3393
  	struct sctp_fwdtsn_hdr ftsn_hdr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3394
3395
3396
3397
3398
  	struct sctp_fwdtsn_skip skip;
  	size_t hint;
  	int i;
  
  	hint = (nstreams + 1) * sizeof(__u32);
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
3399
  	retval = sctp_make_control(asoc, SCTP_CID_FWD_TSN, 0, hint, GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3400
3401
3402
  
  	if (!retval)
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
  	ftsn_hdr.new_cum_tsn = htonl(new_cum_tsn);
  	retval->subh.fwdtsn_hdr =
  		sctp_addto_chunk(retval, sizeof(ftsn_hdr), &ftsn_hdr);
  
  	for (i = 0; i < nstreams; i++) {
  		skip.stream = skiplist[i].stream;
  		skip.ssn = skiplist[i].ssn;
  		sctp_addto_chunk(retval, sizeof(skip), &skip);
  	}
  
  	return retval;
  }
cc16f00f6   Xin Long   sctp: add support...
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
  
  /* RE-CONFIG 3.1 (RE-CONFIG chunk)
   *   0                   1                   2                   3
   *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *  | Type = 130    |  Chunk Flags  |      Chunk Length             |
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *  \                                                               \
   *  /                  Re-configuration Parameter                   /
   *  \                                                               \
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *  \                                                               \
   *  /             Re-configuration Parameter (optional)             /
   *  \                                                               \
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   */
327c0dab8   Xin Long   sctp: fix some in...
3431
3432
  static struct sctp_chunk *sctp_make_reconf(const struct sctp_association *asoc,
  					   int length)
cc16f00f6   Xin Long   sctp: add support...
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
  {
  	struct sctp_reconf_chunk *reconf;
  	struct sctp_chunk *retval;
  
  	retval = sctp_make_control(asoc, SCTP_CID_RECONF, 0, length,
  				   GFP_ATOMIC);
  	if (!retval)
  		return NULL;
  
  	reconf = (struct sctp_reconf_chunk *)retval->chunk_hdr;
  	retval->param_hdr.v = reconf->params;
  
  	return retval;
  }
  
  /* RE-CONFIG 4.1 (STREAM OUT RESET)
   *   0                   1                   2                   3
   *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *  |     Parameter Type = 13       | Parameter Length = 16 + 2 * N |
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *  |           Re-configuration Request Sequence Number            |
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *  |           Re-configuration Response Sequence Number           |
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *  |                Sender's Last Assigned TSN                     |
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *  |  Stream Number 1 (optional)   |    Stream Number 2 (optional) |
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *  /                            ......                             /
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *  |  Stream Number N-1 (optional) |    Stream Number N (optional) |
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *
   * RE-CONFIG 4.2 (STREAM IN RESET)
   *   0                   1                   2                   3
   *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *  |     Parameter Type = 14       |  Parameter Length = 8 + 2 * N |
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *  |          Re-configuration Request Sequence Number             |
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *  |  Stream Number 1 (optional)   |    Stream Number 2 (optional) |
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *  /                            ......                             /
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *  |  Stream Number N-1 (optional) |    Stream Number N (optional) |
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   */
  struct sctp_chunk *sctp_make_strreset_req(
327c0dab8   Xin Long   sctp: fix some in...
3483
  					const struct sctp_association *asoc,
1da4fc97c   Xin Long   sctp: fix some ty...
3484
  					__u16 stream_num, __be16 *stream_list,
327c0dab8   Xin Long   sctp: fix some in...
3485
  					bool out, bool in)
cc16f00f6   Xin Long   sctp: add support...
3486
3487
3488
3489
3490
  {
  	struct sctp_strreset_outreq outreq;
  	__u16 stream_len = stream_num * 2;
  	struct sctp_strreset_inreq inreq;
  	struct sctp_chunk *retval;
16e1a9196   Xin Long   sctp: implement r...
3491
  	__u16 outlen, inlen;
cc16f00f6   Xin Long   sctp: add support...
3492
3493
3494
3495
3496
3497
3498
  
  	outlen = (sizeof(outreq) + stream_len) * out;
  	inlen = (sizeof(inreq) + stream_len) * in;
  
  	retval = sctp_make_reconf(asoc, outlen + inlen);
  	if (!retval)
  		return NULL;
cc16f00f6   Xin Long   sctp: add support...
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
  	if (outlen) {
  		outreq.param_hdr.type = SCTP_PARAM_RESET_OUT_REQUEST;
  		outreq.param_hdr.length = htons(outlen);
  		outreq.request_seq = htonl(asoc->strreset_outseq);
  		outreq.response_seq = htonl(asoc->strreset_inseq - 1);
  		outreq.send_reset_at_tsn = htonl(asoc->next_tsn - 1);
  
  		sctp_addto_chunk(retval, sizeof(outreq), &outreq);
  
  		if (stream_len)
  			sctp_addto_chunk(retval, stream_len, stream_list);
  	}
  
  	if (inlen) {
  		inreq.param_hdr.type = SCTP_PARAM_RESET_IN_REQUEST;
  		inreq.param_hdr.length = htons(inlen);
  		inreq.request_seq = htonl(asoc->strreset_outseq + out);
  
  		sctp_addto_chunk(retval, sizeof(inreq), &inreq);
  
  		if (stream_len)
  			sctp_addto_chunk(retval, stream_len, stream_list);
  	}
cc16f00f6   Xin Long   sctp: add support...
3522
3523
  	return retval;
  }
c56480a1e   Xin Long   sctp: add support...
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
  
  /* RE-CONFIG 4.3 (SSN/TSN RESET ALL)
   *   0                   1                   2                   3
   *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *  |     Parameter Type = 15       |      Parameter Length = 8     |
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *  |         Re-configuration Request Sequence Number              |
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   */
  struct sctp_chunk *sctp_make_strreset_tsnreq(
327c0dab8   Xin Long   sctp: fix some in...
3535
  					const struct sctp_association *asoc)
c56480a1e   Xin Long   sctp: add support...
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
  {
  	struct sctp_strreset_tsnreq tsnreq;
  	__u16 length = sizeof(tsnreq);
  	struct sctp_chunk *retval;
  
  	retval = sctp_make_reconf(asoc, length);
  	if (!retval)
  		return NULL;
  
  	tsnreq.param_hdr.type = SCTP_PARAM_RESET_TSN_REQUEST;
  	tsnreq.param_hdr.length = htons(length);
  	tsnreq.request_seq = htonl(asoc->strreset_outseq);
  
  	sctp_addto_chunk(retval, sizeof(tsnreq), &tsnreq);
  
  	return retval;
  }
78098117f   Xin Long   sctp: add support...
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
  
  /* RE-CONFIG 4.5/4.6 (ADD STREAM)
   *   0                   1                   2                   3
   *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *  |     Parameter Type = 17       |      Parameter Length = 12    |
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *  |          Re-configuration Request Sequence Number             |
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *  |      Number of new streams    |         Reserved              |
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   */
  struct sctp_chunk *sctp_make_strreset_addstrm(
327c0dab8   Xin Long   sctp: fix some in...
3566
3567
  					const struct sctp_association *asoc,
  					__u16 out, __u16 in)
78098117f   Xin Long   sctp: add support...
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
  {
  	struct sctp_strreset_addstrm addstrm;
  	__u16 size = sizeof(addstrm);
  	struct sctp_chunk *retval;
  
  	retval = sctp_make_reconf(asoc, (!!out + !!in) * size);
  	if (!retval)
  		return NULL;
  
  	if (out) {
  		addstrm.param_hdr.type = SCTP_PARAM_RESET_ADD_OUT_STREAMS;
  		addstrm.param_hdr.length = htons(size);
  		addstrm.number_of_streams = htons(out);
  		addstrm.request_seq = htonl(asoc->strreset_outseq);
  		addstrm.reserved = 0;
  
  		sctp_addto_chunk(retval, size, &addstrm);
  	}
  
  	if (in) {
  		addstrm.param_hdr.type = SCTP_PARAM_RESET_ADD_IN_STREAMS;
  		addstrm.param_hdr.length = htons(size);
  		addstrm.number_of_streams = htons(in);
  		addstrm.request_seq = htonl(asoc->strreset_outseq + !!out);
  		addstrm.reserved = 0;
  
  		sctp_addto_chunk(retval, size, &addstrm);
  	}
  
  	return retval;
  }
bd4b9f8b4   Xin Long   sctp: add support...
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
  
  /* RE-CONFIG 4.4 (RESP)
   *   0                   1                   2                   3
   *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *  |     Parameter Type = 16       |      Parameter Length         |
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *  |         Re-configuration Response Sequence Number             |
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *  |                            Result                             |
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   */
327c0dab8   Xin Long   sctp: fix some in...
3611
3612
  struct sctp_chunk *sctp_make_strreset_resp(const struct sctp_association *asoc,
  					   __u32 result, __u32 sn)
bd4b9f8b4   Xin Long   sctp: add support...
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
  {
  	struct sctp_strreset_resp resp;
  	__u16 length = sizeof(resp);
  	struct sctp_chunk *retval;
  
  	retval = sctp_make_reconf(asoc, length);
  	if (!retval)
  		return NULL;
  
  	resp.param_hdr.type = SCTP_PARAM_RESET_RESPONSE;
  	resp.param_hdr.length = htons(length);
  	resp.response_seq = htonl(sn);
  	resp.result = htonl(result);
  
  	sctp_addto_chunk(retval, sizeof(resp), &resp);
  
  	return retval;
  }
  
  /* RE-CONFIG 4.4 OPTIONAL (TSNRESP)
   *   0                   1                   2                   3
   *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *  |     Parameter Type = 16       |      Parameter Length         |
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *  |         Re-configuration Response Sequence Number             |
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *  |                            Result                             |
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *  |                   Sender's Next TSN (optional)                |
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *  |                  Receiver's Next TSN (optional)               |
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   */
327c0dab8   Xin Long   sctp: fix some in...
3647
3648
3649
3650
  struct sctp_chunk *sctp_make_strreset_tsnresp(struct sctp_association *asoc,
  					      __u32 result, __u32 sn,
  					      __u32 sender_tsn,
  					      __u32 receiver_tsn)
bd4b9f8b4   Xin Long   sctp: add support...
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
  {
  	struct sctp_strreset_resptsn tsnresp;
  	__u16 length = sizeof(tsnresp);
  	struct sctp_chunk *retval;
  
  	retval = sctp_make_reconf(asoc, length);
  	if (!retval)
  		return NULL;
  
  	tsnresp.param_hdr.type = SCTP_PARAM_RESET_RESPONSE;
  	tsnresp.param_hdr.length = htons(length);
  
  	tsnresp.response_seq = htonl(sn);
  	tsnresp.result = htonl(result);
  	tsnresp.senders_next_tsn = htonl(sender_tsn);
  	tsnresp.receivers_next_tsn = htonl(receiver_tsn);
  
  	sctp_addto_chunk(retval, sizeof(tsnresp), &tsnresp);
  
  	return retval;
  }
ea6250437   Xin Long   sctp: add a funct...
3672
3673
3674
3675
3676
3677
3678
  
  bool sctp_verify_reconf(const struct sctp_association *asoc,
  			struct sctp_chunk *chunk,
  			struct sctp_paramhdr **errp)
  {
  	struct sctp_reconf_chunk *hdr;
  	union sctp_params param;
1da4fc97c   Xin Long   sctp: fix some ty...
3679
3680
  	__be16 last = 0;
  	__u16 cnt = 0;
ea6250437   Xin Long   sctp: add a funct...
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
  
  	hdr = (struct sctp_reconf_chunk *)chunk->chunk_hdr;
  	sctp_walk_params(param, hdr, params) {
  		__u16 length = ntohs(param.p->length);
  
  		*errp = param.p;
  		if (cnt++ > 2)
  			return false;
  		switch (param.p->type) {
  		case SCTP_PARAM_RESET_OUT_REQUEST:
  			if (length < sizeof(struct sctp_strreset_outreq) ||
  			    (last && last != SCTP_PARAM_RESET_RESPONSE &&
  			     last != SCTP_PARAM_RESET_IN_REQUEST))
  				return false;
  			break;
  		case SCTP_PARAM_RESET_IN_REQUEST:
  			if (length < sizeof(struct sctp_strreset_inreq) ||
  			    (last && last != SCTP_PARAM_RESET_OUT_REQUEST))
  				return false;
  			break;
  		case SCTP_PARAM_RESET_RESPONSE:
  			if ((length != sizeof(struct sctp_strreset_resp) &&
  			     length != sizeof(struct sctp_strreset_resptsn)) ||
  			    (last && last != SCTP_PARAM_RESET_RESPONSE &&
  			     last != SCTP_PARAM_RESET_OUT_REQUEST))
  				return false;
  			break;
  		case SCTP_PARAM_RESET_TSN_REQUEST:
  			if (length !=
  			    sizeof(struct sctp_strreset_tsnreq) || last)
  				return false;
  			break;
  		case SCTP_PARAM_RESET_ADD_IN_STREAMS:
  			if (length != sizeof(struct sctp_strreset_addstrm) ||
  			    (last && last != SCTP_PARAM_RESET_ADD_OUT_STREAMS))
  				return false;
  			break;
  		case SCTP_PARAM_RESET_ADD_OUT_STREAMS:
  			if (length != sizeof(struct sctp_strreset_addstrm) ||
  			    (last && last != SCTP_PARAM_RESET_ADD_IN_STREAMS))
  				return false;
  			break;
  		default:
  			return false;
  		}
  
  		last = param.p->type;
  	}
  
  	return true;
  }