Blame view

net/sctp/sm_make_chunk.c 115 KB
47505b8bc   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
60c778b25   Vlad Yasevich   [SCTP]: Stop clai...
2
  /* SCTP kernel implementation
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
5
6
7
   * (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...
8
   * This file is part of the SCTP kernel implementation
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
11
12
13
   *
   * 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.
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
   * Please send any bug reports or fixes you make to the
   * email address(es):
91705c61b   Daniel Borkmann   net: sctp: trivia...
16
   *    lksctp developers <linux-sctp@vger.kernel.org>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
20
21
22
23
24
25
26
27
28
   * 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
29
   */
145ce502e   Joe Perches   net/sctp: Use pr_...
30
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
5821c7697   Herbert Xu   sctp: Use shash
31
  #include <crypto/hash.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
34
35
36
37
  #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
38
  #include <linux/scatterlist.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
39
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
42
43
44
45
  #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...
46
  static struct sctp_chunk *sctp_make_control(const struct sctp_association *asoc,
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
47
48
  					    __u8 type, __u8 flags, int paylen,
  					    gfp_t gfp);
072017b41   Vlad Yasevich   net: sctp: Add ru...
49
  static struct sctp_chunk *sctp_make_data(const struct sctp_association *asoc,
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
50
  					 __u8 flags, int paylen, gfp_t gfp);
072017b41   Vlad Yasevich   net: sctp: Add ru...
51
  static struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc,
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
52
53
  					   __u8 type, __u8 flags, int paylen,
  					   gfp_t gfp);
f48ef4c7f   Xin Long   sctp: remove the ...
54
55
  static struct sctp_cookie_param *sctp_pack_cookie(
  					const struct sctp_endpoint *ep,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
57
58
59
60
61
62
  					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...
63
  			      gfp_t gfp);
