xref: /openbmc/linux/net/sctp/stream.c (revision 5303b8d3)
1 /* SCTP kernel implementation
2  * (C) Copyright IBM Corp. 2001, 2004
3  * Copyright (c) 1999-2000 Cisco, Inc.
4  * Copyright (c) 1999-2001 Motorola, Inc.
5  * Copyright (c) 2001 Intel Corp.
6  *
7  * This file is part of the SCTP kernel implementation
8  *
9  * These functions manipulate sctp tsn mapping array.
10  *
11  * This SCTP implementation is free software;
12  * you can redistribute it and/or modify it under the terms of
13  * the GNU General Public License as published by
14  * the Free Software Foundation; either version 2, or (at your option)
15  * any later version.
16  *
17  * This SCTP implementation is distributed in the hope that it
18  * will be useful, but WITHOUT ANY WARRANTY; without even the implied
19  *                 ************************
20  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21  * See the GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with GNU CC; see the file COPYING.  If not, see
25  * <http://www.gnu.org/licenses/>.
26  *
27  * Please send any bug reports or fixes you make to the
28  * email address(es):
29  *    lksctp developers <linux-sctp@vger.kernel.org>
30  *
31  * Written or modified by:
32  *    Xin Long <lucien.xin@gmail.com>
33  */
34 
35 #include <net/sctp/sctp.h>
36 #include <net/sctp/sm.h>
37 
38 int sctp_stream_init(struct sctp_stream *stream, __u16 outcnt, __u16 incnt,
39 		     gfp_t gfp)
40 {
41 	int i;
42 
43 	/* Initial stream->out size may be very big, so free it and alloc
44 	 * a new one with new outcnt to save memory.
45 	 */
46 	kfree(stream->out);
47 
48 	stream->out = kcalloc(outcnt, sizeof(*stream->out), gfp);
49 	if (!stream->out)
50 		return -ENOMEM;
51 
52 	stream->outcnt = outcnt;
53 	for (i = 0; i < stream->outcnt; i++)
54 		stream->out[i].state = SCTP_STREAM_OPEN;
55 
56 	if (!incnt)
57 		return 0;
58 
59 	stream->in = kcalloc(incnt, sizeof(*stream->in), gfp);
60 	if (!stream->in) {
61 		kfree(stream->out);
62 		stream->out = NULL;
63 		return -ENOMEM;
64 	}
65 
66 	stream->incnt = incnt;
67 
68 	return 0;
69 }
70 
71 void sctp_stream_free(struct sctp_stream *stream)
72 {
73 	kfree(stream->out);
74 	kfree(stream->in);
75 }
76 
77 void sctp_stream_clear(struct sctp_stream *stream)
78 {
79 	int i;
80 
81 	for (i = 0; i < stream->outcnt; i++)
82 		stream->out[i].ssn = 0;
83 
84 	for (i = 0; i < stream->incnt; i++)
85 		stream->in[i].ssn = 0;
86 }
87 
88 void sctp_stream_update(struct sctp_stream *stream, struct sctp_stream *new)
89 {
90 	sctp_stream_free(stream);
91 
92 	stream->out = new->out;
93 	stream->in  = new->in;
94 	stream->outcnt = new->outcnt;
95 	stream->incnt  = new->incnt;
96 
97 	new->out = NULL;
98 	new->in  = NULL;
99 }
100 
101 static int sctp_send_reconf(struct sctp_association *asoc,
102 			    struct sctp_chunk *chunk)
103 {
104 	struct net *net = sock_net(asoc->base.sk);
105 	int retval = 0;
106 
107 	retval = sctp_primitive_RECONF(net, asoc, chunk);
108 	if (retval)
109 		sctp_chunk_free(chunk);
110 
111 	return retval;
112 }
113 
114 int sctp_send_reset_streams(struct sctp_association *asoc,
115 			    struct sctp_reset_streams *params)
116 {
117 	struct sctp_stream *stream = &asoc->stream;
118 	__u16 i, str_nums, *str_list;
119 	struct sctp_chunk *chunk;
120 	int retval = -EINVAL;
121 	bool out, in;
122 
123 	if (!asoc->peer.reconf_capable ||
124 	    !(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ)) {
125 		retval = -ENOPROTOOPT;
126 		goto out;
127 	}
128 
129 	if (asoc->strreset_outstanding) {
130 		retval = -EINPROGRESS;
131 		goto out;
132 	}
133 
134 	out = params->srs_flags & SCTP_STREAM_RESET_OUTGOING;
135 	in  = params->srs_flags & SCTP_STREAM_RESET_INCOMING;
136 	if (!out && !in)
137 		goto out;
138 
139 	str_nums = params->srs_number_streams;
140 	str_list = params->srs_stream_list;
141 	if (out && str_nums)
142 		for (i = 0; i < str_nums; i++)
143 			if (str_list[i] >= stream->outcnt)
144 				goto out;
145 
146 	if (in && str_nums)
147 		for (i = 0; i < str_nums; i++)
148 			if (str_list[i] >= stream->incnt)
149 				goto out;
150 
151 	for (i = 0; i < str_nums; i++)
152 		str_list[i] = htons(str_list[i]);
153 
154 	chunk = sctp_make_strreset_req(asoc, str_nums, str_list, out, in);
155 
156 	for (i = 0; i < str_nums; i++)
157 		str_list[i] = ntohs(str_list[i]);
158 
159 	if (!chunk) {
160 		retval = -ENOMEM;
161 		goto out;
162 	}
163 
164 	if (out) {
165 		if (str_nums)
166 			for (i = 0; i < str_nums; i++)
167 				stream->out[str_list[i]].state =
168 						       SCTP_STREAM_CLOSED;
169 		else
170 			for (i = 0; i < stream->outcnt; i++)
171 				stream->out[i].state = SCTP_STREAM_CLOSED;
172 	}
173 
174 	asoc->strreset_chunk = chunk;
175 	sctp_chunk_hold(asoc->strreset_chunk);
176 
177 	retval = sctp_send_reconf(asoc, chunk);
178 	if (retval) {
179 		sctp_chunk_put(asoc->strreset_chunk);
180 		asoc->strreset_chunk = NULL;
181 		if (!out)
182 			goto out;
183 
184 		if (str_nums)
185 			for (i = 0; i < str_nums; i++)
186 				stream->out[str_list[i]].state =
187 						       SCTP_STREAM_OPEN;
188 		else
189 			for (i = 0; i < stream->outcnt; i++)
190 				stream->out[i].state = SCTP_STREAM_OPEN;
191 
192 		goto out;
193 	}
194 
195 	asoc->strreset_outstanding = out + in;
196 
197 out:
198 	return retval;
199 }
200 
201 int sctp_send_reset_assoc(struct sctp_association *asoc)
202 {
203 	struct sctp_stream *stream = &asoc->stream;
204 	struct sctp_chunk *chunk = NULL;
205 	int retval;
206 	__u16 i;
207 
208 	if (!asoc->peer.reconf_capable ||
209 	    !(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ))
210 		return -ENOPROTOOPT;
211 
212 	if (asoc->strreset_outstanding)
213 		return -EINPROGRESS;
214 
215 	chunk = sctp_make_strreset_tsnreq(asoc);
216 	if (!chunk)
217 		return -ENOMEM;
218 
219 	/* Block further xmit of data until this request is completed */
220 	for (i = 0; i < stream->outcnt; i++)
221 		stream->out[i].state = SCTP_STREAM_CLOSED;
222 
223 	asoc->strreset_chunk = chunk;
224 	sctp_chunk_hold(asoc->strreset_chunk);
225 
226 	retval = sctp_send_reconf(asoc, chunk);
227 	if (retval) {
228 		sctp_chunk_put(asoc->strreset_chunk);
229 		asoc->strreset_chunk = NULL;
230 
231 		for (i = 0; i < stream->outcnt; i++)
232 			stream->out[i].state = SCTP_STREAM_OPEN;
233 
234 		return retval;
235 	}
236 
237 	asoc->strreset_outstanding = 1;
238 
239 	return 0;
240 }
241 
242 int sctp_send_add_streams(struct sctp_association *asoc,
243 			  struct sctp_add_streams *params)
244 {
245 	struct sctp_stream *stream = &asoc->stream;
246 	struct sctp_chunk *chunk = NULL;
247 	int retval = -ENOMEM;
248 	__u32 outcnt, incnt;
249 	__u16 out, in;
250 
251 	if (!asoc->peer.reconf_capable ||
252 	    !(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ)) {
253 		retval = -ENOPROTOOPT;
254 		goto out;
255 	}
256 
257 	if (asoc->strreset_outstanding) {
258 		retval = -EINPROGRESS;
259 		goto out;
260 	}
261 
262 	out = params->sas_outstrms;
263 	in  = params->sas_instrms;
264 	outcnt = stream->outcnt + out;
265 	incnt = stream->incnt + in;
266 	if (outcnt > SCTP_MAX_STREAM || incnt > SCTP_MAX_STREAM ||
267 	    (!out && !in)) {
268 		retval = -EINVAL;
269 		goto out;
270 	}
271 
272 	if (out) {
273 		struct sctp_stream_out *streamout;
274 
275 		streamout = krealloc(stream->out, outcnt * sizeof(*streamout),
276 				     GFP_KERNEL);
277 		if (!streamout)
278 			goto out;
279 
280 		memset(streamout + stream->outcnt, 0, out * sizeof(*streamout));
281 		stream->out = streamout;
282 	}
283 
284 	chunk = sctp_make_strreset_addstrm(asoc, out, in);
285 	if (!chunk)
286 		goto out;
287 
288 	asoc->strreset_chunk = chunk;
289 	sctp_chunk_hold(asoc->strreset_chunk);
290 
291 	retval = sctp_send_reconf(asoc, chunk);
292 	if (retval) {
293 		sctp_chunk_put(asoc->strreset_chunk);
294 		asoc->strreset_chunk = NULL;
295 		goto out;
296 	}
297 
298 	stream->incnt = incnt;
299 	stream->outcnt = outcnt;
300 
301 	asoc->strreset_outstanding = !!out + !!in;
302 
303 out:
304 	return retval;
305 }
306 
307 static struct sctp_paramhdr *sctp_chunk_lookup_strreset_param(
308 			struct sctp_association *asoc, __u32 resp_seq,
309 			__be16 type)
310 {
311 	struct sctp_chunk *chunk = asoc->strreset_chunk;
312 	struct sctp_reconf_chunk *hdr;
313 	union sctp_params param;
314 
315 	if (!chunk)
316 		return NULL;
317 
318 	hdr = (struct sctp_reconf_chunk *)chunk->chunk_hdr;
319 	sctp_walk_params(param, hdr, params) {
320 		/* sctp_strreset_tsnreq is actually the basic structure
321 		 * of all stream reconf params, so it's safe to use it
322 		 * to access request_seq.
323 		 */
324 		struct sctp_strreset_tsnreq *req = param.v;
325 
326 		if ((!resp_seq || req->request_seq == resp_seq) &&
327 		    (!type || type == req->param_hdr.type))
328 			return param.v;
329 	}
330 
331 	return NULL;
332 }
333 
334 static void sctp_update_strreset_result(struct sctp_association *asoc,
335 					__u32 result)
336 {
337 	asoc->strreset_result[1] = asoc->strreset_result[0];
338 	asoc->strreset_result[0] = result;
339 }
340 
341 struct sctp_chunk *sctp_process_strreset_outreq(
342 				struct sctp_association *asoc,
343 				union sctp_params param,
344 				struct sctp_ulpevent **evp)
345 {
346 	struct sctp_strreset_outreq *outreq = param.v;
347 	struct sctp_stream *stream = &asoc->stream;
348 	__u16 i, nums, flags = 0, *str_p = NULL;
349 	__u32 result = SCTP_STRRESET_DENIED;
350 	__u32 request_seq;
351 
352 	request_seq = ntohl(outreq->request_seq);
353 
354 	if (ntohl(outreq->send_reset_at_tsn) >
355 	    sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map)) {
356 		result = SCTP_STRRESET_IN_PROGRESS;
357 		goto err;
358 	}
359 
360 	if (TSN_lt(asoc->strreset_inseq, request_seq) ||
361 	    TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
362 		result = SCTP_STRRESET_ERR_BAD_SEQNO;
363 		goto err;
364 	} else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
365 		i = asoc->strreset_inseq - request_seq - 1;
366 		result = asoc->strreset_result[i];
367 		goto err;
368 	}
369 	asoc->strreset_inseq++;
370 
371 	/* Check strreset_enable after inseq inc, as sender cannot tell
372 	 * the peer doesn't enable strreset after receiving response with
373 	 * result denied, as well as to keep consistent with bsd.
374 	 */
375 	if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ))
376 		goto out;
377 
378 	if (asoc->strreset_chunk) {
379 		if (!sctp_chunk_lookup_strreset_param(
380 				asoc, outreq->response_seq,
381 				SCTP_PARAM_RESET_IN_REQUEST)) {
382 			/* same process with outstanding isn't 0 */
383 			result = SCTP_STRRESET_ERR_IN_PROGRESS;
384 			goto out;
385 		}
386 
387 		asoc->strreset_outstanding--;
388 		asoc->strreset_outseq++;
389 
390 		if (!asoc->strreset_outstanding) {
391 			struct sctp_transport *t;
392 
393 			t = asoc->strreset_chunk->transport;
394 			if (del_timer(&t->reconf_timer))
395 				sctp_transport_put(t);
396 
397 			sctp_chunk_put(asoc->strreset_chunk);
398 			asoc->strreset_chunk = NULL;
399 		}
400 
401 		flags = SCTP_STREAM_RESET_INCOMING_SSN;
402 	}
403 
404 	nums = (ntohs(param.p->length) - sizeof(*outreq)) / 2;
405 	if (nums) {
406 		str_p = outreq->list_of_streams;
407 		for (i = 0; i < nums; i++) {
408 			if (ntohs(str_p[i]) >= stream->incnt) {
409 				result = SCTP_STRRESET_ERR_WRONG_SSN;
410 				goto out;
411 			}
412 		}
413 
414 		for (i = 0; i < nums; i++)
415 			stream->in[ntohs(str_p[i])].ssn = 0;
416 	} else {
417 		for (i = 0; i < stream->incnt; i++)
418 			stream->in[i].ssn = 0;
419 	}
420 
421 	result = SCTP_STRRESET_PERFORMED;
422 
423 	*evp = sctp_ulpevent_make_stream_reset_event(asoc,
424 		flags | SCTP_STREAM_RESET_OUTGOING_SSN, nums, str_p,
425 		GFP_ATOMIC);
426 
427 out:
428 	sctp_update_strreset_result(asoc, result);
429 err:
430 	return sctp_make_strreset_resp(asoc, result, request_seq);
431 }
432 
433 struct sctp_chunk *sctp_process_strreset_inreq(
434 				struct sctp_association *asoc,
435 				union sctp_params param,
436 				struct sctp_ulpevent **evp)
437 {
438 	struct sctp_strreset_inreq *inreq = param.v;
439 	struct sctp_stream *stream = &asoc->stream;
440 	__u32 result = SCTP_STRRESET_DENIED;
441 	struct sctp_chunk *chunk = NULL;
442 	__u16 i, nums, *str_p;
443 	__u32 request_seq;
444 
445 	request_seq = ntohl(inreq->request_seq);
446 	if (TSN_lt(asoc->strreset_inseq, request_seq) ||
447 	    TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
448 		result = SCTP_STRRESET_ERR_BAD_SEQNO;
449 		goto err;
450 	} else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
451 		i = asoc->strreset_inseq - request_seq - 1;
452 		result = asoc->strreset_result[i];
453 		if (result == SCTP_STRRESET_PERFORMED)
454 			return NULL;
455 		goto err;
456 	}
457 	asoc->strreset_inseq++;
458 
459 	if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ))
460 		goto out;
461 
462 	if (asoc->strreset_outstanding) {
463 		result = SCTP_STRRESET_ERR_IN_PROGRESS;
464 		goto out;
465 	}
466 
467 	nums = (ntohs(param.p->length) - sizeof(*inreq)) / 2;
468 	str_p = inreq->list_of_streams;
469 	for (i = 0; i < nums; i++) {
470 		if (ntohs(str_p[i]) >= stream->outcnt) {
471 			result = SCTP_STRRESET_ERR_WRONG_SSN;
472 			goto out;
473 		}
474 	}
475 
476 	chunk = sctp_make_strreset_req(asoc, nums, str_p, 1, 0);
477 	if (!chunk)
478 		goto out;
479 
480 	if (nums)
481 		for (i = 0; i < nums; i++)
482 			stream->out[ntohs(str_p[i])].state =
483 					       SCTP_STREAM_CLOSED;
484 	else
485 		for (i = 0; i < stream->outcnt; i++)
486 			stream->out[i].state = SCTP_STREAM_CLOSED;
487 
488 	asoc->strreset_chunk = chunk;
489 	asoc->strreset_outstanding = 1;
490 	sctp_chunk_hold(asoc->strreset_chunk);
491 
492 	result = SCTP_STRRESET_PERFORMED;
493 
494 	*evp = sctp_ulpevent_make_stream_reset_event(asoc,
495 		SCTP_STREAM_RESET_INCOMING_SSN, nums, str_p, GFP_ATOMIC);
496 
497 out:
498 	sctp_update_strreset_result(asoc, result);
499 err:
500 	if (!chunk)
501 		chunk =  sctp_make_strreset_resp(asoc, result, request_seq);
502 
503 	return chunk;
504 }
505 
506 struct sctp_chunk *sctp_process_strreset_tsnreq(
507 				struct sctp_association *asoc,
508 				union sctp_params param,
509 				struct sctp_ulpevent **evp)
510 {
511 	__u32 init_tsn = 0, next_tsn = 0, max_tsn_seen;
512 	struct sctp_strreset_tsnreq *tsnreq = param.v;
513 	struct sctp_stream *stream = &asoc->stream;
514 	__u32 result = SCTP_STRRESET_DENIED;
515 	__u32 request_seq;
516 	__u16 i;
517 
518 	request_seq = ntohl(tsnreq->request_seq);
519 	if (TSN_lt(asoc->strreset_inseq, request_seq) ||
520 	    TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
521 		result = SCTP_STRRESET_ERR_BAD_SEQNO;
522 		goto err;
523 	} else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
524 		i = asoc->strreset_inseq - request_seq - 1;
525 		result = asoc->strreset_result[i];
526 		if (result == SCTP_STRRESET_PERFORMED) {
527 			next_tsn = asoc->next_tsn;
528 			init_tsn =
529 				sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + 1;
530 		}
531 		goto err;
532 	}
533 	asoc->strreset_inseq++;
534 
535 	if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ))
536 		goto out;
537 
538 	if (asoc->strreset_outstanding) {
539 		result = SCTP_STRRESET_ERR_IN_PROGRESS;
540 		goto out;
541 	}
542 
543 	/* G3: The same processing as though a SACK chunk with no gap report
544 	 *     and a cumulative TSN ACK of the Sender's Next TSN minus 1 were
545 	 *     received MUST be performed.
546 	 */
547 	max_tsn_seen = sctp_tsnmap_get_max_tsn_seen(&asoc->peer.tsn_map);
548 	sctp_ulpq_reasm_flushtsn(&asoc->ulpq, max_tsn_seen);
549 	sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC);
550 
551 	/* G1: Compute an appropriate value for the Receiver's Next TSN -- the
552 	 *     TSN that the peer should use to send the next DATA chunk.  The
553 	 *     value SHOULD be the smallest TSN not acknowledged by the
554 	 *     receiver of the request plus 2^31.
555 	 */
556 	init_tsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + (1 << 31);
557 	sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL,
558 			 init_tsn, GFP_ATOMIC);
559 
560 	/* G4: The same processing as though a FWD-TSN chunk (as defined in
561 	 *     [RFC3758]) with all streams affected and a new cumulative TSN
562 	 *     ACK of the Receiver's Next TSN minus 1 were received MUST be
563 	 *     performed.
564 	 */
565 	sctp_outq_free(&asoc->outqueue);
566 
567 	/* G2: Compute an appropriate value for the local endpoint's next TSN,
568 	 *     i.e., the next TSN assigned by the receiver of the SSN/TSN reset
569 	 *     chunk.  The value SHOULD be the highest TSN sent by the receiver
570 	 *     of the request plus 1.
571 	 */
572 	next_tsn = asoc->next_tsn;
573 	asoc->ctsn_ack_point = next_tsn - 1;
574 	asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
575 
576 	/* G5:  The next expected and outgoing SSNs MUST be reset to 0 for all
577 	 *      incoming and outgoing streams.
578 	 */
579 	for (i = 0; i < stream->outcnt; i++)
580 		stream->out[i].ssn = 0;
581 	for (i = 0; i < stream->incnt; i++)
582 		stream->in[i].ssn = 0;
583 
584 	result = SCTP_STRRESET_PERFORMED;
585 
586 	*evp = sctp_ulpevent_make_assoc_reset_event(asoc, 0, init_tsn,
587 						    next_tsn, GFP_ATOMIC);
588 
589 out:
590 	sctp_update_strreset_result(asoc, result);
591 err:
592 	return sctp_make_strreset_tsnresp(asoc, result, request_seq,
593 					  next_tsn, init_tsn);
594 }
595 
596 struct sctp_chunk *sctp_process_strreset_addstrm_out(
597 				struct sctp_association *asoc,
598 				union sctp_params param,
599 				struct sctp_ulpevent **evp)
600 {
601 	struct sctp_strreset_addstrm *addstrm = param.v;
602 	struct sctp_stream *stream = &asoc->stream;
603 	__u32 result = SCTP_STRRESET_DENIED;
604 	struct sctp_stream_in *streamin;
605 	__u32 request_seq, incnt;
606 	__u16 in, i;
607 
608 	request_seq = ntohl(addstrm->request_seq);
609 	if (TSN_lt(asoc->strreset_inseq, request_seq) ||
610 	    TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
611 		result = SCTP_STRRESET_ERR_BAD_SEQNO;
612 		goto err;
613 	} else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
614 		i = asoc->strreset_inseq - request_seq - 1;
615 		result = asoc->strreset_result[i];
616 		goto err;
617 	}
618 	asoc->strreset_inseq++;
619 
620 	if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ))
621 		goto out;
622 
623 	if (asoc->strreset_chunk) {
624 		if (!sctp_chunk_lookup_strreset_param(
625 			asoc, 0, SCTP_PARAM_RESET_ADD_IN_STREAMS)) {
626 			/* same process with outstanding isn't 0 */
627 			result = SCTP_STRRESET_ERR_IN_PROGRESS;
628 			goto out;
629 		}
630 
631 		asoc->strreset_outstanding--;
632 		asoc->strreset_outseq++;
633 
634 		if (!asoc->strreset_outstanding) {
635 			struct sctp_transport *t;
636 
637 			t = asoc->strreset_chunk->transport;
638 			if (del_timer(&t->reconf_timer))
639 				sctp_transport_put(t);
640 
641 			sctp_chunk_put(asoc->strreset_chunk);
642 			asoc->strreset_chunk = NULL;
643 		}
644 	}
645 
646 	in = ntohs(addstrm->number_of_streams);
647 	incnt = stream->incnt + in;
648 	if (!in || incnt > SCTP_MAX_STREAM)
649 		goto out;
650 
651 	streamin = krealloc(stream->in, incnt * sizeof(*streamin),
652 			    GFP_ATOMIC);
653 	if (!streamin)
654 		goto out;
655 
656 	memset(streamin + stream->incnt, 0, in * sizeof(*streamin));
657 	stream->in = streamin;
658 	stream->incnt = incnt;
659 
660 	result = SCTP_STRRESET_PERFORMED;
661 
662 	*evp = sctp_ulpevent_make_stream_change_event(asoc,
663 		0, ntohs(addstrm->number_of_streams), 0, GFP_ATOMIC);
664 
665 out:
666 	sctp_update_strreset_result(asoc, result);
667 err:
668 	return sctp_make_strreset_resp(asoc, result, request_seq);
669 }
670 
671 struct sctp_chunk *sctp_process_strreset_addstrm_in(
672 				struct sctp_association *asoc,
673 				union sctp_params param,
674 				struct sctp_ulpevent **evp)
675 {
676 	struct sctp_strreset_addstrm *addstrm = param.v;
677 	struct sctp_stream *stream = &asoc->stream;
678 	__u32 result = SCTP_STRRESET_DENIED;
679 	struct sctp_stream_out *streamout;
680 	struct sctp_chunk *chunk = NULL;
681 	__u32 request_seq, outcnt;
682 	__u16 out, i;
683 
684 	request_seq = ntohl(addstrm->request_seq);
685 	if (TSN_lt(asoc->strreset_inseq, request_seq) ||
686 	    TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
687 		result = SCTP_STRRESET_ERR_BAD_SEQNO;
688 		goto err;
689 	} else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
690 		i = asoc->strreset_inseq - request_seq - 1;
691 		result = asoc->strreset_result[i];
692 		if (result == SCTP_STRRESET_PERFORMED)
693 			return NULL;
694 		goto err;
695 	}
696 	asoc->strreset_inseq++;
697 
698 	if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ))
699 		goto out;
700 
701 	if (asoc->strreset_outstanding) {
702 		result = SCTP_STRRESET_ERR_IN_PROGRESS;
703 		goto out;
704 	}
705 
706 	out = ntohs(addstrm->number_of_streams);
707 	outcnt = stream->outcnt + out;
708 	if (!out || outcnt > SCTP_MAX_STREAM)
709 		goto out;
710 
711 	streamout = krealloc(stream->out, outcnt * sizeof(*streamout),
712 			     GFP_ATOMIC);
713 	if (!streamout)
714 		goto out;
715 
716 	memset(streamout + stream->outcnt, 0, out * sizeof(*streamout));
717 	stream->out = streamout;
718 
719 	chunk = sctp_make_strreset_addstrm(asoc, out, 0);
720 	if (!chunk)
721 		goto out;
722 
723 	asoc->strreset_chunk = chunk;
724 	asoc->strreset_outstanding = 1;
725 	sctp_chunk_hold(asoc->strreset_chunk);
726 
727 	stream->outcnt = outcnt;
728 
729 	result = SCTP_STRRESET_PERFORMED;
730 
731 	*evp = sctp_ulpevent_make_stream_change_event(asoc,
732 		0, 0, ntohs(addstrm->number_of_streams), GFP_ATOMIC);
733 
734 out:
735 	sctp_update_strreset_result(asoc, result);
736 err:
737 	if (!chunk)
738 		chunk = sctp_make_strreset_resp(asoc, result, request_seq);
739 
740 	return chunk;
741 }
742 
743 struct sctp_chunk *sctp_process_strreset_resp(
744 				struct sctp_association *asoc,
745 				union sctp_params param,
746 				struct sctp_ulpevent **evp)
747 {
748 	struct sctp_stream *stream = &asoc->stream;
749 	struct sctp_strreset_resp *resp = param.v;
750 	struct sctp_transport *t;
751 	__u16 i, nums, flags = 0;
752 	struct sctp_paramhdr *req;
753 	__u32 result;
754 
755 	req = sctp_chunk_lookup_strreset_param(asoc, resp->response_seq, 0);
756 	if (!req)
757 		return NULL;
758 
759 	result = ntohl(resp->result);
760 	if (result != SCTP_STRRESET_PERFORMED) {
761 		/* if in progress, do nothing but retransmit */
762 		if (result == SCTP_STRRESET_IN_PROGRESS)
763 			return NULL;
764 		else if (result == SCTP_STRRESET_DENIED)
765 			flags = SCTP_STREAM_RESET_DENIED;
766 		else
767 			flags = SCTP_STREAM_RESET_FAILED;
768 	}
769 
770 	if (req->type == SCTP_PARAM_RESET_OUT_REQUEST) {
771 		struct sctp_strreset_outreq *outreq;
772 		__u16 *str_p;
773 
774 		outreq = (struct sctp_strreset_outreq *)req;
775 		str_p = outreq->list_of_streams;
776 		nums = (ntohs(outreq->param_hdr.length) - sizeof(*outreq)) / 2;
777 
778 		if (result == SCTP_STRRESET_PERFORMED) {
779 			if (nums) {
780 				for (i = 0; i < nums; i++)
781 					stream->out[ntohs(str_p[i])].ssn = 0;
782 			} else {
783 				for (i = 0; i < stream->outcnt; i++)
784 					stream->out[i].ssn = 0;
785 			}
786 
787 			flags = SCTP_STREAM_RESET_OUTGOING_SSN;
788 		}
789 
790 		for (i = 0; i < stream->outcnt; i++)
791 			stream->out[i].state = SCTP_STREAM_OPEN;
792 
793 		*evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
794 			nums, str_p, GFP_ATOMIC);
795 	} else if (req->type == SCTP_PARAM_RESET_IN_REQUEST) {
796 		struct sctp_strreset_inreq *inreq;
797 		__u16 *str_p;
798 
799 		/* if the result is performed, it's impossible for inreq */
800 		if (result == SCTP_STRRESET_PERFORMED)
801 			return NULL;
802 
803 		inreq = (struct sctp_strreset_inreq *)req;
804 		str_p = inreq->list_of_streams;
805 		nums = (ntohs(inreq->param_hdr.length) - sizeof(*inreq)) / 2;
806 
807 		*evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
808 			nums, str_p, GFP_ATOMIC);
809 	} else if (req->type == SCTP_PARAM_RESET_TSN_REQUEST) {
810 		struct sctp_strreset_resptsn *resptsn;
811 		__u32 stsn, rtsn;
812 
813 		/* check for resptsn, as sctp_verify_reconf didn't do it*/
814 		if (ntohs(param.p->length) != sizeof(*resptsn))
815 			return NULL;
816 
817 		resptsn = (struct sctp_strreset_resptsn *)resp;
818 		stsn = ntohl(resptsn->senders_next_tsn);
819 		rtsn = ntohl(resptsn->receivers_next_tsn);
820 
821 		if (result == SCTP_STRRESET_PERFORMED) {
822 			__u32 mtsn = sctp_tsnmap_get_max_tsn_seen(
823 						&asoc->peer.tsn_map);
824 
825 			sctp_ulpq_reasm_flushtsn(&asoc->ulpq, mtsn);
826 			sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC);
827 
828 			sctp_tsnmap_init(&asoc->peer.tsn_map,
829 					 SCTP_TSN_MAP_INITIAL,
830 					 stsn, GFP_ATOMIC);
831 
832 			sctp_outq_free(&asoc->outqueue);
833 
834 			asoc->next_tsn = rtsn;
835 			asoc->ctsn_ack_point = asoc->next_tsn - 1;
836 			asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
837 
838 			for (i = 0; i < stream->outcnt; i++)
839 				stream->out[i].ssn = 0;
840 			for (i = 0; i < stream->incnt; i++)
841 				stream->in[i].ssn = 0;
842 		}
843 
844 		for (i = 0; i < stream->outcnt; i++)
845 			stream->out[i].state = SCTP_STREAM_OPEN;
846 
847 		*evp = sctp_ulpevent_make_assoc_reset_event(asoc, flags,
848 			stsn, rtsn, GFP_ATOMIC);
849 	} else if (req->type == SCTP_PARAM_RESET_ADD_OUT_STREAMS) {
850 		struct sctp_strreset_addstrm *addstrm;
851 		__u16 number;
852 
853 		addstrm = (struct sctp_strreset_addstrm *)req;
854 		nums = ntohs(addstrm->number_of_streams);
855 		number = stream->outcnt - nums;
856 
857 		if (result == SCTP_STRRESET_PERFORMED)
858 			for (i = number; i < stream->outcnt; i++)
859 				stream->out[i].state = SCTP_STREAM_OPEN;
860 		else
861 			stream->outcnt = number;
862 
863 		*evp = sctp_ulpevent_make_stream_change_event(asoc, flags,
864 			0, nums, GFP_ATOMIC);
865 	} else if (req->type == SCTP_PARAM_RESET_ADD_IN_STREAMS) {
866 		struct sctp_strreset_addstrm *addstrm;
867 
868 		/* if the result is performed, it's impossible for addstrm in
869 		 * request.
870 		 */
871 		if (result == SCTP_STRRESET_PERFORMED)
872 			return NULL;
873 
874 		addstrm = (struct sctp_strreset_addstrm *)req;
875 		nums = ntohs(addstrm->number_of_streams);
876 
877 		*evp = sctp_ulpevent_make_stream_change_event(asoc, flags,
878 			nums, 0, GFP_ATOMIC);
879 	}
880 
881 	asoc->strreset_outstanding--;
882 	asoc->strreset_outseq++;
883 
884 	/* remove everything for this reconf request */
885 	if (!asoc->strreset_outstanding) {
886 		t = asoc->strreset_chunk->transport;
887 		if (del_timer(&t->reconf_timer))
888 			sctp_transport_put(t);
889 
890 		sctp_chunk_put(asoc->strreset_chunk);
891 		asoc->strreset_chunk = NULL;
892 	}
893 
894 	return NULL;
895 }
896