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