8ee4be37e   Vlad Yasevich   SCTP: Fix the sup...
64
65
  static void *sctp_addto_param(struct sctp_chunk *chunk, int len,
  			      const void *data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66

072017b41   Vlad Yasevich   net: sctp: Add ru...
67
68
69
  /* Control chunk destructor */
  static void sctp_control_release_owner(struct sk_buff *skb)
  {
1b1e0bc99   Xin Long   sctp: add refcnt ...
70
  	struct sctp_chunk *chunk = skb_shinfo(skb)->destructor_arg;
ec2e506c6   Xin Long   sctp: add SCTP_AU...
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
  	if (chunk->shkey) {
  		struct sctp_shared_key *shkey = chunk->shkey;
  		struct sctp_association *asoc = chunk->asoc;
  
  		/* refcnt == 2 and !list_empty mean after this release, it's
  		 * not being used anywhere, and it's time to notify userland
  		 * that this shkey can be freed if it's been deactivated.
  		 */
  		if (shkey->deactivated && !list_empty(&shkey->key_list) &&
  		    refcount_read(&shkey->refcnt) == 2) {
  			struct sctp_ulpevent *ev;
  
  			ev = sctp_ulpevent_make_authkey(asoc, shkey->key_id,
  							SCTP_AUTH_FREE_KEY,
  							GFP_KERNEL);
  			if (ev)
  				asoc->stream.si->enqueue_event(&asoc->ulpq, ev);
  		}
1b1e0bc99   Xin Long   sctp: add refcnt ...
89
  		sctp_auth_shkey_release(chunk->shkey);
ec2e506c6   Xin Long   sctp: add SCTP_AU...
90
  	}
072017b41   Vlad Yasevich   net: sctp: Add ru...
91
92
93
94
95
96
97
98
99
100
101
102
103
104
  }
  
  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.
  	 */
1b1e0bc99   Xin Long   sctp: add refcnt ...
105
106
107
108
  	if (chunk->auth) {
  		chunk->shkey = asoc->shkey;
  		sctp_auth_shkey_hold(chunk->shkey);
  	}
072017b41   Vlad Yasevich   net: sctp: Add ru...
109
  	skb->sk = asoc ? asoc->base.sk : NULL;
1b1e0bc99   Xin Long   sctp: add refcnt ...
110
  	skb_shinfo(skb)->destructor_arg = chunk;
072017b41   Vlad Yasevich   net: sctp: Add ru...
111
112
  	skb->destructor = sctp_control_release_owner;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
114
115
  /* What was the inbound interface for this chunk? */
  int sctp_chunk_iif(const struct sctp_chunk *chunk)
  {
e7487c86d   Marcelo Ricardo Leitner   sctp: avoid ident...
116
  	struct sk_buff *skb = chunk->skb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117

e7487c86d   Marcelo Ricardo Leitner   sctp: avoid ident...
118
  	return SCTP_INPUT_CB(skb)->af->skb_iif(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
120
121
122
123
124
125
126
127
  }
  
  /* 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...
128
  	cpu_to_be16(sizeof(struct sctp_paramhdr)),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
130
131
  };
  static const struct sctp_paramhdr prsctp_param = {
  	SCTP_PARAM_FWD_TSN_SUPPORT,
09640e636   Harvey Harrison   net: replace uses...
132
  	cpu_to_be16(sizeof(struct sctp_paramhdr)),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133
  };
8914f4bac   Marcelo Ricardo Leitner   sctp: add sctp_ma...
134
135
  /* A helper to initialize an op error inside a provided chunk, as most
   * cause codes will be embedded inside an abort chunk.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
   */
6d3e8aa87   Marcelo Ricardo Leitner   sctp: allow sctp_...
137
138
  int sctp_init_cause(struct sctp_chunk *chunk, __be16 cause_code,
  		    size_t paylen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
  {
d8238d9da   Xin Long   sctp: remove the ...
140
  	struct sctp_errhdr err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
  	__u16 len;
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
142
  	/* Cause code constants are now defined in network order.  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
  	err.cause = cause_code;
d8238d9da   Xin Long   sctp: remove the ...
144
  	len = sizeof(err) + paylen;
6d3e8aa87   Marcelo Ricardo Leitner   sctp: allow sctp_...
145
146
147
148
  	err.length = htons(len);
  
  	if (skb_tailroom(chunk->skb) < len)
  		return -ENOSPC;
d8238d9da   Xin Long   sctp: remove the ...
149
  	chunk->subh.err_hdr = sctp_addto_chunk(chunk, sizeof(err), &err);
6d3e8aa87   Marcelo Ricardo Leitner   sctp: allow sctp_...
150
151
  
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
153
154
155
156
157
158
159
160
161
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
  }
  
  /* 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...
199
200
  				  const struct sctp_bind_addr *bp,
  				  gfp_t gfp, int vparam_len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
  {
327c0dab8   Xin Long   sctp: fix some in...
202
203
204
205
206
  	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 ...
207
  	struct sctp_endpoint *ep = asoc->ep;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
  	struct sctp_chunk *retval = NULL;
  	int num_types, addrs_len = 0;
327c0dab8   Xin Long   sctp: fix some in...
210
211
  	struct sctp_inithdr init;
  	union sctp_params addrs;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
  	struct sctp_sock *sp;
96b120b3c   Xin Long   sctp: add asoc in...
213
  	__u8 extensions[5];
327c0dab8   Xin Long   sctp: fix some in...
214
  	size_t chunksize;
3dbe86566   Al Viro   [SCTP]: Annotate ...
215
  	__be16 types[2];
131a47e31   Vlad Yasevich   [SCTP]: Implement...
216
  	int num_ext = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
218
219
220
221
222
  
  	/* 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
223
224
225
226
227
228
229
230
231
232
233
234
235
  
  	/* 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...
236
  	chunksize = sizeof(init) + addrs_len;
e2f036a97   Marcelo Ricardo Leitner   sctp: rename WORD...
237
  	chunksize += SCTP_PAD4(SCTP_SAT_LEN(num_types));
1b0b8114b   Xin Long   sctp: make ecn fl...
238
239
240
  
  	if (asoc->ep->ecn_enable)
  		chunksize += sizeof(ecap_param);
8ee4be37e   Vlad Yasevich   SCTP: Fix the sup...
241

1c1347536   Xin Long   sctp: remove prsc...
242
  	if (asoc->ep->prsctp_enable)
036b579b1   Vlad Yasevich   [SCTP]: Add back ...
243
  		chunksize += sizeof(prsctp_param);
131a47e31   Vlad Yasevich   [SCTP]: Implement...
244
245
246
247
  	/* 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...
248
  	 */
4e27428fb   Xin Long   sctp: add asconf_...
249
  	if (asoc->ep->asconf_enable) {
131a47e31   Vlad Yasevich   [SCTP]: Implement...
250
251
252
253
  		extensions[num_ext] = SCTP_CID_ASCONF;
  		extensions[num_ext+1] = SCTP_CID_ASCONF_ACK;
  		num_ext += 2;
  	}
a96701fb3   Xin Long   sctp: remove reco...
254
  	if (asoc->ep->reconf_enable) {
c28445c3c   Xin Long   sctp: add reconf_...
255
256
257
  		extensions[num_ext] = SCTP_CID_RECONF;
  		num_ext += 1;
  	}
6fc791ee6   malc   sctp: add Adaptat...
258
259
  	if (sp->adaptation_ind)
  		chunksize += sizeof(aiparam);
e55f4b8bf   Xin Long   sctp: rename sp s...
260
  	if (asoc->ep->intl_enable) {
96b120b3c   Xin Long   sctp: add asoc in...
261
262
263
  		extensions[num_ext] = SCTP_CID_I_DATA;
  		num_ext += 1;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264
  	chunksize += vparam_len;
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
265
  	/* Account for AUTH related parameters */
b14878ccb   Vlad Yasevich   net: sctp: cache ...
266
  	if (ep->auth_enable) {
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
267
268
269
270
  		/* Add random parameter length*/
  		chunksize += sizeof(asoc->c.auth_random);
  
  		/* Add HMACS parameter length if any were defined */
3c9187049   Xin Long   sctp: remove the ...
271
  		auth_hmacs = (struct sctp_paramhdr *)asoc->c.auth_hmacs;
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
272
  		if (auth_hmacs->length)
e2f036a97   Marcelo Ricardo Leitner   sctp: rename WORD...
273
  			chunksize += SCTP_PAD4(ntohs(auth_hmacs->length));
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
274
275
276
277
  		else
  			auth_hmacs = NULL;
  
  		/* Add CHUNKS parameter length */
3c9187049   Xin Long   sctp: remove the ...
278
  		auth_chunks = (struct sctp_paramhdr *)asoc->c.auth_chunks;
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
279
  		if (auth_chunks->length)
e2f036a97   Marcelo Ricardo Leitner   sctp: rename WORD...
280
  			chunksize += SCTP_PAD4(ntohs(auth_chunks->length));
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
281
  		else
9baffaa68   Vlad Yasevich   SCTP: Fix SCTP-AU...
282
  			auth_chunks = NULL;
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
283
284
285
286
  
  		extensions[num_ext] = SCTP_CID_AUTH;
  		num_ext += 1;
  	}
131a47e31   Vlad Yasevich   [SCTP]: Implement...
287
288
  	/* If we have any extensions to report, account for that */
  	if (num_ext)
15328d9fe   Xin Long   sctp: remove the ...
289
  		chunksize += SCTP_PAD4(sizeof(ext_param) + num_ext);
131a47e31   Vlad Yasevich   [SCTP]: Implement...
290

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
292
293
294
295
296
297
298
299
300
301
  	/* 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_...
302
  	retval = sctp_make_control(asoc, SCTP_CID_INIT, 0, chunksize, gfp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
  	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);
1b0b8114b   Xin Long   sctp: make ecn fl...
322
323
  	if (asoc->ep->ecn_enable)
  		sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param);
131a47e31   Vlad Yasevich   [SCTP]: Implement...
324

7aa1b54b7   Joe Perches   [SCTP]: Spelling ...
325
  	/* Add the supported extensions parameter.  Be nice and add this
131a47e31   Vlad Yasevich   [SCTP]: Implement...
326
327
328
329
  	 * 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 ...
330
331
  		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...
332
  		sctp_addto_param(retval, num_ext, extensions);
131a47e31   Vlad Yasevich   [SCTP]: Implement...
333
  	}
1c1347536   Xin Long   sctp: remove prsc...
334
  	if (asoc->ep->prsctp_enable)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
335
  		sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param);
131a47e31   Vlad Yasevich   [SCTP]: Implement...
336

6fc791ee6   malc   sctp: add Adaptat...
337
338
339
340
341
342
  	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...
343

730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
344
  	/* Add SCTP-AUTH chunks to the parameter list */
b14878ccb   Vlad Yasevich   net: sctp: cache ...
345
  	if (ep->auth_enable) {
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
346
347
348
349
350
351
352
353
354
  		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
355
  nodata:
a51482bde   Jesper Juhl   [NET]: kfree cleanup
356
  	kfree(addrs.v);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
358
359
360
  	return retval;
  }
  
  struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
327c0dab8   Xin Long   sctp: fix some in...
361
362
  				      const struct sctp_chunk *chunk,
  				      gfp_t gfp, int unkparam_len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363
  {
327c0dab8   Xin Long   sctp: fix some in...
364
365
366
367
368
369
370
  	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 ...
371
  	struct sctp_inithdr initack;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372
  	union sctp_params addrs;
6fc791ee6   malc   sctp: add Adaptat...
373
  	struct sctp_sock *sp;
96b120b3c   Xin Long   sctp: add asoc in...
374
  	__u8 extensions[5];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375
  	size_t chunksize;
131a47e31   Vlad Yasevich   [SCTP]: Implement...
376
  	int num_ext = 0;
327c0dab8   Xin Long   sctp: fix some in...
377
378
  	int cookie_len;
  	int addrs_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
  
  	/* 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...
400
  	sp = sctp_sk(asoc->base.sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
401
  	chunksize = sizeof(initack) + addrs_len + cookie_len + unkparam_len;
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
402
  	/* Tell peer that we'll do ECN only if peer advertised such cap.  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
404
  	if (asoc->peer.ecn_capable)
  		chunksize += sizeof(ecap_param);
5ffad5ace   Wei Yongjun   sctp: fix to indi...
405
  	if (asoc->peer.prsctp_capable)
036b579b1   Vlad Yasevich   [SCTP]: Add back ...
406
  		chunksize += sizeof(prsctp_param);
5ffad5ace   Wei Yongjun   sctp: fix to indi...
407
  	if (asoc->peer.asconf_capable) {
131a47e31   Vlad Yasevich   [SCTP]: Implement...
408
409
410
411
  		extensions[num_ext] = SCTP_CID_ASCONF;
  		extensions[num_ext+1] = SCTP_CID_ASCONF_ACK;
  		num_ext += 2;
  	}
c28445c3c   Xin Long   sctp: add reconf_...
412
413
414
415
  	if (asoc->peer.reconf_capable) {
  		extensions[num_ext] = SCTP_CID_RECONF;
  		num_ext += 1;
  	}
6fc791ee6   malc   sctp: add Adaptat...
416
417
  	if (sp->adaptation_ind)
  		chunksize += sizeof(aiparam);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
443
  	/* Now allocate and fill out the chunk.  */
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
444
  	retval = sctp_make_control(asoc, SCTP_CID_INIT_ACK, 0, chunksize, gfp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
446
  	if (!retval)
  		goto nomem_chunk;
b99a4d53a   Dan Carpenter   sctp: cleanup: re...
447
448
449
450
451
452
453
454
  	/* 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
455
  	 */
4ff40b862   Xin Long   sctp: set chunk t...
456
457
458
459
  	if (chunk->transport)
  		retval->transport =
  			sctp_assoc_lookup_paddr(asoc,
  						&chunk->transport->ipaddr);
b99a4d53a   Dan Carpenter   sctp: cleanup: re...
460

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
462
463
464
465
466
  	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...
467
468
  	if (num_ext) {
  		ext_param.param_hdr.type = SCTP_PARAM_SUPPORTED_EXT;
15328d9fe   Xin Long   sctp: remove the ...
469
470
  		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...
471
  		sctp_addto_param(retval, num_ext, extensions);
131a47e31   Vlad Yasevich   [SCTP]: Implement...
472
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
473
474
  	if (asoc->peer.prsctp_capable)
  		sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param);
6fc791ee6   malc   sctp: add Adaptat...
475
476
477
478
479
480
  	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
481

730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
482
483
484
485
486
487
488
489
490
491
  	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
492
493
  	/* We need to remove the const qualifier at this point.  */
  	retval->asoc = (struct sctp_association *) asoc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
494
495
496
  nomem_chunk:
  	kfree(cookie);
  nomem_cookie:
a51482bde   Jesper Juhl   [NET]: kfree cleanup
497
  	kfree(addrs.v);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
532
533
534
535
  	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...
536
  					 const struct sctp_chunk *chunk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
538
  {
  	struct sctp_chunk *retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
  	int cookie_len;
327c0dab8   Xin Long   sctp: fix some in...
540
  	void *cookie;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
542
543
544
545
  
  	cookie = asoc->peer.cookie;
  	cookie_len = asoc->peer.cookie_len;
  
  	/* Build a cookie echo chunk.  */
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
546
547
  	retval = sctp_make_control(asoc, SCTP_CID_COOKIE_ECHO, 0,
  				   cookie_len, GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
584
585
586
587
  	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...
588
  					const struct sctp_chunk *chunk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589
590
  {
  	struct sctp_chunk *retval;
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
591
  	retval = sctp_make_control(asoc, SCTP_CID_COOKIE_ACK, 0, 0, GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592
593
594
595
596
597
598
599
600
601
  
  	/* 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.]
  	 */
4ff40b862   Xin Long   sctp: set chunk t...
602
603
604
605
  	if (retval && chunk && chunk->transport)
  		retval->transport =
  			sctp_assoc_lookup_paddr(asoc,
  						&chunk->transport->ipaddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
  
  	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...
634
635
  				 const __u32 lowest_tsn,
  				 const struct sctp_chunk *chunk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636
637
  {
  	struct sctp_chunk *retval;
65f771054   Xin Long   sctp: remove the ...
638
  	struct sctp_cwrhdr cwr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
639
640
  
  	cwr.lowest_tsn = htonl(lowest_tsn);
072017b41   Vlad Yasevich   net: sctp: Add ru...
641
  	retval = sctp_make_control(asoc, SCTP_CID_ECN_CWR, 0,
65f771054   Xin Long   sctp: remove the ...
642
  				   sizeof(cwr), GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
  
  	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...
669
  				  const __u32 lowest_tsn)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670
671
  {
  	struct sctp_chunk *retval;
1fb6d83bd   Xin Long   sctp: remove the ...
672
  	struct sctp_ecnehdr ecne;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
673
674
  
  	ecne.lowest_tsn = htonl(lowest_tsn);
072017b41   Vlad Yasevich   net: sctp: Add ru...
675
  	retval = sctp_make_control(asoc, SCTP_CID_ECN_ECNE, 0,
1fb6d83bd   Xin Long   sctp: remove the ...
676
  				   sizeof(ecne), GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
677
678
679
680
681
682
683
684
685
686
687
688
  	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.
   */
0c3f6f655   Xin Long   sctp: implement m...
689
  struct sctp_chunk *sctp_make_datafrag_empty(const struct sctp_association *asoc,
327c0dab8   Xin Long   sctp: fix some in...
690
  					    const struct sctp_sndrcvinfo *sinfo,
0c3f6f655   Xin Long   sctp: implement m...
691
  					    int len, __u8 flags, gfp_t gfp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
693
694
  {
  	struct sctp_chunk *retval;
  	struct sctp_datahdr dp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
695
696
697
698
  
  	/* We assign the TSN as LATE as possible, not here when
  	 * creating the chunk.
  	 */
0c3f6f655   Xin Long   sctp: implement m...
699
700
  	memset(&dp, 0, sizeof(dp));
  	dp.ppid = sinfo->sinfo_ppid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
701
  	dp.stream = htons(sinfo->sinfo_stream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
703
  
  	/* Set the flags for an unordered send.  */
0c3f6f655   Xin Long   sctp: implement m...
704
  	if (sinfo->sinfo_flags & SCTP_UNORDERED)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
705
  		flags |= SCTP_DATA_UNORDERED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
706

0c3f6f655   Xin Long   sctp: implement m...
707
  	retval = sctp_make_data(asoc, flags, sizeof(dp) + len, gfp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
708
  	if (!retval)
0c3f6f655   Xin Long   sctp: implement m...
709
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
710
711
712
  
  	retval->subh.data_hdr = sctp_addto_chunk(retval, sizeof(dp), &dp);
  	memcpy(&retval->sinfo, sinfo, sizeof(struct sctp_sndrcvinfo));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
713
714
715
716
717
718
719
  	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.
   */
47b3ba517   Marcelo Ricardo Leitner   sctp: fix const p...
720
  struct sctp_chunk *sctp_make_sack(struct sctp_association *asoc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
721
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
  	struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
02015180e   Vlad Yasevich   sctp: shrink sctp...
723
  	struct sctp_gap_ack_block gabs[SCTP_MAX_GABS];
327c0dab8   Xin Long   sctp: fix some in...
724
  	__u16 num_gabs, num_dup_tsns;
4244854d2   Neil Horman   sctp: be more res...
725
  	struct sctp_transport *trans;
327c0dab8   Xin Long   sctp: fix some in...
726
727
728
729
  	struct sctp_chunk *retval;
  	struct sctp_sackhdr sack;
  	__u32 ctsn;
  	int len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730

02015180e   Vlad Yasevich   sctp: shrink sctp...
731
  	memset(gabs, 0, sizeof(gabs));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
732
  	ctsn = sctp_tsnmap_get_ctsn(map);
bb33381d0   Daniel Borkmann   net: sctp: rework...
733
734
735
  
  	pr_debug("%s: sackCTSNAck sent:0x%x
  ", __func__, ctsn);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
736
737
  
  	/* How much room is needed in the chunk? */
02015180e   Vlad Yasevich   sctp: shrink sctp...
738
  	num_gabs = sctp_tsnmap_num_gabs(map, gabs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
739
740
741
742
743
744
745
746
747
748
749
750
751
  	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_...
752
  	retval = sctp_make_control(asoc, SCTP_CID_SACK, 0, len, GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
754
755
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
  	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...
794
  				 gabs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
795
796
  
  	/* Add the duplicate TSN information.  */
196d67593   Michele Baldessari   sctp: Add support...
797
  	if (num_dup_tsns) {
47b3ba517   Marcelo Ricardo Leitner   sctp: fix const p...
798
  		asoc->stats.idupchunks += num_dup_tsns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
799
800
  		sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
  				 sctp_tsnmap_get_dups(map));
196d67593   Michele Baldessari   sctp: Add support...
801
  	}
4244854d2   Neil Horman   sctp: be more res...
802
803
804
805
806
807
808
809
  	/* 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
  	 */
47b3ba517   Marcelo Ricardo Leitner   sctp: fix const p...
810
  	if (++asoc->peer.sack_generation == 0) {
4244854d2   Neil Horman   sctp: be more res...
811
812
813
  		list_for_each_entry(trans, &asoc->peer.transport_addr_list,
  				    transports)
  			trans->sack_generation = 0;
47b3ba517   Marcelo Ricardo Leitner   sctp: fix const p...
814
  		asoc->peer.sack_generation = 1;
4244854d2   Neil Horman   sctp: be more res...
815
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
816
817
818
819
820
821
822
823
  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 ...
824
  	struct sctp_shutdownhdr shut;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
825
  	struct sctp_chunk *retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
826
  	__u32 ctsn;
12dfd78e3   Jere Leppänen   sctp: Fix SHUTDOW...
827
828
829
830
  	if (chunk && chunk->asoc)
  		ctsn = sctp_tsnmap_get_ctsn(&chunk->asoc->peer.tsn_map);
  	else
  		ctsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
831
  	shut.cum_tsn_ack = htonl(ctsn);
072017b41   Vlad Yasevich   net: sctp: Add ru...
832
  	retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN, 0,
e61e4055b   Xin Long   sctp: remove the ...
833
  				   sizeof(shut), GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
834
835
836
837
838
839
840
841
842
843
844
845
846
  	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...
847
  					  const struct sctp_chunk *chunk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
848
849
  {
  	struct sctp_chunk *retval;
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
850
851
  	retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN_ACK, 0, 0,
  				   GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
  
  	/* 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...
869
870
  					const struct sctp_association *asoc,
  					const struct sctp_chunk *chunk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
871
872
873
  {
  	struct sctp_chunk *retval;
  	__u8 flags = 0;
047a2428a   Jerome Forissier   [SCTP] Implement ...
874
875
876
  	/* Set the T-bit if we have no association (vtag will be
  	 * reflected)
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
877
  	flags |= asoc ? 0 : SCTP_CHUNK_FLAG_T;
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
878
879
  	retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN_COMPLETE, flags,
  				   0, GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
880
881
882
883
884
885
886
887
888
889
890
891
892
  
  	/* 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...
893
  	return retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
894
895
896
  }
  
  /* Create an ABORT.  Note that we set the T bit if we have no
047a2428a   Jerome Forissier   [SCTP] Implement ...
897
   * association, except when responding to an INIT (sctpimpguide 2.41).
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
898
899
   */
  struct sctp_chunk *sctp_make_abort(const struct sctp_association *asoc,
327c0dab8   Xin Long   sctp: fix some in...
900
901
  				   const struct sctp_chunk *chunk,
  				   const size_t hint)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
902
903
904
  {
  	struct sctp_chunk *retval;
  	__u8 flags = 0;
047a2428a   Jerome Forissier   [SCTP] Implement ...
905
906
907
908
909
910
911
912
913
914
  	/* 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
915

cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
916
917
  	retval = sctp_make_control(asoc, SCTP_CID_ABORT, flags, hint,
  				   GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
  
  	/* 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...
936
937
938
  					const struct sctp_association *asoc,
  					const struct sctp_chunk *chunk,
  					__u32 tsn)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
939
940
  {
  	struct sctp_chunk *retval;
9f81bcd94   Al Viro   [SCTP]: More triv...
941
  	__be32 payload;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
942

d8238d9da   Xin Long   sctp: remove the ...
943
944
  	retval = sctp_make_abort(asoc, chunk,
  				 sizeof(struct sctp_errhdr) + sizeof(tsn));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
945
946
947
948
949
950
  
  	if (!retval)
  		goto no_mem;
  
  	/* Put the tsn back into network byte order.  */
  	payload = htonl(tsn);
00f1c2df2   Wei Yongjun   SCTP: Fix to enco...
951
952
  	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
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
  
  	/* 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...
972
  					struct msghdr *msg,
c164a9ba0   Sridhar Samudrala   Fix sctp privileg...
973
  					size_t paylen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
974
975
  {
  	struct sctp_chunk *retval;
c164a9ba0   Sridhar Samudrala   Fix sctp privileg...
976
977
  	void *payload = NULL;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
978

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

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

cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
1102
1103
  	retval = sctp_make_control(asoc, SCTP_CID_HEARTBEAT, 0,
  				   sizeof(hbinfo), GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1104
1105
1106
  
  	if (!retval)
  		goto nodata;
92c73af58   Wei Yongjun   sctp: make heartb...
1107
  	hbinfo.param_hdr.type = SCTP_PARAM_HEARTBEAT_INFO;
edf903f83   Xin Long   sctp: remove the ...
1108
  	hbinfo.param_hdr.length = htons(sizeof(hbinfo));
92c73af58   Wei Yongjun   sctp: make heartb...
1109
1110
1111
  	hbinfo.daddr = transport->ipaddr;
  	hbinfo.sent_at = jiffies;
  	hbinfo.hb_nonce = transport->hb_nonce;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1112
1113
1114
1115
  	/* 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...
1116
1117
  	retval->subh.hbs_hdr = sctp_addto_chunk(retval, sizeof(hbinfo),
  						&hbinfo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1118
1119
1120
1121
1122
1123
  
  nodata:
  	return retval;
  }
  
  struct sctp_chunk *sctp_make_heartbeat_ack(const struct sctp_association *asoc,
327c0dab8   Xin Long   sctp: fix some in...
1124
1125
1126
  					   const struct sctp_chunk *chunk,
  					   const void *payload,
  					   const size_t paylen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1127
1128
  {
  	struct sctp_chunk *retval;
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
1129
1130
  	retval  = sctp_make_control(asoc, SCTP_CID_HEARTBEAT_ACK, 0, paylen,
  				    GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
  	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...
1156
1157
1158
  					const struct sctp_association *asoc,
  					const struct sctp_chunk *chunk,
  					size_t size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1159
1160
  {
  	struct sctp_chunk *retval;
072017b41   Vlad Yasevich   net: sctp: Add ru...
1161
  	retval = sctp_make_control(asoc, SCTP_CID_ERROR, 0,
d8238d9da   Xin Long   sctp: remove the ...
1162
1163
  				   sizeof(struct sctp_errhdr) + size,
  				   GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
  	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;
  }
8914f4bac   Marcelo Ricardo Leitner   sctp: add sctp_ma...
1181
1182
  /* Create an Operation Error chunk of a fixed size, specifically,
   * min(asoc->pathmtu, SCTP_DEFAULT_MAXSEGMENT) - overheads.
14f45bb7b   Randy Dunlap   net: sctp: sm_mak...
1183
   * This is a helper function to allocate an error chunk for those
8914f4bac   Marcelo Ricardo Leitner   sctp: add sctp_ma...
1184
1185
1186
   * invalid parameter codes in which we may not want to report all the
   * errors, if the incoming chunk is large. If it can't fit in a single
   * packet, we ignore it.
5fa782c2f   Neil Horman   sctp: Fix skb_ove...
1187
   */
8914f4bac   Marcelo Ricardo Leitner   sctp: add sctp_ma...
1188
  static inline struct sctp_chunk *sctp_make_op_error_limited(
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
  {
8914f4bac   Marcelo Ricardo Leitner   sctp: add sctp_ma...
1192
1193
1194
1195
1196
1197
1198
  	size_t size = SCTP_DEFAULT_MAXSEGMENT;
  	struct sctp_sock *sp = NULL;
  
  	if (asoc) {
  		size = min_t(size_t, size, asoc->pathmtu);
  		sp = sctp_sk(asoc->base.sk);
  	}
5fa782c2f   Neil Horman   sctp: Fix skb_ove...
1199

8914f4bac   Marcelo Ricardo Leitner   sctp: add sctp_ma...
1200
  	size = sctp_mtu_payload(sp, size, sizeof(struct sctp_errhdr));
5fa782c2f   Neil Horman   sctp: Fix skb_ove...
1201
1202
1203
  
  	return sctp_make_op_error_space(asoc, chunk, size);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1204
1205
  /* Create an Operation Error chunk.  */
  struct sctp_chunk *sctp_make_op_error(const struct sctp_association *asoc,
327c0dab8   Xin Long   sctp: fix some in...
1206
1207
1208
  				      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
1209
1210
  {
  	struct sctp_chunk *retval;
6383cfb3e   Vlad Yasevich   sctp: Fix malform...
1211
  	retval = sctp_make_op_error_space(asoc, chunk, paylen + reserve_tail);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1212
1213
  	if (!retval)
  		goto nodata;
6383cfb3e   Vlad Yasevich   sctp: Fix malform...
1214
  	sctp_init_cause(retval, cause_code, paylen + reserve_tail);
00f1c2df2   Wei Yongjun   SCTP: Fix to enco...
1215
  	sctp_addto_chunk(retval, paylen, payload);
6383cfb3e   Vlad Yasevich   sctp: Fix malform...
1216
1217
  	if (reserve_tail)
  		sctp_addto_param(retval, reserve_tail, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1218
1219
1220
1221
  
  nodata:
  	return retval;
  }
1b1e0bc99   Xin Long   sctp: add refcnt ...
1222
1223
  struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc,
  				  __u16 key_id)
4cd57c807   Vlad Yasevich   [SCTP]: Enable th...
1224
  {
4cd57c807   Vlad Yasevich   [SCTP]: Enable th...
1225
  	struct sctp_authhdr auth_hdr;
327c0dab8   Xin Long   sctp: fix some in...
1226
1227
  	struct sctp_hmac *hmac_desc;
  	struct sctp_chunk *retval;
4cd57c807   Vlad Yasevich   [SCTP]: Enable th...
1228
1229
1230
1231
1232
  
  	/* 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...
1233
  	retval = sctp_make_control(asoc, SCTP_CID_AUTH, 0,
96f7ef4d5   Xin Long   sctp: remove the ...
1234
1235
  				   hmac_desc->hmac_len + sizeof(auth_hdr),
  				   GFP_ATOMIC);
4cd57c807   Vlad Yasevich   [SCTP]: Enable th...
1236
1237
1238
1239
  	if (!retval)
  		return NULL;
  
  	auth_hdr.hmac_id = htons(hmac_desc->hmac_id);
1b1e0bc99   Xin Long   sctp: add refcnt ...
1240
  	auth_hdr.shkey_id = htons(key_id);
4cd57c807   Vlad Yasevich   [SCTP]: Enable th...
1241

96f7ef4d5   Xin Long   sctp: remove the ...
1242
1243
  	retval->subh.auth_hdr = sctp_addto_chunk(retval, sizeof(auth_hdr),
  						 &auth_hdr);
4cd57c807   Vlad Yasevich   [SCTP]: Enable th...
1244

594831a8a   Marcelo Ricardo Leitner   sctp: removed unu...
1245
  	skb_put_zero(retval->skb, hmac_desc->hmac_len);
4cd57c807   Vlad Yasevich   [SCTP]: Enable th...
1246
1247
1248
1249
1250
1251
1252
1253
  
  	/* 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
1254
1255
1256
1257
1258
1259
  /********************************************************************
   * 2nd Level Abstractions
   ********************************************************************/
  
  /* Turn an skb into a chunk.
   * FIXME: Eventually move the structure directly inside the skb->cb[].
3dc0a548a   wangweidong   sctp: remove the ...
1260
1261
1262
1263
1264
1265
1266
   *
   * 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
1267
1268
   */
  struct sctp_chunk *sctp_chunkify(struct sk_buff *skb,
327c0dab8   Xin Long   sctp: fix some in...
1269
1270
  				 const struct sctp_association *asoc,
  				 struct sock *sk, gfp_t gfp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1271
1272
  {
  	struct sctp_chunk *retval;
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
1273
  	retval = kmem_cache_zalloc(sctp_chunk_cachep, gfp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1274
1275
1276
  
  	if (!retval)
  		goto nodata;
bb33381d0   Daniel Borkmann   net: sctp: rework...
1277
1278
1279
  	if (!sk)
  		pr_debug("%s: chunkifying skb:%p w/o an sk
  ", __func__, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1280

79af02c25   David S. Miller   [SCTP]: Use struc...
1281
  	INIT_LIST_HEAD(&retval->list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1282
1283
  	retval->skb		= skb;
  	retval->asoc		= (struct sctp_association *)asoc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1284
  	retval->singleton	= 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1285

3dc0a548a   wangweidong   sctp: remove the ...
1286
  	retval->fast_retransmit = SCTP_CAN_FRTX;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1287
1288
1289
1290
1291
  
  	/* 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...
1292
  	refcount_set(&retval->refcnt, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1293
1294
1295
1296
1297
1298
1299
1300
1301
  
  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...
1302
  	memcpy(&chunk->source, src, sizeof(union sctp_addr));
16b0a0303   Al Viro   [SCTP]: Switch sc...
1303
  	memcpy(&chunk->dest, dest, sizeof(union sctp_addr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1304
1305
1306
1307
1308
1309
1310
  }
  
  /* 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...
1311
  		return &chunk->transport->ipaddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1312
1313
  	} else {
  		/* Otherwise, extract it from the IP header.  */
6a1e5f335   Al Viro   [SCTP]: sctp_proc...
1314
  		return &chunk->source;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1315
1316
1317
1318
1319
1320
  	}
  }
  
  /* 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...
1321
  static struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc,
327c0dab8   Xin Long   sctp: fix some in...
1322
1323
  					   __u8 type, __u8 flags, int paylen,
  					   gfp_t gfp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1324
  {
922dbc5be   Xin Long   sctp: remove the ...
1325
  	struct sctp_chunkhdr *chunk_hdr;
327c0dab8   Xin Long   sctp: fix some in...
1326
  	struct sctp_chunk *retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1327
1328
  	struct sk_buff *skb;
  	struct sock *sk;
07f2c7ab6   Alexey Kodanev   sctp: verify size...
1329
1330
1331
1332
1333
  	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
1334
1335
  
  	/* No need to allocate LL here, as this is only a chunk. */
07f2c7ab6   Alexey Kodanev   sctp: verify size...
1336
  	skb = alloc_skb(chunklen, gfp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1337
1338
1339
1340
  	if (!skb)
  		goto nodata;
  
  	/* Make room for the chunk header.  */
922dbc5be   Xin Long   sctp: remove the ...
1341
  	chunk_hdr = (struct sctp_chunkhdr *)skb_put(skb, sizeof(*chunk_hdr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1342
1343
  	chunk_hdr->type	  = type;
  	chunk_hdr->flags  = flags;
922dbc5be   Xin Long   sctp: remove the ...
1344
  	chunk_hdr->length = htons(sizeof(*chunk_hdr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1345
1346
  
  	sk = asoc ? asoc->base.sk : NULL;
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
1347
  	retval = sctp_chunkify(skb, asoc, sk, gfp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1348
1349
1350
1351
1352
1353
  	if (!retval) {
  		kfree_skb(skb);
  		goto nodata;
  	}
  
  	retval->chunk_hdr = chunk_hdr;
922dbc5be   Xin Long   sctp: remove the ...
1354
  	retval->chunk_end = ((__u8 *)chunk_hdr) + sizeof(*chunk_hdr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1355

4cd57c807   Vlad Yasevich   [SCTP]: Enable th...
1356
1357
1358
  	/* 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
1359
1360
1361
1362
  	return retval;
  nodata:
  	return NULL;
  }
072017b41   Vlad Yasevich   net: sctp: Add ru...
1363
  static struct sctp_chunk *sctp_make_data(const struct sctp_association *asoc,
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
1364
  					 __u8 flags, int paylen, gfp_t gfp)
072017b41   Vlad Yasevich   net: sctp: Add ru...
1365
  {
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
1366
  	return _sctp_make_chunk(asoc, SCTP_CID_DATA, flags, paylen, gfp);
072017b41   Vlad Yasevich   net: sctp: Add ru...
1367
  }
ad05a7a05   Xin Long   sctp: add basic s...
1368
1369
1370
1371
1372
  struct sctp_chunk *sctp_make_idata(const struct sctp_association *asoc,
  				   __u8 flags, int paylen, gfp_t gfp)
  {
  	return _sctp_make_chunk(asoc, SCTP_CID_I_DATA, flags, paylen, gfp);
  }
072017b41   Vlad Yasevich   net: sctp: Add ru...
1373
  static struct sctp_chunk *sctp_make_control(const struct sctp_association *asoc,
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
1374
1375
  					    __u8 type, __u8 flags, int paylen,
  					    gfp_t gfp)
072017b41   Vlad Yasevich   net: sctp: Add ru...
1376
  {
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
1377
  	struct sctp_chunk *chunk;
072017b41   Vlad Yasevich   net: sctp: Add ru...
1378

cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
1379
  	chunk = _sctp_make_chunk(asoc, type, flags, paylen, gfp);
072017b41   Vlad Yasevich   net: sctp: Add ru...
1380
1381
1382
1383
1384
  	if (chunk)
  		sctp_control_set_owner_w(chunk);
  
  	return chunk;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1385
1386
1387
1388
  
  /* Release the memory occupied by a chunk.  */
  static void sctp_chunk_destroy(struct sctp_chunk *chunk)
  {
a08de64d0   Vlad Yasevich   [SCTP]: Update AS...
1389
1390
  	BUG_ON(!list_empty(&chunk->list));
  	list_del_init(&chunk->transmitted_list);
c485658ba   Daniel Borkmann   net: sctp: fix sk...
1391
1392
  	consume_skb(chunk->skb);
  	consume_skb(chunk->auth_chunk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1393
1394
1395
1396
1397
1398
1399
1400
  
  	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
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
  	/* 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...
1411
  	refcount_inc(&ch->refcnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1412
1413
1414
1415
1416
  }
  
  /* Release a reference to the chunk. */
  void sctp_chunk_put(struct sctp_chunk *ch)
  {
e7f027961   Reshetova, Elena   net, sctp: conver...
1417
  	if (refcount_dec_and_test(&ch->refcnt))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1418
1419
1420
1421
1422
1423
1424
1425
  		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
1426
  	int chunklen = ntohs(chunk->chunk_hdr->length);
e2f036a97   Marcelo Ricardo Leitner   sctp: rename WORD...
1427
  	int padlen = SCTP_PAD4(chunklen) - chunklen;
327c0dab8   Xin Long   sctp: fix some in...
1428
  	void *target;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1429

b952f4dff   yuan linyu   net: manual clean...
1430
  	skb_put_zero(chunk->skb, padlen);
59ae1d127   Johannes Berg   networking: intro...
1431
  	target = skb_put_data(chunk->skb, data, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1432
1433
1434
  
  	/* Adjust the chunk length field.  */
  	chunk->chunk_hdr->length = htons(chunklen + padlen + len);
27a884dc3   Arnaldo Carvalho de Melo   [SK_BUFF]: Conver...
1435
  	chunk->chunk_end = skb_tail_pointer(chunk->skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1436
1437
1438
1439
1440
1441
1442
1443
  
  	return target;
  }
  
  /* 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) {
75b93c635   Eric Biggers   sctp: use crypto_...
1600
  		struct crypto_shash *tfm = sctp_sk(ep->base.sk)->hmac;
5821c7697   Herbert Xu   sctp: Use shash
1601
  		int err;
1b489e11d   Herbert Xu   [SCTP]: Use HMAC ...
1602

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

9834a2bb4   Vlad Yasevich   [SCTP]: Fix sctp_...
1637
1638
1639
  	/* Header size is static data prior to the actual cookie, including
  	 * any padding.
  	 */
922dbc5be   Xin Long   sctp: remove the ...
1640
  	headersize = sizeof(struct sctp_chunkhdr) +
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
1641
  		     (sizeof(struct sctp_signed_cookie) -
9834a2bb4   Vlad Yasevich   [SCTP]: Fix sctp_...
1642
  		      sizeof(struct sctp_cookie));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
  	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
1666
  	{
75b93c635   Eric Biggers   sctp: use crypto_...
1667
  		struct crypto_shash *tfm = sctp_sk(ep->base.sk)->hmac;
5821c7697   Herbert Xu   sctp: Use shash
1668
  		int err;
75b93c635   Eric Biggers   sctp: use crypto_...
1669
  		err = crypto_shash_setkey(tfm, ep->secret_key,
5821c7697   Herbert Xu   sctp: Use shash
1670
  					  sizeof(ep->secret_key)) ?:
75b93c635   Eric Biggers   sctp: use crypto_...
1671
1672
  		      crypto_shash_tfm_digest(tfm, (u8 *)bear_cookie, bodysize,
  					      digest);
5821c7697   Herbert Xu   sctp: Use shash
1673
1674
1675
1676
  		if (err) {
  			*error = -SCTP_IERROR_NOMEM;
  			goto fail;
  		}
1b489e11d   Herbert Xu   [SCTP]: Use HMAC ...
1677
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1678
1679
  
  	if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) {
570617e79   Daniel Borkmann   net: sctp: remove...
1680
1681
  		*error = -SCTP_IERROR_BAD_SIG;
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
  	}
  
  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...
1696
  	if (chunk->sctp_hdr->source != bear_cookie->peer_addr.v4.sin_port ||
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1697
1698
1699
1700
1701
1702
1703
1704
  	    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...
1705
1706
  	 * If skb has been timestamped, then use the stamp, otherwise
  	 * use current time.  This introduces a small possibility that
14f45bb7b   Randy Dunlap   net: sctp: sm_mak...
1707
  	 * a cookie may be considered expired, but this would only slow
f236218b7   Vlad Yasevich   [SCTP]: Do not ti...
1708
  	 * down the new association establishment instead of every packet.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1709
  	 */
f236218b7   Vlad Yasevich   [SCTP]: Do not ti...
1710
  	if (sock_flag(ep->base.sk, SOCK_TIMESTAMP))
52db882f3   Daniel Borkmann   net: sctp: migrat...
1711
  		kt = skb_get_ktime(skb);
f236218b7   Vlad Yasevich   [SCTP]: Do not ti...
1712
  	else
cb5e173ed   Marcelo Ricardo Leitner   sctp: use the sam...
1713
  		kt = ktime_get_real();
f236218b7   Vlad Yasevich   [SCTP]: Do not ti...
1714

67cb9366f   Daniel Borkmann   ktime: add ktime_...
1715
  	if (!asoc && ktime_before(bear_cookie->expiration, kt)) {
8914f4bac   Marcelo Ricardo Leitner   sctp: add sctp_ma...
1716
1717
  		suseconds_t usecs = ktime_to_us(ktime_sub(kt, bear_cookie->expiration));
  		__be32 n = htonl(usecs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1718
1719
1720
1721
1722
1723
1724
1725
  		/*
  		 * 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.
  		 */
8914f4bac   Marcelo Ricardo Leitner   sctp: add sctp_ma...
1726
1727
1728
1729
  		*errp = sctp_make_op_error(asoc, chunk,
  					   SCTP_ERROR_STALE_COOKIE, &n,
  					   sizeof(n), 0);
  		if (*errp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1730
  			*error = -SCTP_IERROR_STALE_COOKIE;
8914f4bac   Marcelo Ricardo Leitner   sctp: add sctp_ma...
1731
  		else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
  			*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...
1759
  		sctp_add_bind_addr(&retval->base.bind_addr, &chunk->dest,
133800d1f   Marcelo Ricardo Leitner   sctp: fix copying...
1760
1761
  				   sizeof(chunk->dest), SCTP_ADDR_SRC,
  				   GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1762
1763
1764
1765
1766
  	}
  
  	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...
1767
  	retval->strreset_outseq = retval->c.initial_tsn;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1768
1769
  	retval->adv_peer_ack_point = retval->ctsn_ack_point;
  	retval->peer.prsctp_capable = retval->c.prsctp_capable;
0f3fffd8a   Ivan Skytte Jorgensen   [SCTP]: Fix typo ...
1770
  	retval->peer.adaptation_ind = retval->c.adaptation_ind;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
  
  	/* 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...
1794
1795
  	__be32 num_missing;
  	__be16 type;
bc10502db   Eric Dumazet   net: use __packed...
1796
  }  __packed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1797
1798
1799
1800
1801
  
  /*
   * Report a missing mandatory parameter.
   */
  static int sctp_process_missing_param(const struct sctp_association *asoc,
34b4e29b3   Xin Long   sctp: remove the ...
1802
  				      enum sctp_param paramtype,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1803
1804
1805
1806
1807
  				      struct sctp_chunk *chunk,
  				      struct sctp_chunk **errp)
  {
  	struct __sctp_missing report;
  	__u16 len;
e2f036a97   Marcelo Ricardo Leitner   sctp: rename WORD...
1808
  	len = SCTP_PAD4(sizeof(report));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
  
  	/* 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...
1819
  		sctp_init_cause(*errp, SCTP_ERROR_MISS_PARAM,
00f1c2df2   Wei Yongjun   SCTP: Fix to enco...
1820
1821
  				sizeof(report));
  		sctp_addto_chunk(*errp, sizeof(report), &report);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
  	}
  
  	/* 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...
1839
  		sctp_init_cause(*errp, SCTP_ERROR_INV_PARAM, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
  
  	/* 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...
1850
1851
1852
1853
1854
  	/* 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
1855
  	/* Create an error chunk and fill it in with our payload. */
ba0166708   Wei Yongjun   sctp: Fix kernel ...
1856
  	*errp = sctp_make_violation_paramlen(asoc, chunk, param);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
  
  	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...
1871
1872
1873
1874
1875
1876
1877
  	/* 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);
8914f4bac   Marcelo Ricardo Leitner   sctp: add sctp_ma...
1878
1879
  	*errp = sctp_make_op_error(asoc, chunk, SCTP_ERROR_DNS_FAILED,
  				   param.v, len, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1880
1881
1882
1883
  
  	/* Stop processing this chunk. */
  	return 0;
  }
4e27428fb   Xin Long   sctp: add asconf_...
1884
1885
1886
  static int sctp_verify_ext_param(struct net *net,
  				 const struct sctp_endpoint *ep,
  				 union sctp_params param)
d67011913   Vlad Yasevich   [SCTP]: Follow Ad...
1887
  {
3c9187049   Xin Long   sctp: remove the ...
1888
  	__u16 num_ext = ntohs(param.p->length) - sizeof(struct sctp_paramhdr);
d67011913   Vlad Yasevich   [SCTP]: Follow Ad...
1889
  	int have_asconf = 0;
327c0dab8   Xin Long   sctp: fix some in...
1890
  	int have_auth = 0;
d67011913   Vlad Yasevich   [SCTP]: Follow Ad...
1891
1892
1893
1894
  	int i;
  
  	for (i = 0; i < num_ext; i++) {
  		switch (param.ext->chunks[i]) {
f7010e614   wangweidong   sctp: fix checkpa...
1895
1896
1897
1898
1899
1900
1901
  		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...
1902
1903
1904
1905
1906
1907
1908
1909
  		}
  	}
  
  	/* 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...
1910
  	if (net->sctp.addip_noauth)
d67011913   Vlad Yasevich   [SCTP]: Follow Ad...
1911
  		return 1;
4e27428fb   Xin Long   sctp: add asconf_...
1912
  	if (ep->asconf_enable && !have_auth && have_asconf)
d67011913   Vlad Yasevich   [SCTP]: Follow Ad...
1913
1914
1915
1916
  		return 0;
  
  	return 1;
  }
131a47e31   Vlad Yasevich   [SCTP]: Implement...
1917
  static void sctp_process_ext_param(struct sctp_association *asoc,
327c0dab8   Xin Long   sctp: fix some in...
1918
  				   union sctp_params param)
131a47e31   Vlad Yasevich   [SCTP]: Implement...
1919
  {
3c9187049   Xin Long   sctp: remove the ...
1920
  	__u16 num_ext = ntohs(param.p->length) - sizeof(struct sctp_paramhdr);
131a47e31   Vlad Yasevich   [SCTP]: Implement...
1921
1922
1923
1924
  	int i;
  
  	for (i = 0; i < num_ext; i++) {
  		switch (param.ext->chunks[i]) {
c28445c3c   Xin Long   sctp: add reconf_...
1925
  		case SCTP_CID_RECONF:
a96701fb3   Xin Long   sctp: remove reco...
1926
  			if (asoc->ep->reconf_enable)
c28445c3c   Xin Long   sctp: add reconf_...
1927
1928
  				asoc->peer.reconf_capable = 1;
  			break;
f7010e614   wangweidong   sctp: fix checkpa...
1929
  		case SCTP_CID_FWD_TSN:
1c1347536   Xin Long   sctp: remove prsc...
1930
  			if (asoc->ep->prsctp_enable)
28aa4c26f   Xin Long   sctp: add SCTP_PR...
1931
  				asoc->peer.prsctp_capable = 1;
f7010e614   wangweidong   sctp: fix checkpa...
1932
1933
1934
1935
1936
  			break;
  		case SCTP_CID_AUTH:
  			/* if the peer reports AUTH, assume that he
  			 * supports AUTH.
  			 */
b14878ccb   Vlad Yasevich   net: sctp: cache ...
1937
  			if (asoc->ep->auth_enable)
f7010e614   wangweidong   sctp: fix checkpa...
1938
1939
1940
1941
  				asoc->peer.auth_capable = 1;
  			break;
  		case SCTP_CID_ASCONF:
  		case SCTP_CID_ASCONF_ACK:
4e27428fb   Xin Long   sctp: add asconf_...
1942
  			if (asoc->ep->asconf_enable)
f7010e614   wangweidong   sctp: fix checkpa...
1943
1944
  				asoc->peer.asconf_capable = 1;
  			break;
96b120b3c   Xin Long   sctp: add asoc in...
1945
  		case SCTP_CID_I_DATA:
e55f4b8bf   Xin Long   sctp: rename sp s...
1946
  			if (asoc->ep->intl_enable)
da1f6d4de   Xin Long   sctp: rename asoc...
1947
  				asoc->peer.intl_capable = 1;
96b120b3c   Xin Long   sctp: add asoc in...
1948
  			break;
f7010e614   wangweidong   sctp: fix checkpa...
1949
1950
  		default:
  			break;
131a47e31   Vlad Yasevich   [SCTP]: Implement...
1951
1952
1953
  		}
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1954
1955
1956
1957
1958
1959
1960
  /* 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...
1961
1962
   * 00 - Stop processing this parameter; do not process any further
   * 	parameters within this chunk
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1963
   *
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
1964
1965
1966
   * 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
1967
1968
1969
1970
1971
   *
   * 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...
1972
   *	'Unrecognized Parameter' ERROR chunk.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1973
1974
   *
   * Return value:
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
1975
1976
1977
   * 	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
1978
   */
4785c7ae1   Xin Long   sctp: remove the ...
1979
1980
1981
1982
1983
  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
1984
  {
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
1985
  	int retval = SCTP_IERROR_NO_ERROR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1986
1987
1988
  
  	switch (param.p->type & SCTP_PARAM_ACTION_MASK) {
  	case SCTP_PARAM_ACTION_DISCARD:
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
1989
  		retval =  SCTP_IERROR_ERROR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1990
1991
1992
  		break;
  	case SCTP_PARAM_ACTION_SKIP:
  		break;
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
1993
1994
  	case SCTP_PARAM_ACTION_DISCARD_ERR:
  		retval =  SCTP_IERROR_ERROR;
df561f668   Gustavo A. R. Silva   treewide: Use fal...
1995
  		fallthrough;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1996
1997
1998
1999
  	case SCTP_PARAM_ACTION_SKIP_ERR:
  		/* Make an ERROR chunk, preparing enough room for
  		 * returning multiple unknown parameters.
  		 */
8914f4bac   Marcelo Ricardo Leitner   sctp: add sctp_ma...
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
  		if (!*errp) {
  			*errp = sctp_make_op_error_limited(asoc, chunk);
  			if (!*errp) {
  				/* 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.
  				 */
  				retval = SCTP_IERROR_NOMEM;
  				break;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2011
  		}
8914f4bac   Marcelo Ricardo Leitner   sctp: add sctp_ma...
2012
2013
2014
2015
2016
  
  		if (!sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM,
  				     ntohs(param.p->length)))
  			sctp_addto_chunk(*errp, ntohs(param.p->length),
  					 param.v);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2017
2018
2019
2020
2021
2022
2023
  		break;
  	default:
  		break;
  	}
  
  	return retval;
  }
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
2024
  /* Verify variable length parameters
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2025
   * Return values:
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
2026
2027
2028
2029
   * 	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
2030
   */
4785c7ae1   Xin Long   sctp: remove the ...
2031
2032
2033
2034
2035
2036
2037
  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
2038
  {
72da7b386   Wei Yongjun   [SCTP]: Add check...
2039
  	struct sctp_hmac_algo_param *hmacs;
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
2040
  	int retval = SCTP_IERROR_NO_ERROR;
72da7b386   Wei Yongjun   [SCTP]: Add check...
2041
2042
  	__u16 n_elt, id = 0;
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
  
  	/* 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 ...
2058
  	case SCTP_PARAM_ADAPTATION_LAYER_IND:
d67011913   Vlad Yasevich   [SCTP]: Follow Ad...
2059
  		break;
131a47e31   Vlad Yasevich   [SCTP]: Implement...
2060
  	case SCTP_PARAM_SUPPORTED_EXT:
4e27428fb   Xin Long   sctp: add asconf_...
2061
  		if (!sctp_verify_ext_param(net, ep, param))
d67011913   Vlad Yasevich   [SCTP]: Follow Ad...
2062
  			return SCTP_IERROR_ABORT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2063
  		break;
d6de30975   Vlad Yasevich   [SCTP]: Add the h...
2064
  	case SCTP_PARAM_SET_PRIMARY:
4e27428fb   Xin Long   sctp: add asconf_...
2065
  		if (ep->asconf_enable)
d6de30975   Vlad Yasevich   [SCTP]: Add the h...
2066
  			break;
48f9bcf91   Joe Perches   net: sctp: Rename...
2067
  		goto unhandled;
d6de30975   Vlad Yasevich   [SCTP]: Add the h...
2068

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2069
2070
  	case SCTP_PARAM_HOST_NAME_ADDRESS:
  		/* Tell the peer, we won't support this param.  */
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
2071
2072
2073
  		sctp_process_hn_param(asoc, param, chunk, err_chunk);
  		retval = SCTP_IERROR_ABORT;
  		break;
131a47e31   Vlad Yasevich   [SCTP]: Implement...
2074

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2075
  	case SCTP_PARAM_FWD_TSN_SUPPORT:
28aa4c26f   Xin Long   sctp: add SCTP_PR...
2076
  		if (ep->prsctp_enable)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2077
  			break;
48f9bcf91   Joe Perches   net: sctp: Rename...
2078
  		goto unhandled;
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
2079
2080
  
  	case SCTP_PARAM_RANDOM:
b14878ccb   Vlad Yasevich   net: sctp: cache ...
2081
  		if (!ep->auth_enable)
48f9bcf91   Joe Perches   net: sctp: Rename...
2082
  			goto unhandled;
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
2083
2084
2085
2086
2087
2088
  
  		/* 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'.
  		 */
8914f4bac   Marcelo Ricardo Leitner   sctp: add sctp_ma...
2089
2090
  		if (SCTP_AUTH_RANDOM_LENGTH != ntohs(param.p->length) -
  					       sizeof(struct sctp_paramhdr)) {
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
2091
  			sctp_process_inv_paramlength(asoc, param.p,
8914f4bac   Marcelo Ricardo Leitner   sctp: add sctp_ma...
2092
  						     chunk, err_chunk);
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
2093
2094
  			retval = SCTP_IERROR_ABORT;
  		}
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
2095
2096
2097
  		break;
  
  	case SCTP_PARAM_CHUNKS:
b14878ccb   Vlad Yasevich   net: sctp: cache ...
2098
  		if (!ep->auth_enable)
48f9bcf91   Joe Perches   net: sctp: Rename...
2099
  			goto unhandled;
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
2100
2101
2102
2103
2104
2105
  
  		/* 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...
2106
2107
2108
2109
2110
  		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...
2111
2112
2113
  		break;
  
  	case SCTP_PARAM_HMAC_ALGO:
b14878ccb   Vlad Yasevich   net: sctp: cache ...
2114
  		if (!ep->auth_enable)
48f9bcf91   Joe Perches   net: sctp: Rename...
2115
  			goto unhandled;
72da7b386   Wei Yongjun   [SCTP]: Add check...
2116
2117
  
  		hmacs = (struct sctp_hmac_algo_param *)param.p;
3c9187049   Xin Long   sctp: remove the ...
2118
2119
  		n_elt = (ntohs(param.p->length) -
  			 sizeof(struct sctp_paramhdr)) >> 1;
72da7b386   Wei Yongjun   [SCTP]: Add check...
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
  
  		/* 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;
48f9bcf91   Joe Perches   net: sctp: Rename...
2138
  unhandled:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2139
  	default:
bb33381d0   Daniel Borkmann   net: sctp: rework...
2140
2141
2142
  		pr_debug("%s: unrecognized param:%d for chunk:%d
  ",
  			 __func__, ntohs(param.p->type), cid);
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
2143
  		retval = sctp_process_unk_param(asoc, param, chunk, err_chunk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2144
2145
2146
2147
2148
2149
  		break;
  	}
  	return retval;
  }
  
  /* Verify the INIT packet before we process it.  */
b14878ccb   Vlad Yasevich   net: sctp: cache ...
2150
  int sctp_verify_init(struct net *net, const struct sctp_endpoint *ep,
6d85e68f4   Xin Long   sctp: remove the ...
2151
  		     const struct sctp_association *asoc, enum sctp_cid cid,
01a992bea   Xin Long   sctp: remove the ...
2152
2153
  		     struct sctp_init_chunk *peer_init,
  		     struct sctp_chunk *chunk, struct sctp_chunk **errp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2154
2155
  {
  	union sctp_params param;
7613f5fe1   Daniel Borkmann   net: sctp: sctp_v...
2156
  	bool has_cookie = false;
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
2157
  	int result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2158

7613f5fe1   Daniel Borkmann   net: sctp: sctp_v...
2159
2160
2161
2162
2163
2164
2165
2166
  	/* 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...
2167
  		return sctp_process_inv_mandatory(asoc, chunk, errp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2168

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2169
  	sctp_walk_params(param, peer_init, init_hdr.params) {
7613f5fe1   Daniel Borkmann   net: sctp: sctp_v...
2170
2171
2172
  		if (param.p->type == SCTP_PARAM_STATE_COOKIE)
  			has_cookie = true;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2173
2174
2175
2176
2177
2178
2179
2180
  
  	/* 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...
2181
  	if (param.v != (void *)chunk->chunk_end)
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
2182
  		return sctp_process_inv_paramlength(asoc, param.p, chunk, errp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2183
2184
2185
2186
  
  	/* The only missing mandatory param possible today is
  	 * the state cookie for an INIT-ACK chunk.
  	 */
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
2187
2188
2189
  	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
2190

7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
2191
  	/* Verify all the variable length parameters */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2192
  	sctp_walk_params(param, peer_init, init_hdr.params) {
b14878ccb   Vlad Yasevich   net: sctp: cache ...
2193
2194
  		result = sctp_verify_param(net, ep, asoc, param, cid,
  					   chunk, errp);
7ab908046   Vlad Yasevich   SCTP: Make sctp_v...
2195
  		switch (result) {
f7010e614   wangweidong   sctp: fix checkpa...
2196
2197
2198
2199
2200
2201
2202
2203
  		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
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
  		}
  
  	} /* 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...
2215
  int sctp_process_init(struct sctp_association *asoc, struct sctp_chunk *chunk,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2216
  		      const union sctp_addr *peer_addr,
01a992bea   Xin Long   sctp: remove the ...
2217
  		      struct sctp_init_chunk *peer_init, gfp_t gfp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2218
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2219
2220
  	struct sctp_transport *transport;
  	struct list_head *pos, *temp;
327c0dab8   Xin Long   sctp: fix some in...
2221
  	union sctp_params param;
de6becdc0   Wei Yongjun   sctp: fix to chec...
2222
  	union sctp_addr addr;
327c0dab8   Xin Long   sctp: fix some in...
2223
  	struct sctp_af *af;
de6becdc0   Wei Yongjun   sctp: fix to chec...
2224
  	int src_match = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2225
2226
2227
2228
2229
2230
2231
2232
2233
  
  	/* 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
14f45bb7b   Randy Dunlap   net: sctp: sm_mak...
2234
  	 * be a better choice than any of the embedded addresses.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2235
  	 */
cb3f837ba   wangweidong   sctp: fix checkpa...
2236
  	if (!sctp_assoc_add_peer(asoc, peer_addr, gfp, SCTP_ACTIVE))
de6becdc0   Wei Yongjun   sctp: fix to chec...
2237
2238
2239
2240
  		goto nomem;
  
  	if (sctp_cmp_addr_exact(sctp_source(chunk), peer_addr))
  		src_match = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2241
2242
  
  	/* Process the initialization parameters.  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2243
  	sctp_walk_params(param, peer_init, init_hdr.params) {
de6becdc0   Wei Yongjun   sctp: fix to chec...
2244
2245
2246
2247
2248
2249
2250
2251
  		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
2252
2253
  
  		if (!sctp_process_param(asoc, param, peer_addr, gfp))
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
2254
  			goto clean_up;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2255
  	}
de6becdc0   Wei Yongjun   sctp: fix to chec...
2256
2257
2258
  	/* source address of chunk may not match any valid address */
  	if (!src_match)
  		goto clean_up;
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
2259
2260
2261
2262
2263
2264
  	/* 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...
2265
2266
2267
2268
2269
  	/* 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...
2270
  	 */
4e7696d90   Xin Long   sctp: get netns f...
2271
2272
  	if (!asoc->base.net->sctp.addip_noauth &&
  	    (asoc->peer.asconf_capable && !asoc->peer.auth_capable)) {
6b2f9cb64   Vlad Yasevich   [SCTP]: Tie ADD-I...
2273
2274
2275
  		asoc->peer.addip_disabled_mask |= (SCTP_PARAM_ADD_IP |
  						  SCTP_PARAM_DEL_IP |
  						  SCTP_PARAM_SET_PRIMARY);
88799fe5e   Vlad Yasevich   SCTP: Correctly d...
2276
  		asoc->peer.asconf_capable = 0;
d67011913   Vlad Yasevich   [SCTP]: Follow Ad...
2277
  		goto clean_up;
6b2f9cb64   Vlad Yasevich   [SCTP]: Tie ADD-I...
2278
  	}
3f7a87d2f   Frank Filz   [SCTP] sctp_conne...
2279
2280
2281
2282
2283
2284
2285
  	/* 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
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
  	/* 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...
2299
  	asoc->strreset_inseq = asoc->peer.i.initial_tsn;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
  	/* 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;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2320
2321
2322
2323
  	/* 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...
2324
2325
  	list_for_each_entry(transport, &asoc->peer.transport_addr_list,
  			transports) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2326
2327
2328
2329
  		transport->ssthresh = asoc->peer.i.a_rwnd;
  	}
  
  	/* Set up the TSN tracking pieces.  */
8e1ee18c3   Vlad Yasevich   sctp: Rework the ...
2330
2331
2332
  	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
2333
2334
2335
2336
2337
2338
2339
2340
  
  	/* 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_...
2341
2342
  	if (sctp_stream_init(&asoc->stream, asoc->c.sinit_num_ostreams,
  			     asoc->c.sinit_max_instreams, gfp))
7e0629776   Xin Long   sctp: set new_aso...
2343
  		goto clean_up;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2344

4135cce7f   Xin Long   sctp: update frag...
2345
2346
  	/* Update frag_point when stream_interleave may get changed. */
  	sctp_assoc_update_frag_point(asoc);
7e0629776   Xin Long   sctp: set new_aso...
2347
2348
  	if (!asoc->temp && sctp_assoc_set_id(asoc, gfp))
  		goto clean_up;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
  
  	/* 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...
2367
2368
  		if (transport->state != SCTP_ACTIVE)
  			sctp_assoc_rm_peer(asoc, transport);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2369
  	}
3f7a87d2f   Frank Filz   [SCTP] sctp_conne...
2370

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
2389
  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...
2390
  			      gfp_t gfp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2391
  {
327c0dab8   Xin Long   sctp: fix some in...
2392
  	struct sctp_endpoint *ep = asoc->ep;
d6de30975   Vlad Yasevich   [SCTP]: Add the h...
2393
  	union sctp_addr_param *addr_param;
4e7696d90   Xin Long   sctp: get netns f...
2394
  	struct net *net = asoc->base.net;
d6de30975   Vlad Yasevich   [SCTP]: Add the h...
2395
  	struct sctp_transport *t;
327c0dab8   Xin Long   sctp: fix some in...
2396
2397
2398
2399
2400
2401
  	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
2402
2403
2404
2405
2406
2407
2408
2409
2410
  
  	/* 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...
2411
  		goto do_addr_param;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2412
  	case SCTP_PARAM_IPV4_ADDRESS:
7dab83de5   Vlad Yasevich   sctp: Support ipv...
2413
2414
2415
2416
  		/* 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
2417
  		af = sctp_get_af_specific(param_type2af(param.p->type));
dd86d136f   Al Viro   [SCTP]: Switch ->...
2418
  		af->from_addr_param(&addr, param.addr, htons(asoc->peer.port), 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2419
  		scope = sctp_scope(peer_addr);
e7ff4a703   Eric W. Biederman   sctp: Push struct...
2420
  		if (sctp_in_scope(net, &addr, scope))
dd86d136f   Al Viro   [SCTP]: Switch ->...
2421
  			if (!sctp_assoc_add_peer(asoc, &addr, gfp, SCTP_UNCONFIRMED))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2422
2423
2424
2425
  				return 0;
  		break;
  
  	case SCTP_PARAM_COOKIE_PRESERVATIVE:
e1fc3b14f   Eric W. Biederman   sctp: Make sysctl...
2426
  		if (!net->sctp.cookie_preserve_enable)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2427
2428
2429
2430
2431
2432
2433
  			break;
  
  		stale = ntohl(param.life->lifespan_increment);
  
  		/* Suggested Cookie Life span increment's unit is msec,
  		 * (1/1000sec).
  		 */
52db882f3   Daniel Borkmann   net: sctp: migrat...
2434
  		asoc->cookie_life = ktime_add_ms(asoc->cookie_life, stale);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2435
2436
2437
  		break;
  
  	case SCTP_PARAM_HOST_NAME_ADDRESS:
bb33381d0   Daniel Borkmann   net: sctp: rework...
2438
2439
  		pr_debug("%s: unimplemented SCTP_HOST_NAME_ADDRESS
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2440
2441
2442
2443
2444
2445
2446
2447
  		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...
2448
2449
2450
2451
2452
2453
2454
  		/* 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
2455
  		/* Cycle through address types; avoid divide by 0. */
3c9187049   Xin Long   sctp: remove the ...
2456
  		sat = ntohs(param.p->length) - sizeof(struct sctp_paramhdr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
  		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...
2467
2468
  				if (PF_INET6 == asoc->base.sk->sk_family)
  					asoc->peer.ipv6_address = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2469
2470
2471
2472
2473
2474
2475
2476
  				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...
2477
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2478
2479
2480
2481
2482
  		}
  		break;
  
  	case SCTP_PARAM_STATE_COOKIE:
  		asoc->peer.cookie_len =
3c9187049   Xin Long   sctp: remove the ...
2483
  			ntohs(param.p->length) - sizeof(struct sctp_paramhdr);
86fda90ab   Hariprasad Kelam   net: sctp: fix wa...
2484
  		kfree(asoc->peer.cookie);
0a8dd9f67   Neil Horman   Fix memory leak i...
2485
2486
2487
  		asoc->peer.cookie = kmemdup(param.cookie->body, asoc->peer.cookie_len, gfp);
  		if (!asoc->peer.cookie)
  			retval = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
  		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:
1b0b8114b   Xin Long   sctp: make ecn fl...
2499
2500
2501
2502
2503
2504
  		if (asoc->ep->ecn_enable) {
  			asoc->peer.ecn_capable = 1;
  			break;
  		}
  		/* Fall Through */
  		goto fall_through;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2505

0f3fffd8a   Ivan Skytte Jorgensen   [SCTP]: Fix typo ...
2506
  	case SCTP_PARAM_ADAPTATION_LAYER_IND:
e69c4e0f1   Vlad Yasevich   sctp: correctly s...
2507
  		asoc->peer.adaptation_ind = ntohl(param.aind->adaptation_ind);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2508
  		break;
d6de30975   Vlad Yasevich   [SCTP]: Add the h...
2509
  	case SCTP_PARAM_SET_PRIMARY:
4e27428fb   Xin Long   sctp: add asconf_...
2510
  		if (!ep->asconf_enable)
0ef46e285   Vlad Yasevich   sctp: do not enab...
2511
  			goto fall_through;
8b32f2348   Xin Long   sctp: remove the ...
2512
  		addr_param = param.v + sizeof(struct sctp_addip_param);
d6de30975   Vlad Yasevich   [SCTP]: Add the h...
2513

cfbf654ef   Saran Maruti Ramanara   net: sctp: fix pa...
2514
  		af = sctp_get_af_specific(param_type2af(addr_param->p.type));
e40607cbe   Daniel Borkmann   net: sctp: fix NU...
2515
2516
  		if (af == NULL)
  			break;
d6de30975   Vlad Yasevich   [SCTP]: Add the h...
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
  		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...
2532
2533
2534
  	case SCTP_PARAM_SUPPORTED_EXT:
  		sctp_process_ext_param(asoc, param);
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2535
  	case SCTP_PARAM_FWD_TSN_SUPPORT:
1c1347536   Xin Long   sctp: remove prsc...
2536
  		if (asoc->ep->prsctp_enable) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2537
2538
2539
  			asoc->peer.prsctp_capable = 1;
  			break;
  		}
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
2540
  		/* Fall Through */
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
2541
2542
2543
  		goto fall_through;
  
  	case SCTP_PARAM_RANDOM:
b14878ccb   Vlad Yasevich   net: sctp: cache ...
2544
  		if (!ep->auth_enable)
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
2545
2546
2547
  			goto fall_through;
  
  		/* Save peer's random parameter */
86fda90ab   Hariprasad Kelam   net: sctp: fix wa...
2548
  		kfree(asoc->peer.peer_random);
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
2549
2550
2551
2552
2553
2554
2555
2556
2557
  		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 ...
2558
  		if (!ep->auth_enable)
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
2559
2560
2561
  			goto fall_through;
  
  		/* Save peer's HMAC list */
86fda90ab   Hariprasad Kelam   net: sctp: fix wa...
2562
  		kfree(asoc->peer.peer_hmacs);
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
  		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 ...
2575
  		if (!ep->auth_enable)
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
2576
  			goto fall_through;
86fda90ab   Hariprasad Kelam   net: sctp: fix wa...
2577
  		kfree(asoc->peer.peer_chunks);
730fc3d05   Vlad Yasevich   [SCTP]: Implete S...
2578
2579
2580
2581
2582
2583
  		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
2584
2585
2586
2587
2588
2589
  	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...
2590
2591
2592
  		pr_debug("%s: ignoring param:%d for association:%p.
  ",
  			 __func__, ntohs(param.p->type), asoc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2593
  		break;
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
2594
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
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
  
  	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...
2643
   * Address Parameter and other parameter will not be wrapped in this function
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2644
2645
2646
2647
2648
   */
  static struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,
  					   union sctp_addr *addr,
  					   int vparam_len)
  {
65205cc46   Xin Long   sctp: remove the ...
2649
  	struct sctp_addiphdr asconf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
  	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_...
2662
2663
  	retval = sctp_make_control(asoc, SCTP_CID_ASCONF, 0, length,
  				   GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
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
  	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...
2702
2703
2704
  					      union sctp_addr *laddr,
  					      struct sockaddr *addrs,
  					      int addrcnt, __be16 flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2705
  {
327c0dab8   Xin Long   sctp: fix some in...
2706
  	union sctp_addr_param addr_param;
8b32f2348   Xin Long   sctp: remove the ...
2707
  	struct sctp_addip_param	param;
327c0dab8   Xin Long   sctp: fix some in...
2708
2709
2710
2711
2712
2713
2714
2715
  	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
2716
2717
2718
2719
  
  	/* Get total length of all the address parameters. */
  	addr_buf = addrs;
  	for (i = 0; i < addrcnt; i++) {
ea1107338   Joe Perches   net: Remove casts...
2720
  		addr = addr_buf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2721
2722
2723
2724
2725
2726
2727
  		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 ...
2728
2729
2730
2731
2732
  		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...
2733
2734
2735
2736
2737
  
  			pr_debug("%s: picked same-scope del_pending addr, "
  				 "totallen for all addresses is %d
  ",
  				 __func__, totallen);
8a07eb0a5   Michio Honda   sctp: Add ASCONF ...
2738
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
  	}
  
  	/* 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...
2749
  		addr = addr_buf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2750
2751
2752
2753
  		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...
2754
  		param.crr_id = htonl(i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2755
2756
2757
2758
2759
2760
  
  		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 ...
2761
2762
2763
2764
2765
2766
  	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...
2767
  		param.crr_id = htonl(i);
8a07eb0a5   Michio Honda   sctp: Add ASCONF ...
2768
2769
2770
2771
  
  		sctp_addto_chunk(retval, paramlen, &param);
  		sctp_addto_chunk(retval, addr_param_len, &addr_param);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
  	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...
2787
   * Create an ASCONF chunk with Set Primary IP address parameter.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2788
2789
2790
2791
   */
  struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc,
  					     union sctp_addr *addr)
  {
327c0dab8   Xin Long   sctp: fix some in...
2792
2793
  	struct sctp_af *af = sctp_get_af_specific(addr->v4.sin_family);
  	union sctp_addr_param addrparam;
8b32f2348   Xin Long   sctp: remove the ...
2794
  	struct sctp_addip_param	param;
327c0dab8   Xin Long   sctp: fix some in...
2795
2796
2797
  	struct sctp_chunk *retval;
  	int len = sizeof(param);
  	int addrlen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
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
  
  	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...
2836
   * Create an ASCONF_ACK chunk with enough space for the parameter responses.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2837
2838
2839
2840
   */
  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...
2841
2842
2843
  	struct sctp_addiphdr asconf;
  	struct sctp_chunk *retval;
  	int length = sizeof(asconf) + vparam_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2844
2845
  
  	/* Create the chunk.  */
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
2846
2847
  	retval = sctp_make_control(asoc, SCTP_CID_ASCONF_ACK, 0, length,
  				   GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
  	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...
2860
  static void sctp_add_asconf_response(struct sctp_chunk *chunk, __be32 crr_id,
8b32f2348   Xin Long   sctp: remove the ...
2861
2862
  				     __be16 err_code,
  				     struct sctp_addip_param *asconf_param)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2863
  {
8b32f2348   Xin Long   sctp: remove the ...
2864
  	struct sctp_addip_param ack_param;
327c0dab8   Xin Long   sctp: fix some in...
2865
2866
2867
2868
  	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
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
  
  	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...
2879
  	/* Add Success Indication or Error Cause Indication parameter. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
  	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...
2901
  static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
8b32f2348   Xin Long   sctp: remove the ...
2902
2903
  					struct sctp_chunk *asconf,
  					struct sctp_addip_param *asconf_param)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2904
  {
327c0dab8   Xin Long   sctp: fix some in...
2905
  	union sctp_addr_param *addr_param;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2906
  	struct sctp_transport *peer;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2907
  	union sctp_addr	addr;
327c0dab8   Xin Long   sctp: fix some in...
2908
  	struct sctp_af *af;
5f242a13e   Al Viro   [SCTP]: Switch ->...
2909

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

44e65c1ef   Wei Yongjun   sctp: check the u...
2912
2913
2914
2915
  	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 ...
2916
  	switch (addr_param->p.type) {
c4492586a   Wei Yongjun   sctp: Add address...
2917
2918
  	case SCTP_PARAM_IPV6_ADDRESS:
  		if (!asoc->peer.ipv6_address)
945e5abce   Wei Yongjun   sctp: fix the err...
2919
  			return SCTP_ERROR_DNS_FAILED;
c4492586a   Wei Yongjun   sctp: Add address...
2920
2921
2922
  		break;
  	case SCTP_PARAM_IPV4_ADDRESS:
  		if (!asoc->peer.ipv4_address)
945e5abce   Wei Yongjun   sctp: fix the err...
2923
  			return SCTP_ERROR_DNS_FAILED;
c4492586a   Wei Yongjun   sctp: Add address...
2924
2925
  		break;
  	default:
945e5abce   Wei Yongjun   sctp: fix the err...
2926
  		return SCTP_ERROR_DNS_FAILED;
c4492586a   Wei Yongjun   sctp: Add address...
2927
  	}
6a435732a   Shan Wei   sctp: use common ...
2928
  	af = sctp_get_af_specific(param_type2af(addr_param->p.type));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2929
  	if (unlikely(!af))
945e5abce   Wei Yongjun   sctp: fix the err...
2930
  		return SCTP_ERROR_DNS_FAILED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2931

dd86d136f   Al Viro   [SCTP]: Switch ->...
2932
  	af->from_addr_param(&addr, addr_param, htons(asoc->peer.port), 0);
42e30bf34   Vlad Yasevich   [SCTP]: Handle th...
2933
2934
2935
2936
2937
2938
2939
  
  	/* 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...
2940
  		return SCTP_ERROR_DNS_FAILED;
42e30bf34   Vlad Yasevich   [SCTP]: Handle th...
2941

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2942
2943
  	switch (asconf_param->param_hdr.type) {
  	case SCTP_PARAM_ADD_IP:
42e30bf34   Vlad Yasevich   [SCTP]: Handle th...
2944
2945
2946
2947
2948
2949
  		/* 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));
2277c7cd7   Richard Haines   sctp: Add LSM hooks
2950
2951
2952
2953
2954
  		if (security_sctp_bind_connect(asoc->ep->base.sk,
  					       SCTP_PARAM_ADD_IP,
  					       (struct sockaddr *)&addr,
  					       af->sockaddr_len))
  			return SCTP_ERROR_REQ_REFUSED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2955
  		/* ADDIP 4.3 D9) If an endpoint receives an ADD IP address
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
2956
2957
2958
2959
2960
  		 * 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
2961

dd86d136f   Al Viro   [SCTP]: Switch ->...
2962
  		peer = sctp_assoc_add_peer(asoc, &addr, GFP_ATOMIC, SCTP_UNCONFIRMED);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2963
2964
2965
2966
  		if (!peer)
  			return SCTP_ERROR_RSRC_LOW;
  
  		/* Start the heartbeat timer. */
ba6f5e33b   Marcelo Ricardo Leitner   sctp: avoid refre...
2967
  		sctp_transport_reset_hb_timer(peer);
6af29ccc2   Michio Honda   sctp: Bundle HEAE...
2968
  		asoc->new_transport = peer;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2969
2970
2971
  		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...
2972
2973
2974
2975
  		 * 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...
2976
  		if (asoc->peer.transport_count == 1)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2977
2978
2979
2980
2981
2982
2983
2984
2985
  			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...
2986
  		if (sctp_cmp_addr_exact(&asconf->source, &addr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2987
  			return SCTP_ERROR_DEL_SRC_IP;
42e30bf34   Vlad Yasevich   [SCTP]: Handle th...
2988
2989
2990
2991
2992
2993
2994
2995
2996
  		/* 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 ...
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
  			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
3010
3011
  		break;
  	case SCTP_PARAM_SET_PRIMARY:
42e30bf34   Vlad Yasevich   [SCTP]: Handle th...
3012
3013
3014
3015
3016
3017
3018
  		/* 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));
2277c7cd7   Richard Haines   sctp: Add LSM hooks
3019
3020
3021
3022
3023
  		if (security_sctp_bind_connect(asoc->ep->base.sk,
  					       SCTP_PARAM_SET_PRIMARY,
  					       (struct sockaddr *)&addr,
  					       af->sockaddr_len))
  			return SCTP_ERROR_REQ_REFUSED;
dd86d136f   Al Viro   [SCTP]: Switch ->...
3024
  		peer = sctp_assoc_lookup_paddr(asoc, &addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3025
  		if (!peer)
945e5abce   Wei Yongjun   sctp: fix the err...
3026
  			return SCTP_ERROR_DNS_FAILED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3027
3028
3029
  
  		sctp_assoc_set_primary(asoc, peer);
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3030
3031
3032
3033
  	}
  
  	return SCTP_ERROR_NO_ERROR;
  }
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3034
3035
3036
3037
3038
  /* 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 ...
3039
  	struct sctp_addip_chunk *addip;
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3040
  	bool addr_param_seen = false;
327c0dab8   Xin Long   sctp: fix some in...
3041
  	union sctp_params param;
6f4c618dd   Wei Yongjun   SCTP : Add paramt...
3042

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

9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3047
  		*errp = param.p;
6f4c618dd   Wei Yongjun   SCTP : Add paramt...
3048
  		switch (param.p->type) {
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3049
3050
3051
  		case SCTP_PARAM_ERR_CAUSE:
  			break;
  		case SCTP_PARAM_IPV4_ADDRESS:
a38905e6a   Xin Long   sctp: remove the ...
3052
  			if (length != sizeof(struct sctp_ipv4addr_param))
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3053
  				return false;
ce7b4ccc4   lucien   sctp: asconf's pr...
3054
3055
3056
3057
3058
  			/* 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...
3059
3060
3061
  			addr_param_seen = true;
  			break;
  		case SCTP_PARAM_IPV6_ADDRESS:
00987cc07   Xin Long   sctp: remove the ...
3062
  			if (length != sizeof(struct sctp_ipv6addr_param))
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3063
  				return false;
ce7b4ccc4   lucien   sctp: asconf's pr...
3064
3065
  			if (param.v != addip->addip_hdr.params)
  				return false;
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3066
3067
  			addr_param_seen = true;
  			break;
6f4c618dd   Wei Yongjun   SCTP : Add paramt...
3068
3069
3070
  		case SCTP_PARAM_ADD_IP:
  		case SCTP_PARAM_DEL_IP:
  		case SCTP_PARAM_SET_PRIMARY:
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3071
3072
3073
3074
  			/* 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 ...
3075
  			if (length < sizeof(struct sctp_addip_param) +
3c9187049   Xin Long   sctp: remove the ...
3076
  				     sizeof(**errp))
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3077
  				return false;
6f4c618dd   Wei Yongjun   SCTP : Add paramt...
3078
3079
3080
  			break;
  		case SCTP_PARAM_SUCCESS_REPORT:
  		case SCTP_PARAM_ADAPTATION_LAYER_IND:
8b32f2348   Xin Long   sctp: remove the ...
3081
  			if (length != sizeof(struct sctp_addip_param))
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3082
  				return false;
6f4c618dd   Wei Yongjun   SCTP : Add paramt...
3083
3084
  			break;
  		default:
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3085
3086
  			/* This is unkown to us, reject! */
  			return false;
6f4c618dd   Wei Yongjun   SCTP : Add paramt...
3087
  		}
6f4c618dd   Wei Yongjun   SCTP : Add paramt...
3088
  	}
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3089
3090
3091
3092
3093
3094
3095
  	/* 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...
3096

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

68d754694   Xin Long   sctp: remove the ...
3115
  	addip = (struct sctp_addip_chunk *)asconf->chunk_hdr;
922dbc5be   Xin Long   sctp: remove the ...
3116
3117
  	chunk_len = ntohs(asconf->chunk_hdr->length) -
  		    sizeof(struct sctp_chunkhdr);
65205cc46   Xin Long   sctp: remove the ...
3118
  	hdr = (struct sctp_addiphdr *)asconf->skb->data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3119
  	serial = ntohl(hdr->serial);
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
3120
  	/* Skip the addiphdr and store a pointer to address parameter.  */
65205cc46   Xin Long   sctp: remove the ...
3121
  	length = sizeof(*hdr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3122
3123
3124
3125
  	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 ...
3126
  	 * asconf parameter.
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
3127
  	 */
6a435732a   Shan Wei   sctp: use common ...
3128
  	length = ntohs(addr_param->p.length);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3129
  	chunk_len -= length;
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
3130
  	/* create an ASCONF_ACK chunk.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3131
  	 * Based on the definitions of parameters, we know that the size of
2cab86bee   Wei Yongjun   sctp: malloc enou...
3132
  	 * ASCONF_ACK parameters are less than or equal to the fourfold of ASCONF
7aa1b54b7   Joe Perches   [SCTP]: Spelling ...
3133
  	 * parameters.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3134
  	 */
2cab86bee   Wei Yongjun   sctp: malloc enou...
3135
  	asconf_ack = sctp_make_asconf_ack(asoc, serial, chunk_len * 4);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3136
3137
3138
3139
  	if (!asconf_ack)
  		goto done;
  
  	/* Process the TLVs contained within the ASCONF chunk. */
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3140
3141
3142
3143
3144
  	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
3145
  		err_code = sctp_process_asconf_param(asoc, asconf,
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3146
  						     param.addip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3147
3148
3149
3150
3151
3152
3153
  		/* 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...
3154
3155
  		if (err_code != SCTP_ERROR_NO_ERROR)
  			all_param_pass = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3156
  		if (!all_param_pass)
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3157
3158
  			sctp_add_asconf_response(asconf_ack, param.addip->crr_id,
  						 err_code, param.addip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3159
3160
3161
3162
  
  		/* 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...
3163
  		 * in the ASCONF.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3164
  		 */
9de7922bc   Daniel Borkmann   net: sctp: fix sk...
3165
  		if (err_code == SCTP_ERROR_RSRC_LOW)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3166
  			goto done;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3167
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3168
3169
3170
3171
  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...
3172
  	 * after freeing the reference to old asconf ack if any.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3173
3174
  	 */
  	if (asconf_ack) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3175
  		sctp_chunk_hold(asconf_ack);
a08de64d0   Vlad Yasevich   [SCTP]: Update AS...
3176
3177
  		list_add_tail(&asconf_ack->transmitted_list,
  			      &asoc->asconf_ack_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3178
3179
3180
3181
3182
3183
  	}
  
  	return asconf_ack;
  }
  
  /* Process a asconf parameter that is successfully acked. */
425e0f685   Wei Yongjun   sctp: avoid overw...
3184
  static void sctp_asconf_param_success(struct sctp_association *asoc,
8b32f2348   Xin Long   sctp: remove the ...
3185
  				      struct sctp_addip_param *asconf_param)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3186
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3187
3188
  	struct sctp_bind_addr *bp = &asoc->base.bind_addr;
  	union sctp_addr_param *addr_param;
dc022a987   Sridhar Samudrala   [SCTP]: ADDIP: Do...
3189
  	struct sctp_sockaddr_entry *saddr;
327c0dab8   Xin Long   sctp: fix some in...
3190
3191
3192
  	struct sctp_transport *transport;
  	union sctp_addr	addr;
  	struct sctp_af *af;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3193

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3261
3262
  	/* 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...
3263
  	 */
65205cc46   Xin Long   sctp: remove the ...
3264
  	length = sizeof(struct sctp_addiphdr);
8b32f2348   Xin Long   sctp: remove the ...
3265
3266
  	asconf_ack_param = (struct sctp_addip_param *)(asconf_ack->skb->data +
  						       length);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3267
3268
3269
3270
  	asconf_ack_len -= length;
  
  	while (asconf_ack_len > 0) {
  		if (asconf_ack_param->crr_id == asconf_param->crr_id) {
cb3f837ba   wangweidong   sctp: fix checkpa...
3271
  			switch (asconf_ack_param->param_hdr.type) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3272
3273
3274
  			case SCTP_PARAM_SUCCESS_REPORT:
  				return SCTP_ERROR_NO_ERROR;
  			case SCTP_PARAM_ERR_CAUSE:
8b32f2348   Xin Long   sctp: remove the ...
3275
  				length = sizeof(*asconf_ack_param);
ea1107338   Joe Perches   net: Remove casts...
3276
  				err_param = (void *)asconf_ack_param + length;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
  				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...
3289
  		asconf_ack_param = (void *)asconf_ack_param + length;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
  		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...
3300
3301
3302
3303
3304
3305
3306
3307
3308
  	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
3309
3310
3311
  
  	/* Skip the chunkhdr and addiphdr from the last asconf sent and store
  	 * a pointer to address parameter.
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
3312
  	 */
68d754694   Xin Long   sctp: remove the ...
3313
  	length = sizeof(struct sctp_addip_chunk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3314
3315
3316
3317
  	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 ...
3318
  	 * pointer to the first asconf parameter.
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
3319
  	 */
6a435732a   Shan Wei   sctp: use common ...
3320
  	length = ntohs(addr_param->p.length);
ea1107338   Joe Perches   net: Remove casts...
3321
  	asconf_param = (void *)addr_param + length;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3322
3323
3324
3325
3326
3327
3328
  	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 ...
3329
  	if (asconf_ack->skb->len == sizeof(struct sctp_addiphdr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
  		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...
3346
  			sctp_asconf_param_success(asoc, asconf_param);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3347
3348
3349
3350
3351
  			break;
  
  		case SCTP_ERROR_RSRC_LOW:
  			retval = 1;
  			break;
a987f762c   Wei Yongjun   sctp: fix report ...
3352
  		case SCTP_ERROR_UNKNOWN_PARAM:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3353
3354
  			/* Disable sending this type of asconf parameter in
  			 * future.
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
3355
  			 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
  			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...
3369
  		 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3370
  		length = ntohs(asconf_param->param_hdr.length);
ea1107338   Joe Perches   net: Remove casts...
3371
  		asconf_param = (void *)asconf_param + length;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3372
3373
  		asconf_len -= length;
  	}
ddc4bbee6   Michio Honda   sctp: fasthandoff...
3374
  	if (no_err && asoc->src_out_of_asoc_ok) {
8a07eb0a5   Michio Honda   sctp: Add ASCONF ...
3375
  		asoc->src_out_of_asoc_ok = 0;
ddc4bbee6   Michio Honda   sctp: fasthandoff...
3376
3377
  		sctp_transport_immediate_rtx(asoc->peer.primary_path);
  	}
8a07eb0a5   Michio Honda   sctp: Add ASCONF ...
3378

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3379
  	/* Free the cached last sent asconf chunk. */
5f9646c3d   Vlad Yasevich   [SCTP]: Make sure...
3380
  	list_del_init(&asconf->transmitted_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3381
3382
  	sctp_chunk_free(asconf);
  	asoc->addip_last_asconf = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3383
3384
  	return retval;
  }
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
3385
  /* Make a FWD TSN chunk. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3386
3387
3388
3389
3390
  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...
3391
  	struct sctp_fwdtsn_hdr ftsn_hdr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3392
3393
3394
3395
3396
  	struct sctp_fwdtsn_skip skip;
  	size_t hint;
  	int i;
  
  	hint = (nstreams + 1) * sizeof(__u32);
cea8768f3   Marcelo Ricardo Leitner   sctp: allow sctp_...
3397
  	retval = sctp_make_control(asoc, SCTP_CID_FWD_TSN, 0, hint, GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3398
3399
3400
  
  	if (!retval)
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
  	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...
3413

2d07a49ad   Xin Long   sctp: add basic s...
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
  struct sctp_chunk *sctp_make_ifwdtsn(const struct sctp_association *asoc,
  				     __u32 new_cum_tsn, size_t nstreams,
  				     struct sctp_ifwdtsn_skip *skiplist)
  {
  	struct sctp_chunk *retval = NULL;
  	struct sctp_ifwdtsn_hdr ftsn_hdr;
  	size_t hint;
  
  	hint = (nstreams + 1) * sizeof(__u32);
  
  	retval = sctp_make_control(asoc, SCTP_CID_I_FWD_TSN, 0, hint,
  				   GFP_ATOMIC);
  	if (!retval)
  		return NULL;
  
  	ftsn_hdr.new_cum_tsn = htonl(new_cum_tsn);
  	retval->subh.ifwdtsn_hdr =
  		sctp_addto_chunk(retval, sizeof(ftsn_hdr), &ftsn_hdr);
  
  	sctp_addto_chunk(retval, nstreams * sizeof(skiplist[0]), skiplist);
  
  	return retval;
  }
cc16f00f6   Xin Long   sctp: add support...
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
  /* 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...
3452
3453
  static struct sctp_chunk *sctp_make_reconf(const struct sctp_association *asoc,
  					   int length)
cc16f00f6   Xin Long   sctp: add support...
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
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
  {
  	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...
3504
  					const struct sctp_association *asoc,
1da4fc97c   Xin Long   sctp: fix some ty...
3505
  					__u16 stream_num, __be16 *stream_list,
327c0dab8   Xin Long   sctp: fix some in...
3506
  					bool out, bool in)
cc16f00f6   Xin Long   sctp: add support...
3507
  {
423852f89   Xin Long   sctp: check strea...
3508
  	__u16 stream_len = stream_num * sizeof(__u16);
cc16f00f6   Xin Long   sctp: add support...
3509
  	struct sctp_strreset_outreq outreq;
cc16f00f6   Xin Long   sctp: add support...
3510
3511
  	struct sctp_strreset_inreq inreq;
  	struct sctp_chunk *retval;
16e1a9196   Xin Long   sctp: implement r...
3512
  	__u16 outlen, inlen;
cc16f00f6   Xin Long   sctp: add support...
3513
3514
3515
3516
3517
3518
3519
  
  	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...
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
  	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...
3543
3544
  	return retval;
  }
c56480a1e   Xin Long   sctp: add support...
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
  
  /* 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...
3556
  					const struct sctp_association *asoc)
c56480a1e   Xin Long   sctp: add support...
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
  {
  	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...
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
  
  /* 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...
3587
3588
  					const struct sctp_association *asoc,
  					__u16 out, __u16 in)
78098117f   Xin Long   sctp: add support...
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
  {
  	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...
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
  
  /* 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...
3632
3633
  struct sctp_chunk *sctp_make_strreset_resp(const struct sctp_association *asoc,
  					   __u32 result, __u32 sn)
bd4b9f8b4   Xin Long   sctp: add support...
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
  {
  	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...
3668
3669
3670
3671
  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...
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
  {
  	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...
3693
3694
3695
3696
3697
3698
3699
  
  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...
3700
3701
  	__be16 last = 0;
  	__u16 cnt = 0;
ea6250437   Xin Long   sctp: add a funct...
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
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
  
  	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;
  }