Blame view

net/sctp/ulpevent.c 32.5 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
8
9
10
11
   * (C) Copyright IBM Corp. 2001, 2004
   * Copyright (c) 1999-2000 Cisco, Inc.
   * Copyright (c) 1999-2001 Motorola, Inc.
   * Copyright (c) 2001 Intel Corp.
   * Copyright (c) 2001 Nokia, Inc.
   * Copyright (c) 2001 La Monte H.P. Yarroll
   *
   * These functions manipulate an sctp event.   The struct ulpevent is used
   * to carry notifications and data to the ULP (sockets).
60c778b25   Vlad Yasevich   [SCTP]: Stop clai...
12
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
14
   * Please send any bug reports or fixes you make to the
   * email address(es):
91705c61b   Daniel Borkmann   net: sctp: trivia...
15
   *    lksctp developers <linux-sctp@vger.kernel.org>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
19
20
21
   * Written or modified by:
   *    Jon Grimm             <jgrimm@us.ibm.com>
   *    La Monte H.P. Yarroll <piggy@acm.org>
   *    Ardelle Fan	    <ardelle.fan@intel.com>
   *    Sridhar Samudrala     <sri@us.ibm.com>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
   */
5a0e3ad6a   Tejun Heo   include cleanup: ...
23
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
27
28
29
30
31
32
  #include <linux/types.h>
  #include <linux/skbuff.h>
  #include <net/sctp/structs.h>
  #include <net/sctp/sctp.h>
  #include <net/sctp/sm.h>
  
  static void sctp_ulpevent_receive_data(struct sctp_ulpevent *event,
  				       struct sctp_association *asoc);
  static void sctp_ulpevent_release_data(struct sctp_ulpevent *event);
d7c2c9e39   Tsutomu Fujii   [SCTP]: Send only...
33
  static void sctp_ulpevent_release_frag_data(struct sctp_ulpevent *event);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
  /* Initialize an ULP event from an given skb.  */
