1a8386317SXin Long /* SCTP kernel implementation 2a8386317SXin Long * (C) Copyright IBM Corp. 2001, 2004 3a8386317SXin Long * Copyright (c) 1999-2000 Cisco, Inc. 4a8386317SXin Long * Copyright (c) 1999-2001 Motorola, Inc. 5a8386317SXin Long * Copyright (c) 2001 Intel Corp. 6a8386317SXin Long * 7a8386317SXin Long * This file is part of the SCTP kernel implementation 8a8386317SXin Long * 9a8386317SXin Long * These functions manipulate sctp tsn mapping array. 10a8386317SXin Long * 11a8386317SXin Long * This SCTP implementation is free software; 12a8386317SXin Long * you can redistribute it and/or modify it under the terms of 13a8386317SXin Long * the GNU General Public License as published by 14a8386317SXin Long * the Free Software Foundation; either version 2, or (at your option) 15a8386317SXin Long * any later version. 16a8386317SXin Long * 17a8386317SXin Long * This SCTP implementation is distributed in the hope that it 18a8386317SXin Long * will be useful, but WITHOUT ANY WARRANTY; without even the implied 19a8386317SXin Long * ************************ 20a8386317SXin Long * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 21a8386317SXin Long * See the GNU General Public License for more details. 22a8386317SXin Long * 23a8386317SXin Long * You should have received a copy of the GNU General Public License 24a8386317SXin Long * along with GNU CC; see the file COPYING. If not, see 25a8386317SXin Long * <http://www.gnu.org/licenses/>. 26a8386317SXin Long * 27a8386317SXin Long * Please send any bug reports or fixes you make to the 28a8386317SXin Long * email address(es): 29a8386317SXin Long * lksctp developers <linux-sctp@vger.kernel.org> 30a8386317SXin Long * 31a8386317SXin Long * Written or modified by: 32a8386317SXin Long * Xin Long <lucien.xin@gmail.com> 33a8386317SXin Long */ 34a8386317SXin Long 35a8386317SXin Long #include <net/sctp/sctp.h> 367f9d68acSXin Long #include <net/sctp/sm.h> 37a8386317SXin Long 38e090abd0SMarcelo Ricardo Leitner static int sctp_stream_alloc_out(struct sctp_stream *stream, __u16 outcnt, 39e090abd0SMarcelo Ricardo Leitner gfp_t gfp) 40e090abd0SMarcelo Ricardo Leitner { 41e090abd0SMarcelo Ricardo Leitner struct sctp_stream_out *out; 42e090abd0SMarcelo Ricardo Leitner 43e090abd0SMarcelo Ricardo Leitner out = kmalloc_array(outcnt, sizeof(*out), gfp); 44e090abd0SMarcelo Ricardo Leitner if (!out) 45e090abd0SMarcelo Ricardo Leitner return -ENOMEM; 46e090abd0SMarcelo Ricardo Leitner 47e090abd0SMarcelo Ricardo Leitner if (stream->out) { 48e090abd0SMarcelo Ricardo Leitner memcpy(out, stream->out, min(outcnt, stream->outcnt) * 49e090abd0SMarcelo Ricardo Leitner sizeof(*out)); 50e090abd0SMarcelo Ricardo Leitner kfree(stream->out); 51e090abd0SMarcelo Ricardo Leitner } 52e090abd0SMarcelo Ricardo Leitner 53e090abd0SMarcelo Ricardo Leitner if (outcnt > stream->outcnt) 54e090abd0SMarcelo Ricardo Leitner memset(out + stream->outcnt, 0, 55e090abd0SMarcelo Ricardo Leitner (outcnt - stream->outcnt) * sizeof(*out)); 56e090abd0SMarcelo Ricardo Leitner 57e090abd0SMarcelo Ricardo Leitner stream->out = out; 58e090abd0SMarcelo Ricardo Leitner 59e090abd0SMarcelo Ricardo Leitner return 0; 60e090abd0SMarcelo Ricardo Leitner } 61e090abd0SMarcelo Ricardo Leitner 621fdb8d8fSMarcelo Ricardo Leitner static int sctp_stream_alloc_in(struct sctp_stream *stream, __u16 incnt, 631fdb8d8fSMarcelo Ricardo Leitner gfp_t gfp) 641fdb8d8fSMarcelo Ricardo Leitner { 651fdb8d8fSMarcelo Ricardo Leitner struct sctp_stream_in *in; 661fdb8d8fSMarcelo Ricardo Leitner 671fdb8d8fSMarcelo Ricardo Leitner in = kmalloc_array(incnt, sizeof(*stream->in), gfp); 681fdb8d8fSMarcelo Ricardo Leitner 691fdb8d8fSMarcelo Ricardo Leitner if (!in) 701fdb8d8fSMarcelo Ricardo Leitner return -ENOMEM; 711fdb8d8fSMarcelo Ricardo Leitner 721fdb8d8fSMarcelo Ricardo Leitner if (stream->in) { 731fdb8d8fSMarcelo Ricardo Leitner memcpy(in, stream->in, min(incnt, stream->incnt) * 741fdb8d8fSMarcelo Ricardo Leitner sizeof(*in)); 751fdb8d8fSMarcelo Ricardo Leitner kfree(stream->in); 761fdb8d8fSMarcelo Ricardo Leitner } 771fdb8d8fSMarcelo Ricardo Leitner 781fdb8d8fSMarcelo Ricardo Leitner if (incnt > stream->incnt) 791fdb8d8fSMarcelo Ricardo Leitner memset(in + stream->incnt, 0, 801fdb8d8fSMarcelo Ricardo Leitner (incnt - stream->incnt) * sizeof(*in)); 811fdb8d8fSMarcelo Ricardo Leitner 821fdb8d8fSMarcelo Ricardo Leitner stream->in = in; 831fdb8d8fSMarcelo Ricardo Leitner 841fdb8d8fSMarcelo Ricardo Leitner return 0; 851fdb8d8fSMarcelo Ricardo Leitner } 861fdb8d8fSMarcelo Ricardo Leitner 87ff356414SXin Long int sctp_stream_init(struct sctp_stream *stream, __u16 outcnt, __u16 incnt, 88ff356414SXin Long gfp_t gfp) 89a8386317SXin Long { 903dbcc105SXin Long int i; 913dbcc105SXin Long 921ae2eaaaSMarcelo Ricardo Leitner gfp |= __GFP_NOWARN; 931ae2eaaaSMarcelo Ricardo Leitner 943dbcc105SXin Long /* Initial stream->out size may be very big, so free it and alloc 951ae2eaaaSMarcelo Ricardo Leitner * a new one with new outcnt to save memory if needed. 963dbcc105SXin Long */ 971ae2eaaaSMarcelo Ricardo Leitner if (outcnt == stream->outcnt) 981ae2eaaaSMarcelo Ricardo Leitner goto in; 991ae2eaaaSMarcelo Ricardo Leitner 100e090abd0SMarcelo Ricardo Leitner i = sctp_stream_alloc_out(stream, outcnt, gfp); 101e090abd0SMarcelo Ricardo Leitner if (i) 102e090abd0SMarcelo Ricardo Leitner return i; 1033dbcc105SXin Long 104ff356414SXin Long stream->outcnt = outcnt; 1053dbcc105SXin Long for (i = 0; i < stream->outcnt; i++) 1063dbcc105SXin Long stream->out[i].state = SCTP_STREAM_OPEN; 1073dbcc105SXin Long 1081ae2eaaaSMarcelo Ricardo Leitner in: 109ff356414SXin Long if (!incnt) 110ff356414SXin Long return 0; 111ff356414SXin Long 1121fdb8d8fSMarcelo Ricardo Leitner i = sctp_stream_alloc_in(stream, incnt, gfp); 1131fdb8d8fSMarcelo Ricardo Leitner if (i) { 114a8386317SXin Long kfree(stream->out); 115cee360abSXin Long stream->out = NULL; 116cee360abSXin Long return -ENOMEM; 117a8386317SXin Long } 118a8386317SXin Long 119ff356414SXin Long stream->incnt = incnt; 120ff356414SXin Long 1213dbcc105SXin Long return 0; 122a8386317SXin Long } 123a8386317SXin Long 124a8386317SXin Long void sctp_stream_free(struct sctp_stream *stream) 125a8386317SXin Long { 126a8386317SXin Long kfree(stream->out); 127a8386317SXin Long kfree(stream->in); 128a8386317SXin Long } 129a8386317SXin Long 130a8386317SXin Long void sctp_stream_clear(struct sctp_stream *stream) 131a8386317SXin Long { 132a8386317SXin Long int i; 133a8386317SXin Long 134a8386317SXin Long for (i = 0; i < stream->outcnt; i++) 135a8386317SXin Long stream->out[i].ssn = 0; 136a8386317SXin Long 137a8386317SXin Long for (i = 0; i < stream->incnt; i++) 138a8386317SXin Long stream->in[i].ssn = 0; 139a8386317SXin Long } 1407f9d68acSXin Long 141cee360abSXin Long void sctp_stream_update(struct sctp_stream *stream, struct sctp_stream *new) 142cee360abSXin Long { 143cee360abSXin Long sctp_stream_free(stream); 144cee360abSXin Long 145cee360abSXin Long stream->out = new->out; 146cee360abSXin Long stream->in = new->in; 147cee360abSXin Long stream->outcnt = new->outcnt; 148cee360abSXin Long stream->incnt = new->incnt; 149cee360abSXin Long 150cee360abSXin Long new->out = NULL; 151cee360abSXin Long new->in = NULL; 152cee360abSXin Long } 153cee360abSXin Long 1547f9d68acSXin Long static int sctp_send_reconf(struct sctp_association *asoc, 1557f9d68acSXin Long struct sctp_chunk *chunk) 1567f9d68acSXin Long { 1577f9d68acSXin Long struct net *net = sock_net(asoc->base.sk); 1587f9d68acSXin Long int retval = 0; 1597f9d68acSXin Long 1607f9d68acSXin Long retval = sctp_primitive_RECONF(net, asoc, chunk); 1617f9d68acSXin Long if (retval) 1627f9d68acSXin Long sctp_chunk_free(chunk); 1637f9d68acSXin Long 1647f9d68acSXin Long return retval; 1657f9d68acSXin Long } 1667f9d68acSXin Long 1677f9d68acSXin Long int sctp_send_reset_streams(struct sctp_association *asoc, 1687f9d68acSXin Long struct sctp_reset_streams *params) 1697f9d68acSXin Long { 170cee360abSXin Long struct sctp_stream *stream = &asoc->stream; 1717f9d68acSXin Long __u16 i, str_nums, *str_list; 1727f9d68acSXin Long struct sctp_chunk *chunk; 1737f9d68acSXin Long int retval = -EINVAL; 1747f9d68acSXin Long bool out, in; 1757f9d68acSXin Long 1767f9d68acSXin Long if (!asoc->peer.reconf_capable || 1777f9d68acSXin Long !(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ)) { 1787f9d68acSXin Long retval = -ENOPROTOOPT; 1797f9d68acSXin Long goto out; 1807f9d68acSXin Long } 1817f9d68acSXin Long 1827f9d68acSXin Long if (asoc->strreset_outstanding) { 1837f9d68acSXin Long retval = -EINPROGRESS; 1847f9d68acSXin Long goto out; 1857f9d68acSXin Long } 1867f9d68acSXin Long 1877f9d68acSXin Long out = params->srs_flags & SCTP_STREAM_RESET_OUTGOING; 1887f9d68acSXin Long in = params->srs_flags & SCTP_STREAM_RESET_INCOMING; 1897f9d68acSXin Long if (!out && !in) 1907f9d68acSXin Long goto out; 1917f9d68acSXin Long 1927f9d68acSXin Long str_nums = params->srs_number_streams; 1937f9d68acSXin Long str_list = params->srs_stream_list; 1947f9d68acSXin Long if (out && str_nums) 1957f9d68acSXin Long for (i = 0; i < str_nums; i++) 1967f9d68acSXin Long if (str_list[i] >= stream->outcnt) 1977f9d68acSXin Long goto out; 1987f9d68acSXin Long 1997f9d68acSXin Long if (in && str_nums) 2007f9d68acSXin Long for (i = 0; i < str_nums; i++) 2017f9d68acSXin Long if (str_list[i] >= stream->incnt) 2027f9d68acSXin Long goto out; 2037f9d68acSXin Long 20416e1a919SXin Long for (i = 0; i < str_nums; i++) 20516e1a919SXin Long str_list[i] = htons(str_list[i]); 20616e1a919SXin Long 2077f9d68acSXin Long chunk = sctp_make_strreset_req(asoc, str_nums, str_list, out, in); 20816e1a919SXin Long 20916e1a919SXin Long for (i = 0; i < str_nums; i++) 21016e1a919SXin Long str_list[i] = ntohs(str_list[i]); 21116e1a919SXin Long 212119aecbaSXin Long if (!chunk) { 213119aecbaSXin Long retval = -ENOMEM; 2147f9d68acSXin Long goto out; 215119aecbaSXin Long } 2167f9d68acSXin Long 2177f9d68acSXin Long if (out) { 2187f9d68acSXin Long if (str_nums) 2197f9d68acSXin Long for (i = 0; i < str_nums; i++) 2207f9d68acSXin Long stream->out[str_list[i]].state = 2217f9d68acSXin Long SCTP_STREAM_CLOSED; 2227f9d68acSXin Long else 2237f9d68acSXin Long for (i = 0; i < stream->outcnt; i++) 2247f9d68acSXin Long stream->out[i].state = SCTP_STREAM_CLOSED; 2257f9d68acSXin Long } 2267f9d68acSXin Long 2277f9d68acSXin Long asoc->strreset_chunk = chunk; 2287f9d68acSXin Long sctp_chunk_hold(asoc->strreset_chunk); 2297f9d68acSXin Long 2307f9d68acSXin Long retval = sctp_send_reconf(asoc, chunk); 2317f9d68acSXin Long if (retval) { 2327f9d68acSXin Long sctp_chunk_put(asoc->strreset_chunk); 2337f9d68acSXin Long asoc->strreset_chunk = NULL; 234119aecbaSXin Long if (!out) 235119aecbaSXin Long goto out; 236119aecbaSXin Long 237119aecbaSXin Long if (str_nums) 238119aecbaSXin Long for (i = 0; i < str_nums; i++) 239119aecbaSXin Long stream->out[str_list[i]].state = 240119aecbaSXin Long SCTP_STREAM_OPEN; 241119aecbaSXin Long else 242119aecbaSXin Long for (i = 0; i < stream->outcnt; i++) 243119aecbaSXin Long stream->out[i].state = SCTP_STREAM_OPEN; 244119aecbaSXin Long 245119aecbaSXin Long goto out; 2467f9d68acSXin Long } 2477f9d68acSXin Long 248119aecbaSXin Long asoc->strreset_outstanding = out + in; 249119aecbaSXin Long 2507f9d68acSXin Long out: 2517f9d68acSXin Long return retval; 2527f9d68acSXin Long } 253a92ce1a4SXin Long 254a92ce1a4SXin Long int sctp_send_reset_assoc(struct sctp_association *asoc) 255a92ce1a4SXin Long { 256cee360abSXin Long struct sctp_stream *stream = &asoc->stream; 257a92ce1a4SXin Long struct sctp_chunk *chunk = NULL; 258a92ce1a4SXin Long int retval; 259a92ce1a4SXin Long __u16 i; 260a92ce1a4SXin Long 261a92ce1a4SXin Long if (!asoc->peer.reconf_capable || 262a92ce1a4SXin Long !(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ)) 263a92ce1a4SXin Long return -ENOPROTOOPT; 264a92ce1a4SXin Long 265a92ce1a4SXin Long if (asoc->strreset_outstanding) 266a92ce1a4SXin Long return -EINPROGRESS; 267a92ce1a4SXin Long 268a92ce1a4SXin Long chunk = sctp_make_strreset_tsnreq(asoc); 269a92ce1a4SXin Long if (!chunk) 270a92ce1a4SXin Long return -ENOMEM; 271a92ce1a4SXin Long 272a92ce1a4SXin Long /* Block further xmit of data until this request is completed */ 273cee360abSXin Long for (i = 0; i < stream->outcnt; i++) 274cee360abSXin Long stream->out[i].state = SCTP_STREAM_CLOSED; 275a92ce1a4SXin Long 276a92ce1a4SXin Long asoc->strreset_chunk = chunk; 277a92ce1a4SXin Long sctp_chunk_hold(asoc->strreset_chunk); 278a92ce1a4SXin Long 279a92ce1a4SXin Long retval = sctp_send_reconf(asoc, chunk); 280a92ce1a4SXin Long if (retval) { 281a92ce1a4SXin Long sctp_chunk_put(asoc->strreset_chunk); 282a92ce1a4SXin Long asoc->strreset_chunk = NULL; 283a92ce1a4SXin Long 284cee360abSXin Long for (i = 0; i < stream->outcnt; i++) 285cee360abSXin Long stream->out[i].state = SCTP_STREAM_OPEN; 286a92ce1a4SXin Long 287a92ce1a4SXin Long return retval; 288a92ce1a4SXin Long } 289a92ce1a4SXin Long 290a92ce1a4SXin Long asoc->strreset_outstanding = 1; 291a92ce1a4SXin Long 292a92ce1a4SXin Long return 0; 293a92ce1a4SXin Long } 294242bd2d5SXin Long 295242bd2d5SXin Long int sctp_send_add_streams(struct sctp_association *asoc, 296242bd2d5SXin Long struct sctp_add_streams *params) 297242bd2d5SXin Long { 298cee360abSXin Long struct sctp_stream *stream = &asoc->stream; 299242bd2d5SXin Long struct sctp_chunk *chunk = NULL; 300242bd2d5SXin Long int retval = -ENOMEM; 301242bd2d5SXin Long __u32 outcnt, incnt; 302242bd2d5SXin Long __u16 out, in; 303242bd2d5SXin Long 304242bd2d5SXin Long if (!asoc->peer.reconf_capable || 305242bd2d5SXin Long !(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ)) { 306242bd2d5SXin Long retval = -ENOPROTOOPT; 307242bd2d5SXin Long goto out; 308242bd2d5SXin Long } 309242bd2d5SXin Long 310242bd2d5SXin Long if (asoc->strreset_outstanding) { 311242bd2d5SXin Long retval = -EINPROGRESS; 312242bd2d5SXin Long goto out; 313242bd2d5SXin Long } 314242bd2d5SXin Long 315242bd2d5SXin Long out = params->sas_outstrms; 316242bd2d5SXin Long in = params->sas_instrms; 317242bd2d5SXin Long outcnt = stream->outcnt + out; 318242bd2d5SXin Long incnt = stream->incnt + in; 319242bd2d5SXin Long if (outcnt > SCTP_MAX_STREAM || incnt > SCTP_MAX_STREAM || 320242bd2d5SXin Long (!out && !in)) { 321242bd2d5SXin Long retval = -EINVAL; 322242bd2d5SXin Long goto out; 323242bd2d5SXin Long } 324242bd2d5SXin Long 325242bd2d5SXin Long if (out) { 326e090abd0SMarcelo Ricardo Leitner retval = sctp_stream_alloc_out(stream, outcnt, GFP_KERNEL); 327e090abd0SMarcelo Ricardo Leitner if (retval) 328242bd2d5SXin Long goto out; 329242bd2d5SXin Long } 330242bd2d5SXin Long 331242bd2d5SXin Long chunk = sctp_make_strreset_addstrm(asoc, out, in); 332242bd2d5SXin Long if (!chunk) 333242bd2d5SXin Long goto out; 334242bd2d5SXin Long 335242bd2d5SXin Long asoc->strreset_chunk = chunk; 336242bd2d5SXin Long sctp_chunk_hold(asoc->strreset_chunk); 337242bd2d5SXin Long 338242bd2d5SXin Long retval = sctp_send_reconf(asoc, chunk); 339242bd2d5SXin Long if (retval) { 340242bd2d5SXin Long sctp_chunk_put(asoc->strreset_chunk); 341242bd2d5SXin Long asoc->strreset_chunk = NULL; 342242bd2d5SXin Long goto out; 343242bd2d5SXin Long } 344242bd2d5SXin Long 345242bd2d5SXin Long stream->incnt = incnt; 346242bd2d5SXin Long stream->outcnt = outcnt; 347242bd2d5SXin Long 348242bd2d5SXin Long asoc->strreset_outstanding = !!out + !!in; 349242bd2d5SXin Long 350242bd2d5SXin Long out: 351242bd2d5SXin Long return retval; 352242bd2d5SXin Long } 35381054476SXin Long 3543c918704SXin Long static struct sctp_paramhdr *sctp_chunk_lookup_strreset_param( 35550a41591SXin Long struct sctp_association *asoc, __u32 resp_seq, 35650a41591SXin Long __be16 type) 35781054476SXin Long { 35881054476SXin Long struct sctp_chunk *chunk = asoc->strreset_chunk; 35981054476SXin Long struct sctp_reconf_chunk *hdr; 36081054476SXin Long union sctp_params param; 36181054476SXin Long 36250a41591SXin Long if (!chunk) 36381054476SXin Long return NULL; 36481054476SXin Long 36581054476SXin Long hdr = (struct sctp_reconf_chunk *)chunk->chunk_hdr; 36681054476SXin Long sctp_walk_params(param, hdr, params) { 36781054476SXin Long /* sctp_strreset_tsnreq is actually the basic structure 36881054476SXin Long * of all stream reconf params, so it's safe to use it 36981054476SXin Long * to access request_seq. 37081054476SXin Long */ 37181054476SXin Long struct sctp_strreset_tsnreq *req = param.v; 37281054476SXin Long 37350a41591SXin Long if ((!resp_seq || req->request_seq == resp_seq) && 37450a41591SXin Long (!type || type == req->param_hdr.type)) 37581054476SXin Long return param.v; 37681054476SXin Long } 37781054476SXin Long 37881054476SXin Long return NULL; 37981054476SXin Long } 38081054476SXin Long 381e4dc99c7SXin Long static void sctp_update_strreset_result(struct sctp_association *asoc, 382e4dc99c7SXin Long __u32 result) 383e4dc99c7SXin Long { 384e4dc99c7SXin Long asoc->strreset_result[1] = asoc->strreset_result[0]; 385e4dc99c7SXin Long asoc->strreset_result[0] = result; 386e4dc99c7SXin Long } 387e4dc99c7SXin Long 38881054476SXin Long struct sctp_chunk *sctp_process_strreset_outreq( 38981054476SXin Long struct sctp_association *asoc, 39081054476SXin Long union sctp_params param, 39181054476SXin Long struct sctp_ulpevent **evp) 39281054476SXin Long { 39381054476SXin Long struct sctp_strreset_outreq *outreq = param.v; 394cee360abSXin Long struct sctp_stream *stream = &asoc->stream; 39581054476SXin Long __u16 i, nums, flags = 0, *str_p = NULL; 39681054476SXin Long __u32 result = SCTP_STRRESET_DENIED; 39781054476SXin Long __u32 request_seq; 39881054476SXin Long 39981054476SXin Long request_seq = ntohl(outreq->request_seq); 40081054476SXin Long 40181054476SXin Long if (ntohl(outreq->send_reset_at_tsn) > 40281054476SXin Long sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map)) { 40381054476SXin Long result = SCTP_STRRESET_IN_PROGRESS; 404e4dc99c7SXin Long goto err; 40581054476SXin Long } 40681054476SXin Long 407e4dc99c7SXin Long if (TSN_lt(asoc->strreset_inseq, request_seq) || 408e4dc99c7SXin Long TSN_lt(request_seq, asoc->strreset_inseq - 2)) { 40981054476SXin Long result = SCTP_STRRESET_ERR_BAD_SEQNO; 410e4dc99c7SXin Long goto err; 411e4dc99c7SXin Long } else if (TSN_lt(request_seq, asoc->strreset_inseq)) { 412e4dc99c7SXin Long i = asoc->strreset_inseq - request_seq - 1; 413e4dc99c7SXin Long result = asoc->strreset_result[i]; 414e4dc99c7SXin Long goto err; 41581054476SXin Long } 416e4dc99c7SXin Long asoc->strreset_inseq++; 41781054476SXin Long 41881054476SXin Long /* Check strreset_enable after inseq inc, as sender cannot tell 41981054476SXin Long * the peer doesn't enable strreset after receiving response with 42081054476SXin Long * result denied, as well as to keep consistent with bsd. 42181054476SXin Long */ 42281054476SXin Long if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ)) 42381054476SXin Long goto out; 42481054476SXin Long 42581054476SXin Long if (asoc->strreset_chunk) { 42650a41591SXin Long if (!sctp_chunk_lookup_strreset_param( 42750a41591SXin Long asoc, outreq->response_seq, 42850a41591SXin Long SCTP_PARAM_RESET_IN_REQUEST)) { 42981054476SXin Long /* same process with outstanding isn't 0 */ 43081054476SXin Long result = SCTP_STRRESET_ERR_IN_PROGRESS; 43181054476SXin Long goto out; 43281054476SXin Long } 43381054476SXin Long 43481054476SXin Long asoc->strreset_outstanding--; 43581054476SXin Long asoc->strreset_outseq++; 43681054476SXin Long 43781054476SXin Long if (!asoc->strreset_outstanding) { 43850a41591SXin Long struct sctp_transport *t; 43950a41591SXin Long 44081054476SXin Long t = asoc->strreset_chunk->transport; 44181054476SXin Long if (del_timer(&t->reconf_timer)) 44281054476SXin Long sctp_transport_put(t); 44381054476SXin Long 44481054476SXin Long sctp_chunk_put(asoc->strreset_chunk); 44581054476SXin Long asoc->strreset_chunk = NULL; 44681054476SXin Long } 44781054476SXin Long 44881054476SXin Long flags = SCTP_STREAM_RESET_INCOMING_SSN; 44981054476SXin Long } 45081054476SXin Long 45181054476SXin Long nums = (ntohs(param.p->length) - sizeof(*outreq)) / 2; 45281054476SXin Long if (nums) { 45381054476SXin Long str_p = outreq->list_of_streams; 45481054476SXin Long for (i = 0; i < nums; i++) { 45581054476SXin Long if (ntohs(str_p[i]) >= stream->incnt) { 45681054476SXin Long result = SCTP_STRRESET_ERR_WRONG_SSN; 45781054476SXin Long goto out; 45881054476SXin Long } 45981054476SXin Long } 46081054476SXin Long 46181054476SXin Long for (i = 0; i < nums; i++) 46281054476SXin Long stream->in[ntohs(str_p[i])].ssn = 0; 46381054476SXin Long } else { 46481054476SXin Long for (i = 0; i < stream->incnt; i++) 46581054476SXin Long stream->in[i].ssn = 0; 46681054476SXin Long } 46781054476SXin Long 46881054476SXin Long result = SCTP_STRRESET_PERFORMED; 46981054476SXin Long 47081054476SXin Long *evp = sctp_ulpevent_make_stream_reset_event(asoc, 47181054476SXin Long flags | SCTP_STREAM_RESET_OUTGOING_SSN, nums, str_p, 47281054476SXin Long GFP_ATOMIC); 47381054476SXin Long 47481054476SXin Long out: 475e4dc99c7SXin Long sctp_update_strreset_result(asoc, result); 476e4dc99c7SXin Long err: 47781054476SXin Long return sctp_make_strreset_resp(asoc, result, request_seq); 47881054476SXin Long } 47916e1a919SXin Long 48016e1a919SXin Long struct sctp_chunk *sctp_process_strreset_inreq( 48116e1a919SXin Long struct sctp_association *asoc, 48216e1a919SXin Long union sctp_params param, 48316e1a919SXin Long struct sctp_ulpevent **evp) 48416e1a919SXin Long { 48516e1a919SXin Long struct sctp_strreset_inreq *inreq = param.v; 486cee360abSXin Long struct sctp_stream *stream = &asoc->stream; 48716e1a919SXin Long __u32 result = SCTP_STRRESET_DENIED; 48816e1a919SXin Long struct sctp_chunk *chunk = NULL; 48916e1a919SXin Long __u16 i, nums, *str_p; 49016e1a919SXin Long __u32 request_seq; 49116e1a919SXin Long 49216e1a919SXin Long request_seq = ntohl(inreq->request_seq); 493d0f025e6SXin Long if (TSN_lt(asoc->strreset_inseq, request_seq) || 494d0f025e6SXin Long TSN_lt(request_seq, asoc->strreset_inseq - 2)) { 49516e1a919SXin Long result = SCTP_STRRESET_ERR_BAD_SEQNO; 496d0f025e6SXin Long goto err; 497d0f025e6SXin Long } else if (TSN_lt(request_seq, asoc->strreset_inseq)) { 498d0f025e6SXin Long i = asoc->strreset_inseq - request_seq - 1; 499d0f025e6SXin Long result = asoc->strreset_result[i]; 500d0f025e6SXin Long if (result == SCTP_STRRESET_PERFORMED) 501d0f025e6SXin Long return NULL; 502d0f025e6SXin Long goto err; 50316e1a919SXin Long } 504d0f025e6SXin Long asoc->strreset_inseq++; 50516e1a919SXin Long 50616e1a919SXin Long if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ)) 50716e1a919SXin Long goto out; 50816e1a919SXin Long 50916e1a919SXin Long if (asoc->strreset_outstanding) { 51016e1a919SXin Long result = SCTP_STRRESET_ERR_IN_PROGRESS; 51116e1a919SXin Long goto out; 51216e1a919SXin Long } 51316e1a919SXin Long 51416e1a919SXin Long nums = (ntohs(param.p->length) - sizeof(*inreq)) / 2; 51516e1a919SXin Long str_p = inreq->list_of_streams; 51616e1a919SXin Long for (i = 0; i < nums; i++) { 51716e1a919SXin Long if (ntohs(str_p[i]) >= stream->outcnt) { 51816e1a919SXin Long result = SCTP_STRRESET_ERR_WRONG_SSN; 51916e1a919SXin Long goto out; 52016e1a919SXin Long } 52116e1a919SXin Long } 52216e1a919SXin Long 52316e1a919SXin Long chunk = sctp_make_strreset_req(asoc, nums, str_p, 1, 0); 52416e1a919SXin Long if (!chunk) 52516e1a919SXin Long goto out; 52616e1a919SXin Long 52716e1a919SXin Long if (nums) 52816e1a919SXin Long for (i = 0; i < nums; i++) 52916e1a919SXin Long stream->out[ntohs(str_p[i])].state = 53016e1a919SXin Long SCTP_STREAM_CLOSED; 53116e1a919SXin Long else 53216e1a919SXin Long for (i = 0; i < stream->outcnt; i++) 53316e1a919SXin Long stream->out[i].state = SCTP_STREAM_CLOSED; 53416e1a919SXin Long 53516e1a919SXin Long asoc->strreset_chunk = chunk; 53616e1a919SXin Long asoc->strreset_outstanding = 1; 53716e1a919SXin Long sctp_chunk_hold(asoc->strreset_chunk); 53816e1a919SXin Long 539d0f025e6SXin Long result = SCTP_STRRESET_PERFORMED; 540d0f025e6SXin Long 54116e1a919SXin Long *evp = sctp_ulpevent_make_stream_reset_event(asoc, 54216e1a919SXin Long SCTP_STREAM_RESET_INCOMING_SSN, nums, str_p, GFP_ATOMIC); 54316e1a919SXin Long 54416e1a919SXin Long out: 545d0f025e6SXin Long sctp_update_strreset_result(asoc, result); 546d0f025e6SXin Long err: 54716e1a919SXin Long if (!chunk) 54816e1a919SXin Long chunk = sctp_make_strreset_resp(asoc, result, request_seq); 54916e1a919SXin Long 55016e1a919SXin Long return chunk; 55116e1a919SXin Long } 552692787ceSXin Long 553692787ceSXin Long struct sctp_chunk *sctp_process_strreset_tsnreq( 554692787ceSXin Long struct sctp_association *asoc, 555692787ceSXin Long union sctp_params param, 556692787ceSXin Long struct sctp_ulpevent **evp) 557692787ceSXin Long { 558692787ceSXin Long __u32 init_tsn = 0, next_tsn = 0, max_tsn_seen; 559692787ceSXin Long struct sctp_strreset_tsnreq *tsnreq = param.v; 560cee360abSXin Long struct sctp_stream *stream = &asoc->stream; 561692787ceSXin Long __u32 result = SCTP_STRRESET_DENIED; 562692787ceSXin Long __u32 request_seq; 563692787ceSXin Long __u16 i; 564692787ceSXin Long 565692787ceSXin Long request_seq = ntohl(tsnreq->request_seq); 5666c801387SXin Long if (TSN_lt(asoc->strreset_inseq, request_seq) || 5676c801387SXin Long TSN_lt(request_seq, asoc->strreset_inseq - 2)) { 568692787ceSXin Long result = SCTP_STRRESET_ERR_BAD_SEQNO; 5696c801387SXin Long goto err; 5706c801387SXin Long } else if (TSN_lt(request_seq, asoc->strreset_inseq)) { 5716c801387SXin Long i = asoc->strreset_inseq - request_seq - 1; 5726c801387SXin Long result = asoc->strreset_result[i]; 5736c801387SXin Long if (result == SCTP_STRRESET_PERFORMED) { 5746c801387SXin Long next_tsn = asoc->next_tsn; 5756c801387SXin Long init_tsn = 5766c801387SXin Long sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + 1; 577692787ceSXin Long } 5786c801387SXin Long goto err; 5796c801387SXin Long } 5806c801387SXin Long asoc->strreset_inseq++; 581692787ceSXin Long 582692787ceSXin Long if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ)) 583692787ceSXin Long goto out; 584692787ceSXin Long 585692787ceSXin Long if (asoc->strreset_outstanding) { 586692787ceSXin Long result = SCTP_STRRESET_ERR_IN_PROGRESS; 587692787ceSXin Long goto out; 588692787ceSXin Long } 589692787ceSXin Long 590692787ceSXin Long /* G3: The same processing as though a SACK chunk with no gap report 591692787ceSXin Long * and a cumulative TSN ACK of the Sender's Next TSN minus 1 were 592692787ceSXin Long * received MUST be performed. 593692787ceSXin Long */ 594692787ceSXin Long max_tsn_seen = sctp_tsnmap_get_max_tsn_seen(&asoc->peer.tsn_map); 595692787ceSXin Long sctp_ulpq_reasm_flushtsn(&asoc->ulpq, max_tsn_seen); 596692787ceSXin Long sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC); 597692787ceSXin Long 598692787ceSXin Long /* G1: Compute an appropriate value for the Receiver's Next TSN -- the 599692787ceSXin Long * TSN that the peer should use to send the next DATA chunk. The 600692787ceSXin Long * value SHOULD be the smallest TSN not acknowledged by the 601692787ceSXin Long * receiver of the request plus 2^31. 602692787ceSXin Long */ 603692787ceSXin Long init_tsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + (1 << 31); 604692787ceSXin Long sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL, 605692787ceSXin Long init_tsn, GFP_ATOMIC); 606692787ceSXin Long 607692787ceSXin Long /* G4: The same processing as though a FWD-TSN chunk (as defined in 608692787ceSXin Long * [RFC3758]) with all streams affected and a new cumulative TSN 609692787ceSXin Long * ACK of the Receiver's Next TSN minus 1 were received MUST be 610692787ceSXin Long * performed. 611692787ceSXin Long */ 612692787ceSXin Long sctp_outq_free(&asoc->outqueue); 613692787ceSXin Long 614692787ceSXin Long /* G2: Compute an appropriate value for the local endpoint's next TSN, 615692787ceSXin Long * i.e., the next TSN assigned by the receiver of the SSN/TSN reset 616692787ceSXin Long * chunk. The value SHOULD be the highest TSN sent by the receiver 617692787ceSXin Long * of the request plus 1. 618692787ceSXin Long */ 619692787ceSXin Long next_tsn = asoc->next_tsn; 620692787ceSXin Long asoc->ctsn_ack_point = next_tsn - 1; 621692787ceSXin Long asoc->adv_peer_ack_point = asoc->ctsn_ack_point; 622692787ceSXin Long 623692787ceSXin Long /* G5: The next expected and outgoing SSNs MUST be reset to 0 for all 624692787ceSXin Long * incoming and outgoing streams. 625692787ceSXin Long */ 626692787ceSXin Long for (i = 0; i < stream->outcnt; i++) 627692787ceSXin Long stream->out[i].ssn = 0; 628692787ceSXin Long for (i = 0; i < stream->incnt; i++) 629692787ceSXin Long stream->in[i].ssn = 0; 630692787ceSXin Long 631692787ceSXin Long result = SCTP_STRRESET_PERFORMED; 632692787ceSXin Long 633692787ceSXin Long *evp = sctp_ulpevent_make_assoc_reset_event(asoc, 0, init_tsn, 634692787ceSXin Long next_tsn, GFP_ATOMIC); 635692787ceSXin Long 636692787ceSXin Long out: 6376c801387SXin Long sctp_update_strreset_result(asoc, result); 6386c801387SXin Long err: 639692787ceSXin Long return sctp_make_strreset_tsnresp(asoc, result, request_seq, 640692787ceSXin Long next_tsn, init_tsn); 641692787ceSXin Long } 64250a41591SXin Long 64350a41591SXin Long struct sctp_chunk *sctp_process_strreset_addstrm_out( 64450a41591SXin Long struct sctp_association *asoc, 64550a41591SXin Long union sctp_params param, 64650a41591SXin Long struct sctp_ulpevent **evp) 64750a41591SXin Long { 64850a41591SXin Long struct sctp_strreset_addstrm *addstrm = param.v; 649cee360abSXin Long struct sctp_stream *stream = &asoc->stream; 65050a41591SXin Long __u32 result = SCTP_STRRESET_DENIED; 65150a41591SXin Long __u32 request_seq, incnt; 652e4dc99c7SXin Long __u16 in, i; 65350a41591SXin Long 65450a41591SXin Long request_seq = ntohl(addstrm->request_seq); 655e4dc99c7SXin Long if (TSN_lt(asoc->strreset_inseq, request_seq) || 656e4dc99c7SXin Long TSN_lt(request_seq, asoc->strreset_inseq - 2)) { 65750a41591SXin Long result = SCTP_STRRESET_ERR_BAD_SEQNO; 658e4dc99c7SXin Long goto err; 659e4dc99c7SXin Long } else if (TSN_lt(request_seq, asoc->strreset_inseq)) { 660e4dc99c7SXin Long i = asoc->strreset_inseq - request_seq - 1; 661e4dc99c7SXin Long result = asoc->strreset_result[i]; 662e4dc99c7SXin Long goto err; 66350a41591SXin Long } 664e4dc99c7SXin Long asoc->strreset_inseq++; 66550a41591SXin Long 66650a41591SXin Long if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ)) 66750a41591SXin Long goto out; 66850a41591SXin Long 66950a41591SXin Long if (asoc->strreset_chunk) { 67050a41591SXin Long if (!sctp_chunk_lookup_strreset_param( 67150a41591SXin Long asoc, 0, SCTP_PARAM_RESET_ADD_IN_STREAMS)) { 67250a41591SXin Long /* same process with outstanding isn't 0 */ 67350a41591SXin Long result = SCTP_STRRESET_ERR_IN_PROGRESS; 67450a41591SXin Long goto out; 67550a41591SXin Long } 67650a41591SXin Long 67750a41591SXin Long asoc->strreset_outstanding--; 67850a41591SXin Long asoc->strreset_outseq++; 67950a41591SXin Long 68050a41591SXin Long if (!asoc->strreset_outstanding) { 68150a41591SXin Long struct sctp_transport *t; 68250a41591SXin Long 68350a41591SXin Long t = asoc->strreset_chunk->transport; 68450a41591SXin Long if (del_timer(&t->reconf_timer)) 68550a41591SXin Long sctp_transport_put(t); 68650a41591SXin Long 68750a41591SXin Long sctp_chunk_put(asoc->strreset_chunk); 68850a41591SXin Long asoc->strreset_chunk = NULL; 68950a41591SXin Long } 69050a41591SXin Long } 69150a41591SXin Long 69250a41591SXin Long in = ntohs(addstrm->number_of_streams); 69350a41591SXin Long incnt = stream->incnt + in; 69450a41591SXin Long if (!in || incnt > SCTP_MAX_STREAM) 69550a41591SXin Long goto out; 69650a41591SXin Long 6971fdb8d8fSMarcelo Ricardo Leitner if (sctp_stream_alloc_in(stream, incnt, GFP_ATOMIC)) 69850a41591SXin Long goto out; 69950a41591SXin Long 70050a41591SXin Long stream->incnt = incnt; 70150a41591SXin Long 70250a41591SXin Long result = SCTP_STRRESET_PERFORMED; 70350a41591SXin Long 70450a41591SXin Long *evp = sctp_ulpevent_make_stream_change_event(asoc, 70550a41591SXin Long 0, ntohs(addstrm->number_of_streams), 0, GFP_ATOMIC); 70650a41591SXin Long 70750a41591SXin Long out: 708e4dc99c7SXin Long sctp_update_strreset_result(asoc, result); 709e4dc99c7SXin Long err: 71050a41591SXin Long return sctp_make_strreset_resp(asoc, result, request_seq); 71150a41591SXin Long } 712c5c4ebb3SXin Long 713c5c4ebb3SXin Long struct sctp_chunk *sctp_process_strreset_addstrm_in( 714c5c4ebb3SXin Long struct sctp_association *asoc, 715c5c4ebb3SXin Long union sctp_params param, 716c5c4ebb3SXin Long struct sctp_ulpevent **evp) 717c5c4ebb3SXin Long { 718c5c4ebb3SXin Long struct sctp_strreset_addstrm *addstrm = param.v; 719cee360abSXin Long struct sctp_stream *stream = &asoc->stream; 720c5c4ebb3SXin Long __u32 result = SCTP_STRRESET_DENIED; 721c5c4ebb3SXin Long struct sctp_chunk *chunk = NULL; 722c5c4ebb3SXin Long __u32 request_seq, outcnt; 723d0f025e6SXin Long __u16 out, i; 724e090abd0SMarcelo Ricardo Leitner int ret; 725c5c4ebb3SXin Long 726c5c4ebb3SXin Long request_seq = ntohl(addstrm->request_seq); 727d0f025e6SXin Long if (TSN_lt(asoc->strreset_inseq, request_seq) || 728d0f025e6SXin Long TSN_lt(request_seq, asoc->strreset_inseq - 2)) { 729c5c4ebb3SXin Long result = SCTP_STRRESET_ERR_BAD_SEQNO; 730d0f025e6SXin Long goto err; 731d0f025e6SXin Long } else if (TSN_lt(request_seq, asoc->strreset_inseq)) { 732d0f025e6SXin Long i = asoc->strreset_inseq - request_seq - 1; 733d0f025e6SXin Long result = asoc->strreset_result[i]; 734d0f025e6SXin Long if (result == SCTP_STRRESET_PERFORMED) 735d0f025e6SXin Long return NULL; 736d0f025e6SXin Long goto err; 737c5c4ebb3SXin Long } 738d0f025e6SXin Long asoc->strreset_inseq++; 739c5c4ebb3SXin Long 740c5c4ebb3SXin Long if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ)) 741c5c4ebb3SXin Long goto out; 742c5c4ebb3SXin Long 743c5c4ebb3SXin Long if (asoc->strreset_outstanding) { 744c5c4ebb3SXin Long result = SCTP_STRRESET_ERR_IN_PROGRESS; 745c5c4ebb3SXin Long goto out; 746c5c4ebb3SXin Long } 747c5c4ebb3SXin Long 748c5c4ebb3SXin Long out = ntohs(addstrm->number_of_streams); 749c5c4ebb3SXin Long outcnt = stream->outcnt + out; 750c5c4ebb3SXin Long if (!out || outcnt > SCTP_MAX_STREAM) 751c5c4ebb3SXin Long goto out; 752c5c4ebb3SXin Long 753e090abd0SMarcelo Ricardo Leitner ret = sctp_stream_alloc_out(stream, outcnt, GFP_ATOMIC); 754e090abd0SMarcelo Ricardo Leitner if (ret) 755c5c4ebb3SXin Long goto out; 756c5c4ebb3SXin Long 757c5c4ebb3SXin Long chunk = sctp_make_strreset_addstrm(asoc, out, 0); 758c5c4ebb3SXin Long if (!chunk) 759c5c4ebb3SXin Long goto out; 760c5c4ebb3SXin Long 761c5c4ebb3SXin Long asoc->strreset_chunk = chunk; 762c5c4ebb3SXin Long asoc->strreset_outstanding = 1; 763c5c4ebb3SXin Long sctp_chunk_hold(asoc->strreset_chunk); 764c5c4ebb3SXin Long 765c5c4ebb3SXin Long stream->outcnt = outcnt; 766c5c4ebb3SXin Long 767d0f025e6SXin Long result = SCTP_STRRESET_PERFORMED; 768d0f025e6SXin Long 769c5c4ebb3SXin Long *evp = sctp_ulpevent_make_stream_change_event(asoc, 770c5c4ebb3SXin Long 0, 0, ntohs(addstrm->number_of_streams), GFP_ATOMIC); 771c5c4ebb3SXin Long 772c5c4ebb3SXin Long out: 773d0f025e6SXin Long sctp_update_strreset_result(asoc, result); 774d0f025e6SXin Long err: 775c5c4ebb3SXin Long if (!chunk) 776c5c4ebb3SXin Long chunk = sctp_make_strreset_resp(asoc, result, request_seq); 777c5c4ebb3SXin Long 778c5c4ebb3SXin Long return chunk; 779c5c4ebb3SXin Long } 78011ae76e6SXin Long 78111ae76e6SXin Long struct sctp_chunk *sctp_process_strreset_resp( 78211ae76e6SXin Long struct sctp_association *asoc, 78311ae76e6SXin Long union sctp_params param, 78411ae76e6SXin Long struct sctp_ulpevent **evp) 78511ae76e6SXin Long { 786cee360abSXin Long struct sctp_stream *stream = &asoc->stream; 78711ae76e6SXin Long struct sctp_strreset_resp *resp = param.v; 78811ae76e6SXin Long struct sctp_transport *t; 78911ae76e6SXin Long __u16 i, nums, flags = 0; 7903c918704SXin Long struct sctp_paramhdr *req; 79111ae76e6SXin Long __u32 result; 79211ae76e6SXin Long 79311ae76e6SXin Long req = sctp_chunk_lookup_strreset_param(asoc, resp->response_seq, 0); 79411ae76e6SXin Long if (!req) 79511ae76e6SXin Long return NULL; 79611ae76e6SXin Long 79711ae76e6SXin Long result = ntohl(resp->result); 79811ae76e6SXin Long if (result != SCTP_STRRESET_PERFORMED) { 79911ae76e6SXin Long /* if in progress, do nothing but retransmit */ 80011ae76e6SXin Long if (result == SCTP_STRRESET_IN_PROGRESS) 80111ae76e6SXin Long return NULL; 80211ae76e6SXin Long else if (result == SCTP_STRRESET_DENIED) 80311ae76e6SXin Long flags = SCTP_STREAM_RESET_DENIED; 80411ae76e6SXin Long else 80511ae76e6SXin Long flags = SCTP_STREAM_RESET_FAILED; 80611ae76e6SXin Long } 80711ae76e6SXin Long 80811ae76e6SXin Long if (req->type == SCTP_PARAM_RESET_OUT_REQUEST) { 80911ae76e6SXin Long struct sctp_strreset_outreq *outreq; 810edb12f2dSXin Long __u16 *str_p; 81111ae76e6SXin Long 81211ae76e6SXin Long outreq = (struct sctp_strreset_outreq *)req; 813edb12f2dSXin Long str_p = outreq->list_of_streams; 81411ae76e6SXin Long nums = (ntohs(outreq->param_hdr.length) - sizeof(*outreq)) / 2; 81511ae76e6SXin Long 81611ae76e6SXin Long if (result == SCTP_STRRESET_PERFORMED) { 81711ae76e6SXin Long if (nums) { 81811ae76e6SXin Long for (i = 0; i < nums; i++) 81911ae76e6SXin Long stream->out[ntohs(str_p[i])].ssn = 0; 82011ae76e6SXin Long } else { 82111ae76e6SXin Long for (i = 0; i < stream->outcnt; i++) 82211ae76e6SXin Long stream->out[i].ssn = 0; 82311ae76e6SXin Long } 82411ae76e6SXin Long 82511ae76e6SXin Long flags = SCTP_STREAM_RESET_OUTGOING_SSN; 82611ae76e6SXin Long } 82711ae76e6SXin Long 82811ae76e6SXin Long for (i = 0; i < stream->outcnt; i++) 82911ae76e6SXin Long stream->out[i].state = SCTP_STREAM_OPEN; 83011ae76e6SXin Long 83111ae76e6SXin Long *evp = sctp_ulpevent_make_stream_reset_event(asoc, flags, 83211ae76e6SXin Long nums, str_p, GFP_ATOMIC); 83311ae76e6SXin Long } else if (req->type == SCTP_PARAM_RESET_IN_REQUEST) { 83411ae76e6SXin Long struct sctp_strreset_inreq *inreq; 835edb12f2dSXin Long __u16 *str_p; 83611ae76e6SXin Long 83711ae76e6SXin Long /* if the result is performed, it's impossible for inreq */ 83811ae76e6SXin Long if (result == SCTP_STRRESET_PERFORMED) 83911ae76e6SXin Long return NULL; 84011ae76e6SXin Long 84111ae76e6SXin Long inreq = (struct sctp_strreset_inreq *)req; 842edb12f2dSXin Long str_p = inreq->list_of_streams; 84311ae76e6SXin Long nums = (ntohs(inreq->param_hdr.length) - sizeof(*inreq)) / 2; 84411ae76e6SXin Long 84511ae76e6SXin Long *evp = sctp_ulpevent_make_stream_reset_event(asoc, flags, 84611ae76e6SXin Long nums, str_p, GFP_ATOMIC); 84711ae76e6SXin Long } else if (req->type == SCTP_PARAM_RESET_TSN_REQUEST) { 84811ae76e6SXin Long struct sctp_strreset_resptsn *resptsn; 84911ae76e6SXin Long __u32 stsn, rtsn; 85011ae76e6SXin Long 85111ae76e6SXin Long /* check for resptsn, as sctp_verify_reconf didn't do it*/ 85211ae76e6SXin Long if (ntohs(param.p->length) != sizeof(*resptsn)) 85311ae76e6SXin Long return NULL; 85411ae76e6SXin Long 85511ae76e6SXin Long resptsn = (struct sctp_strreset_resptsn *)resp; 85611ae76e6SXin Long stsn = ntohl(resptsn->senders_next_tsn); 85711ae76e6SXin Long rtsn = ntohl(resptsn->receivers_next_tsn); 85811ae76e6SXin Long 85911ae76e6SXin Long if (result == SCTP_STRRESET_PERFORMED) { 86011ae76e6SXin Long __u32 mtsn = sctp_tsnmap_get_max_tsn_seen( 86111ae76e6SXin Long &asoc->peer.tsn_map); 86211ae76e6SXin Long 86311ae76e6SXin Long sctp_ulpq_reasm_flushtsn(&asoc->ulpq, mtsn); 86411ae76e6SXin Long sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC); 86511ae76e6SXin Long 86611ae76e6SXin Long sctp_tsnmap_init(&asoc->peer.tsn_map, 86711ae76e6SXin Long SCTP_TSN_MAP_INITIAL, 86811ae76e6SXin Long stsn, GFP_ATOMIC); 86911ae76e6SXin Long 87011ae76e6SXin Long sctp_outq_free(&asoc->outqueue); 87111ae76e6SXin Long 87211ae76e6SXin Long asoc->next_tsn = rtsn; 87311ae76e6SXin Long asoc->ctsn_ack_point = asoc->next_tsn - 1; 87411ae76e6SXin Long asoc->adv_peer_ack_point = asoc->ctsn_ack_point; 87511ae76e6SXin Long 87611ae76e6SXin Long for (i = 0; i < stream->outcnt; i++) 87711ae76e6SXin Long stream->out[i].ssn = 0; 87811ae76e6SXin Long for (i = 0; i < stream->incnt; i++) 87911ae76e6SXin Long stream->in[i].ssn = 0; 88011ae76e6SXin Long } 88111ae76e6SXin Long 88211ae76e6SXin Long for (i = 0; i < stream->outcnt; i++) 88311ae76e6SXin Long stream->out[i].state = SCTP_STREAM_OPEN; 88411ae76e6SXin Long 88511ae76e6SXin Long *evp = sctp_ulpevent_make_assoc_reset_event(asoc, flags, 88611ae76e6SXin Long stsn, rtsn, GFP_ATOMIC); 88711ae76e6SXin Long } else if (req->type == SCTP_PARAM_RESET_ADD_OUT_STREAMS) { 88811ae76e6SXin Long struct sctp_strreset_addstrm *addstrm; 88911ae76e6SXin Long __u16 number; 89011ae76e6SXin Long 89111ae76e6SXin Long addstrm = (struct sctp_strreset_addstrm *)req; 89211ae76e6SXin Long nums = ntohs(addstrm->number_of_streams); 89311ae76e6SXin Long number = stream->outcnt - nums; 89411ae76e6SXin Long 89511ae76e6SXin Long if (result == SCTP_STRRESET_PERFORMED) 89611ae76e6SXin Long for (i = number; i < stream->outcnt; i++) 89711ae76e6SXin Long stream->out[i].state = SCTP_STREAM_OPEN; 89811ae76e6SXin Long else 89911ae76e6SXin Long stream->outcnt = number; 90011ae76e6SXin Long 90111ae76e6SXin Long *evp = sctp_ulpevent_make_stream_change_event(asoc, flags, 90211ae76e6SXin Long 0, nums, GFP_ATOMIC); 90311ae76e6SXin Long } else if (req->type == SCTP_PARAM_RESET_ADD_IN_STREAMS) { 90411ae76e6SXin Long struct sctp_strreset_addstrm *addstrm; 90511ae76e6SXin Long 90611ae76e6SXin Long /* if the result is performed, it's impossible for addstrm in 90711ae76e6SXin Long * request. 90811ae76e6SXin Long */ 90911ae76e6SXin Long if (result == SCTP_STRRESET_PERFORMED) 91011ae76e6SXin Long return NULL; 91111ae76e6SXin Long 91211ae76e6SXin Long addstrm = (struct sctp_strreset_addstrm *)req; 91311ae76e6SXin Long nums = ntohs(addstrm->number_of_streams); 91411ae76e6SXin Long 91511ae76e6SXin Long *evp = sctp_ulpevent_make_stream_change_event(asoc, flags, 91611ae76e6SXin Long nums, 0, GFP_ATOMIC); 91711ae76e6SXin Long } 91811ae76e6SXin Long 91911ae76e6SXin Long asoc->strreset_outstanding--; 92011ae76e6SXin Long asoc->strreset_outseq++; 92111ae76e6SXin Long 92211ae76e6SXin Long /* remove everything for this reconf request */ 92311ae76e6SXin Long if (!asoc->strreset_outstanding) { 92411ae76e6SXin Long t = asoc->strreset_chunk->transport; 92511ae76e6SXin Long if (del_timer(&t->reconf_timer)) 92611ae76e6SXin Long sctp_transport_put(t); 92711ae76e6SXin Long 92811ae76e6SXin Long sctp_chunk_put(asoc->strreset_chunk); 92911ae76e6SXin Long asoc->strreset_chunk = NULL; 93011ae76e6SXin Long } 93111ae76e6SXin Long 93211ae76e6SXin Long return NULL; 93311ae76e6SXin Long } 934