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