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