Linux Audio

Check our new training course

Yocto / OpenEmbedded training

Mar 24-27, 2025, special US time zones
Register
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
  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, params) {
 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}