dda919285   Daniel Borkmann   net: sctp: remove...
36
  static void sctp_ulpevent_init(struct sctp_ulpevent *event,
f5d258e60   Marcelo Ricardo Leitner   sctp: reorder sct...
37
  			       __u16 msg_flags,
dda919285   Daniel Borkmann   net: sctp: remove...
38
  			       unsigned int len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
41
  {
  	memset(event, 0, sizeof(struct sctp_ulpevent));
  	event->msg_flags = msg_flags;
331c4ee7f   Vlad Yasevich   [SCTP]: Fix recei...
42
  	event->rmem_len = len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
45
  }
  
  /* Create a new sctp_ulpevent.  */
f5d258e60   Marcelo Ricardo Leitner   sctp: reorder sct...
46
  static struct sctp_ulpevent *sctp_ulpevent_new(int size, __u16 msg_flags,
dda919285   Daniel Borkmann   net: sctp: remove...
47
  					       gfp_t gfp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
49
50
51
52
53
54
55
56
  {
  	struct sctp_ulpevent *event;
  	struct sk_buff *skb;
  
  	skb = alloc_skb(size, gfp);
  	if (!skb)
  		goto fail;
  
  	event = sctp_skb2event(skb);
331c4ee7f   Vlad Yasevich   [SCTP]: Fix recei...
57
  	sctp_ulpevent_init(event, msg_flags, skb->truesize);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
  
  	return event;
  
  fail:
  	return NULL;
  }
  
  /* Is this a MSG_NOTIFICATION?  */
  int sctp_ulpevent_is_notification(const struct sctp_ulpevent *event)
  {
  	return MSG_NOTIFICATION == (event->msg_flags & MSG_NOTIFICATION);
  }
  
  /* Hold the association in case the msg_name needs read out of
   * the association.
   */
  static inline void sctp_ulpevent_set_owner(struct sctp_ulpevent *event,
  					   const struct sctp_association *asoc)
  {
52253db92   Marcelo Ricardo Leitner   sctp: also point ...
77
  	struct sctp_chunk *chunk = event->chunk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78
79
80
81
82
83
84
  	struct sk_buff *skb;
  
  	/* Cast away the const, as we are just wanting to
  	 * bump the reference count.
  	 */
  	sctp_association_hold((struct sctp_association *)asoc);
  	skb = sctp_event2skb(event);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
  	event->asoc = (struct sctp_association *)asoc;
331c4ee7f   Vlad Yasevich   [SCTP]: Fix recei...
86
87
  	atomic_add(event->rmem_len, &event->asoc->rmem_alloc);
  	sctp_skb_set_owner_r(skb, asoc->base.sk);
52253db92   Marcelo Ricardo Leitner   sctp: also point ...
88
89
  	if (chunk && chunk->head_skb && !chunk->head_skb->sk)
  		chunk->head_skb->sk = asoc->base.sk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
91
92
93
94
  }
  
  /* A simple destructor to give up the reference to the association. */
  static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event)
  {
049b3ff5a   Neil Horman   [SCTP]: Include u...
95
  	struct sctp_association *asoc = event->asoc;
049b3ff5a   Neil Horman   [SCTP]: Include u...
96

331c4ee7f   Vlad Yasevich   [SCTP]: Fix recei...
97
  	atomic_sub(event->rmem_len, &asoc->rmem_alloc);
049b3ff5a   Neil Horman   [SCTP]: Include u...
98
  	sctp_association_put(asoc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
  }
  
  /* Create and initialize an SCTP_ASSOC_CHANGE event.
   *
   * 5.3.1.1 SCTP_ASSOC_CHANGE
   *
   * Communication notifications inform the ULP that an SCTP association
   * has either begun or ended. The identifier for a new association is
   * provided by this notification.
   *
   * Note: There is no field checking here.  If a field is unused it will be
   * zero'd out.
   */
  struct sctp_ulpevent  *sctp_ulpevent_make_assoc_change(
  	const struct sctp_association *asoc,
  	__u16 flags, __u16 state, __u16 error, __u16 outbound,
a5a35e767   Vlad Yasevich   [SCTP]: Implement...
115
  	__u16 inbound, struct sctp_chunk *chunk, gfp_t gfp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
117
118
119
  {
  	struct sctp_ulpevent *event;
  	struct sctp_assoc_change *sac;
  	struct sk_buff *skb;
a5a35e767   Vlad Yasevich   [SCTP]: Implement...
120
121
122
123
  	/* If the lower layer passed in the chunk, it will be
  	 * an ABORT, so we need to include it in the sac_info.
  	 */
  	if (chunk) {
a5a35e767   Vlad Yasevich   [SCTP]: Implement...
124
125
126
127
128
129
130
131
  		/* Copy the chunk data to a new skb and reserve enough
  		 * head room to use as notification.
  		 */
  		skb = skb_copy_expand(chunk->skb,
  				      sizeof(struct sctp_assoc_change), 0, gfp);
  
  		if (!skb)
  			goto fail;
a5a35e767   Vlad Yasevich   [SCTP]: Implement...
132
133
134
135
136
  		/* Embed the event fields inside the cloned skb.  */
  		event = sctp_skb2event(skb);
  		sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize);
  
  		/* Include the notification structure */
d58ff3512   Johannes Berg   networking: make ...
137
  		sac = skb_push(skb, sizeof(struct sctp_assoc_change));
a5a35e767   Vlad Yasevich   [SCTP]: Implement...
138
139
140
  
  		/* Trim the buffer to the right length.  */
  		skb_trim(skb, sizeof(struct sctp_assoc_change) +
ac40e41f4   Vlad Yasevich   [SCTP]: Do not in...
141
  			 ntohs(chunk->chunk_hdr->length) -
922dbc5be   Xin Long   sctp: remove the ...
142
  			 sizeof(struct sctp_chunkhdr));
a5a35e767   Vlad Yasevich   [SCTP]: Implement...
143
144
  	} else {
  		event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
  				  MSG_NOTIFICATION, gfp);
a5a35e767   Vlad Yasevich   [SCTP]: Implement...
146
147
148
149
  		if (!event)
  			goto fail;
  
  		skb = sctp_event2skb(event);
4df864c1d   Johannes Berg   networking: make ...
150
  		sac = skb_put(skb, sizeof(struct sctp_assoc_change));
a5a35e767   Vlad Yasevich   [SCTP]: Implement...
151
  	}
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
  
  	/* Socket Extensions for SCTP
  	 * 5.3.1.1 SCTP_ASSOC_CHANGE
  	 *
  	 * sac_type:
  	 * It should be SCTP_ASSOC_CHANGE.
  	 */
  	sac->sac_type = SCTP_ASSOC_CHANGE;
  
  	/* Socket Extensions for SCTP
  	 * 5.3.1.1 SCTP_ASSOC_CHANGE
  	 *
  	 * sac_state: 32 bits (signed integer)
  	 * This field holds one of a number of values that communicate the
  	 * event that happened to the association.
  	 */
  	sac->sac_state = state;
  
  	/* Socket Extensions for SCTP
  	 * 5.3.1.1 SCTP_ASSOC_CHANGE
  	 *
  	 * sac_flags: 16 bits (unsigned integer)
  	 * Currently unused.
  	 */
  	sac->sac_flags = 0;
  
  	/* Socket Extensions for SCTP
  	 * 5.3.1.1 SCTP_ASSOC_CHANGE
  	 *
  	 * sac_length: sizeof (__u32)
  	 * This field is the total length of the notification data, including
  	 * the notification header.
  	 */
b90a137d3   Vlad Yasevich   [SCTP]: Correctly...
185
  	sac->sac_length = skb->len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
  
  	/* Socket Extensions for SCTP
  	 * 5.3.1.1 SCTP_ASSOC_CHANGE
  	 *
  	 * sac_error:  32 bits (signed integer)
  	 *
  	 * If the state was reached due to a error condition (e.g.
  	 * COMMUNICATION_LOST) any relevant error information is available in
  	 * this field. This corresponds to the protocol error codes defined in
  	 * [SCTP].
  	 */
  	sac->sac_error = error;
  
  	/* Socket Extensions for SCTP
  	 * 5.3.1.1 SCTP_ASSOC_CHANGE
  	 *
  	 * sac_outbound_streams:  16 bits (unsigned integer)
  	 * sac_inbound_streams:  16 bits (unsigned integer)
  	 *
  	 * The maximum number of streams allowed in each direction are
  	 * available in sac_outbound_streams and sac_inbound streams.
  	 */
  	sac->sac_outbound_streams = outbound;
  	sac->sac_inbound_streams = inbound;
  
  	/* Socket Extensions for SCTP
  	 * 5.3.1.1 SCTP_ASSOC_CHANGE
  	 *
  	 * sac_assoc_id: sizeof (sctp_assoc_t)
  	 *
  	 * The association id field, holds the identifier for the association.
  	 * All notifications for a given association have the same association
  	 * identifier.  For TCP style socket, this field is ignored.
  	 */
  	sctp_ulpevent_set_owner(event, asoc);
  	sac->sac_assoc_id = sctp_assoc2id(asoc);
  
  	return event;
  
  fail:
  	return NULL;
  }
  
  /* Create and initialize an SCTP_PEER_ADDR_CHANGE event.
   *
   * Socket Extensions for SCTP - draft-01
   * 5.3.1.2 SCTP_PEER_ADDR_CHANGE
   *
   * When a destination address on a multi-homed peer encounters a change
   * an interface details event is sent.
   */
4b7740324   Xin Long   sctp: add SCTP_AD...
237
  static struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change(
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
239
  	const struct sctp_association *asoc,
  	const struct sockaddr_storage *aaddr,
dd0fc66fb   Al Viro   [PATCH] gfp flags...
240
  	int flags, int state, int error, gfp_t gfp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241
242
243
244
245
246
247
248
249
250
251
  {
  	struct sctp_ulpevent *event;
  	struct sctp_paddr_change  *spc;
  	struct sk_buff *skb;
  
  	event = sctp_ulpevent_new(sizeof(struct sctp_paddr_change),
  				  MSG_NOTIFICATION, gfp);
  	if (!event)
  		goto fail;
  
  	skb = sctp_event2skb(event);
4df864c1d   Johannes Berg   networking: make ...
252
  	spc = skb_put(skb, sizeof(struct sctp_paddr_change));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
  
  	/* Sockets API Extensions for SCTP
  	 * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE
  	 *
  	 * spc_type:
  	 *
  	 *    It should be SCTP_PEER_ADDR_CHANGE.
  	 */
  	spc->spc_type = SCTP_PEER_ADDR_CHANGE;
  
  	/* Sockets API Extensions for SCTP
  	 * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE
  	 *
  	 * spc_length: sizeof (__u32)
  	 *
  	 * This field is the total length of the notification data, including
  	 * the notification header.
  	 */
  	spc->spc_length = sizeof(struct sctp_paddr_change);
  
  	/* Sockets API Extensions for SCTP
  	 * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE
  	 *
  	 * spc_flags: 16 bits (unsigned integer)
  	 * Currently unused.
  	 */
  	spc->spc_flags = 0;
  
  	/* Sockets API Extensions for SCTP
  	 * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE
  	 *
  	 * spc_state:  32 bits (signed integer)
  	 *
  	 * This field holds one of a number of values that communicate the
  	 * event that happened to the address.
  	 */
  	spc->spc_state = state;
  
  	/* Sockets API Extensions for SCTP
  	 * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE
  	 *
  	 * spc_error:  32 bits (signed integer)
  	 *
  	 * If the state was reached due to any error condition (e.g.
  	 * ADDRESS_UNREACHABLE) any relevant error information is available in
  	 * this field.
  	 */
  	spc->spc_error = error;
  
  	/* Socket Extensions for SCTP
  	 * 5.3.1.1 SCTP_ASSOC_CHANGE
  	 *
  	 * spc_assoc_id: sizeof (sctp_assoc_t)
  	 *
  	 * The association id field, holds the identifier for the association.
  	 * All notifications for a given association have the same association
  	 * identifier.  For TCP style socket, this field is ignored.
  	 */
  	sctp_ulpevent_set_owner(event, asoc);
  	spc->spc_assoc_id = sctp_assoc2id(asoc);
  
  	/* Sockets API Extensions for SCTP
  	 * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE
  	 *
  	 * spc_aaddr: sizeof (struct sockaddr_storage)
  	 *
  	 * The affected address field, holds the remote peer's address that is
  	 * encountering the change of state.
  	 */
  	memcpy(&spc->spc_aaddr, aaddr, sizeof(struct sockaddr_storage));
  
  	/* Map ipv4 address into v4-mapped-on-v6 address.  */
299ee123e   Jason Gunthorpe   sctp: Fixup v4map...
325
  	sctp_get_pf_specific(asoc->base.sk->sk_family)->addr_to_user(
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326
327
328
329
330
331
332
333
  					sctp_sk(asoc->base.sk),
  					(union sctp_addr *)&spc->spc_aaddr);
  
  	return event;
  
  fail:
  	return NULL;
  }
4b7740324   Xin Long   sctp: add SCTP_AD...
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
  void sctp_ulpevent_nofity_peer_addr_change(struct sctp_transport *transport,
  					   int state, int error)
  {
  	struct sctp_association *asoc = transport->asoc;
  	struct sockaddr_storage addr;
  	struct sctp_ulpevent *event;
  
  	memset(&addr, 0, sizeof(struct sockaddr_storage));
  	memcpy(&addr, &transport->ipaddr, transport->af_specific->sockaddr_len);
  
  	event = sctp_ulpevent_make_peer_addr_change(asoc, &addr, 0, state,
  						    error, GFP_ATOMIC);
  	if (event)
  		asoc->stream.si->enqueue_event(&asoc->ulpq, event);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
  /* Create and initialize an SCTP_REMOTE_ERROR notification.
   *
   * Note: This assumes that the chunk->skb->data already points to the
   * operation error payload.
   *
   * Socket Extensions for SCTP - draft-01
   * 5.3.1.3 SCTP_REMOTE_ERROR
   *
   * A remote peer may send an Operational Error message to its peer.
   * This message indicates a variety of error conditions on an
   * association. The entire error TLV as it appears on the wire is
   * included in a SCTP_REMOTE_ERROR event.  Please refer to the SCTP
   * specification [SCTP] and any extensions for a list of possible
   * error formats.
   */
8f2e5ae40   Daniel Borkmann   net: sctp: fix in...
364
365
366
367
  struct sctp_ulpevent *
  sctp_ulpevent_make_remote_error(const struct sctp_association *asoc,
  				struct sctp_chunk *chunk, __u16 flags,
  				gfp_t gfp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
  	struct sctp_remote_error *sre;
d8238d9da   Xin Long   sctp: remove the ...
370
371
  	struct sctp_ulpevent *event;
  	struct sctp_errhdr *ch;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372
  	struct sk_buff *skb;
9f81bcd94   Al Viro   [SCTP]: More triv...
373
  	__be16 cause;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
  	int elen;
d8238d9da   Xin Long   sctp: remove the ...
375
  	ch = (struct sctp_errhdr *)(chunk->skb->data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
  	cause = ch->cause;
d8238d9da   Xin Long   sctp: remove the ...
377
  	elen = SCTP_PAD4(ntohs(ch->length)) - sizeof(*ch);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378
379
  
  	/* Pull off the ERROR header.  */
d8238d9da   Xin Long   sctp: remove the ...
380
  	skb_pull(chunk->skb, sizeof(*ch));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381
382
383
384
  
  	/* Copy the skb to a new skb with room for us to prepend
  	 * notification with.
  	 */
8f2e5ae40   Daniel Borkmann   net: sctp: fix in...
385
  	skb = skb_copy_expand(chunk->skb, sizeof(*sre), 0, gfp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386
387
388
389
390
391
392
393
  
  	/* Pull off the rest of the cause TLV from the chunk.  */
  	skb_pull(chunk->skb, elen);
  	if (!skb)
  		goto fail;
  
  	/* Embed the event fields inside the cloned skb.  */
  	event = sctp_skb2event(skb);
331c4ee7f   Vlad Yasevich   [SCTP]: Fix recei...
394
  	sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395

d58ff3512   Johannes Berg   networking: make ...
396
  	sre = skb_push(skb, sizeof(*sre));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397
398
  
  	/* Trim the buffer to the right length.  */
8f2e5ae40   Daniel Borkmann   net: sctp: fix in...
399
  	skb_trim(skb, sizeof(*sre) + elen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400

8f2e5ae40   Daniel Borkmann   net: sctp: fix in...
401
402
  	/* RFC6458, Section 6.1.3. SCTP_REMOTE_ERROR */
  	memset(sre, 0, sizeof(*sre));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
  	sre->sre_type = SCTP_REMOTE_ERROR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
  	sre->sre_flags = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
  	sre->sre_length = skb->len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
406
  	sre->sre_error = cause;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
408
409
410
  	sctp_ulpevent_set_owner(event, asoc);
  	sre->sre_assoc_id = sctp_assoc2id(asoc);
  
  	return event;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
412
413
414
415
416
417
418
419
420
421
  fail:
  	return NULL;
  }
  
  /* Create and initialize a SCTP_SEND_FAILED notification.
   *
   * Socket Extensions for SCTP - draft-01
   * 5.3.1.4 SCTP_SEND_FAILED
   */
  struct sctp_ulpevent *sctp_ulpevent_make_send_failed(
  	const struct sctp_association *asoc, struct sctp_chunk *chunk,
dd0fc66fb   Al Viro   [PATCH] gfp flags...
422
  	__u16 flags, __u32 error, gfp_t gfp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
  {
  	struct sctp_ulpevent *event;
  	struct sctp_send_failed *ssf;
  	struct sk_buff *skb;
  
  	/* Pull off any padding. */
  	int len = ntohs(chunk->chunk_hdr->length);
  
  	/* Make skb with more room so we can prepend notification.  */
  	skb = skb_copy_expand(chunk->skb,
  			      sizeof(struct sctp_send_failed), /* headroom */
  			      0,                               /* tailroom */
  			      gfp);
  	if (!skb)
  		goto fail;
  
  	/* Pull off the common chunk header and DATA header.  */
668c9beb9   Xin Long   sctp: implement a...
440
441
  	skb_pull(skb, sctp_datachk_len(&asoc->stream));
  	len -= sctp_datachk_len(&asoc->stream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
443
444
  
  	/* Embed the event fields inside the cloned skb.  */
  	event = sctp_skb2event(skb);
331c4ee7f   Vlad Yasevich   [SCTP]: Fix recei...
445
  	sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446

d58ff3512   Johannes Berg   networking: make ...
447
  	ssf = skb_push(skb, sizeof(struct sctp_send_failed));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
  
  	/* Socket Extensions for SCTP
  	 * 5.3.1.4 SCTP_SEND_FAILED
  	 *
  	 * ssf_type:
  	 * It should be SCTP_SEND_FAILED.
  	 */
  	ssf->ssf_type = SCTP_SEND_FAILED;
  
  	/* Socket Extensions for SCTP
  	 * 5.3.1.4 SCTP_SEND_FAILED
  	 *
  	 * ssf_flags: 16 bits (unsigned integer)
  	 * The flag value will take one of the following values
  	 *
  	 * SCTP_DATA_UNSENT - Indicates that the data was never put on
  	 *                    the wire.
  	 *
  	 * SCTP_DATA_SENT   - Indicates that the data was put on the wire.
  	 *                    Note that this does not necessarily mean that the
  	 *                    data was (or was not) successfully delivered.
  	 */
  	ssf->ssf_flags = flags;
  
  	/* Socket Extensions for SCTP
  	 * 5.3.1.4 SCTP_SEND_FAILED
  	 *
  	 * ssf_length: sizeof (__u32)
  	 * This field is the total length of the notification data, including
  	 * the notification header.
  	 */
  	ssf->ssf_length = sizeof(struct sctp_send_failed) + len;
  	skb_trim(skb, ssf->ssf_length);
  
  	/* Socket Extensions for SCTP
  	 * 5.3.1.4 SCTP_SEND_FAILED
  	 *
  	 * ssf_error: 16 bits (unsigned integer)
  	 * This value represents the reason why the send failed, and if set,
  	 * will be a SCTP protocol error code as defined in [SCTP] section
  	 * 3.3.10.
  	 */
  	ssf->ssf_error = error;
  
  	/* Socket Extensions for SCTP
  	 * 5.3.1.4 SCTP_SEND_FAILED
  	 *
  	 * ssf_info: sizeof (struct sctp_sndrcvinfo)
  	 * The original send information associated with the undelivered
  	 * message.
  	 */
  	memcpy(&ssf->ssf_info, &chunk->sinfo, sizeof(struct sctp_sndrcvinfo));
  
  	/* Per TSVWG discussion with Randy. Allow the application to
e9c549998   Lucas De Marchi   Revert wrong fixe...
502
  	 * reassemble a fragmented message.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
  	 */
  	ssf->ssf_info.sinfo_flags = chunk->chunk_hdr->flags;
  
  	/* Socket Extensions for SCTP
  	 * 5.3.1.4 SCTP_SEND_FAILED
  	 *
  	 * ssf_assoc_id: sizeof (sctp_assoc_t)
  	 * The association id field, sf_assoc_id, holds the identifier for the
  	 * association.  All notifications for a given association have the
  	 * same association identifier.  For TCP style socket, this field is
  	 * ignored.
  	 */
  	sctp_ulpevent_set_owner(event, asoc);
  	ssf->ssf_assoc_id = sctp_assoc2id(asoc);
  	return event;
  
  fail:
  	return NULL;
  }
b6e6b5f1d   Xin Long   sctp: add SCTP_SE...
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
  struct sctp_ulpevent *sctp_ulpevent_make_send_failed_event(
  	const struct sctp_association *asoc, struct sctp_chunk *chunk,
  	__u16 flags, __u32 error, gfp_t gfp)
  {
  	struct sctp_send_failed_event *ssf;
  	struct sctp_ulpevent *event;
  	struct sk_buff *skb;
  	int len;
  
  	skb = skb_copy_expand(chunk->skb, sizeof(*ssf), 0, gfp);
  	if (!skb)
  		return NULL;
  
  	len = ntohs(chunk->chunk_hdr->length);
  	len -= sctp_datachk_len(&asoc->stream);
  
  	skb_pull(skb, sctp_datachk_len(&asoc->stream));
  	event = sctp_skb2event(skb);
  	sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize);
  
  	ssf = skb_push(skb, sizeof(*ssf));
  	ssf->ssf_type = SCTP_SEND_FAILED_EVENT;
  	ssf->ssf_flags = flags;
  	ssf->ssf_length = sizeof(*ssf) + len;
  	skb_trim(skb, ssf->ssf_length);
  	ssf->ssf_error = error;
  
  	ssf->ssfe_info.snd_sid = chunk->sinfo.sinfo_stream;
  	ssf->ssfe_info.snd_ppid = chunk->sinfo.sinfo_ppid;
  	ssf->ssfe_info.snd_context = chunk->sinfo.sinfo_context;
  	ssf->ssfe_info.snd_assoc_id = chunk->sinfo.sinfo_assoc_id;
  	ssf->ssfe_info.snd_flags = chunk->chunk_hdr->flags;
  
  	sctp_ulpevent_set_owner(event, asoc);
  	ssf->ssf_assoc_id = sctp_assoc2id(asoc);
  
  	return event;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
560
561
562
563
564
565
566
  /* Create and initialize a SCTP_SHUTDOWN_EVENT notification.
   *
   * Socket Extensions for SCTP - draft-01
   * 5.3.1.5 SCTP_SHUTDOWN_EVENT
   */
  struct sctp_ulpevent *sctp_ulpevent_make_shutdown_event(
  	const struct sctp_association *asoc,
dd0fc66fb   Al Viro   [PATCH] gfp flags...
567
  	__u16 flags, gfp_t gfp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568
569
570
571
572
573
574
575
576
577
578
  {
  	struct sctp_ulpevent *event;
  	struct sctp_shutdown_event *sse;
  	struct sk_buff *skb;
  
  	event = sctp_ulpevent_new(sizeof(struct sctp_shutdown_event),
  				  MSG_NOTIFICATION, gfp);
  	if (!event)
  		goto fail;
  
  	skb = sctp_event2skb(event);
4df864c1d   Johannes Berg   networking: make ...
579
  	sse = skb_put(skb, sizeof(struct sctp_shutdown_event));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
  
  	/* Socket Extensions for SCTP
  	 * 5.3.1.5 SCTP_SHUTDOWN_EVENT
  	 *
  	 * sse_type
  	 * It should be SCTP_SHUTDOWN_EVENT
  	 */
  	sse->sse_type = SCTP_SHUTDOWN_EVENT;
  
  	/* Socket Extensions for SCTP
  	 * 5.3.1.5 SCTP_SHUTDOWN_EVENT
  	 *
  	 * sse_flags: 16 bits (unsigned integer)
  	 * Currently unused.
  	 */
  	sse->sse_flags = 0;
  
  	/* Socket Extensions for SCTP
  	 * 5.3.1.5 SCTP_SHUTDOWN_EVENT
  	 *
  	 * sse_length: sizeof (__u32)
  	 * This field is the total length of the notification data, including
  	 * the notification header.
  	 */
  	sse->sse_length = sizeof(struct sctp_shutdown_event);
  
  	/* Socket Extensions for SCTP
  	 * 5.3.1.5 SCTP_SHUTDOWN_EVENT
  	 *
  	 * sse_assoc_id: sizeof (sctp_assoc_t)
  	 * The association id field, holds the identifier for the association.
  	 * All notifications for a given association have the same association
  	 * identifier.  For TCP style socket, this field is ignored.
  	 */
  	sctp_ulpevent_set_owner(event, asoc);
  	sse->sse_assoc_id = sctp_assoc2id(asoc);
  
  	return event;
  
  fail:
  	return NULL;
  }
0f3fffd8a   Ivan Skytte Jorgensen   [SCTP]: Fix typo ...
622
  /* Create and initialize a SCTP_ADAPTATION_INDICATION notification.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
623
624
   *
   * Socket Extensions for SCTP
0f3fffd8a   Ivan Skytte Jorgensen   [SCTP]: Fix typo ...
625
   * 5.3.1.6 SCTP_ADAPTATION_INDICATION
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
626
   */
0f3fffd8a   Ivan Skytte Jorgensen   [SCTP]: Fix typo ...
627
  struct sctp_ulpevent *sctp_ulpevent_make_adaptation_indication(
dd0fc66fb   Al Viro   [PATCH] gfp flags...
628
  	const struct sctp_association *asoc, gfp_t gfp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
629
630
  {
  	struct sctp_ulpevent *event;
0f3fffd8a   Ivan Skytte Jorgensen   [SCTP]: Fix typo ...
631
  	struct sctp_adaptation_event *sai;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
632
  	struct sk_buff *skb;
0f3fffd8a   Ivan Skytte Jorgensen   [SCTP]: Fix typo ...
633
  	event = sctp_ulpevent_new(sizeof(struct sctp_adaptation_event),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
634
635
636
637
638
  				  MSG_NOTIFICATION, gfp);
  	if (!event)
  		goto fail;
  
  	skb = sctp_event2skb(event);
4df864c1d   Johannes Berg   networking: make ...
639
  	sai = skb_put(skb, sizeof(struct sctp_adaptation_event));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
640

0f3fffd8a   Ivan Skytte Jorgensen   [SCTP]: Fix typo ...
641
  	sai->sai_type = SCTP_ADAPTATION_INDICATION;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
642
  	sai->sai_flags = 0;
0f3fffd8a   Ivan Skytte Jorgensen   [SCTP]: Fix typo ...
643
644
  	sai->sai_length = sizeof(struct sctp_adaptation_event);
  	sai->sai_adaptation_ind = asoc->peer.adaptation_ind;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
  	sctp_ulpevent_set_owner(event, asoc);
  	sai->sai_assoc_id = sctp_assoc2id(asoc);
  
  	return event;
  
  fail:
  	return NULL;
  }
  
  /* A message has been received.  Package this message as a notification
   * to pass it to the upper layers.  Go ahead and calculate the sndrcvinfo
   * even if filtered out later.
   *
   * Socket Extensions for SCTP
   * 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV)
   */
  struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
  						struct sctp_chunk *chunk,
dd0fc66fb   Al Viro   [PATCH] gfp flags...
663
  						gfp_t gfp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
665
  {
  	struct sctp_ulpevent *event = NULL;
9dde27de3   Xin Long   sctp: implement m...
666
667
668
  	struct sk_buff *skb = chunk->skb;
  	struct sock *sk = asoc->base.sk;
  	size_t padding, datalen;
4d93df0ab   Neil Horman   [SCTP]: Rewrite o...
669
670
671
672
673
674
675
676
677
678
  	int rx_count;
  
  	/*
  	 * check to see if we need to make space for this
  	 * new skb, expand the rcvbuffer if needed, or drop
  	 * the frame
  	 */
  	if (asoc->ep->rcvbuf_policy)
  		rx_count = atomic_read(&asoc->rmem_alloc);
  	else
9dde27de3   Xin Long   sctp: implement m...
679
  		rx_count = atomic_read(&sk->sk_rmem_alloc);
4d93df0ab   Neil Horman   [SCTP]: Rewrite o...
680

9dde27de3   Xin Long   sctp: implement m...
681
  	datalen = ntohs(chunk->chunk_hdr->length);
4d93df0ab   Neil Horman   [SCTP]: Rewrite o...
682

9dde27de3   Xin Long   sctp: implement m...
683
684
  	if (rx_count >= sk->sk_rcvbuf || !sk_rmem_schedule(sk, skb, datalen))
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685
686
687
688
689
  
  	/* Clone the original skb, sharing the data.  */
  	skb = skb_clone(chunk->skb, gfp);
  	if (!skb)
  		goto fail;
3888e9efc   Vlad Yasevich   sctp: Mark the ts...
690
691
692
  	/* Now that all memory allocations for this chunk succeeded, we
  	 * can mark it as received so the tsn_map is updated correctly.
  	 */
8e1ee18c3   Vlad Yasevich   sctp: Rework the ...
693
  	if (sctp_tsnmap_mark(&asoc->peer.tsn_map,
4244854d2   Neil Horman   sctp: be more res...
694
695
  			     ntohl(chunk->subh.data_hdr->tsn),
  			     chunk->transport))
8e1ee18c3   Vlad Yasevich   sctp: Rework the ...
696
  		goto fail_mark;
3888e9efc   Vlad Yasevich   sctp: Mark the ts...
697

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698
699
700
701
702
703
704
705
706
707
708
709
  	/* First calculate the padding, so we don't inadvertently
  	 * pass up the wrong length to the user.
  	 *
  	 * RFC 2960 - Section 3.2  Chunk Field Descriptions
  	 *
  	 * The total length of a chunk(including Type, Length and Value fields)
  	 * MUST be a multiple of 4 bytes.  If the length of the chunk is not a
  	 * multiple of 4 bytes, the sender MUST pad the chunk with all zero
  	 * bytes and this padding is not included in the chunk length field.
  	 * The sender should never pad with more than 3 bytes.  The receiver
  	 * MUST ignore the padding bytes.
  	 */
9dde27de3   Xin Long   sctp: implement m...
710
  	padding = SCTP_PAD4(datalen) - datalen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
711
712
713
714
715
716
  
  	/* Fixup cloned skb with just this chunks data.  */
  	skb_trim(skb, chunk->chunk_end - padding - skb->data);
  
  	/* Embed the event fields inside the cloned skb.  */
  	event = sctp_skb2event(skb);
331c4ee7f   Vlad Yasevich   [SCTP]: Fix recei...
717
718
719
720
721
  	/* Initialize event with flags 0  and correct length
  	 * Since this is a clone of the original skb, only account for
  	 * the data of this chunk as other chunks will be accounted separately.
  	 */
  	sctp_ulpevent_init(event, 0, skb->len + sizeof(struct sk_buff));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722

1f45f78f8   Marcelo Ricardo Leitner   sctp: allow GSO f...
723
724
725
726
727
  	/* And hold the chunk as we need it for getting the IP headers
  	 * later in recvmsg
  	 */
  	sctp_chunk_hold(chunk);
  	event->chunk = chunk;
1fe323aa1   Xin Long   sctp: use event->...
728
  	sctp_ulpevent_receive_data(event, asoc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
729
  	event->stream = ntohs(chunk->subh.data_hdr->stream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730
  	if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) {
eaa5c54db   Ivan Skytte Jorgensen   [SCTP] Rename SCT...
731
  		event->flags |= SCTP_UNORDERED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
732
733
734
735
  		event->cumtsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map);
  	}
  	event->tsn = ntohl(chunk->subh.data_hdr->tsn);
  	event->msg_flags |= chunk->chunk_hdr->flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
736

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
737
  	return event;
8e1ee18c3   Vlad Yasevich   sctp: Rework the ...
738
739
740
741
742
  
  fail_mark:
  	kfree_skb(skb);
  fail:
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
743
744
745
746
747
748
749
750
751
752
753
  }
  
  /* Create a partial delivery related event.
   *
   * 5.3.1.7 SCTP_PARTIAL_DELIVERY_EVENT
   *
   *   When a receiver is engaged in a partial delivery of a
   *   message this notification will be used to indicate
   *   various events.
   */
  struct sctp_ulpevent *sctp_ulpevent_make_pdapi(
65f5e3578   Xin Long   sctp: implement a...
754
755
756
  					const struct sctp_association *asoc,
  					__u32 indication, __u32 sid, __u32 seq,
  					__u32 flags, gfp_t gfp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
757
758
759
760
761
762
763
764
765
766
767
  {
  	struct sctp_ulpevent *event;
  	struct sctp_pdapi_event *pd;
  	struct sk_buff *skb;
  
  	event = sctp_ulpevent_new(sizeof(struct sctp_pdapi_event),
  				  MSG_NOTIFICATION, gfp);
  	if (!event)
  		goto fail;
  
  	skb = sctp_event2skb(event);
4df864c1d   Johannes Berg   networking: make ...
768
  	pd = skb_put(skb, sizeof(struct sctp_pdapi_event));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
769
770
771
772
773
774
775
776
  
  	/* pdapi_type
  	 *   It should be SCTP_PARTIAL_DELIVERY_EVENT
  	 *
  	 * pdapi_flags: 16 bits (unsigned integer)
  	 *   Currently unused.
  	 */
  	pd->pdapi_type = SCTP_PARTIAL_DELIVERY_EVENT;
65f5e3578   Xin Long   sctp: implement a...
777
778
779
  	pd->pdapi_flags = flags;
  	pd->pdapi_stream = sid;
  	pd->pdapi_seq = seq;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
780
781
782
783
784
785
786
787
  
  	/* pdapi_length: 32 bits (unsigned integer)
  	 *
  	 * This field is the total length of the notification data, including
  	 * the notification header.  It will generally be sizeof (struct
  	 * sctp_pdapi_event).
  	 */
  	pd->pdapi_length = sizeof(struct sctp_pdapi_event);
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
788
  	/*  pdapi_indication: 32 bits (unsigned integer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
  	 *
  	 * This field holds the indication being sent to the application.
  	 */
  	pd->pdapi_indication = indication;
  
  	/*  pdapi_assoc_id: sizeof (sctp_assoc_t)
  	 *
  	 * The association id field, holds the identifier for the association.
  	 */
  	sctp_ulpevent_set_owner(event, asoc);
  	pd->pdapi_assoc_id = sctp_assoc2id(asoc);
  
  	return event;
  fail:
  	return NULL;
  }
65b07e5d0   Vlad Yasevich   [SCTP]: API updat...
805
806
807
808
809
810
811
812
813
814
815
816
817
818
  struct sctp_ulpevent *sctp_ulpevent_make_authkey(
  	const struct sctp_association *asoc, __u16 key_id,
  	__u32 indication, gfp_t gfp)
  {
  	struct sctp_ulpevent *event;
  	struct sctp_authkey_event *ak;
  	struct sk_buff *skb;
  
  	event = sctp_ulpevent_new(sizeof(struct sctp_authkey_event),
  				  MSG_NOTIFICATION, gfp);
  	if (!event)
  		goto fail;
  
  	skb = sctp_event2skb(event);
4df864c1d   Johannes Berg   networking: make ...
819
  	ak = skb_put(skb, sizeof(struct sctp_authkey_event));
65b07e5d0   Vlad Yasevich   [SCTP]: API updat...
820

ee916fd0f   Wei Yongjun   sctp: change auth...
821
  	ak->auth_type = SCTP_AUTHENTICATION_EVENT;
65b07e5d0   Vlad Yasevich   [SCTP]: API updat...
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
  	ak->auth_flags = 0;
  	ak->auth_length = sizeof(struct sctp_authkey_event);
  
  	ak->auth_keynumber = key_id;
  	ak->auth_altkeynumber = 0;
  	ak->auth_indication = indication;
  
  	/*
  	 * The association id field, holds the identifier for the association.
  	 */
  	sctp_ulpevent_set_owner(event, asoc);
  	ak->auth_assoc_id = sctp_assoc2id(asoc);
  
  	return event;
  fail:
  	return NULL;
  }
e1cdd553d   Wei Yongjun   sctp: implement e...
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
  /*
   * Socket Extensions for SCTP
   * 6.3.10. SCTP_SENDER_DRY_EVENT
   */
  struct sctp_ulpevent *sctp_ulpevent_make_sender_dry_event(
  	const struct sctp_association *asoc, gfp_t gfp)
  {
  	struct sctp_ulpevent *event;
  	struct sctp_sender_dry_event *sdry;
  	struct sk_buff *skb;
  
  	event = sctp_ulpevent_new(sizeof(struct sctp_sender_dry_event),
  				  MSG_NOTIFICATION, gfp);
  	if (!event)
  		return NULL;
  
  	skb = sctp_event2skb(event);
4df864c1d   Johannes Berg   networking: make ...
856
  	sdry = skb_put(skb, sizeof(struct sctp_sender_dry_event));
e1cdd553d   Wei Yongjun   sctp: implement e...
857
858
859
860
861
862
863
864
865
  
  	sdry->sender_dry_type = SCTP_SENDER_DRY_EVENT;
  	sdry->sender_dry_flags = 0;
  	sdry->sender_dry_length = sizeof(struct sctp_sender_dry_event);
  	sctp_ulpevent_set_owner(event, asoc);
  	sdry->sender_dry_assoc_id = sctp_assoc2id(asoc);
  
  	return event;
  }
65b07e5d0   Vlad Yasevich   [SCTP]: API updat...
866

35ea82d61   Xin Long   sctp: add support...
867
868
  struct sctp_ulpevent *sctp_ulpevent_make_stream_reset_event(
  	const struct sctp_association *asoc, __u16 flags, __u16 stream_num,
1da4fc97c   Xin Long   sctp: fix some ty...
869
  	__be16 *stream_list, gfp_t gfp)
35ea82d61   Xin Long   sctp: add support...
870
871
872
873
874
875
876
877
878
879
880
881
  {
  	struct sctp_stream_reset_event *sreset;
  	struct sctp_ulpevent *event;
  	struct sk_buff *skb;
  	int length, i;
  
  	length = sizeof(struct sctp_stream_reset_event) + 2 * stream_num;
  	event = sctp_ulpevent_new(length, MSG_NOTIFICATION, gfp);
  	if (!event)
  		return NULL;
  
  	skb = sctp_event2skb(event);
4df864c1d   Johannes Berg   networking: make ...
882
  	sreset = skb_put(skb, length);
35ea82d61   Xin Long   sctp: add support...
883
884
885
886
887
888
889
890
891
892
893
894
  
  	sreset->strreset_type = SCTP_STREAM_RESET_EVENT;
  	sreset->strreset_flags = flags;
  	sreset->strreset_length = length;
  	sctp_ulpevent_set_owner(event, asoc);
  	sreset->strreset_assoc_id = sctp_assoc2id(asoc);
  
  	for (i = 0; i < stream_num; i++)
  		sreset->strreset_stream_list[i] = ntohs(stream_list[i]);
  
  	return event;
  }
c95129d12   Xin Long   sctp: add support...
895
896
897
898
899
900
901
902
903
904
905
906
907
908
  struct sctp_ulpevent *sctp_ulpevent_make_assoc_reset_event(
  	const struct sctp_association *asoc, __u16 flags, __u32 local_tsn,
  	__u32 remote_tsn, gfp_t gfp)
  {
  	struct sctp_assoc_reset_event *areset;
  	struct sctp_ulpevent *event;
  	struct sk_buff *skb;
  
  	event = sctp_ulpevent_new(sizeof(struct sctp_assoc_reset_event),
  				  MSG_NOTIFICATION, gfp);
  	if (!event)
  		return NULL;
  
  	skb = sctp_event2skb(event);
4df864c1d   Johannes Berg   networking: make ...
909
  	areset = skb_put(skb, sizeof(struct sctp_assoc_reset_event));
c95129d12   Xin Long   sctp: add support...
910
911
912
913
914
915
916
917
918
919
920
  
  	areset->assocreset_type = SCTP_ASSOC_RESET_EVENT;
  	areset->assocreset_flags = flags;
  	areset->assocreset_length = sizeof(struct sctp_assoc_reset_event);
  	sctp_ulpevent_set_owner(event, asoc);
  	areset->assocreset_assoc_id = sctp_assoc2id(asoc);
  	areset->assocreset_local_tsn = local_tsn;
  	areset->assocreset_remote_tsn = remote_tsn;
  
  	return event;
  }
b444153fb   Xin Long   sctp: add support...
921
922
923
924
925
926
927
928
929
930
931
932
933
934
  struct sctp_ulpevent *sctp_ulpevent_make_stream_change_event(
  	const struct sctp_association *asoc, __u16 flags,
  	__u32 strchange_instrms, __u32 strchange_outstrms, gfp_t gfp)
  {
  	struct sctp_stream_change_event *schange;
  	struct sctp_ulpevent *event;
  	struct sk_buff *skb;
  
  	event = sctp_ulpevent_new(sizeof(struct sctp_stream_change_event),
  				  MSG_NOTIFICATION, gfp);
  	if (!event)
  		return NULL;
  
  	skb = sctp_event2skb(event);
4df864c1d   Johannes Berg   networking: make ...
935
  	schange = skb_put(skb, sizeof(struct sctp_stream_change_event));
b444153fb   Xin Long   sctp: add support...
936
937
938
939
940
941
942
943
944
945
946
  
  	schange->strchange_type = SCTP_STREAM_CHANGE_EVENT;
  	schange->strchange_flags = flags;
  	schange->strchange_length = sizeof(struct sctp_stream_change_event);
  	sctp_ulpevent_set_owner(event, asoc);
  	schange->strchange_assoc_id = sctp_assoc2id(asoc);
  	schange->strchange_instrms = strchange_instrms;
  	schange->strchange_outstrms = strchange_outstrms;
  
  	return event;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
947
948
949
950
951
952
953
  /* Return the notification type, assuming this is a notification
   * event.
   */
  __u16 sctp_ulpevent_get_notification_type(const struct sctp_ulpevent *event)
  {
  	union sctp_notification *notification;
  	struct sk_buff *skb;
ab38fb04c   Vlad Yasevich   [SCTP]: Fix compi...
954
  	skb = sctp_event2skb(event);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
955
956
957
  	notification = (union sctp_notification *) skb->data;
  	return notification->sn_header.sn_type;
  }
8f2e5ae40   Daniel Borkmann   net: sctp: fix in...
958
959
960
  /* RFC6458, Section 5.3.2. SCTP Header Information Structure
   * (SCTP_SNDRCV, DEPRECATED)
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
961
962
963
964
965
966
967
  void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event,
  				   struct msghdr *msghdr)
  {
  	struct sctp_sndrcvinfo sinfo;
  
  	if (sctp_ulpevent_is_notification(event))
  		return;
8f2e5ae40   Daniel Borkmann   net: sctp: fix in...
968
  	memset(&sinfo, 0, sizeof(sinfo));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
969
  	sinfo.sinfo_stream = event->stream;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
970
  	sinfo.sinfo_ssn = event->ssn;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
971
  	sinfo.sinfo_ppid = event->ppid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
972
  	sinfo.sinfo_flags = event->flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
973
  	sinfo.sinfo_tsn = event->tsn;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
974
  	sinfo.sinfo_cumtsn = event->cumtsn;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
975
  	sinfo.sinfo_assoc_id = sctp_assoc2id(event->asoc);
8f2e5ae40   Daniel Borkmann   net: sctp: fix in...
976
  	/* Context value that is set via SCTP_CONTEXT socket option. */
6ab792f57   Ivan Skytte Jorgensen   [SCTP]: Add suppo...
977
  	sinfo.sinfo_context = event->asoc->default_rcv_context;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
978
  	/* These fields are not used while receiving. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
979
980
981
  	sinfo.sinfo_timetolive = 0;
  
  	put_cmsg(msghdr, IPPROTO_SCTP, SCTP_SNDRCV,
8f2e5ae40   Daniel Borkmann   net: sctp: fix in...
982
  		 sizeof(sinfo), &sinfo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
983
  }
0d3a421d2   Geir Ola Vaagland   net: sctp: implem...
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
  /* RFC6458, Section 5.3.5 SCTP Receive Information Structure
   * (SCTP_SNDRCV)
   */
  void sctp_ulpevent_read_rcvinfo(const struct sctp_ulpevent *event,
  				struct msghdr *msghdr)
  {
  	struct sctp_rcvinfo rinfo;
  
  	if (sctp_ulpevent_is_notification(event))
  		return;
  
  	memset(&rinfo, 0, sizeof(struct sctp_rcvinfo));
  	rinfo.rcv_sid = event->stream;
  	rinfo.rcv_ssn = event->ssn;
  	rinfo.rcv_ppid = event->ppid;
  	rinfo.rcv_flags = event->flags;
  	rinfo.rcv_tsn = event->tsn;
  	rinfo.rcv_cumtsn = event->cumtsn;
  	rinfo.rcv_assoc_id = sctp_assoc2id(event->asoc);
  	rinfo.rcv_context = event->asoc->default_rcv_context;
  
  	put_cmsg(msghdr, IPPROTO_SCTP, SCTP_RCVINFO,
  		 sizeof(rinfo), &rinfo);
  }
2347c80ff   Geir Ola Vaagland   net: sctp: implem...
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
  /* RFC6458, Section 5.3.6. SCTP Next Receive Information Structure
   * (SCTP_NXTINFO)
   */
  static void __sctp_ulpevent_read_nxtinfo(const struct sctp_ulpevent *event,
  					 struct msghdr *msghdr,
  					 const struct sk_buff *skb)
  {
  	struct sctp_nxtinfo nxtinfo;
  
  	memset(&nxtinfo, 0, sizeof(nxtinfo));
  	nxtinfo.nxt_sid = event->stream;
  	nxtinfo.nxt_ppid = event->ppid;
  	nxtinfo.nxt_flags = event->flags;
  	if (sctp_ulpevent_is_notification(event))
  		nxtinfo.nxt_flags |= SCTP_NOTIFICATION;
  	nxtinfo.nxt_length = skb->len;
  	nxtinfo.nxt_assoc_id = sctp_assoc2id(event->asoc);
  
  	put_cmsg(msghdr, IPPROTO_SCTP, SCTP_NXTINFO,
  		 sizeof(nxtinfo), &nxtinfo);
  }
  
  void sctp_ulpevent_read_nxtinfo(const struct sctp_ulpevent *event,
  				struct msghdr *msghdr,
  				struct sock *sk)
  {
  	struct sk_buff *skb;
  	int err;
  
  	skb = sctp_skb_recv_datagram(sk, MSG_PEEK, 1, &err);
  	if (skb != NULL) {
  		__sctp_ulpevent_read_nxtinfo(sctp_skb2event(skb),
  					     msghdr, skb);
  		/* Just release refcount here. */
  		kfree_skb(skb);
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
  /* Do accounting for bytes received and hold a reference to the association
   * for each skb.
   */
  static void sctp_ulpevent_receive_data(struct sctp_ulpevent *event,
  				       struct sctp_association *asoc)
  {
  	struct sk_buff *skb, *frag;
  
  	skb = sctp_event2skb(event);
  	/* Set the owner and charge rwnd for bytes received.  */
  	sctp_ulpevent_set_owner(event, asoc);
362d52040   Daniel Borkmann   Revert "net: sctp...
1056
  	sctp_assoc_rwnd_decrease(asoc, skb_headlen(skb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1057
1058
1059
1060
1061
1062
1063
1064
  
  	if (!skb->data_len)
  		return;
  
  	/* Note:  Not clearing the entire event struct as this is just a
  	 * fragment of the real event.  However, we still need to do rwnd
  	 * accounting.
  	 * In general, the skb passed from IP can have only 1 level of
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
1065
  	 * fragments. But we allow multiple levels of fragments.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1066
  	 */
1b003be39   David S. Miller   sctp: Use frag li...
1067
  	skb_walk_frags(skb, frag)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1068
  		sctp_ulpevent_receive_data(sctp_skb2event(frag), asoc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1069
1070
1071
1072
  }
  
  /* Do accounting for bytes just read by user and release the references to
   * the association.
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
1073
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1074
1075
1076
  static void sctp_ulpevent_release_data(struct sctp_ulpevent *event)
  {
  	struct sk_buff *skb, *frag;
d7c2c9e39   Tsutomu Fujii   [SCTP]: Send only...
1077
  	unsigned int	len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1078
1079
1080
1081
1082
1083
1084
1085
1086
  
  	/* Current stack structures assume that the rcv buffer is
  	 * per socket.   For UDP style sockets this is not true as
  	 * multiple associations may be on a single UDP-style socket.
  	 * Use the local private area of the skb to track the owning
  	 * association.
  	 */
  
  	skb = sctp_event2skb(event);
d7c2c9e39   Tsutomu Fujii   [SCTP]: Send only...
1087
1088
1089
1090
1091
1092
  	len = skb->len;
  
  	if (!skb->data_len)
  		goto done;
  
  	/* Don't forget the fragments. */
1b003be39   David S. Miller   sctp: Use frag li...
1093
  	skb_walk_frags(skb, frag) {
d7c2c9e39   Tsutomu Fujii   [SCTP]: Send only...
1094
1095
1096
1097
1098
1099
1100
1101
  		/* NOTE:  skb_shinfos are recursive. Although IP returns
  		 * skb's with only 1 level of fragments, SCTP reassembly can
  		 * increase the levels.
  		 */
  		sctp_ulpevent_release_frag_data(sctp_skb2event(frag));
  	}
  
  done:
362d52040   Daniel Borkmann   Revert "net: sctp...
1102
  	sctp_assoc_rwnd_increase(event->asoc, len);
1f45f78f8   Marcelo Ricardo Leitner   sctp: allow GSO f...
1103
  	sctp_chunk_put(event->chunk);
d7c2c9e39   Tsutomu Fujii   [SCTP]: Send only...
1104
1105
1106
1107
1108
1109
1110
1111
  	sctp_ulpevent_release_owner(event);
  }
  
  static void sctp_ulpevent_release_frag_data(struct sctp_ulpevent *event)
  {
  	struct sk_buff *skb, *frag;
  
  	skb = sctp_event2skb(event);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1112
1113
1114
1115
1116
  
  	if (!skb->data_len)
  		goto done;
  
  	/* Don't forget the fragments. */
1b003be39   David S. Miller   sctp: Use frag li...
1117
  	skb_walk_frags(skb, frag) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1118
1119
1120
1121
  		/* NOTE:  skb_shinfos are recursive. Although IP returns
  		 * skb's with only 1 level of fragments, SCTP reassembly can
  		 * increase the levels.
  		 */
d7c2c9e39   Tsutomu Fujii   [SCTP]: Send only...
1122
  		sctp_ulpevent_release_frag_data(sctp_skb2event(frag));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1123
1124
1125
  	}
  
  done:
1f45f78f8   Marcelo Ricardo Leitner   sctp: allow GSO f...
1126
  	sctp_chunk_put(event->chunk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1127
1128
1129
1130
1131
1132
  	sctp_ulpevent_release_owner(event);
  }
  
  /* Free a ulpevent that has an owner.  It includes releasing the reference
   * to the owner, updating the rwnd in case of a DATA event and freeing the
   * skb.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
   */
  void sctp_ulpevent_free(struct sctp_ulpevent *event)
  {
  	if (sctp_ulpevent_is_notification(event))
  		sctp_ulpevent_release_owner(event);
  	else
  		sctp_ulpevent_release_data(event);
  
  	kfree_skb(sctp_event2skb(event));
  }
  
  /* Purge the skb lists holding ulpevents. */
cd4fcc704   Thomas Graf   sctp: ABORT if re...
1145
  unsigned int sctp_queue_purge_ulpevents(struct sk_buff_head *list)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1146
1147
  {
  	struct sk_buff *skb;
cd4fcc704   Thomas Graf   sctp: ABORT if re...
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
  	unsigned int data_unread = 0;
  
  	while ((skb = skb_dequeue(list)) != NULL) {
  		struct sctp_ulpevent *event = sctp_skb2event(skb);
  
  		if (!sctp_ulpevent_is_notification(event))
  			data_unread += skb->len;
  
  		sctp_ulpevent_free(event);
  	}
  
  	return data_unread;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1160
  }