Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
   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}