cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

stream.c (27131B)


      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}