Linux Audio

Check our new training course

Loading...
v5.4
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/* SCTP kernel implementation
   3 * (C) Copyright IBM Corp. 2001, 2004
   4 * Copyright (c) 1999-2000 Cisco, Inc.
   5 * Copyright (c) 1999-2001 Motorola, Inc.
   6 * Copyright (c) 2001 Intel Corp.
   7 *
   8 * This file is part of the SCTP kernel implementation
   9 *
  10 * This file contains sctp stream maniuplation primitives and helpers.
  11 *
  12 * Please send any bug reports or fixes you make to the
  13 * email address(es):
  14 *    lksctp developers <linux-sctp@vger.kernel.org>
  15 *
  16 * Written or modified by:
  17 *    Xin Long <lucien.xin@gmail.com>
  18 */
  19
  20#include <linux/list.h>
  21#include <net/sctp/sctp.h>
  22#include <net/sctp/sm.h>
  23#include <net/sctp/stream_sched.h>
  24
  25/* Migrates chunks from stream queues to new stream queues if needed,
  26 * but not across associations. Also, removes those chunks to streams
  27 * higher than the new max.
  28 */
  29static void sctp_stream_outq_migrate(struct sctp_stream *stream,
  30				     struct sctp_stream *new, __u16 outcnt)
  31{
  32	struct sctp_association *asoc;
  33	struct sctp_chunk *ch, *temp;
  34	struct sctp_outq *outq;
  35	int i;
  36
  37	asoc = container_of(stream, struct sctp_association, stream);
  38	outq = &asoc->outqueue;
  39
  40	list_for_each_entry_safe(ch, temp, &outq->out_chunk_list, list) {
  41		__u16 sid = sctp_chunk_stream_no(ch);
  42
  43		if (sid < outcnt)
  44			continue;
  45
  46		sctp_sched_dequeue_common(outq, ch);
  47		/* No need to call dequeue_done here because
  48		 * the chunks are not scheduled by now.
  49		 */
  50
  51		/* Mark as failed send. */
  52		sctp_chunk_fail(ch, (__force __u32)SCTP_ERROR_INV_STRM);
  53		if (asoc->peer.prsctp_capable &&
  54		    SCTP_PR_PRIO_ENABLED(ch->sinfo.sinfo_flags))
  55			asoc->sent_cnt_removable--;
  56
  57		sctp_chunk_free(ch);
  58	}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  59
  60	if (new) {
  61		/* Here we actually move the old ext stuff into the new
  62		 * buffer, because we want to keep it. Then
  63		 * sctp_stream_update will swap ->out pointers.
  64		 */
  65		for (i = 0; i < outcnt; i++) {
  66			kfree(SCTP_SO(new, i)->ext);
  67			SCTP_SO(new, i)->ext = SCTP_SO(stream, i)->ext;
  68			SCTP_SO(stream, i)->ext = NULL;
  69		}
  70	}
  71
  72	for (i = outcnt; i < stream->outcnt; i++) {
  73		kfree(SCTP_SO(stream, i)->ext);
  74		SCTP_SO(stream, i)->ext = NULL;
  75	}
  76}
  77
  78static int sctp_stream_alloc_out(struct sctp_stream *stream, __u16 outcnt,
  79				 gfp_t gfp)
  80{
  81	int ret;
  82
  83	if (outcnt <= stream->outcnt)
  84		return 0;
  85
  86	ret = genradix_prealloc(&stream->out, outcnt, gfp);
  87	if (ret)
  88		return ret;
  89
 
  90	stream->outcnt = outcnt;
  91	return 0;
  92}
  93
  94static int sctp_stream_alloc_in(struct sctp_stream *stream, __u16 incnt,
  95				gfp_t gfp)
  96{
  97	int ret;
  98
  99	if (incnt <= stream->incnt)
 100		return 0;
 101
 102	ret = genradix_prealloc(&stream->in, incnt, gfp);
 103	if (ret)
 104		return ret;
 105
 
 106	stream->incnt = incnt;
 107	return 0;
 108}
 109
 110int sctp_stream_init(struct sctp_stream *stream, __u16 outcnt, __u16 incnt,
 111		     gfp_t gfp)
 112{
 113	struct sctp_sched_ops *sched = sctp_sched_ops_from_stream(stream);
 114	int i, ret = 0;
 115
 116	gfp |= __GFP_NOWARN;
 117
 118	/* Initial stream->out size may be very big, so free it and alloc
 119	 * a new one with new outcnt to save memory if needed.
 120	 */
 121	if (outcnt == stream->outcnt)
 122		goto in;
 123
 124	/* Filter out chunks queued on streams that won't exist anymore */
 125	sched->unsched_all(stream);
 126	sctp_stream_outq_migrate(stream, NULL, outcnt);
 127	sched->sched_all(stream);
 128
 129	ret = sctp_stream_alloc_out(stream, outcnt, gfp);
 130	if (ret)
 131		goto out;
 132
 133	for (i = 0; i < stream->outcnt; i++)
 134		SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
 135
 136in:
 137	sctp_stream_interleave_init(stream);
 138	if (!incnt)
 139		goto out;
 140
 141	ret = sctp_stream_alloc_in(stream, incnt, gfp);
 142	if (ret) {
 143		sched->free(stream);
 144		genradix_free(&stream->out);
 145		stream->outcnt = 0;
 146		goto out;
 147	}
 148
 149out:
 150	return ret;
 151}
 152
 153int sctp_stream_init_ext(struct sctp_stream *stream, __u16 sid)
 154{
 155	struct sctp_stream_out_ext *soute;
 156	int ret;
 157
 158	soute = kzalloc(sizeof(*soute), GFP_KERNEL);
 159	if (!soute)
 160		return -ENOMEM;
 161	SCTP_SO(stream, sid)->ext = soute;
 162
 163	ret = sctp_sched_init_sid(stream, sid, GFP_KERNEL);
 164	if (ret) {
 165		kfree(SCTP_SO(stream, sid)->ext);
 166		SCTP_SO(stream, sid)->ext = NULL;
 167	}
 168
 169	return ret;
 170}
 171
 172void sctp_stream_free(struct sctp_stream *stream)
 173{
 174	struct sctp_sched_ops *sched = sctp_sched_ops_from_stream(stream);
 175	int i;
 176
 177	sched->free(stream);
 178	for (i = 0; i < stream->outcnt; i++)
 179		kfree(SCTP_SO(stream, i)->ext);
 180	genradix_free(&stream->out);
 181	genradix_free(&stream->in);
 182}
 183
 184void sctp_stream_clear(struct sctp_stream *stream)
 185{
 186	int i;
 187
 188	for (i = 0; i < stream->outcnt; i++) {
 189		SCTP_SO(stream, i)->mid = 0;
 190		SCTP_SO(stream, i)->mid_uo = 0;
 191	}
 192
 193	for (i = 0; i < stream->incnt; i++)
 194		SCTP_SI(stream, i)->mid = 0;
 195}
 196
 197void sctp_stream_update(struct sctp_stream *stream, struct sctp_stream *new)
 198{
 199	struct sctp_sched_ops *sched = sctp_sched_ops_from_stream(stream);
 200
 201	sched->unsched_all(stream);
 202	sctp_stream_outq_migrate(stream, new, new->outcnt);
 203	sctp_stream_free(stream);
 204
 205	stream->out = new->out;
 206	stream->in  = new->in;
 207	stream->outcnt = new->outcnt;
 208	stream->incnt  = new->incnt;
 209
 210	sched->sched_all(stream);
 211
 212	new->out.tree.root = NULL;
 213	new->in.tree.root  = NULL;
 214	new->outcnt = 0;
 215	new->incnt  = 0;
 216}
 217
 218static int sctp_send_reconf(struct sctp_association *asoc,
 219			    struct sctp_chunk *chunk)
 220{
 221	struct net *net = sock_net(asoc->base.sk);
 222	int retval = 0;
 223
 224	retval = sctp_primitive_RECONF(net, asoc, chunk);
 225	if (retval)
 226		sctp_chunk_free(chunk);
 227
 228	return retval;
 229}
 230
 231static bool sctp_stream_outq_is_empty(struct sctp_stream *stream,
 232				      __u16 str_nums, __be16 *str_list)
 233{
 234	struct sctp_association *asoc;
 235	__u16 i;
 236
 237	asoc = container_of(stream, struct sctp_association, stream);
 238	if (!asoc->outqueue.out_qlen)
 239		return true;
 240
 241	if (!str_nums)
 242		return false;
 243
 244	for (i = 0; i < str_nums; i++) {
 245		__u16 sid = ntohs(str_list[i]);
 246
 247		if (SCTP_SO(stream, sid)->ext &&
 248		    !list_empty(&SCTP_SO(stream, sid)->ext->outq))
 249			return false;
 250	}
 251
 252	return true;
 253}
 254
 255int sctp_send_reset_streams(struct sctp_association *asoc,
 256			    struct sctp_reset_streams *params)
 257{
 258	struct sctp_stream *stream = &asoc->stream;
 259	__u16 i, str_nums, *str_list;
 260	struct sctp_chunk *chunk;
 261	int retval = -EINVAL;
 262	__be16 *nstr_list;
 263	bool out, in;
 264
 265	if (!asoc->peer.reconf_capable ||
 266	    !(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ)) {
 267		retval = -ENOPROTOOPT;
 268		goto out;
 269	}
 270
 271	if (asoc->strreset_outstanding) {
 272		retval = -EINPROGRESS;
 273		goto out;
 274	}
 275
 276	out = params->srs_flags & SCTP_STREAM_RESET_OUTGOING;
 277	in  = params->srs_flags & SCTP_STREAM_RESET_INCOMING;
 278	if (!out && !in)
 279		goto out;
 280
 281	str_nums = params->srs_number_streams;
 282	str_list = params->srs_stream_list;
 283	if (str_nums) {
 284		int param_len = 0;
 285
 286		if (out) {
 287			for (i = 0; i < str_nums; i++)
 288				if (str_list[i] >= stream->outcnt)
 289					goto out;
 290
 291			param_len = str_nums * sizeof(__u16) +
 292				    sizeof(struct sctp_strreset_outreq);
 293		}
 294
 295		if (in) {
 296			for (i = 0; i < str_nums; i++)
 297				if (str_list[i] >= stream->incnt)
 298					goto out;
 299
 300			param_len += str_nums * sizeof(__u16) +
 301				     sizeof(struct sctp_strreset_inreq);
 302		}
 303
 304		if (param_len > SCTP_MAX_CHUNK_LEN -
 305				sizeof(struct sctp_reconf_chunk))
 306			goto out;
 307	}
 308
 309	nstr_list = kcalloc(str_nums, sizeof(__be16), GFP_KERNEL);
 310	if (!nstr_list) {
 311		retval = -ENOMEM;
 312		goto out;
 313	}
 314
 315	for (i = 0; i < str_nums; i++)
 316		nstr_list[i] = htons(str_list[i]);
 317
 318	if (out && !sctp_stream_outq_is_empty(stream, str_nums, nstr_list)) {
 319		kfree(nstr_list);
 320		retval = -EAGAIN;
 321		goto out;
 322	}
 323
 324	chunk = sctp_make_strreset_req(asoc, str_nums, nstr_list, out, in);
 325
 326	kfree(nstr_list);
 327
 328	if (!chunk) {
 329		retval = -ENOMEM;
 330		goto out;
 331	}
 332
 333	if (out) {
 334		if (str_nums)
 335			for (i = 0; i < str_nums; i++)
 336				SCTP_SO(stream, str_list[i])->state =
 337						       SCTP_STREAM_CLOSED;
 338		else
 339			for (i = 0; i < stream->outcnt; i++)
 340				SCTP_SO(stream, i)->state = SCTP_STREAM_CLOSED;
 341	}
 342
 343	asoc->strreset_chunk = chunk;
 344	sctp_chunk_hold(asoc->strreset_chunk);
 345
 346	retval = sctp_send_reconf(asoc, chunk);
 347	if (retval) {
 348		sctp_chunk_put(asoc->strreset_chunk);
 349		asoc->strreset_chunk = NULL;
 350		if (!out)
 351			goto out;
 352
 353		if (str_nums)
 354			for (i = 0; i < str_nums; i++)
 355				SCTP_SO(stream, str_list[i])->state =
 356						       SCTP_STREAM_OPEN;
 357		else
 358			for (i = 0; i < stream->outcnt; i++)
 359				SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
 360
 361		goto out;
 362	}
 363
 364	asoc->strreset_outstanding = out + in;
 365
 366out:
 367	return retval;
 368}
 369
 370int sctp_send_reset_assoc(struct sctp_association *asoc)
 371{
 372	struct sctp_stream *stream = &asoc->stream;
 373	struct sctp_chunk *chunk = NULL;
 374	int retval;
 375	__u16 i;
 376
 377	if (!asoc->peer.reconf_capable ||
 378	    !(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ))
 379		return -ENOPROTOOPT;
 380
 381	if (asoc->strreset_outstanding)
 382		return -EINPROGRESS;
 383
 384	if (!sctp_outq_is_empty(&asoc->outqueue))
 385		return -EAGAIN;
 386
 387	chunk = sctp_make_strreset_tsnreq(asoc);
 388	if (!chunk)
 389		return -ENOMEM;
 390
 391	/* Block further xmit of data until this request is completed */
 392	for (i = 0; i < stream->outcnt; i++)
 393		SCTP_SO(stream, i)->state = SCTP_STREAM_CLOSED;
 394
 395	asoc->strreset_chunk = chunk;
 396	sctp_chunk_hold(asoc->strreset_chunk);
 397
 398	retval = sctp_send_reconf(asoc, chunk);
 399	if (retval) {
 400		sctp_chunk_put(asoc->strreset_chunk);
 401		asoc->strreset_chunk = NULL;
 402
 403		for (i = 0; i < stream->outcnt; i++)
 404			SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
 405
 406		return retval;
 407	}
 408
 409	asoc->strreset_outstanding = 1;
 410
 411	return 0;
 412}
 413
 414int sctp_send_add_streams(struct sctp_association *asoc,
 415			  struct sctp_add_streams *params)
 416{
 417	struct sctp_stream *stream = &asoc->stream;
 418	struct sctp_chunk *chunk = NULL;
 419	int retval;
 420	__u32 outcnt, incnt;
 421	__u16 out, in;
 422
 423	if (!asoc->peer.reconf_capable ||
 424	    !(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ)) {
 425		retval = -ENOPROTOOPT;
 426		goto out;
 427	}
 428
 429	if (asoc->strreset_outstanding) {
 430		retval = -EINPROGRESS;
 431		goto out;
 432	}
 433
 434	out = params->sas_outstrms;
 435	in  = params->sas_instrms;
 436	outcnt = stream->outcnt + out;
 437	incnt = stream->incnt + in;
 438	if (outcnt > SCTP_MAX_STREAM || incnt > SCTP_MAX_STREAM ||
 439	    (!out && !in)) {
 440		retval = -EINVAL;
 441		goto out;
 442	}
 443
 444	if (out) {
 445		retval = sctp_stream_alloc_out(stream, outcnt, GFP_KERNEL);
 446		if (retval)
 447			goto out;
 448	}
 449
 450	chunk = sctp_make_strreset_addstrm(asoc, out, in);
 451	if (!chunk) {
 452		retval = -ENOMEM;
 453		goto out;
 454	}
 455
 456	asoc->strreset_chunk = chunk;
 457	sctp_chunk_hold(asoc->strreset_chunk);
 458
 459	retval = sctp_send_reconf(asoc, chunk);
 460	if (retval) {
 461		sctp_chunk_put(asoc->strreset_chunk);
 462		asoc->strreset_chunk = NULL;
 463		goto out;
 464	}
 465
 466	asoc->strreset_outstanding = !!out + !!in;
 467
 468out:
 469	return retval;
 470}
 471
 472static struct sctp_paramhdr *sctp_chunk_lookup_strreset_param(
 473			struct sctp_association *asoc, __be32 resp_seq,
 474			__be16 type)
 475{
 476	struct sctp_chunk *chunk = asoc->strreset_chunk;
 477	struct sctp_reconf_chunk *hdr;
 478	union sctp_params param;
 479
 480	if (!chunk)
 481		return NULL;
 482
 483	hdr = (struct sctp_reconf_chunk *)chunk->chunk_hdr;
 484	sctp_walk_params(param, hdr, params) {
 485		/* sctp_strreset_tsnreq is actually the basic structure
 486		 * of all stream reconf params, so it's safe to use it
 487		 * to access request_seq.
 488		 */
 489		struct sctp_strreset_tsnreq *req = param.v;
 490
 491		if ((!resp_seq || req->request_seq == resp_seq) &&
 492		    (!type || type == req->param_hdr.type))
 493			return param.v;
 494	}
 495
 496	return NULL;
 497}
 498
 499static void sctp_update_strreset_result(struct sctp_association *asoc,
 500					__u32 result)
 501{
 502	asoc->strreset_result[1] = asoc->strreset_result[0];
 503	asoc->strreset_result[0] = result;
 504}
 505
 506struct sctp_chunk *sctp_process_strreset_outreq(
 507				struct sctp_association *asoc,
 508				union sctp_params param,
 509				struct sctp_ulpevent **evp)
 510{
 511	struct sctp_strreset_outreq *outreq = param.v;
 512	struct sctp_stream *stream = &asoc->stream;
 513	__u32 result = SCTP_STRRESET_DENIED;
 514	__be16 *str_p = NULL;
 515	__u32 request_seq;
 516	__u16 i, nums;
 517
 518	request_seq = ntohl(outreq->request_seq);
 519
 520	if (ntohl(outreq->send_reset_at_tsn) >
 521	    sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map)) {
 522		result = SCTP_STRRESET_IN_PROGRESS;
 523		goto err;
 524	}
 525
 526	if (TSN_lt(asoc->strreset_inseq, request_seq) ||
 527	    TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
 528		result = SCTP_STRRESET_ERR_BAD_SEQNO;
 529		goto err;
 530	} else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
 531		i = asoc->strreset_inseq - request_seq - 1;
 532		result = asoc->strreset_result[i];
 533		goto err;
 534	}
 535	asoc->strreset_inseq++;
 536
 537	/* Check strreset_enable after inseq inc, as sender cannot tell
 538	 * the peer doesn't enable strreset after receiving response with
 539	 * result denied, as well as to keep consistent with bsd.
 540	 */
 541	if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ))
 542		goto out;
 543
 544	nums = (ntohs(param.p->length) - sizeof(*outreq)) / sizeof(__u16);
 545	str_p = outreq->list_of_streams;
 546	for (i = 0; i < nums; i++) {
 547		if (ntohs(str_p[i]) >= stream->incnt) {
 548			result = SCTP_STRRESET_ERR_WRONG_SSN;
 549			goto out;
 550		}
 551	}
 552
 553	if (asoc->strreset_chunk) {
 554		if (!sctp_chunk_lookup_strreset_param(
 555				asoc, outreq->response_seq,
 556				SCTP_PARAM_RESET_IN_REQUEST)) {
 557			/* same process with outstanding isn't 0 */
 558			result = SCTP_STRRESET_ERR_IN_PROGRESS;
 559			goto out;
 560		}
 561
 562		asoc->strreset_outstanding--;
 563		asoc->strreset_outseq++;
 564
 565		if (!asoc->strreset_outstanding) {
 566			struct sctp_transport *t;
 567
 568			t = asoc->strreset_chunk->transport;
 569			if (del_timer(&t->reconf_timer))
 570				sctp_transport_put(t);
 571
 572			sctp_chunk_put(asoc->strreset_chunk);
 573			asoc->strreset_chunk = NULL;
 574		}
 575	}
 576
 577	if (nums)
 578		for (i = 0; i < nums; i++)
 579			SCTP_SI(stream, ntohs(str_p[i]))->mid = 0;
 580	else
 581		for (i = 0; i < stream->incnt; i++)
 582			SCTP_SI(stream, i)->mid = 0;
 583
 584	result = SCTP_STRRESET_PERFORMED;
 585
 586	*evp = sctp_ulpevent_make_stream_reset_event(asoc,
 587		SCTP_STREAM_RESET_INCOMING_SSN, nums, str_p, GFP_ATOMIC);
 588
 589out:
 590	sctp_update_strreset_result(asoc, result);
 591err:
 592	return sctp_make_strreset_resp(asoc, result, request_seq);
 593}
 594
 595struct sctp_chunk *sctp_process_strreset_inreq(
 596				struct sctp_association *asoc,
 597				union sctp_params param,
 598				struct sctp_ulpevent **evp)
 599{
 600	struct sctp_strreset_inreq *inreq = param.v;
 601	struct sctp_stream *stream = &asoc->stream;
 602	__u32 result = SCTP_STRRESET_DENIED;
 603	struct sctp_chunk *chunk = NULL;
 604	__u32 request_seq;
 605	__u16 i, nums;
 606	__be16 *str_p;
 607
 608	request_seq = ntohl(inreq->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		if (result == SCTP_STRRESET_PERFORMED)
 617			return NULL;
 618		goto err;
 619	}
 620	asoc->strreset_inseq++;
 621
 622	if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ))
 623		goto out;
 624
 625	if (asoc->strreset_outstanding) {
 626		result = SCTP_STRRESET_ERR_IN_PROGRESS;
 627		goto out;
 628	}
 629
 630	nums = (ntohs(param.p->length) - sizeof(*inreq)) / sizeof(__u16);
 631	str_p = inreq->list_of_streams;
 632	for (i = 0; i < nums; i++) {
 633		if (ntohs(str_p[i]) >= stream->outcnt) {
 634			result = SCTP_STRRESET_ERR_WRONG_SSN;
 635			goto out;
 636		}
 637	}
 638
 639	if (!sctp_stream_outq_is_empty(stream, nums, str_p)) {
 640		result = SCTP_STRRESET_IN_PROGRESS;
 641		asoc->strreset_inseq--;
 642		goto err;
 643	}
 644
 645	chunk = sctp_make_strreset_req(asoc, nums, str_p, 1, 0);
 646	if (!chunk)
 647		goto out;
 648
 649	if (nums)
 650		for (i = 0; i < nums; i++)
 651			SCTP_SO(stream, ntohs(str_p[i]))->state =
 652					       SCTP_STREAM_CLOSED;
 653	else
 654		for (i = 0; i < stream->outcnt; i++)
 655			SCTP_SO(stream, i)->state = SCTP_STREAM_CLOSED;
 656
 657	asoc->strreset_chunk = chunk;
 658	asoc->strreset_outstanding = 1;
 659	sctp_chunk_hold(asoc->strreset_chunk);
 660
 661	result = SCTP_STRRESET_PERFORMED;
 662
 663out:
 664	sctp_update_strreset_result(asoc, result);
 665err:
 666	if (!chunk)
 667		chunk =  sctp_make_strreset_resp(asoc, result, request_seq);
 668
 669	return chunk;
 670}
 671
 672struct sctp_chunk *sctp_process_strreset_tsnreq(
 673				struct sctp_association *asoc,
 674				union sctp_params param,
 675				struct sctp_ulpevent **evp)
 676{
 677	__u32 init_tsn = 0, next_tsn = 0, max_tsn_seen;
 678	struct sctp_strreset_tsnreq *tsnreq = param.v;
 679	struct sctp_stream *stream = &asoc->stream;
 680	__u32 result = SCTP_STRRESET_DENIED;
 681	__u32 request_seq;
 682	__u16 i;
 683
 684	request_seq = ntohl(tsnreq->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			next_tsn = asoc->ctsn_ack_point + 1;
 694			init_tsn =
 695				sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + 1;
 696		}
 697		goto err;
 698	}
 699
 700	if (!sctp_outq_is_empty(&asoc->outqueue)) {
 701		result = SCTP_STRRESET_IN_PROGRESS;
 702		goto err;
 703	}
 704
 705	asoc->strreset_inseq++;
 706
 707	if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ))
 708		goto out;
 709
 710	if (asoc->strreset_outstanding) {
 711		result = SCTP_STRRESET_ERR_IN_PROGRESS;
 712		goto out;
 713	}
 714
 715	/* G4: The same processing as though a FWD-TSN chunk (as defined in
 716	 *     [RFC3758]) with all streams affected and a new cumulative TSN
 717	 *     ACK of the Receiver's Next TSN minus 1 were received MUST be
 718	 *     performed.
 719	 */
 720	max_tsn_seen = sctp_tsnmap_get_max_tsn_seen(&asoc->peer.tsn_map);
 721	asoc->stream.si->report_ftsn(&asoc->ulpq, max_tsn_seen);
 722
 723	/* G1: Compute an appropriate value for the Receiver's Next TSN -- the
 724	 *     TSN that the peer should use to send the next DATA chunk.  The
 725	 *     value SHOULD be the smallest TSN not acknowledged by the
 726	 *     receiver of the request plus 2^31.
 727	 */
 728	init_tsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + (1 << 31);
 729	sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL,
 730			 init_tsn, GFP_ATOMIC);
 731
 732	/* G3: The same processing as though a SACK chunk with no gap report
 733	 *     and a cumulative TSN ACK of the Sender's Next TSN minus 1 were
 734	 *     received MUST be performed.
 735	 */
 736	sctp_outq_free(&asoc->outqueue);
 737
 738	/* G2: Compute an appropriate value for the local endpoint's next TSN,
 739	 *     i.e., the next TSN assigned by the receiver of the SSN/TSN reset
 740	 *     chunk.  The value SHOULD be the highest TSN sent by the receiver
 741	 *     of the request plus 1.
 742	 */
 743	next_tsn = asoc->next_tsn;
 744	asoc->ctsn_ack_point = next_tsn - 1;
 745	asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
 746
 747	/* G5:  The next expected and outgoing SSNs MUST be reset to 0 for all
 748	 *      incoming and outgoing streams.
 749	 */
 750	for (i = 0; i < stream->outcnt; i++) {
 751		SCTP_SO(stream, i)->mid = 0;
 752		SCTP_SO(stream, i)->mid_uo = 0;
 753	}
 754	for (i = 0; i < stream->incnt; i++)
 755		SCTP_SI(stream, i)->mid = 0;
 756
 757	result = SCTP_STRRESET_PERFORMED;
 758
 759	*evp = sctp_ulpevent_make_assoc_reset_event(asoc, 0, init_tsn,
 760						    next_tsn, GFP_ATOMIC);
 761
 762out:
 763	sctp_update_strreset_result(asoc, result);
 764err:
 765	return sctp_make_strreset_tsnresp(asoc, result, request_seq,
 766					  next_tsn, init_tsn);
 767}
 768
 769struct sctp_chunk *sctp_process_strreset_addstrm_out(
 770				struct sctp_association *asoc,
 771				union sctp_params param,
 772				struct sctp_ulpevent **evp)
 773{
 774	struct sctp_strreset_addstrm *addstrm = param.v;
 775	struct sctp_stream *stream = &asoc->stream;
 776	__u32 result = SCTP_STRRESET_DENIED;
 777	__u32 request_seq, incnt;
 778	__u16 in, i;
 779
 780	request_seq = ntohl(addstrm->request_seq);
 781	if (TSN_lt(asoc->strreset_inseq, request_seq) ||
 782	    TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
 783		result = SCTP_STRRESET_ERR_BAD_SEQNO;
 784		goto err;
 785	} else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
 786		i = asoc->strreset_inseq - request_seq - 1;
 787		result = asoc->strreset_result[i];
 788		goto err;
 789	}
 790	asoc->strreset_inseq++;
 791
 792	if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ))
 793		goto out;
 794
 795	in = ntohs(addstrm->number_of_streams);
 796	incnt = stream->incnt + in;
 797	if (!in || incnt > SCTP_MAX_STREAM)
 798		goto out;
 799
 800	if (sctp_stream_alloc_in(stream, incnt, GFP_ATOMIC))
 801		goto out;
 802
 803	if (asoc->strreset_chunk) {
 804		if (!sctp_chunk_lookup_strreset_param(
 805			asoc, 0, SCTP_PARAM_RESET_ADD_IN_STREAMS)) {
 806			/* same process with outstanding isn't 0 */
 807			result = SCTP_STRRESET_ERR_IN_PROGRESS;
 808			goto out;
 809		}
 810
 811		asoc->strreset_outstanding--;
 812		asoc->strreset_outseq++;
 813
 814		if (!asoc->strreset_outstanding) {
 815			struct sctp_transport *t;
 816
 817			t = asoc->strreset_chunk->transport;
 818			if (del_timer(&t->reconf_timer))
 819				sctp_transport_put(t);
 820
 821			sctp_chunk_put(asoc->strreset_chunk);
 822			asoc->strreset_chunk = NULL;
 823		}
 824	}
 825
 826	stream->incnt = incnt;
 827
 828	result = SCTP_STRRESET_PERFORMED;
 829
 830	*evp = sctp_ulpevent_make_stream_change_event(asoc,
 831		0, ntohs(addstrm->number_of_streams), 0, GFP_ATOMIC);
 832
 833out:
 834	sctp_update_strreset_result(asoc, result);
 835err:
 836	return sctp_make_strreset_resp(asoc, result, request_seq);
 837}
 838
 839struct sctp_chunk *sctp_process_strreset_addstrm_in(
 840				struct sctp_association *asoc,
 841				union sctp_params param,
 842				struct sctp_ulpevent **evp)
 843{
 844	struct sctp_strreset_addstrm *addstrm = param.v;
 845	struct sctp_stream *stream = &asoc->stream;
 846	__u32 result = SCTP_STRRESET_DENIED;
 847	struct sctp_chunk *chunk = NULL;
 848	__u32 request_seq, outcnt;
 849	__u16 out, i;
 850	int ret;
 851
 852	request_seq = ntohl(addstrm->request_seq);
 853	if (TSN_lt(asoc->strreset_inseq, request_seq) ||
 854	    TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
 855		result = SCTP_STRRESET_ERR_BAD_SEQNO;
 856		goto err;
 857	} else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
 858		i = asoc->strreset_inseq - request_seq - 1;
 859		result = asoc->strreset_result[i];
 860		if (result == SCTP_STRRESET_PERFORMED)
 861			return NULL;
 862		goto err;
 863	}
 864	asoc->strreset_inseq++;
 865
 866	if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ))
 867		goto out;
 868
 869	if (asoc->strreset_outstanding) {
 870		result = SCTP_STRRESET_ERR_IN_PROGRESS;
 871		goto out;
 872	}
 873
 874	out = ntohs(addstrm->number_of_streams);
 875	outcnt = stream->outcnt + out;
 876	if (!out || outcnt > SCTP_MAX_STREAM)
 877		goto out;
 878
 879	ret = sctp_stream_alloc_out(stream, outcnt, GFP_ATOMIC);
 880	if (ret)
 881		goto out;
 882
 883	chunk = sctp_make_strreset_addstrm(asoc, out, 0);
 884	if (!chunk)
 885		goto out;
 886
 887	asoc->strreset_chunk = chunk;
 888	asoc->strreset_outstanding = 1;
 889	sctp_chunk_hold(asoc->strreset_chunk);
 890
 891	stream->outcnt = outcnt;
 892
 893	result = SCTP_STRRESET_PERFORMED;
 894
 895out:
 896	sctp_update_strreset_result(asoc, result);
 897err:
 898	if (!chunk)
 899		chunk = sctp_make_strreset_resp(asoc, result, request_seq);
 900
 901	return chunk;
 902}
 903
 904struct sctp_chunk *sctp_process_strreset_resp(
 905				struct sctp_association *asoc,
 906				union sctp_params param,
 907				struct sctp_ulpevent **evp)
 908{
 909	struct sctp_stream *stream = &asoc->stream;
 910	struct sctp_strreset_resp *resp = param.v;
 911	struct sctp_transport *t;
 912	__u16 i, nums, flags = 0;
 913	struct sctp_paramhdr *req;
 914	__u32 result;
 915
 916	req = sctp_chunk_lookup_strreset_param(asoc, resp->response_seq, 0);
 917	if (!req)
 918		return NULL;
 919
 920	result = ntohl(resp->result);
 921	if (result != SCTP_STRRESET_PERFORMED) {
 922		/* if in progress, do nothing but retransmit */
 923		if (result == SCTP_STRRESET_IN_PROGRESS)
 924			return NULL;
 925		else if (result == SCTP_STRRESET_DENIED)
 926			flags = SCTP_STREAM_RESET_DENIED;
 927		else
 928			flags = SCTP_STREAM_RESET_FAILED;
 929	}
 930
 931	if (req->type == SCTP_PARAM_RESET_OUT_REQUEST) {
 932		struct sctp_strreset_outreq *outreq;
 933		__be16 *str_p;
 934
 935		outreq = (struct sctp_strreset_outreq *)req;
 936		str_p = outreq->list_of_streams;
 937		nums = (ntohs(outreq->param_hdr.length) - sizeof(*outreq)) /
 938		       sizeof(__u16);
 939
 940		if (result == SCTP_STRRESET_PERFORMED) {
 941			struct sctp_stream_out *sout;
 942			if (nums) {
 943				for (i = 0; i < nums; i++) {
 944					sout = SCTP_SO(stream, ntohs(str_p[i]));
 945					sout->mid = 0;
 946					sout->mid_uo = 0;
 947				}
 948			} else {
 949				for (i = 0; i < stream->outcnt; i++) {
 950					sout = SCTP_SO(stream, i);
 951					sout->mid = 0;
 952					sout->mid_uo = 0;
 953				}
 954			}
 955		}
 956
 957		flags |= SCTP_STREAM_RESET_OUTGOING_SSN;
 958
 959		for (i = 0; i < stream->outcnt; i++)
 960			SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
 961
 962		*evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
 963			nums, str_p, GFP_ATOMIC);
 964	} else if (req->type == SCTP_PARAM_RESET_IN_REQUEST) {
 965		struct sctp_strreset_inreq *inreq;
 966		__be16 *str_p;
 967
 968		/* if the result is performed, it's impossible for inreq */
 969		if (result == SCTP_STRRESET_PERFORMED)
 970			return NULL;
 971
 972		inreq = (struct sctp_strreset_inreq *)req;
 973		str_p = inreq->list_of_streams;
 974		nums = (ntohs(inreq->param_hdr.length) - sizeof(*inreq)) /
 975		       sizeof(__u16);
 976
 977		flags |= SCTP_STREAM_RESET_INCOMING_SSN;
 978
 979		*evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
 980			nums, str_p, GFP_ATOMIC);
 981	} else if (req->type == SCTP_PARAM_RESET_TSN_REQUEST) {
 982		struct sctp_strreset_resptsn *resptsn;
 983		__u32 stsn, rtsn;
 984
 985		/* check for resptsn, as sctp_verify_reconf didn't do it*/
 986		if (ntohs(param.p->length) != sizeof(*resptsn))
 987			return NULL;
 988
 989		resptsn = (struct sctp_strreset_resptsn *)resp;
 990		stsn = ntohl(resptsn->senders_next_tsn);
 991		rtsn = ntohl(resptsn->receivers_next_tsn);
 992
 993		if (result == SCTP_STRRESET_PERFORMED) {
 994			__u32 mtsn = sctp_tsnmap_get_max_tsn_seen(
 995						&asoc->peer.tsn_map);
 996			LIST_HEAD(temp);
 997
 998			asoc->stream.si->report_ftsn(&asoc->ulpq, mtsn);
 999
1000			sctp_tsnmap_init(&asoc->peer.tsn_map,
1001					 SCTP_TSN_MAP_INITIAL,
1002					 stsn, GFP_ATOMIC);
1003
1004			/* Clean up sacked and abandoned queues only. As the
1005			 * out_chunk_list may not be empty, splice it to temp,
1006			 * then get it back after sctp_outq_free is done.
1007			 */
1008			list_splice_init(&asoc->outqueue.out_chunk_list, &temp);
1009			sctp_outq_free(&asoc->outqueue);
1010			list_splice_init(&temp, &asoc->outqueue.out_chunk_list);
1011
1012			asoc->next_tsn = rtsn;
1013			asoc->ctsn_ack_point = asoc->next_tsn - 1;
1014			asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
1015
1016			for (i = 0; i < stream->outcnt; i++) {
1017				SCTP_SO(stream, i)->mid = 0;
1018				SCTP_SO(stream, i)->mid_uo = 0;
1019			}
1020			for (i = 0; i < stream->incnt; i++)
1021				SCTP_SI(stream, i)->mid = 0;
1022		}
1023
1024		for (i = 0; i < stream->outcnt; i++)
1025			SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
1026
1027		*evp = sctp_ulpevent_make_assoc_reset_event(asoc, flags,
1028			stsn, rtsn, GFP_ATOMIC);
1029	} else if (req->type == SCTP_PARAM_RESET_ADD_OUT_STREAMS) {
1030		struct sctp_strreset_addstrm *addstrm;
1031		__u16 number;
1032
1033		addstrm = (struct sctp_strreset_addstrm *)req;
1034		nums = ntohs(addstrm->number_of_streams);
1035		number = stream->outcnt - nums;
1036
1037		if (result == SCTP_STRRESET_PERFORMED)
1038			for (i = number; i < stream->outcnt; i++)
1039				SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
1040		else
 
1041			stream->outcnt = number;
 
1042
1043		*evp = sctp_ulpevent_make_stream_change_event(asoc, flags,
1044			0, nums, GFP_ATOMIC);
1045	} else if (req->type == SCTP_PARAM_RESET_ADD_IN_STREAMS) {
1046		struct sctp_strreset_addstrm *addstrm;
1047
1048		/* if the result is performed, it's impossible for addstrm in
1049		 * request.
1050		 */
1051		if (result == SCTP_STRRESET_PERFORMED)
1052			return NULL;
1053
1054		addstrm = (struct sctp_strreset_addstrm *)req;
1055		nums = ntohs(addstrm->number_of_streams);
1056
1057		*evp = sctp_ulpevent_make_stream_change_event(asoc, flags,
1058			nums, 0, GFP_ATOMIC);
1059	}
1060
1061	asoc->strreset_outstanding--;
1062	asoc->strreset_outseq++;
1063
1064	/* remove everything for this reconf request */
1065	if (!asoc->strreset_outstanding) {
1066		t = asoc->strreset_chunk->transport;
1067		if (del_timer(&t->reconf_timer))
1068			sctp_transport_put(t);
1069
1070		sctp_chunk_put(asoc->strreset_chunk);
1071		asoc->strreset_chunk = NULL;
1072	}
1073
1074	return NULL;
1075}
v6.13.7
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/* SCTP kernel implementation
   3 * (C) Copyright IBM Corp. 2001, 2004
   4 * Copyright (c) 1999-2000 Cisco, Inc.
   5 * Copyright (c) 1999-2001 Motorola, Inc.
   6 * Copyright (c) 2001 Intel Corp.
   7 *
   8 * This file is part of the SCTP kernel implementation
   9 *
  10 * This file contains sctp stream maniuplation primitives and helpers.
  11 *
  12 * Please send any bug reports or fixes you make to the
  13 * email address(es):
  14 *    lksctp developers <linux-sctp@vger.kernel.org>
  15 *
  16 * Written or modified by:
  17 *    Xin Long <lucien.xin@gmail.com>
  18 */
  19
  20#include <linux/list.h>
  21#include <net/sctp/sctp.h>
  22#include <net/sctp/sm.h>
  23#include <net/sctp/stream_sched.h>
  24
  25static void sctp_stream_shrink_out(struct sctp_stream *stream, __u16 outcnt)
 
 
 
 
 
  26{
  27	struct sctp_association *asoc;
  28	struct sctp_chunk *ch, *temp;
  29	struct sctp_outq *outq;
 
  30
  31	asoc = container_of(stream, struct sctp_association, stream);
  32	outq = &asoc->outqueue;
  33
  34	list_for_each_entry_safe(ch, temp, &outq->out_chunk_list, list) {
  35		__u16 sid = sctp_chunk_stream_no(ch);
  36
  37		if (sid < outcnt)
  38			continue;
  39
  40		sctp_sched_dequeue_common(outq, ch);
  41		/* No need to call dequeue_done here because
  42		 * the chunks are not scheduled by now.
  43		 */
  44
  45		/* Mark as failed send. */
  46		sctp_chunk_fail(ch, (__force __u32)SCTP_ERROR_INV_STRM);
  47		if (asoc->peer.prsctp_capable &&
  48		    SCTP_PR_PRIO_ENABLED(ch->sinfo.sinfo_flags))
  49			asoc->sent_cnt_removable--;
  50
  51		sctp_chunk_free(ch);
  52	}
  53}
  54
  55static void sctp_stream_free_ext(struct sctp_stream *stream, __u16 sid)
  56{
  57	struct sctp_sched_ops *sched;
  58
  59	if (!SCTP_SO(stream, sid)->ext)
  60		return;
  61
  62	sched = sctp_sched_ops_from_stream(stream);
  63	sched->free_sid(stream, sid);
  64	kfree(SCTP_SO(stream, sid)->ext);
  65	SCTP_SO(stream, sid)->ext = NULL;
  66}
  67
  68/* Migrates chunks from stream queues to new stream queues if needed,
  69 * but not across associations. Also, removes those chunks to streams
  70 * higher than the new max.
  71 */
  72static void sctp_stream_outq_migrate(struct sctp_stream *stream,
  73				     struct sctp_stream *new, __u16 outcnt)
  74{
  75	int i;
  76
  77	if (stream->outcnt > outcnt)
  78		sctp_stream_shrink_out(stream, outcnt);
  79
  80	if (new) {
  81		/* Here we actually move the old ext stuff into the new
  82		 * buffer, because we want to keep it. Then
  83		 * sctp_stream_update will swap ->out pointers.
  84		 */
  85		for (i = 0; i < outcnt; i++) {
  86			sctp_stream_free_ext(new, i);
  87			SCTP_SO(new, i)->ext = SCTP_SO(stream, i)->ext;
  88			SCTP_SO(stream, i)->ext = NULL;
  89		}
  90	}
  91
  92	for (i = outcnt; i < stream->outcnt; i++)
  93		sctp_stream_free_ext(stream, i);
 
 
  94}
  95
  96static int sctp_stream_alloc_out(struct sctp_stream *stream, __u16 outcnt,
  97				 gfp_t gfp)
  98{
  99	int ret;
 100
 101	if (outcnt <= stream->outcnt)
 102		goto out;
 103
 104	ret = genradix_prealloc(&stream->out, outcnt, gfp);
 105	if (ret)
 106		return ret;
 107
 108out:
 109	stream->outcnt = outcnt;
 110	return 0;
 111}
 112
 113static int sctp_stream_alloc_in(struct sctp_stream *stream, __u16 incnt,
 114				gfp_t gfp)
 115{
 116	int ret;
 117
 118	if (incnt <= stream->incnt)
 119		goto out;
 120
 121	ret = genradix_prealloc(&stream->in, incnt, gfp);
 122	if (ret)
 123		return ret;
 124
 125out:
 126	stream->incnt = incnt;
 127	return 0;
 128}
 129
 130int sctp_stream_init(struct sctp_stream *stream, __u16 outcnt, __u16 incnt,
 131		     gfp_t gfp)
 132{
 133	struct sctp_sched_ops *sched = sctp_sched_ops_from_stream(stream);
 134	int i, ret = 0;
 135
 136	gfp |= __GFP_NOWARN;
 137
 138	/* Initial stream->out size may be very big, so free it and alloc
 139	 * a new one with new outcnt to save memory if needed.
 140	 */
 141	if (outcnt == stream->outcnt)
 142		goto handle_in;
 143
 144	/* Filter out chunks queued on streams that won't exist anymore */
 145	sched->unsched_all(stream);
 146	sctp_stream_outq_migrate(stream, NULL, outcnt);
 147	sched->sched_all(stream);
 148
 149	ret = sctp_stream_alloc_out(stream, outcnt, gfp);
 150	if (ret)
 151		return ret;
 152
 153	for (i = 0; i < stream->outcnt; i++)
 154		SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
 155
 156handle_in:
 157	sctp_stream_interleave_init(stream);
 158	if (!incnt)
 159		return 0;
 
 
 
 
 
 
 
 
 160
 161	return sctp_stream_alloc_in(stream, incnt, gfp);
 
 162}
 163
 164int sctp_stream_init_ext(struct sctp_stream *stream, __u16 sid)
 165{
 166	struct sctp_stream_out_ext *soute;
 167	int ret;
 168
 169	soute = kzalloc(sizeof(*soute), GFP_KERNEL);
 170	if (!soute)
 171		return -ENOMEM;
 172	SCTP_SO(stream, sid)->ext = soute;
 173
 174	ret = sctp_sched_init_sid(stream, sid, GFP_KERNEL);
 175	if (ret) {
 176		kfree(SCTP_SO(stream, sid)->ext);
 177		SCTP_SO(stream, sid)->ext = NULL;
 178	}
 179
 180	return ret;
 181}
 182
 183void sctp_stream_free(struct sctp_stream *stream)
 184{
 185	struct sctp_sched_ops *sched = sctp_sched_ops_from_stream(stream);
 186	int i;
 187
 188	sched->unsched_all(stream);
 189	for (i = 0; i < stream->outcnt; i++)
 190		sctp_stream_free_ext(stream, i);
 191	genradix_free(&stream->out);
 192	genradix_free(&stream->in);
 193}
 194
 195void sctp_stream_clear(struct sctp_stream *stream)
 196{
 197	int i;
 198
 199	for (i = 0; i < stream->outcnt; i++) {
 200		SCTP_SO(stream, i)->mid = 0;
 201		SCTP_SO(stream, i)->mid_uo = 0;
 202	}
 203
 204	for (i = 0; i < stream->incnt; i++)
 205		SCTP_SI(stream, i)->mid = 0;
 206}
 207
 208void sctp_stream_update(struct sctp_stream *stream, struct sctp_stream *new)
 209{
 210	struct sctp_sched_ops *sched = sctp_sched_ops_from_stream(stream);
 211
 212	sched->unsched_all(stream);
 213	sctp_stream_outq_migrate(stream, new, new->outcnt);
 214	sctp_stream_free(stream);
 215
 216	stream->out = new->out;
 217	stream->in  = new->in;
 218	stream->outcnt = new->outcnt;
 219	stream->incnt  = new->incnt;
 220
 221	sched->sched_all(stream);
 222
 223	new->out.tree.root = NULL;
 224	new->in.tree.root  = NULL;
 225	new->outcnt = 0;
 226	new->incnt  = 0;
 227}
 228
 229static int sctp_send_reconf(struct sctp_association *asoc,
 230			    struct sctp_chunk *chunk)
 231{
 
 232	int retval = 0;
 233
 234	retval = sctp_primitive_RECONF(asoc->base.net, asoc, chunk);
 235	if (retval)
 236		sctp_chunk_free(chunk);
 237
 238	return retval;
 239}
 240
 241static bool sctp_stream_outq_is_empty(struct sctp_stream *stream,
 242				      __u16 str_nums, __be16 *str_list)
 243{
 244	struct sctp_association *asoc;
 245	__u16 i;
 246
 247	asoc = container_of(stream, struct sctp_association, stream);
 248	if (!asoc->outqueue.out_qlen)
 249		return true;
 250
 251	if (!str_nums)
 252		return false;
 253
 254	for (i = 0; i < str_nums; i++) {
 255		__u16 sid = ntohs(str_list[i]);
 256
 257		if (SCTP_SO(stream, sid)->ext &&
 258		    !list_empty(&SCTP_SO(stream, sid)->ext->outq))
 259			return false;
 260	}
 261
 262	return true;
 263}
 264
 265int sctp_send_reset_streams(struct sctp_association *asoc,
 266			    struct sctp_reset_streams *params)
 267{
 268	struct sctp_stream *stream = &asoc->stream;
 269	__u16 i, str_nums, *str_list;
 270	struct sctp_chunk *chunk;
 271	int retval = -EINVAL;
 272	__be16 *nstr_list;
 273	bool out, in;
 274
 275	if (!asoc->peer.reconf_capable ||
 276	    !(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ)) {
 277		retval = -ENOPROTOOPT;
 278		goto out;
 279	}
 280
 281	if (asoc->strreset_outstanding) {
 282		retval = -EINPROGRESS;
 283		goto out;
 284	}
 285
 286	out = params->srs_flags & SCTP_STREAM_RESET_OUTGOING;
 287	in  = params->srs_flags & SCTP_STREAM_RESET_INCOMING;
 288	if (!out && !in)
 289		goto out;
 290
 291	str_nums = params->srs_number_streams;
 292	str_list = params->srs_stream_list;
 293	if (str_nums) {
 294		int param_len = 0;
 295
 296		if (out) {
 297			for (i = 0; i < str_nums; i++)
 298				if (str_list[i] >= stream->outcnt)
 299					goto out;
 300
 301			param_len = str_nums * sizeof(__u16) +
 302				    sizeof(struct sctp_strreset_outreq);
 303		}
 304
 305		if (in) {
 306			for (i = 0; i < str_nums; i++)
 307				if (str_list[i] >= stream->incnt)
 308					goto out;
 309
 310			param_len += str_nums * sizeof(__u16) +
 311				     sizeof(struct sctp_strreset_inreq);
 312		}
 313
 314		if (param_len > SCTP_MAX_CHUNK_LEN -
 315				sizeof(struct sctp_reconf_chunk))
 316			goto out;
 317	}
 318
 319	nstr_list = kcalloc(str_nums, sizeof(__be16), GFP_KERNEL);
 320	if (!nstr_list) {
 321		retval = -ENOMEM;
 322		goto out;
 323	}
 324
 325	for (i = 0; i < str_nums; i++)
 326		nstr_list[i] = htons(str_list[i]);
 327
 328	if (out && !sctp_stream_outq_is_empty(stream, str_nums, nstr_list)) {
 329		kfree(nstr_list);
 330		retval = -EAGAIN;
 331		goto out;
 332	}
 333
 334	chunk = sctp_make_strreset_req(asoc, str_nums, nstr_list, out, in);
 335
 336	kfree(nstr_list);
 337
 338	if (!chunk) {
 339		retval = -ENOMEM;
 340		goto out;
 341	}
 342
 343	if (out) {
 344		if (str_nums)
 345			for (i = 0; i < str_nums; i++)
 346				SCTP_SO(stream, str_list[i])->state =
 347						       SCTP_STREAM_CLOSED;
 348		else
 349			for (i = 0; i < stream->outcnt; i++)
 350				SCTP_SO(stream, i)->state = SCTP_STREAM_CLOSED;
 351	}
 352
 353	asoc->strreset_chunk = chunk;
 354	sctp_chunk_hold(asoc->strreset_chunk);
 355
 356	retval = sctp_send_reconf(asoc, chunk);
 357	if (retval) {
 358		sctp_chunk_put(asoc->strreset_chunk);
 359		asoc->strreset_chunk = NULL;
 360		if (!out)
 361			goto out;
 362
 363		if (str_nums)
 364			for (i = 0; i < str_nums; i++)
 365				SCTP_SO(stream, str_list[i])->state =
 366						       SCTP_STREAM_OPEN;
 367		else
 368			for (i = 0; i < stream->outcnt; i++)
 369				SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
 370
 371		goto out;
 372	}
 373
 374	asoc->strreset_outstanding = out + in;
 375
 376out:
 377	return retval;
 378}
 379
 380int sctp_send_reset_assoc(struct sctp_association *asoc)
 381{
 382	struct sctp_stream *stream = &asoc->stream;
 383	struct sctp_chunk *chunk = NULL;
 384	int retval;
 385	__u16 i;
 386
 387	if (!asoc->peer.reconf_capable ||
 388	    !(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ))
 389		return -ENOPROTOOPT;
 390
 391	if (asoc->strreset_outstanding)
 392		return -EINPROGRESS;
 393
 394	if (!sctp_outq_is_empty(&asoc->outqueue))
 395		return -EAGAIN;
 396
 397	chunk = sctp_make_strreset_tsnreq(asoc);
 398	if (!chunk)
 399		return -ENOMEM;
 400
 401	/* Block further xmit of data until this request is completed */
 402	for (i = 0; i < stream->outcnt; i++)
 403		SCTP_SO(stream, i)->state = SCTP_STREAM_CLOSED;
 404
 405	asoc->strreset_chunk = chunk;
 406	sctp_chunk_hold(asoc->strreset_chunk);
 407
 408	retval = sctp_send_reconf(asoc, chunk);
 409	if (retval) {
 410		sctp_chunk_put(asoc->strreset_chunk);
 411		asoc->strreset_chunk = NULL;
 412
 413		for (i = 0; i < stream->outcnt; i++)
 414			SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
 415
 416		return retval;
 417	}
 418
 419	asoc->strreset_outstanding = 1;
 420
 421	return 0;
 422}
 423
 424int sctp_send_add_streams(struct sctp_association *asoc,
 425			  struct sctp_add_streams *params)
 426{
 427	struct sctp_stream *stream = &asoc->stream;
 428	struct sctp_chunk *chunk = NULL;
 429	int retval;
 430	__u32 outcnt, incnt;
 431	__u16 out, in;
 432
 433	if (!asoc->peer.reconf_capable ||
 434	    !(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ)) {
 435		retval = -ENOPROTOOPT;
 436		goto out;
 437	}
 438
 439	if (asoc->strreset_outstanding) {
 440		retval = -EINPROGRESS;
 441		goto out;
 442	}
 443
 444	out = params->sas_outstrms;
 445	in  = params->sas_instrms;
 446	outcnt = stream->outcnt + out;
 447	incnt = stream->incnt + in;
 448	if (outcnt > SCTP_MAX_STREAM || incnt > SCTP_MAX_STREAM ||
 449	    (!out && !in)) {
 450		retval = -EINVAL;
 451		goto out;
 452	}
 453
 454	if (out) {
 455		retval = sctp_stream_alloc_out(stream, outcnt, GFP_KERNEL);
 456		if (retval)
 457			goto out;
 458	}
 459
 460	chunk = sctp_make_strreset_addstrm(asoc, out, in);
 461	if (!chunk) {
 462		retval = -ENOMEM;
 463		goto out;
 464	}
 465
 466	asoc->strreset_chunk = chunk;
 467	sctp_chunk_hold(asoc->strreset_chunk);
 468
 469	retval = sctp_send_reconf(asoc, chunk);
 470	if (retval) {
 471		sctp_chunk_put(asoc->strreset_chunk);
 472		asoc->strreset_chunk = NULL;
 473		goto out;
 474	}
 475
 476	asoc->strreset_outstanding = !!out + !!in;
 477
 478out:
 479	return retval;
 480}
 481
 482static struct sctp_paramhdr *sctp_chunk_lookup_strreset_param(
 483			struct sctp_association *asoc, __be32 resp_seq,
 484			__be16 type)
 485{
 486	struct sctp_chunk *chunk = asoc->strreset_chunk;
 487	struct sctp_reconf_chunk *hdr;
 488	union sctp_params param;
 489
 490	if (!chunk)
 491		return NULL;
 492
 493	hdr = (struct sctp_reconf_chunk *)chunk->chunk_hdr;
 494	sctp_walk_params(param, hdr) {
 495		/* sctp_strreset_tsnreq is actually the basic structure
 496		 * of all stream reconf params, so it's safe to use it
 497		 * to access request_seq.
 498		 */
 499		struct sctp_strreset_tsnreq *req = param.v;
 500
 501		if ((!resp_seq || req->request_seq == resp_seq) &&
 502		    (!type || type == req->param_hdr.type))
 503			return param.v;
 504	}
 505
 506	return NULL;
 507}
 508
 509static void sctp_update_strreset_result(struct sctp_association *asoc,
 510					__u32 result)
 511{
 512	asoc->strreset_result[1] = asoc->strreset_result[0];
 513	asoc->strreset_result[0] = result;
 514}
 515
 516struct sctp_chunk *sctp_process_strreset_outreq(
 517				struct sctp_association *asoc,
 518				union sctp_params param,
 519				struct sctp_ulpevent **evp)
 520{
 521	struct sctp_strreset_outreq *outreq = param.v;
 522	struct sctp_stream *stream = &asoc->stream;
 523	__u32 result = SCTP_STRRESET_DENIED;
 524	__be16 *str_p = NULL;
 525	__u32 request_seq;
 526	__u16 i, nums;
 527
 528	request_seq = ntohl(outreq->request_seq);
 529
 530	if (ntohl(outreq->send_reset_at_tsn) >
 531	    sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map)) {
 532		result = SCTP_STRRESET_IN_PROGRESS;
 533		goto err;
 534	}
 535
 536	if (TSN_lt(asoc->strreset_inseq, request_seq) ||
 537	    TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
 538		result = SCTP_STRRESET_ERR_BAD_SEQNO;
 539		goto err;
 540	} else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
 541		i = asoc->strreset_inseq - request_seq - 1;
 542		result = asoc->strreset_result[i];
 543		goto err;
 544	}
 545	asoc->strreset_inseq++;
 546
 547	/* Check strreset_enable after inseq inc, as sender cannot tell
 548	 * the peer doesn't enable strreset after receiving response with
 549	 * result denied, as well as to keep consistent with bsd.
 550	 */
 551	if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ))
 552		goto out;
 553
 554	nums = (ntohs(param.p->length) - sizeof(*outreq)) / sizeof(__u16);
 555	str_p = outreq->list_of_streams;
 556	for (i = 0; i < nums; i++) {
 557		if (ntohs(str_p[i]) >= stream->incnt) {
 558			result = SCTP_STRRESET_ERR_WRONG_SSN;
 559			goto out;
 560		}
 561	}
 562
 563	if (asoc->strreset_chunk) {
 564		if (!sctp_chunk_lookup_strreset_param(
 565				asoc, outreq->response_seq,
 566				SCTP_PARAM_RESET_IN_REQUEST)) {
 567			/* same process with outstanding isn't 0 */
 568			result = SCTP_STRRESET_ERR_IN_PROGRESS;
 569			goto out;
 570		}
 571
 572		asoc->strreset_outstanding--;
 573		asoc->strreset_outseq++;
 574
 575		if (!asoc->strreset_outstanding) {
 576			struct sctp_transport *t;
 577
 578			t = asoc->strreset_chunk->transport;
 579			if (del_timer(&t->reconf_timer))
 580				sctp_transport_put(t);
 581
 582			sctp_chunk_put(asoc->strreset_chunk);
 583			asoc->strreset_chunk = NULL;
 584		}
 585	}
 586
 587	if (nums)
 588		for (i = 0; i < nums; i++)
 589			SCTP_SI(stream, ntohs(str_p[i]))->mid = 0;
 590	else
 591		for (i = 0; i < stream->incnt; i++)
 592			SCTP_SI(stream, i)->mid = 0;
 593
 594	result = SCTP_STRRESET_PERFORMED;
 595
 596	*evp = sctp_ulpevent_make_stream_reset_event(asoc,
 597		SCTP_STREAM_RESET_INCOMING_SSN, nums, str_p, GFP_ATOMIC);
 598
 599out:
 600	sctp_update_strreset_result(asoc, result);
 601err:
 602	return sctp_make_strreset_resp(asoc, result, request_seq);
 603}
 604
 605struct sctp_chunk *sctp_process_strreset_inreq(
 606				struct sctp_association *asoc,
 607				union sctp_params param,
 608				struct sctp_ulpevent **evp)
 609{
 610	struct sctp_strreset_inreq *inreq = param.v;
 611	struct sctp_stream *stream = &asoc->stream;
 612	__u32 result = SCTP_STRRESET_DENIED;
 613	struct sctp_chunk *chunk = NULL;
 614	__u32 request_seq;
 615	__u16 i, nums;
 616	__be16 *str_p;
 617
 618	request_seq = ntohl(inreq->request_seq);
 619	if (TSN_lt(asoc->strreset_inseq, request_seq) ||
 620	    TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
 621		result = SCTP_STRRESET_ERR_BAD_SEQNO;
 622		goto err;
 623	} else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
 624		i = asoc->strreset_inseq - request_seq - 1;
 625		result = asoc->strreset_result[i];
 626		if (result == SCTP_STRRESET_PERFORMED)
 627			return NULL;
 628		goto err;
 629	}
 630	asoc->strreset_inseq++;
 631
 632	if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ))
 633		goto out;
 634
 635	if (asoc->strreset_outstanding) {
 636		result = SCTP_STRRESET_ERR_IN_PROGRESS;
 637		goto out;
 638	}
 639
 640	nums = (ntohs(param.p->length) - sizeof(*inreq)) / sizeof(__u16);
 641	str_p = inreq->list_of_streams;
 642	for (i = 0; i < nums; i++) {
 643		if (ntohs(str_p[i]) >= stream->outcnt) {
 644			result = SCTP_STRRESET_ERR_WRONG_SSN;
 645			goto out;
 646		}
 647	}
 648
 649	if (!sctp_stream_outq_is_empty(stream, nums, str_p)) {
 650		result = SCTP_STRRESET_IN_PROGRESS;
 651		asoc->strreset_inseq--;
 652		goto err;
 653	}
 654
 655	chunk = sctp_make_strreset_req(asoc, nums, str_p, 1, 0);
 656	if (!chunk)
 657		goto out;
 658
 659	if (nums)
 660		for (i = 0; i < nums; i++)
 661			SCTP_SO(stream, ntohs(str_p[i]))->state =
 662					       SCTP_STREAM_CLOSED;
 663	else
 664		for (i = 0; i < stream->outcnt; i++)
 665			SCTP_SO(stream, i)->state = SCTP_STREAM_CLOSED;
 666
 667	asoc->strreset_chunk = chunk;
 668	asoc->strreset_outstanding = 1;
 669	sctp_chunk_hold(asoc->strreset_chunk);
 670
 671	result = SCTP_STRRESET_PERFORMED;
 672
 673out:
 674	sctp_update_strreset_result(asoc, result);
 675err:
 676	if (!chunk)
 677		chunk =  sctp_make_strreset_resp(asoc, result, request_seq);
 678
 679	return chunk;
 680}
 681
 682struct sctp_chunk *sctp_process_strreset_tsnreq(
 683				struct sctp_association *asoc,
 684				union sctp_params param,
 685				struct sctp_ulpevent **evp)
 686{
 687	__u32 init_tsn = 0, next_tsn = 0, max_tsn_seen;
 688	struct sctp_strreset_tsnreq *tsnreq = param.v;
 689	struct sctp_stream *stream = &asoc->stream;
 690	__u32 result = SCTP_STRRESET_DENIED;
 691	__u32 request_seq;
 692	__u16 i;
 693
 694	request_seq = ntohl(tsnreq->request_seq);
 695	if (TSN_lt(asoc->strreset_inseq, request_seq) ||
 696	    TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
 697		result = SCTP_STRRESET_ERR_BAD_SEQNO;
 698		goto err;
 699	} else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
 700		i = asoc->strreset_inseq - request_seq - 1;
 701		result = asoc->strreset_result[i];
 702		if (result == SCTP_STRRESET_PERFORMED) {
 703			next_tsn = asoc->ctsn_ack_point + 1;
 704			init_tsn =
 705				sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + 1;
 706		}
 707		goto err;
 708	}
 709
 710	if (!sctp_outq_is_empty(&asoc->outqueue)) {
 711		result = SCTP_STRRESET_IN_PROGRESS;
 712		goto err;
 713	}
 714
 715	asoc->strreset_inseq++;
 716
 717	if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ))
 718		goto out;
 719
 720	if (asoc->strreset_outstanding) {
 721		result = SCTP_STRRESET_ERR_IN_PROGRESS;
 722		goto out;
 723	}
 724
 725	/* G4: The same processing as though a FWD-TSN chunk (as defined in
 726	 *     [RFC3758]) with all streams affected and a new cumulative TSN
 727	 *     ACK of the Receiver's Next TSN minus 1 were received MUST be
 728	 *     performed.
 729	 */
 730	max_tsn_seen = sctp_tsnmap_get_max_tsn_seen(&asoc->peer.tsn_map);
 731	asoc->stream.si->report_ftsn(&asoc->ulpq, max_tsn_seen);
 732
 733	/* G1: Compute an appropriate value for the Receiver's Next TSN -- the
 734	 *     TSN that the peer should use to send the next DATA chunk.  The
 735	 *     value SHOULD be the smallest TSN not acknowledged by the
 736	 *     receiver of the request plus 2^31.
 737	 */
 738	init_tsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + (1 << 31);
 739	sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL,
 740			 init_tsn, GFP_ATOMIC);
 741
 742	/* G3: The same processing as though a SACK chunk with no gap report
 743	 *     and a cumulative TSN ACK of the Sender's Next TSN minus 1 were
 744	 *     received MUST be performed.
 745	 */
 746	sctp_outq_free(&asoc->outqueue);
 747
 748	/* G2: Compute an appropriate value for the local endpoint's next TSN,
 749	 *     i.e., the next TSN assigned by the receiver of the SSN/TSN reset
 750	 *     chunk.  The value SHOULD be the highest TSN sent by the receiver
 751	 *     of the request plus 1.
 752	 */
 753	next_tsn = asoc->next_tsn;
 754	asoc->ctsn_ack_point = next_tsn - 1;
 755	asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
 756
 757	/* G5:  The next expected and outgoing SSNs MUST be reset to 0 for all
 758	 *      incoming and outgoing streams.
 759	 */
 760	for (i = 0; i < stream->outcnt; i++) {
 761		SCTP_SO(stream, i)->mid = 0;
 762		SCTP_SO(stream, i)->mid_uo = 0;
 763	}
 764	for (i = 0; i < stream->incnt; i++)
 765		SCTP_SI(stream, i)->mid = 0;
 766
 767	result = SCTP_STRRESET_PERFORMED;
 768
 769	*evp = sctp_ulpevent_make_assoc_reset_event(asoc, 0, init_tsn,
 770						    next_tsn, GFP_ATOMIC);
 771
 772out:
 773	sctp_update_strreset_result(asoc, result);
 774err:
 775	return sctp_make_strreset_tsnresp(asoc, result, request_seq,
 776					  next_tsn, init_tsn);
 777}
 778
 779struct sctp_chunk *sctp_process_strreset_addstrm_out(
 780				struct sctp_association *asoc,
 781				union sctp_params param,
 782				struct sctp_ulpevent **evp)
 783{
 784	struct sctp_strreset_addstrm *addstrm = param.v;
 785	struct sctp_stream *stream = &asoc->stream;
 786	__u32 result = SCTP_STRRESET_DENIED;
 787	__u32 request_seq, incnt;
 788	__u16 in, i;
 789
 790	request_seq = ntohl(addstrm->request_seq);
 791	if (TSN_lt(asoc->strreset_inseq, request_seq) ||
 792	    TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
 793		result = SCTP_STRRESET_ERR_BAD_SEQNO;
 794		goto err;
 795	} else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
 796		i = asoc->strreset_inseq - request_seq - 1;
 797		result = asoc->strreset_result[i];
 798		goto err;
 799	}
 800	asoc->strreset_inseq++;
 801
 802	if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ))
 803		goto out;
 804
 805	in = ntohs(addstrm->number_of_streams);
 806	incnt = stream->incnt + in;
 807	if (!in || incnt > SCTP_MAX_STREAM)
 808		goto out;
 809
 810	if (sctp_stream_alloc_in(stream, incnt, GFP_ATOMIC))
 811		goto out;
 812
 813	if (asoc->strreset_chunk) {
 814		if (!sctp_chunk_lookup_strreset_param(
 815			asoc, 0, SCTP_PARAM_RESET_ADD_IN_STREAMS)) {
 816			/* same process with outstanding isn't 0 */
 817			result = SCTP_STRRESET_ERR_IN_PROGRESS;
 818			goto out;
 819		}
 820
 821		asoc->strreset_outstanding--;
 822		asoc->strreset_outseq++;
 823
 824		if (!asoc->strreset_outstanding) {
 825			struct sctp_transport *t;
 826
 827			t = asoc->strreset_chunk->transport;
 828			if (del_timer(&t->reconf_timer))
 829				sctp_transport_put(t);
 830
 831			sctp_chunk_put(asoc->strreset_chunk);
 832			asoc->strreset_chunk = NULL;
 833		}
 834	}
 835
 836	stream->incnt = incnt;
 837
 838	result = SCTP_STRRESET_PERFORMED;
 839
 840	*evp = sctp_ulpevent_make_stream_change_event(asoc,
 841		0, ntohs(addstrm->number_of_streams), 0, GFP_ATOMIC);
 842
 843out:
 844	sctp_update_strreset_result(asoc, result);
 845err:
 846	return sctp_make_strreset_resp(asoc, result, request_seq);
 847}
 848
 849struct sctp_chunk *sctp_process_strreset_addstrm_in(
 850				struct sctp_association *asoc,
 851				union sctp_params param,
 852				struct sctp_ulpevent **evp)
 853{
 854	struct sctp_strreset_addstrm *addstrm = param.v;
 855	struct sctp_stream *stream = &asoc->stream;
 856	__u32 result = SCTP_STRRESET_DENIED;
 857	struct sctp_chunk *chunk = NULL;
 858	__u32 request_seq, outcnt;
 859	__u16 out, i;
 860	int ret;
 861
 862	request_seq = ntohl(addstrm->request_seq);
 863	if (TSN_lt(asoc->strreset_inseq, request_seq) ||
 864	    TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
 865		result = SCTP_STRRESET_ERR_BAD_SEQNO;
 866		goto err;
 867	} else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
 868		i = asoc->strreset_inseq - request_seq - 1;
 869		result = asoc->strreset_result[i];
 870		if (result == SCTP_STRRESET_PERFORMED)
 871			return NULL;
 872		goto err;
 873	}
 874	asoc->strreset_inseq++;
 875
 876	if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ))
 877		goto out;
 878
 879	if (asoc->strreset_outstanding) {
 880		result = SCTP_STRRESET_ERR_IN_PROGRESS;
 881		goto out;
 882	}
 883
 884	out = ntohs(addstrm->number_of_streams);
 885	outcnt = stream->outcnt + out;
 886	if (!out || outcnt > SCTP_MAX_STREAM)
 887		goto out;
 888
 889	ret = sctp_stream_alloc_out(stream, outcnt, GFP_ATOMIC);
 890	if (ret)
 891		goto out;
 892
 893	chunk = sctp_make_strreset_addstrm(asoc, out, 0);
 894	if (!chunk)
 895		goto out;
 896
 897	asoc->strreset_chunk = chunk;
 898	asoc->strreset_outstanding = 1;
 899	sctp_chunk_hold(asoc->strreset_chunk);
 900
 901	stream->outcnt = outcnt;
 902
 903	result = SCTP_STRRESET_PERFORMED;
 904
 905out:
 906	sctp_update_strreset_result(asoc, result);
 907err:
 908	if (!chunk)
 909		chunk = sctp_make_strreset_resp(asoc, result, request_seq);
 910
 911	return chunk;
 912}
 913
 914struct sctp_chunk *sctp_process_strreset_resp(
 915				struct sctp_association *asoc,
 916				union sctp_params param,
 917				struct sctp_ulpevent **evp)
 918{
 919	struct sctp_stream *stream = &asoc->stream;
 920	struct sctp_strreset_resp *resp = param.v;
 921	struct sctp_transport *t;
 922	__u16 i, nums, flags = 0;
 923	struct sctp_paramhdr *req;
 924	__u32 result;
 925
 926	req = sctp_chunk_lookup_strreset_param(asoc, resp->response_seq, 0);
 927	if (!req)
 928		return NULL;
 929
 930	result = ntohl(resp->result);
 931	if (result != SCTP_STRRESET_PERFORMED) {
 932		/* if in progress, do nothing but retransmit */
 933		if (result == SCTP_STRRESET_IN_PROGRESS)
 934			return NULL;
 935		else if (result == SCTP_STRRESET_DENIED)
 936			flags = SCTP_STREAM_RESET_DENIED;
 937		else
 938			flags = SCTP_STREAM_RESET_FAILED;
 939	}
 940
 941	if (req->type == SCTP_PARAM_RESET_OUT_REQUEST) {
 942		struct sctp_strreset_outreq *outreq;
 943		__be16 *str_p;
 944
 945		outreq = (struct sctp_strreset_outreq *)req;
 946		str_p = outreq->list_of_streams;
 947		nums = (ntohs(outreq->param_hdr.length) - sizeof(*outreq)) /
 948		       sizeof(__u16);
 949
 950		if (result == SCTP_STRRESET_PERFORMED) {
 951			struct sctp_stream_out *sout;
 952			if (nums) {
 953				for (i = 0; i < nums; i++) {
 954					sout = SCTP_SO(stream, ntohs(str_p[i]));
 955					sout->mid = 0;
 956					sout->mid_uo = 0;
 957				}
 958			} else {
 959				for (i = 0; i < stream->outcnt; i++) {
 960					sout = SCTP_SO(stream, i);
 961					sout->mid = 0;
 962					sout->mid_uo = 0;
 963				}
 964			}
 965		}
 966
 967		flags |= SCTP_STREAM_RESET_OUTGOING_SSN;
 968
 969		for (i = 0; i < stream->outcnt; i++)
 970			SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
 971
 972		*evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
 973			nums, str_p, GFP_ATOMIC);
 974	} else if (req->type == SCTP_PARAM_RESET_IN_REQUEST) {
 975		struct sctp_strreset_inreq *inreq;
 976		__be16 *str_p;
 977
 978		/* if the result is performed, it's impossible for inreq */
 979		if (result == SCTP_STRRESET_PERFORMED)
 980			return NULL;
 981
 982		inreq = (struct sctp_strreset_inreq *)req;
 983		str_p = inreq->list_of_streams;
 984		nums = (ntohs(inreq->param_hdr.length) - sizeof(*inreq)) /
 985		       sizeof(__u16);
 986
 987		flags |= SCTP_STREAM_RESET_INCOMING_SSN;
 988
 989		*evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
 990			nums, str_p, GFP_ATOMIC);
 991	} else if (req->type == SCTP_PARAM_RESET_TSN_REQUEST) {
 992		struct sctp_strreset_resptsn *resptsn;
 993		__u32 stsn, rtsn;
 994
 995		/* check for resptsn, as sctp_verify_reconf didn't do it*/
 996		if (ntohs(param.p->length) != sizeof(*resptsn))
 997			return NULL;
 998
 999		resptsn = (struct sctp_strreset_resptsn *)resp;
1000		stsn = ntohl(resptsn->senders_next_tsn);
1001		rtsn = ntohl(resptsn->receivers_next_tsn);
1002
1003		if (result == SCTP_STRRESET_PERFORMED) {
1004			__u32 mtsn = sctp_tsnmap_get_max_tsn_seen(
1005						&asoc->peer.tsn_map);
1006			LIST_HEAD(temp);
1007
1008			asoc->stream.si->report_ftsn(&asoc->ulpq, mtsn);
1009
1010			sctp_tsnmap_init(&asoc->peer.tsn_map,
1011					 SCTP_TSN_MAP_INITIAL,
1012					 stsn, GFP_ATOMIC);
1013
1014			/* Clean up sacked and abandoned queues only. As the
1015			 * out_chunk_list may not be empty, splice it to temp,
1016			 * then get it back after sctp_outq_free is done.
1017			 */
1018			list_splice_init(&asoc->outqueue.out_chunk_list, &temp);
1019			sctp_outq_free(&asoc->outqueue);
1020			list_splice_init(&temp, &asoc->outqueue.out_chunk_list);
1021
1022			asoc->next_tsn = rtsn;
1023			asoc->ctsn_ack_point = asoc->next_tsn - 1;
1024			asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
1025
1026			for (i = 0; i < stream->outcnt; i++) {
1027				SCTP_SO(stream, i)->mid = 0;
1028				SCTP_SO(stream, i)->mid_uo = 0;
1029			}
1030			for (i = 0; i < stream->incnt; i++)
1031				SCTP_SI(stream, i)->mid = 0;
1032		}
1033
1034		for (i = 0; i < stream->outcnt; i++)
1035			SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
1036
1037		*evp = sctp_ulpevent_make_assoc_reset_event(asoc, flags,
1038			stsn, rtsn, GFP_ATOMIC);
1039	} else if (req->type == SCTP_PARAM_RESET_ADD_OUT_STREAMS) {
1040		struct sctp_strreset_addstrm *addstrm;
1041		__u16 number;
1042
1043		addstrm = (struct sctp_strreset_addstrm *)req;
1044		nums = ntohs(addstrm->number_of_streams);
1045		number = stream->outcnt - nums;
1046
1047		if (result == SCTP_STRRESET_PERFORMED) {
1048			for (i = number; i < stream->outcnt; i++)
1049				SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
1050		} else {
1051			sctp_stream_shrink_out(stream, number);
1052			stream->outcnt = number;
1053		}
1054
1055		*evp = sctp_ulpevent_make_stream_change_event(asoc, flags,
1056			0, nums, GFP_ATOMIC);
1057	} else if (req->type == SCTP_PARAM_RESET_ADD_IN_STREAMS) {
1058		struct sctp_strreset_addstrm *addstrm;
1059
1060		/* if the result is performed, it's impossible for addstrm in
1061		 * request.
1062		 */
1063		if (result == SCTP_STRRESET_PERFORMED)
1064			return NULL;
1065
1066		addstrm = (struct sctp_strreset_addstrm *)req;
1067		nums = ntohs(addstrm->number_of_streams);
1068
1069		*evp = sctp_ulpevent_make_stream_change_event(asoc, flags,
1070			nums, 0, GFP_ATOMIC);
1071	}
1072
1073	asoc->strreset_outstanding--;
1074	asoc->strreset_outseq++;
1075
1076	/* remove everything for this reconf request */
1077	if (!asoc->strreset_outstanding) {
1078		t = asoc->strreset_chunk->transport;
1079		if (del_timer(&t->reconf_timer))
1080			sctp_transport_put(t);
1081
1082		sctp_chunk_put(asoc->strreset_chunk);
1083		asoc->strreset_chunk = NULL;
1084	}
1085
1086	return NULL;
1087}