xref: /freebsd/sys/netinet/sctputil.c (revision b0471b4b9596d165f05ecdf023fa7a11963b5f04)
1f8829a4aSRandall Stewart /*-
251369649SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
351369649SPedro F. Giffuni  *
4830d754dSRandall Stewart  * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved.
5807aad63SMichael Tuexen  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
6807aad63SMichael Tuexen  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
7f8829a4aSRandall Stewart  *
8f8829a4aSRandall Stewart  * Redistribution and use in source and binary forms, with or without
9f8829a4aSRandall Stewart  * modification, are permitted provided that the following conditions are met:
10f8829a4aSRandall Stewart  *
11f8829a4aSRandall Stewart  * a) Redistributions of source code must retain the above copyright notice,
12f8829a4aSRandall Stewart  *    this list of conditions and the following disclaimer.
13f8829a4aSRandall Stewart  *
14f8829a4aSRandall Stewart  * b) Redistributions in binary form must reproduce the above copyright
15f8829a4aSRandall Stewart  *    notice, this list of conditions and the following disclaimer in
16f8829a4aSRandall Stewart  *    the documentation and/or other materials provided with the distribution.
17f8829a4aSRandall Stewart  *
18f8829a4aSRandall Stewart  * c) Neither the name of Cisco Systems, Inc. nor the names of its
19f8829a4aSRandall Stewart  *    contributors may be used to endorse or promote products derived
20f8829a4aSRandall Stewart  *    from this software without specific prior written permission.
21f8829a4aSRandall Stewart  *
22f8829a4aSRandall Stewart  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23f8829a4aSRandall Stewart  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
24f8829a4aSRandall Stewart  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25f8829a4aSRandall Stewart  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26f8829a4aSRandall Stewart  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27f8829a4aSRandall Stewart  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28f8829a4aSRandall Stewart  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29f8829a4aSRandall Stewart  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30f8829a4aSRandall Stewart  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31f8829a4aSRandall Stewart  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32f8829a4aSRandall Stewart  * THE POSSIBILITY OF SUCH DAMAGE.
33f8829a4aSRandall Stewart  */
34f8829a4aSRandall Stewart 
35f8829a4aSRandall Stewart #include <sys/cdefs.h>
36f8829a4aSRandall Stewart __FBSDID("$FreeBSD$");
37f8829a4aSRandall Stewart 
38f8829a4aSRandall Stewart #include <netinet/sctp_os.h>
39f8829a4aSRandall Stewart #include <netinet/sctp_pcb.h>
40f8829a4aSRandall Stewart #include <netinet/sctputil.h>
41f8829a4aSRandall Stewart #include <netinet/sctp_var.h>
4242551e99SRandall Stewart #include <netinet/sctp_sysctl.h>
43f8829a4aSRandall Stewart #ifdef INET6
443a51a264SMichael Tuexen #include <netinet6/sctp6_var.h>
45f8829a4aSRandall Stewart #endif
46f8829a4aSRandall Stewart #include <netinet/sctp_header.h>
47f8829a4aSRandall Stewart #include <netinet/sctp_output.h>
48f8829a4aSRandall Stewart #include <netinet/sctp_uio.h>
49f8829a4aSRandall Stewart #include <netinet/sctp_timer.h>
5046bf534cSMichael Tuexen #include <netinet/sctp_indata.h>
51f8829a4aSRandall Stewart #include <netinet/sctp_auth.h>
52f8829a4aSRandall Stewart #include <netinet/sctp_asconf.h>
53f7517433SRandall Stewart #include <netinet/sctp_bsd_addr.h>
5410e0318aSMichael Tuexen #if defined(INET6) || defined(INET)
5510e0318aSMichael Tuexen #include <netinet/tcp_var.h>
5610e0318aSMichael Tuexen #endif
573a51a264SMichael Tuexen #include <netinet/udp.h>
583a51a264SMichael Tuexen #include <netinet/udp_var.h>
593a51a264SMichael Tuexen #include <sys/proc.h>
60fd7af143SMichael Tuexen #ifdef INET6
61fd7af143SMichael Tuexen #include <netinet/icmp6.h>
62fd7af143SMichael Tuexen #endif
63f8829a4aSRandall Stewart 
64f8829a4aSRandall Stewart 
65b9e7085aSRandall Stewart #ifndef KTR_SCTP
66b9e7085aSRandall Stewart #define KTR_SCTP KTR_SUBSYS
6780fefe0aSRandall Stewart #endif
68f8829a4aSRandall Stewart 
69ed654363SMichael Tuexen extern const struct sctp_cc_functions sctp_cc_functions[];
70ed654363SMichael Tuexen extern const struct sctp_ss_functions sctp_ss_functions[];
710e9a9c10SMichael Tuexen 
72f8829a4aSRandall Stewart void
73dcb68fbaSMichael Tuexen sctp_sblog(struct sockbuf *sb, struct sctp_tcb *stcb, int from, int incr)
74f8829a4aSRandall Stewart {
75c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
76c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
77f8829a4aSRandall Stewart 
7880fefe0aSRandall Stewart 	sctp_clog.x.sb.stcb = stcb;
794e88d37aSMichael Tuexen 	sctp_clog.x.sb.so_sbcc = sb->sb_cc;
80f8829a4aSRandall Stewart 	if (stcb)
814e88d37aSMichael Tuexen 		sctp_clog.x.sb.stcb_sbcc = stcb->asoc.sb_cc;
82f8829a4aSRandall Stewart 	else
8380fefe0aSRandall Stewart 		sctp_clog.x.sb.stcb_sbcc = 0;
8480fefe0aSRandall Stewart 	sctp_clog.x.sb.incr = incr;
85c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
8680fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_SB,
8780fefe0aSRandall Stewart 	    from,
8880fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
8980fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
9080fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
9180fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
92c692df45SMichael Tuexen #endif
93f8829a4aSRandall Stewart }
94f8829a4aSRandall Stewart 
95f8829a4aSRandall Stewart void
96f8829a4aSRandall Stewart sctp_log_closing(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int16_t loc)
97f8829a4aSRandall Stewart {
98c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
99c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
100f8829a4aSRandall Stewart 
10180fefe0aSRandall Stewart 	sctp_clog.x.close.inp = (void *)inp;
10280fefe0aSRandall Stewart 	sctp_clog.x.close.sctp_flags = inp->sctp_flags;
103f8829a4aSRandall Stewart 	if (stcb) {
10480fefe0aSRandall Stewart 		sctp_clog.x.close.stcb = (void *)stcb;
10580fefe0aSRandall Stewart 		sctp_clog.x.close.state = (uint16_t)stcb->asoc.state;
106f8829a4aSRandall Stewart 	} else {
10780fefe0aSRandall Stewart 		sctp_clog.x.close.stcb = 0;
10880fefe0aSRandall Stewart 		sctp_clog.x.close.state = 0;
109f8829a4aSRandall Stewart 	}
11080fefe0aSRandall Stewart 	sctp_clog.x.close.loc = loc;
111c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
11280fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_CLOSE,
11380fefe0aSRandall Stewart 	    0,
11480fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
11580fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
11680fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
11780fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
118c692df45SMichael Tuexen #endif
119f8829a4aSRandall Stewart }
120f8829a4aSRandall Stewart 
121f8829a4aSRandall Stewart void
122f8829a4aSRandall Stewart rto_logging(struct sctp_nets *net, int from)
123f8829a4aSRandall Stewart {
124c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
125c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
126f8829a4aSRandall Stewart 
127bfefd190SRandall Stewart 	memset(&sctp_clog, 0, sizeof(sctp_clog));
12880fefe0aSRandall Stewart 	sctp_clog.x.rto.net = (void *)net;
129be1d9176SMichael Tuexen 	sctp_clog.x.rto.rtt = net->rtt / 1000;
130c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
13180fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_RTT,
13280fefe0aSRandall Stewart 	    from,
13380fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
13480fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
13580fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
13680fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
137c692df45SMichael Tuexen #endif
138f8829a4aSRandall Stewart }
139f8829a4aSRandall Stewart 
140f8829a4aSRandall Stewart void
1416a91f103SRandall Stewart sctp_log_strm_del_alt(struct sctp_tcb *stcb, uint32_t tsn, uint16_t sseq, uint16_t stream, int from)
142f8829a4aSRandall Stewart {
143c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
144c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
145f8829a4aSRandall Stewart 
14680fefe0aSRandall Stewart 	sctp_clog.x.strlog.stcb = stcb;
14780fefe0aSRandall Stewart 	sctp_clog.x.strlog.n_tsn = tsn;
14880fefe0aSRandall Stewart 	sctp_clog.x.strlog.n_sseq = sseq;
14980fefe0aSRandall Stewart 	sctp_clog.x.strlog.e_tsn = 0;
15080fefe0aSRandall Stewart 	sctp_clog.x.strlog.e_sseq = 0;
15180fefe0aSRandall Stewart 	sctp_clog.x.strlog.strm = stream;
152c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
15380fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_STRM,
15480fefe0aSRandall Stewart 	    from,
15580fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
15680fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
15780fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
15880fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
159c692df45SMichael Tuexen #endif
160f8829a4aSRandall Stewart }
161f8829a4aSRandall Stewart 
162f8829a4aSRandall Stewart void
163f8829a4aSRandall Stewart sctp_log_nagle_event(struct sctp_tcb *stcb, int action)
164f8829a4aSRandall Stewart {
165c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
166c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
167f8829a4aSRandall Stewart 
16880fefe0aSRandall Stewart 	sctp_clog.x.nagle.stcb = (void *)stcb;
16980fefe0aSRandall Stewart 	sctp_clog.x.nagle.total_flight = stcb->asoc.total_flight;
17080fefe0aSRandall Stewart 	sctp_clog.x.nagle.total_in_queue = stcb->asoc.total_output_queue_size;
17180fefe0aSRandall Stewart 	sctp_clog.x.nagle.count_in_queue = stcb->asoc.chunks_on_out_queue;
17280fefe0aSRandall Stewart 	sctp_clog.x.nagle.count_in_flight = stcb->asoc.total_flight_count;
173c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
17480fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_NAGLE,
17580fefe0aSRandall Stewart 	    action,
17680fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
17780fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
17880fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
17980fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
180c692df45SMichael Tuexen #endif
181f8829a4aSRandall Stewart }
182f8829a4aSRandall Stewart 
183f8829a4aSRandall Stewart void
184f8829a4aSRandall Stewart sctp_log_sack(uint32_t old_cumack, uint32_t cumack, uint32_t tsn, uint16_t gaps, uint16_t dups, int from)
185f8829a4aSRandall Stewart {
186c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
187c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
188f8829a4aSRandall Stewart 
18980fefe0aSRandall Stewart 	sctp_clog.x.sack.cumack = cumack;
19080fefe0aSRandall Stewart 	sctp_clog.x.sack.oldcumack = old_cumack;
19180fefe0aSRandall Stewart 	sctp_clog.x.sack.tsn = tsn;
19280fefe0aSRandall Stewart 	sctp_clog.x.sack.numGaps = gaps;
19380fefe0aSRandall Stewart 	sctp_clog.x.sack.numDups = dups;
194c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
19580fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_SACK,
19680fefe0aSRandall Stewart 	    from,
19780fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
19880fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
19980fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
20080fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
201c692df45SMichael Tuexen #endif
202f8829a4aSRandall Stewart }
203f8829a4aSRandall Stewart 
204f8829a4aSRandall Stewart void
205f8829a4aSRandall Stewart sctp_log_map(uint32_t map, uint32_t cum, uint32_t high, int from)
206f8829a4aSRandall Stewart {
207c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
208c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
209f8829a4aSRandall Stewart 
210bfefd190SRandall Stewart 	memset(&sctp_clog, 0, sizeof(sctp_clog));
21180fefe0aSRandall Stewart 	sctp_clog.x.map.base = map;
21280fefe0aSRandall Stewart 	sctp_clog.x.map.cum = cum;
21380fefe0aSRandall Stewart 	sctp_clog.x.map.high = high;
214c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
21580fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_MAP,
21680fefe0aSRandall Stewart 	    from,
21780fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
21880fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
21980fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
22080fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
221c692df45SMichael Tuexen #endif
222f8829a4aSRandall Stewart }
223f8829a4aSRandall Stewart 
224f8829a4aSRandall Stewart void
225dcb68fbaSMichael Tuexen sctp_log_fr(uint32_t biggest_tsn, uint32_t biggest_new_tsn, uint32_t tsn, int from)
226f8829a4aSRandall Stewart {
227c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
228c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
229f8829a4aSRandall Stewart 
230bfefd190SRandall Stewart 	memset(&sctp_clog, 0, sizeof(sctp_clog));
23180fefe0aSRandall Stewart 	sctp_clog.x.fr.largest_tsn = biggest_tsn;
23280fefe0aSRandall Stewart 	sctp_clog.x.fr.largest_new_tsn = biggest_new_tsn;
23380fefe0aSRandall Stewart 	sctp_clog.x.fr.tsn = tsn;
234c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
23580fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_FR,
23680fefe0aSRandall Stewart 	    from,
23780fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
23880fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
23980fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
24080fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
241c692df45SMichael Tuexen #endif
242f8829a4aSRandall Stewart }
243f8829a4aSRandall Stewart 
2444be807c4SMichael Tuexen #ifdef SCTP_MBUF_LOGGING
245f8829a4aSRandall Stewart void
246f8829a4aSRandall Stewart sctp_log_mb(struct mbuf *m, int from)
247f8829a4aSRandall Stewart {
248c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
249c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
250f8829a4aSRandall Stewart 
25180fefe0aSRandall Stewart 	sctp_clog.x.mb.mp = m;
25280fefe0aSRandall Stewart 	sctp_clog.x.mb.mbuf_flags = (uint8_t)(SCTP_BUF_GET_FLAGS(m));
25380fefe0aSRandall Stewart 	sctp_clog.x.mb.size = (uint16_t)(SCTP_BUF_LEN(m));
25480fefe0aSRandall Stewart 	sctp_clog.x.mb.data = SCTP_BUF_AT(m, 0);
255139bc87fSRandall Stewart 	if (SCTP_BUF_IS_EXTENDED(m)) {
25680fefe0aSRandall Stewart 		sctp_clog.x.mb.ext = SCTP_BUF_EXTEND_BASE(m);
25780fefe0aSRandall Stewart 		sctp_clog.x.mb.refcnt = (uint8_t)(SCTP_BUF_EXTEND_REFCNT(m));
258f8829a4aSRandall Stewart 	} else {
25980fefe0aSRandall Stewart 		sctp_clog.x.mb.ext = 0;
26080fefe0aSRandall Stewart 		sctp_clog.x.mb.refcnt = 0;
261f8829a4aSRandall Stewart 	}
262c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
26380fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_MBUF,
26480fefe0aSRandall Stewart 	    from,
26580fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
26680fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
26780fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
26880fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
269c692df45SMichael Tuexen #endif
270f8829a4aSRandall Stewart }
271f8829a4aSRandall Stewart 
272f8829a4aSRandall Stewart void
2734be807c4SMichael Tuexen sctp_log_mbc(struct mbuf *m, int from)
2744be807c4SMichael Tuexen {
2754be807c4SMichael Tuexen 	struct mbuf *mat;
2764be807c4SMichael Tuexen 
2774be807c4SMichael Tuexen 	for (mat = m; mat; mat = SCTP_BUF_NEXT(mat)) {
2784be807c4SMichael Tuexen 		sctp_log_mb(mat, from);
2794be807c4SMichael Tuexen 	}
2804be807c4SMichael Tuexen }
2814be807c4SMichael Tuexen #endif
2824be807c4SMichael Tuexen 
2834be807c4SMichael Tuexen void
284dcb68fbaSMichael Tuexen sctp_log_strm_del(struct sctp_queued_to_read *control, struct sctp_queued_to_read *poschk, int from)
285f8829a4aSRandall Stewart {
286c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
287c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
288f8829a4aSRandall Stewart 
289f8829a4aSRandall Stewart 	if (control == NULL) {
290ad81507eSRandall Stewart 		SCTP_PRINTF("Gak log of NULL?\n");
291f8829a4aSRandall Stewart 		return;
292f8829a4aSRandall Stewart 	}
29380fefe0aSRandall Stewart 	sctp_clog.x.strlog.stcb = control->stcb;
29480fefe0aSRandall Stewart 	sctp_clog.x.strlog.n_tsn = control->sinfo_tsn;
29549656eefSMichael Tuexen 	sctp_clog.x.strlog.n_sseq = (uint16_t)control->mid;
29680fefe0aSRandall Stewart 	sctp_clog.x.strlog.strm = control->sinfo_stream;
297f8829a4aSRandall Stewart 	if (poschk != NULL) {
29880fefe0aSRandall Stewart 		sctp_clog.x.strlog.e_tsn = poschk->sinfo_tsn;
29949656eefSMichael Tuexen 		sctp_clog.x.strlog.e_sseq = (uint16_t)poschk->mid;
300f8829a4aSRandall Stewart 	} else {
30180fefe0aSRandall Stewart 		sctp_clog.x.strlog.e_tsn = 0;
30280fefe0aSRandall Stewart 		sctp_clog.x.strlog.e_sseq = 0;
303f8829a4aSRandall Stewart 	}
304c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
30580fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_STRM,
30680fefe0aSRandall Stewart 	    from,
30780fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
30880fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
30980fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
31080fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
311c692df45SMichael Tuexen #endif
312f8829a4aSRandall Stewart }
313f8829a4aSRandall Stewart 
314f8829a4aSRandall Stewart void
315f8829a4aSRandall Stewart sctp_log_cwnd(struct sctp_tcb *stcb, struct sctp_nets *net, int augment, uint8_t from)
316f8829a4aSRandall Stewart {
317c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
318c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
319f8829a4aSRandall Stewart 
32080fefe0aSRandall Stewart 	sctp_clog.x.cwnd.net = net;
321f8829a4aSRandall Stewart 	if (stcb->asoc.send_queue_cnt > 255)
32280fefe0aSRandall Stewart 		sctp_clog.x.cwnd.cnt_in_send = 255;
323f8829a4aSRandall Stewart 	else
32480fefe0aSRandall Stewart 		sctp_clog.x.cwnd.cnt_in_send = stcb->asoc.send_queue_cnt;
325f8829a4aSRandall Stewart 	if (stcb->asoc.stream_queue_cnt > 255)
32680fefe0aSRandall Stewart 		sctp_clog.x.cwnd.cnt_in_str = 255;
327f8829a4aSRandall Stewart 	else
32880fefe0aSRandall Stewart 		sctp_clog.x.cwnd.cnt_in_str = stcb->asoc.stream_queue_cnt;
329f8829a4aSRandall Stewart 
330f8829a4aSRandall Stewart 	if (net) {
33180fefe0aSRandall Stewart 		sctp_clog.x.cwnd.cwnd_new_value = net->cwnd;
33280fefe0aSRandall Stewart 		sctp_clog.x.cwnd.inflight = net->flight_size;
33380fefe0aSRandall Stewart 		sctp_clog.x.cwnd.pseudo_cumack = net->pseudo_cumack;
33480fefe0aSRandall Stewart 		sctp_clog.x.cwnd.meets_pseudo_cumack = net->new_pseudo_cumack;
33580fefe0aSRandall Stewart 		sctp_clog.x.cwnd.need_new_pseudo_cumack = net->find_pseudo_cumack;
336f8829a4aSRandall Stewart 	}
337f8829a4aSRandall Stewart 	if (SCTP_CWNDLOG_PRESEND == from) {
33880fefe0aSRandall Stewart 		sctp_clog.x.cwnd.meets_pseudo_cumack = stcb->asoc.peers_rwnd;
339f8829a4aSRandall Stewart 	}
34080fefe0aSRandall Stewart 	sctp_clog.x.cwnd.cwnd_augment = augment;
341c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
34280fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_CWND,
34380fefe0aSRandall Stewart 	    from,
34480fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
34580fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
34680fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
34780fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
348c692df45SMichael Tuexen #endif
349f8829a4aSRandall Stewart }
350f8829a4aSRandall Stewart 
351f8829a4aSRandall Stewart void
352f8829a4aSRandall Stewart sctp_log_lock(struct sctp_inpcb *inp, struct sctp_tcb *stcb, uint8_t from)
353f8829a4aSRandall Stewart {
354c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
355c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
356f8829a4aSRandall Stewart 
357bfefd190SRandall Stewart 	memset(&sctp_clog, 0, sizeof(sctp_clog));
35803b0b021SRandall Stewart 	if (inp) {
35980fefe0aSRandall Stewart 		sctp_clog.x.lock.sock = (void *)inp->sctp_socket;
36003b0b021SRandall Stewart 
36103b0b021SRandall Stewart 	} else {
36280fefe0aSRandall Stewart 		sctp_clog.x.lock.sock = (void *)NULL;
36303b0b021SRandall Stewart 	}
36480fefe0aSRandall Stewart 	sctp_clog.x.lock.inp = (void *)inp;
365f8829a4aSRandall Stewart 	if (stcb) {
36680fefe0aSRandall Stewart 		sctp_clog.x.lock.tcb_lock = mtx_owned(&stcb->tcb_mtx);
367f8829a4aSRandall Stewart 	} else {
36880fefe0aSRandall Stewart 		sctp_clog.x.lock.tcb_lock = SCTP_LOCK_UNKNOWN;
369f8829a4aSRandall Stewart 	}
370f8829a4aSRandall Stewart 	if (inp) {
37180fefe0aSRandall Stewart 		sctp_clog.x.lock.inp_lock = mtx_owned(&inp->inp_mtx);
37280fefe0aSRandall Stewart 		sctp_clog.x.lock.create_lock = mtx_owned(&inp->inp_create_mtx);
373f8829a4aSRandall Stewart 	} else {
37480fefe0aSRandall Stewart 		sctp_clog.x.lock.inp_lock = SCTP_LOCK_UNKNOWN;
37580fefe0aSRandall Stewart 		sctp_clog.x.lock.create_lock = SCTP_LOCK_UNKNOWN;
376f8829a4aSRandall Stewart 	}
377b3f1ea41SRandall Stewart 	sctp_clog.x.lock.info_lock = rw_wowned(&SCTP_BASE_INFO(ipi_ep_mtx));
37852129fcdSRandall Stewart 	if (inp && (inp->sctp_socket)) {
37980fefe0aSRandall Stewart 		sctp_clog.x.lock.sock_lock = mtx_owned(&(inp->sctp_socket->so_rcv.sb_mtx));
38080fefe0aSRandall Stewart 		sctp_clog.x.lock.sockrcvbuf_lock = mtx_owned(&(inp->sctp_socket->so_rcv.sb_mtx));
38180fefe0aSRandall Stewart 		sctp_clog.x.lock.socksndbuf_lock = mtx_owned(&(inp->sctp_socket->so_snd.sb_mtx));
382f8829a4aSRandall Stewart 	} else {
38380fefe0aSRandall Stewart 		sctp_clog.x.lock.sock_lock = SCTP_LOCK_UNKNOWN;
38480fefe0aSRandall Stewart 		sctp_clog.x.lock.sockrcvbuf_lock = SCTP_LOCK_UNKNOWN;
38580fefe0aSRandall Stewart 		sctp_clog.x.lock.socksndbuf_lock = SCTP_LOCK_UNKNOWN;
386f8829a4aSRandall Stewart 	}
387c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
38880fefe0aSRandall Stewart 	    SCTP_LOG_LOCK_EVENT,
38980fefe0aSRandall Stewart 	    from,
39080fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
39180fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
39280fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
39380fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
394c692df45SMichael Tuexen #endif
395f8829a4aSRandall Stewart }
396f8829a4aSRandall Stewart 
397f8829a4aSRandall Stewart void
398f8829a4aSRandall Stewart sctp_log_maxburst(struct sctp_tcb *stcb, struct sctp_nets *net, int error, int burst, uint8_t from)
399f8829a4aSRandall Stewart {
400c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
401c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
402f8829a4aSRandall Stewart 
403bfefd190SRandall Stewart 	memset(&sctp_clog, 0, sizeof(sctp_clog));
40480fefe0aSRandall Stewart 	sctp_clog.x.cwnd.net = net;
40580fefe0aSRandall Stewart 	sctp_clog.x.cwnd.cwnd_new_value = error;
40680fefe0aSRandall Stewart 	sctp_clog.x.cwnd.inflight = net->flight_size;
40780fefe0aSRandall Stewart 	sctp_clog.x.cwnd.cwnd_augment = burst;
408f8829a4aSRandall Stewart 	if (stcb->asoc.send_queue_cnt > 255)
40980fefe0aSRandall Stewart 		sctp_clog.x.cwnd.cnt_in_send = 255;
410f8829a4aSRandall Stewart 	else
41180fefe0aSRandall Stewart 		sctp_clog.x.cwnd.cnt_in_send = stcb->asoc.send_queue_cnt;
412f8829a4aSRandall Stewart 	if (stcb->asoc.stream_queue_cnt > 255)
41380fefe0aSRandall Stewart 		sctp_clog.x.cwnd.cnt_in_str = 255;
414f8829a4aSRandall Stewart 	else
41580fefe0aSRandall Stewart 		sctp_clog.x.cwnd.cnt_in_str = stcb->asoc.stream_queue_cnt;
416c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
41780fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_MAXBURST,
41880fefe0aSRandall Stewart 	    from,
41980fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
42080fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
42180fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
42280fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
423c692df45SMichael Tuexen #endif
424f8829a4aSRandall Stewart }
425f8829a4aSRandall Stewart 
426f8829a4aSRandall Stewart void
427f8829a4aSRandall Stewart sctp_log_rwnd(uint8_t from, uint32_t peers_rwnd, uint32_t snd_size, uint32_t overhead)
428f8829a4aSRandall Stewart {
429c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
430c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
431f8829a4aSRandall Stewart 
43280fefe0aSRandall Stewart 	sctp_clog.x.rwnd.rwnd = peers_rwnd;
43380fefe0aSRandall Stewart 	sctp_clog.x.rwnd.send_size = snd_size;
43480fefe0aSRandall Stewart 	sctp_clog.x.rwnd.overhead = overhead;
43580fefe0aSRandall Stewart 	sctp_clog.x.rwnd.new_rwnd = 0;
436c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
43780fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_RWND,
43880fefe0aSRandall Stewart 	    from,
43980fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
44080fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
44180fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
44280fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
443c692df45SMichael Tuexen #endif
444f8829a4aSRandall Stewart }
445f8829a4aSRandall Stewart 
446f8829a4aSRandall Stewart void
447f8829a4aSRandall Stewart sctp_log_rwnd_set(uint8_t from, uint32_t peers_rwnd, uint32_t flight_size, uint32_t overhead, uint32_t a_rwndval)
448f8829a4aSRandall Stewart {
449c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
450c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
451f8829a4aSRandall Stewart 
45280fefe0aSRandall Stewart 	sctp_clog.x.rwnd.rwnd = peers_rwnd;
45380fefe0aSRandall Stewart 	sctp_clog.x.rwnd.send_size = flight_size;
45480fefe0aSRandall Stewart 	sctp_clog.x.rwnd.overhead = overhead;
45580fefe0aSRandall Stewart 	sctp_clog.x.rwnd.new_rwnd = a_rwndval;
456c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
45780fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_RWND,
45880fefe0aSRandall Stewart 	    from,
45980fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
46080fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
46180fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
46280fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
463c692df45SMichael Tuexen #endif
464f8829a4aSRandall Stewart }
465f8829a4aSRandall Stewart 
4664be807c4SMichael Tuexen #ifdef SCTP_MBCNT_LOGGING
4674be807c4SMichael Tuexen static void
468f8829a4aSRandall Stewart sctp_log_mbcnt(uint8_t from, uint32_t total_oq, uint32_t book, uint32_t total_mbcnt_q, uint32_t mbcnt)
469f8829a4aSRandall Stewart {
470c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
471c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
472f8829a4aSRandall Stewart 
47380fefe0aSRandall Stewart 	sctp_clog.x.mbcnt.total_queue_size = total_oq;
47480fefe0aSRandall Stewart 	sctp_clog.x.mbcnt.size_change = book;
47580fefe0aSRandall Stewart 	sctp_clog.x.mbcnt.total_queue_mb_size = total_mbcnt_q;
47680fefe0aSRandall Stewart 	sctp_clog.x.mbcnt.mbcnt_change = mbcnt;
477c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
47880fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_MBCNT,
47980fefe0aSRandall Stewart 	    from,
48080fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
48180fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
48280fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
48380fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
484c692df45SMichael Tuexen #endif
485f8829a4aSRandall Stewart }
4864be807c4SMichael Tuexen #endif
4874be807c4SMichael Tuexen 
488f8829a4aSRandall Stewart void
489f8829a4aSRandall Stewart sctp_misc_ints(uint8_t from, uint32_t a, uint32_t b, uint32_t c, uint32_t d)
490f8829a4aSRandall Stewart {
491c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
492c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
49380fefe0aSRandall Stewart 	    SCTP_LOG_MISC_EVENT,
49480fefe0aSRandall Stewart 	    from,
49580fefe0aSRandall Stewart 	    a, b, c, d);
496c692df45SMichael Tuexen #endif
497f8829a4aSRandall Stewart }
498f8829a4aSRandall Stewart 
499f8829a4aSRandall Stewart void
5007215cc1bSMichael Tuexen sctp_wakeup_log(struct sctp_tcb *stcb, uint32_t wake_cnt, int from)
501f8829a4aSRandall Stewart {
502c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
503c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
504f8829a4aSRandall Stewart 
50580fefe0aSRandall Stewart 	sctp_clog.x.wake.stcb = (void *)stcb;
50680fefe0aSRandall Stewart 	sctp_clog.x.wake.wake_cnt = wake_cnt;
50780fefe0aSRandall Stewart 	sctp_clog.x.wake.flight = stcb->asoc.total_flight_count;
50880fefe0aSRandall Stewart 	sctp_clog.x.wake.send_q = stcb->asoc.send_queue_cnt;
50980fefe0aSRandall Stewart 	sctp_clog.x.wake.sent_q = stcb->asoc.sent_queue_cnt;
510f8829a4aSRandall Stewart 
511f8829a4aSRandall Stewart 	if (stcb->asoc.stream_queue_cnt < 0xff)
51280fefe0aSRandall Stewart 		sctp_clog.x.wake.stream_qcnt = (uint8_t)stcb->asoc.stream_queue_cnt;
513f8829a4aSRandall Stewart 	else
51480fefe0aSRandall Stewart 		sctp_clog.x.wake.stream_qcnt = 0xff;
515f8829a4aSRandall Stewart 
516f8829a4aSRandall Stewart 	if (stcb->asoc.chunks_on_out_queue < 0xff)
51780fefe0aSRandall Stewart 		sctp_clog.x.wake.chunks_on_oque = (uint8_t)stcb->asoc.chunks_on_out_queue;
518f8829a4aSRandall Stewart 	else
51980fefe0aSRandall Stewart 		sctp_clog.x.wake.chunks_on_oque = 0xff;
520f8829a4aSRandall Stewart 
52180fefe0aSRandall Stewart 	sctp_clog.x.wake.sctpflags = 0;
522f8829a4aSRandall Stewart 	/* set in the defered mode stuff */
523f8829a4aSRandall Stewart 	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE)
52480fefe0aSRandall Stewart 		sctp_clog.x.wake.sctpflags |= 1;
525f8829a4aSRandall Stewart 	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT)
52680fefe0aSRandall Stewart 		sctp_clog.x.wake.sctpflags |= 2;
527f8829a4aSRandall Stewart 	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT)
52880fefe0aSRandall Stewart 		sctp_clog.x.wake.sctpflags |= 4;
529f8829a4aSRandall Stewart 	/* what about the sb */
530f8829a4aSRandall Stewart 	if (stcb->sctp_socket) {
531f8829a4aSRandall Stewart 		struct socket *so = stcb->sctp_socket;
532f8829a4aSRandall Stewart 
53380fefe0aSRandall Stewart 		sctp_clog.x.wake.sbflags = (uint8_t)((so->so_snd.sb_flags & 0x00ff));
534f8829a4aSRandall Stewart 	} else {
53580fefe0aSRandall Stewart 		sctp_clog.x.wake.sbflags = 0xff;
536f8829a4aSRandall Stewart 	}
537c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
53880fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_WAKE,
53980fefe0aSRandall Stewart 	    from,
54080fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
54180fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
54280fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
54380fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
544c692df45SMichael Tuexen #endif
545f8829a4aSRandall Stewart }
546f8829a4aSRandall Stewart 
547f8829a4aSRandall Stewart void
5489a8e3088SMichael Tuexen sctp_log_block(uint8_t from, struct sctp_association *asoc, size_t sendlen)
549f8829a4aSRandall Stewart {
550c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
551c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
552f8829a4aSRandall Stewart 
55380fefe0aSRandall Stewart 	sctp_clog.x.blk.onsb = asoc->total_output_queue_size;
55480fefe0aSRandall Stewart 	sctp_clog.x.blk.send_sent_qcnt = (uint16_t)(asoc->send_queue_cnt + asoc->sent_queue_cnt);
55580fefe0aSRandall Stewart 	sctp_clog.x.blk.peer_rwnd = asoc->peers_rwnd;
55680fefe0aSRandall Stewart 	sctp_clog.x.blk.stream_qcnt = (uint16_t)asoc->stream_queue_cnt;
55780fefe0aSRandall Stewart 	sctp_clog.x.blk.chunks_on_oque = (uint16_t)asoc->chunks_on_out_queue;
55880fefe0aSRandall Stewart 	sctp_clog.x.blk.flight_size = (uint16_t)(asoc->total_flight / 1024);
5599a8e3088SMichael Tuexen 	sctp_clog.x.blk.sndlen = (uint32_t)sendlen;
560c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
56180fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_BLOCK,
56280fefe0aSRandall Stewart 	    from,
56380fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
56480fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
56580fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
56680fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
567c692df45SMichael Tuexen #endif
568f8829a4aSRandall Stewart }
569f8829a4aSRandall Stewart 
570f8829a4aSRandall Stewart int
5717215cc1bSMichael Tuexen sctp_fill_stat_log(void *optval SCTP_UNUSED, size_t *optsize SCTP_UNUSED)
572f8829a4aSRandall Stewart {
57380fefe0aSRandall Stewart 	/* May need to fix this if ktrdump does not work */
574f8829a4aSRandall Stewart 	return (0);
575f8829a4aSRandall Stewart }
576f8829a4aSRandall Stewart 
577f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED
578f8829a4aSRandall Stewart uint8_t sctp_audit_data[SCTP_AUDIT_SIZE][2];
579f8829a4aSRandall Stewart static int sctp_audit_indx = 0;
580f8829a4aSRandall Stewart 
581f8829a4aSRandall Stewart static
582f8829a4aSRandall Stewart void
583f8829a4aSRandall Stewart sctp_print_audit_report(void)
584f8829a4aSRandall Stewart {
585f8829a4aSRandall Stewart 	int i;
586f8829a4aSRandall Stewart 	int cnt;
587f8829a4aSRandall Stewart 
588f8829a4aSRandall Stewart 	cnt = 0;
589f8829a4aSRandall Stewart 	for (i = sctp_audit_indx; i < SCTP_AUDIT_SIZE; i++) {
590f8829a4aSRandall Stewart 		if ((sctp_audit_data[i][0] == 0xe0) &&
591f8829a4aSRandall Stewart 		    (sctp_audit_data[i][1] == 0x01)) {
592f8829a4aSRandall Stewart 			cnt = 0;
593ad81507eSRandall Stewart 			SCTP_PRINTF("\n");
594f8829a4aSRandall Stewart 		} else if (sctp_audit_data[i][0] == 0xf0) {
595f8829a4aSRandall Stewart 			cnt = 0;
596ad81507eSRandall Stewart 			SCTP_PRINTF("\n");
597f8829a4aSRandall Stewart 		} else if ((sctp_audit_data[i][0] == 0xc0) &&
598f8829a4aSRandall Stewart 		    (sctp_audit_data[i][1] == 0x01)) {
599ad81507eSRandall Stewart 			SCTP_PRINTF("\n");
600f8829a4aSRandall Stewart 			cnt = 0;
601f8829a4aSRandall Stewart 		}
602ad81507eSRandall Stewart 		SCTP_PRINTF("%2.2x%2.2x ", (uint32_t)sctp_audit_data[i][0],
603f8829a4aSRandall Stewart 		    (uint32_t)sctp_audit_data[i][1]);
604f8829a4aSRandall Stewart 		cnt++;
605f8829a4aSRandall Stewart 		if ((cnt % 14) == 0)
606ad81507eSRandall Stewart 			SCTP_PRINTF("\n");
607f8829a4aSRandall Stewart 	}
608f8829a4aSRandall Stewart 	for (i = 0; i < sctp_audit_indx; i++) {
609f8829a4aSRandall Stewart 		if ((sctp_audit_data[i][0] == 0xe0) &&
610f8829a4aSRandall Stewart 		    (sctp_audit_data[i][1] == 0x01)) {
611f8829a4aSRandall Stewart 			cnt = 0;
612ad81507eSRandall Stewart 			SCTP_PRINTF("\n");
613f8829a4aSRandall Stewart 		} else if (sctp_audit_data[i][0] == 0xf0) {
614f8829a4aSRandall Stewart 			cnt = 0;
615ad81507eSRandall Stewart 			SCTP_PRINTF("\n");
616f8829a4aSRandall Stewart 		} else if ((sctp_audit_data[i][0] == 0xc0) &&
617f8829a4aSRandall Stewart 		    (sctp_audit_data[i][1] == 0x01)) {
618ad81507eSRandall Stewart 			SCTP_PRINTF("\n");
619f8829a4aSRandall Stewart 			cnt = 0;
620f8829a4aSRandall Stewart 		}
621ad81507eSRandall Stewart 		SCTP_PRINTF("%2.2x%2.2x ", (uint32_t)sctp_audit_data[i][0],
622f8829a4aSRandall Stewart 		    (uint32_t)sctp_audit_data[i][1]);
623f8829a4aSRandall Stewart 		cnt++;
624f8829a4aSRandall Stewart 		if ((cnt % 14) == 0)
625ad81507eSRandall Stewart 			SCTP_PRINTF("\n");
626f8829a4aSRandall Stewart 	}
627ad81507eSRandall Stewart 	SCTP_PRINTF("\n");
628f8829a4aSRandall Stewart }
629f8829a4aSRandall Stewart 
630f8829a4aSRandall Stewart void
631f8829a4aSRandall Stewart sctp_auditing(int from, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
632f8829a4aSRandall Stewart     struct sctp_nets *net)
633f8829a4aSRandall Stewart {
634f8829a4aSRandall Stewart 	int resend_cnt, tot_out, rep, tot_book_cnt;
635f8829a4aSRandall Stewart 	struct sctp_nets *lnet;
636f8829a4aSRandall Stewart 	struct sctp_tmit_chunk *chk;
637f8829a4aSRandall Stewart 
638f8829a4aSRandall Stewart 	sctp_audit_data[sctp_audit_indx][0] = 0xAA;
639f8829a4aSRandall Stewart 	sctp_audit_data[sctp_audit_indx][1] = 0x000000ff & from;
640f8829a4aSRandall Stewart 	sctp_audit_indx++;
641f8829a4aSRandall Stewart 	if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
642f8829a4aSRandall Stewart 		sctp_audit_indx = 0;
643f8829a4aSRandall Stewart 	}
644f8829a4aSRandall Stewart 	if (inp == NULL) {
645f8829a4aSRandall Stewart 		sctp_audit_data[sctp_audit_indx][0] = 0xAF;
646f8829a4aSRandall Stewart 		sctp_audit_data[sctp_audit_indx][1] = 0x01;
647f8829a4aSRandall Stewart 		sctp_audit_indx++;
648f8829a4aSRandall Stewart 		if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
649f8829a4aSRandall Stewart 			sctp_audit_indx = 0;
650f8829a4aSRandall Stewart 		}
651f8829a4aSRandall Stewart 		return;
652f8829a4aSRandall Stewart 	}
653f8829a4aSRandall Stewart 	if (stcb == NULL) {
654f8829a4aSRandall Stewart 		sctp_audit_data[sctp_audit_indx][0] = 0xAF;
655f8829a4aSRandall Stewart 		sctp_audit_data[sctp_audit_indx][1] = 0x02;
656f8829a4aSRandall Stewart 		sctp_audit_indx++;
657f8829a4aSRandall Stewart 		if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
658f8829a4aSRandall Stewart 			sctp_audit_indx = 0;
659f8829a4aSRandall Stewart 		}
660f8829a4aSRandall Stewart 		return;
661f8829a4aSRandall Stewart 	}
662f8829a4aSRandall Stewart 	sctp_audit_data[sctp_audit_indx][0] = 0xA1;
663f8829a4aSRandall Stewart 	sctp_audit_data[sctp_audit_indx][1] =
664f8829a4aSRandall Stewart 	    (0x000000ff & stcb->asoc.sent_queue_retran_cnt);
665f8829a4aSRandall Stewart 	sctp_audit_indx++;
666f8829a4aSRandall Stewart 	if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
667f8829a4aSRandall Stewart 		sctp_audit_indx = 0;
668f8829a4aSRandall Stewart 	}
669f8829a4aSRandall Stewart 	rep = 0;
670f8829a4aSRandall Stewart 	tot_book_cnt = 0;
671f8829a4aSRandall Stewart 	resend_cnt = tot_out = 0;
672f8829a4aSRandall Stewart 	TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
673f8829a4aSRandall Stewart 		if (chk->sent == SCTP_DATAGRAM_RESEND) {
674f8829a4aSRandall Stewart 			resend_cnt++;
675f8829a4aSRandall Stewart 		} else if (chk->sent < SCTP_DATAGRAM_RESEND) {
676f8829a4aSRandall Stewart 			tot_out += chk->book_size;
677f8829a4aSRandall Stewart 			tot_book_cnt++;
678f8829a4aSRandall Stewart 		}
679f8829a4aSRandall Stewart 	}
680f8829a4aSRandall Stewart 	if (resend_cnt != stcb->asoc.sent_queue_retran_cnt) {
681f8829a4aSRandall Stewart 		sctp_audit_data[sctp_audit_indx][0] = 0xAF;
682f8829a4aSRandall Stewart 		sctp_audit_data[sctp_audit_indx][1] = 0xA1;
683f8829a4aSRandall Stewart 		sctp_audit_indx++;
684f8829a4aSRandall Stewart 		if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
685f8829a4aSRandall Stewart 			sctp_audit_indx = 0;
686f8829a4aSRandall Stewart 		}
687ad81507eSRandall Stewart 		SCTP_PRINTF("resend_cnt:%d asoc-tot:%d\n",
688f8829a4aSRandall Stewart 		    resend_cnt, stcb->asoc.sent_queue_retran_cnt);
689f8829a4aSRandall Stewart 		rep = 1;
690f8829a4aSRandall Stewart 		stcb->asoc.sent_queue_retran_cnt = resend_cnt;
691f8829a4aSRandall Stewart 		sctp_audit_data[sctp_audit_indx][0] = 0xA2;
692f8829a4aSRandall Stewart 		sctp_audit_data[sctp_audit_indx][1] =
693f8829a4aSRandall Stewart 		    (0x000000ff & stcb->asoc.sent_queue_retran_cnt);
694f8829a4aSRandall Stewart 		sctp_audit_indx++;
695f8829a4aSRandall Stewart 		if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
696f8829a4aSRandall Stewart 			sctp_audit_indx = 0;
697f8829a4aSRandall Stewart 		}
698f8829a4aSRandall Stewart 	}
699f8829a4aSRandall Stewart 	if (tot_out != stcb->asoc.total_flight) {
700f8829a4aSRandall Stewart 		sctp_audit_data[sctp_audit_indx][0] = 0xAF;
701f8829a4aSRandall Stewart 		sctp_audit_data[sctp_audit_indx][1] = 0xA2;
702f8829a4aSRandall Stewart 		sctp_audit_indx++;
703f8829a4aSRandall Stewart 		if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
704f8829a4aSRandall Stewart 			sctp_audit_indx = 0;
705f8829a4aSRandall Stewart 		}
706f8829a4aSRandall Stewart 		rep = 1;
707ad81507eSRandall Stewart 		SCTP_PRINTF("tot_flt:%d asoc_tot:%d\n", tot_out,
708f8829a4aSRandall Stewart 		    (int)stcb->asoc.total_flight);
709f8829a4aSRandall Stewart 		stcb->asoc.total_flight = tot_out;
710f8829a4aSRandall Stewart 	}
711f8829a4aSRandall Stewart 	if (tot_book_cnt != stcb->asoc.total_flight_count) {
712f8829a4aSRandall Stewart 		sctp_audit_data[sctp_audit_indx][0] = 0xAF;
713f8829a4aSRandall Stewart 		sctp_audit_data[sctp_audit_indx][1] = 0xA5;
714f8829a4aSRandall Stewart 		sctp_audit_indx++;
715f8829a4aSRandall Stewart 		if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
716f8829a4aSRandall Stewart 			sctp_audit_indx = 0;
717f8829a4aSRandall Stewart 		}
718f8829a4aSRandall Stewart 		rep = 1;
719f31e6c7fSMichael Tuexen 		SCTP_PRINTF("tot_flt_book:%d\n", tot_book_cnt);
720f8829a4aSRandall Stewart 
721f8829a4aSRandall Stewart 		stcb->asoc.total_flight_count = tot_book_cnt;
722f8829a4aSRandall Stewart 	}
723f8829a4aSRandall Stewart 	tot_out = 0;
724f8829a4aSRandall Stewart 	TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
725f8829a4aSRandall Stewart 		tot_out += lnet->flight_size;
726f8829a4aSRandall Stewart 	}
727f8829a4aSRandall Stewart 	if (tot_out != stcb->asoc.total_flight) {
728f8829a4aSRandall Stewart 		sctp_audit_data[sctp_audit_indx][0] = 0xAF;
729f8829a4aSRandall Stewart 		sctp_audit_data[sctp_audit_indx][1] = 0xA3;
730f8829a4aSRandall Stewart 		sctp_audit_indx++;
731f8829a4aSRandall Stewart 		if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
732f8829a4aSRandall Stewart 			sctp_audit_indx = 0;
733f8829a4aSRandall Stewart 		}
734f8829a4aSRandall Stewart 		rep = 1;
735ad81507eSRandall Stewart 		SCTP_PRINTF("real flight:%d net total was %d\n",
736f8829a4aSRandall Stewart 		    stcb->asoc.total_flight, tot_out);
737f8829a4aSRandall Stewart 		/* now corrective action */
738f8829a4aSRandall Stewart 		TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
739f8829a4aSRandall Stewart 
740f8829a4aSRandall Stewart 			tot_out = 0;
741f8829a4aSRandall Stewart 			TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
742f8829a4aSRandall Stewart 				if ((chk->whoTo == lnet) &&
743f8829a4aSRandall Stewart 				    (chk->sent < SCTP_DATAGRAM_RESEND)) {
744f8829a4aSRandall Stewart 					tot_out += chk->book_size;
745f8829a4aSRandall Stewart 				}
746f8829a4aSRandall Stewart 			}
747f8829a4aSRandall Stewart 			if (lnet->flight_size != tot_out) {
748f31e6c7fSMichael Tuexen 				SCTP_PRINTF("net:%p flight was %d corrected to %d\n",
749dd294dceSMichael Tuexen 				    (void *)lnet, lnet->flight_size,
750ad81507eSRandall Stewart 				    tot_out);
751f8829a4aSRandall Stewart 				lnet->flight_size = tot_out;
752f8829a4aSRandall Stewart 			}
753f8829a4aSRandall Stewart 		}
754f8829a4aSRandall Stewart 	}
755f8829a4aSRandall Stewart 	if (rep) {
756f8829a4aSRandall Stewart 		sctp_print_audit_report();
757f8829a4aSRandall Stewart 	}
758f8829a4aSRandall Stewart }
759f8829a4aSRandall Stewart 
760f8829a4aSRandall Stewart void
761f8829a4aSRandall Stewart sctp_audit_log(uint8_t ev, uint8_t fd)
762f8829a4aSRandall Stewart {
763f8829a4aSRandall Stewart 
764f8829a4aSRandall Stewart 	sctp_audit_data[sctp_audit_indx][0] = ev;
765f8829a4aSRandall Stewart 	sctp_audit_data[sctp_audit_indx][1] = fd;
766f8829a4aSRandall Stewart 	sctp_audit_indx++;
767f8829a4aSRandall Stewart 	if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
768f8829a4aSRandall Stewart 		sctp_audit_indx = 0;
769f8829a4aSRandall Stewart 	}
770f8829a4aSRandall Stewart }
771f8829a4aSRandall Stewart 
772f8829a4aSRandall Stewart #endif
773f8829a4aSRandall Stewart 
774f8829a4aSRandall Stewart /*
77512af6654SMichael Tuexen  * sctp_stop_timers_for_shutdown() should be called
77612af6654SMichael Tuexen  * when entering the SHUTDOWN_SENT or SHUTDOWN_ACK_SENT
77712af6654SMichael Tuexen  * state to make sure that all timers are stopped.
77812af6654SMichael Tuexen  */
77912af6654SMichael Tuexen void
78012af6654SMichael Tuexen sctp_stop_timers_for_shutdown(struct sctp_tcb *stcb)
78112af6654SMichael Tuexen {
78212af6654SMichael Tuexen 	struct sctp_association *asoc;
78312af6654SMichael Tuexen 	struct sctp_nets *net;
78412af6654SMichael Tuexen 
78512af6654SMichael Tuexen 	asoc = &stcb->asoc;
78612af6654SMichael Tuexen 
78712af6654SMichael Tuexen 	(void)SCTP_OS_TIMER_STOP(&asoc->dack_timer.timer);
78812af6654SMichael Tuexen 	(void)SCTP_OS_TIMER_STOP(&asoc->strreset_timer.timer);
78912af6654SMichael Tuexen 	(void)SCTP_OS_TIMER_STOP(&asoc->asconf_timer.timer);
79012af6654SMichael Tuexen 	(void)SCTP_OS_TIMER_STOP(&asoc->autoclose_timer.timer);
79112af6654SMichael Tuexen 	(void)SCTP_OS_TIMER_STOP(&asoc->delayed_event_timer.timer);
79212af6654SMichael Tuexen 	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
79312af6654SMichael Tuexen 		(void)SCTP_OS_TIMER_STOP(&net->pmtu_timer.timer);
794ca85e948SMichael Tuexen 		(void)SCTP_OS_TIMER_STOP(&net->hb_timer.timer);
79512af6654SMichael Tuexen 	}
79612af6654SMichael Tuexen }
79712af6654SMichael Tuexen 
79812af6654SMichael Tuexen /*
799589c42c2SMichael Tuexen  * A list of sizes based on typical mtu's, used only if next hop size not
800589c42c2SMichael Tuexen  * returned. These values MUST be multiples of 4 and MUST be ordered.
801f8829a4aSRandall Stewart  */
802437fc91aSMichael Tuexen static uint32_t sctp_mtu_sizes[] = {
803f8829a4aSRandall Stewart 	68,
804f8829a4aSRandall Stewart 	296,
805f8829a4aSRandall Stewart 	508,
806f8829a4aSRandall Stewart 	512,
807f8829a4aSRandall Stewart 	544,
808f8829a4aSRandall Stewart 	576,
809589c42c2SMichael Tuexen 	1004,
810f8829a4aSRandall Stewart 	1492,
811f8829a4aSRandall Stewart 	1500,
812f8829a4aSRandall Stewart 	1536,
813589c42c2SMichael Tuexen 	2000,
814f8829a4aSRandall Stewart 	2048,
815f8829a4aSRandall Stewart 	4352,
816f8829a4aSRandall Stewart 	4464,
817f8829a4aSRandall Stewart 	8166,
818589c42c2SMichael Tuexen 	17912,
819f8829a4aSRandall Stewart 	32000,
820589c42c2SMichael Tuexen 	65532
821f8829a4aSRandall Stewart };
822f8829a4aSRandall Stewart 
823f8829a4aSRandall Stewart /*
824589c42c2SMichael Tuexen  * Return the largest MTU in sctp_mtu_sizes smaller than val.
825589c42c2SMichael Tuexen  * If val is smaller than the minimum, just return the largest
826589c42c2SMichael Tuexen  * multiple of 4 smaller or equal to val.
827589c42c2SMichael Tuexen  * Ensure that the result is a multiple of 4.
828f8829a4aSRandall Stewart  */
829437fc91aSMichael Tuexen uint32_t
830*b0471b4bSMichael Tuexen sctp_get_prev_mtu(uint32_t val)
831*b0471b4bSMichael Tuexen {
832437fc91aSMichael Tuexen 	uint32_t i;
833437fc91aSMichael Tuexen 
834eef8d4a9SMichael Tuexen 	val &= 0xfffffffc;
835437fc91aSMichael Tuexen 	if (val <= sctp_mtu_sizes[0]) {
836437fc91aSMichael Tuexen 		return (val);
837437fc91aSMichael Tuexen 	}
838437fc91aSMichael Tuexen 	for (i = 1; i < (sizeof(sctp_mtu_sizes) / sizeof(uint32_t)); i++) {
839437fc91aSMichael Tuexen 		if (val <= sctp_mtu_sizes[i]) {
840f8829a4aSRandall Stewart 			break;
841f8829a4aSRandall Stewart 		}
842f8829a4aSRandall Stewart 	}
843589c42c2SMichael Tuexen 	KASSERT((sctp_mtu_sizes[i - 1] & 0x00000003) == 0,
844589c42c2SMichael Tuexen 	    ("sctp_mtu_sizes[%u] not a multiple of 4", i - 1));
845437fc91aSMichael Tuexen 	return (sctp_mtu_sizes[i - 1]);
846437fc91aSMichael Tuexen }
847437fc91aSMichael Tuexen 
848437fc91aSMichael Tuexen /*
849589c42c2SMichael Tuexen  * Return the smallest MTU in sctp_mtu_sizes larger than val.
850589c42c2SMichael Tuexen  * If val is larger than the maximum, just return the largest multiple of 4 smaller
851589c42c2SMichael Tuexen  * or equal to val.
852589c42c2SMichael Tuexen  * Ensure that the result is a multiple of 4.
853437fc91aSMichael Tuexen  */
854437fc91aSMichael Tuexen uint32_t
855*b0471b4bSMichael Tuexen sctp_get_next_mtu(uint32_t val)
856*b0471b4bSMichael Tuexen {
857437fc91aSMichael Tuexen 	/* select another MTU that is just bigger than this one */
858437fc91aSMichael Tuexen 	uint32_t i;
859437fc91aSMichael Tuexen 
860eef8d4a9SMichael Tuexen 	val &= 0xfffffffc;
861437fc91aSMichael Tuexen 	for (i = 0; i < (sizeof(sctp_mtu_sizes) / sizeof(uint32_t)); i++) {
862437fc91aSMichael Tuexen 		if (val < sctp_mtu_sizes[i]) {
863589c42c2SMichael Tuexen 			KASSERT((sctp_mtu_sizes[i] & 0x00000003) == 0,
864589c42c2SMichael Tuexen 			    ("sctp_mtu_sizes[%u] not a multiple of 4", i));
865437fc91aSMichael Tuexen 			return (sctp_mtu_sizes[i]);
866437fc91aSMichael Tuexen 		}
867437fc91aSMichael Tuexen 	}
868437fc91aSMichael Tuexen 	return (val);
869f8829a4aSRandall Stewart }
870f8829a4aSRandall Stewart 
871f8829a4aSRandall Stewart void
872f8829a4aSRandall Stewart sctp_fill_random_store(struct sctp_pcb *m)
873f8829a4aSRandall Stewart {
874f8829a4aSRandall Stewart 	/*
875f8829a4aSRandall Stewart 	 * Here we use the MD5/SHA-1 to hash with our good randomNumbers and
876f8829a4aSRandall Stewart 	 * our counter. The result becomes our good random numbers and we
877f8829a4aSRandall Stewart 	 * then setup to give these out. Note that we do no locking to
878f8829a4aSRandall Stewart 	 * protect this. This is ok, since if competing folks call this we
87917205eccSRandall Stewart 	 * will get more gobbled gook in the random store which is what we
880f8829a4aSRandall Stewart 	 * want. There is a danger that two guys will use the same random
881f8829a4aSRandall Stewart 	 * numbers, but thats ok too since that is random as well :->
882f8829a4aSRandall Stewart 	 */
883f8829a4aSRandall Stewart 	m->store_at = 0;
884ad81507eSRandall Stewart 	(void)sctp_hmac(SCTP_HMAC, (uint8_t *)m->random_numbers,
885f8829a4aSRandall Stewart 	    sizeof(m->random_numbers), (uint8_t *)&m->random_counter,
886f8829a4aSRandall Stewart 	    sizeof(m->random_counter), (uint8_t *)m->random_store);
887f8829a4aSRandall Stewart 	m->random_counter++;
888f8829a4aSRandall Stewart }
889f8829a4aSRandall Stewart 
890f8829a4aSRandall Stewart uint32_t
891*b0471b4bSMichael Tuexen sctp_select_initial_TSN(struct sctp_pcb *inp)
892*b0471b4bSMichael Tuexen {
893f8829a4aSRandall Stewart 	/*
894f8829a4aSRandall Stewart 	 * A true implementation should use random selection process to get
895f8829a4aSRandall Stewart 	 * the initial stream sequence number, using RFC1750 as a good
896f8829a4aSRandall Stewart 	 * guideline
897f8829a4aSRandall Stewart 	 */
898139bc87fSRandall Stewart 	uint32_t x, *xp;
899f8829a4aSRandall Stewart 	uint8_t *p;
900851b7298SRandall Stewart 	int store_at, new_store;
901f8829a4aSRandall Stewart 
902851b7298SRandall Stewart 	if (inp->initial_sequence_debug != 0) {
903f8829a4aSRandall Stewart 		uint32_t ret;
904f8829a4aSRandall Stewart 
905851b7298SRandall Stewart 		ret = inp->initial_sequence_debug;
906851b7298SRandall Stewart 		inp->initial_sequence_debug++;
907f8829a4aSRandall Stewart 		return (ret);
908f8829a4aSRandall Stewart 	}
909851b7298SRandall Stewart retry:
910851b7298SRandall Stewart 	store_at = inp->store_at;
911851b7298SRandall Stewart 	new_store = store_at + sizeof(uint32_t);
912851b7298SRandall Stewart 	if (new_store >= (SCTP_SIGNATURE_SIZE - 3)) {
913851b7298SRandall Stewart 		new_store = 0;
914f8829a4aSRandall Stewart 	}
915851b7298SRandall Stewart 	if (!atomic_cmpset_int(&inp->store_at, store_at, new_store)) {
916851b7298SRandall Stewart 		goto retry;
917851b7298SRandall Stewart 	}
918851b7298SRandall Stewart 	if (new_store == 0) {
919851b7298SRandall Stewart 		/* Refill the random store */
920851b7298SRandall Stewart 		sctp_fill_random_store(inp);
921851b7298SRandall Stewart 	}
922851b7298SRandall Stewart 	p = &inp->random_store[store_at];
923139bc87fSRandall Stewart 	xp = (uint32_t *)p;
924f8829a4aSRandall Stewart 	x = *xp;
925f8829a4aSRandall Stewart 	return (x);
926f8829a4aSRandall Stewart }
927f8829a4aSRandall Stewart 
928f8829a4aSRandall Stewart uint32_t
929*b0471b4bSMichael Tuexen sctp_select_a_tag(struct sctp_inpcb *inp, uint16_t lport, uint16_t rport, int check)
930*b0471b4bSMichael Tuexen {
9317215cc1bSMichael Tuexen 	uint32_t x;
932f8829a4aSRandall Stewart 	struct timeval now;
933f8829a4aSRandall Stewart 
9347215cc1bSMichael Tuexen 	if (check) {
9356e55db54SRandall Stewart 		(void)SCTP_GETTIME_TIMEVAL(&now);
9367215cc1bSMichael Tuexen 	}
9377215cc1bSMichael Tuexen 	for (;;) {
938851b7298SRandall Stewart 		x = sctp_select_initial_TSN(&inp->sctp_ep);
939f8829a4aSRandall Stewart 		if (x == 0) {
940f8829a4aSRandall Stewart 			/* we never use 0 */
941f8829a4aSRandall Stewart 			continue;
942f8829a4aSRandall Stewart 		}
9437215cc1bSMichael Tuexen 		if (!check || sctp_is_vtag_good(x, lport, rport, &now)) {
9447215cc1bSMichael Tuexen 			break;
945f8829a4aSRandall Stewart 		}
946f8829a4aSRandall Stewart 	}
947f8829a4aSRandall Stewart 	return (x);
948f8829a4aSRandall Stewart }
949f8829a4aSRandall Stewart 
950e92c2a8dSMichael Tuexen int32_t
951*b0471b4bSMichael Tuexen sctp_map_assoc_state(int kernel_state)
952*b0471b4bSMichael Tuexen {
953e92c2a8dSMichael Tuexen 	int32_t user_state;
954e92c2a8dSMichael Tuexen 
955e92c2a8dSMichael Tuexen 	if (kernel_state & SCTP_STATE_WAS_ABORTED) {
956e92c2a8dSMichael Tuexen 		user_state = SCTP_CLOSED;
957e92c2a8dSMichael Tuexen 	} else if (kernel_state & SCTP_STATE_SHUTDOWN_PENDING) {
958e92c2a8dSMichael Tuexen 		user_state = SCTP_SHUTDOWN_PENDING;
959e92c2a8dSMichael Tuexen 	} else {
960e92c2a8dSMichael Tuexen 		switch (kernel_state & SCTP_STATE_MASK) {
961e92c2a8dSMichael Tuexen 		case SCTP_STATE_EMPTY:
962e92c2a8dSMichael Tuexen 			user_state = SCTP_CLOSED;
963e92c2a8dSMichael Tuexen 			break;
964e92c2a8dSMichael Tuexen 		case SCTP_STATE_INUSE:
965e92c2a8dSMichael Tuexen 			user_state = SCTP_CLOSED;
966e92c2a8dSMichael Tuexen 			break;
967e92c2a8dSMichael Tuexen 		case SCTP_STATE_COOKIE_WAIT:
968e92c2a8dSMichael Tuexen 			user_state = SCTP_COOKIE_WAIT;
969e92c2a8dSMichael Tuexen 			break;
970e92c2a8dSMichael Tuexen 		case SCTP_STATE_COOKIE_ECHOED:
971e92c2a8dSMichael Tuexen 			user_state = SCTP_COOKIE_ECHOED;
972e92c2a8dSMichael Tuexen 			break;
973e92c2a8dSMichael Tuexen 		case SCTP_STATE_OPEN:
974e92c2a8dSMichael Tuexen 			user_state = SCTP_ESTABLISHED;
975e92c2a8dSMichael Tuexen 			break;
976e92c2a8dSMichael Tuexen 		case SCTP_STATE_SHUTDOWN_SENT:
977e92c2a8dSMichael Tuexen 			user_state = SCTP_SHUTDOWN_SENT;
978e92c2a8dSMichael Tuexen 			break;
979e92c2a8dSMichael Tuexen 		case SCTP_STATE_SHUTDOWN_RECEIVED:
980e92c2a8dSMichael Tuexen 			user_state = SCTP_SHUTDOWN_RECEIVED;
981e92c2a8dSMichael Tuexen 			break;
982e92c2a8dSMichael Tuexen 		case SCTP_STATE_SHUTDOWN_ACK_SENT:
983e92c2a8dSMichael Tuexen 			user_state = SCTP_SHUTDOWN_ACK_SENT;
984e92c2a8dSMichael Tuexen 			break;
985e92c2a8dSMichael Tuexen 		default:
986e92c2a8dSMichael Tuexen 			user_state = SCTP_CLOSED;
987e92c2a8dSMichael Tuexen 			break;
988e92c2a8dSMichael Tuexen 		}
989e92c2a8dSMichael Tuexen 	}
990e92c2a8dSMichael Tuexen 	return (user_state);
991e92c2a8dSMichael Tuexen }
992e92c2a8dSMichael Tuexen 
993f8829a4aSRandall Stewart int
994a1cb341bSMichael Tuexen sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
995c979034bSMichael Tuexen     uint32_t override_tag, uint32_t vrf_id, uint16_t o_strms)
996f8829a4aSRandall Stewart {
9970696e120SRandall Stewart 	struct sctp_association *asoc;
9980696e120SRandall Stewart 
999f8829a4aSRandall Stewart 	/*
1000f8829a4aSRandall Stewart 	 * Anything set to zero is taken care of by the allocation routine's
1001f8829a4aSRandall Stewart 	 * bzero
1002f8829a4aSRandall Stewart 	 */
1003f8829a4aSRandall Stewart 
1004f8829a4aSRandall Stewart 	/*
1005f8829a4aSRandall Stewart 	 * Up front select what scoping to apply on addresses I tell my peer
1006f8829a4aSRandall Stewart 	 * Not sure what to do with these right now, we will need to come up
1007f8829a4aSRandall Stewart 	 * with a way to set them. We may need to pass them through from the
1008f8829a4aSRandall Stewart 	 * caller in the sctp_aloc_assoc() function.
1009f8829a4aSRandall Stewart 	 */
1010f8829a4aSRandall Stewart 	int i;
1011f0396ad1SMichael Tuexen #if defined(SCTP_DETAILED_STR_STATS)
1012f0396ad1SMichael Tuexen 	int j;
1013f0396ad1SMichael Tuexen #endif
1014f0396ad1SMichael Tuexen 
10150696e120SRandall Stewart 	asoc = &stcb->asoc;
1016f8829a4aSRandall Stewart 	/* init all variables to a known value. */
1017c4739e2fSRandall Stewart 	SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_INUSE);
1018a1cb341bSMichael Tuexen 	asoc->max_burst = inp->sctp_ep.max_burst;
1019a1cb341bSMichael Tuexen 	asoc->fr_max_burst = inp->sctp_ep.fr_max_burst;
1020a1cb341bSMichael Tuexen 	asoc->heart_beat_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]);
1021a1cb341bSMichael Tuexen 	asoc->cookie_life = inp->sctp_ep.def_cookie_life;
1022a1cb341bSMichael Tuexen 	asoc->sctp_cmt_on_off = inp->sctp_cmt_on_off;
1023f342355aSMichael Tuexen 	asoc->ecn_supported = inp->ecn_supported;
1024dd973b0eSMichael Tuexen 	asoc->prsctp_supported = inp->prsctp_supported;
102544249214SRandall Stewart 	asoc->idata_supported = inp->idata_supported;
1026c79bec9cSMichael Tuexen 	asoc->auth_supported = inp->auth_supported;
1027c79bec9cSMichael Tuexen 	asoc->asconf_supported = inp->asconf_supported;
1028317e00efSMichael Tuexen 	asoc->reconfig_supported = inp->reconfig_supported;
1029caea9879SMichael Tuexen 	asoc->nrsack_supported = inp->nrsack_supported;
1030cb9b8e6fSMichael Tuexen 	asoc->pktdrop_supported = inp->pktdrop_supported;
103144249214SRandall Stewart 	asoc->idata_supported = inp->idata_supported;
1032ca85e948SMichael Tuexen 	asoc->sctp_cmt_pf = (uint8_t)0;
1033a1cb341bSMichael Tuexen 	asoc->sctp_frag_point = inp->sctp_frag_point;
1034a1cb341bSMichael Tuexen 	asoc->sctp_features = inp->sctp_features;
1035a1cb341bSMichael Tuexen 	asoc->default_dscp = inp->sctp_ep.default_dscp;
103659b6d5beSMichael Tuexen 	asoc->max_cwnd = inp->max_cwnd;
103742551e99SRandall Stewart #ifdef INET6
1038a1cb341bSMichael Tuexen 	if (inp->sctp_ep.default_flowlabel) {
1039a1cb341bSMichael Tuexen 		asoc->default_flowlabel = inp->sctp_ep.default_flowlabel;
104058bdb691SMichael Tuexen 	} else {
1041a1cb341bSMichael Tuexen 		if (inp->ip_inp.inp.inp_flags & IN6P_AUTOFLOWLABEL) {
1042a1cb341bSMichael Tuexen 			asoc->default_flowlabel = sctp_select_initial_TSN(&inp->sctp_ep);
104358bdb691SMichael Tuexen 			asoc->default_flowlabel &= 0x000fffff;
104458bdb691SMichael Tuexen 			asoc->default_flowlabel |= 0x80000000;
104558bdb691SMichael Tuexen 		} else {
1046f8829a4aSRandall Stewart 			asoc->default_flowlabel = 0;
104758bdb691SMichael Tuexen 		}
104858bdb691SMichael Tuexen 	}
1049f8829a4aSRandall Stewart #endif
10509f22f500SRandall Stewart 	asoc->sb_send_resv = 0;
1051f8829a4aSRandall Stewart 	if (override_tag) {
1052f8829a4aSRandall Stewart 		asoc->my_vtag = override_tag;
1053f8829a4aSRandall Stewart 	} else {
1054a1cb341bSMichael Tuexen 		asoc->my_vtag = sctp_select_a_tag(inp, stcb->sctp_ep->sctp_lport, stcb->rport, 1);
1055f8829a4aSRandall Stewart 	}
1056de0e935bSRandall Stewart 	/* Get the nonce tags */
1057a1cb341bSMichael Tuexen 	asoc->my_vtag_nonce = sctp_select_a_tag(inp, stcb->sctp_ep->sctp_lport, stcb->rport, 0);
1058a1cb341bSMichael Tuexen 	asoc->peer_vtag_nonce = sctp_select_a_tag(inp, stcb->sctp_ep->sctp_lport, stcb->rport, 0);
105942551e99SRandall Stewart 	asoc->vrf_id = vrf_id;
1060de0e935bSRandall Stewart 
106118e198d3SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS
106218e198d3SRandall Stewart 	asoc->tsn_in_at = 0;
106318e198d3SRandall Stewart 	asoc->tsn_out_at = 0;
106418e198d3SRandall Stewart 	asoc->tsn_in_wrapped = 0;
106518e198d3SRandall Stewart 	asoc->tsn_out_wrapped = 0;
106618e198d3SRandall Stewart 	asoc->cumack_log_at = 0;
1067b201f536SRandall Stewart 	asoc->cumack_log_atsnt = 0;
106818e198d3SRandall Stewart #endif
106918e198d3SRandall Stewart #ifdef SCTP_FS_SPEC_LOG
107018e198d3SRandall Stewart 	asoc->fs_index = 0;
107118e198d3SRandall Stewart #endif
1072f8829a4aSRandall Stewart 	asoc->refcnt = 0;
1073f8829a4aSRandall Stewart 	asoc->assoc_up_sent = 0;
1074f8829a4aSRandall Stewart 	asoc->asconf_seq_out = asoc->str_reset_seq_out = asoc->init_seq_number = asoc->sending_seq =
1075a1cb341bSMichael Tuexen 	    sctp_select_initial_TSN(&inp->sctp_ep);
1076c54a18d2SRandall Stewart 	asoc->asconf_seq_out_acked = asoc->asconf_seq_out - 1;
1077f8829a4aSRandall Stewart 	/* we are optimisitic here */
1078830d754dSRandall Stewart 	asoc->peer_supports_nat = 0;
1079f8829a4aSRandall Stewart 	asoc->sent_queue_retran_cnt = 0;
1080f8829a4aSRandall Stewart 
1081f8829a4aSRandall Stewart 	/* for CMT */
10828933fa13SRandall Stewart 	asoc->last_net_cmt_send_started = NULL;
1083f8829a4aSRandall Stewart 
1084f8829a4aSRandall Stewart 	/* This will need to be adjusted */
1085f8829a4aSRandall Stewart 	asoc->last_acked_seq = asoc->init_seq_number - 1;
1086f8829a4aSRandall Stewart 	asoc->advanced_peer_ack_point = asoc->last_acked_seq;
1087f8829a4aSRandall Stewart 	asoc->asconf_seq_in = asoc->last_acked_seq;
1088f8829a4aSRandall Stewart 
1089f8829a4aSRandall Stewart 	/* here we are different, we hold the next one we expect */
1090f8829a4aSRandall Stewart 	asoc->str_reset_seq_in = asoc->last_acked_seq + 1;
1091f8829a4aSRandall Stewart 
1092a1cb341bSMichael Tuexen 	asoc->initial_init_rto_max = inp->sctp_ep.initial_init_rto_max;
1093a1cb341bSMichael Tuexen 	asoc->initial_rto = inp->sctp_ep.initial_rto;
1094f8829a4aSRandall Stewart 
109528a6addeSMichael Tuexen 	asoc->default_mtu = inp->sctp_ep.default_mtu;
1096a1cb341bSMichael Tuexen 	asoc->max_init_times = inp->sctp_ep.max_init_times;
1097a1cb341bSMichael Tuexen 	asoc->max_send_times = inp->sctp_ep.max_send_times;
1098a1cb341bSMichael Tuexen 	asoc->def_net_failure = inp->sctp_ep.def_net_failure;
1099a1cb341bSMichael Tuexen 	asoc->def_net_pf_threshold = inp->sctp_ep.def_net_pf_threshold;
1100f8829a4aSRandall Stewart 	asoc->free_chunk_cnt = 0;
1101f8829a4aSRandall Stewart 
1102f8829a4aSRandall Stewart 	asoc->iam_blocking = 0;
1103a1cb341bSMichael Tuexen 	asoc->context = inp->sctp_context;
1104a1cb341bSMichael Tuexen 	asoc->local_strreset_support = inp->local_strreset_support;
1105a1cb341bSMichael Tuexen 	asoc->def_send = inp->def_send;
1106a1cb341bSMichael Tuexen 	asoc->delayed_ack = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]);
1107a1cb341bSMichael Tuexen 	asoc->sack_freq = inp->sctp_ep.sctp_sack_freq;
1108f8829a4aSRandall Stewart 	asoc->pr_sctp_cnt = 0;
1109f8829a4aSRandall Stewart 	asoc->total_output_queue_size = 0;
1110f8829a4aSRandall Stewart 
1111a1cb341bSMichael Tuexen 	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
1112a1cb341bSMichael Tuexen 		asoc->scope.ipv6_addr_legal = 1;
1113a1cb341bSMichael Tuexen 		if (SCTP_IPV6_V6ONLY(inp) == 0) {
1114a1cb341bSMichael Tuexen 			asoc->scope.ipv4_addr_legal = 1;
1115f8829a4aSRandall Stewart 		} else {
1116a1cb341bSMichael Tuexen 			asoc->scope.ipv4_addr_legal = 0;
1117f8829a4aSRandall Stewart 		}
1118f8829a4aSRandall Stewart 	} else {
1119a1cb341bSMichael Tuexen 		asoc->scope.ipv6_addr_legal = 0;
1120a1cb341bSMichael Tuexen 		asoc->scope.ipv4_addr_legal = 1;
1121f8829a4aSRandall Stewart 	}
1122f8829a4aSRandall Stewart 
1123a1cb341bSMichael Tuexen 	asoc->my_rwnd = max(SCTP_SB_LIMIT_RCV(inp->sctp_socket), SCTP_MINIMAL_RWND);
1124a1cb341bSMichael Tuexen 	asoc->peers_rwnd = SCTP_SB_LIMIT_RCV(inp->sctp_socket);
1125f8829a4aSRandall Stewart 
1126a1cb341bSMichael Tuexen 	asoc->smallest_mtu = inp->sctp_frag_point;
1127a1cb341bSMichael Tuexen 	asoc->minrto = inp->sctp_ep.sctp_minrto;
1128a1cb341bSMichael Tuexen 	asoc->maxrto = inp->sctp_ep.sctp_maxrto;
1129f8829a4aSRandall Stewart 
1130f8829a4aSRandall Stewart 	asoc->stream_locked_on = 0;
1131f8829a4aSRandall Stewart 	asoc->ecn_echo_cnt_onq = 0;
1132f8829a4aSRandall Stewart 	asoc->stream_locked = 0;
1133f8829a4aSRandall Stewart 
113442551e99SRandall Stewart 	asoc->send_sack = 1;
113542551e99SRandall Stewart 
113642551e99SRandall Stewart 	LIST_INIT(&asoc->sctp_restricted_addrs);
113742551e99SRandall Stewart 
1138f8829a4aSRandall Stewart 	TAILQ_INIT(&asoc->nets);
1139f8829a4aSRandall Stewart 	TAILQ_INIT(&asoc->pending_reply_queue);
11402afb3e84SRandall Stewart 	TAILQ_INIT(&asoc->asconf_ack_sent);
1141f8829a4aSRandall Stewart 	/* Setup to fill the hb random cache at first HB */
1142f8829a4aSRandall Stewart 	asoc->hb_random_idx = 4;
1143f8829a4aSRandall Stewart 
1144a1cb341bSMichael Tuexen 	asoc->sctp_autoclose_ticks = inp->sctp_ep.auto_close_time;
1145f8829a4aSRandall Stewart 
1146a1cb341bSMichael Tuexen 	stcb->asoc.congestion_control_module = inp->sctp_ep.sctp_default_cc_module;
1147a1cb341bSMichael Tuexen 	stcb->asoc.cc_functions = sctp_cc_functions[inp->sctp_ep.sctp_default_cc_module];
1148b54d3a6cSRandall Stewart 
1149a1cb341bSMichael Tuexen 	stcb->asoc.stream_scheduling_module = inp->sctp_ep.sctp_default_ss_module;
1150a1cb341bSMichael Tuexen 	stcb->asoc.ss_functions = sctp_ss_functions[inp->sctp_ep.sctp_default_ss_module];
1151f7a77f6fSMichael Tuexen 
1152b54d3a6cSRandall Stewart 	/*
1153f8829a4aSRandall Stewart 	 * Now the stream parameters, here we allocate space for all streams
1154f8829a4aSRandall Stewart 	 * that we request by default.
1155f8829a4aSRandall Stewart 	 */
1156ea44232bSRandall Stewart 	asoc->strm_realoutsize = asoc->streamoutcnt = asoc->pre_open_streams =
1157c979034bSMichael Tuexen 	    o_strms;
1158f8829a4aSRandall Stewart 	SCTP_MALLOC(asoc->strmout, struct sctp_stream_out *,
1159f8829a4aSRandall Stewart 	    asoc->streamoutcnt * sizeof(struct sctp_stream_out),
1160207304d4SRandall Stewart 	    SCTP_M_STRMO);
1161f8829a4aSRandall Stewart 	if (asoc->strmout == NULL) {
1162f8829a4aSRandall Stewart 		/* big trouble no memory */
1163c4739e2fSRandall Stewart 		SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM);
1164f8829a4aSRandall Stewart 		return (ENOMEM);
1165f8829a4aSRandall Stewart 	}
1166f8829a4aSRandall Stewart 	for (i = 0; i < asoc->streamoutcnt; i++) {
1167f8829a4aSRandall Stewart 		/*
1168f8829a4aSRandall Stewart 		 * inbound side must be set to 0xffff, also NOTE when we get
1169f8829a4aSRandall Stewart 		 * the INIT-ACK back (for INIT sender) we MUST reduce the
1170f8829a4aSRandall Stewart 		 * count (streamoutcnt) but first check if we sent to any of
1171f8829a4aSRandall Stewart 		 * the upper streams that were dropped (if some were). Those
1172f8829a4aSRandall Stewart 		 * that were dropped must be notified to the upper layer as
1173f8829a4aSRandall Stewart 		 * failed to send.
1174f8829a4aSRandall Stewart 		 */
117563d5b568SMichael Tuexen 		asoc->strmout[i].next_mid_ordered = 0;
117663d5b568SMichael Tuexen 		asoc->strmout[i].next_mid_unordered = 0;
1177f8829a4aSRandall Stewart 		TAILQ_INIT(&asoc->strmout[i].outqueue);
1178325c8c46SMichael Tuexen 		asoc->strmout[i].chunks_on_queues = 0;
1179f0396ad1SMichael Tuexen #if defined(SCTP_DETAILED_STR_STATS)
1180f0396ad1SMichael Tuexen 		for (j = 0; j < SCTP_PR_SCTP_MAX + 1; j++) {
1181f0396ad1SMichael Tuexen 			asoc->strmout[i].abandoned_sent[j] = 0;
1182f0396ad1SMichael Tuexen 			asoc->strmout[i].abandoned_unsent[j] = 0;
1183f0396ad1SMichael Tuexen 		}
1184f0396ad1SMichael Tuexen #else
1185f0396ad1SMichael Tuexen 		asoc->strmout[i].abandoned_sent[0] = 0;
1186f0396ad1SMichael Tuexen 		asoc->strmout[i].abandoned_unsent[0] = 0;
1187f0396ad1SMichael Tuexen #endif
118849656eefSMichael Tuexen 		asoc->strmout[i].sid = i;
1189f8829a4aSRandall Stewart 		asoc->strmout[i].last_msg_incomplete = 0;
11907cca1775SRandall Stewart 		asoc->strmout[i].state = SCTP_STREAM_OPENING;
1191d1ea5fa9SMichael Tuexen 		asoc->ss_functions.sctp_ss_init_stream(stcb, &asoc->strmout[i], NULL);
1192f8829a4aSRandall Stewart 	}
1193f7a77f6fSMichael Tuexen 	asoc->ss_functions.sctp_ss_init(stcb, asoc, 0);
1194f7a77f6fSMichael Tuexen 
1195f8829a4aSRandall Stewart 	/* Now the mapping array */
1196f8829a4aSRandall Stewart 	asoc->mapping_array_size = SCTP_INITIAL_MAPPING_ARRAY;
1197f8829a4aSRandall Stewart 	SCTP_MALLOC(asoc->mapping_array, uint8_t *, asoc->mapping_array_size,
1198207304d4SRandall Stewart 	    SCTP_M_MAP);
1199f8829a4aSRandall Stewart 	if (asoc->mapping_array == NULL) {
1200207304d4SRandall Stewart 		SCTP_FREE(asoc->strmout, SCTP_M_STRMO);
1201c4739e2fSRandall Stewart 		SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM);
1202f8829a4aSRandall Stewart 		return (ENOMEM);
1203f8829a4aSRandall Stewart 	}
1204f8829a4aSRandall Stewart 	memset(asoc->mapping_array, 0, asoc->mapping_array_size);
1205b5c16493SMichael Tuexen 	SCTP_MALLOC(asoc->nr_mapping_array, uint8_t *, asoc->mapping_array_size,
1206830d754dSRandall Stewart 	    SCTP_M_MAP);
1207bf1be571SRandall Stewart 	if (asoc->nr_mapping_array == NULL) {
1208bf1be571SRandall Stewart 		SCTP_FREE(asoc->strmout, SCTP_M_STRMO);
1209bf1be571SRandall Stewart 		SCTP_FREE(asoc->mapping_array, SCTP_M_MAP);
1210bf1be571SRandall Stewart 		SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM);
1211bf1be571SRandall Stewart 		return (ENOMEM);
1212bf1be571SRandall Stewart 	}
1213b5c16493SMichael Tuexen 	memset(asoc->nr_mapping_array, 0, asoc->mapping_array_size);
1214830d754dSRandall Stewart 
1215f8829a4aSRandall Stewart 	/* Now the init of the other outqueues */
1216f8829a4aSRandall Stewart 	TAILQ_INIT(&asoc->free_chunks);
1217f8829a4aSRandall Stewart 	TAILQ_INIT(&asoc->control_send_queue);
1218c54a18d2SRandall Stewart 	TAILQ_INIT(&asoc->asconf_send_queue);
1219f8829a4aSRandall Stewart 	TAILQ_INIT(&asoc->send_queue);
1220f8829a4aSRandall Stewart 	TAILQ_INIT(&asoc->sent_queue);
1221f8829a4aSRandall Stewart 	TAILQ_INIT(&asoc->resetHead);
1222a1cb341bSMichael Tuexen 	asoc->max_inbound_streams = inp->sctp_ep.max_open_streams_intome;
1223f8829a4aSRandall Stewart 	TAILQ_INIT(&asoc->asconf_queue);
1224f8829a4aSRandall Stewart 	/* authentication fields */
1225f8829a4aSRandall Stewart 	asoc->authinfo.random = NULL;
1226830d754dSRandall Stewart 	asoc->authinfo.active_keyid = 0;
1227f8829a4aSRandall Stewart 	asoc->authinfo.assoc_key = NULL;
1228f8829a4aSRandall Stewart 	asoc->authinfo.assoc_keyid = 0;
1229f8829a4aSRandall Stewart 	asoc->authinfo.recv_key = NULL;
1230f8829a4aSRandall Stewart 	asoc->authinfo.recv_keyid = 0;
1231f8829a4aSRandall Stewart 	LIST_INIT(&asoc->shared_keys);
1232f42a358aSRandall Stewart 	asoc->marked_retrans = 0;
1233a1cb341bSMichael Tuexen 	asoc->port = inp->sctp_ep.port;
1234f42a358aSRandall Stewart 	asoc->timoinit = 0;
1235f42a358aSRandall Stewart 	asoc->timodata = 0;
1236f42a358aSRandall Stewart 	asoc->timosack = 0;
1237f42a358aSRandall Stewart 	asoc->timoshutdown = 0;
1238f42a358aSRandall Stewart 	asoc->timoheartbeat = 0;
1239f42a358aSRandall Stewart 	asoc->timocookie = 0;
1240f42a358aSRandall Stewart 	asoc->timoshutdownack = 0;
12416e55db54SRandall Stewart 	(void)SCTP_GETTIME_TIMEVAL(&asoc->start_time);
12426e55db54SRandall Stewart 	asoc->discontinuity_time = asoc->start_time;
1243f0396ad1SMichael Tuexen 	for (i = 0; i < SCTP_PR_SCTP_MAX + 1; i++) {
1244f0396ad1SMichael Tuexen 		asoc->abandoned_unsent[i] = 0;
1245f0396ad1SMichael Tuexen 		asoc->abandoned_sent[i] = 0;
1246f0396ad1SMichael Tuexen 	}
1247eacc51c5SRandall Stewart 	/*
1248eacc51c5SRandall Stewart 	 * sa_ignore MEMLEAK {memory is put in the assoc mapping array and
124977acdc25SRandall Stewart 	 * freed later when the association is freed.
1250eacc51c5SRandall Stewart 	 */
1251f8829a4aSRandall Stewart 	return (0);
1252f8829a4aSRandall Stewart }
1253f8829a4aSRandall Stewart 
12540e13104dSRandall Stewart void
12550e13104dSRandall Stewart sctp_print_mapping_array(struct sctp_association *asoc)
12560e13104dSRandall Stewart {
1257aed5947cSMichael Tuexen 	unsigned int i, limit;
12580e13104dSRandall Stewart 
1259cd3fd531SMichael Tuexen 	SCTP_PRINTF("Mapping array size: %d, baseTSN: %8.8x, cumAck: %8.8x, highestTSN: (%8.8x, %8.8x).\n",
12600e13104dSRandall Stewart 	    asoc->mapping_array_size,
12610e13104dSRandall Stewart 	    asoc->mapping_array_base_tsn,
12620e13104dSRandall Stewart 	    asoc->cumulative_tsn,
1263aed5947cSMichael Tuexen 	    asoc->highest_tsn_inside_map,
1264aed5947cSMichael Tuexen 	    asoc->highest_tsn_inside_nr_map);
1265aed5947cSMichael Tuexen 	for (limit = asoc->mapping_array_size; limit > 1; limit--) {
126660990c0cSMichael Tuexen 		if (asoc->mapping_array[limit - 1] != 0) {
126777acdc25SRandall Stewart 			break;
126877acdc25SRandall Stewart 		}
126977acdc25SRandall Stewart 	}
1270cd3fd531SMichael Tuexen 	SCTP_PRINTF("Renegable mapping array (last %d entries are zero):\n", asoc->mapping_array_size - limit);
127177acdc25SRandall Stewart 	for (i = 0; i < limit; i++) {
1272cd3fd531SMichael Tuexen 		SCTP_PRINTF("%2.2x%c", asoc->mapping_array[i], ((i + 1) % 16) ? ' ' : '\n');
127377acdc25SRandall Stewart 	}
1274aed5947cSMichael Tuexen 	if (limit % 16)
1275cd3fd531SMichael Tuexen 		SCTP_PRINTF("\n");
1276aed5947cSMichael Tuexen 	for (limit = asoc->mapping_array_size; limit > 1; limit--) {
1277aed5947cSMichael Tuexen 		if (asoc->nr_mapping_array[limit - 1]) {
127877acdc25SRandall Stewart 			break;
127977acdc25SRandall Stewart 		}
128077acdc25SRandall Stewart 	}
1281cd3fd531SMichael Tuexen 	SCTP_PRINTF("Non renegable mapping array (last %d entries are zero):\n", asoc->mapping_array_size - limit);
128277acdc25SRandall Stewart 	for (i = 0; i < limit; i++) {
1283cd3fd531SMichael Tuexen 		SCTP_PRINTF("%2.2x%c", asoc->nr_mapping_array[i], ((i + 1) % 16) ? ' ' : '\n');
12840e13104dSRandall Stewart 	}
1285aed5947cSMichael Tuexen 	if (limit % 16)
1286cd3fd531SMichael Tuexen 		SCTP_PRINTF("\n");
12870e13104dSRandall Stewart }
12880e13104dSRandall Stewart 
1289f8829a4aSRandall Stewart int
12900696e120SRandall Stewart sctp_expand_mapping_array(struct sctp_association *asoc, uint32_t needed)
1291f8829a4aSRandall Stewart {
1292f8829a4aSRandall Stewart 	/* mapping array needs to grow */
1293b5c16493SMichael Tuexen 	uint8_t *new_array1, *new_array2;
12940696e120SRandall Stewart 	uint32_t new_size;
1295f8829a4aSRandall Stewart 
12960696e120SRandall Stewart 	new_size = asoc->mapping_array_size + ((needed + 7) / 8 + SCTP_MAPPING_ARRAY_INCR);
1297b5c16493SMichael Tuexen 	SCTP_MALLOC(new_array1, uint8_t *, new_size, SCTP_M_MAP);
1298b5c16493SMichael Tuexen 	SCTP_MALLOC(new_array2, uint8_t *, new_size, SCTP_M_MAP);
1299b5c16493SMichael Tuexen 	if ((new_array1 == NULL) || (new_array2 == NULL)) {
1300f8829a4aSRandall Stewart 		/* can't get more, forget it */
1301b5c16493SMichael Tuexen 		SCTP_PRINTF("No memory for expansion of SCTP mapping array %d\n", new_size);
1302b5c16493SMichael Tuexen 		if (new_array1) {
1303b5c16493SMichael Tuexen 			SCTP_FREE(new_array1, SCTP_M_MAP);
1304b5c16493SMichael Tuexen 		}
1305b5c16493SMichael Tuexen 		if (new_array2) {
1306b5c16493SMichael Tuexen 			SCTP_FREE(new_array2, SCTP_M_MAP);
1307b5c16493SMichael Tuexen 		}
1308f8829a4aSRandall Stewart 		return (-1);
1309f8829a4aSRandall Stewart 	}
1310b5c16493SMichael Tuexen 	memset(new_array1, 0, new_size);
1311b5c16493SMichael Tuexen 	memset(new_array2, 0, new_size);
1312b5c16493SMichael Tuexen 	memcpy(new_array1, asoc->mapping_array, asoc->mapping_array_size);
1313b5c16493SMichael Tuexen 	memcpy(new_array2, asoc->nr_mapping_array, asoc->mapping_array_size);
1314207304d4SRandall Stewart 	SCTP_FREE(asoc->mapping_array, SCTP_M_MAP);
1315830d754dSRandall Stewart 	SCTP_FREE(asoc->nr_mapping_array, SCTP_M_MAP);
1316b5c16493SMichael Tuexen 	asoc->mapping_array = new_array1;
1317b5c16493SMichael Tuexen 	asoc->nr_mapping_array = new_array2;
1318b5c16493SMichael Tuexen 	asoc->mapping_array_size = new_size;
1319830d754dSRandall Stewart 	return (0);
1320830d754dSRandall Stewart }
1321830d754dSRandall Stewart 
13228933fa13SRandall Stewart 
132342551e99SRandall Stewart static void
132442551e99SRandall Stewart sctp_iterator_work(struct sctp_iterator *it)
132542551e99SRandall Stewart {
132642551e99SRandall Stewart 	int iteration_count = 0;
132742551e99SRandall Stewart 	int inp_skip = 0;
1328ec4c19fcSRandall Stewart 	int first_in = 1;
1329ec4c19fcSRandall Stewart 	struct sctp_inpcb *tinp;
133042551e99SRandall Stewart 
1331ec4c19fcSRandall Stewart 	SCTP_INP_INFO_RLOCK();
133242551e99SRandall Stewart 	SCTP_ITERATOR_LOCK();
1333dcb436c9SMichael Tuexen 	sctp_it_ctl.cur_it = it;
1334ad81507eSRandall Stewart 	if (it->inp) {
1335ec4c19fcSRandall Stewart 		SCTP_INP_RLOCK(it->inp);
133642551e99SRandall Stewart 		SCTP_INP_DECR_REF(it->inp);
1337ad81507eSRandall Stewart 	}
133842551e99SRandall Stewart 	if (it->inp == NULL) {
133942551e99SRandall Stewart 		/* iterator is complete */
134042551e99SRandall Stewart done_with_iterator:
1341dcb436c9SMichael Tuexen 		sctp_it_ctl.cur_it = NULL;
134242551e99SRandall Stewart 		SCTP_ITERATOR_UNLOCK();
1343ec4c19fcSRandall Stewart 		SCTP_INP_INFO_RUNLOCK();
134442551e99SRandall Stewart 		if (it->function_atend != NULL) {
134542551e99SRandall Stewart 			(*it->function_atend) (it->pointer, it->val);
134642551e99SRandall Stewart 		}
1347207304d4SRandall Stewart 		SCTP_FREE(it, SCTP_M_ITER);
134842551e99SRandall Stewart 		return;
134942551e99SRandall Stewart 	}
135042551e99SRandall Stewart select_a_new_ep:
1351ec4c19fcSRandall Stewart 	if (first_in) {
1352ec4c19fcSRandall Stewart 		first_in = 0;
1353ec4c19fcSRandall Stewart 	} else {
1354f7517433SRandall Stewart 		SCTP_INP_RLOCK(it->inp);
1355ec4c19fcSRandall Stewart 	}
135642551e99SRandall Stewart 	while (((it->pcb_flags) &&
135742551e99SRandall Stewart 	    ((it->inp->sctp_flags & it->pcb_flags) != it->pcb_flags)) ||
135842551e99SRandall Stewart 	    ((it->pcb_features) &&
135942551e99SRandall Stewart 	    ((it->inp->sctp_features & it->pcb_features) != it->pcb_features))) {
136042551e99SRandall Stewart 		/* endpoint flags or features don't match, so keep looking */
136142551e99SRandall Stewart 		if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) {
1362f7517433SRandall Stewart 			SCTP_INP_RUNLOCK(it->inp);
136342551e99SRandall Stewart 			goto done_with_iterator;
136442551e99SRandall Stewart 		}
1365ec4c19fcSRandall Stewart 		tinp = it->inp;
136642551e99SRandall Stewart 		it->inp = LIST_NEXT(it->inp, sctp_list);
1367ec4c19fcSRandall Stewart 		SCTP_INP_RUNLOCK(tinp);
136842551e99SRandall Stewart 		if (it->inp == NULL) {
136942551e99SRandall Stewart 			goto done_with_iterator;
137042551e99SRandall Stewart 		}
137142551e99SRandall Stewart 		SCTP_INP_RLOCK(it->inp);
1372f7517433SRandall Stewart 	}
137342551e99SRandall Stewart 	/* now go through each assoc which is in the desired state */
137442551e99SRandall Stewart 	if (it->done_current_ep == 0) {
137542551e99SRandall Stewart 		if (it->function_inp != NULL)
137642551e99SRandall Stewart 			inp_skip = (*it->function_inp) (it->inp, it->pointer, it->val);
137742551e99SRandall Stewart 		it->done_current_ep = 1;
137842551e99SRandall Stewart 	}
137942551e99SRandall Stewart 	if (it->stcb == NULL) {
138042551e99SRandall Stewart 		/* run the per instance function */
138142551e99SRandall Stewart 		it->stcb = LIST_FIRST(&it->inp->sctp_asoc_list);
138242551e99SRandall Stewart 	}
138342551e99SRandall Stewart 	if ((inp_skip) || it->stcb == NULL) {
138442551e99SRandall Stewart 		if (it->function_inp_end != NULL) {
138542551e99SRandall Stewart 			inp_skip = (*it->function_inp_end) (it->inp,
138642551e99SRandall Stewart 			    it->pointer,
138742551e99SRandall Stewart 			    it->val);
138842551e99SRandall Stewart 		}
138942551e99SRandall Stewart 		SCTP_INP_RUNLOCK(it->inp);
139042551e99SRandall Stewart 		goto no_stcb;
139142551e99SRandall Stewart 	}
139242551e99SRandall Stewart 	while (it->stcb) {
139342551e99SRandall Stewart 		SCTP_TCB_LOCK(it->stcb);
139442551e99SRandall Stewart 		if (it->asoc_state && ((it->stcb->asoc.state & it->asoc_state) != it->asoc_state)) {
139542551e99SRandall Stewart 			/* not in the right state... keep looking */
139642551e99SRandall Stewart 			SCTP_TCB_UNLOCK(it->stcb);
139742551e99SRandall Stewart 			goto next_assoc;
139842551e99SRandall Stewart 		}
139942551e99SRandall Stewart 		/* see if we have limited out the iterator loop */
140042551e99SRandall Stewart 		iteration_count++;
140142551e99SRandall Stewart 		if (iteration_count > SCTP_ITERATOR_MAX_AT_ONCE) {
140242551e99SRandall Stewart 			/* Pause to let others grab the lock */
140342551e99SRandall Stewart 			atomic_add_int(&it->stcb->asoc.refcnt, 1);
140442551e99SRandall Stewart 			SCTP_TCB_UNLOCK(it->stcb);
1405c4739e2fSRandall Stewart 			SCTP_INP_INCR_REF(it->inp);
140642551e99SRandall Stewart 			SCTP_INP_RUNLOCK(it->inp);
140742551e99SRandall Stewart 			SCTP_ITERATOR_UNLOCK();
1408ec4c19fcSRandall Stewart 			SCTP_INP_INFO_RUNLOCK();
1409ec4c19fcSRandall Stewart 			SCTP_INP_INFO_RLOCK();
141042551e99SRandall Stewart 			SCTP_ITERATOR_LOCK();
1411f7517433SRandall Stewart 			if (sctp_it_ctl.iterator_flags) {
1412f7517433SRandall Stewart 				/* We won't be staying here */
1413f7517433SRandall Stewart 				SCTP_INP_DECR_REF(it->inp);
1414f7517433SRandall Stewart 				atomic_add_int(&it->stcb->asoc.refcnt, -1);
1415f7517433SRandall Stewart 				if (sctp_it_ctl.iterator_flags &
1416f7517433SRandall Stewart 				    SCTP_ITERATOR_STOP_CUR_IT) {
1417f7517433SRandall Stewart 					sctp_it_ctl.iterator_flags &= ~SCTP_ITERATOR_STOP_CUR_IT;
1418f7517433SRandall Stewart 					goto done_with_iterator;
1419f7517433SRandall Stewart 				}
1420f7517433SRandall Stewart 				if (sctp_it_ctl.iterator_flags &
1421f7517433SRandall Stewart 				    SCTP_ITERATOR_STOP_CUR_INP) {
1422f7517433SRandall Stewart 					sctp_it_ctl.iterator_flags &= ~SCTP_ITERATOR_STOP_CUR_INP;
1423f7517433SRandall Stewart 					goto no_stcb;
1424f7517433SRandall Stewart 				}
1425f7517433SRandall Stewart 				/* If we reach here huh? */
1426cd3fd531SMichael Tuexen 				SCTP_PRINTF("Unknown it ctl flag %x\n",
1427f7517433SRandall Stewart 				    sctp_it_ctl.iterator_flags);
1428f7517433SRandall Stewart 				sctp_it_ctl.iterator_flags = 0;
1429f7517433SRandall Stewart 			}
143042551e99SRandall Stewart 			SCTP_INP_RLOCK(it->inp);
1431c4739e2fSRandall Stewart 			SCTP_INP_DECR_REF(it->inp);
143242551e99SRandall Stewart 			SCTP_TCB_LOCK(it->stcb);
143342551e99SRandall Stewart 			atomic_add_int(&it->stcb->asoc.refcnt, -1);
143442551e99SRandall Stewart 			iteration_count = 0;
143542551e99SRandall Stewart 		}
143642551e99SRandall Stewart 		/* run function on this one */
143742551e99SRandall Stewart 		(*it->function_assoc) (it->inp, it->stcb, it->pointer, it->val);
143842551e99SRandall Stewart 
143942551e99SRandall Stewart 		/*
144042551e99SRandall Stewart 		 * we lie here, it really needs to have its own type but
144142551e99SRandall Stewart 		 * first I must verify that this won't effect things :-0
144242551e99SRandall Stewart 		 */
144342551e99SRandall Stewart 		if (it->no_chunk_output == 0)
1444ceaad40aSRandall Stewart 			sctp_chunk_output(it->inp, it->stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
144542551e99SRandall Stewart 
144642551e99SRandall Stewart 		SCTP_TCB_UNLOCK(it->stcb);
144742551e99SRandall Stewart next_assoc:
144842551e99SRandall Stewart 		it->stcb = LIST_NEXT(it->stcb, sctp_tcblist);
144942551e99SRandall Stewart 		if (it->stcb == NULL) {
145042551e99SRandall Stewart 			/* Run last function */
145142551e99SRandall Stewart 			if (it->function_inp_end != NULL) {
145242551e99SRandall Stewart 				inp_skip = (*it->function_inp_end) (it->inp,
145342551e99SRandall Stewart 				    it->pointer,
145442551e99SRandall Stewart 				    it->val);
145542551e99SRandall Stewart 			}
145642551e99SRandall Stewart 		}
145742551e99SRandall Stewart 	}
145842551e99SRandall Stewart 	SCTP_INP_RUNLOCK(it->inp);
145942551e99SRandall Stewart no_stcb:
146042551e99SRandall Stewart 	/* done with all assocs on this endpoint, move on to next endpoint */
146142551e99SRandall Stewart 	it->done_current_ep = 0;
146242551e99SRandall Stewart 	if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) {
146342551e99SRandall Stewart 		it->inp = NULL;
146442551e99SRandall Stewart 	} else {
146542551e99SRandall Stewart 		it->inp = LIST_NEXT(it->inp, sctp_list);
146642551e99SRandall Stewart 	}
146742551e99SRandall Stewart 	if (it->inp == NULL) {
146842551e99SRandall Stewart 		goto done_with_iterator;
146942551e99SRandall Stewart 	}
147042551e99SRandall Stewart 	goto select_a_new_ep;
147142551e99SRandall Stewart }
147242551e99SRandall Stewart 
147342551e99SRandall Stewart void
147442551e99SRandall Stewart sctp_iterator_worker(void)
147542551e99SRandall Stewart {
14764a9ef3f8SMichael Tuexen 	struct sctp_iterator *it, *nit;
147742551e99SRandall Stewart 
147842551e99SRandall Stewart 	/* This function is called with the WQ lock in place */
147942551e99SRandall Stewart 
1480f7517433SRandall Stewart 	sctp_it_ctl.iterator_running = 1;
14814a9ef3f8SMichael Tuexen 	TAILQ_FOREACH_SAFE(it, &sctp_it_ctl.iteratorhead, sctp_nxt_itr, nit) {
148242551e99SRandall Stewart 		/* now lets work on this one */
1483f7517433SRandall Stewart 		TAILQ_REMOVE(&sctp_it_ctl.iteratorhead, it, sctp_nxt_itr);
148442551e99SRandall Stewart 		SCTP_IPI_ITERATOR_WQ_UNLOCK();
1485f7517433SRandall Stewart 		CURVNET_SET(it->vn);
148642551e99SRandall Stewart 		sctp_iterator_work(it);
1487f7517433SRandall Stewart 		CURVNET_RESTORE();
148842551e99SRandall Stewart 		SCTP_IPI_ITERATOR_WQ_LOCK();
14893c503c28SRandall Stewart 		/* sa_ignore FREED_MEMORY */
149042551e99SRandall Stewart 	}
1491f7517433SRandall Stewart 	sctp_it_ctl.iterator_running = 0;
149242551e99SRandall Stewart 	return;
149342551e99SRandall Stewart }
149442551e99SRandall Stewart 
1495f8829a4aSRandall Stewart 
1496f8829a4aSRandall Stewart static void
1497f8829a4aSRandall Stewart sctp_handle_addr_wq(void)
1498f8829a4aSRandall Stewart {
1499f8829a4aSRandall Stewart 	/* deal with the ADDR wq from the rtsock calls */
15004a9ef3f8SMichael Tuexen 	struct sctp_laddr *wi, *nwi;
150142551e99SRandall Stewart 	struct sctp_asconf_iterator *asc;
1502f8829a4aSRandall Stewart 
150342551e99SRandall Stewart 	SCTP_MALLOC(asc, struct sctp_asconf_iterator *,
1504207304d4SRandall Stewart 	    sizeof(struct sctp_asconf_iterator), SCTP_M_ASC_IT);
150542551e99SRandall Stewart 	if (asc == NULL) {
150642551e99SRandall Stewart 		/* Try later, no memory */
1507f8829a4aSRandall Stewart 		sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ,
1508f8829a4aSRandall Stewart 		    (struct sctp_inpcb *)NULL,
1509f8829a4aSRandall Stewart 		    (struct sctp_tcb *)NULL,
1510f8829a4aSRandall Stewart 		    (struct sctp_nets *)NULL);
151142551e99SRandall Stewart 		return;
1512f8829a4aSRandall Stewart 	}
151342551e99SRandall Stewart 	LIST_INIT(&asc->list_of_work);
151442551e99SRandall Stewart 	asc->cnt = 0;
1515f7517433SRandall Stewart 
15164a9ef3f8SMichael Tuexen 	LIST_FOREACH_SAFE(wi, &SCTP_BASE_INFO(addr_wq), sctp_nxt_addr, nwi) {
151742551e99SRandall Stewart 		LIST_REMOVE(wi, sctp_nxt_addr);
151842551e99SRandall Stewart 		LIST_INSERT_HEAD(&asc->list_of_work, wi, sctp_nxt_addr);
151942551e99SRandall Stewart 		asc->cnt++;
1520f8829a4aSRandall Stewart 	}
1521f7517433SRandall Stewart 
152242551e99SRandall Stewart 	if (asc->cnt == 0) {
1523207304d4SRandall Stewart 		SCTP_FREE(asc, SCTP_M_ASC_IT);
152442551e99SRandall Stewart 	} else {
15252b1c7de4SMichael Tuexen 		int ret;
15262b1c7de4SMichael Tuexen 
15272b1c7de4SMichael Tuexen 		ret = sctp_initiate_iterator(sctp_asconf_iterator_ep,
15281b649582SRandall Stewart 		    sctp_asconf_iterator_stcb,
152942551e99SRandall Stewart 		    NULL,	/* No ep end for boundall */
153042551e99SRandall Stewart 		    SCTP_PCB_FLAGS_BOUNDALL,
153142551e99SRandall Stewart 		    SCTP_PCB_ANY_FEATURES,
15321b649582SRandall Stewart 		    SCTP_ASOC_ANY_STATE,
15331b649582SRandall Stewart 		    (void *)asc, 0,
15341b649582SRandall Stewart 		    sctp_asconf_iterator_end, NULL, 0);
15352b1c7de4SMichael Tuexen 		if (ret) {
15362b1c7de4SMichael Tuexen 			SCTP_PRINTF("Failed to initiate iterator for handle_addr_wq\n");
1537b7b84c0eSMichael Tuexen 			/*
1538b7b84c0eSMichael Tuexen 			 * Freeing if we are stopping or put back on the
1539b7b84c0eSMichael Tuexen 			 * addr_wq.
1540b7b84c0eSMichael Tuexen 			 */
15412b1c7de4SMichael Tuexen 			if (SCTP_BASE_VAR(sctp_pcb_initialized) == 0) {
15422b1c7de4SMichael Tuexen 				sctp_asconf_iterator_end(asc, 0);
15432b1c7de4SMichael Tuexen 			} else {
15442b1c7de4SMichael Tuexen 				LIST_FOREACH(wi, &asc->list_of_work, sctp_nxt_addr) {
15452b1c7de4SMichael Tuexen 					LIST_INSERT_HEAD(&SCTP_BASE_INFO(addr_wq), wi, sctp_nxt_addr);
15462b1c7de4SMichael Tuexen 				}
15472b1c7de4SMichael Tuexen 				SCTP_FREE(asc, SCTP_M_ASC_IT);
15482b1c7de4SMichael Tuexen 			}
15492b1c7de4SMichael Tuexen 		}
155042551e99SRandall Stewart 	}
1551f8829a4aSRandall Stewart }
1552f8829a4aSRandall Stewart 
1553f8829a4aSRandall Stewart void
1554f8829a4aSRandall Stewart sctp_timeout_handler(void *t)
1555f8829a4aSRandall Stewart {
1556f8829a4aSRandall Stewart 	struct sctp_inpcb *inp;
1557f8829a4aSRandall Stewart 	struct sctp_tcb *stcb;
1558f8829a4aSRandall Stewart 	struct sctp_nets *net;
1559f8829a4aSRandall Stewart 	struct sctp_timer *tmr;
1560267dbe63SMichael Tuexen 	struct mbuf *op_err;
1561ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
1562ceaad40aSRandall Stewart 	struct socket *so;
1563ceaad40aSRandall Stewart #endif
1564548f47a8SMichael Tuexen 	int did_output;
1565fa89f692SMichael Tuexen 	int type;
1566f8829a4aSRandall Stewart 
1567f8829a4aSRandall Stewart 	tmr = (struct sctp_timer *)t;
1568f8829a4aSRandall Stewart 	inp = (struct sctp_inpcb *)tmr->ep;
1569f8829a4aSRandall Stewart 	stcb = (struct sctp_tcb *)tmr->tcb;
1570f8829a4aSRandall Stewart 	net = (struct sctp_nets *)tmr->net;
15718518270eSMichael Tuexen 	CURVNET_SET((struct vnet *)tmr->vnet);
1572f8829a4aSRandall Stewart 	did_output = 1;
1573f8829a4aSRandall Stewart 
1574f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED
1575f8829a4aSRandall Stewart 	sctp_audit_log(0xF0, (uint8_t)tmr->type);
1576f8829a4aSRandall Stewart 	sctp_auditing(3, inp, stcb, net);
1577f8829a4aSRandall Stewart #endif
1578f8829a4aSRandall Stewart 
1579f8829a4aSRandall Stewart 	/* sanity checks... */
1580f8829a4aSRandall Stewart 	if (tmr->self != (void *)tmr) {
1581f8829a4aSRandall Stewart 		/*
1582ad81507eSRandall Stewart 		 * SCTP_PRINTF("Stale SCTP timer fired (%p), ignoring...\n",
1583dd294dceSMichael Tuexen 		 * (void *)tmr);
1584f8829a4aSRandall Stewart 		 */
15858518270eSMichael Tuexen 		CURVNET_RESTORE();
1586f8829a4aSRandall Stewart 		return;
1587f8829a4aSRandall Stewart 	}
1588a5d547adSRandall Stewart 	tmr->stopped_from = 0xa001;
1589f8829a4aSRandall Stewart 	if (!SCTP_IS_TIMER_TYPE_VALID(tmr->type)) {
1590f8829a4aSRandall Stewart 		/*
1591ad81507eSRandall Stewart 		 * SCTP_PRINTF("SCTP timer fired with invalid type: 0x%x\n",
1592f8829a4aSRandall Stewart 		 * tmr->type);
1593f8829a4aSRandall Stewart 		 */
15948518270eSMichael Tuexen 		CURVNET_RESTORE();
1595f8829a4aSRandall Stewart 		return;
1596f8829a4aSRandall Stewart 	}
1597a5d547adSRandall Stewart 	tmr->stopped_from = 0xa002;
1598f8829a4aSRandall Stewart 	if ((tmr->type != SCTP_TIMER_TYPE_ADDR_WQ) && (inp == NULL)) {
15998518270eSMichael Tuexen 		CURVNET_RESTORE();
1600f8829a4aSRandall Stewart 		return;
1601f8829a4aSRandall Stewart 	}
1602f8829a4aSRandall Stewart 	/* if this is an iterator timeout, get the struct and clear inp */
1603a5d547adSRandall Stewart 	tmr->stopped_from = 0xa003;
1604f8829a4aSRandall Stewart 	if (inp) {
1605f8829a4aSRandall Stewart 		SCTP_INP_INCR_REF(inp);
1606aa1808b7SMichael Tuexen 		if ((inp->sctp_socket == NULL) &&
1607f8829a4aSRandall Stewart 		    ((tmr->type != SCTP_TIMER_TYPE_INPKILL) &&
1608810ec536SMichael Tuexen 		    (tmr->type != SCTP_TIMER_TYPE_INIT) &&
1609a1e13272SRandall Stewart 		    (tmr->type != SCTP_TIMER_TYPE_SEND) &&
1610a1e13272SRandall Stewart 		    (tmr->type != SCTP_TIMER_TYPE_RECV) &&
1611a1e13272SRandall Stewart 		    (tmr->type != SCTP_TIMER_TYPE_HEARTBEAT) &&
1612f8829a4aSRandall Stewart 		    (tmr->type != SCTP_TIMER_TYPE_SHUTDOWN) &&
1613f8829a4aSRandall Stewart 		    (tmr->type != SCTP_TIMER_TYPE_SHUTDOWNACK) &&
1614f8829a4aSRandall Stewart 		    (tmr->type != SCTP_TIMER_TYPE_SHUTDOWNGUARD) &&
16152c62ba73SMichael Tuexen 		    (tmr->type != SCTP_TIMER_TYPE_ASOCKILL))) {
1616f8829a4aSRandall Stewart 			SCTP_INP_DECR_REF(inp);
16178518270eSMichael Tuexen 			CURVNET_RESTORE();
1618f8829a4aSRandall Stewart 			return;
1619f8829a4aSRandall Stewart 		}
1620f8829a4aSRandall Stewart 	}
1621a5d547adSRandall Stewart 	tmr->stopped_from = 0xa004;
1622f8829a4aSRandall Stewart 	if (stcb) {
1623c105859eSRandall Stewart 		atomic_add_int(&stcb->asoc.refcnt, 1);
1624f8829a4aSRandall Stewart 		if (stcb->asoc.state == 0) {
1625c105859eSRandall Stewart 			atomic_add_int(&stcb->asoc.refcnt, -1);
1626f8829a4aSRandall Stewart 			if (inp) {
1627f8829a4aSRandall Stewart 				SCTP_INP_DECR_REF(inp);
1628f8829a4aSRandall Stewart 			}
16298518270eSMichael Tuexen 			CURVNET_RESTORE();
1630f8829a4aSRandall Stewart 			return;
1631f8829a4aSRandall Stewart 		}
1632f8829a4aSRandall Stewart 	}
1633fa89f692SMichael Tuexen 	type = tmr->type;
1634a5d547adSRandall Stewart 	tmr->stopped_from = 0xa005;
1635fa89f692SMichael Tuexen 	SCTPDBG(SCTP_DEBUG_TIMER1, "Timer type %d goes off\n", type);
1636139bc87fSRandall Stewart 	if (!SCTP_OS_TIMER_ACTIVE(&tmr->timer)) {
1637f8829a4aSRandall Stewart 		if (inp) {
1638f8829a4aSRandall Stewart 			SCTP_INP_DECR_REF(inp);
1639f8829a4aSRandall Stewart 		}
1640207304d4SRandall Stewart 		if (stcb) {
1641207304d4SRandall Stewart 			atomic_add_int(&stcb->asoc.refcnt, -1);
1642207304d4SRandall Stewart 		}
16438518270eSMichael Tuexen 		CURVNET_RESTORE();
1644f8829a4aSRandall Stewart 		return;
1645f8829a4aSRandall Stewart 	}
1646a5d547adSRandall Stewart 	tmr->stopped_from = 0xa006;
1647a5d547adSRandall Stewart 
1648f8829a4aSRandall Stewart 	if (stcb) {
1649f8829a4aSRandall Stewart 		SCTP_TCB_LOCK(stcb);
165050cec919SRandall Stewart 		atomic_add_int(&stcb->asoc.refcnt, -1);
1651fa89f692SMichael Tuexen 		if ((type != SCTP_TIMER_TYPE_ASOCKILL) &&
1652b54d3a6cSRandall Stewart 		    ((stcb->asoc.state == 0) ||
1653b54d3a6cSRandall Stewart 		    (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED))) {
1654b54d3a6cSRandall Stewart 			SCTP_TCB_UNLOCK(stcb);
1655b54d3a6cSRandall Stewart 			if (inp) {
1656b54d3a6cSRandall Stewart 				SCTP_INP_DECR_REF(inp);
1657b54d3a6cSRandall Stewart 			}
16588518270eSMichael Tuexen 			CURVNET_RESTORE();
1659b54d3a6cSRandall Stewart 			return;
1660b54d3a6cSRandall Stewart 		}
16612c62ba73SMichael Tuexen 	} else if (inp != NULL) {
16622c62ba73SMichael Tuexen 		if (type != SCTP_TIMER_TYPE_INPKILL) {
16632c62ba73SMichael Tuexen 			SCTP_INP_WLOCK(inp);
16642c62ba73SMichael Tuexen 		}
16652c62ba73SMichael Tuexen 	} else {
16662c62ba73SMichael Tuexen 		SCTP_WQ_ADDR_LOCK();
1667f8829a4aSRandall Stewart 	}
1668cd0a4ff6SPedro F. Giffuni 	/* record in stopped what t-o occurred */
1669fa89f692SMichael Tuexen 	tmr->stopped_from = type;
167044b7479bSRandall Stewart 
1671f8829a4aSRandall Stewart 	/* mark as being serviced now */
167244b7479bSRandall Stewart 	if (SCTP_OS_TIMER_PENDING(&tmr->timer)) {
167344b7479bSRandall Stewart 		/*
167444b7479bSRandall Stewart 		 * Callout has been rescheduled.
167544b7479bSRandall Stewart 		 */
167644b7479bSRandall Stewart 		goto get_out;
167744b7479bSRandall Stewart 	}
167844b7479bSRandall Stewart 	if (!SCTP_OS_TIMER_ACTIVE(&tmr->timer)) {
167944b7479bSRandall Stewart 		/*
168044b7479bSRandall Stewart 		 * Not active, so no action.
168144b7479bSRandall Stewart 		 */
168244b7479bSRandall Stewart 		goto get_out;
168344b7479bSRandall Stewart 	}
1684139bc87fSRandall Stewart 	SCTP_OS_TIMER_DEACTIVATE(&tmr->timer);
1685f8829a4aSRandall Stewart 
1686f8829a4aSRandall Stewart 	/* call the handler for the appropriate timer type */
1687fa89f692SMichael Tuexen 	switch (type) {
1688f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_ADDR_WQ:
1689f8829a4aSRandall Stewart 		sctp_handle_addr_wq();
1690f8829a4aSRandall Stewart 		break;
1691f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_SEND:
1692ad81507eSRandall Stewart 		if ((stcb == NULL) || (inp == NULL)) {
1693ad81507eSRandall Stewart 			break;
1694ad81507eSRandall Stewart 		}
1695f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_timodata);
1696f42a358aSRandall Stewart 		stcb->asoc.timodata++;
1697f8829a4aSRandall Stewart 		stcb->asoc.num_send_timers_up--;
1698f8829a4aSRandall Stewart 		if (stcb->asoc.num_send_timers_up < 0) {
1699f8829a4aSRandall Stewart 			stcb->asoc.num_send_timers_up = 0;
1700f8829a4aSRandall Stewart 		}
1701b54d3a6cSRandall Stewart 		SCTP_TCB_LOCK_ASSERT(stcb);
170260990c0cSMichael Tuexen 		if (sctp_t3rxt_timer(inp, stcb, net)) {
1703f8829a4aSRandall Stewart 			/* no need to unlock on tcb its gone */
1704f8829a4aSRandall Stewart 
1705f8829a4aSRandall Stewart 			goto out_decr;
1706f8829a4aSRandall Stewart 		}
1707b54d3a6cSRandall Stewart 		SCTP_TCB_LOCK_ASSERT(stcb);
1708f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED
1709f8829a4aSRandall Stewart 		sctp_auditing(4, inp, stcb, net);
1710f8829a4aSRandall Stewart #endif
1711ceaad40aSRandall Stewart 		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
1712f8829a4aSRandall Stewart 		if ((stcb->asoc.num_send_timers_up == 0) &&
17134a9ef3f8SMichael Tuexen 		    (stcb->asoc.sent_queue_cnt > 0)) {
1714f8829a4aSRandall Stewart 			struct sctp_tmit_chunk *chk;
1715f8829a4aSRandall Stewart 
1716f8829a4aSRandall Stewart 			/*
1717f8829a4aSRandall Stewart 			 * safeguard. If there on some on the sent queue
1718f8829a4aSRandall Stewart 			 * somewhere but no timers running something is
1719f8829a4aSRandall Stewart 			 * wrong... so we start a timer on the first chunk
1720f8829a4aSRandall Stewart 			 * on the send queue on whatever net it is sent to.
1721f8829a4aSRandall Stewart 			 */
1722f8829a4aSRandall Stewart 			chk = TAILQ_FIRST(&stcb->asoc.sent_queue);
1723f8829a4aSRandall Stewart 			sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb,
1724f8829a4aSRandall Stewart 			    chk->whoTo);
1725f8829a4aSRandall Stewart 		}
1726f8829a4aSRandall Stewart 		break;
1727f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_INIT:
1728ad81507eSRandall Stewart 		if ((stcb == NULL) || (inp == NULL)) {
1729ad81507eSRandall Stewart 			break;
1730ad81507eSRandall Stewart 		}
1731f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_timoinit);
1732f42a358aSRandall Stewart 		stcb->asoc.timoinit++;
1733f8829a4aSRandall Stewart 		if (sctp_t1init_timer(inp, stcb, net)) {
1734f8829a4aSRandall Stewart 			/* no need to unlock on tcb its gone */
1735f8829a4aSRandall Stewart 			goto out_decr;
1736f8829a4aSRandall Stewart 		}
1737f8829a4aSRandall Stewart 		/* We do output but not here */
1738f8829a4aSRandall Stewart 		did_output = 0;
1739f8829a4aSRandall Stewart 		break;
1740f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_RECV:
1741ad81507eSRandall Stewart 		if ((stcb == NULL) || (inp == NULL)) {
1742ad81507eSRandall Stewart 			break;
1743ca85e948SMichael Tuexen 		}
1744f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_timosack);
1745f42a358aSRandall Stewart 		stcb->asoc.timosack++;
1746689e6a5fSMichael Tuexen 		sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED);
1747f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED
1748f8829a4aSRandall Stewart 		sctp_auditing(4, inp, stcb, net);
1749f8829a4aSRandall Stewart #endif
1750ceaad40aSRandall Stewart 		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SACK_TMR, SCTP_SO_NOT_LOCKED);
1751f8829a4aSRandall Stewart 		break;
1752f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_SHUTDOWN:
1753ad81507eSRandall Stewart 		if ((stcb == NULL) || (inp == NULL)) {
1754ad81507eSRandall Stewart 			break;
1755ad81507eSRandall Stewart 		}
1756f8829a4aSRandall Stewart 		if (sctp_shutdown_timer(inp, stcb, net)) {
1757f8829a4aSRandall Stewart 			/* no need to unlock on tcb its gone */
1758f8829a4aSRandall Stewart 			goto out_decr;
1759f8829a4aSRandall Stewart 		}
1760f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_timoshutdown);
1761f42a358aSRandall Stewart 		stcb->asoc.timoshutdown++;
1762f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED
1763f8829a4aSRandall Stewart 		sctp_auditing(4, inp, stcb, net);
1764f8829a4aSRandall Stewart #endif
1765ceaad40aSRandall Stewart 		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_TMR, SCTP_SO_NOT_LOCKED);
1766f8829a4aSRandall Stewart 		break;
1767f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_HEARTBEAT:
1768ca85e948SMichael Tuexen 		if ((stcb == NULL) || (inp == NULL) || (net == NULL)) {
1769ad81507eSRandall Stewart 			break;
1770ad81507eSRandall Stewart 		}
1771f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_timoheartbeat);
1772f42a358aSRandall Stewart 		stcb->asoc.timoheartbeat++;
1773ca85e948SMichael Tuexen 		if (sctp_heartbeat_timer(inp, stcb, net)) {
1774f8829a4aSRandall Stewart 			/* no need to unlock on tcb its gone */
1775f8829a4aSRandall Stewart 			goto out_decr;
1776f8829a4aSRandall Stewart 		}
1777f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED
1778ca85e948SMichael Tuexen 		sctp_auditing(4, inp, stcb, net);
1779f8829a4aSRandall Stewart #endif
1780ca85e948SMichael Tuexen 		if (!(net->dest_state & SCTP_ADDR_NOHB)) {
1781629749b6SMichael Tuexen 			sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
1782ceaad40aSRandall Stewart 			sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_HB_TMR, SCTP_SO_NOT_LOCKED);
1783f8829a4aSRandall Stewart 		}
1784f8829a4aSRandall Stewart 		break;
1785f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_COOKIE:
1786ad81507eSRandall Stewart 		if ((stcb == NULL) || (inp == NULL)) {
1787ad81507eSRandall Stewart 			break;
1788ad81507eSRandall Stewart 		}
1789f8829a4aSRandall Stewart 		if (sctp_cookie_timer(inp, stcb, net)) {
1790f8829a4aSRandall Stewart 			/* no need to unlock on tcb its gone */
1791f8829a4aSRandall Stewart 			goto out_decr;
1792f8829a4aSRandall Stewart 		}
1793f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_timocookie);
1794f42a358aSRandall Stewart 		stcb->asoc.timocookie++;
1795f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED
1796f8829a4aSRandall Stewart 		sctp_auditing(4, inp, stcb, net);
1797f8829a4aSRandall Stewart #endif
1798f8829a4aSRandall Stewart 		/*
1799f8829a4aSRandall Stewart 		 * We consider T3 and Cookie timer pretty much the same with
1800f8829a4aSRandall Stewart 		 * respect to where from in chunk_output.
1801f8829a4aSRandall Stewart 		 */
1802ceaad40aSRandall Stewart 		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
1803f8829a4aSRandall Stewart 		break;
1804f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_NEWCOOKIE:
1805f8829a4aSRandall Stewart 		{
1806f8829a4aSRandall Stewart 			struct timeval tv;
1807f8829a4aSRandall Stewart 			int i, secret;
1808f8829a4aSRandall Stewart 
1809ad81507eSRandall Stewart 			if (inp == NULL) {
1810ad81507eSRandall Stewart 				break;
1811ad81507eSRandall Stewart 			}
1812f8829a4aSRandall Stewart 			SCTP_STAT_INCR(sctps_timosecret);
18136e55db54SRandall Stewart 			(void)SCTP_GETTIME_TIMEVAL(&tv);
1814f8829a4aSRandall Stewart 			inp->sctp_ep.time_of_secret_change = tv.tv_sec;
1815f8829a4aSRandall Stewart 			inp->sctp_ep.last_secret_number =
1816f8829a4aSRandall Stewart 			    inp->sctp_ep.current_secret_number;
1817f8829a4aSRandall Stewart 			inp->sctp_ep.current_secret_number++;
1818f8829a4aSRandall Stewart 			if (inp->sctp_ep.current_secret_number >=
1819f8829a4aSRandall Stewart 			    SCTP_HOW_MANY_SECRETS) {
1820f8829a4aSRandall Stewart 				inp->sctp_ep.current_secret_number = 0;
1821f8829a4aSRandall Stewart 			}
1822f8829a4aSRandall Stewart 			secret = (int)inp->sctp_ep.current_secret_number;
1823f8829a4aSRandall Stewart 			for (i = 0; i < SCTP_NUMBER_OF_SECRETS; i++) {
1824f8829a4aSRandall Stewart 				inp->sctp_ep.secret_key[secret][i] =
1825f8829a4aSRandall Stewart 				    sctp_select_initial_TSN(&inp->sctp_ep);
1826f8829a4aSRandall Stewart 			}
1827f8829a4aSRandall Stewart 			sctp_timer_start(SCTP_TIMER_TYPE_NEWCOOKIE, inp, stcb, net);
1828f8829a4aSRandall Stewart 		}
1829f8829a4aSRandall Stewart 		did_output = 0;
1830f8829a4aSRandall Stewart 		break;
1831f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_PATHMTURAISE:
1832ad81507eSRandall Stewart 		if ((stcb == NULL) || (inp == NULL)) {
1833ad81507eSRandall Stewart 			break;
1834ad81507eSRandall Stewart 		}
1835f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_timopathmtu);
1836f8829a4aSRandall Stewart 		sctp_pathmtu_timer(inp, stcb, net);
1837f8829a4aSRandall Stewart 		did_output = 0;
1838f8829a4aSRandall Stewart 		break;
1839f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_SHUTDOWNACK:
1840ad81507eSRandall Stewart 		if ((stcb == NULL) || (inp == NULL)) {
1841ad81507eSRandall Stewart 			break;
1842ad81507eSRandall Stewart 		}
1843f8829a4aSRandall Stewart 		if (sctp_shutdownack_timer(inp, stcb, net)) {
1844f8829a4aSRandall Stewart 			/* no need to unlock on tcb its gone */
1845f8829a4aSRandall Stewart 			goto out_decr;
1846f8829a4aSRandall Stewart 		}
1847f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_timoshutdownack);
1848f42a358aSRandall Stewart 		stcb->asoc.timoshutdownack++;
1849f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED
1850f8829a4aSRandall Stewart 		sctp_auditing(4, inp, stcb, net);
1851f8829a4aSRandall Stewart #endif
1852ceaad40aSRandall Stewart 		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_ACK_TMR, SCTP_SO_NOT_LOCKED);
1853f8829a4aSRandall Stewart 		break;
1854f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_SHUTDOWNGUARD:
1855ad81507eSRandall Stewart 		if ((stcb == NULL) || (inp == NULL)) {
1856ad81507eSRandall Stewart 			break;
1857ad81507eSRandall Stewart 		}
1858f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_timoshutdownguard);
1859267dbe63SMichael Tuexen 		op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
1860267dbe63SMichael Tuexen 		    "Shutdown guard timer expired");
1861267dbe63SMichael Tuexen 		sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED);
1862f8829a4aSRandall Stewart 		/* no need to unlock on tcb its gone */
1863f8829a4aSRandall Stewart 		goto out_decr;
1864f8829a4aSRandall Stewart 
1865f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_STRRESET:
1866ad81507eSRandall Stewart 		if ((stcb == NULL) || (inp == NULL)) {
1867ad81507eSRandall Stewart 			break;
1868ad81507eSRandall Stewart 		}
1869f8829a4aSRandall Stewart 		if (sctp_strreset_timer(inp, stcb, net)) {
1870f8829a4aSRandall Stewart 			/* no need to unlock on tcb its gone */
1871f8829a4aSRandall Stewart 			goto out_decr;
1872f8829a4aSRandall Stewart 		}
1873f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_timostrmrst);
1874ceaad40aSRandall Stewart 		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_TMR, SCTP_SO_NOT_LOCKED);
1875f8829a4aSRandall Stewart 		break;
1876f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_ASCONF:
1877ad81507eSRandall Stewart 		if ((stcb == NULL) || (inp == NULL)) {
1878ad81507eSRandall Stewart 			break;
1879ad81507eSRandall Stewart 		}
1880f8829a4aSRandall Stewart 		if (sctp_asconf_timer(inp, stcb, net)) {
1881f8829a4aSRandall Stewart 			/* no need to unlock on tcb its gone */
1882f8829a4aSRandall Stewart 			goto out_decr;
1883f8829a4aSRandall Stewart 		}
1884f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_timoasconf);
1885f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED
1886f8829a4aSRandall Stewart 		sctp_auditing(4, inp, stcb, net);
1887f8829a4aSRandall Stewart #endif
1888ceaad40aSRandall Stewart 		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_ASCONF_TMR, SCTP_SO_NOT_LOCKED);
1889f8829a4aSRandall Stewart 		break;
1890851b7298SRandall Stewart 	case SCTP_TIMER_TYPE_PRIM_DELETED:
1891851b7298SRandall Stewart 		if ((stcb == NULL) || (inp == NULL)) {
1892851b7298SRandall Stewart 			break;
1893851b7298SRandall Stewart 		}
189404ee05e8SRandall Stewart 		sctp_delete_prim_timer(inp, stcb, net);
1895851b7298SRandall Stewart 		SCTP_STAT_INCR(sctps_timodelprim);
1896851b7298SRandall Stewart 		break;
1897f8829a4aSRandall Stewart 
1898f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_AUTOCLOSE:
1899ad81507eSRandall Stewart 		if ((stcb == NULL) || (inp == NULL)) {
1900ad81507eSRandall Stewart 			break;
1901ad81507eSRandall Stewart 		}
1902f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_timoautoclose);
1903f8829a4aSRandall Stewart 		sctp_autoclose_timer(inp, stcb, net);
1904ceaad40aSRandall Stewart 		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_AUTOCLOSE_TMR, SCTP_SO_NOT_LOCKED);
1905f8829a4aSRandall Stewart 		did_output = 0;
1906f8829a4aSRandall Stewart 		break;
1907f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_ASOCKILL:
1908ad81507eSRandall Stewart 		if ((stcb == NULL) || (inp == NULL)) {
1909ad81507eSRandall Stewart 			break;
1910ad81507eSRandall Stewart 		}
1911f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_timoassockill);
1912f8829a4aSRandall Stewart 		/* Can we free it yet? */
1913f8829a4aSRandall Stewart 		SCTP_INP_DECR_REF(inp);
1914ba785902SMichael Tuexen 		sctp_timer_stop(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL,
1915ba785902SMichael Tuexen 		    SCTP_FROM_SCTPUTIL + SCTP_LOC_1);
1916ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
1917ceaad40aSRandall Stewart 		so = SCTP_INP_SO(inp);
1918ceaad40aSRandall Stewart 		atomic_add_int(&stcb->asoc.refcnt, 1);
1919ceaad40aSRandall Stewart 		SCTP_TCB_UNLOCK(stcb);
1920ceaad40aSRandall Stewart 		SCTP_SOCKET_LOCK(so, 1);
1921ceaad40aSRandall Stewart 		SCTP_TCB_LOCK(stcb);
1922ceaad40aSRandall Stewart 		atomic_subtract_int(&stcb->asoc.refcnt, 1);
1923ceaad40aSRandall Stewart #endif
1924ba785902SMichael Tuexen 		(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
1925ba785902SMichael Tuexen 		    SCTP_FROM_SCTPUTIL + SCTP_LOC_2);
1926ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
1927ceaad40aSRandall Stewart 		SCTP_SOCKET_UNLOCK(so, 1);
1928ceaad40aSRandall Stewart #endif
1929f8829a4aSRandall Stewart 		/*
1930f8829a4aSRandall Stewart 		 * free asoc, always unlocks (or destroy's) so prevent
1931f8829a4aSRandall Stewart 		 * duplicate unlock or unlock of a free mtx :-0
1932f8829a4aSRandall Stewart 		 */
1933f8829a4aSRandall Stewart 		stcb = NULL;
1934f8829a4aSRandall Stewart 		goto out_no_decr;
1935f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_INPKILL:
1936f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_timoinpkill);
1937ad81507eSRandall Stewart 		if (inp == NULL) {
1938ad81507eSRandall Stewart 			break;
1939ad81507eSRandall Stewart 		}
1940f8829a4aSRandall Stewart 		/*
1941f8829a4aSRandall Stewart 		 * special case, take away our increment since WE are the
1942f8829a4aSRandall Stewart 		 * killer
1943f8829a4aSRandall Stewart 		 */
1944f8829a4aSRandall Stewart 		SCTP_INP_DECR_REF(inp);
1945ba785902SMichael Tuexen 		sctp_timer_stop(SCTP_TIMER_TYPE_INPKILL, inp, NULL, NULL,
1946ba785902SMichael Tuexen 		    SCTP_FROM_SCTPUTIL + SCTP_LOC_3);
1947b0552ae2SRandall Stewart 		sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
19480c7dc840SRandall Stewart 		    SCTP_CALLED_FROM_INPKILL_TIMER);
1949d61374e1SRandall Stewart 		inp = NULL;
1950f8829a4aSRandall Stewart 		goto out_no_decr;
1951f8829a4aSRandall Stewart 	default:
1952ad81507eSRandall Stewart 		SCTPDBG(SCTP_DEBUG_TIMER1, "sctp_timeout_handler:unknown timer %d\n",
1953fa89f692SMichael Tuexen 		    type);
1954f8829a4aSRandall Stewart 		break;
195560990c0cSMichael Tuexen 	}
1956f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED
1957fa89f692SMichael Tuexen 	sctp_audit_log(0xF1, (uint8_t)type);
1958f8829a4aSRandall Stewart 	if (inp)
1959f8829a4aSRandall Stewart 		sctp_auditing(5, inp, stcb, net);
1960f8829a4aSRandall Stewart #endif
1961f8829a4aSRandall Stewart 	if ((did_output) && stcb) {
1962f8829a4aSRandall Stewart 		/*
1963f8829a4aSRandall Stewart 		 * Now we need to clean up the control chunk chain if an
1964f8829a4aSRandall Stewart 		 * ECNE is on it. It must be marked as UNSENT again so next
1965f8829a4aSRandall Stewart 		 * call will continue to send it until such time that we get
1966f8829a4aSRandall Stewart 		 * a CWR, to remove it. It is, however, less likely that we
1967f8829a4aSRandall Stewart 		 * will find a ecn echo on the chain though.
1968f8829a4aSRandall Stewart 		 */
1969f8829a4aSRandall Stewart 		sctp_fix_ecn_echo(&stcb->asoc);
1970f8829a4aSRandall Stewart 	}
197144b7479bSRandall Stewart get_out:
1972f8829a4aSRandall Stewart 	if (stcb) {
1973f8829a4aSRandall Stewart 		SCTP_TCB_UNLOCK(stcb);
19742c62ba73SMichael Tuexen 	} else if (inp != NULL) {
19752c62ba73SMichael Tuexen 		SCTP_INP_WUNLOCK(inp);
19762c62ba73SMichael Tuexen 	} else {
19772c62ba73SMichael Tuexen 		SCTP_WQ_ADDR_UNLOCK();
1978f8829a4aSRandall Stewart 	}
19792c62ba73SMichael Tuexen 
1980f8829a4aSRandall Stewart out_decr:
1981f8829a4aSRandall Stewart 	if (inp) {
1982f8829a4aSRandall Stewart 		SCTP_INP_DECR_REF(inp);
1983f8829a4aSRandall Stewart 	}
1984f8829a4aSRandall Stewart out_no_decr:
1985fa89f692SMichael Tuexen 	SCTPDBG(SCTP_DEBUG_TIMER1, "Timer now complete (type = %d)\n", type);
19868518270eSMichael Tuexen 	CURVNET_RESTORE();
1987f8829a4aSRandall Stewart }
1988f8829a4aSRandall Stewart 
1989ad81507eSRandall Stewart void
1990f8829a4aSRandall Stewart sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
1991f8829a4aSRandall Stewart     struct sctp_nets *net)
1992f8829a4aSRandall Stewart {
1993ca85e948SMichael Tuexen 	uint32_t to_ticks;
1994f8829a4aSRandall Stewart 	struct sctp_timer *tmr;
1995f8829a4aSRandall Stewart 
1996139bc87fSRandall Stewart 	if ((t_type != SCTP_TIMER_TYPE_ADDR_WQ) && (inp == NULL))
1997ad81507eSRandall Stewart 		return;
1998f8829a4aSRandall Stewart 
1999f8829a4aSRandall Stewart 	tmr = NULL;
2000f8829a4aSRandall Stewart 	if (stcb) {
2001f8829a4aSRandall Stewart 		SCTP_TCB_LOCK_ASSERT(stcb);
2002f8829a4aSRandall Stewart 	}
2003f8829a4aSRandall Stewart 	switch (t_type) {
2004f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_ADDR_WQ:
2005f8829a4aSRandall Stewart 		/* Only 1 tick away :-) */
2006b3f1ea41SRandall Stewart 		tmr = &SCTP_BASE_INFO(addr_wq_timer);
200742551e99SRandall Stewart 		to_ticks = SCTP_ADDRESS_TICK_DELAY;
2008f8829a4aSRandall Stewart 		break;
2009f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_SEND:
2010f8829a4aSRandall Stewart 		/* Here we use the RTO timer */
2011f8829a4aSRandall Stewart 		{
2012f8829a4aSRandall Stewart 			int rto_val;
2013f8829a4aSRandall Stewart 
2014f8829a4aSRandall Stewart 			if ((stcb == NULL) || (net == NULL)) {
2015ad81507eSRandall Stewart 				return;
2016f8829a4aSRandall Stewart 			}
2017f8829a4aSRandall Stewart 			tmr = &net->rxt_timer;
2018f8829a4aSRandall Stewart 			if (net->RTO == 0) {
2019f8829a4aSRandall Stewart 				rto_val = stcb->asoc.initial_rto;
2020f8829a4aSRandall Stewart 			} else {
2021f8829a4aSRandall Stewart 				rto_val = net->RTO;
2022f8829a4aSRandall Stewart 			}
2023f8829a4aSRandall Stewart 			to_ticks = MSEC_TO_TICKS(rto_val);
2024f8829a4aSRandall Stewart 		}
2025f8829a4aSRandall Stewart 		break;
2026f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_INIT:
2027f8829a4aSRandall Stewart 		/*
2028f8829a4aSRandall Stewart 		 * Here we use the INIT timer default usually about 1
2029f8829a4aSRandall Stewart 		 * minute.
2030f8829a4aSRandall Stewart 		 */
2031f8829a4aSRandall Stewart 		if ((stcb == NULL) || (net == NULL)) {
2032ad81507eSRandall Stewart 			return;
2033f8829a4aSRandall Stewart 		}
2034f8829a4aSRandall Stewart 		tmr = &net->rxt_timer;
2035f8829a4aSRandall Stewart 		if (net->RTO == 0) {
2036f8829a4aSRandall Stewart 			to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
2037f8829a4aSRandall Stewart 		} else {
2038f8829a4aSRandall Stewart 			to_ticks = MSEC_TO_TICKS(net->RTO);
2039f8829a4aSRandall Stewart 		}
2040f8829a4aSRandall Stewart 		break;
2041f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_RECV:
2042f8829a4aSRandall Stewart 		/*
2043f8829a4aSRandall Stewart 		 * Here we use the Delayed-Ack timer value from the inp
2044f8829a4aSRandall Stewart 		 * ususually about 200ms.
2045f8829a4aSRandall Stewart 		 */
2046f8829a4aSRandall Stewart 		if (stcb == NULL) {
2047ad81507eSRandall Stewart 			return;
2048f8829a4aSRandall Stewart 		}
2049f8829a4aSRandall Stewart 		tmr = &stcb->asoc.dack_timer;
2050f8829a4aSRandall Stewart 		to_ticks = MSEC_TO_TICKS(stcb->asoc.delayed_ack);
2051f8829a4aSRandall Stewart 		break;
2052f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_SHUTDOWN:
2053f8829a4aSRandall Stewart 		/* Here we use the RTO of the destination. */
2054f8829a4aSRandall Stewart 		if ((stcb == NULL) || (net == NULL)) {
2055ad81507eSRandall Stewart 			return;
2056f8829a4aSRandall Stewart 		}
2057f8829a4aSRandall Stewart 		if (net->RTO == 0) {
2058f8829a4aSRandall Stewart 			to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
2059f8829a4aSRandall Stewart 		} else {
2060f8829a4aSRandall Stewart 			to_ticks = MSEC_TO_TICKS(net->RTO);
2061f8829a4aSRandall Stewart 		}
2062f8829a4aSRandall Stewart 		tmr = &net->rxt_timer;
2063f8829a4aSRandall Stewart 		break;
2064f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_HEARTBEAT:
2065f8829a4aSRandall Stewart 		/*
2066f8829a4aSRandall Stewart 		 * the net is used here so that we can add in the RTO. Even
2067f8829a4aSRandall Stewart 		 * though we use a different timer. We also add the HB timer
2068f8829a4aSRandall Stewart 		 * PLUS a random jitter.
2069f8829a4aSRandall Stewart 		 */
2070f3ba71beSMichael Tuexen 		if ((stcb == NULL) || (net == NULL)) {
2071ad81507eSRandall Stewart 			return;
2072ad81507eSRandall Stewart 		} else {
2073f8829a4aSRandall Stewart 			uint32_t rndval;
2074ca85e948SMichael Tuexen 			uint32_t jitter;
2075f8829a4aSRandall Stewart 
2076ca85e948SMichael Tuexen 			if ((net->dest_state & SCTP_ADDR_NOHB) &&
2077ca85e948SMichael Tuexen 			    !(net->dest_state & SCTP_ADDR_UNCONFIRMED)) {
2078ad81507eSRandall Stewart 				return;
2079f8829a4aSRandall Stewart 			}
2080f8829a4aSRandall Stewart 			if (net->RTO == 0) {
2081ca85e948SMichael Tuexen 				to_ticks = stcb->asoc.initial_rto;
2082f8829a4aSRandall Stewart 			} else {
2083ca85e948SMichael Tuexen 				to_ticks = net->RTO;
2084f8829a4aSRandall Stewart 			}
2085ca85e948SMichael Tuexen 			rndval = sctp_select_initial_TSN(&inp->sctp_ep);
2086ca85e948SMichael Tuexen 			jitter = rndval % to_ticks;
2087ca85e948SMichael Tuexen 			if (jitter >= (to_ticks >> 1)) {
2088ca85e948SMichael Tuexen 				to_ticks = to_ticks + (jitter - (to_ticks >> 1));
2089f8829a4aSRandall Stewart 			} else {
2090ca85e948SMichael Tuexen 				to_ticks = to_ticks - jitter;
2091f8829a4aSRandall Stewart 			}
2092ca85e948SMichael Tuexen 			if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED) &&
2093ca85e948SMichael Tuexen 			    !(net->dest_state & SCTP_ADDR_PF)) {
2094ca85e948SMichael Tuexen 				to_ticks += net->heart_beat_delay;
2095f8829a4aSRandall Stewart 			}
2096f8829a4aSRandall Stewart 			/*
2097f8829a4aSRandall Stewart 			 * Now we must convert the to_ticks that are now in
2098f8829a4aSRandall Stewart 			 * ms to ticks.
2099f8829a4aSRandall Stewart 			 */
2100f8829a4aSRandall Stewart 			to_ticks = MSEC_TO_TICKS(to_ticks);
2101ca85e948SMichael Tuexen 			tmr = &net->hb_timer;
2102f8829a4aSRandall Stewart 		}
2103f8829a4aSRandall Stewart 		break;
2104f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_COOKIE:
2105f8829a4aSRandall Stewart 		/*
2106f8829a4aSRandall Stewart 		 * Here we can use the RTO timer from the network since one
2107f8829a4aSRandall Stewart 		 * RTT was compelete. If a retran happened then we will be
2108f8829a4aSRandall Stewart 		 * using the RTO initial value.
2109f8829a4aSRandall Stewart 		 */
2110f8829a4aSRandall Stewart 		if ((stcb == NULL) || (net == NULL)) {
2111ad81507eSRandall Stewart 			return;
2112f8829a4aSRandall Stewart 		}
2113f8829a4aSRandall Stewart 		if (net->RTO == 0) {
2114f8829a4aSRandall Stewart 			to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
2115f8829a4aSRandall Stewart 		} else {
2116f8829a4aSRandall Stewart 			to_ticks = MSEC_TO_TICKS(net->RTO);
2117f8829a4aSRandall Stewart 		}
2118f8829a4aSRandall Stewart 		tmr = &net->rxt_timer;
2119f8829a4aSRandall Stewart 		break;
2120f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_NEWCOOKIE:
2121f8829a4aSRandall Stewart 		/*
2122f8829a4aSRandall Stewart 		 * nothing needed but the endpoint here ususually about 60
2123f8829a4aSRandall Stewart 		 * minutes.
2124f8829a4aSRandall Stewart 		 */
2125f8829a4aSRandall Stewart 		tmr = &inp->sctp_ep.signature_change;
2126f8829a4aSRandall Stewart 		to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_SIGNATURE];
2127f8829a4aSRandall Stewart 		break;
2128f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_ASOCKILL:
2129f8829a4aSRandall Stewart 		if (stcb == NULL) {
2130ad81507eSRandall Stewart 			return;
2131f8829a4aSRandall Stewart 		}
2132f8829a4aSRandall Stewart 		tmr = &stcb->asoc.strreset_timer;
2133f8829a4aSRandall Stewart 		to_ticks = MSEC_TO_TICKS(SCTP_ASOC_KILL_TIMEOUT);
2134f8829a4aSRandall Stewart 		break;
2135f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_INPKILL:
2136f8829a4aSRandall Stewart 		/*
2137f8829a4aSRandall Stewart 		 * The inp is setup to die. We re-use the signature_chage
2138f8829a4aSRandall Stewart 		 * timer since that has stopped and we are in the GONE
2139f8829a4aSRandall Stewart 		 * state.
2140f8829a4aSRandall Stewart 		 */
2141f8829a4aSRandall Stewart 		tmr = &inp->sctp_ep.signature_change;
2142f8829a4aSRandall Stewart 		to_ticks = MSEC_TO_TICKS(SCTP_INP_KILL_TIMEOUT);
2143f8829a4aSRandall Stewart 		break;
2144f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_PATHMTURAISE:
2145f8829a4aSRandall Stewart 		/*
2146f8829a4aSRandall Stewart 		 * Here we use the value found in the EP for PMTU ususually
2147f8829a4aSRandall Stewart 		 * about 10 minutes.
2148f8829a4aSRandall Stewart 		 */
2149f3ba71beSMichael Tuexen 		if ((stcb == NULL) || (net == NULL)) {
2150ad81507eSRandall Stewart 			return;
2151f8829a4aSRandall Stewart 		}
215280c79bbeSMichael Tuexen 		if (net->dest_state & SCTP_ADDR_NO_PMTUD) {
215380c79bbeSMichael Tuexen 			return;
215480c79bbeSMichael Tuexen 		}
2155f8829a4aSRandall Stewart 		to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_PMTU];
2156f8829a4aSRandall Stewart 		tmr = &net->pmtu_timer;
2157f8829a4aSRandall Stewart 		break;
2158f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_SHUTDOWNACK:
2159f8829a4aSRandall Stewart 		/* Here we use the RTO of the destination */
2160f8829a4aSRandall Stewart 		if ((stcb == NULL) || (net == NULL)) {
2161ad81507eSRandall Stewart 			return;
2162f8829a4aSRandall Stewart 		}
2163f8829a4aSRandall Stewart 		if (net->RTO == 0) {
2164f8829a4aSRandall Stewart 			to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
2165f8829a4aSRandall Stewart 		} else {
2166f8829a4aSRandall Stewart 			to_ticks = MSEC_TO_TICKS(net->RTO);
2167f8829a4aSRandall Stewart 		}
2168f8829a4aSRandall Stewart 		tmr = &net->rxt_timer;
2169f8829a4aSRandall Stewart 		break;
2170f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_SHUTDOWNGUARD:
2171f8829a4aSRandall Stewart 		/*
2172f8829a4aSRandall Stewart 		 * Here we use the endpoints shutdown guard timer usually
2173f8829a4aSRandall Stewart 		 * about 3 minutes.
2174f8829a4aSRandall Stewart 		 */
2175f3ba71beSMichael Tuexen 		if (stcb == NULL) {
2176ad81507eSRandall Stewart 			return;
2177f8829a4aSRandall Stewart 		}
21782e2d6794SMichael Tuexen 		if (inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_MAXSHUTDOWN] == 0) {
21792e2d6794SMichael Tuexen 			to_ticks = 5 * MSEC_TO_TICKS(stcb->asoc.maxrto);
21802e2d6794SMichael Tuexen 		} else {
2181f8829a4aSRandall Stewart 			to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_MAXSHUTDOWN];
21822e2d6794SMichael Tuexen 		}
2183f8829a4aSRandall Stewart 		tmr = &stcb->asoc.shut_guard_timer;
2184f8829a4aSRandall Stewart 		break;
2185f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_STRRESET:
2186f8829a4aSRandall Stewart 		/*
21871b649582SRandall Stewart 		 * Here the timer comes from the stcb but its value is from
21881b649582SRandall Stewart 		 * the net's RTO.
2189f8829a4aSRandall Stewart 		 */
2190f8829a4aSRandall Stewart 		if ((stcb == NULL) || (net == NULL)) {
2191ad81507eSRandall Stewart 			return;
2192f8829a4aSRandall Stewart 		}
2193f8829a4aSRandall Stewart 		if (net->RTO == 0) {
2194f8829a4aSRandall Stewart 			to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
2195f8829a4aSRandall Stewart 		} else {
2196f8829a4aSRandall Stewart 			to_ticks = MSEC_TO_TICKS(net->RTO);
2197f8829a4aSRandall Stewart 		}
2198f8829a4aSRandall Stewart 		tmr = &stcb->asoc.strreset_timer;
2199f8829a4aSRandall Stewart 		break;
2200f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_ASCONF:
2201f8829a4aSRandall Stewart 		/*
22021b649582SRandall Stewart 		 * Here the timer comes from the stcb but its value is from
22031b649582SRandall Stewart 		 * the net's RTO.
2204f8829a4aSRandall Stewart 		 */
2205f8829a4aSRandall Stewart 		if ((stcb == NULL) || (net == NULL)) {
2206ad81507eSRandall Stewart 			return;
2207f8829a4aSRandall Stewart 		}
2208f8829a4aSRandall Stewart 		if (net->RTO == 0) {
2209f8829a4aSRandall Stewart 			to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
2210f8829a4aSRandall Stewart 		} else {
2211f8829a4aSRandall Stewart 			to_ticks = MSEC_TO_TICKS(net->RTO);
2212f8829a4aSRandall Stewart 		}
2213f8829a4aSRandall Stewart 		tmr = &stcb->asoc.asconf_timer;
2214f8829a4aSRandall Stewart 		break;
2215851b7298SRandall Stewart 	case SCTP_TIMER_TYPE_PRIM_DELETED:
2216851b7298SRandall Stewart 		if ((stcb == NULL) || (net != NULL)) {
2217851b7298SRandall Stewart 			return;
2218851b7298SRandall Stewart 		}
2219851b7298SRandall Stewart 		to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
2220851b7298SRandall Stewart 		tmr = &stcb->asoc.delete_prim_timer;
2221851b7298SRandall Stewart 		break;
2222f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_AUTOCLOSE:
2223f8829a4aSRandall Stewart 		if (stcb == NULL) {
2224ad81507eSRandall Stewart 			return;
2225f8829a4aSRandall Stewart 		}
2226f8829a4aSRandall Stewart 		if (stcb->asoc.sctp_autoclose_ticks == 0) {
2227f8829a4aSRandall Stewart 			/*
2228f8829a4aSRandall Stewart 			 * Really an error since stcb is NOT set to
2229f8829a4aSRandall Stewart 			 * autoclose
2230f8829a4aSRandall Stewart 			 */
2231ad81507eSRandall Stewart 			return;
2232f8829a4aSRandall Stewart 		}
2233f8829a4aSRandall Stewart 		to_ticks = stcb->asoc.sctp_autoclose_ticks;
2234f8829a4aSRandall Stewart 		tmr = &stcb->asoc.autoclose_timer;
2235f8829a4aSRandall Stewart 		break;
2236f8829a4aSRandall Stewart 	default:
2237ad81507eSRandall Stewart 		SCTPDBG(SCTP_DEBUG_TIMER1, "%s: Unknown timer type %d\n",
22386e9c45e0SMichael Tuexen 		    __func__, t_type);
2239ad81507eSRandall Stewart 		return;
2240f8829a4aSRandall Stewart 		break;
224160990c0cSMichael Tuexen 	}
2242f8829a4aSRandall Stewart 	if ((to_ticks <= 0) || (tmr == NULL)) {
2243ad81507eSRandall Stewart 		SCTPDBG(SCTP_DEBUG_TIMER1, "%s: %d:software error to_ticks:%d tmr:%p not set ??\n",
22446e9c45e0SMichael Tuexen 		    __func__, t_type, to_ticks, (void *)tmr);
2245ad81507eSRandall Stewart 		return;
2246f8829a4aSRandall Stewart 	}
2247139bc87fSRandall Stewart 	if (SCTP_OS_TIMER_PENDING(&tmr->timer)) {
2248f8829a4aSRandall Stewart 		/*
2249f8829a4aSRandall Stewart 		 * we do NOT allow you to have it already running. if it is
2250f8829a4aSRandall Stewart 		 * we leave the current one up unchanged
2251f8829a4aSRandall Stewart 		 */
2252ad81507eSRandall Stewart 		return;
2253f8829a4aSRandall Stewart 	}
2254f8829a4aSRandall Stewart 	/* At this point we can proceed */
2255f8829a4aSRandall Stewart 	if (t_type == SCTP_TIMER_TYPE_SEND) {
2256f8829a4aSRandall Stewart 		stcb->asoc.num_send_timers_up++;
2257f8829a4aSRandall Stewart 	}
2258a5d547adSRandall Stewart 	tmr->stopped_from = 0;
2259f8829a4aSRandall Stewart 	tmr->type = t_type;
2260f8829a4aSRandall Stewart 	tmr->ep = (void *)inp;
2261f8829a4aSRandall Stewart 	tmr->tcb = (void *)stcb;
2262f8829a4aSRandall Stewart 	tmr->net = (void *)net;
2263f8829a4aSRandall Stewart 	tmr->self = (void *)tmr;
22648518270eSMichael Tuexen 	tmr->vnet = (void *)curvnet;
2265c4739e2fSRandall Stewart 	tmr->ticks = sctp_get_tick_count();
2266ad81507eSRandall Stewart 	(void)SCTP_OS_TIMER_START(&tmr->timer, to_ticks, sctp_timeout_handler, tmr);
2267ad81507eSRandall Stewart 	return;
2268f8829a4aSRandall Stewart }
2269f8829a4aSRandall Stewart 
22706e55db54SRandall Stewart void
2271f8829a4aSRandall Stewart sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
2272a5d547adSRandall Stewart     struct sctp_nets *net, uint32_t from)
2273f8829a4aSRandall Stewart {
2274f8829a4aSRandall Stewart 	struct sctp_timer *tmr;
2275f8829a4aSRandall Stewart 
2276f8829a4aSRandall Stewart 	if ((t_type != SCTP_TIMER_TYPE_ADDR_WQ) &&
2277f8829a4aSRandall Stewart 	    (inp == NULL))
22786e55db54SRandall Stewart 		return;
2279f8829a4aSRandall Stewart 
2280f8829a4aSRandall Stewart 	tmr = NULL;
2281f8829a4aSRandall Stewart 	if (stcb) {
2282f8829a4aSRandall Stewart 		SCTP_TCB_LOCK_ASSERT(stcb);
2283f8829a4aSRandall Stewart 	}
2284f8829a4aSRandall Stewart 	switch (t_type) {
2285f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_ADDR_WQ:
2286b3f1ea41SRandall Stewart 		tmr = &SCTP_BASE_INFO(addr_wq_timer);
2287f8829a4aSRandall Stewart 		break;
2288f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_SEND:
2289f8829a4aSRandall Stewart 		if ((stcb == NULL) || (net == NULL)) {
22906e55db54SRandall Stewart 			return;
2291f8829a4aSRandall Stewart 		}
2292f8829a4aSRandall Stewart 		tmr = &net->rxt_timer;
2293f8829a4aSRandall Stewart 		break;
2294f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_INIT:
2295f8829a4aSRandall Stewart 		if ((stcb == NULL) || (net == NULL)) {
22966e55db54SRandall Stewart 			return;
2297f8829a4aSRandall Stewart 		}
2298f8829a4aSRandall Stewart 		tmr = &net->rxt_timer;
2299f8829a4aSRandall Stewart 		break;
2300f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_RECV:
2301f8829a4aSRandall Stewart 		if (stcb == NULL) {
23026e55db54SRandall Stewart 			return;
2303f8829a4aSRandall Stewart 		}
2304f8829a4aSRandall Stewart 		tmr = &stcb->asoc.dack_timer;
2305f8829a4aSRandall Stewart 		break;
2306f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_SHUTDOWN:
2307f8829a4aSRandall Stewart 		if ((stcb == NULL) || (net == NULL)) {
23086e55db54SRandall Stewart 			return;
2309f8829a4aSRandall Stewart 		}
2310f8829a4aSRandall Stewart 		tmr = &net->rxt_timer;
2311f8829a4aSRandall Stewart 		break;
2312f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_HEARTBEAT:
2313ca85e948SMichael Tuexen 		if ((stcb == NULL) || (net == NULL)) {
23146e55db54SRandall Stewart 			return;
2315f8829a4aSRandall Stewart 		}
2316ca85e948SMichael Tuexen 		tmr = &net->hb_timer;
2317f8829a4aSRandall Stewart 		break;
2318f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_COOKIE:
2319f8829a4aSRandall Stewart 		if ((stcb == NULL) || (net == NULL)) {
23206e55db54SRandall Stewart 			return;
2321f8829a4aSRandall Stewart 		}
2322f8829a4aSRandall Stewart 		tmr = &net->rxt_timer;
2323f8829a4aSRandall Stewart 		break;
2324f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_NEWCOOKIE:
2325f8829a4aSRandall Stewart 		/* nothing needed but the endpoint here */
2326f8829a4aSRandall Stewart 		tmr = &inp->sctp_ep.signature_change;
2327f8829a4aSRandall Stewart 		/*
2328f8829a4aSRandall Stewart 		 * We re-use the newcookie timer for the INP kill timer. We
2329f8829a4aSRandall Stewart 		 * must assure that we do not kill it by accident.
2330f8829a4aSRandall Stewart 		 */
2331f8829a4aSRandall Stewart 		break;
2332f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_ASOCKILL:
2333f8829a4aSRandall Stewart 		/*
2334f8829a4aSRandall Stewart 		 * Stop the asoc kill timer.
2335f8829a4aSRandall Stewart 		 */
2336f8829a4aSRandall Stewart 		if (stcb == NULL) {
23376e55db54SRandall Stewart 			return;
2338f8829a4aSRandall Stewart 		}
2339f8829a4aSRandall Stewart 		tmr = &stcb->asoc.strreset_timer;
2340f8829a4aSRandall Stewart 		break;
2341f8829a4aSRandall Stewart 
2342f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_INPKILL:
2343f8829a4aSRandall Stewart 		/*
2344f8829a4aSRandall Stewart 		 * The inp is setup to die. We re-use the signature_chage
2345f8829a4aSRandall Stewart 		 * timer since that has stopped and we are in the GONE
2346f8829a4aSRandall Stewart 		 * state.
2347f8829a4aSRandall Stewart 		 */
2348f8829a4aSRandall Stewart 		tmr = &inp->sctp_ep.signature_change;
2349f8829a4aSRandall Stewart 		break;
2350f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_PATHMTURAISE:
2351f8829a4aSRandall Stewart 		if ((stcb == NULL) || (net == NULL)) {
23526e55db54SRandall Stewart 			return;
2353f8829a4aSRandall Stewart 		}
2354f8829a4aSRandall Stewart 		tmr = &net->pmtu_timer;
2355f8829a4aSRandall Stewart 		break;
2356f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_SHUTDOWNACK:
2357f8829a4aSRandall Stewart 		if ((stcb == NULL) || (net == NULL)) {
23586e55db54SRandall Stewart 			return;
2359f8829a4aSRandall Stewart 		}
2360f8829a4aSRandall Stewart 		tmr = &net->rxt_timer;
2361f8829a4aSRandall Stewart 		break;
2362f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_SHUTDOWNGUARD:
2363f8829a4aSRandall Stewart 		if (stcb == NULL) {
23646e55db54SRandall Stewart 			return;
2365f8829a4aSRandall Stewart 		}
2366f8829a4aSRandall Stewart 		tmr = &stcb->asoc.shut_guard_timer;
2367f8829a4aSRandall Stewart 		break;
2368f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_STRRESET:
2369f8829a4aSRandall Stewart 		if (stcb == NULL) {
23706e55db54SRandall Stewart 			return;
2371f8829a4aSRandall Stewart 		}
2372f8829a4aSRandall Stewart 		tmr = &stcb->asoc.strreset_timer;
2373f8829a4aSRandall Stewart 		break;
2374f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_ASCONF:
2375f8829a4aSRandall Stewart 		if (stcb == NULL) {
23766e55db54SRandall Stewart 			return;
2377f8829a4aSRandall Stewart 		}
2378f8829a4aSRandall Stewart 		tmr = &stcb->asoc.asconf_timer;
2379f8829a4aSRandall Stewart 		break;
2380851b7298SRandall Stewart 	case SCTP_TIMER_TYPE_PRIM_DELETED:
2381851b7298SRandall Stewart 		if (stcb == NULL) {
2382851b7298SRandall Stewart 			return;
2383851b7298SRandall Stewart 		}
2384851b7298SRandall Stewart 		tmr = &stcb->asoc.delete_prim_timer;
2385851b7298SRandall Stewart 		break;
2386f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_AUTOCLOSE:
2387f8829a4aSRandall Stewart 		if (stcb == NULL) {
23886e55db54SRandall Stewart 			return;
2389f8829a4aSRandall Stewart 		}
2390f8829a4aSRandall Stewart 		tmr = &stcb->asoc.autoclose_timer;
2391f8829a4aSRandall Stewart 		break;
2392f8829a4aSRandall Stewart 	default:
2393ad81507eSRandall Stewart 		SCTPDBG(SCTP_DEBUG_TIMER1, "%s: Unknown timer type %d\n",
23946e9c45e0SMichael Tuexen 		    __func__, t_type);
2395f8829a4aSRandall Stewart 		break;
239660990c0cSMichael Tuexen 	}
2397f8829a4aSRandall Stewart 	if (tmr == NULL) {
23986e55db54SRandall Stewart 		return;
2399f8829a4aSRandall Stewart 	}
2400f8829a4aSRandall Stewart 	if ((tmr->type != t_type) && tmr->type) {
2401f8829a4aSRandall Stewart 		/*
2402f8829a4aSRandall Stewart 		 * Ok we have a timer that is under joint use. Cookie timer
2403f8829a4aSRandall Stewart 		 * per chance with the SEND timer. We therefore are NOT
2404f8829a4aSRandall Stewart 		 * running the timer that the caller wants stopped.  So just
2405f8829a4aSRandall Stewart 		 * return.
2406f8829a4aSRandall Stewart 		 */
24076e55db54SRandall Stewart 		return;
2408f8829a4aSRandall Stewart 	}
2409ad81507eSRandall Stewart 	if ((t_type == SCTP_TIMER_TYPE_SEND) && (stcb != NULL)) {
2410f8829a4aSRandall Stewart 		stcb->asoc.num_send_timers_up--;
2411f8829a4aSRandall Stewart 		if (stcb->asoc.num_send_timers_up < 0) {
2412f8829a4aSRandall Stewart 			stcb->asoc.num_send_timers_up = 0;
2413f8829a4aSRandall Stewart 		}
2414f8829a4aSRandall Stewart 	}
2415f8829a4aSRandall Stewart 	tmr->self = NULL;
2416a5d547adSRandall Stewart 	tmr->stopped_from = from;
24176e55db54SRandall Stewart 	(void)SCTP_OS_TIMER_STOP(&tmr->timer);
24186e55db54SRandall Stewart 	return;
2419f8829a4aSRandall Stewart }
2420f8829a4aSRandall Stewart 
2421f8829a4aSRandall Stewart uint32_t
2422*b0471b4bSMichael Tuexen sctp_calculate_len(struct mbuf *m)
2423*b0471b4bSMichael Tuexen {
2424f8829a4aSRandall Stewart 	uint32_t tlen = 0;
2425f8829a4aSRandall Stewart 	struct mbuf *at;
2426f8829a4aSRandall Stewart 
2427f8829a4aSRandall Stewart 	at = m;
2428f8829a4aSRandall Stewart 	while (at) {
2429139bc87fSRandall Stewart 		tlen += SCTP_BUF_LEN(at);
2430139bc87fSRandall Stewart 		at = SCTP_BUF_NEXT(at);
2431f8829a4aSRandall Stewart 	}
2432f8829a4aSRandall Stewart 	return (tlen);
2433f8829a4aSRandall Stewart }
2434f8829a4aSRandall Stewart 
2435f8829a4aSRandall Stewart void
2436f8829a4aSRandall Stewart sctp_mtu_size_reset(struct sctp_inpcb *inp,
243744b7479bSRandall Stewart     struct sctp_association *asoc, uint32_t mtu)
2438f8829a4aSRandall Stewart {
2439f8829a4aSRandall Stewart 	/*
2440f8829a4aSRandall Stewart 	 * Reset the P-MTU size on this association, this involves changing
2441f8829a4aSRandall Stewart 	 * the asoc MTU, going through ANY chunk+overhead larger than mtu to
2442f8829a4aSRandall Stewart 	 * allow the DF flag to be cleared.
2443f8829a4aSRandall Stewart 	 */
2444f8829a4aSRandall Stewart 	struct sctp_tmit_chunk *chk;
2445f8829a4aSRandall Stewart 	unsigned int eff_mtu, ovh;
2446f8829a4aSRandall Stewart 
2447f8829a4aSRandall Stewart 	asoc->smallest_mtu = mtu;
2448f8829a4aSRandall Stewart 	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
2449f8829a4aSRandall Stewart 		ovh = SCTP_MIN_OVERHEAD;
2450f8829a4aSRandall Stewart 	} else {
2451f8829a4aSRandall Stewart 		ovh = SCTP_MIN_V4_OVERHEAD;
2452f8829a4aSRandall Stewart 	}
2453f8829a4aSRandall Stewart 	eff_mtu = mtu - ovh;
2454f8829a4aSRandall Stewart 	TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) {
2455f8829a4aSRandall Stewart 		if (chk->send_size > eff_mtu) {
2456f8829a4aSRandall Stewart 			chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
2457f8829a4aSRandall Stewart 		}
2458f8829a4aSRandall Stewart 	}
2459f8829a4aSRandall Stewart 	TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) {
2460f8829a4aSRandall Stewart 		if (chk->send_size > eff_mtu) {
2461f8829a4aSRandall Stewart 			chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
2462f8829a4aSRandall Stewart 		}
2463f8829a4aSRandall Stewart 	}
2464f8829a4aSRandall Stewart }
2465f8829a4aSRandall Stewart 
2466f8829a4aSRandall Stewart 
2467f8829a4aSRandall Stewart /*
2468f8829a4aSRandall Stewart  * given an association and starting time of the current RTT period return
2469f42a358aSRandall Stewart  * RTO in number of msecs net should point to the current network
2470f8829a4aSRandall Stewart  */
2471899288aeSRandall Stewart 
2472f8829a4aSRandall Stewart uint32_t
2473f8829a4aSRandall Stewart sctp_calculate_rto(struct sctp_tcb *stcb,
2474f8829a4aSRandall Stewart     struct sctp_association *asoc,
2475f8829a4aSRandall Stewart     struct sctp_nets *net,
24768c8e10b7SMichael Tuexen     struct timeval *old,
2477*b0471b4bSMichael Tuexen     int rtt_from_sack)
2478*b0471b4bSMichael Tuexen {
247918e198d3SRandall Stewart 	/*-
2480f8829a4aSRandall Stewart 	 * given an association and the starting time of the current RTT
2481f42a358aSRandall Stewart 	 * period (in value1/value2) return RTO in number of msecs.
2482f8829a4aSRandall Stewart 	 */
2483be1d9176SMichael Tuexen 	int32_t rtt;		/* RTT in ms */
2484be1d9176SMichael Tuexen 	uint32_t new_rto;
2485f8829a4aSRandall Stewart 	int first_measure = 0;
24868c8e10b7SMichael Tuexen 	struct timeval now;
2487f8829a4aSRandall Stewart 
2488f8829a4aSRandall Stewart 	/************************/
2489f8829a4aSRandall Stewart 	/* 1. calculate new RTT */
2490f8829a4aSRandall Stewart 	/************************/
2491f8829a4aSRandall Stewart 	/* get the current time */
2492299108c5SRandall Stewart 	if (stcb->asoc.use_precise_time) {
2493299108c5SRandall Stewart 		(void)SCTP_GETPTIME_TIMEVAL(&now);
2494299108c5SRandall Stewart 	} else {
24956e55db54SRandall Stewart 		(void)SCTP_GETTIME_TIMEVAL(&now);
2496299108c5SRandall Stewart 	}
2497be1d9176SMichael Tuexen 	timevalsub(&now, old);
2498be1d9176SMichael Tuexen 	/* store the current RTT in us */
249981eb4e63SMichael Tuexen 	net->rtt = (uint64_t)1000000 *(uint64_t)now.tv_sec +
2500be1d9176SMichael Tuexen 	        (uint64_t)now.tv_usec;
2501*b0471b4bSMichael Tuexen 
2502b60b0fe6SMichael Tuexen 	/* compute rtt in ms */
2503b60b0fe6SMichael Tuexen 	rtt = (int32_t)(net->rtt / 1000);
2504f79aab18SRandall Stewart 	if ((asoc->cc_functions.sctp_rtt_calculated) && (rtt_from_sack == SCTP_RTT_FROM_DATA)) {
2505b7b84c0eSMichael Tuexen 		/*
2506b7b84c0eSMichael Tuexen 		 * Tell the CC module that a new update has just occurred
2507b7b84c0eSMichael Tuexen 		 * from a sack
2508b7b84c0eSMichael Tuexen 		 */
2509f79aab18SRandall Stewart 		(*asoc->cc_functions.sctp_rtt_calculated) (stcb, net, &now);
2510f79aab18SRandall Stewart 	}
2511f79aab18SRandall Stewart 	/*
2512f79aab18SRandall Stewart 	 * Do we need to determine the lan? We do this only on sacks i.e.
2513f79aab18SRandall Stewart 	 * RTT being determined from data not non-data (HB/INIT->INITACK).
2514f79aab18SRandall Stewart 	 */
2515f79aab18SRandall Stewart 	if ((rtt_from_sack == SCTP_RTT_FROM_DATA) &&
2516be1d9176SMichael Tuexen 	    (net->lan_type == SCTP_LAN_UNKNOWN)) {
2517be1d9176SMichael Tuexen 		if (net->rtt > SCTP_LOCAL_LAN_RTT) {
2518899288aeSRandall Stewart 			net->lan_type = SCTP_LAN_INTERNET;
2519899288aeSRandall Stewart 		} else {
2520899288aeSRandall Stewart 			net->lan_type = SCTP_LAN_LOCAL;
2521899288aeSRandall Stewart 		}
2522899288aeSRandall Stewart 	}
2523f8829a4aSRandall Stewart 	/***************************/
2524f8829a4aSRandall Stewart 	/* 2. update RTTVAR & SRTT */
2525f8829a4aSRandall Stewart 	/***************************/
2526be1d9176SMichael Tuexen 	/*-
2527be1d9176SMichael Tuexen 	 * Compute the scaled average lastsa and the
2528be1d9176SMichael Tuexen 	 * scaled variance lastsv as described in van Jacobson
2529be1d9176SMichael Tuexen 	 * Paper "Congestion Avoidance and Control", Annex A.
2530be1d9176SMichael Tuexen 	 *
2531be1d9176SMichael Tuexen 	 * (net->lastsa >> SCTP_RTT_SHIFT) is the srtt
2532be1d9176SMichael Tuexen 	 * (net->lastsa >> SCTP_RTT_VAR_SHIFT) is the rttvar
2533be1d9176SMichael Tuexen 	 */
25349a972525SRandall Stewart 	if (net->RTO_measured) {
2535be1d9176SMichael Tuexen 		rtt -= (net->lastsa >> SCTP_RTT_SHIFT);
2536be1d9176SMichael Tuexen 		net->lastsa += rtt;
2537be1d9176SMichael Tuexen 		if (rtt < 0) {
2538be1d9176SMichael Tuexen 			rtt = -rtt;
2539be1d9176SMichael Tuexen 		}
2540be1d9176SMichael Tuexen 		rtt -= (net->lastsv >> SCTP_RTT_VAR_SHIFT);
2541be1d9176SMichael Tuexen 		net->lastsv += rtt;
2542b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RTTVAR_LOGGING_ENABLE) {
2543f8829a4aSRandall Stewart 			rto_logging(net, SCTP_LOG_RTTVAR);
254480fefe0aSRandall Stewart 		}
2545f8829a4aSRandall Stewart 	} else {
2546f8829a4aSRandall Stewart 		/* First RTO measurment */
25479a972525SRandall Stewart 		net->RTO_measured = 1;
2548f8829a4aSRandall Stewart 		first_measure = 1;
2549be1d9176SMichael Tuexen 		net->lastsa = rtt << SCTP_RTT_SHIFT;
2550be1d9176SMichael Tuexen 		net->lastsv = (rtt / 2) << SCTP_RTT_VAR_SHIFT;
2551b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RTTVAR_LOGGING_ENABLE) {
2552f8829a4aSRandall Stewart 			rto_logging(net, SCTP_LOG_INITIAL_RTT);
255380fefe0aSRandall Stewart 		}
2554f8829a4aSRandall Stewart 	}
2555be1d9176SMichael Tuexen 	if (net->lastsv == 0) {
2556be1d9176SMichael Tuexen 		net->lastsv = SCTP_CLOCK_GRANULARITY;
2557be1d9176SMichael Tuexen 	}
2558108df27cSRandall Stewart 	new_rto = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv;
2559f8829a4aSRandall Stewart 	if ((new_rto > SCTP_SAT_NETWORK_MIN) &&
2560f8829a4aSRandall Stewart 	    (stcb->asoc.sat_network_lockout == 0)) {
2561f8829a4aSRandall Stewart 		stcb->asoc.sat_network = 1;
2562f8829a4aSRandall Stewart 	} else if ((!first_measure) && stcb->asoc.sat_network) {
2563f8829a4aSRandall Stewart 		stcb->asoc.sat_network = 0;
2564f8829a4aSRandall Stewart 		stcb->asoc.sat_network_lockout = 1;
2565f8829a4aSRandall Stewart 	}
2566f8829a4aSRandall Stewart 	/* bound it, per C6/C7 in Section 5.3.1 */
2567f8829a4aSRandall Stewart 	if (new_rto < stcb->asoc.minrto) {
2568f8829a4aSRandall Stewart 		new_rto = stcb->asoc.minrto;
2569f8829a4aSRandall Stewart 	}
2570f8829a4aSRandall Stewart 	if (new_rto > stcb->asoc.maxrto) {
2571f8829a4aSRandall Stewart 		new_rto = stcb->asoc.maxrto;
2572f8829a4aSRandall Stewart 	}
25735e54f665SRandall Stewart 	/* we are now returning the RTO */
25745e54f665SRandall Stewart 	return (new_rto);
2575f8829a4aSRandall Stewart }
2576f8829a4aSRandall Stewart 
2577f8829a4aSRandall Stewart /*
2578f8829a4aSRandall Stewart  * return a pointer to a contiguous piece of data from the given mbuf chain
2579f8829a4aSRandall Stewart  * starting at 'off' for 'len' bytes.  If the desired piece spans more than
2580f8829a4aSRandall Stewart  * one mbuf, a copy is made at 'ptr'. caller must ensure that the buffer size
2581f8829a4aSRandall Stewart  * is >= 'len' returns NULL if there there isn't 'len' bytes in the chain.
2582f8829a4aSRandall Stewart  */
258372fb6fdbSRandall Stewart caddr_t
2584f8829a4aSRandall Stewart sctp_m_getptr(struct mbuf *m, int off, int len, uint8_t *in_ptr)
2585f8829a4aSRandall Stewart {
2586f8829a4aSRandall Stewart 	uint32_t count;
2587f8829a4aSRandall Stewart 	uint8_t *ptr;
2588f8829a4aSRandall Stewart 
2589f8829a4aSRandall Stewart 	ptr = in_ptr;
2590f8829a4aSRandall Stewart 	if ((off < 0) || (len <= 0))
2591f8829a4aSRandall Stewart 		return (NULL);
2592f8829a4aSRandall Stewart 
2593f8829a4aSRandall Stewart 	/* find the desired start location */
2594f8829a4aSRandall Stewart 	while ((m != NULL) && (off > 0)) {
2595139bc87fSRandall Stewart 		if (off < SCTP_BUF_LEN(m))
2596f8829a4aSRandall Stewart 			break;
2597139bc87fSRandall Stewart 		off -= SCTP_BUF_LEN(m);
2598139bc87fSRandall Stewart 		m = SCTP_BUF_NEXT(m);
2599f8829a4aSRandall Stewart 	}
2600f8829a4aSRandall Stewart 	if (m == NULL)
2601f8829a4aSRandall Stewart 		return (NULL);
2602f8829a4aSRandall Stewart 
2603f8829a4aSRandall Stewart 	/* is the current mbuf large enough (eg. contiguous)? */
2604139bc87fSRandall Stewart 	if ((SCTP_BUF_LEN(m) - off) >= len) {
2605f8829a4aSRandall Stewart 		return (mtod(m, caddr_t)+off);
2606f8829a4aSRandall Stewart 	} else {
2607f8829a4aSRandall Stewart 		/* else, it spans more than one mbuf, so save a temp copy... */
2608f8829a4aSRandall Stewart 		while ((m != NULL) && (len > 0)) {
2609139bc87fSRandall Stewart 			count = min(SCTP_BUF_LEN(m) - off, len);
26105ba7f91fSMichael Tuexen 			memcpy(ptr, mtod(m, caddr_t)+off, count);
2611f8829a4aSRandall Stewart 			len -= count;
2612f8829a4aSRandall Stewart 			ptr += count;
2613f8829a4aSRandall Stewart 			off = 0;
2614139bc87fSRandall Stewart 			m = SCTP_BUF_NEXT(m);
2615f8829a4aSRandall Stewart 		}
2616f8829a4aSRandall Stewart 		if ((m == NULL) && (len > 0))
2617f8829a4aSRandall Stewart 			return (NULL);
2618f8829a4aSRandall Stewart 		else
2619f8829a4aSRandall Stewart 			return ((caddr_t)in_ptr);
2620f8829a4aSRandall Stewart 	}
2621f8829a4aSRandall Stewart }
2622f8829a4aSRandall Stewart 
2623f8829a4aSRandall Stewart 
262444b7479bSRandall Stewart 
2625f8829a4aSRandall Stewart struct sctp_paramhdr *
2626f8829a4aSRandall Stewart sctp_get_next_param(struct mbuf *m,
2627f8829a4aSRandall Stewart     int offset,
2628f8829a4aSRandall Stewart     struct sctp_paramhdr *pull,
2629f8829a4aSRandall Stewart     int pull_limit)
2630f8829a4aSRandall Stewart {
2631f8829a4aSRandall Stewart 	/* This just provides a typed signature to Peter's Pull routine */
2632f8829a4aSRandall Stewart 	return ((struct sctp_paramhdr *)sctp_m_getptr(m, offset, pull_limit,
2633f8829a4aSRandall Stewart 	    (uint8_t *)pull));
2634f8829a4aSRandall Stewart }
2635f8829a4aSRandall Stewart 
2636f8829a4aSRandall Stewart 
2637ce11b842SMichael Tuexen struct mbuf *
2638f8829a4aSRandall Stewart sctp_add_pad_tombuf(struct mbuf *m, int padlen)
2639f8829a4aSRandall Stewart {
2640ce11b842SMichael Tuexen 	struct mbuf *m_last;
2641ce11b842SMichael Tuexen 	caddr_t dp;
2642f8829a4aSRandall Stewart 
2643f8829a4aSRandall Stewart 	if (padlen > 3) {
2644ce11b842SMichael Tuexen 		return (NULL);
2645f8829a4aSRandall Stewart 	}
264641eee555SRandall Stewart 	if (padlen <= M_TRAILINGSPACE(m)) {
2647f8829a4aSRandall Stewart 		/*
2648f8829a4aSRandall Stewart 		 * The easy way. We hope the majority of the time we hit
2649f8829a4aSRandall Stewart 		 * here :)
2650f8829a4aSRandall Stewart 		 */
2651ce11b842SMichael Tuexen 		m_last = m;
2652f8829a4aSRandall Stewart 	} else {
2653ce11b842SMichael Tuexen 		/* Hard way we must grow the mbuf chain */
2654ce11b842SMichael Tuexen 		m_last = sctp_get_mbuf_for_msg(padlen, 0, M_NOWAIT, 1, MT_DATA);
2655ce11b842SMichael Tuexen 		if (m_last == NULL) {
2656ce11b842SMichael Tuexen 			return (NULL);
2657f8829a4aSRandall Stewart 		}
2658ce11b842SMichael Tuexen 		SCTP_BUF_LEN(m_last) = 0;
2659ce11b842SMichael Tuexen 		SCTP_BUF_NEXT(m_last) = NULL;
2660ce11b842SMichael Tuexen 		SCTP_BUF_NEXT(m) = m_last;
2661f8829a4aSRandall Stewart 	}
2662ce11b842SMichael Tuexen 	dp = mtod(m_last, caddr_t)+SCTP_BUF_LEN(m_last);
2663ce11b842SMichael Tuexen 	SCTP_BUF_LEN(m_last) += padlen;
2664ce11b842SMichael Tuexen 	memset(dp, 0, padlen);
2665ce11b842SMichael Tuexen 	return (m_last);
2666f8829a4aSRandall Stewart }
2667f8829a4aSRandall Stewart 
2668ce11b842SMichael Tuexen struct mbuf *
2669f8829a4aSRandall Stewart sctp_pad_lastmbuf(struct mbuf *m, int padval, struct mbuf *last_mbuf)
2670f8829a4aSRandall Stewart {
2671f8829a4aSRandall Stewart 	/* find the last mbuf in chain and pad it */
2672f8829a4aSRandall Stewart 	struct mbuf *m_at;
2673f8829a4aSRandall Stewart 
2674ce11b842SMichael Tuexen 	if (last_mbuf != NULL) {
2675f8829a4aSRandall Stewart 		return (sctp_add_pad_tombuf(last_mbuf, padval));
2676f8829a4aSRandall Stewart 	} else {
267717267b32SMichael Tuexen 		for (m_at = m; m_at; m_at = SCTP_BUF_NEXT(m_at)) {
2678139bc87fSRandall Stewart 			if (SCTP_BUF_NEXT(m_at) == NULL) {
2679f8829a4aSRandall Stewart 				return (sctp_add_pad_tombuf(m_at, padval));
2680f8829a4aSRandall Stewart 			}
2681f8829a4aSRandall Stewart 		}
2682f8829a4aSRandall Stewart 	}
2683ce11b842SMichael Tuexen 	return (NULL);
2684f8829a4aSRandall Stewart }
2685f8829a4aSRandall Stewart 
2686f8829a4aSRandall Stewart static void
2687c5b5675dSMichael Tuexen sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb,
2688410a3b1eSMichael Tuexen     uint16_t error, struct sctp_abort_chunk *abort, uint8_t from_peer, int so_locked
2689ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
2690ceaad40aSRandall Stewart     SCTP_UNUSED
2691ceaad40aSRandall Stewart #endif
2692ceaad40aSRandall Stewart )
2693f8829a4aSRandall Stewart {
2694f8829a4aSRandall Stewart 	struct mbuf *m_notify;
2695f8829a4aSRandall Stewart 	struct sctp_assoc_change *sac;
2696f8829a4aSRandall Stewart 	struct sctp_queued_to_read *control;
26979a8e3088SMichael Tuexen 	unsigned int notif_len;
26989a8e3088SMichael Tuexen 	uint16_t abort_len;
2699e06b67c7SMichael Tuexen 	unsigned int i;
2700ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
2701ceaad40aSRandall Stewart 	struct socket *so;
2702ceaad40aSRandall Stewart #endif
2703ceaad40aSRandall Stewart 
270459713bbfSMichael Tuexen 	if (stcb == NULL) {
270559713bbfSMichael Tuexen 		return;
270659713bbfSMichael Tuexen 	}
270758411b08SMichael Tuexen 	if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT)) {
27089a8e3088SMichael Tuexen 		notif_len = (unsigned int)sizeof(struct sctp_assoc_change);
2709a2b42326SMichael Tuexen 		if (abort != NULL) {
2710c9eb4473SMichael Tuexen 			abort_len = ntohs(abort->ch.chunk_length);
27119669e724SMichael Tuexen 			/*
27129669e724SMichael Tuexen 			 * Only SCTP_CHUNK_BUFFER_SIZE are guaranteed to be
271345d41de5SMichael Tuexen 			 * contiguous.
27149669e724SMichael Tuexen 			 */
27159669e724SMichael Tuexen 			if (abort_len > SCTP_CHUNK_BUFFER_SIZE) {
27169669e724SMichael Tuexen 				abort_len = SCTP_CHUNK_BUFFER_SIZE;
27179669e724SMichael Tuexen 			}
2718a2b42326SMichael Tuexen 		} else {
2719a2b42326SMichael Tuexen 			abort_len = 0;
2720c5b5675dSMichael Tuexen 		}
2721a2b42326SMichael Tuexen 		if ((state == SCTP_COMM_UP) || (state == SCTP_RESTART)) {
2722a2b42326SMichael Tuexen 			notif_len += SCTP_ASSOC_SUPPORTS_MAX;
2723a2b42326SMichael Tuexen 		} else if ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC)) {
2724a2b42326SMichael Tuexen 			notif_len += abort_len;
2725a2b42326SMichael Tuexen 		}
2726eb1b1807SGleb Smirnoff 		m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA);
2727a2b42326SMichael Tuexen 		if (m_notify == NULL) {
2728a2b42326SMichael Tuexen 			/* Retry with smaller value. */
27299a8e3088SMichael Tuexen 			notif_len = (unsigned int)sizeof(struct sctp_assoc_change);
2730eb1b1807SGleb Smirnoff 			m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA);
2731a2b42326SMichael Tuexen 			if (m_notify == NULL) {
273258411b08SMichael Tuexen 				goto set_error;
2733a2b42326SMichael Tuexen 			}
2734a2b42326SMichael Tuexen 		}
2735a2b42326SMichael Tuexen 		SCTP_BUF_NEXT(m_notify) = NULL;
2736f8829a4aSRandall Stewart 		sac = mtod(m_notify, struct sctp_assoc_change *);
2737e432298aSXin LI 		memset(sac, 0, notif_len);
2738f8829a4aSRandall Stewart 		sac->sac_type = SCTP_ASSOC_CHANGE;
2739f8829a4aSRandall Stewart 		sac->sac_flags = 0;
2740f8829a4aSRandall Stewart 		sac->sac_length = sizeof(struct sctp_assoc_change);
2741c5b5675dSMichael Tuexen 		sac->sac_state = state;
2742f8829a4aSRandall Stewart 		sac->sac_error = error;
2743f8829a4aSRandall Stewart 		/* XXX verify these stream counts */
2744f8829a4aSRandall Stewart 		sac->sac_outbound_streams = stcb->asoc.streamoutcnt;
2745f8829a4aSRandall Stewart 		sac->sac_inbound_streams = stcb->asoc.streamincnt;
2746f8829a4aSRandall Stewart 		sac->sac_assoc_id = sctp_get_associd(stcb);
2747a2b42326SMichael Tuexen 		if (notif_len > sizeof(struct sctp_assoc_change)) {
2748c5b5675dSMichael Tuexen 			if ((state == SCTP_COMM_UP) || (state == SCTP_RESTART)) {
2749e06b67c7SMichael Tuexen 				i = 0;
2750c79bec9cSMichael Tuexen 				if (stcb->asoc.prsctp_supported == 1) {
2751e06b67c7SMichael Tuexen 					sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_PR;
2752e06b67c7SMichael Tuexen 				}
2753c79bec9cSMichael Tuexen 				if (stcb->asoc.auth_supported == 1) {
2754e06b67c7SMichael Tuexen 					sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_AUTH;
2755e06b67c7SMichael Tuexen 				}
2756c79bec9cSMichael Tuexen 				if (stcb->asoc.asconf_supported == 1) {
2757e06b67c7SMichael Tuexen 					sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_ASCONF;
2758e06b67c7SMichael Tuexen 				}
275944249214SRandall Stewart 				if (stcb->asoc.idata_supported == 1) {
276044249214SRandall Stewart 					sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_INTERLEAVING;
276144249214SRandall Stewart 				}
2762e06b67c7SMichael Tuexen 				sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_MULTIBUF;
2763c79bec9cSMichael Tuexen 				if (stcb->asoc.reconfig_supported == 1) {
2764e06b67c7SMichael Tuexen 					sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_RE_CONFIG;
2765e06b67c7SMichael Tuexen 				}
2766e06b67c7SMichael Tuexen 				sac->sac_length += i;
2767a2b42326SMichael Tuexen 			} else if ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC)) {
2768a2b42326SMichael Tuexen 				memcpy(sac->sac_info, abort, abort_len);
2769a2b42326SMichael Tuexen 				sac->sac_length += abort_len;
2770a2b42326SMichael Tuexen 			}
2771c5b5675dSMichael Tuexen 		}
2772e06b67c7SMichael Tuexen 		SCTP_BUF_LEN(m_notify) = sac->sac_length;
2773f8829a4aSRandall Stewart 		control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
27747215cc1bSMichael Tuexen 		    0, 0, stcb->asoc.context, 0, 0, 0,
2775f8829a4aSRandall Stewart 		    m_notify);
277658411b08SMichael Tuexen 		if (control != NULL) {
2777139bc87fSRandall Stewart 			control->length = SCTP_BUF_LEN(m_notify);
277828cd0699SMichael Tuexen 			control->spec_flags = M_NOTIFICATION;
2779f8829a4aSRandall Stewart 			/* not that we need this */
2780f8829a4aSRandall Stewart 			control->tail_mbuf = m_notify;
2781f8829a4aSRandall Stewart 			sctp_add_to_readq(stcb->sctp_ep, stcb,
2782f8829a4aSRandall Stewart 			    control,
2783cfde3ff7SRandall Stewart 			    &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD,
2784cfde3ff7SRandall Stewart 			    so_locked);
278558411b08SMichael Tuexen 		} else {
278658411b08SMichael Tuexen 			sctp_m_freem(m_notify);
278758411b08SMichael Tuexen 		}
278858411b08SMichael Tuexen 	}
278958411b08SMichael Tuexen 	/*
279058411b08SMichael Tuexen 	 * For 1-to-1 style sockets, we send up and error when an ABORT
279158411b08SMichael Tuexen 	 * comes in.
279258411b08SMichael Tuexen 	 */
279358411b08SMichael Tuexen set_error:
279458411b08SMichael Tuexen 	if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
279558411b08SMichael Tuexen 	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) &&
279658411b08SMichael Tuexen 	    ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC))) {
2797e045904fSMichael Tuexen 		SOCK_LOCK(stcb->sctp_socket);
2798410a3b1eSMichael Tuexen 		if (from_peer) {
279958411b08SMichael Tuexen 			if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_WAIT) {
280058411b08SMichael Tuexen 				SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNREFUSED);
280158411b08SMichael Tuexen 				stcb->sctp_socket->so_error = ECONNREFUSED;
280258411b08SMichael Tuexen 			} else {
280358411b08SMichael Tuexen 				SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET);
280458411b08SMichael Tuexen 				stcb->sctp_socket->so_error = ECONNRESET;
280558411b08SMichael Tuexen 			}
2806410a3b1eSMichael Tuexen 		} else {
2807553bb068SMichael Tuexen 			if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_WAIT) ||
2808553bb068SMichael Tuexen 			    (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED)) {
2809553bb068SMichael Tuexen 				SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ETIMEDOUT);
2810553bb068SMichael Tuexen 				stcb->sctp_socket->so_error = ETIMEDOUT;
2811553bb068SMichael Tuexen 			} else {
2812410a3b1eSMichael Tuexen 				SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNABORTED);
2813410a3b1eSMichael Tuexen 				stcb->sctp_socket->so_error = ECONNABORTED;
2814410a3b1eSMichael Tuexen 			}
281558411b08SMichael Tuexen 		}
28163acfe1e1SGleb Smirnoff 		SOCK_UNLOCK(stcb->sctp_socket);
2817553bb068SMichael Tuexen 	}
281858411b08SMichael Tuexen 	/* Wake ANY sleepers */
2819ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
2820ceaad40aSRandall Stewart 	so = SCTP_INP_SO(stcb->sctp_ep);
2821ceaad40aSRandall Stewart 	if (!so_locked) {
2822ceaad40aSRandall Stewart 		atomic_add_int(&stcb->asoc.refcnt, 1);
2823ceaad40aSRandall Stewart 		SCTP_TCB_UNLOCK(stcb);
2824ceaad40aSRandall Stewart 		SCTP_SOCKET_LOCK(so, 1);
2825ceaad40aSRandall Stewart 		SCTP_TCB_LOCK(stcb);
2826ceaad40aSRandall Stewart 		atomic_subtract_int(&stcb->asoc.refcnt, 1);
2827ceaad40aSRandall Stewart 		if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
2828ceaad40aSRandall Stewart 			SCTP_SOCKET_UNLOCK(so, 1);
2829ceaad40aSRandall Stewart 			return;
2830ceaad40aSRandall Stewart 		}
2831ceaad40aSRandall Stewart 	}
2832ceaad40aSRandall Stewart #endif
283358411b08SMichael Tuexen 	if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
283458411b08SMichael Tuexen 	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) &&
283558411b08SMichael Tuexen 	    ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC))) {
28363acfe1e1SGleb Smirnoff 		socantrcvmore(stcb->sctp_socket);
283758411b08SMichael Tuexen 	}
283858411b08SMichael Tuexen 	sorwakeup(stcb->sctp_socket);
283958411b08SMichael Tuexen 	sowwakeup(stcb->sctp_socket);
2840ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
2841ceaad40aSRandall Stewart 	if (!so_locked) {
2842ceaad40aSRandall Stewart 		SCTP_SOCKET_UNLOCK(so, 1);
2843ceaad40aSRandall Stewart 	}
2844ceaad40aSRandall Stewart #endif
2845f8829a4aSRandall Stewart }
2846f8829a4aSRandall Stewart 
2847f8829a4aSRandall Stewart static void
2848f8829a4aSRandall Stewart sctp_notify_peer_addr_change(struct sctp_tcb *stcb, uint32_t state,
28493cb3567dSMichael Tuexen     struct sockaddr *sa, uint32_t error, int so_locked
28503cb3567dSMichael Tuexen #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
28513cb3567dSMichael Tuexen     SCTP_UNUSED
28523cb3567dSMichael Tuexen #endif
28533cb3567dSMichael Tuexen )
2854f8829a4aSRandall Stewart {
2855f8829a4aSRandall Stewart 	struct mbuf *m_notify;
2856f8829a4aSRandall Stewart 	struct sctp_paddr_change *spc;
2857f8829a4aSRandall Stewart 	struct sctp_queued_to_read *control;
2858f8829a4aSRandall Stewart 
285960990c0cSMichael Tuexen 	if ((stcb == NULL) ||
286060990c0cSMichael Tuexen 	    sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT)) {
2861f8829a4aSRandall Stewart 		/* event not enabled */
2862f8829a4aSRandall Stewart 		return;
2863830d754dSRandall Stewart 	}
2864eb1b1807SGleb Smirnoff 	m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_paddr_change), 0, M_NOWAIT, 1, MT_DATA);
2865f8829a4aSRandall Stewart 	if (m_notify == NULL)
2866f8829a4aSRandall Stewart 		return;
2867139bc87fSRandall Stewart 	SCTP_BUF_LEN(m_notify) = 0;
2868f8829a4aSRandall Stewart 	spc = mtod(m_notify, struct sctp_paddr_change *);
286956711f94SMichael Tuexen 	memset(spc, 0, sizeof(struct sctp_paddr_change));
2870f8829a4aSRandall Stewart 	spc->spc_type = SCTP_PEER_ADDR_CHANGE;
2871f8829a4aSRandall Stewart 	spc->spc_flags = 0;
2872f8829a4aSRandall Stewart 	spc->spc_length = sizeof(struct sctp_paddr_change);
28735e2c2d87SRandall Stewart 	switch (sa->sa_family) {
2874ea5eba11SMichael Tuexen #ifdef INET
28755e2c2d87SRandall Stewart 	case AF_INET:
2876d59107f7SMichael Tuexen #ifdef INET6
2877d59107f7SMichael Tuexen 		if (sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
2878d59107f7SMichael Tuexen 			in6_sin_2_v4mapsin6((struct sockaddr_in *)sa,
2879d59107f7SMichael Tuexen 			    (struct sockaddr_in6 *)&spc->spc_aaddr);
2880d59107f7SMichael Tuexen 		} else {
2881f8829a4aSRandall Stewart 			memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in));
2882d59107f7SMichael Tuexen 		}
2883d59107f7SMichael Tuexen #else
2884d59107f7SMichael Tuexen 		memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in));
2885d59107f7SMichael Tuexen #endif
28865e2c2d87SRandall Stewart 		break;
2887ea5eba11SMichael Tuexen #endif
28885e2c2d87SRandall Stewart #ifdef INET6
28895e2c2d87SRandall Stewart 	case AF_INET6:
28905e2c2d87SRandall Stewart 		{
2891f42a358aSRandall Stewart 			struct sockaddr_in6 *sin6;
2892f42a358aSRandall Stewart 
2893f8829a4aSRandall Stewart 			memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in6));
2894f42a358aSRandall Stewart 
2895f42a358aSRandall Stewart 			sin6 = (struct sockaddr_in6 *)&spc->spc_aaddr;
2896f42a358aSRandall Stewart 			if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) {
289742551e99SRandall Stewart 				if (sin6->sin6_scope_id == 0) {
289842551e99SRandall Stewart 					/* recover scope_id for user */
2899f42a358aSRandall Stewart 					(void)sa6_recoverscope(sin6);
290042551e99SRandall Stewart 				} else {
290142551e99SRandall Stewart 					/* clear embedded scope_id for user */
290242551e99SRandall Stewart 					in6_clearscope(&sin6->sin6_addr);
290342551e99SRandall Stewart 				}
2904f42a358aSRandall Stewart 			}
29055e2c2d87SRandall Stewart 			break;
29065e2c2d87SRandall Stewart 		}
29075e2c2d87SRandall Stewart #endif
29085e2c2d87SRandall Stewart 	default:
29095e2c2d87SRandall Stewart 		/* TSNH */
29105e2c2d87SRandall Stewart 		break;
2911f8829a4aSRandall Stewart 	}
2912f8829a4aSRandall Stewart 	spc->spc_state = state;
2913f8829a4aSRandall Stewart 	spc->spc_error = error;
2914f8829a4aSRandall Stewart 	spc->spc_assoc_id = sctp_get_associd(stcb);
2915f8829a4aSRandall Stewart 
2916139bc87fSRandall Stewart 	SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_paddr_change);
2917139bc87fSRandall Stewart 	SCTP_BUF_NEXT(m_notify) = NULL;
2918f8829a4aSRandall Stewart 
2919f8829a4aSRandall Stewart 	/* append to socket */
2920f8829a4aSRandall Stewart 	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
29217215cc1bSMichael Tuexen 	    0, 0, stcb->asoc.context, 0, 0, 0,
2922f8829a4aSRandall Stewart 	    m_notify);
2923f8829a4aSRandall Stewart 	if (control == NULL) {
2924f8829a4aSRandall Stewart 		/* no memory */
2925f8829a4aSRandall Stewart 		sctp_m_freem(m_notify);
2926f8829a4aSRandall Stewart 		return;
2927f8829a4aSRandall Stewart 	}
2928139bc87fSRandall Stewart 	control->length = SCTP_BUF_LEN(m_notify);
2929139bc87fSRandall Stewart 	control->spec_flags = M_NOTIFICATION;
2930f8829a4aSRandall Stewart 	/* not that we need this */
2931f8829a4aSRandall Stewart 	control->tail_mbuf = m_notify;
2932f8829a4aSRandall Stewart 	sctp_add_to_readq(stcb->sctp_ep, stcb,
2933f8829a4aSRandall Stewart 	    control,
2934cfde3ff7SRandall Stewart 	    &stcb->sctp_socket->so_rcv, 1,
2935cfde3ff7SRandall Stewart 	    SCTP_READ_LOCK_NOT_HELD,
29363cb3567dSMichael Tuexen 	    so_locked);
2937f8829a4aSRandall Stewart }
2938f8829a4aSRandall Stewart 
2939f8829a4aSRandall Stewart 
2940f8829a4aSRandall Stewart static void
29411edc9dbaSMichael Tuexen sctp_notify_send_failed(struct sctp_tcb *stcb, uint8_t sent, uint32_t error,
2942ceaad40aSRandall Stewart     struct sctp_tmit_chunk *chk, int so_locked
2943ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
2944ceaad40aSRandall Stewart     SCTP_UNUSED
2945ceaad40aSRandall Stewart #endif
2946ceaad40aSRandall Stewart )
2947f8829a4aSRandall Stewart {
2948830d754dSRandall Stewart 	struct mbuf *m_notify;
2949f8829a4aSRandall Stewart 	struct sctp_send_failed *ssf;
29509935403aSMichael Tuexen 	struct sctp_send_failed_event *ssfe;
2951f8829a4aSRandall Stewart 	struct sctp_queued_to_read *control;
2952ab337314SMichael Tuexen 	struct sctp_chunkhdr *chkhdr;
2953ab337314SMichael Tuexen 	int notifhdr_len, chk_len, chkhdr_len, padding_len, payload_len;
2954f8829a4aSRandall Stewart 
295560990c0cSMichael Tuexen 	if ((stcb == NULL) ||
29569935403aSMichael Tuexen 	    (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT) &&
29579935403aSMichael Tuexen 	    sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT))) {
2958f8829a4aSRandall Stewart 		/* event not enabled */
2959f8829a4aSRandall Stewart 		return;
2960830d754dSRandall Stewart 	}
29619935403aSMichael Tuexen 	if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) {
2962ab337314SMichael Tuexen 		notifhdr_len = sizeof(struct sctp_send_failed_event);
29639935403aSMichael Tuexen 	} else {
2964ab337314SMichael Tuexen 		notifhdr_len = sizeof(struct sctp_send_failed);
29659935403aSMichael Tuexen 	}
2966ab337314SMichael Tuexen 	m_notify = sctp_get_mbuf_for_msg(notifhdr_len, 0, M_NOWAIT, 1, MT_DATA);
2967f8829a4aSRandall Stewart 	if (m_notify == NULL)
2968f8829a4aSRandall Stewart 		/* no space left */
2969f8829a4aSRandall Stewart 		return;
2970ab337314SMichael Tuexen 	SCTP_BUF_LEN(m_notify) = notifhdr_len;
2971ab337314SMichael Tuexen 	if (stcb->asoc.idata_supported) {
2972ab337314SMichael Tuexen 		chkhdr_len = sizeof(struct sctp_idata_chunk);
2973ab337314SMichael Tuexen 	} else {
2974ab337314SMichael Tuexen 		chkhdr_len = sizeof(struct sctp_data_chunk);
2975ab337314SMichael Tuexen 	}
2976ab337314SMichael Tuexen 	/* Use some defaults in case we can't access the chunk header */
2977ab337314SMichael Tuexen 	if (chk->send_size >= chkhdr_len) {
2978ab337314SMichael Tuexen 		payload_len = chk->send_size - chkhdr_len;
2979ab337314SMichael Tuexen 	} else {
2980ab337314SMichael Tuexen 		payload_len = 0;
2981ab337314SMichael Tuexen 	}
2982ab337314SMichael Tuexen 	padding_len = 0;
2983ab337314SMichael Tuexen 	if (chk->data != NULL) {
2984ab337314SMichael Tuexen 		chkhdr = mtod(chk->data, struct sctp_chunkhdr *);
2985ab337314SMichael Tuexen 		if (chkhdr != NULL) {
2986ab337314SMichael Tuexen 			chk_len = ntohs(chkhdr->chunk_length);
2987ab337314SMichael Tuexen 			if ((chk_len >= chkhdr_len) &&
2988ab337314SMichael Tuexen 			    (chk->send_size >= chk_len) &&
2989ab337314SMichael Tuexen 			    (chk->send_size - chk_len < 4)) {
2990ab337314SMichael Tuexen 				padding_len = chk->send_size - chk_len;
2991ab337314SMichael Tuexen 				payload_len = chk->send_size - chkhdr_len - padding_len;
2992ab337314SMichael Tuexen 			}
2993ab337314SMichael Tuexen 		}
2994ab337314SMichael Tuexen 	}
29959935403aSMichael Tuexen 	if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) {
29969935403aSMichael Tuexen 		ssfe = mtod(m_notify, struct sctp_send_failed_event *);
2997ab337314SMichael Tuexen 		memset(ssfe, 0, notifhdr_len);
29989935403aSMichael Tuexen 		ssfe->ssfe_type = SCTP_SEND_FAILED_EVENT;
29991edc9dbaSMichael Tuexen 		if (sent) {
30009935403aSMichael Tuexen 			ssfe->ssfe_flags = SCTP_DATA_SENT;
30011edc9dbaSMichael Tuexen 		} else {
30021edc9dbaSMichael Tuexen 			ssfe->ssfe_flags = SCTP_DATA_UNSENT;
30031edc9dbaSMichael Tuexen 		}
3004ab337314SMichael Tuexen 		ssfe->ssfe_length = (uint32_t)(notifhdr_len + payload_len);
30059935403aSMichael Tuexen 		ssfe->ssfe_error = error;
30069935403aSMichael Tuexen 		/* not exactly what the user sent in, but should be close :) */
300749656eefSMichael Tuexen 		ssfe->ssfe_info.snd_sid = chk->rec.data.sid;
30089935403aSMichael Tuexen 		ssfe->ssfe_info.snd_flags = chk->rec.data.rcv_flags;
300949656eefSMichael Tuexen 		ssfe->ssfe_info.snd_ppid = chk->rec.data.ppid;
30109935403aSMichael Tuexen 		ssfe->ssfe_info.snd_context = chk->rec.data.context;
30119935403aSMichael Tuexen 		ssfe->ssfe_info.snd_assoc_id = sctp_get_associd(stcb);
30129935403aSMichael Tuexen 		ssfe->ssfe_assoc_id = sctp_get_associd(stcb);
30139935403aSMichael Tuexen 	} else {
3014f8829a4aSRandall Stewart 		ssf = mtod(m_notify, struct sctp_send_failed *);
3015ab337314SMichael Tuexen 		memset(ssf, 0, notifhdr_len);
3016f8829a4aSRandall Stewart 		ssf->ssf_type = SCTP_SEND_FAILED;
30171edc9dbaSMichael Tuexen 		if (sent) {
3018f8829a4aSRandall Stewart 			ssf->ssf_flags = SCTP_DATA_SENT;
30191edc9dbaSMichael Tuexen 		} else {
30201edc9dbaSMichael Tuexen 			ssf->ssf_flags = SCTP_DATA_UNSENT;
30211edc9dbaSMichael Tuexen 		}
3022ab337314SMichael Tuexen 		ssf->ssf_length = (uint32_t)(notifhdr_len + payload_len);
3023f8829a4aSRandall Stewart 		ssf->ssf_error = error;
3024f8829a4aSRandall Stewart 		/* not exactly what the user sent in, but should be close :) */
302549656eefSMichael Tuexen 		ssf->ssf_info.sinfo_stream = chk->rec.data.sid;
302649656eefSMichael Tuexen 		ssf->ssf_info.sinfo_ssn = (uint16_t)chk->rec.data.mid;
3027f8829a4aSRandall Stewart 		ssf->ssf_info.sinfo_flags = chk->rec.data.rcv_flags;
302849656eefSMichael Tuexen 		ssf->ssf_info.sinfo_ppid = chk->rec.data.ppid;
3029f8829a4aSRandall Stewart 		ssf->ssf_info.sinfo_context = chk->rec.data.context;
3030f8829a4aSRandall Stewart 		ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb);
3031f8829a4aSRandall Stewart 		ssf->ssf_assoc_id = sctp_get_associd(stcb);
30329935403aSMichael Tuexen 	}
3033ab337314SMichael Tuexen 	if (chk->data != NULL) {
3034ab337314SMichael Tuexen 		/* Trim off the sctp chunk header (it should be there) */
3035ab337314SMichael Tuexen 		if (chk->send_size == chkhdr_len + payload_len + padding_len) {
3036ab337314SMichael Tuexen 			m_adj(chk->data, chkhdr_len);
3037ab337314SMichael Tuexen 			m_adj(chk->data, -padding_len);
3038830d754dSRandall Stewart 			sctp_mbuf_crush(chk->data);
3039ab337314SMichael Tuexen 			chk->send_size -= (chkhdr_len + padding_len);
3040830d754dSRandall Stewart 		}
3041830d754dSRandall Stewart 	}
3042810ec536SMichael Tuexen 	SCTP_BUF_NEXT(m_notify) = chk->data;
3043f8829a4aSRandall Stewart 	/* Steal off the mbuf */
3044f8829a4aSRandall Stewart 	chk->data = NULL;
3045f8829a4aSRandall Stewart 	/*
3046f8829a4aSRandall Stewart 	 * For this case, we check the actual socket buffer, since the assoc
3047f8829a4aSRandall Stewart 	 * is going away we don't want to overfill the socket buffer for a
3048f8829a4aSRandall Stewart 	 * non-reader
3049f8829a4aSRandall Stewart 	 */
3050139bc87fSRandall Stewart 	if (sctp_sbspace_failedmsgs(&stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) {
3051f8829a4aSRandall Stewart 		sctp_m_freem(m_notify);
3052f8829a4aSRandall Stewart 		return;
3053f8829a4aSRandall Stewart 	}
3054f8829a4aSRandall Stewart 	/* append to socket */
3055f8829a4aSRandall Stewart 	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
30567215cc1bSMichael Tuexen 	    0, 0, stcb->asoc.context, 0, 0, 0,
3057f8829a4aSRandall Stewart 	    m_notify);
3058f8829a4aSRandall Stewart 	if (control == NULL) {
3059f8829a4aSRandall Stewart 		/* no memory */
3060f8829a4aSRandall Stewart 		sctp_m_freem(m_notify);
3061f8829a4aSRandall Stewart 		return;
3062f8829a4aSRandall Stewart 	}
306328cd0699SMichael Tuexen 	control->length = SCTP_BUF_LEN(m_notify);
3064139bc87fSRandall Stewart 	control->spec_flags = M_NOTIFICATION;
306528cd0699SMichael Tuexen 	/* not that we need this */
306628cd0699SMichael Tuexen 	control->tail_mbuf = m_notify;
3067f8829a4aSRandall Stewart 	sctp_add_to_readq(stcb->sctp_ep, stcb,
3068f8829a4aSRandall Stewart 	    control,
3069cfde3ff7SRandall Stewart 	    &stcb->sctp_socket->so_rcv, 1,
3070cfde3ff7SRandall Stewart 	    SCTP_READ_LOCK_NOT_HELD,
3071cfde3ff7SRandall Stewart 	    so_locked);
3072f8829a4aSRandall Stewart }
3073f8829a4aSRandall Stewart 
3074f8829a4aSRandall Stewart 
3075f8829a4aSRandall Stewart static void
3076f8829a4aSRandall Stewart sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error,
3077ceaad40aSRandall Stewart     struct sctp_stream_queue_pending *sp, int so_locked
3078ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
3079ceaad40aSRandall Stewart     SCTP_UNUSED
3080ceaad40aSRandall Stewart #endif
3081ceaad40aSRandall Stewart )
3082f8829a4aSRandall Stewart {
3083f8829a4aSRandall Stewart 	struct mbuf *m_notify;
3084f8829a4aSRandall Stewart 	struct sctp_send_failed *ssf;
30859935403aSMichael Tuexen 	struct sctp_send_failed_event *ssfe;
3086f8829a4aSRandall Stewart 	struct sctp_queued_to_read *control;
3087ab337314SMichael Tuexen 	int notifhdr_len;
3088f8829a4aSRandall Stewart 
308960990c0cSMichael Tuexen 	if ((stcb == NULL) ||
30909935403aSMichael Tuexen 	    (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT) &&
30919935403aSMichael Tuexen 	    sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT))) {
3092f8829a4aSRandall Stewart 		/* event not enabled */
3093f8829a4aSRandall Stewart 		return;
3094830d754dSRandall Stewart 	}
30959935403aSMichael Tuexen 	if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) {
3096ab337314SMichael Tuexen 		notifhdr_len = sizeof(struct sctp_send_failed_event);
30979935403aSMichael Tuexen 	} else {
3098ab337314SMichael Tuexen 		notifhdr_len = sizeof(struct sctp_send_failed);
30999935403aSMichael Tuexen 	}
3100ab337314SMichael Tuexen 	m_notify = sctp_get_mbuf_for_msg(notifhdr_len, 0, M_NOWAIT, 1, MT_DATA);
31019935403aSMichael Tuexen 	if (m_notify == NULL) {
3102f8829a4aSRandall Stewart 		/* no space left */
3103f8829a4aSRandall Stewart 		return;
31049935403aSMichael Tuexen 	}
3105ab337314SMichael Tuexen 	SCTP_BUF_LEN(m_notify) = notifhdr_len;
31069935403aSMichael Tuexen 	if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) {
31079935403aSMichael Tuexen 		ssfe = mtod(m_notify, struct sctp_send_failed_event *);
3108ab337314SMichael Tuexen 		memset(ssfe, 0, notifhdr_len);
3109ad83c8a5SMichael Tuexen 		ssfe->ssfe_type = SCTP_SEND_FAILED_EVENT;
31109935403aSMichael Tuexen 		ssfe->ssfe_flags = SCTP_DATA_UNSENT;
3111ab337314SMichael Tuexen 		ssfe->ssfe_length = (uint32_t)(notifhdr_len + sp->length);
31129935403aSMichael Tuexen 		ssfe->ssfe_error = error;
31139935403aSMichael Tuexen 		/* not exactly what the user sent in, but should be close :) */
311449656eefSMichael Tuexen 		ssfe->ssfe_info.snd_sid = sp->sid;
31159935403aSMichael Tuexen 		if (sp->some_taken) {
31169935403aSMichael Tuexen 			ssfe->ssfe_info.snd_flags = SCTP_DATA_LAST_FRAG;
31179935403aSMichael Tuexen 		} else {
31189935403aSMichael Tuexen 			ssfe->ssfe_info.snd_flags = SCTP_DATA_NOT_FRAG;
31199935403aSMichael Tuexen 		}
31209935403aSMichael Tuexen 		ssfe->ssfe_info.snd_ppid = sp->ppid;
31219935403aSMichael Tuexen 		ssfe->ssfe_info.snd_context = sp->context;
31229935403aSMichael Tuexen 		ssfe->ssfe_info.snd_assoc_id = sctp_get_associd(stcb);
31239935403aSMichael Tuexen 		ssfe->ssfe_assoc_id = sctp_get_associd(stcb);
31249935403aSMichael Tuexen 	} else {
3125f8829a4aSRandall Stewart 		ssf = mtod(m_notify, struct sctp_send_failed *);
3126ab337314SMichael Tuexen 		memset(ssf, 0, notifhdr_len);
3127f8829a4aSRandall Stewart 		ssf->ssf_type = SCTP_SEND_FAILED;
3128f8829a4aSRandall Stewart 		ssf->ssf_flags = SCTP_DATA_UNSENT;
3129ab337314SMichael Tuexen 		ssf->ssf_length = (uint32_t)(notifhdr_len + sp->length);
3130f8829a4aSRandall Stewart 		ssf->ssf_error = error;
3131f8829a4aSRandall Stewart 		/* not exactly what the user sent in, but should be close :) */
313249656eefSMichael Tuexen 		ssf->ssf_info.sinfo_stream = sp->sid;
3133f3b05218SMichael Tuexen 		ssf->ssf_info.sinfo_ssn = 0;
3134fc14de76SRandall Stewart 		if (sp->some_taken) {
3135fc14de76SRandall Stewart 			ssf->ssf_info.sinfo_flags = SCTP_DATA_LAST_FRAG;
3136fc14de76SRandall Stewart 		} else {
3137fc14de76SRandall Stewart 			ssf->ssf_info.sinfo_flags = SCTP_DATA_NOT_FRAG;
3138fc14de76SRandall Stewart 		}
3139f8829a4aSRandall Stewart 		ssf->ssf_info.sinfo_ppid = sp->ppid;
3140f8829a4aSRandall Stewart 		ssf->ssf_info.sinfo_context = sp->context;
3141f8829a4aSRandall Stewart 		ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb);
3142f8829a4aSRandall Stewart 		ssf->ssf_assoc_id = sctp_get_associd(stcb);
31439935403aSMichael Tuexen 	}
31449935403aSMichael Tuexen 	SCTP_BUF_NEXT(m_notify) = sp->data;
3145f8829a4aSRandall Stewart 
3146f8829a4aSRandall Stewart 	/* Steal off the mbuf */
3147f8829a4aSRandall Stewart 	sp->data = NULL;
3148f8829a4aSRandall Stewart 	/*
3149f8829a4aSRandall Stewart 	 * For this case, we check the actual socket buffer, since the assoc
3150f8829a4aSRandall Stewart 	 * is going away we don't want to overfill the socket buffer for a
3151f8829a4aSRandall Stewart 	 * non-reader
3152f8829a4aSRandall Stewart 	 */
3153139bc87fSRandall Stewart 	if (sctp_sbspace_failedmsgs(&stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) {
3154f8829a4aSRandall Stewart 		sctp_m_freem(m_notify);
3155f8829a4aSRandall Stewart 		return;
3156f8829a4aSRandall Stewart 	}
3157f8829a4aSRandall Stewart 	/* append to socket */
3158f8829a4aSRandall Stewart 	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
31597215cc1bSMichael Tuexen 	    0, 0, stcb->asoc.context, 0, 0, 0,
3160f8829a4aSRandall Stewart 	    m_notify);
3161f8829a4aSRandall Stewart 	if (control == NULL) {
3162f8829a4aSRandall Stewart 		/* no memory */
3163f8829a4aSRandall Stewart 		sctp_m_freem(m_notify);
3164f8829a4aSRandall Stewart 		return;
3165f8829a4aSRandall Stewart 	}
316628cd0699SMichael Tuexen 	control->length = SCTP_BUF_LEN(m_notify);
3167139bc87fSRandall Stewart 	control->spec_flags = M_NOTIFICATION;
316828cd0699SMichael Tuexen 	/* not that we need this */
316928cd0699SMichael Tuexen 	control->tail_mbuf = m_notify;
3170f8829a4aSRandall Stewart 	sctp_add_to_readq(stcb->sctp_ep, stcb,
3171f8829a4aSRandall Stewart 	    control,
3172cfde3ff7SRandall Stewart 	    &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, so_locked);
3173f8829a4aSRandall Stewart }
3174f8829a4aSRandall Stewart 
3175f8829a4aSRandall Stewart 
3176f8829a4aSRandall Stewart 
3177f8829a4aSRandall Stewart static void
31787215cc1bSMichael Tuexen sctp_notify_adaptation_layer(struct sctp_tcb *stcb)
3179f8829a4aSRandall Stewart {
3180f8829a4aSRandall Stewart 	struct mbuf *m_notify;
3181f8829a4aSRandall Stewart 	struct sctp_adaptation_event *sai;
3182f8829a4aSRandall Stewart 	struct sctp_queued_to_read *control;
3183f8829a4aSRandall Stewart 
318460990c0cSMichael Tuexen 	if ((stcb == NULL) ||
318560990c0cSMichael Tuexen 	    sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT)) {
3186f8829a4aSRandall Stewart 		/* event not enabled */
3187f8829a4aSRandall Stewart 		return;
3188830d754dSRandall Stewart 	}
3189eb1b1807SGleb Smirnoff 	m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_adaption_event), 0, M_NOWAIT, 1, MT_DATA);
3190f8829a4aSRandall Stewart 	if (m_notify == NULL)
3191f8829a4aSRandall Stewart 		/* no space left */
3192f8829a4aSRandall Stewart 		return;
3193139bc87fSRandall Stewart 	SCTP_BUF_LEN(m_notify) = 0;
3194f8829a4aSRandall Stewart 	sai = mtod(m_notify, struct sctp_adaptation_event *);
3195e432298aSXin LI 	memset(sai, 0, sizeof(struct sctp_adaptation_event));
3196f8829a4aSRandall Stewart 	sai->sai_type = SCTP_ADAPTATION_INDICATION;
3197f8829a4aSRandall Stewart 	sai->sai_flags = 0;
3198f8829a4aSRandall Stewart 	sai->sai_length = sizeof(struct sctp_adaptation_event);
31992afb3e84SRandall Stewart 	sai->sai_adaptation_ind = stcb->asoc.peers_adaptation;
3200f8829a4aSRandall Stewart 	sai->sai_assoc_id = sctp_get_associd(stcb);
3201f8829a4aSRandall Stewart 
3202139bc87fSRandall Stewart 	SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_adaptation_event);
3203139bc87fSRandall Stewart 	SCTP_BUF_NEXT(m_notify) = NULL;
3204f8829a4aSRandall Stewart 
3205f8829a4aSRandall Stewart 	/* append to socket */
3206f8829a4aSRandall Stewart 	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
32077215cc1bSMichael Tuexen 	    0, 0, stcb->asoc.context, 0, 0, 0,
3208f8829a4aSRandall Stewart 	    m_notify);
3209f8829a4aSRandall Stewart 	if (control == NULL) {
3210f8829a4aSRandall Stewart 		/* no memory */
3211f8829a4aSRandall Stewart 		sctp_m_freem(m_notify);
3212f8829a4aSRandall Stewart 		return;
3213f8829a4aSRandall Stewart 	}
3214139bc87fSRandall Stewart 	control->length = SCTP_BUF_LEN(m_notify);
3215139bc87fSRandall Stewart 	control->spec_flags = M_NOTIFICATION;
3216f8829a4aSRandall Stewart 	/* not that we need this */
3217f8829a4aSRandall Stewart 	control->tail_mbuf = m_notify;
3218f8829a4aSRandall Stewart 	sctp_add_to_readq(stcb->sctp_ep, stcb,
3219f8829a4aSRandall Stewart 	    control,
3220cfde3ff7SRandall Stewart 	    &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
3221f8829a4aSRandall Stewart }
3222f8829a4aSRandall Stewart 
322303b0b021SRandall Stewart /* This always must be called with the read-queue LOCKED in the INP */
3224810ec536SMichael Tuexen static void
32252dad8a55SRandall Stewart sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, uint32_t error,
3226810ec536SMichael Tuexen     uint32_t val, int so_locked
3227810ec536SMichael Tuexen #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
3228810ec536SMichael Tuexen     SCTP_UNUSED
3229810ec536SMichael Tuexen #endif
3230810ec536SMichael Tuexen )
3231f8829a4aSRandall Stewart {
3232f8829a4aSRandall Stewart 	struct mbuf *m_notify;
3233f8829a4aSRandall Stewart 	struct sctp_pdapi_event *pdapi;
3234f8829a4aSRandall Stewart 	struct sctp_queued_to_read *control;
323503b0b021SRandall Stewart 	struct sockbuf *sb;
3236f8829a4aSRandall Stewart 
323760990c0cSMichael Tuexen 	if ((stcb == NULL) ||
323860990c0cSMichael Tuexen 	    sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_PDAPIEVNT)) {
3239f8829a4aSRandall Stewart 		/* event not enabled */
3240f8829a4aSRandall Stewart 		return;
3241830d754dSRandall Stewart 	}
3242cd1386abSMichael Tuexen 	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_CANT_READ) {
3243cd1386abSMichael Tuexen 		return;
3244cd1386abSMichael Tuexen 	}
3245eb1b1807SGleb Smirnoff 	m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_pdapi_event), 0, M_NOWAIT, 1, MT_DATA);
3246f8829a4aSRandall Stewart 	if (m_notify == NULL)
3247f8829a4aSRandall Stewart 		/* no space left */
3248f8829a4aSRandall Stewart 		return;
3249139bc87fSRandall Stewart 	SCTP_BUF_LEN(m_notify) = 0;
3250f8829a4aSRandall Stewart 	pdapi = mtod(m_notify, struct sctp_pdapi_event *);
3251e432298aSXin LI 	memset(pdapi, 0, sizeof(struct sctp_pdapi_event));
3252f8829a4aSRandall Stewart 	pdapi->pdapi_type = SCTP_PARTIAL_DELIVERY_EVENT;
3253f8829a4aSRandall Stewart 	pdapi->pdapi_flags = 0;
3254f8829a4aSRandall Stewart 	pdapi->pdapi_length = sizeof(struct sctp_pdapi_event);
3255f8829a4aSRandall Stewart 	pdapi->pdapi_indication = error;
32569a6142d8SRandall Stewart 	pdapi->pdapi_stream = (val >> 16);
32579a6142d8SRandall Stewart 	pdapi->pdapi_seq = (val & 0x0000ffff);
3258f8829a4aSRandall Stewart 	pdapi->pdapi_assoc_id = sctp_get_associd(stcb);
3259f8829a4aSRandall Stewart 
3260139bc87fSRandall Stewart 	SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_pdapi_event);
3261139bc87fSRandall Stewart 	SCTP_BUF_NEXT(m_notify) = NULL;
3262f8829a4aSRandall Stewart 	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
32637215cc1bSMichael Tuexen 	    0, 0, stcb->asoc.context, 0, 0, 0,
3264f8829a4aSRandall Stewart 	    m_notify);
3265f8829a4aSRandall Stewart 	if (control == NULL) {
3266f8829a4aSRandall Stewart 		/* no memory */
3267f8829a4aSRandall Stewart 		sctp_m_freem(m_notify);
3268f8829a4aSRandall Stewart 		return;
3269f8829a4aSRandall Stewart 	}
3270139bc87fSRandall Stewart 	control->length = SCTP_BUF_LEN(m_notify);
327128cd0699SMichael Tuexen 	control->spec_flags = M_NOTIFICATION;
3272f8829a4aSRandall Stewart 	/* not that we need this */
3273f8829a4aSRandall Stewart 	control->tail_mbuf = m_notify;
327403b0b021SRandall Stewart 	sb = &stcb->sctp_socket->so_rcv;
3275b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
3276139bc87fSRandall Stewart 		sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(m_notify));
327780fefe0aSRandall Stewart 	}
327803b0b021SRandall Stewart 	sctp_sballoc(stcb, sb, m_notify);
3279b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
328003b0b021SRandall Stewart 		sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0);
328180fefe0aSRandall Stewart 	}
328203b0b021SRandall Stewart 	control->end_added = 1;
328303b0b021SRandall Stewart 	if (stcb->asoc.control_pdapi)
328403b0b021SRandall Stewart 		TAILQ_INSERT_AFTER(&stcb->sctp_ep->read_queue, stcb->asoc.control_pdapi, control, next);
328503b0b021SRandall Stewart 	else {
328603b0b021SRandall Stewart 		/* we really should not see this case */
328703b0b021SRandall Stewart 		TAILQ_INSERT_TAIL(&stcb->sctp_ep->read_queue, control, next);
328803b0b021SRandall Stewart 	}
328903b0b021SRandall Stewart 	if (stcb->sctp_ep && stcb->sctp_socket) {
329003b0b021SRandall Stewart 		/* This should always be the case */
3291810ec536SMichael Tuexen #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
3292810ec536SMichael Tuexen 		struct socket *so;
3293810ec536SMichael Tuexen 
3294810ec536SMichael Tuexen 		so = SCTP_INP_SO(stcb->sctp_ep);
3295810ec536SMichael Tuexen 		if (!so_locked) {
3296810ec536SMichael Tuexen 			atomic_add_int(&stcb->asoc.refcnt, 1);
3297810ec536SMichael Tuexen 			SCTP_TCB_UNLOCK(stcb);
3298810ec536SMichael Tuexen 			SCTP_SOCKET_LOCK(so, 1);
3299810ec536SMichael Tuexen 			SCTP_TCB_LOCK(stcb);
3300810ec536SMichael Tuexen 			atomic_subtract_int(&stcb->asoc.refcnt, 1);
3301810ec536SMichael Tuexen 			if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
3302810ec536SMichael Tuexen 				SCTP_SOCKET_UNLOCK(so, 1);
3303810ec536SMichael Tuexen 				return;
3304810ec536SMichael Tuexen 			}
3305810ec536SMichael Tuexen 		}
3306810ec536SMichael Tuexen #endif
330703b0b021SRandall Stewart 		sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
3308810ec536SMichael Tuexen #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
3309810ec536SMichael Tuexen 		if (!so_locked) {
3310810ec536SMichael Tuexen 			SCTP_SOCKET_UNLOCK(so, 1);
3311810ec536SMichael Tuexen 		}
3312810ec536SMichael Tuexen #endif
3313f8829a4aSRandall Stewart 	}
3314f8829a4aSRandall Stewart }
3315f8829a4aSRandall Stewart 
3316f8829a4aSRandall Stewart static void
3317f8829a4aSRandall Stewart sctp_notify_shutdown_event(struct sctp_tcb *stcb)
3318f8829a4aSRandall Stewart {
3319f8829a4aSRandall Stewart 	struct mbuf *m_notify;
3320f8829a4aSRandall Stewart 	struct sctp_shutdown_event *sse;
3321f8829a4aSRandall Stewart 	struct sctp_queued_to_read *control;
3322f8829a4aSRandall Stewart 
3323f8829a4aSRandall Stewart 	/*
3324f8829a4aSRandall Stewart 	 * For TCP model AND UDP connected sockets we will send an error up
3325f8829a4aSRandall Stewart 	 * when an SHUTDOWN completes
3326f8829a4aSRandall Stewart 	 */
3327f8829a4aSRandall Stewart 	if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3328f8829a4aSRandall Stewart 	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
3329f8829a4aSRandall Stewart 		/* mark socket closed for read/write and wakeup! */
3330ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
3331ceaad40aSRandall Stewart 		struct socket *so;
3332ceaad40aSRandall Stewart 
3333ceaad40aSRandall Stewart 		so = SCTP_INP_SO(stcb->sctp_ep);
3334ceaad40aSRandall Stewart 		atomic_add_int(&stcb->asoc.refcnt, 1);
3335ceaad40aSRandall Stewart 		SCTP_TCB_UNLOCK(stcb);
3336ceaad40aSRandall Stewart 		SCTP_SOCKET_LOCK(so, 1);
3337ceaad40aSRandall Stewart 		SCTP_TCB_LOCK(stcb);
3338ceaad40aSRandall Stewart 		atomic_subtract_int(&stcb->asoc.refcnt, 1);
3339ceaad40aSRandall Stewart 		if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
3340ceaad40aSRandall Stewart 			SCTP_SOCKET_UNLOCK(so, 1);
3341ceaad40aSRandall Stewart 			return;
3342ceaad40aSRandall Stewart 		}
3343ceaad40aSRandall Stewart #endif
3344f8829a4aSRandall Stewart 		socantsendmore(stcb->sctp_socket);
3345ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
3346ceaad40aSRandall Stewart 		SCTP_SOCKET_UNLOCK(so, 1);
3347ceaad40aSRandall Stewart #endif
3348f8829a4aSRandall Stewart 	}
3349e2e7c62eSMichael Tuexen 	if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT)) {
3350f8829a4aSRandall Stewart 		/* event not enabled */
3351f8829a4aSRandall Stewart 		return;
3352830d754dSRandall Stewart 	}
3353eb1b1807SGleb Smirnoff 	m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_shutdown_event), 0, M_NOWAIT, 1, MT_DATA);
3354f8829a4aSRandall Stewart 	if (m_notify == NULL)
3355f8829a4aSRandall Stewart 		/* no space left */
3356f8829a4aSRandall Stewart 		return;
3357f8829a4aSRandall Stewart 	sse = mtod(m_notify, struct sctp_shutdown_event *);
3358e432298aSXin LI 	memset(sse, 0, sizeof(struct sctp_shutdown_event));
3359f8829a4aSRandall Stewart 	sse->sse_type = SCTP_SHUTDOWN_EVENT;
3360f8829a4aSRandall Stewart 	sse->sse_flags = 0;
3361f8829a4aSRandall Stewart 	sse->sse_length = sizeof(struct sctp_shutdown_event);
3362f8829a4aSRandall Stewart 	sse->sse_assoc_id = sctp_get_associd(stcb);
3363f8829a4aSRandall Stewart 
3364139bc87fSRandall Stewart 	SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_shutdown_event);
3365139bc87fSRandall Stewart 	SCTP_BUF_NEXT(m_notify) = NULL;
3366f8829a4aSRandall Stewart 
3367f8829a4aSRandall Stewart 	/* append to socket */
3368f8829a4aSRandall Stewart 	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
33697215cc1bSMichael Tuexen 	    0, 0, stcb->asoc.context, 0, 0, 0,
3370f8829a4aSRandall Stewart 	    m_notify);
3371f8829a4aSRandall Stewart 	if (control == NULL) {
3372f8829a4aSRandall Stewart 		/* no memory */
3373f8829a4aSRandall Stewart 		sctp_m_freem(m_notify);
3374f8829a4aSRandall Stewart 		return;
3375f8829a4aSRandall Stewart 	}
3376139bc87fSRandall Stewart 	control->length = SCTP_BUF_LEN(m_notify);
337728cd0699SMichael Tuexen 	control->spec_flags = M_NOTIFICATION;
3378f8829a4aSRandall Stewart 	/* not that we need this */
3379f8829a4aSRandall Stewart 	control->tail_mbuf = m_notify;
3380f8829a4aSRandall Stewart 	sctp_add_to_readq(stcb->sctp_ep, stcb,
3381f8829a4aSRandall Stewart 	    control,
3382cfde3ff7SRandall Stewart 	    &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
3383f8829a4aSRandall Stewart }
3384f8829a4aSRandall Stewart 
3385f8829a4aSRandall Stewart static void
3386830d754dSRandall Stewart sctp_notify_sender_dry_event(struct sctp_tcb *stcb,
3387830d754dSRandall Stewart     int so_locked
3388830d754dSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
3389830d754dSRandall Stewart     SCTP_UNUSED
3390830d754dSRandall Stewart #endif
3391830d754dSRandall Stewart )
3392830d754dSRandall Stewart {
3393830d754dSRandall Stewart 	struct mbuf *m_notify;
3394830d754dSRandall Stewart 	struct sctp_sender_dry_event *event;
3395830d754dSRandall Stewart 	struct sctp_queued_to_read *control;
3396830d754dSRandall Stewart 
339760990c0cSMichael Tuexen 	if ((stcb == NULL) ||
339860990c0cSMichael Tuexen 	    sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_DRYEVNT)) {
3399830d754dSRandall Stewart 		/* event not enabled */
3400830d754dSRandall Stewart 		return;
3401830d754dSRandall Stewart 	}
3402eb1b1807SGleb Smirnoff 	m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_sender_dry_event), 0, M_NOWAIT, 1, MT_DATA);
3403830d754dSRandall Stewart 	if (m_notify == NULL) {
3404830d754dSRandall Stewart 		/* no space left */
3405830d754dSRandall Stewart 		return;
3406830d754dSRandall Stewart 	}
3407830d754dSRandall Stewart 	SCTP_BUF_LEN(m_notify) = 0;
3408830d754dSRandall Stewart 	event = mtod(m_notify, struct sctp_sender_dry_event *);
3409e432298aSXin LI 	memset(event, 0, sizeof(struct sctp_sender_dry_event));
3410830d754dSRandall Stewart 	event->sender_dry_type = SCTP_SENDER_DRY_EVENT;
3411830d754dSRandall Stewart 	event->sender_dry_flags = 0;
3412830d754dSRandall Stewart 	event->sender_dry_length = sizeof(struct sctp_sender_dry_event);
3413830d754dSRandall Stewart 	event->sender_dry_assoc_id = sctp_get_associd(stcb);
3414830d754dSRandall Stewart 
3415830d754dSRandall Stewart 	SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_sender_dry_event);
3416830d754dSRandall Stewart 	SCTP_BUF_NEXT(m_notify) = NULL;
3417830d754dSRandall Stewart 
3418830d754dSRandall Stewart 	/* append to socket */
3419830d754dSRandall Stewart 	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
34207215cc1bSMichael Tuexen 	    0, 0, stcb->asoc.context, 0, 0, 0,
34217215cc1bSMichael Tuexen 	    m_notify);
3422830d754dSRandall Stewart 	if (control == NULL) {
3423830d754dSRandall Stewart 		/* no memory */
3424830d754dSRandall Stewart 		sctp_m_freem(m_notify);
3425830d754dSRandall Stewart 		return;
3426830d754dSRandall Stewart 	}
3427830d754dSRandall Stewart 	control->length = SCTP_BUF_LEN(m_notify);
3428830d754dSRandall Stewart 	control->spec_flags = M_NOTIFICATION;
3429830d754dSRandall Stewart 	/* not that we need this */
3430830d754dSRandall Stewart 	control->tail_mbuf = m_notify;
3431830d754dSRandall Stewart 	sctp_add_to_readq(stcb->sctp_ep, stcb, control,
3432cfde3ff7SRandall Stewart 	    &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, so_locked);
3433830d754dSRandall Stewart }
3434830d754dSRandall Stewart 
3435ea44232bSRandall Stewart 
3436c4e848b7SRandall Stewart void
3437c4e848b7SRandall Stewart sctp_notify_stream_reset_add(struct sctp_tcb *stcb, uint16_t numberin, uint16_t numberout, int flag)
3438ea44232bSRandall Stewart {
3439ea44232bSRandall Stewart 	struct mbuf *m_notify;
3440ea44232bSRandall Stewart 	struct sctp_queued_to_read *control;
3441c4e848b7SRandall Stewart 	struct sctp_stream_change_event *stradd;
3442ea44232bSRandall Stewart 
34438c501e51SMichael Tuexen 	if ((stcb == NULL) ||
34448c501e51SMichael Tuexen 	    (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_STREAM_CHANGEEVNT))) {
3445ea44232bSRandall Stewart 		/* event not enabled */
3446ea44232bSRandall Stewart 		return;
3447ea44232bSRandall Stewart 	}
3448c4e848b7SRandall Stewart 	if ((stcb->asoc.peer_req_out) && flag) {
3449c4e848b7SRandall Stewart 		/* Peer made the request, don't tell the local user */
3450c4e848b7SRandall Stewart 		stcb->asoc.peer_req_out = 0;
3451c4e848b7SRandall Stewart 		return;
3452c4e848b7SRandall Stewart 	}
3453c4e848b7SRandall Stewart 	stcb->asoc.peer_req_out = 0;
3454e432298aSXin LI 	m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_stream_change_event), 0, M_NOWAIT, 1, MT_DATA);
3455ea44232bSRandall Stewart 	if (m_notify == NULL)
3456ea44232bSRandall Stewart 		/* no space left */
3457ea44232bSRandall Stewart 		return;
3458ea44232bSRandall Stewart 	SCTP_BUF_LEN(m_notify) = 0;
3459c4e848b7SRandall Stewart 	stradd = mtod(m_notify, struct sctp_stream_change_event *);
3460e432298aSXin LI 	memset(stradd, 0, sizeof(struct sctp_stream_change_event));
3461c4e848b7SRandall Stewart 	stradd->strchange_type = SCTP_STREAM_CHANGE_EVENT;
3462c4e848b7SRandall Stewart 	stradd->strchange_flags = flag;
3463e432298aSXin LI 	stradd->strchange_length = sizeof(struct sctp_stream_change_event);
3464c4e848b7SRandall Stewart 	stradd->strchange_assoc_id = sctp_get_associd(stcb);
3465c4e848b7SRandall Stewart 	stradd->strchange_instrms = numberin;
3466c4e848b7SRandall Stewart 	stradd->strchange_outstrms = numberout;
3467e432298aSXin LI 	SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_stream_change_event);
3468ea44232bSRandall Stewart 	SCTP_BUF_NEXT(m_notify) = NULL;
3469ea44232bSRandall Stewart 	if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) {
3470ea44232bSRandall Stewart 		/* no space */
3471ea44232bSRandall Stewart 		sctp_m_freem(m_notify);
3472ea44232bSRandall Stewart 		return;
3473ea44232bSRandall Stewart 	}
3474ea44232bSRandall Stewart 	/* append to socket */
3475ea44232bSRandall Stewart 	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
34767215cc1bSMichael Tuexen 	    0, 0, stcb->asoc.context, 0, 0, 0,
3477ea44232bSRandall Stewart 	    m_notify);
3478ea44232bSRandall Stewart 	if (control == NULL) {
3479ea44232bSRandall Stewart 		/* no memory */
3480ea44232bSRandall Stewart 		sctp_m_freem(m_notify);
3481ea44232bSRandall Stewart 		return;
3482ea44232bSRandall Stewart 	}
3483ea44232bSRandall Stewart 	control->length = SCTP_BUF_LEN(m_notify);
348428cd0699SMichael Tuexen 	control->spec_flags = M_NOTIFICATION;
3485ea44232bSRandall Stewart 	/* not that we need this */
3486ea44232bSRandall Stewart 	control->tail_mbuf = m_notify;
3487ea44232bSRandall Stewart 	sctp_add_to_readq(stcb->sctp_ep, stcb,
3488ea44232bSRandall Stewart 	    control,
3489cfde3ff7SRandall Stewart 	    &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
3490ea44232bSRandall Stewart }
3491ea44232bSRandall Stewart 
3492c4e848b7SRandall Stewart void
3493c4e848b7SRandall Stewart sctp_notify_stream_reset_tsn(struct sctp_tcb *stcb, uint32_t sending_tsn, uint32_t recv_tsn, int flag)
3494c4e848b7SRandall Stewart {
3495c4e848b7SRandall Stewart 	struct mbuf *m_notify;
3496c4e848b7SRandall Stewart 	struct sctp_queued_to_read *control;
3497c4e848b7SRandall Stewart 	struct sctp_assoc_reset_event *strasoc;
3498c4e848b7SRandall Stewart 
34998c501e51SMichael Tuexen 	if ((stcb == NULL) ||
35008c501e51SMichael Tuexen 	    (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_ASSOC_RESETEVNT))) {
3501c4e848b7SRandall Stewart 		/* event not enabled */
3502c4e848b7SRandall Stewart 		return;
3503c4e848b7SRandall Stewart 	}
3504e432298aSXin LI 	m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_assoc_reset_event), 0, M_NOWAIT, 1, MT_DATA);
3505c4e848b7SRandall Stewart 	if (m_notify == NULL)
3506c4e848b7SRandall Stewart 		/* no space left */
3507c4e848b7SRandall Stewart 		return;
3508c4e848b7SRandall Stewart 	SCTP_BUF_LEN(m_notify) = 0;
3509c4e848b7SRandall Stewart 	strasoc = mtod(m_notify, struct sctp_assoc_reset_event *);
3510e432298aSXin LI 	memset(strasoc, 0, sizeof(struct sctp_assoc_reset_event));
3511c4e848b7SRandall Stewart 	strasoc->assocreset_type = SCTP_ASSOC_RESET_EVENT;
3512c4e848b7SRandall Stewart 	strasoc->assocreset_flags = flag;
3513e432298aSXin LI 	strasoc->assocreset_length = sizeof(struct sctp_assoc_reset_event);
3514c4e848b7SRandall Stewart 	strasoc->assocreset_assoc_id = sctp_get_associd(stcb);
3515c4e848b7SRandall Stewart 	strasoc->assocreset_local_tsn = sending_tsn;
3516c4e848b7SRandall Stewart 	strasoc->assocreset_remote_tsn = recv_tsn;
3517e432298aSXin LI 	SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_assoc_reset_event);
3518c4e848b7SRandall Stewart 	SCTP_BUF_NEXT(m_notify) = NULL;
3519c4e848b7SRandall Stewart 	if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) {
3520c4e848b7SRandall Stewart 		/* no space */
3521c4e848b7SRandall Stewart 		sctp_m_freem(m_notify);
3522c4e848b7SRandall Stewart 		return;
3523c4e848b7SRandall Stewart 	}
3524c4e848b7SRandall Stewart 	/* append to socket */
3525c4e848b7SRandall Stewart 	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
3526c4e848b7SRandall Stewart 	    0, 0, stcb->asoc.context, 0, 0, 0,
3527c4e848b7SRandall Stewart 	    m_notify);
3528c4e848b7SRandall Stewart 	if (control == NULL) {
3529c4e848b7SRandall Stewart 		/* no memory */
3530c4e848b7SRandall Stewart 		sctp_m_freem(m_notify);
3531c4e848b7SRandall Stewart 		return;
3532c4e848b7SRandall Stewart 	}
3533c4e848b7SRandall Stewart 	control->length = SCTP_BUF_LEN(m_notify);
353428cd0699SMichael Tuexen 	control->spec_flags = M_NOTIFICATION;
3535c4e848b7SRandall Stewart 	/* not that we need this */
3536c4e848b7SRandall Stewart 	control->tail_mbuf = m_notify;
3537c4e848b7SRandall Stewart 	sctp_add_to_readq(stcb->sctp_ep, stcb,
3538c4e848b7SRandall Stewart 	    control,
3539c4e848b7SRandall Stewart 	    &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
3540c4e848b7SRandall Stewart }
3541c4e848b7SRandall Stewart 
3542c4e848b7SRandall Stewart 
3543ea44232bSRandall Stewart 
3544830d754dSRandall Stewart static void
3545f8829a4aSRandall Stewart sctp_notify_stream_reset(struct sctp_tcb *stcb,
3546f8829a4aSRandall Stewart     int number_entries, uint16_t *list, int flag)
3547f8829a4aSRandall Stewart {
3548f8829a4aSRandall Stewart 	struct mbuf *m_notify;
3549f8829a4aSRandall Stewart 	struct sctp_queued_to_read *control;
3550f8829a4aSRandall Stewart 	struct sctp_stream_reset_event *strreset;
3551f8829a4aSRandall Stewart 	int len;
3552f8829a4aSRandall Stewart 
35538c501e51SMichael Tuexen 	if ((stcb == NULL) ||
35548c501e51SMichael Tuexen 	    (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT))) {
3555f8829a4aSRandall Stewart 		/* event not enabled */
3556f8829a4aSRandall Stewart 		return;
3557830d754dSRandall Stewart 	}
3558eb1b1807SGleb Smirnoff 	m_notify = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA);
3559f8829a4aSRandall Stewart 	if (m_notify == NULL)
3560f8829a4aSRandall Stewart 		/* no space left */
3561f8829a4aSRandall Stewart 		return;
3562139bc87fSRandall Stewart 	SCTP_BUF_LEN(m_notify) = 0;
3563f8829a4aSRandall Stewart 	len = sizeof(struct sctp_stream_reset_event) + (number_entries * sizeof(uint16_t));
3564f8829a4aSRandall Stewart 	if (len > M_TRAILINGSPACE(m_notify)) {
3565f8829a4aSRandall Stewart 		/* never enough room */
3566f8829a4aSRandall Stewart 		sctp_m_freem(m_notify);
3567f8829a4aSRandall Stewart 		return;
3568f8829a4aSRandall Stewart 	}
3569f8829a4aSRandall Stewart 	strreset = mtod(m_notify, struct sctp_stream_reset_event *);
3570e432298aSXin LI 	memset(strreset, 0, len);
3571f8829a4aSRandall Stewart 	strreset->strreset_type = SCTP_STREAM_RESET_EVENT;
3572c4e848b7SRandall Stewart 	strreset->strreset_flags = flag;
3573f8829a4aSRandall Stewart 	strreset->strreset_length = len;
3574f8829a4aSRandall Stewart 	strreset->strreset_assoc_id = sctp_get_associd(stcb);
3575f8829a4aSRandall Stewart 	if (number_entries) {
3576f8829a4aSRandall Stewart 		int i;
3577f8829a4aSRandall Stewart 
3578f8829a4aSRandall Stewart 		for (i = 0; i < number_entries; i++) {
3579c4e848b7SRandall Stewart 			strreset->strreset_stream_list[i] = ntohs(list[i]);
3580f8829a4aSRandall Stewart 		}
3581f8829a4aSRandall Stewart 	}
3582139bc87fSRandall Stewart 	SCTP_BUF_LEN(m_notify) = len;
3583139bc87fSRandall Stewart 	SCTP_BUF_NEXT(m_notify) = NULL;
3584139bc87fSRandall Stewart 	if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) {
3585f8829a4aSRandall Stewart 		/* no space */
3586f8829a4aSRandall Stewart 		sctp_m_freem(m_notify);
3587f8829a4aSRandall Stewart 		return;
3588f8829a4aSRandall Stewart 	}
3589f8829a4aSRandall Stewart 	/* append to socket */
3590f8829a4aSRandall Stewart 	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
35917215cc1bSMichael Tuexen 	    0, 0, stcb->asoc.context, 0, 0, 0,
3592f8829a4aSRandall Stewart 	    m_notify);
3593f8829a4aSRandall Stewart 	if (control == NULL) {
3594f8829a4aSRandall Stewart 		/* no memory */
3595f8829a4aSRandall Stewart 		sctp_m_freem(m_notify);
3596f8829a4aSRandall Stewart 		return;
3597f8829a4aSRandall Stewart 	}
3598139bc87fSRandall Stewart 	control->length = SCTP_BUF_LEN(m_notify);
359928cd0699SMichael Tuexen 	control->spec_flags = M_NOTIFICATION;
3600f8829a4aSRandall Stewart 	/* not that we need this */
3601f8829a4aSRandall Stewart 	control->tail_mbuf = m_notify;
3602f8829a4aSRandall Stewart 	sctp_add_to_readq(stcb->sctp_ep, stcb,
3603f8829a4aSRandall Stewart 	    control,
3604cfde3ff7SRandall Stewart 	    &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
3605f8829a4aSRandall Stewart }
3606f8829a4aSRandall Stewart 
3607f8829a4aSRandall Stewart 
3608389b1b11SMichael Tuexen static void
3609389b1b11SMichael Tuexen sctp_notify_remote_error(struct sctp_tcb *stcb, uint16_t error, struct sctp_error_chunk *chunk)
3610389b1b11SMichael Tuexen {
3611389b1b11SMichael Tuexen 	struct mbuf *m_notify;
3612389b1b11SMichael Tuexen 	struct sctp_remote_error *sre;
3613389b1b11SMichael Tuexen 	struct sctp_queued_to_read *control;
36149a8e3088SMichael Tuexen 	unsigned int notif_len;
36159a8e3088SMichael Tuexen 	uint16_t chunk_len;
3616389b1b11SMichael Tuexen 
3617389b1b11SMichael Tuexen 	if ((stcb == NULL) ||
3618389b1b11SMichael Tuexen 	    sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVPEERERR)) {
3619389b1b11SMichael Tuexen 		return;
3620389b1b11SMichael Tuexen 	}
3621389b1b11SMichael Tuexen 	if (chunk != NULL) {
3622c9eb4473SMichael Tuexen 		chunk_len = ntohs(chunk->ch.chunk_length);
36239669e724SMichael Tuexen 		/*
36249669e724SMichael Tuexen 		 * Only SCTP_CHUNK_BUFFER_SIZE are guaranteed to be
362545d41de5SMichael Tuexen 		 * contiguous.
36269669e724SMichael Tuexen 		 */
36279669e724SMichael Tuexen 		if (chunk_len > SCTP_CHUNK_BUFFER_SIZE) {
36289669e724SMichael Tuexen 			chunk_len = SCTP_CHUNK_BUFFER_SIZE;
36299669e724SMichael Tuexen 		}
3630389b1b11SMichael Tuexen 	} else {
3631389b1b11SMichael Tuexen 		chunk_len = 0;
3632389b1b11SMichael Tuexen 	}
36339a8e3088SMichael Tuexen 	notif_len = (unsigned int)(sizeof(struct sctp_remote_error) + chunk_len);
3634eb1b1807SGleb Smirnoff 	m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA);
3635389b1b11SMichael Tuexen 	if (m_notify == NULL) {
3636389b1b11SMichael Tuexen 		/* Retry with smaller value. */
36379a8e3088SMichael Tuexen 		notif_len = (unsigned int)sizeof(struct sctp_remote_error);
3638eb1b1807SGleb Smirnoff 		m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA);
3639389b1b11SMichael Tuexen 		if (m_notify == NULL) {
3640389b1b11SMichael Tuexen 			return;
3641389b1b11SMichael Tuexen 		}
3642389b1b11SMichael Tuexen 	}
3643389b1b11SMichael Tuexen 	SCTP_BUF_NEXT(m_notify) = NULL;
3644389b1b11SMichael Tuexen 	sre = mtod(m_notify, struct sctp_remote_error *);
364556711f94SMichael Tuexen 	memset(sre, 0, notif_len);
3646389b1b11SMichael Tuexen 	sre->sre_type = SCTP_REMOTE_ERROR;
3647389b1b11SMichael Tuexen 	sre->sre_flags = 0;
3648389b1b11SMichael Tuexen 	sre->sre_length = sizeof(struct sctp_remote_error);
3649389b1b11SMichael Tuexen 	sre->sre_error = error;
3650389b1b11SMichael Tuexen 	sre->sre_assoc_id = sctp_get_associd(stcb);
3651389b1b11SMichael Tuexen 	if (notif_len > sizeof(struct sctp_remote_error)) {
3652389b1b11SMichael Tuexen 		memcpy(sre->sre_data, chunk, chunk_len);
3653389b1b11SMichael Tuexen 		sre->sre_length += chunk_len;
3654389b1b11SMichael Tuexen 	}
3655389b1b11SMichael Tuexen 	SCTP_BUF_LEN(m_notify) = sre->sre_length;
3656389b1b11SMichael Tuexen 	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
3657389b1b11SMichael Tuexen 	    0, 0, stcb->asoc.context, 0, 0, 0,
3658389b1b11SMichael Tuexen 	    m_notify);
3659389b1b11SMichael Tuexen 	if (control != NULL) {
3660389b1b11SMichael Tuexen 		control->length = SCTP_BUF_LEN(m_notify);
366128cd0699SMichael Tuexen 		control->spec_flags = M_NOTIFICATION;
3662389b1b11SMichael Tuexen 		/* not that we need this */
3663389b1b11SMichael Tuexen 		control->tail_mbuf = m_notify;
3664389b1b11SMichael Tuexen 		sctp_add_to_readq(stcb->sctp_ep, stcb,
3665389b1b11SMichael Tuexen 		    control,
3666389b1b11SMichael Tuexen 		    &stcb->sctp_socket->so_rcv, 1,
3667389b1b11SMichael Tuexen 		    SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
3668389b1b11SMichael Tuexen 	} else {
3669389b1b11SMichael Tuexen 		sctp_m_freem(m_notify);
3670389b1b11SMichael Tuexen 	}
3671389b1b11SMichael Tuexen }
3672389b1b11SMichael Tuexen 
3673389b1b11SMichael Tuexen 
3674f8829a4aSRandall Stewart void
3675f8829a4aSRandall Stewart sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
3676ceaad40aSRandall Stewart     uint32_t error, void *data, int so_locked
3677ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
3678ceaad40aSRandall Stewart     SCTP_UNUSED
3679ceaad40aSRandall Stewart #endif
3680ceaad40aSRandall Stewart )
3681f8829a4aSRandall Stewart {
3682830d754dSRandall Stewart 	if ((stcb == NULL) ||
3683830d754dSRandall Stewart 	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
3684f8829a4aSRandall Stewart 	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
3685830d754dSRandall Stewart 	    (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) {
3686830d754dSRandall Stewart 		/* If the socket is gone we are out of here */
3687f8829a4aSRandall Stewart 		return;
3688f8829a4aSRandall Stewart 	}
3689a99b6783SRandall Stewart 	if (stcb->sctp_socket->so_rcv.sb_state & SBS_CANTRCVMORE) {
3690a99b6783SRandall Stewart 		return;
3691a99b6783SRandall Stewart 	}
3692fb4a67d2SMichael Tuexen 	if ((stcb->asoc.state & SCTP_STATE_COOKIE_WAIT) ||
3693fb4a67d2SMichael Tuexen 	    (stcb->asoc.state & SCTP_STATE_COOKIE_ECHOED)) {
369417205eccSRandall Stewart 		if ((notification == SCTP_NOTIFY_INTERFACE_DOWN) ||
369517205eccSRandall Stewart 		    (notification == SCTP_NOTIFY_INTERFACE_UP) ||
369617205eccSRandall Stewart 		    (notification == SCTP_NOTIFY_INTERFACE_CONFIRMED)) {
369717205eccSRandall Stewart 			/* Don't report these in front states */
369817205eccSRandall Stewart 			return;
369917205eccSRandall Stewart 		}
370017205eccSRandall Stewart 	}
3701f8829a4aSRandall Stewart 	switch (notification) {
3702f8829a4aSRandall Stewart 	case SCTP_NOTIFY_ASSOC_UP:
3703f8829a4aSRandall Stewart 		if (stcb->asoc.assoc_up_sent == 0) {
3704410a3b1eSMichael Tuexen 			sctp_notify_assoc_change(SCTP_COMM_UP, stcb, error, NULL, 0, so_locked);
3705f8829a4aSRandall Stewart 			stcb->asoc.assoc_up_sent = 1;
3706f8829a4aSRandall Stewart 		}
37072afb3e84SRandall Stewart 		if (stcb->asoc.adaptation_needed && (stcb->asoc.adaptation_sent == 0)) {
37087215cc1bSMichael Tuexen 			sctp_notify_adaptation_layer(stcb);
37092afb3e84SRandall Stewart 		}
3710c79bec9cSMichael Tuexen 		if (stcb->asoc.auth_supported == 0) {
3711830d754dSRandall Stewart 			sctp_ulp_notify(SCTP_NOTIFY_NO_PEER_AUTH, stcb, 0,
3712830d754dSRandall Stewart 			    NULL, so_locked);
3713830d754dSRandall Stewart 		}
3714f8829a4aSRandall Stewart 		break;
3715f8829a4aSRandall Stewart 	case SCTP_NOTIFY_ASSOC_DOWN:
3716410a3b1eSMichael Tuexen 		sctp_notify_assoc_change(SCTP_SHUTDOWN_COMP, stcb, error, NULL, 0, so_locked);
3717f8829a4aSRandall Stewart 		break;
3718f8829a4aSRandall Stewart 	case SCTP_NOTIFY_INTERFACE_DOWN:
3719f8829a4aSRandall Stewart 		{
3720f8829a4aSRandall Stewart 			struct sctp_nets *net;
3721f8829a4aSRandall Stewart 
3722f8829a4aSRandall Stewart 			net = (struct sctp_nets *)data;
3723f8829a4aSRandall Stewart 			sctp_notify_peer_addr_change(stcb, SCTP_ADDR_UNREACHABLE,
37243cb3567dSMichael Tuexen 			    (struct sockaddr *)&net->ro._l_addr, error, so_locked);
3725f8829a4aSRandall Stewart 			break;
3726f8829a4aSRandall Stewart 		}
3727f8829a4aSRandall Stewart 	case SCTP_NOTIFY_INTERFACE_UP:
3728f8829a4aSRandall Stewart 		{
3729f8829a4aSRandall Stewart 			struct sctp_nets *net;
3730f8829a4aSRandall Stewart 
3731f8829a4aSRandall Stewart 			net = (struct sctp_nets *)data;
3732f8829a4aSRandall Stewart 			sctp_notify_peer_addr_change(stcb, SCTP_ADDR_AVAILABLE,
37333cb3567dSMichael Tuexen 			    (struct sockaddr *)&net->ro._l_addr, error, so_locked);
3734f8829a4aSRandall Stewart 			break;
3735f8829a4aSRandall Stewart 		}
3736f8829a4aSRandall Stewart 	case SCTP_NOTIFY_INTERFACE_CONFIRMED:
3737f8829a4aSRandall Stewart 		{
3738f8829a4aSRandall Stewart 			struct sctp_nets *net;
3739f8829a4aSRandall Stewart 
3740f8829a4aSRandall Stewart 			net = (struct sctp_nets *)data;
3741f8829a4aSRandall Stewart 			sctp_notify_peer_addr_change(stcb, SCTP_ADDR_CONFIRMED,
37423cb3567dSMichael Tuexen 			    (struct sockaddr *)&net->ro._l_addr, error, so_locked);
3743f8829a4aSRandall Stewart 			break;
3744f8829a4aSRandall Stewart 		}
3745f8829a4aSRandall Stewart 	case SCTP_NOTIFY_SPECIAL_SP_FAIL:
3746f8829a4aSRandall Stewart 		sctp_notify_send_failed2(stcb, error,
3747ceaad40aSRandall Stewart 		    (struct sctp_stream_queue_pending *)data, so_locked);
3748f8829a4aSRandall Stewart 		break;
37491edc9dbaSMichael Tuexen 	case SCTP_NOTIFY_SENT_DG_FAIL:
37501edc9dbaSMichael Tuexen 		sctp_notify_send_failed(stcb, 1, error,
37511edc9dbaSMichael Tuexen 		    (struct sctp_tmit_chunk *)data, so_locked);
37521edc9dbaSMichael Tuexen 		break;
37531edc9dbaSMichael Tuexen 	case SCTP_NOTIFY_UNSENT_DG_FAIL:
37541edc9dbaSMichael Tuexen 		sctp_notify_send_failed(stcb, 0, error,
3755ceaad40aSRandall Stewart 		    (struct sctp_tmit_chunk *)data, so_locked);
3756f8829a4aSRandall Stewart 		break;
3757f8829a4aSRandall Stewart 	case SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION:
37589a6142d8SRandall Stewart 		{
37599a6142d8SRandall Stewart 			uint32_t val;
37609a6142d8SRandall Stewart 
37619a6142d8SRandall Stewart 			val = *((uint32_t *)data);
37629a6142d8SRandall Stewart 
3763810ec536SMichael Tuexen 			sctp_notify_partial_delivery_indication(stcb, error, val, so_locked);
3764f8829a4aSRandall Stewart 			break;
3765810ec536SMichael Tuexen 		}
3766410a3b1eSMichael Tuexen 	case SCTP_NOTIFY_ASSOC_LOC_ABORTED:
3767fb4a67d2SMichael Tuexen 		if (((stcb->asoc.state & SCTP_STATE_MASK) == SCTP_STATE_COOKIE_WAIT) ||
3768fb4a67d2SMichael Tuexen 		    ((stcb->asoc.state & SCTP_STATE_MASK) == SCTP_STATE_COOKIE_ECHOED)) {
3769410a3b1eSMichael Tuexen 			sctp_notify_assoc_change(SCTP_CANT_STR_ASSOC, stcb, error, data, 0, so_locked);
3770c105859eSRandall Stewart 		} else {
3771410a3b1eSMichael Tuexen 			sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error, data, 0, so_locked);
3772410a3b1eSMichael Tuexen 		}
3773410a3b1eSMichael Tuexen 		break;
3774410a3b1eSMichael Tuexen 	case SCTP_NOTIFY_ASSOC_REM_ABORTED:
3775fb4a67d2SMichael Tuexen 		if (((stcb->asoc.state & SCTP_STATE_MASK) == SCTP_STATE_COOKIE_WAIT) ||
3776fb4a67d2SMichael Tuexen 		    ((stcb->asoc.state & SCTP_STATE_MASK) == SCTP_STATE_COOKIE_ECHOED)) {
3777410a3b1eSMichael Tuexen 			sctp_notify_assoc_change(SCTP_CANT_STR_ASSOC, stcb, error, data, 1, so_locked);
3778410a3b1eSMichael Tuexen 		} else {
3779410a3b1eSMichael Tuexen 			sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error, data, 1, so_locked);
3780c105859eSRandall Stewart 		}
3781f8829a4aSRandall Stewart 		break;
3782f8829a4aSRandall Stewart 	case SCTP_NOTIFY_ASSOC_RESTART:
3783410a3b1eSMichael Tuexen 		sctp_notify_assoc_change(SCTP_RESTART, stcb, error, NULL, 0, so_locked);
3784c79bec9cSMichael Tuexen 		if (stcb->asoc.auth_supported == 0) {
3785830d754dSRandall Stewart 			sctp_ulp_notify(SCTP_NOTIFY_NO_PEER_AUTH, stcb, 0,
3786830d754dSRandall Stewart 			    NULL, so_locked);
3787830d754dSRandall Stewart 		}
3788f8829a4aSRandall Stewart 		break;
3789f8829a4aSRandall Stewart 	case SCTP_NOTIFY_STR_RESET_SEND:
3790d7714577SMichael Tuexen 		sctp_notify_stream_reset(stcb, error, ((uint16_t *)data), SCTP_STREAM_RESET_OUTGOING_SSN);
3791f8829a4aSRandall Stewart 		break;
3792f8829a4aSRandall Stewart 	case SCTP_NOTIFY_STR_RESET_RECV:
3793d7714577SMichael Tuexen 		sctp_notify_stream_reset(stcb, error, ((uint16_t *)data), SCTP_STREAM_RESET_INCOMING);
3794f8829a4aSRandall Stewart 		break;
3795f8829a4aSRandall Stewart 	case SCTP_NOTIFY_STR_RESET_FAILED_OUT:
3796c4e848b7SRandall Stewart 		sctp_notify_stream_reset(stcb, error, ((uint16_t *)data),
3797d7714577SMichael Tuexen 		    (SCTP_STREAM_RESET_OUTGOING_SSN | SCTP_STREAM_RESET_FAILED));
3798f8829a4aSRandall Stewart 		break;
3799d4260646SMichael Tuexen 	case SCTP_NOTIFY_STR_RESET_DENIED_OUT:
3800d4260646SMichael Tuexen 		sctp_notify_stream_reset(stcb, error, ((uint16_t *)data),
3801d4260646SMichael Tuexen 		    (SCTP_STREAM_RESET_OUTGOING_SSN | SCTP_STREAM_RESET_DENIED));
3802d4260646SMichael Tuexen 		break;
3803f8829a4aSRandall Stewart 	case SCTP_NOTIFY_STR_RESET_FAILED_IN:
3804c4e848b7SRandall Stewart 		sctp_notify_stream_reset(stcb, error, ((uint16_t *)data),
3805d7714577SMichael Tuexen 		    (SCTP_STREAM_RESET_INCOMING | SCTP_STREAM_RESET_FAILED));
3806f8829a4aSRandall Stewart 		break;
3807d4260646SMichael Tuexen 	case SCTP_NOTIFY_STR_RESET_DENIED_IN:
3808d4260646SMichael Tuexen 		sctp_notify_stream_reset(stcb, error, ((uint16_t *)data),
3809d4260646SMichael Tuexen 		    (SCTP_STREAM_RESET_INCOMING | SCTP_STREAM_RESET_DENIED));
3810d4260646SMichael Tuexen 		break;
3811f8829a4aSRandall Stewart 	case SCTP_NOTIFY_ASCONF_ADD_IP:
3812f8829a4aSRandall Stewart 		sctp_notify_peer_addr_change(stcb, SCTP_ADDR_ADDED, data,
38133cb3567dSMichael Tuexen 		    error, so_locked);
3814f8829a4aSRandall Stewart 		break;
3815f8829a4aSRandall Stewart 	case SCTP_NOTIFY_ASCONF_DELETE_IP:
3816f8829a4aSRandall Stewart 		sctp_notify_peer_addr_change(stcb, SCTP_ADDR_REMOVED, data,
38173cb3567dSMichael Tuexen 		    error, so_locked);
3818f8829a4aSRandall Stewart 		break;
3819f8829a4aSRandall Stewart 	case SCTP_NOTIFY_ASCONF_SET_PRIMARY:
3820f8829a4aSRandall Stewart 		sctp_notify_peer_addr_change(stcb, SCTP_ADDR_MADE_PRIM, data,
38213cb3567dSMichael Tuexen 		    error, so_locked);
3822f8829a4aSRandall Stewart 		break;
3823f8829a4aSRandall Stewart 	case SCTP_NOTIFY_PEER_SHUTDOWN:
3824f8829a4aSRandall Stewart 		sctp_notify_shutdown_event(stcb);
3825f8829a4aSRandall Stewart 		break;
3826f8829a4aSRandall Stewart 	case SCTP_NOTIFY_AUTH_NEW_KEY:
382778f28045SMichael Tuexen 		sctp_notify_authentication(stcb, SCTP_AUTH_NEW_KEY, error,
3828830d754dSRandall Stewart 		    (uint16_t)(uintptr_t)data,
3829830d754dSRandall Stewart 		    so_locked);
3830f8829a4aSRandall Stewart 		break;
3831830d754dSRandall Stewart 	case SCTP_NOTIFY_AUTH_FREE_KEY:
3832830d754dSRandall Stewart 		sctp_notify_authentication(stcb, SCTP_AUTH_FREE_KEY, error,
3833830d754dSRandall Stewart 		    (uint16_t)(uintptr_t)data,
3834830d754dSRandall Stewart 		    so_locked);
3835f8829a4aSRandall Stewart 		break;
3836830d754dSRandall Stewart 	case SCTP_NOTIFY_NO_PEER_AUTH:
3837830d754dSRandall Stewart 		sctp_notify_authentication(stcb, SCTP_AUTH_NO_AUTH, error,
3838830d754dSRandall Stewart 		    (uint16_t)(uintptr_t)data,
3839830d754dSRandall Stewart 		    so_locked);
3840830d754dSRandall Stewart 		break;
3841830d754dSRandall Stewart 	case SCTP_NOTIFY_SENDER_DRY:
3842830d754dSRandall Stewart 		sctp_notify_sender_dry_event(stcb, so_locked);
3843830d754dSRandall Stewart 		break;
3844389b1b11SMichael Tuexen 	case SCTP_NOTIFY_REMOTE_ERROR:
3845389b1b11SMichael Tuexen 		sctp_notify_remote_error(stcb, error, data);
3846389b1b11SMichael Tuexen 		break;
3847f8829a4aSRandall Stewart 	default:
3848ad81507eSRandall Stewart 		SCTPDBG(SCTP_DEBUG_UTIL1, "%s: unknown notification %xh (%u)\n",
38496e9c45e0SMichael Tuexen 		    __func__, notification, notification);
3850f8829a4aSRandall Stewart 		break;
3851f8829a4aSRandall Stewart 	}			/* end switch */
3852f8829a4aSRandall Stewart }
3853f8829a4aSRandall Stewart 
3854f8829a4aSRandall Stewart void
38551edc9dbaSMichael Tuexen sctp_report_all_outbound(struct sctp_tcb *stcb, uint16_t error, int holds_lock, int so_locked
3856ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
3857ceaad40aSRandall Stewart     SCTP_UNUSED
3858ceaad40aSRandall Stewart #endif
3859ceaad40aSRandall Stewart )
3860f8829a4aSRandall Stewart {
3861f8829a4aSRandall Stewart 	struct sctp_association *asoc;
3862f8829a4aSRandall Stewart 	struct sctp_stream_out *outs;
38634a9ef3f8SMichael Tuexen 	struct sctp_tmit_chunk *chk, *nchk;
38644a9ef3f8SMichael Tuexen 	struct sctp_stream_queue_pending *sp, *nsp;
38657f34832bSRandall Stewart 	int i;
3866f8829a4aSRandall Stewart 
3867ad81507eSRandall Stewart 	if (stcb == NULL) {
3868ad81507eSRandall Stewart 		return;
3869ad81507eSRandall Stewart 	}
38704a9ef3f8SMichael Tuexen 	asoc = &stcb->asoc;
38714a9ef3f8SMichael Tuexen 	if (asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) {
3872478fbccbSRandall Stewart 		/* already being freed */
3873478fbccbSRandall Stewart 		return;
3874478fbccbSRandall Stewart 	}
3875f8829a4aSRandall Stewart 	if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
3876f8829a4aSRandall Stewart 	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
38774a9ef3f8SMichael Tuexen 	    (asoc->state & SCTP_STATE_CLOSED_SOCKET)) {
3878f8829a4aSRandall Stewart 		return;
3879f8829a4aSRandall Stewart 	}
3880f8829a4aSRandall Stewart 	/* now through all the gunk freeing chunks */
3881ad81507eSRandall Stewart 	if (holds_lock == 0) {
38827f34832bSRandall Stewart 		SCTP_TCB_SEND_LOCK(stcb);
3883ad81507eSRandall Stewart 	}
3884d00aff5dSRandall Stewart 	/* sent queue SHOULD be empty */
38854a9ef3f8SMichael Tuexen 	TAILQ_FOREACH_SAFE(chk, &asoc->sent_queue, sctp_next, nchk) {
3886d00aff5dSRandall Stewart 		TAILQ_REMOVE(&asoc->sent_queue, chk, sctp_next);
3887d00aff5dSRandall Stewart 		asoc->sent_queue_cnt--;
3888325c8c46SMichael Tuexen 		if (chk->sent != SCTP_DATAGRAM_NR_ACKED) {
388949656eefSMichael Tuexen 			if (asoc->strmout[chk->rec.data.sid].chunks_on_queues > 0) {
389049656eefSMichael Tuexen 				asoc->strmout[chk->rec.data.sid].chunks_on_queues--;
3891a7ad6026SMichael Tuexen #ifdef INVARIANTS
3892a7ad6026SMichael Tuexen 			} else {
389349656eefSMichael Tuexen 				panic("No chunks on the queues for sid %u.", chk->rec.data.sid);
3894a7ad6026SMichael Tuexen #endif
3895a7ad6026SMichael Tuexen 			}
3896a7ad6026SMichael Tuexen 		}
38970c0982b8SRandall Stewart 		if (chk->data != NULL) {
3898d00aff5dSRandall Stewart 			sctp_free_bufspace(stcb, asoc, chk, 1);
38991edc9dbaSMichael Tuexen 			sctp_ulp_notify(SCTP_NOTIFY_SENT_DG_FAIL, stcb,
39001edc9dbaSMichael Tuexen 			    error, chk, so_locked);
3901810ec536SMichael Tuexen 			if (chk->data) {
3902d00aff5dSRandall Stewart 				sctp_m_freem(chk->data);
3903d00aff5dSRandall Stewart 				chk->data = NULL;
3904d00aff5dSRandall Stewart 			}
3905810ec536SMichael Tuexen 		}
3906689e6a5fSMichael Tuexen 		sctp_free_a_chunk(stcb, chk, so_locked);
3907d00aff5dSRandall Stewart 		/* sa_ignore FREED_MEMORY */
3908d00aff5dSRandall Stewart 	}
3909d00aff5dSRandall Stewart 	/* pending send queue SHOULD be empty */
39104a9ef3f8SMichael Tuexen 	TAILQ_FOREACH_SAFE(chk, &asoc->send_queue, sctp_next, nchk) {
3911d00aff5dSRandall Stewart 		TAILQ_REMOVE(&asoc->send_queue, chk, sctp_next);
3912d00aff5dSRandall Stewart 		asoc->send_queue_cnt--;
391349656eefSMichael Tuexen 		if (asoc->strmout[chk->rec.data.sid].chunks_on_queues > 0) {
391449656eefSMichael Tuexen 			asoc->strmout[chk->rec.data.sid].chunks_on_queues--;
3915a7ad6026SMichael Tuexen #ifdef INVARIANTS
3916a7ad6026SMichael Tuexen 		} else {
391749656eefSMichael Tuexen 			panic("No chunks on the queues for sid %u.", chk->rec.data.sid);
3918a7ad6026SMichael Tuexen #endif
3919a7ad6026SMichael Tuexen 		}
39200c0982b8SRandall Stewart 		if (chk->data != NULL) {
3921d00aff5dSRandall Stewart 			sctp_free_bufspace(stcb, asoc, chk, 1);
39221edc9dbaSMichael Tuexen 			sctp_ulp_notify(SCTP_NOTIFY_UNSENT_DG_FAIL, stcb,
39231edc9dbaSMichael Tuexen 			    error, chk, so_locked);
3924810ec536SMichael Tuexen 			if (chk->data) {
3925d00aff5dSRandall Stewart 				sctp_m_freem(chk->data);
3926d00aff5dSRandall Stewart 				chk->data = NULL;
3927d00aff5dSRandall Stewart 			}
3928810ec536SMichael Tuexen 		}
3929689e6a5fSMichael Tuexen 		sctp_free_a_chunk(stcb, chk, so_locked);
3930d00aff5dSRandall Stewart 		/* sa_ignore FREED_MEMORY */
3931d00aff5dSRandall Stewart 	}
39324a9ef3f8SMichael Tuexen 	for (i = 0; i < asoc->streamoutcnt; i++) {
39337f34832bSRandall Stewart 		/* For each stream */
39344a9ef3f8SMichael Tuexen 		outs = &asoc->strmout[i];
39357f34832bSRandall Stewart 		/* clean up any sends there */
39364a9ef3f8SMichael Tuexen 		TAILQ_FOREACH_SAFE(sp, &outs->outqueue, next, nsp) {
39374d58b0c3SMichael Tuexen 			atomic_subtract_int(&asoc->stream_queue_cnt, 1);
3938f8829a4aSRandall Stewart 			TAILQ_REMOVE(&outs->outqueue, sp, next);
39394d58b0c3SMichael Tuexen 			stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, outs, sp, holds_lock);
3940f8829a4aSRandall Stewart 			sctp_free_spbufspace(stcb, asoc, sp);
3941478fbccbSRandall Stewart 			if (sp->data) {
3942f8829a4aSRandall Stewart 				sctp_ulp_notify(SCTP_NOTIFY_SPECIAL_SP_FAIL, stcb,
39431edc9dbaSMichael Tuexen 				    error, (void *)sp, so_locked);
3944f8829a4aSRandall Stewart 				if (sp->data) {
3945f8829a4aSRandall Stewart 					sctp_m_freem(sp->data);
3946f8829a4aSRandall Stewart 					sp->data = NULL;
3947d07b2ac6SMichael Tuexen 					sp->tail_mbuf = NULL;
3948d07b2ac6SMichael Tuexen 					sp->length = 0;
3949f8829a4aSRandall Stewart 				}
3950478fbccbSRandall Stewart 			}
39519eea4a2dSMichael Tuexen 			if (sp->net) {
3952f8829a4aSRandall Stewart 				sctp_free_remote_addr(sp->net);
3953f8829a4aSRandall Stewart 				sp->net = NULL;
39549eea4a2dSMichael Tuexen 			}
3955f8829a4aSRandall Stewart 			/* Free the chunk */
3956689e6a5fSMichael Tuexen 			sctp_free_a_strmoq(stcb, sp, so_locked);
39573c503c28SRandall Stewart 			/* sa_ignore FREED_MEMORY */
3958f8829a4aSRandall Stewart 		}
3959f8829a4aSRandall Stewart 	}
3960f8829a4aSRandall Stewart 
3961ad81507eSRandall Stewart 	if (holds_lock == 0) {
39627f34832bSRandall Stewart 		SCTP_TCB_SEND_UNLOCK(stcb);
3963f8829a4aSRandall Stewart 	}
3964ad81507eSRandall Stewart }
3965f8829a4aSRandall Stewart 
3966f8829a4aSRandall Stewart void
3967410a3b1eSMichael Tuexen sctp_abort_notification(struct sctp_tcb *stcb, uint8_t from_peer, uint16_t error,
3968a2b42326SMichael Tuexen     struct sctp_abort_chunk *abort, int so_locked
3969ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
3970ceaad40aSRandall Stewart     SCTP_UNUSED
3971ceaad40aSRandall Stewart #endif
3972ceaad40aSRandall Stewart )
3973f8829a4aSRandall Stewart {
3974ad81507eSRandall Stewart 	if (stcb == NULL) {
3975ad81507eSRandall Stewart 		return;
3976ad81507eSRandall Stewart 	}
3977c55b70ceSMichael Tuexen 	if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3978c55b70ceSMichael Tuexen 	    ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
3979c55b70ceSMichael Tuexen 	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED))) {
3980c55b70ceSMichael Tuexen 		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_WAS_ABORTED;
3981c55b70ceSMichael Tuexen 	}
3982f8829a4aSRandall Stewart 	if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
3983f8829a4aSRandall Stewart 	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
3984f8829a4aSRandall Stewart 	    (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) {
3985f8829a4aSRandall Stewart 		return;
3986f8829a4aSRandall Stewart 	}
3987f8829a4aSRandall Stewart 	/* Tell them we lost the asoc */
39881edc9dbaSMichael Tuexen 	sctp_report_all_outbound(stcb, error, 1, so_locked);
3989410a3b1eSMichael Tuexen 	if (from_peer) {
3990410a3b1eSMichael Tuexen 		sctp_ulp_notify(SCTP_NOTIFY_ASSOC_REM_ABORTED, stcb, error, abort, so_locked);
3991410a3b1eSMichael Tuexen 	} else {
3992410a3b1eSMichael Tuexen 		sctp_ulp_notify(SCTP_NOTIFY_ASSOC_LOC_ABORTED, stcb, error, abort, so_locked);
3993410a3b1eSMichael Tuexen 	}
3994f8829a4aSRandall Stewart }
3995f8829a4aSRandall Stewart 
3996f8829a4aSRandall Stewart void
3997f8829a4aSRandall Stewart sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
3998b1754ad1SMichael Tuexen     struct mbuf *m, int iphlen,
3999b1754ad1SMichael Tuexen     struct sockaddr *src, struct sockaddr *dst,
4000b1754ad1SMichael Tuexen     struct sctphdr *sh, struct mbuf *op_err,
4001457b4b88SMichael Tuexen     uint8_t mflowtype, uint32_t mflowid,
4002c54a18d2SRandall Stewart     uint32_t vrf_id, uint16_t port)
4003f8829a4aSRandall Stewart {
4004f8829a4aSRandall Stewart 	uint32_t vtag;
4005ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
4006ceaad40aSRandall Stewart 	struct socket *so;
4007ceaad40aSRandall Stewart #endif
4008ceaad40aSRandall Stewart 
4009f8829a4aSRandall Stewart 	vtag = 0;
4010f8829a4aSRandall Stewart 	if (stcb != NULL) {
4011f8829a4aSRandall Stewart 		vtag = stcb->asoc.peer_vtag;
401217205eccSRandall Stewart 		vrf_id = stcb->asoc.vrf_id;
4013f8829a4aSRandall Stewart 	}
4014b1754ad1SMichael Tuexen 	sctp_send_abort(m, iphlen, src, dst, sh, vtag, op_err,
4015d089f9b9SMichael Tuexen 	    mflowtype, mflowid, inp->fibnum,
4016f30ac432SMichael Tuexen 	    vrf_id, port);
4017f8829a4aSRandall Stewart 	if (stcb != NULL) {
4018884d8c53SMichael Tuexen 		/* We have a TCB to abort, send notification too */
4019884d8c53SMichael Tuexen 		sctp_abort_notification(stcb, 0, 0, NULL, SCTP_SO_NOT_LOCKED);
4020884d8c53SMichael Tuexen 		stcb->asoc.state |= SCTP_STATE_WAS_ABORTED;
4021f8829a4aSRandall Stewart 		/* Ok, now lets free it */
4022ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
4023ceaad40aSRandall Stewart 		so = SCTP_INP_SO(inp);
4024ceaad40aSRandall Stewart 		atomic_add_int(&stcb->asoc.refcnt, 1);
4025ceaad40aSRandall Stewart 		SCTP_TCB_UNLOCK(stcb);
4026ceaad40aSRandall Stewart 		SCTP_SOCKET_LOCK(so, 1);
4027ceaad40aSRandall Stewart 		SCTP_TCB_LOCK(stcb);
4028ceaad40aSRandall Stewart 		atomic_subtract_int(&stcb->asoc.refcnt, 1);
4029ceaad40aSRandall Stewart #endif
40300271d0cdSMichael Tuexen 		SCTP_STAT_INCR_COUNTER32(sctps_aborted);
40310271d0cdSMichael Tuexen 		if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
40320271d0cdSMichael Tuexen 		    (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
40330271d0cdSMichael Tuexen 			SCTP_STAT_DECR_GAUGE32(sctps_currestab);
40340271d0cdSMichael Tuexen 		}
4035ba785902SMichael Tuexen 		(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
4036ba785902SMichael Tuexen 		    SCTP_FROM_SCTPUTIL + SCTP_LOC_4);
4037ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
4038ceaad40aSRandall Stewart 		SCTP_SOCKET_UNLOCK(so, 1);
4039ceaad40aSRandall Stewart #endif
4040f8829a4aSRandall Stewart 	}
4041f8829a4aSRandall Stewart }
4042f1f73e57SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS
4043f1f73e57SRandall Stewart void
4044f1f73e57SRandall Stewart sctp_print_out_track_log(struct sctp_tcb *stcb)
4045f1f73e57SRandall Stewart {
404618e198d3SRandall Stewart #ifdef NOSIY_PRINTS
4047f1f73e57SRandall Stewart 	int i;
4048f1f73e57SRandall Stewart 
4049ad81507eSRandall Stewart 	SCTP_PRINTF("Last ep reason:%x\n", stcb->sctp_ep->last_abort_code);
4050ad81507eSRandall Stewart 	SCTP_PRINTF("IN bound TSN log-aaa\n");
4051f1f73e57SRandall Stewart 	if ((stcb->asoc.tsn_in_at == 0) && (stcb->asoc.tsn_in_wrapped == 0)) {
4052ad81507eSRandall Stewart 		SCTP_PRINTF("None rcvd\n");
4053f1f73e57SRandall Stewart 		goto none_in;
4054f1f73e57SRandall Stewart 	}
4055f1f73e57SRandall Stewart 	if (stcb->asoc.tsn_in_wrapped) {
4056f1f73e57SRandall Stewart 		for (i = stcb->asoc.tsn_in_at; i < SCTP_TSN_LOG_SIZE; i++) {
4057ad81507eSRandall Stewart 			SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n",
4058f1f73e57SRandall Stewart 			    stcb->asoc.in_tsnlog[i].tsn,
4059f1f73e57SRandall Stewart 			    stcb->asoc.in_tsnlog[i].strm,
4060f1f73e57SRandall Stewart 			    stcb->asoc.in_tsnlog[i].seq,
4061f1f73e57SRandall Stewart 			    stcb->asoc.in_tsnlog[i].flgs,
4062f1f73e57SRandall Stewart 			    stcb->asoc.in_tsnlog[i].sz);
4063f1f73e57SRandall Stewart 		}
4064f1f73e57SRandall Stewart 	}
4065f1f73e57SRandall Stewart 	if (stcb->asoc.tsn_in_at) {
4066f1f73e57SRandall Stewart 		for (i = 0; i < stcb->asoc.tsn_in_at; i++) {
4067ad81507eSRandall Stewart 			SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n",
4068f1f73e57SRandall Stewart 			    stcb->asoc.in_tsnlog[i].tsn,
4069f1f73e57SRandall Stewart 			    stcb->asoc.in_tsnlog[i].strm,
4070f1f73e57SRandall Stewart 			    stcb->asoc.in_tsnlog[i].seq,
4071f1f73e57SRandall Stewart 			    stcb->asoc.in_tsnlog[i].flgs,
4072f1f73e57SRandall Stewart 			    stcb->asoc.in_tsnlog[i].sz);
4073f1f73e57SRandall Stewart 		}
4074f1f73e57SRandall Stewart 	}
4075f1f73e57SRandall Stewart none_in:
4076ad81507eSRandall Stewart 	SCTP_PRINTF("OUT bound TSN log-aaa\n");
4077ad81507eSRandall Stewart 	if ((stcb->asoc.tsn_out_at == 0) &&
4078ad81507eSRandall Stewart 	    (stcb->asoc.tsn_out_wrapped == 0)) {
4079ad81507eSRandall Stewart 		SCTP_PRINTF("None sent\n");
4080f1f73e57SRandall Stewart 	}
4081f1f73e57SRandall Stewart 	if (stcb->asoc.tsn_out_wrapped) {
4082f1f73e57SRandall Stewart 		for (i = stcb->asoc.tsn_out_at; i < SCTP_TSN_LOG_SIZE; i++) {
4083ad81507eSRandall Stewart 			SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n",
4084f1f73e57SRandall Stewart 			    stcb->asoc.out_tsnlog[i].tsn,
4085f1f73e57SRandall Stewart 			    stcb->asoc.out_tsnlog[i].strm,
4086f1f73e57SRandall Stewart 			    stcb->asoc.out_tsnlog[i].seq,
4087f1f73e57SRandall Stewart 			    stcb->asoc.out_tsnlog[i].flgs,
4088f1f73e57SRandall Stewart 			    stcb->asoc.out_tsnlog[i].sz);
4089f1f73e57SRandall Stewart 		}
4090f1f73e57SRandall Stewart 	}
4091f1f73e57SRandall Stewart 	if (stcb->asoc.tsn_out_at) {
4092f1f73e57SRandall Stewart 		for (i = 0; i < stcb->asoc.tsn_out_at; i++) {
4093ad81507eSRandall Stewart 			SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n",
4094f1f73e57SRandall Stewart 			    stcb->asoc.out_tsnlog[i].tsn,
4095f1f73e57SRandall Stewart 			    stcb->asoc.out_tsnlog[i].strm,
4096f1f73e57SRandall Stewart 			    stcb->asoc.out_tsnlog[i].seq,
4097f1f73e57SRandall Stewart 			    stcb->asoc.out_tsnlog[i].flgs,
4098f1f73e57SRandall Stewart 			    stcb->asoc.out_tsnlog[i].sz);
4099f1f73e57SRandall Stewart 		}
4100f1f73e57SRandall Stewart 	}
410118e198d3SRandall Stewart #endif
4102f1f73e57SRandall Stewart }
4103f1f73e57SRandall Stewart #endif
4104f1f73e57SRandall Stewart 
4105f8829a4aSRandall Stewart void
4106f8829a4aSRandall Stewart sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
4107a2b42326SMichael Tuexen     struct mbuf *op_err,
4108ceaad40aSRandall Stewart     int so_locked
4109ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
4110ceaad40aSRandall Stewart     SCTP_UNUSED
4111ceaad40aSRandall Stewart #endif
4112ceaad40aSRandall Stewart )
4113f8829a4aSRandall Stewart {
4114ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
4115ceaad40aSRandall Stewart 	struct socket *so;
4116ceaad40aSRandall Stewart #endif
4117ceaad40aSRandall Stewart 
4118ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
4119ceaad40aSRandall Stewart 	so = SCTP_INP_SO(inp);
4120ceaad40aSRandall Stewart #endif
4121f8829a4aSRandall Stewart 	if (stcb == NULL) {
4122f8829a4aSRandall Stewart 		/* Got to have a TCB */
4123f8829a4aSRandall Stewart 		if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
4124fe1831e0SMichael Tuexen 			if (LIST_EMPTY(&inp->sctp_asoc_list)) {
4125b0552ae2SRandall Stewart 				sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
4126b0552ae2SRandall Stewart 				    SCTP_CALLED_DIRECTLY_NOCMPSET);
4127f8829a4aSRandall Stewart 			}
4128f8829a4aSRandall Stewart 		}
4129f8829a4aSRandall Stewart 		return;
413063981c2bSRandall Stewart 	} else {
413163981c2bSRandall Stewart 		stcb->asoc.state |= SCTP_STATE_WAS_ABORTED;
4132f8829a4aSRandall Stewart 	}
4133f8829a4aSRandall Stewart 	/* notify the peer */
4134ceaad40aSRandall Stewart 	sctp_send_abort_tcb(stcb, op_err, so_locked);
4135f8829a4aSRandall Stewart 	SCTP_STAT_INCR_COUNTER32(sctps_aborted);
4136f8829a4aSRandall Stewart 	if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
4137f8829a4aSRandall Stewart 	    (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
4138f8829a4aSRandall Stewart 		SCTP_STAT_DECR_GAUGE32(sctps_currestab);
4139f8829a4aSRandall Stewart 	}
4140884d8c53SMichael Tuexen 	/* notify the ulp */
4141884d8c53SMichael Tuexen 	if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
4142884d8c53SMichael Tuexen 		sctp_abort_notification(stcb, 0, 0, NULL, so_locked);
4143884d8c53SMichael Tuexen 	}
4144f8829a4aSRandall Stewart 	/* now free the asoc */
4145f1f73e57SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS
4146f1f73e57SRandall Stewart 	sctp_print_out_track_log(stcb);
4147f1f73e57SRandall Stewart #endif
4148ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
4149ceaad40aSRandall Stewart 	if (!so_locked) {
4150ceaad40aSRandall Stewart 		atomic_add_int(&stcb->asoc.refcnt, 1);
4151ceaad40aSRandall Stewart 		SCTP_TCB_UNLOCK(stcb);
4152ceaad40aSRandall Stewart 		SCTP_SOCKET_LOCK(so, 1);
4153ceaad40aSRandall Stewart 		SCTP_TCB_LOCK(stcb);
4154ceaad40aSRandall Stewart 		atomic_subtract_int(&stcb->asoc.refcnt, 1);
4155ceaad40aSRandall Stewart 	}
4156ceaad40aSRandall Stewart #endif
4157ba785902SMichael Tuexen 	(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
4158ba785902SMichael Tuexen 	    SCTP_FROM_SCTPUTIL + SCTP_LOC_5);
4159ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
4160ceaad40aSRandall Stewart 	if (!so_locked) {
4161ceaad40aSRandall Stewart 		SCTP_SOCKET_UNLOCK(so, 1);
4162ceaad40aSRandall Stewart 	}
4163ceaad40aSRandall Stewart #endif
4164f8829a4aSRandall Stewart }
4165f8829a4aSRandall Stewart 
4166f8829a4aSRandall Stewart void
4167b1754ad1SMichael Tuexen sctp_handle_ootb(struct mbuf *m, int iphlen, int offset,
4168b1754ad1SMichael Tuexen     struct sockaddr *src, struct sockaddr *dst,
4169b1754ad1SMichael Tuexen     struct sctphdr *sh, struct sctp_inpcb *inp,
4170ff1ffd74SMichael Tuexen     struct mbuf *cause,
4171d089f9b9SMichael Tuexen     uint8_t mflowtype, uint32_t mflowid, uint16_t fibnum,
4172f30ac432SMichael Tuexen     uint32_t vrf_id, uint16_t port)
4173f8829a4aSRandall Stewart {
4174f8829a4aSRandall Stewart 	struct sctp_chunkhdr *ch, chunk_buf;
4175f8829a4aSRandall Stewart 	unsigned int chk_length;
4176c58e60beSMichael Tuexen 	int contains_init_chunk;
4177f8829a4aSRandall Stewart 
4178f8829a4aSRandall Stewart 	SCTP_STAT_INCR_COUNTER32(sctps_outoftheblue);
4179f8829a4aSRandall Stewart 	/* Generate a TO address for future reference */
4180f8829a4aSRandall Stewart 	if (inp && (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
4181fe1831e0SMichael Tuexen 		if (LIST_EMPTY(&inp->sctp_asoc_list)) {
4182b0552ae2SRandall Stewart 			sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
4183b0552ae2SRandall Stewart 			    SCTP_CALLED_DIRECTLY_NOCMPSET);
4184f8829a4aSRandall Stewart 		}
4185f8829a4aSRandall Stewart 	}
4186c58e60beSMichael Tuexen 	contains_init_chunk = 0;
4187f8829a4aSRandall Stewart 	ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset,
4188f8829a4aSRandall Stewart 	    sizeof(*ch), (uint8_t *)&chunk_buf);
4189f8829a4aSRandall Stewart 	while (ch != NULL) {
4190f8829a4aSRandall Stewart 		chk_length = ntohs(ch->chunk_length);
4191f8829a4aSRandall Stewart 		if (chk_length < sizeof(*ch)) {
4192f8829a4aSRandall Stewart 			/* break to abort land */
4193f8829a4aSRandall Stewart 			break;
4194f8829a4aSRandall Stewart 		}
4195f8829a4aSRandall Stewart 		switch (ch->chunk_type) {
4196c58e60beSMichael Tuexen 		case SCTP_INIT:
4197c58e60beSMichael Tuexen 			contains_init_chunk = 1;
4198c58e60beSMichael Tuexen 			break;
4199f8829a4aSRandall Stewart 		case SCTP_PACKET_DROPPED:
4200f8829a4aSRandall Stewart 			/* we don't respond to pkt-dropped */
4201f8829a4aSRandall Stewart 			return;
4202f8829a4aSRandall Stewart 		case SCTP_ABORT_ASSOCIATION:
4203f8829a4aSRandall Stewart 			/* we don't respond with an ABORT to an ABORT */
4204f8829a4aSRandall Stewart 			return;
4205f8829a4aSRandall Stewart 		case SCTP_SHUTDOWN_COMPLETE:
4206f8829a4aSRandall Stewart 			/*
4207f8829a4aSRandall Stewart 			 * we ignore it since we are not waiting for it and
4208f8829a4aSRandall Stewart 			 * peer is gone
4209f8829a4aSRandall Stewart 			 */
4210f8829a4aSRandall Stewart 			return;
4211f8829a4aSRandall Stewart 		case SCTP_SHUTDOWN_ACK:
4212b1754ad1SMichael Tuexen 			sctp_send_shutdown_complete2(src, dst, sh,
4213d089f9b9SMichael Tuexen 			    mflowtype, mflowid, fibnum,
4214f30ac432SMichael Tuexen 			    vrf_id, port);
4215f8829a4aSRandall Stewart 			return;
4216f8829a4aSRandall Stewart 		default:
4217f8829a4aSRandall Stewart 			break;
4218f8829a4aSRandall Stewart 		}
4219f8829a4aSRandall Stewart 		offset += SCTP_SIZE32(chk_length);
4220f8829a4aSRandall Stewart 		ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset,
4221f8829a4aSRandall Stewart 		    sizeof(*ch), (uint8_t *)&chunk_buf);
4222f8829a4aSRandall Stewart 	}
4223c58e60beSMichael Tuexen 	if ((SCTP_BASE_SYSCTL(sctp_blackhole) == 0) ||
4224c58e60beSMichael Tuexen 	    ((SCTP_BASE_SYSCTL(sctp_blackhole) == 1) &&
4225c58e60beSMichael Tuexen 	    (contains_init_chunk == 0))) {
4226ff1ffd74SMichael Tuexen 		sctp_send_abort(m, iphlen, src, dst, sh, 0, cause,
4227d089f9b9SMichael Tuexen 		    mflowtype, mflowid, fibnum,
4228f30ac432SMichael Tuexen 		    vrf_id, port);
4229f8829a4aSRandall Stewart 	}
4230c58e60beSMichael Tuexen }
4231f8829a4aSRandall Stewart 
4232f8829a4aSRandall Stewart /*
4233f8829a4aSRandall Stewart  * check the inbound datagram to make sure there is not an abort inside it,
4234f8829a4aSRandall Stewart  * if there is return 1, else return 0.
4235f8829a4aSRandall Stewart  */
4236f8829a4aSRandall Stewart int
4237f8829a4aSRandall Stewart sctp_is_there_an_abort_here(struct mbuf *m, int iphlen, uint32_t *vtagfill)
4238f8829a4aSRandall Stewart {
4239f8829a4aSRandall Stewart 	struct sctp_chunkhdr *ch;
4240f8829a4aSRandall Stewart 	struct sctp_init_chunk *init_chk, chunk_buf;
4241f8829a4aSRandall Stewart 	int offset;
4242f8829a4aSRandall Stewart 	unsigned int chk_length;
4243f8829a4aSRandall Stewart 
4244f8829a4aSRandall Stewart 	offset = iphlen + sizeof(struct sctphdr);
4245f8829a4aSRandall Stewart 	ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, sizeof(*ch),
4246f8829a4aSRandall Stewart 	    (uint8_t *)&chunk_buf);
4247f8829a4aSRandall Stewart 	while (ch != NULL) {
4248f8829a4aSRandall Stewart 		chk_length = ntohs(ch->chunk_length);
4249f8829a4aSRandall Stewart 		if (chk_length < sizeof(*ch)) {
4250f8829a4aSRandall Stewart 			/* packet is probably corrupt */
4251f8829a4aSRandall Stewart 			break;
4252f8829a4aSRandall Stewart 		}
4253f8829a4aSRandall Stewart 		/* we seem to be ok, is it an abort? */
4254f8829a4aSRandall Stewart 		if (ch->chunk_type == SCTP_ABORT_ASSOCIATION) {
4255f8829a4aSRandall Stewart 			/* yep, tell them */
4256f8829a4aSRandall Stewart 			return (1);
4257f8829a4aSRandall Stewart 		}
4258f8829a4aSRandall Stewart 		if (ch->chunk_type == SCTP_INITIATION) {
4259f8829a4aSRandall Stewart 			/* need to update the Vtag */
4260f8829a4aSRandall Stewart 			init_chk = (struct sctp_init_chunk *)sctp_m_getptr(m,
4261f8829a4aSRandall Stewart 			    offset, sizeof(*init_chk), (uint8_t *)&chunk_buf);
4262f8829a4aSRandall Stewart 			if (init_chk != NULL) {
4263f8829a4aSRandall Stewart 				*vtagfill = ntohl(init_chk->init.initiate_tag);
4264f8829a4aSRandall Stewart 			}
4265f8829a4aSRandall Stewart 		}
4266f8829a4aSRandall Stewart 		/* Nope, move to the next chunk */
4267f8829a4aSRandall Stewart 		offset += SCTP_SIZE32(chk_length);
4268f8829a4aSRandall Stewart 		ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset,
4269f8829a4aSRandall Stewart 		    sizeof(*ch), (uint8_t *)&chunk_buf);
4270f8829a4aSRandall Stewart 	}
4271f8829a4aSRandall Stewart 	return (0);
4272f8829a4aSRandall Stewart }
4273f8829a4aSRandall Stewart 
4274f8829a4aSRandall Stewart /*
4275f8829a4aSRandall Stewart  * currently (2/02), ifa_addr embeds scope_id's and don't have sin6_scope_id
4276f8829a4aSRandall Stewart  * set (i.e. it's 0) so, create this function to compare link local scopes
4277f8829a4aSRandall Stewart  */
42785e2c2d87SRandall Stewart #ifdef INET6
4279f8829a4aSRandall Stewart uint32_t
4280*b0471b4bSMichael Tuexen sctp_is_same_scope(struct sockaddr_in6 *addr1, struct sockaddr_in6 *addr2)
4281*b0471b4bSMichael Tuexen {
4282f8829a4aSRandall Stewart 	struct sockaddr_in6 a, b;
4283f8829a4aSRandall Stewart 
4284f8829a4aSRandall Stewart 	/* save copies */
4285f8829a4aSRandall Stewart 	a = *addr1;
4286f8829a4aSRandall Stewart 	b = *addr2;
4287f8829a4aSRandall Stewart 
4288f8829a4aSRandall Stewart 	if (a.sin6_scope_id == 0)
4289f8829a4aSRandall Stewart 		if (sa6_recoverscope(&a)) {
4290f8829a4aSRandall Stewart 			/* can't get scope, so can't match */
4291f8829a4aSRandall Stewart 			return (0);
4292f8829a4aSRandall Stewart 		}
4293f8829a4aSRandall Stewart 	if (b.sin6_scope_id == 0)
4294f8829a4aSRandall Stewart 		if (sa6_recoverscope(&b)) {
4295f8829a4aSRandall Stewart 			/* can't get scope, so can't match */
4296f8829a4aSRandall Stewart 			return (0);
4297f8829a4aSRandall Stewart 		}
4298f8829a4aSRandall Stewart 	if (a.sin6_scope_id != b.sin6_scope_id)
4299f8829a4aSRandall Stewart 		return (0);
4300f8829a4aSRandall Stewart 
4301f8829a4aSRandall Stewart 	return (1);
4302f8829a4aSRandall Stewart }
4303f8829a4aSRandall Stewart 
4304f8829a4aSRandall Stewart /*
4305f8829a4aSRandall Stewart  * returns a sockaddr_in6 with embedded scope recovered and removed
4306f8829a4aSRandall Stewart  */
4307f8829a4aSRandall Stewart struct sockaddr_in6 *
4308f8829a4aSRandall Stewart sctp_recover_scope(struct sockaddr_in6 *addr, struct sockaddr_in6 *store)
4309f8829a4aSRandall Stewart {
4310f8829a4aSRandall Stewart 	/* check and strip embedded scope junk */
4311f8829a4aSRandall Stewart 	if (addr->sin6_family == AF_INET6) {
4312f8829a4aSRandall Stewart 		if (IN6_IS_SCOPE_LINKLOCAL(&addr->sin6_addr)) {
4313f8829a4aSRandall Stewart 			if (addr->sin6_scope_id == 0) {
4314f8829a4aSRandall Stewart 				*store = *addr;
4315f8829a4aSRandall Stewart 				if (!sa6_recoverscope(store)) {
4316f8829a4aSRandall Stewart 					/* use the recovered scope */
4317f8829a4aSRandall Stewart 					addr = store;
4318f8829a4aSRandall Stewart 				}
4319f42a358aSRandall Stewart 			} else {
4320f8829a4aSRandall Stewart 				/* else, return the original "to" addr */
4321f42a358aSRandall Stewart 				in6_clearscope(&addr->sin6_addr);
4322f8829a4aSRandall Stewart 			}
4323f8829a4aSRandall Stewart 		}
4324f8829a4aSRandall Stewart 	}
4325f8829a4aSRandall Stewart 	return (addr);
4326f8829a4aSRandall Stewart }
43275e2c2d87SRandall Stewart #endif
43285e2c2d87SRandall Stewart 
4329f8829a4aSRandall Stewart /*
4330f8829a4aSRandall Stewart  * are the two addresses the same?  currently a "scopeless" check returns: 1
4331f8829a4aSRandall Stewart  * if same, 0 if not
4332f8829a4aSRandall Stewart  */
433372fb6fdbSRandall Stewart int
4334f8829a4aSRandall Stewart sctp_cmpaddr(struct sockaddr *sa1, struct sockaddr *sa2)
4335f8829a4aSRandall Stewart {
4336f8829a4aSRandall Stewart 
4337f8829a4aSRandall Stewart 	/* must be valid */
4338f8829a4aSRandall Stewart 	if (sa1 == NULL || sa2 == NULL)
4339f8829a4aSRandall Stewart 		return (0);
4340f8829a4aSRandall Stewart 
4341f8829a4aSRandall Stewart 	/* must be the same family */
4342f8829a4aSRandall Stewart 	if (sa1->sa_family != sa2->sa_family)
4343f8829a4aSRandall Stewart 		return (0);
4344f8829a4aSRandall Stewart 
43455e2c2d87SRandall Stewart 	switch (sa1->sa_family) {
43465e2c2d87SRandall Stewart #ifdef INET6
43475e2c2d87SRandall Stewart 	case AF_INET6:
43485e2c2d87SRandall Stewart 		{
4349f8829a4aSRandall Stewart 			/* IPv6 addresses */
4350f8829a4aSRandall Stewart 			struct sockaddr_in6 *sin6_1, *sin6_2;
4351f8829a4aSRandall Stewart 
4352f8829a4aSRandall Stewart 			sin6_1 = (struct sockaddr_in6 *)sa1;
4353f8829a4aSRandall Stewart 			sin6_2 = (struct sockaddr_in6 *)sa2;
4354c54a18d2SRandall Stewart 			return (SCTP6_ARE_ADDR_EQUAL(sin6_1,
4355c54a18d2SRandall Stewart 			    sin6_2));
43565e2c2d87SRandall Stewart 		}
43575e2c2d87SRandall Stewart #endif
4358ea5eba11SMichael Tuexen #ifdef INET
43595e2c2d87SRandall Stewart 	case AF_INET:
43605e2c2d87SRandall Stewart 		{
4361f8829a4aSRandall Stewart 			/* IPv4 addresses */
4362f8829a4aSRandall Stewart 			struct sockaddr_in *sin_1, *sin_2;
4363f8829a4aSRandall Stewart 
4364f8829a4aSRandall Stewart 			sin_1 = (struct sockaddr_in *)sa1;
4365f8829a4aSRandall Stewart 			sin_2 = (struct sockaddr_in *)sa2;
4366f8829a4aSRandall Stewart 			return (sin_1->sin_addr.s_addr == sin_2->sin_addr.s_addr);
43675e2c2d87SRandall Stewart 		}
4368ea5eba11SMichael Tuexen #endif
43695e2c2d87SRandall Stewart 	default:
4370f8829a4aSRandall Stewart 		/* we don't do these... */
4371f8829a4aSRandall Stewart 		return (0);
4372f8829a4aSRandall Stewart 	}
4373f8829a4aSRandall Stewart }
4374f8829a4aSRandall Stewart 
4375f8829a4aSRandall Stewart void
4376f8829a4aSRandall Stewart sctp_print_address(struct sockaddr *sa)
4377f8829a4aSRandall Stewart {
43785e2c2d87SRandall Stewart #ifdef INET6
43797d32aa0cSBjoern A. Zeeb 	char ip6buf[INET6_ADDRSTRLEN];
43805e2c2d87SRandall Stewart #endif
43815e2c2d87SRandall Stewart 
43825e2c2d87SRandall Stewart 	switch (sa->sa_family) {
43835e2c2d87SRandall Stewart #ifdef INET6
43845e2c2d87SRandall Stewart 	case AF_INET6:
43855e2c2d87SRandall Stewart 		{
4386ad81507eSRandall Stewart 			struct sockaddr_in6 *sin6;
4387ad81507eSRandall Stewart 
4388f8829a4aSRandall Stewart 			sin6 = (struct sockaddr_in6 *)sa;
4389ad81507eSRandall Stewart 			SCTP_PRINTF("IPv6 address: %s:port:%d scope:%u\n",
43907d32aa0cSBjoern A. Zeeb 			    ip6_sprintf(ip6buf, &sin6->sin6_addr),
43917d32aa0cSBjoern A. Zeeb 			    ntohs(sin6->sin6_port),
4392f8829a4aSRandall Stewart 			    sin6->sin6_scope_id);
43935e2c2d87SRandall Stewart 			break;
43945e2c2d87SRandall Stewart 		}
43955e2c2d87SRandall Stewart #endif
4396ea5eba11SMichael Tuexen #ifdef INET
43975e2c2d87SRandall Stewart 	case AF_INET:
43985e2c2d87SRandall Stewart 		{
4399f8829a4aSRandall Stewart 			struct sockaddr_in *sin;
4400f8829a4aSRandall Stewart 			unsigned char *p;
4401f8829a4aSRandall Stewart 
4402f8829a4aSRandall Stewart 			sin = (struct sockaddr_in *)sa;
4403f8829a4aSRandall Stewart 			p = (unsigned char *)&sin->sin_addr;
4404ad81507eSRandall Stewart 			SCTP_PRINTF("IPv4 address: %u.%u.%u.%u:%d\n",
4405f8829a4aSRandall Stewart 			    p[0], p[1], p[2], p[3], ntohs(sin->sin_port));
44065e2c2d87SRandall Stewart 			break;
44075e2c2d87SRandall Stewart 		}
4408ea5eba11SMichael Tuexen #endif
44095e2c2d87SRandall Stewart 	default:
4410ad81507eSRandall Stewart 		SCTP_PRINTF("?\n");
44115e2c2d87SRandall Stewart 		break;
4412f8829a4aSRandall Stewart 	}
4413f8829a4aSRandall Stewart }
4414f8829a4aSRandall Stewart 
4415f8829a4aSRandall Stewart void
4416f8829a4aSRandall Stewart sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp,
4417f8829a4aSRandall Stewart     struct sctp_inpcb *new_inp,
4418d06c82f1SRandall Stewart     struct sctp_tcb *stcb,
4419d06c82f1SRandall Stewart     int waitflags)
4420f8829a4aSRandall Stewart {
4421f8829a4aSRandall Stewart 	/*
4422f8829a4aSRandall Stewart 	 * go through our old INP and pull off any control structures that
4423f8829a4aSRandall Stewart 	 * belong to stcb and move then to the new inp.
4424f8829a4aSRandall Stewart 	 */
4425f8829a4aSRandall Stewart 	struct socket *old_so, *new_so;
4426f8829a4aSRandall Stewart 	struct sctp_queued_to_read *control, *nctl;
4427f8829a4aSRandall Stewart 	struct sctp_readhead tmp_queue;
4428f8829a4aSRandall Stewart 	struct mbuf *m;
4429bff64a4dSRandall Stewart 	int error = 0;
4430f8829a4aSRandall Stewart 
4431f8829a4aSRandall Stewart 	old_so = old_inp->sctp_socket;
4432f8829a4aSRandall Stewart 	new_so = new_inp->sctp_socket;
4433f8829a4aSRandall Stewart 	TAILQ_INIT(&tmp_queue);
4434d06c82f1SRandall Stewart 	error = sblock(&old_so->so_rcv, waitflags);
4435f8829a4aSRandall Stewart 	if (error) {
4436f8829a4aSRandall Stewart 		/*
4437f8829a4aSRandall Stewart 		 * Gak, can't get sblock, we have a problem. data will be
4438f8829a4aSRandall Stewart 		 * left stranded.. and we don't dare look at it since the
4439f8829a4aSRandall Stewart 		 * other thread may be reading something. Oh well, its a
4440f8829a4aSRandall Stewart 		 * screwed up app that does a peeloff OR a accept while
4441f8829a4aSRandall Stewart 		 * reading from the main socket... actually its only the
4442f8829a4aSRandall Stewart 		 * peeloff() case, since I think read will fail on a
4443f8829a4aSRandall Stewart 		 * listening socket..
4444f8829a4aSRandall Stewart 		 */
4445f8829a4aSRandall Stewart 		return;
4446f8829a4aSRandall Stewart 	}
4447f8829a4aSRandall Stewart 	/* lock the socket buffers */
4448f8829a4aSRandall Stewart 	SCTP_INP_READ_LOCK(old_inp);
44494a9ef3f8SMichael Tuexen 	TAILQ_FOREACH_SAFE(control, &old_inp->read_queue, next, nctl) {
4450f8829a4aSRandall Stewart 		/* Pull off all for out target stcb */
4451f8829a4aSRandall Stewart 		if (control->stcb == stcb) {
4452f8829a4aSRandall Stewart 			/* remove it we want it */
4453f8829a4aSRandall Stewart 			TAILQ_REMOVE(&old_inp->read_queue, control, next);
4454f8829a4aSRandall Stewart 			TAILQ_INSERT_TAIL(&tmp_queue, control, next);
4455f8829a4aSRandall Stewart 			m = control->data;
4456f8829a4aSRandall Stewart 			while (m) {
4457b3f1ea41SRandall Stewart 				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
4458139bc87fSRandall Stewart 					sctp_sblog(&old_so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m));
445980fefe0aSRandall Stewart 				}
4460f8829a4aSRandall Stewart 				sctp_sbfree(control, stcb, &old_so->so_rcv, m);
4461b3f1ea41SRandall Stewart 				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
4462f8829a4aSRandall Stewart 					sctp_sblog(&old_so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0);
446380fefe0aSRandall Stewart 				}
4464139bc87fSRandall Stewart 				m = SCTP_BUF_NEXT(m);
4465f8829a4aSRandall Stewart 			}
4466f8829a4aSRandall Stewart 		}
4467f8829a4aSRandall Stewart 	}
4468f8829a4aSRandall Stewart 	SCTP_INP_READ_UNLOCK(old_inp);
4469f8829a4aSRandall Stewart 	/* Remove the sb-lock on the old socket */
4470f8829a4aSRandall Stewart 
4471f8829a4aSRandall Stewart 	sbunlock(&old_so->so_rcv);
4472f8829a4aSRandall Stewart 	/* Now we move them over to the new socket buffer */
4473f8829a4aSRandall Stewart 	SCTP_INP_READ_LOCK(new_inp);
44744a9ef3f8SMichael Tuexen 	TAILQ_FOREACH_SAFE(control, &tmp_queue, next, nctl) {
4475f8829a4aSRandall Stewart 		TAILQ_INSERT_TAIL(&new_inp->read_queue, control, next);
4476f8829a4aSRandall Stewart 		m = control->data;
4477f8829a4aSRandall Stewart 		while (m) {
4478b3f1ea41SRandall Stewart 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
4479139bc87fSRandall Stewart 				sctp_sblog(&new_so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(m));
448080fefe0aSRandall Stewart 			}
4481f8829a4aSRandall Stewart 			sctp_sballoc(stcb, &new_so->so_rcv, m);
4482b3f1ea41SRandall Stewart 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
4483f8829a4aSRandall Stewart 				sctp_sblog(&new_so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0);
448480fefe0aSRandall Stewart 			}
4485139bc87fSRandall Stewart 			m = SCTP_BUF_NEXT(m);
4486f8829a4aSRandall Stewart 		}
4487f8829a4aSRandall Stewart 	}
4488f8829a4aSRandall Stewart 	SCTP_INP_READ_UNLOCK(new_inp);
4489f8829a4aSRandall Stewart }
4490f8829a4aSRandall Stewart 
4491f8829a4aSRandall Stewart void
4492b1deed45SMichael Tuexen sctp_wakeup_the_read_socket(struct sctp_inpcb *inp,
4493b1deed45SMichael Tuexen     struct sctp_tcb *stcb,
4494b1deed45SMichael Tuexen     int so_locked
4495b1deed45SMichael Tuexen #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
4496b1deed45SMichael Tuexen     SCTP_UNUSED
4497b1deed45SMichael Tuexen #endif
4498b1deed45SMichael Tuexen )
449944249214SRandall Stewart {
4500b1deed45SMichael Tuexen 	if ((inp != NULL) && (inp->sctp_socket != NULL)) {
450144249214SRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
450244249214SRandall Stewart 		struct socket *so;
450344249214SRandall Stewart 
450444249214SRandall Stewart 		so = SCTP_INP_SO(inp);
450544249214SRandall Stewart 		if (!so_locked) {
450644249214SRandall Stewart 			if (stcb) {
450744249214SRandall Stewart 				atomic_add_int(&stcb->asoc.refcnt, 1);
450844249214SRandall Stewart 				SCTP_TCB_UNLOCK(stcb);
450944249214SRandall Stewart 			}
451044249214SRandall Stewart 			SCTP_SOCKET_LOCK(so, 1);
451144249214SRandall Stewart 			if (stcb) {
451244249214SRandall Stewart 				SCTP_TCB_LOCK(stcb);
451344249214SRandall Stewart 				atomic_subtract_int(&stcb->asoc.refcnt, 1);
451444249214SRandall Stewart 			}
451544249214SRandall Stewart 			if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
451644249214SRandall Stewart 				SCTP_SOCKET_UNLOCK(so, 1);
451744249214SRandall Stewart 				return;
451844249214SRandall Stewart 			}
451944249214SRandall Stewart 		}
452044249214SRandall Stewart #endif
452144249214SRandall Stewart 		sctp_sorwakeup(inp, inp->sctp_socket);
452244249214SRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
452344249214SRandall Stewart 		if (!so_locked) {
452444249214SRandall Stewart 			SCTP_SOCKET_UNLOCK(so, 1);
452544249214SRandall Stewart 		}
452644249214SRandall Stewart #endif
452744249214SRandall Stewart 	}
452844249214SRandall Stewart }
452944249214SRandall Stewart 
453044249214SRandall Stewart void
4531f8829a4aSRandall Stewart sctp_add_to_readq(struct sctp_inpcb *inp,
4532f8829a4aSRandall Stewart     struct sctp_tcb *stcb,
4533f8829a4aSRandall Stewart     struct sctp_queued_to_read *control,
4534f8829a4aSRandall Stewart     struct sockbuf *sb,
4535ceaad40aSRandall Stewart     int end,
4536cfde3ff7SRandall Stewart     int inp_read_lock_held,
4537ceaad40aSRandall Stewart     int so_locked
4538ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
4539ceaad40aSRandall Stewart     SCTP_UNUSED
4540ceaad40aSRandall Stewart #endif
4541ceaad40aSRandall Stewart )
4542f8829a4aSRandall Stewart {
4543f8829a4aSRandall Stewart 	/*
4544f8829a4aSRandall Stewart 	 * Here we must place the control on the end of the socket read
45454e88d37aSMichael Tuexen 	 * queue AND increment sb_cc so that select will work properly on
4546f8829a4aSRandall Stewart 	 * read.
4547f8829a4aSRandall Stewart 	 */
4548f8829a4aSRandall Stewart 	struct mbuf *m, *prev = NULL;
4549f8829a4aSRandall Stewart 
455003b0b021SRandall Stewart 	if (inp == NULL) {
455103b0b021SRandall Stewart 		/* Gak, TSNH!! */
4552a5d547adSRandall Stewart #ifdef INVARIANTS
455303b0b021SRandall Stewart 		panic("Gak, inp NULL on add_to_readq");
455403b0b021SRandall Stewart #endif
455503b0b021SRandall Stewart 		return;
455603b0b021SRandall Stewart 	}
4557cfde3ff7SRandall Stewart 	if (inp_read_lock_held == 0)
4558f8829a4aSRandall Stewart 		SCTP_INP_READ_LOCK(inp);
4559cd1386abSMichael Tuexen 	if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_CANT_READ) {
4560cd1386abSMichael Tuexen 		sctp_free_remote_addr(control->whoFrom);
4561cd1386abSMichael Tuexen 		if (control->data) {
4562cd1386abSMichael Tuexen 			sctp_m_freem(control->data);
4563cd1386abSMichael Tuexen 			control->data = NULL;
4564cd1386abSMichael Tuexen 		}
456544249214SRandall Stewart 		sctp_free_a_readq(stcb, control);
4566cd1386abSMichael Tuexen 		if (inp_read_lock_held == 0)
4567cd1386abSMichael Tuexen 			SCTP_INP_READ_UNLOCK(inp);
4568cd1386abSMichael Tuexen 		return;
4569cd1386abSMichael Tuexen 	}
457042551e99SRandall Stewart 	if (!(control->spec_flags & M_NOTIFICATION)) {
4571a5d547adSRandall Stewart 		atomic_add_int(&inp->total_recvs, 1);
457242551e99SRandall Stewart 		if (!control->do_not_ref_stcb) {
4573a5d547adSRandall Stewart 			atomic_add_int(&stcb->total_recvs, 1);
457442551e99SRandall Stewart 		}
457542551e99SRandall Stewart 	}
4576f8829a4aSRandall Stewart 	m = control->data;
4577f8829a4aSRandall Stewart 	control->held_length = 0;
4578f8829a4aSRandall Stewart 	control->length = 0;
4579f8829a4aSRandall Stewart 	while (m) {
4580139bc87fSRandall Stewart 		if (SCTP_BUF_LEN(m) == 0) {
4581f8829a4aSRandall Stewart 			/* Skip mbufs with NO length */
4582f8829a4aSRandall Stewart 			if (prev == NULL) {
4583f8829a4aSRandall Stewart 				/* First one */
4584f8829a4aSRandall Stewart 				control->data = sctp_m_free(m);
4585f8829a4aSRandall Stewart 				m = control->data;
4586f8829a4aSRandall Stewart 			} else {
4587139bc87fSRandall Stewart 				SCTP_BUF_NEXT(prev) = sctp_m_free(m);
4588139bc87fSRandall Stewart 				m = SCTP_BUF_NEXT(prev);
4589f8829a4aSRandall Stewart 			}
4590f8829a4aSRandall Stewart 			if (m == NULL) {
4591c2ede4b3SMartin Blapp 				control->tail_mbuf = prev;
4592f8829a4aSRandall Stewart 			}
4593f8829a4aSRandall Stewart 			continue;
4594f8829a4aSRandall Stewart 		}
4595f8829a4aSRandall Stewart 		prev = m;
4596b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
4597139bc87fSRandall Stewart 			sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(m));
459880fefe0aSRandall Stewart 		}
4599f8829a4aSRandall Stewart 		sctp_sballoc(stcb, sb, m);
4600b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
4601f8829a4aSRandall Stewart 			sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0);
460280fefe0aSRandall Stewart 		}
4603139bc87fSRandall Stewart 		atomic_add_int(&control->length, SCTP_BUF_LEN(m));
4604139bc87fSRandall Stewart 		m = SCTP_BUF_NEXT(m);
4605f8829a4aSRandall Stewart 	}
4606f8829a4aSRandall Stewart 	if (prev != NULL) {
4607f8829a4aSRandall Stewart 		control->tail_mbuf = prev;
4608f8829a4aSRandall Stewart 	} else {
4609139bc87fSRandall Stewart 		/* Everything got collapsed out?? */
4610cd1386abSMichael Tuexen 		sctp_free_remote_addr(control->whoFrom);
461144249214SRandall Stewart 		sctp_free_a_readq(stcb, control);
4612cfde3ff7SRandall Stewart 		if (inp_read_lock_held == 0)
461347a490cbSMichael Tuexen 			SCTP_INP_READ_UNLOCK(inp);
4614f8829a4aSRandall Stewart 		return;
4615f8829a4aSRandall Stewart 	}
4616f8829a4aSRandall Stewart 	if (end) {
4617f8829a4aSRandall Stewart 		control->end_added = 1;
4618f8829a4aSRandall Stewart 	}
4619f8829a4aSRandall Stewart 	TAILQ_INSERT_TAIL(&inp->read_queue, control, next);
462044249214SRandall Stewart 	control->on_read_q = 1;
4621cfde3ff7SRandall Stewart 	if (inp_read_lock_held == 0)
4622f8829a4aSRandall Stewart 		SCTP_INP_READ_UNLOCK(inp);
4623f8829a4aSRandall Stewart 	if (inp && inp->sctp_socket) {
4624b1deed45SMichael Tuexen 		sctp_wakeup_the_read_socket(inp, stcb, so_locked);
4625f8829a4aSRandall Stewart 	}
4626f8829a4aSRandall Stewart }
4627f8829a4aSRandall Stewart 
4628f8829a4aSRandall Stewart /*************HOLD THIS COMMENT FOR PATCH FILE OF
4629f8829a4aSRandall Stewart  *************ALTERNATE ROUTING CODE
4630f8829a4aSRandall Stewart  */
4631f8829a4aSRandall Stewart 
4632f8829a4aSRandall Stewart /*************HOLD THIS COMMENT FOR END OF PATCH FILE OF
4633f8829a4aSRandall Stewart  *************ALTERNATE ROUTING CODE
4634f8829a4aSRandall Stewart  */
4635f8829a4aSRandall Stewart 
4636f8829a4aSRandall Stewart struct mbuf *
4637ff1ffd74SMichael Tuexen sctp_generate_cause(uint16_t code, char *info)
4638f8829a4aSRandall Stewart {
4639f8829a4aSRandall Stewart 	struct mbuf *m;
4640ff1ffd74SMichael Tuexen 	struct sctp_gen_error_cause *cause;
46419a8e3088SMichael Tuexen 	size_t info_len;
46429a8e3088SMichael Tuexen 	uint16_t len;
4643f8829a4aSRandall Stewart 
4644ff1ffd74SMichael Tuexen 	if ((code == 0) || (info == NULL)) {
4645ff1ffd74SMichael Tuexen 		return (NULL);
4646ff1ffd74SMichael Tuexen 	}
4647ff1ffd74SMichael Tuexen 	info_len = strlen(info);
46489a8e3088SMichael Tuexen 	if (info_len > (SCTP_MAX_CAUSE_LENGTH - sizeof(struct sctp_paramhdr))) {
46499a8e3088SMichael Tuexen 		return (NULL);
46509a8e3088SMichael Tuexen 	}
46519a8e3088SMichael Tuexen 	len = (uint16_t)(sizeof(struct sctp_paramhdr) + info_len);
4652ff1ffd74SMichael Tuexen 	m = sctp_get_mbuf_for_msg(len, 0, M_NOWAIT, 1, MT_DATA);
4653ff1ffd74SMichael Tuexen 	if (m != NULL) {
4654ff1ffd74SMichael Tuexen 		SCTP_BUF_LEN(m) = len;
4655ff1ffd74SMichael Tuexen 		cause = mtod(m, struct sctp_gen_error_cause *);
4656ff1ffd74SMichael Tuexen 		cause->code = htons(code);
46579a8e3088SMichael Tuexen 		cause->length = htons(len);
4658ff1ffd74SMichael Tuexen 		memcpy(cause->info, info, info_len);
4659f8829a4aSRandall Stewart 	}
4660f8829a4aSRandall Stewart 	return (m);
4661f8829a4aSRandall Stewart }
4662f8829a4aSRandall Stewart 
466332451da4SMichael Tuexen struct mbuf *
466432451da4SMichael Tuexen sctp_generate_no_user_data_cause(uint32_t tsn)
466532451da4SMichael Tuexen {
466632451da4SMichael Tuexen 	struct mbuf *m;
466732451da4SMichael Tuexen 	struct sctp_error_no_user_data *no_user_data_cause;
46689a8e3088SMichael Tuexen 	uint16_t len;
466932451da4SMichael Tuexen 
46709a8e3088SMichael Tuexen 	len = (uint16_t)sizeof(struct sctp_error_no_user_data);
467132451da4SMichael Tuexen 	m = sctp_get_mbuf_for_msg(len, 0, M_NOWAIT, 1, MT_DATA);
467232451da4SMichael Tuexen 	if (m != NULL) {
467332451da4SMichael Tuexen 		SCTP_BUF_LEN(m) = len;
467432451da4SMichael Tuexen 		no_user_data_cause = mtod(m, struct sctp_error_no_user_data *);
467532451da4SMichael Tuexen 		no_user_data_cause->cause.code = htons(SCTP_CAUSE_NO_USER_DATA);
46769a8e3088SMichael Tuexen 		no_user_data_cause->cause.length = htons(len);
46778b9c95f4SMichael Tuexen 		no_user_data_cause->tsn = htonl(tsn);
467832451da4SMichael Tuexen 	}
467932451da4SMichael Tuexen 	return (m);
468032451da4SMichael Tuexen }
468132451da4SMichael Tuexen 
4682f8829a4aSRandall Stewart #ifdef SCTP_MBCNT_LOGGING
4683f8829a4aSRandall Stewart void
4684f8829a4aSRandall Stewart sctp_free_bufspace(struct sctp_tcb *stcb, struct sctp_association *asoc,
4685f8829a4aSRandall Stewart     struct sctp_tmit_chunk *tp1, int chk_cnt)
4686f8829a4aSRandall Stewart {
4687f8829a4aSRandall Stewart 	if (tp1->data == NULL) {
4688f8829a4aSRandall Stewart 		return;
4689f8829a4aSRandall Stewart 	}
4690f8829a4aSRandall Stewart 	asoc->chunks_on_out_queue -= chk_cnt;
4691b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBCNT_LOGGING_ENABLE) {
4692f8829a4aSRandall Stewart 		sctp_log_mbcnt(SCTP_LOG_MBCNT_DECREASE,
4693f8829a4aSRandall Stewart 		    asoc->total_output_queue_size,
4694f8829a4aSRandall Stewart 		    tp1->book_size,
4695f8829a4aSRandall Stewart 		    0,
4696f8829a4aSRandall Stewart 		    tp1->mbcnt);
469780fefe0aSRandall Stewart 	}
4698f8829a4aSRandall Stewart 	if (asoc->total_output_queue_size >= tp1->book_size) {
469944b7479bSRandall Stewart 		atomic_add_int(&asoc->total_output_queue_size, -tp1->book_size);
4700f8829a4aSRandall Stewart 	} else {
4701f8829a4aSRandall Stewart 		asoc->total_output_queue_size = 0;
4702f8829a4aSRandall Stewart 	}
4703f8829a4aSRandall Stewart 
4704f8829a4aSRandall Stewart 	if (stcb->sctp_socket && (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) ||
4705f8829a4aSRandall Stewart 	    ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE)))) {
47064e88d37aSMichael Tuexen 		if (stcb->sctp_socket->so_snd.sb_cc >= tp1->book_size) {
47074e88d37aSMichael Tuexen 			stcb->sctp_socket->so_snd.sb_cc -= tp1->book_size;
4708f8829a4aSRandall Stewart 		} else {
47094e88d37aSMichael Tuexen 			stcb->sctp_socket->so_snd.sb_cc = 0;
4710f8829a4aSRandall Stewart 
4711f8829a4aSRandall Stewart 		}
4712f8829a4aSRandall Stewart 	}
4713f8829a4aSRandall Stewart }
4714f8829a4aSRandall Stewart 
4715f8829a4aSRandall Stewart #endif
4716f8829a4aSRandall Stewart 
4717f8829a4aSRandall Stewart int
4718f8829a4aSRandall Stewart sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1,
47191edc9dbaSMichael Tuexen     uint8_t sent, int so_locked
4720ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
4721ceaad40aSRandall Stewart     SCTP_UNUSED
4722ceaad40aSRandall Stewart #endif
4723ceaad40aSRandall Stewart )
4724f8829a4aSRandall Stewart {
47250c0982b8SRandall Stewart 	struct sctp_stream_out *strq;
47264a9ef3f8SMichael Tuexen 	struct sctp_tmit_chunk *chk = NULL, *tp2;
47270c0982b8SRandall Stewart 	struct sctp_stream_queue_pending *sp;
472849656eefSMichael Tuexen 	uint32_t mid;
472949656eefSMichael Tuexen 	uint16_t sid;
47300c0982b8SRandall Stewart 	uint8_t foundeom = 0;
4731f8829a4aSRandall Stewart 	int ret_sz = 0;
4732f8829a4aSRandall Stewart 	int notdone;
47330c0982b8SRandall Stewart 	int do_wakeup_routine = 0;
4734f8829a4aSRandall Stewart 
473549656eefSMichael Tuexen 	sid = tp1->rec.data.sid;
473649656eefSMichael Tuexen 	mid = tp1->rec.data.mid;
4737f0396ad1SMichael Tuexen 	if (sent || !(tp1->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG)) {
4738f0396ad1SMichael Tuexen 		stcb->asoc.abandoned_sent[0]++;
4739f0396ad1SMichael Tuexen 		stcb->asoc.abandoned_sent[PR_SCTP_POLICY(tp1->flags)]++;
474049656eefSMichael Tuexen 		stcb->asoc.strmout[sid].abandoned_sent[0]++;
4741f0396ad1SMichael Tuexen #if defined(SCTP_DETAILED_STR_STATS)
4742ad15e154SMichael Tuexen 		stcb->asoc.strmout[sid].abandoned_sent[PR_SCTP_POLICY(tp1->flags)]++;
4743f0396ad1SMichael Tuexen #endif
4744f0396ad1SMichael Tuexen 	} else {
4745f0396ad1SMichael Tuexen 		stcb->asoc.abandoned_unsent[0]++;
4746f0396ad1SMichael Tuexen 		stcb->asoc.abandoned_unsent[PR_SCTP_POLICY(tp1->flags)]++;
474749656eefSMichael Tuexen 		stcb->asoc.strmout[sid].abandoned_unsent[0]++;
4748f0396ad1SMichael Tuexen #if defined(SCTP_DETAILED_STR_STATS)
4749ad15e154SMichael Tuexen 		stcb->asoc.strmout[sid].abandoned_unsent[PR_SCTP_POLICY(tp1->flags)]++;
4750f0396ad1SMichael Tuexen #endif
4751f0396ad1SMichael Tuexen 	}
4752f8829a4aSRandall Stewart 	do {
4753f8829a4aSRandall Stewart 		ret_sz += tp1->book_size;
47540c0982b8SRandall Stewart 		if (tp1->data != NULL) {
47558933fa13SRandall Stewart 			if (tp1->sent < SCTP_DATAGRAM_RESEND) {
4756830d754dSRandall Stewart 				sctp_flight_size_decrease(tp1);
4757830d754dSRandall Stewart 				sctp_total_flight_decrease(stcb, tp1);
47588933fa13SRandall Stewart 			}
47598933fa13SRandall Stewart 			sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1);
47600c0982b8SRandall Stewart 			stcb->asoc.peers_rwnd += tp1->send_size;
47610c0982b8SRandall Stewart 			stcb->asoc.peers_rwnd += SCTP_BASE_SYSCTL(sctp_peer_chunk_oh);
47621edc9dbaSMichael Tuexen 			if (sent) {
47631edc9dbaSMichael Tuexen 				sctp_ulp_notify(SCTP_NOTIFY_SENT_DG_FAIL, stcb, 0, tp1, so_locked);
47641edc9dbaSMichael Tuexen 			} else {
47651edc9dbaSMichael Tuexen 				sctp_ulp_notify(SCTP_NOTIFY_UNSENT_DG_FAIL, stcb, 0, tp1, so_locked);
47661edc9dbaSMichael Tuexen 			}
47672f99457bSMichael Tuexen 			if (tp1->data) {
4768f8829a4aSRandall Stewart 				sctp_m_freem(tp1->data);
4769f8829a4aSRandall Stewart 				tp1->data = NULL;
47702f99457bSMichael Tuexen 			}
47710c0982b8SRandall Stewart 			do_wakeup_routine = 1;
4772f8829a4aSRandall Stewart 			if (PR_SCTP_BUF_ENABLED(tp1->flags)) {
4773f8829a4aSRandall Stewart 				stcb->asoc.sent_queue_cnt_removeable--;
4774f8829a4aSRandall Stewart 			}
4775f8829a4aSRandall Stewart 		}
47768933fa13SRandall Stewart 		tp1->sent = SCTP_FORWARD_TSN_SKIP;
4777f8829a4aSRandall Stewart 		if ((tp1->rec.data.rcv_flags & SCTP_DATA_NOT_FRAG) ==
4778f8829a4aSRandall Stewart 		    SCTP_DATA_NOT_FRAG) {
4779f8829a4aSRandall Stewart 			/* not frag'ed we ae done   */
4780f8829a4aSRandall Stewart 			notdone = 0;
4781f8829a4aSRandall Stewart 			foundeom = 1;
4782f8829a4aSRandall Stewart 		} else if (tp1->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) {
4783f8829a4aSRandall Stewart 			/* end of frag, we are done */
4784f8829a4aSRandall Stewart 			notdone = 0;
4785f8829a4aSRandall Stewart 			foundeom = 1;
4786f8829a4aSRandall Stewart 		} else {
4787f8829a4aSRandall Stewart 			/*
4788f8829a4aSRandall Stewart 			 * Its a begin or middle piece, we must mark all of
4789f8829a4aSRandall Stewart 			 * it
4790f8829a4aSRandall Stewart 			 */
4791f8829a4aSRandall Stewart 			notdone = 1;
4792f8829a4aSRandall Stewart 			tp1 = TAILQ_NEXT(tp1, sctp_next);
4793f8829a4aSRandall Stewart 		}
4794f8829a4aSRandall Stewart 	} while (tp1 && notdone);
47950c0982b8SRandall Stewart 	if (foundeom == 0) {
4796f8829a4aSRandall Stewart 		/*
4797f8829a4aSRandall Stewart 		 * The multi-part message was scattered across the send and
4798f8829a4aSRandall Stewart 		 * sent queue.
4799f8829a4aSRandall Stewart 		 */
48004a9ef3f8SMichael Tuexen 		TAILQ_FOREACH_SAFE(tp1, &stcb->asoc.send_queue, sctp_next, tp2) {
480149656eefSMichael Tuexen 			if ((tp1->rec.data.sid != sid) ||
480249656eefSMichael Tuexen 			    (!SCTP_MID_EQ(stcb->asoc.idata_supported, tp1->rec.data.mid, mid))) {
48034a9ef3f8SMichael Tuexen 				break;
48044a9ef3f8SMichael Tuexen 			}
48050c0982b8SRandall Stewart 			/*
48060c0982b8SRandall Stewart 			 * save to chk in case we have some on stream out
48070c0982b8SRandall Stewart 			 * queue. If so and we have an un-transmitted one we
48080c0982b8SRandall Stewart 			 * don't have to fudge the TSN.
48090c0982b8SRandall Stewart 			 */
48100c0982b8SRandall Stewart 			chk = tp1;
48110c0982b8SRandall Stewart 			ret_sz += tp1->book_size;
48120c0982b8SRandall Stewart 			sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1);
48131edc9dbaSMichael Tuexen 			if (sent) {
48141edc9dbaSMichael Tuexen 				sctp_ulp_notify(SCTP_NOTIFY_SENT_DG_FAIL, stcb, 0, tp1, so_locked);
48151edc9dbaSMichael Tuexen 			} else {
48161edc9dbaSMichael Tuexen 				sctp_ulp_notify(SCTP_NOTIFY_UNSENT_DG_FAIL, stcb, 0, tp1, so_locked);
48171edc9dbaSMichael Tuexen 			}
48182f99457bSMichael Tuexen 			if (tp1->data) {
48190c0982b8SRandall Stewart 				sctp_m_freem(tp1->data);
48202f99457bSMichael Tuexen 				tp1->data = NULL;
48212f99457bSMichael Tuexen 			}
48228933fa13SRandall Stewart 			/* No flight involved here book the size to 0 */
48238933fa13SRandall Stewart 			tp1->book_size = 0;
48240c0982b8SRandall Stewart 			if (tp1->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) {
48250c0982b8SRandall Stewart 				foundeom = 1;
4826f8829a4aSRandall Stewart 			}
48270c0982b8SRandall Stewart 			do_wakeup_routine = 1;
48280c0982b8SRandall Stewart 			tp1->sent = SCTP_FORWARD_TSN_SKIP;
48290c0982b8SRandall Stewart 			TAILQ_REMOVE(&stcb->asoc.send_queue, tp1, sctp_next);
4830b7b84c0eSMichael Tuexen 			/*
4831b7b84c0eSMichael Tuexen 			 * on to the sent queue so we can wait for it to be
4832b7b84c0eSMichael Tuexen 			 * passed by.
4833b7b84c0eSMichael Tuexen 			 */
48340c0982b8SRandall Stewart 			TAILQ_INSERT_TAIL(&stcb->asoc.sent_queue, tp1,
48350c0982b8SRandall Stewart 			    sctp_next);
48360c0982b8SRandall Stewart 			stcb->asoc.send_queue_cnt--;
48370c0982b8SRandall Stewart 			stcb->asoc.sent_queue_cnt++;
48380c0982b8SRandall Stewart 		}
48390c0982b8SRandall Stewart 	}
48400c0982b8SRandall Stewart 	if (foundeom == 0) {
48410c0982b8SRandall Stewart 		/*
48420c0982b8SRandall Stewart 		 * Still no eom found. That means there is stuff left on the
48430c0982b8SRandall Stewart 		 * stream out queue.. yuck.
48440c0982b8SRandall Stewart 		 */
48450c0982b8SRandall Stewart 		SCTP_TCB_SEND_LOCK(stcb);
484649656eefSMichael Tuexen 		strq = &stcb->asoc.strmout[sid];
4847f3b05218SMichael Tuexen 		sp = TAILQ_FIRST(&strq->outqueue);
4848f3b05218SMichael Tuexen 		if (sp != NULL) {
48490c0982b8SRandall Stewart 			sp->discard_rest = 1;
48500c0982b8SRandall Stewart 			/*
4851f3b05218SMichael Tuexen 			 * We may need to put a chunk on the queue that
4852f3b05218SMichael Tuexen 			 * holds the TSN that would have been sent with the
4853f3b05218SMichael Tuexen 			 * LAST bit.
48540c0982b8SRandall Stewart 			 */
48550c0982b8SRandall Stewart 			if (chk == NULL) {
48560c0982b8SRandall Stewart 				/* Yep, we have to */
48570c0982b8SRandall Stewart 				sctp_alloc_a_chunk(stcb, chk);
48580c0982b8SRandall Stewart 				if (chk == NULL) {
48590c0982b8SRandall Stewart 					/*
4860f3b05218SMichael Tuexen 					 * we are hosed. All we can do is
4861f3b05218SMichael Tuexen 					 * nothing.. which will cause an
4862f3b05218SMichael Tuexen 					 * abort if the peer is paying
48630c0982b8SRandall Stewart 					 * attention.
48640c0982b8SRandall Stewart 					 */
48650c0982b8SRandall Stewart 					goto oh_well;
48660c0982b8SRandall Stewart 				}
48670c0982b8SRandall Stewart 				memset(chk, 0, sizeof(*chk));
486863d5b568SMichael Tuexen 				chk->rec.data.rcv_flags = 0;
48690c0982b8SRandall Stewart 				chk->sent = SCTP_FORWARD_TSN_SKIP;
48700c0982b8SRandall Stewart 				chk->asoc = &stcb->asoc;
487163d5b568SMichael Tuexen 				if (stcb->asoc.idata_supported == 0) {
487263d5b568SMichael Tuexen 					if (sp->sinfo_flags & SCTP_UNORDERED) {
487349656eefSMichael Tuexen 						chk->rec.data.mid = 0;
487463d5b568SMichael Tuexen 					} else {
487549656eefSMichael Tuexen 						chk->rec.data.mid = strq->next_mid_ordered;
487663d5b568SMichael Tuexen 					}
487763d5b568SMichael Tuexen 				} else {
487863d5b568SMichael Tuexen 					if (sp->sinfo_flags & SCTP_UNORDERED) {
487949656eefSMichael Tuexen 						chk->rec.data.mid = strq->next_mid_unordered;
488063d5b568SMichael Tuexen 					} else {
488149656eefSMichael Tuexen 						chk->rec.data.mid = strq->next_mid_ordered;
488263d5b568SMichael Tuexen 					}
488363d5b568SMichael Tuexen 				}
488449656eefSMichael Tuexen 				chk->rec.data.sid = sp->sid;
488549656eefSMichael Tuexen 				chk->rec.data.ppid = sp->ppid;
48860c0982b8SRandall Stewart 				chk->rec.data.context = sp->context;
48870c0982b8SRandall Stewart 				chk->flags = sp->act_flags;
48887fd5b436SMichael Tuexen 				chk->whoTo = NULL;
488949656eefSMichael Tuexen 				chk->rec.data.tsn = atomic_fetchadd_int(&stcb->asoc.sending_seq, 1);
48907fd5b436SMichael Tuexen 				strq->chunks_on_queues++;
48910c0982b8SRandall Stewart 				TAILQ_INSERT_TAIL(&stcb->asoc.sent_queue, chk, sctp_next);
48920c0982b8SRandall Stewart 				stcb->asoc.sent_queue_cnt++;
48938933fa13SRandall Stewart 				stcb->asoc.pr_sctp_cnt++;
48940c0982b8SRandall Stewart 			}
489563d5b568SMichael Tuexen 			chk->rec.data.rcv_flags |= SCTP_DATA_LAST_FRAG;
4896d1ea5fa9SMichael Tuexen 			if (sp->sinfo_flags & SCTP_UNORDERED) {
4897d1ea5fa9SMichael Tuexen 				chk->rec.data.rcv_flags |= SCTP_DATA_UNORDERED;
4898d1ea5fa9SMichael Tuexen 			}
489963d5b568SMichael Tuexen 			if (stcb->asoc.idata_supported == 0) {
490063d5b568SMichael Tuexen 				if ((sp->sinfo_flags & SCTP_UNORDERED) == 0) {
490163d5b568SMichael Tuexen 					strq->next_mid_ordered++;
490263d5b568SMichael Tuexen 				}
490363d5b568SMichael Tuexen 			} else {
490463d5b568SMichael Tuexen 				if (sp->sinfo_flags & SCTP_UNORDERED) {
490563d5b568SMichael Tuexen 					strq->next_mid_unordered++;
490663d5b568SMichael Tuexen 				} else {
490763d5b568SMichael Tuexen 					strq->next_mid_ordered++;
490863d5b568SMichael Tuexen 				}
490963d5b568SMichael Tuexen 			}
49100c0982b8SRandall Stewart 	oh_well:
49110c0982b8SRandall Stewart 			if (sp->data) {
49120c0982b8SRandall Stewart 				/*
4913f3b05218SMichael Tuexen 				 * Pull any data to free up the SB and allow
4914f3b05218SMichael Tuexen 				 * sender to "add more" while we will throw
4915f3b05218SMichael Tuexen 				 * away :-)
49160c0982b8SRandall Stewart 				 */
4917f3b05218SMichael Tuexen 				sctp_free_spbufspace(stcb, &stcb->asoc, sp);
49180c0982b8SRandall Stewart 				ret_sz += sp->length;
49190c0982b8SRandall Stewart 				do_wakeup_routine = 1;
49200c0982b8SRandall Stewart 				sp->some_taken = 1;
49210c0982b8SRandall Stewart 				sctp_m_freem(sp->data);
49220c0982b8SRandall Stewart 				sp->data = NULL;
49230c0982b8SRandall Stewart 				sp->tail_mbuf = NULL;
4924d07b2ac6SMichael Tuexen 				sp->length = 0;
49250c0982b8SRandall Stewart 			}
49260c0982b8SRandall Stewart 		}
49270c0982b8SRandall Stewart 		SCTP_TCB_SEND_UNLOCK(stcb);
49280c0982b8SRandall Stewart 	}
49290c0982b8SRandall Stewart 	if (do_wakeup_routine) {
49300c0982b8SRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
49318933fa13SRandall Stewart 		struct socket *so;
49328933fa13SRandall Stewart 
49330c0982b8SRandall Stewart 		so = SCTP_INP_SO(stcb->sctp_ep);
49340c0982b8SRandall Stewart 		if (!so_locked) {
49350c0982b8SRandall Stewart 			atomic_add_int(&stcb->asoc.refcnt, 1);
49360c0982b8SRandall Stewart 			SCTP_TCB_UNLOCK(stcb);
49370c0982b8SRandall Stewart 			SCTP_SOCKET_LOCK(so, 1);
49380c0982b8SRandall Stewart 			SCTP_TCB_LOCK(stcb);
49390c0982b8SRandall Stewart 			atomic_subtract_int(&stcb->asoc.refcnt, 1);
49400c0982b8SRandall Stewart 			if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
49410c0982b8SRandall Stewart 				/* assoc was freed while we were unlocked */
49420c0982b8SRandall Stewart 				SCTP_SOCKET_UNLOCK(so, 1);
49430c0982b8SRandall Stewart 				return (ret_sz);
49440c0982b8SRandall Stewart 			}
49450c0982b8SRandall Stewart 		}
49460c0982b8SRandall Stewart #endif
49470c0982b8SRandall Stewart 		sctp_sowwakeup(stcb->sctp_ep, stcb->sctp_socket);
49480c0982b8SRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
49490c0982b8SRandall Stewart 		if (!so_locked) {
49500c0982b8SRandall Stewart 			SCTP_SOCKET_UNLOCK(so, 1);
49510c0982b8SRandall Stewart 		}
49520c0982b8SRandall Stewart #endif
4953f8829a4aSRandall Stewart 	}
4954f8829a4aSRandall Stewart 	return (ret_sz);
4955f8829a4aSRandall Stewart }
4956f8829a4aSRandall Stewart 
4957f8829a4aSRandall Stewart /*
4958f8829a4aSRandall Stewart  * checks to see if the given address, sa, is one that is currently known by
4959f8829a4aSRandall Stewart  * the kernel note: can't distinguish the same address on multiple interfaces
4960f8829a4aSRandall Stewart  * and doesn't handle multiple addresses with different zone/scope id's note:
4961f8829a4aSRandall Stewart  * ifa_ifwithaddr() compares the entire sockaddr struct
4962f8829a4aSRandall Stewart  */
496342551e99SRandall Stewart struct sctp_ifa *
496480fefe0aSRandall Stewart sctp_find_ifa_in_ep(struct sctp_inpcb *inp, struct sockaddr *addr,
496580fefe0aSRandall Stewart     int holds_lock)
4966f8829a4aSRandall Stewart {
496742551e99SRandall Stewart 	struct sctp_laddr *laddr;
4968f8829a4aSRandall Stewart 
4969ad81507eSRandall Stewart 	if (holds_lock == 0) {
497042551e99SRandall Stewart 		SCTP_INP_RLOCK(inp);
4971ad81507eSRandall Stewart 	}
497242551e99SRandall Stewart 	LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
497342551e99SRandall Stewart 		if (laddr->ifa == NULL)
4974f8829a4aSRandall Stewart 			continue;
497542551e99SRandall Stewart 		if (addr->sa_family != laddr->ifa->address.sa.sa_family)
497642551e99SRandall Stewart 			continue;
4977e6194c2eSMichael Tuexen #ifdef INET
497842551e99SRandall Stewart 		if (addr->sa_family == AF_INET) {
497942551e99SRandall Stewart 			if (((struct sockaddr_in *)addr)->sin_addr.s_addr ==
498042551e99SRandall Stewart 			    laddr->ifa->address.sin.sin_addr.s_addr) {
498142551e99SRandall Stewart 				/* found him. */
4982ad81507eSRandall Stewart 				if (holds_lock == 0) {
498342551e99SRandall Stewart 					SCTP_INP_RUNLOCK(inp);
4984ad81507eSRandall Stewart 				}
498542551e99SRandall Stewart 				return (laddr->ifa);
498642551e99SRandall Stewart 				break;
498742551e99SRandall Stewart 			}
49885e2c2d87SRandall Stewart 		}
4989e6194c2eSMichael Tuexen #endif
49905e2c2d87SRandall Stewart #ifdef INET6
49915e2c2d87SRandall Stewart 		if (addr->sa_family == AF_INET6) {
4992c54a18d2SRandall Stewart 			if (SCTP6_ARE_ADDR_EQUAL((struct sockaddr_in6 *)addr,
4993c54a18d2SRandall Stewart 			    &laddr->ifa->address.sin6)) {
499442551e99SRandall Stewart 				/* found him. */
4995ad81507eSRandall Stewart 				if (holds_lock == 0) {
499642551e99SRandall Stewart 					SCTP_INP_RUNLOCK(inp);
4997ad81507eSRandall Stewart 				}
499842551e99SRandall Stewart 				return (laddr->ifa);
499942551e99SRandall Stewart 				break;
500042551e99SRandall Stewart 			}
500142551e99SRandall Stewart 		}
50025e2c2d87SRandall Stewart #endif
500342551e99SRandall Stewart 	}
5004ad81507eSRandall Stewart 	if (holds_lock == 0) {
500542551e99SRandall Stewart 		SCTP_INP_RUNLOCK(inp);
5006ad81507eSRandall Stewart 	}
500742551e99SRandall Stewart 	return (NULL);
500842551e99SRandall Stewart }
5009f8829a4aSRandall Stewart 
50106a27c376SRandall Stewart uint32_t
5011*b0471b4bSMichael Tuexen sctp_get_ifa_hash_val(struct sockaddr *addr)
5012*b0471b4bSMichael Tuexen {
5013ea5eba11SMichael Tuexen 	switch (addr->sa_family) {
5014ea5eba11SMichael Tuexen #ifdef INET
5015ea5eba11SMichael Tuexen 	case AF_INET:
5016ea5eba11SMichael Tuexen 		{
50176a27c376SRandall Stewart 			struct sockaddr_in *sin;
50186a27c376SRandall Stewart 
50196a27c376SRandall Stewart 			sin = (struct sockaddr_in *)addr;
50206a27c376SRandall Stewart 			return (sin->sin_addr.s_addr ^ (sin->sin_addr.s_addr >> 16));
5021ea5eba11SMichael Tuexen 		}
5022ea5eba11SMichael Tuexen #endif
5023ea5eba11SMichael Tuexen #ifdef INET6
50242c2e3218SMichael Tuexen 	case AF_INET6:
5025ea5eba11SMichael Tuexen 		{
50266a27c376SRandall Stewart 			struct sockaddr_in6 *sin6;
50276a27c376SRandall Stewart 			uint32_t hash_of_addr;
50286a27c376SRandall Stewart 
50296a27c376SRandall Stewart 			sin6 = (struct sockaddr_in6 *)addr;
50306a27c376SRandall Stewart 			hash_of_addr = (sin6->sin6_addr.s6_addr32[0] +
50316a27c376SRandall Stewart 			    sin6->sin6_addr.s6_addr32[1] +
50326a27c376SRandall Stewart 			    sin6->sin6_addr.s6_addr32[2] +
50336a27c376SRandall Stewart 			    sin6->sin6_addr.s6_addr32[3]);
50346a27c376SRandall Stewart 			hash_of_addr = (hash_of_addr ^ (hash_of_addr >> 16));
50356a27c376SRandall Stewart 			return (hash_of_addr);
50366a27c376SRandall Stewart 		}
5037ea5eba11SMichael Tuexen #endif
5038ea5eba11SMichael Tuexen 	default:
5039ea5eba11SMichael Tuexen 		break;
5040ea5eba11SMichael Tuexen 	}
50416a27c376SRandall Stewart 	return (0);
50426a27c376SRandall Stewart }
50436a27c376SRandall Stewart 
504442551e99SRandall Stewart struct sctp_ifa *
504542551e99SRandall Stewart sctp_find_ifa_by_addr(struct sockaddr *addr, uint32_t vrf_id, int holds_lock)
504642551e99SRandall Stewart {
504742551e99SRandall Stewart 	struct sctp_ifa *sctp_ifap;
504842551e99SRandall Stewart 	struct sctp_vrf *vrf;
50496a27c376SRandall Stewart 	struct sctp_ifalist *hash_head;
50506a27c376SRandall Stewart 	uint32_t hash_of_addr;
505142551e99SRandall Stewart 
505242551e99SRandall Stewart 	if (holds_lock == 0)
5053c99efcf6SRandall Stewart 		SCTP_IPI_ADDR_RLOCK();
505442551e99SRandall Stewart 
5055bff64a4dSRandall Stewart 	vrf = sctp_find_vrf(vrf_id);
5056bff64a4dSRandall Stewart 	if (vrf == NULL) {
5057bff64a4dSRandall Stewart 		if (holds_lock == 0)
5058c99efcf6SRandall Stewart 			SCTP_IPI_ADDR_RUNLOCK();
5059bff64a4dSRandall Stewart 		return (NULL);
5060bff64a4dSRandall Stewart 	}
5061bff64a4dSRandall Stewart 	hash_of_addr = sctp_get_ifa_hash_val(addr);
5062bff64a4dSRandall Stewart 
506317205eccSRandall Stewart 	hash_head = &vrf->vrf_addr_hash[(hash_of_addr & vrf->vrf_addr_hashmark)];
5064bff64a4dSRandall Stewart 	if (hash_head == NULL) {
5065ad81507eSRandall Stewart 		SCTP_PRINTF("hash_of_addr:%x mask:%x table:%x - ",
5066c99efcf6SRandall Stewart 		    hash_of_addr, (uint32_t)vrf->vrf_addr_hashmark,
5067c99efcf6SRandall Stewart 		    (uint32_t)(hash_of_addr & vrf->vrf_addr_hashmark));
5068bff64a4dSRandall Stewart 		sctp_print_address(addr);
5069ad81507eSRandall Stewart 		SCTP_PRINTF("No such bucket for address\n");
5070bff64a4dSRandall Stewart 		if (holds_lock == 0)
5071c99efcf6SRandall Stewart 			SCTP_IPI_ADDR_RUNLOCK();
5072bff64a4dSRandall Stewart 
5073bff64a4dSRandall Stewart 		return (NULL);
5074bff64a4dSRandall Stewart 	}
50756a27c376SRandall Stewart 	LIST_FOREACH(sctp_ifap, hash_head, next_bucket) {
50766a27c376SRandall Stewart 		if (addr->sa_family != sctp_ifap->address.sa.sa_family)
50776a27c376SRandall Stewart 			continue;
5078e6194c2eSMichael Tuexen #ifdef INET
50796a27c376SRandall Stewart 		if (addr->sa_family == AF_INET) {
50806a27c376SRandall Stewart 			if (((struct sockaddr_in *)addr)->sin_addr.s_addr ==
50816a27c376SRandall Stewart 			    sctp_ifap->address.sin.sin_addr.s_addr) {
50826a27c376SRandall Stewart 				/* found him. */
508342551e99SRandall Stewart 				if (holds_lock == 0)
5084c99efcf6SRandall Stewart 					SCTP_IPI_ADDR_RUNLOCK();
508542551e99SRandall Stewart 				return (sctp_ifap);
50866a27c376SRandall Stewart 				break;
50876a27c376SRandall Stewart 			}
50885e2c2d87SRandall Stewart 		}
5089e6194c2eSMichael Tuexen #endif
50905e2c2d87SRandall Stewart #ifdef INET6
50915e2c2d87SRandall Stewart 		if (addr->sa_family == AF_INET6) {
5092c54a18d2SRandall Stewart 			if (SCTP6_ARE_ADDR_EQUAL((struct sockaddr_in6 *)addr,
5093c54a18d2SRandall Stewart 			    &sctp_ifap->address.sin6)) {
50946a27c376SRandall Stewart 				/* found him. */
50956a27c376SRandall Stewart 				if (holds_lock == 0)
5096c99efcf6SRandall Stewart 					SCTP_IPI_ADDR_RUNLOCK();
50976a27c376SRandall Stewart 				return (sctp_ifap);
50986a27c376SRandall Stewart 				break;
50996a27c376SRandall Stewart 			}
510042551e99SRandall Stewart 		}
51015e2c2d87SRandall Stewart #endif
510242551e99SRandall Stewart 	}
510342551e99SRandall Stewart 	if (holds_lock == 0)
5104c99efcf6SRandall Stewart 		SCTP_IPI_ADDR_RUNLOCK();
5105f8829a4aSRandall Stewart 	return (NULL);
5106f8829a4aSRandall Stewart }
5107f8829a4aSRandall Stewart 
5108f8829a4aSRandall Stewart static void
51094c9179adSRandall Stewart sctp_user_rcvd(struct sctp_tcb *stcb, uint32_t *freed_so_far, int hold_rlock,
5110f8829a4aSRandall Stewart     uint32_t rwnd_req)
5111f8829a4aSRandall Stewart {
5112f8829a4aSRandall Stewart 	/* User pulled some data, do we need a rwnd update? */
5113f8829a4aSRandall Stewart 	int r_unlocked = 0;
5114f8829a4aSRandall Stewart 	uint32_t dif, rwnd;
5115f8829a4aSRandall Stewart 	struct socket *so = NULL;
5116f8829a4aSRandall Stewart 
5117f8829a4aSRandall Stewart 	if (stcb == NULL)
5118f8829a4aSRandall Stewart 		return;
5119f8829a4aSRandall Stewart 
512050cec919SRandall Stewart 	atomic_add_int(&stcb->asoc.refcnt, 1);
5121f8829a4aSRandall Stewart 
512262c1ff9cSRandall Stewart 	if (stcb->asoc.state & (SCTP_STATE_ABOUT_TO_BE_FREED |
512362c1ff9cSRandall Stewart 	    SCTP_STATE_SHUTDOWN_RECEIVED |
51244c9179adSRandall Stewart 	    SCTP_STATE_SHUTDOWN_ACK_SENT)) {
5125f8829a4aSRandall Stewart 		/* Pre-check If we are freeing no update */
5126f8829a4aSRandall Stewart 		goto no_lock;
5127f8829a4aSRandall Stewart 	}
5128f8829a4aSRandall Stewart 	SCTP_INP_INCR_REF(stcb->sctp_ep);
5129f8829a4aSRandall Stewart 	if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
5130f8829a4aSRandall Stewart 	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE)) {
5131f8829a4aSRandall Stewart 		goto out;
5132f8829a4aSRandall Stewart 	}
5133f8829a4aSRandall Stewart 	so = stcb->sctp_socket;
5134f8829a4aSRandall Stewart 	if (so == NULL) {
5135f8829a4aSRandall Stewart 		goto out;
5136f8829a4aSRandall Stewart 	}
5137f8829a4aSRandall Stewart 	atomic_add_int(&stcb->freed_by_sorcv_sincelast, *freed_so_far);
5138f8829a4aSRandall Stewart 	/* Have you have freed enough to look */
5139f8829a4aSRandall Stewart 	*freed_so_far = 0;
5140f8829a4aSRandall Stewart 	/* Yep, its worth a look and the lock overhead */
5141f8829a4aSRandall Stewart 
5142f8829a4aSRandall Stewart 	/* Figure out what the rwnd would be */
5143f8829a4aSRandall Stewart 	rwnd = sctp_calc_rwnd(stcb, &stcb->asoc);
5144f8829a4aSRandall Stewart 	if (rwnd >= stcb->asoc.my_last_reported_rwnd) {
5145f8829a4aSRandall Stewart 		dif = rwnd - stcb->asoc.my_last_reported_rwnd;
5146f8829a4aSRandall Stewart 	} else {
5147f8829a4aSRandall Stewart 		dif = 0;
5148f8829a4aSRandall Stewart 	}
5149f8829a4aSRandall Stewart 	if (dif >= rwnd_req) {
5150f8829a4aSRandall Stewart 		if (hold_rlock) {
5151f8829a4aSRandall Stewart 			SCTP_INP_READ_UNLOCK(stcb->sctp_ep);
5152f8829a4aSRandall Stewart 			r_unlocked = 1;
5153f8829a4aSRandall Stewart 		}
5154f8829a4aSRandall Stewart 		if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
5155f8829a4aSRandall Stewart 			/*
5156f8829a4aSRandall Stewart 			 * One last check before we allow the guy possibly
5157f8829a4aSRandall Stewart 			 * to get in. There is a race, where the guy has not
5158f8829a4aSRandall Stewart 			 * reached the gate. In that case
5159f8829a4aSRandall Stewart 			 */
5160f8829a4aSRandall Stewart 			goto out;
5161f8829a4aSRandall Stewart 		}
5162f8829a4aSRandall Stewart 		SCTP_TCB_LOCK(stcb);
5163f8829a4aSRandall Stewart 		if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
5164f8829a4aSRandall Stewart 			/* No reports here */
5165f8829a4aSRandall Stewart 			SCTP_TCB_UNLOCK(stcb);
5166f8829a4aSRandall Stewart 			goto out;
5167f8829a4aSRandall Stewart 		}
5168f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_wu_sacks_sent);
5169689e6a5fSMichael Tuexen 		sctp_send_sack(stcb, SCTP_SO_LOCKED);
5170830d754dSRandall Stewart 
5171f8829a4aSRandall Stewart 		sctp_chunk_output(stcb->sctp_ep, stcb,
5172ceaad40aSRandall Stewart 		    SCTP_OUTPUT_FROM_USR_RCVD, SCTP_SO_LOCKED);
5173f8829a4aSRandall Stewart 		/* make sure no timer is running */
5174ba785902SMichael Tuexen 		sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL,
5175ba785902SMichael Tuexen 		    SCTP_FROM_SCTPUTIL + SCTP_LOC_6);
5176f8829a4aSRandall Stewart 		SCTP_TCB_UNLOCK(stcb);
5177f8829a4aSRandall Stewart 	} else {
5178f8829a4aSRandall Stewart 		/* Update how much we have pending */
5179f8829a4aSRandall Stewart 		stcb->freed_by_sorcv_sincelast = dif;
5180f8829a4aSRandall Stewart 	}
5181f8829a4aSRandall Stewart out:
5182f8829a4aSRandall Stewart 	if (so && r_unlocked && hold_rlock) {
5183f8829a4aSRandall Stewart 		SCTP_INP_READ_LOCK(stcb->sctp_ep);
5184f8829a4aSRandall Stewart 	}
5185f8829a4aSRandall Stewart 	SCTP_INP_DECR_REF(stcb->sctp_ep);
5186f8829a4aSRandall Stewart no_lock:
518750cec919SRandall Stewart 	atomic_add_int(&stcb->asoc.refcnt, -1);
5188f8829a4aSRandall Stewart 	return;
5189f8829a4aSRandall Stewart }
5190f8829a4aSRandall Stewart 
5191f8829a4aSRandall Stewart int
5192f8829a4aSRandall Stewart sctp_sorecvmsg(struct socket *so,
5193f8829a4aSRandall Stewart     struct uio *uio,
5194f8829a4aSRandall Stewart     struct mbuf **mp,
5195f8829a4aSRandall Stewart     struct sockaddr *from,
5196f8829a4aSRandall Stewart     int fromlen,
5197f8829a4aSRandall Stewart     int *msg_flags,
5198f8829a4aSRandall Stewart     struct sctp_sndrcvinfo *sinfo,
5199f8829a4aSRandall Stewart     int filling_sinfo)
5200f8829a4aSRandall Stewart {
5201f8829a4aSRandall Stewart 	/*
5202f8829a4aSRandall Stewart 	 * MSG flags we will look at MSG_DONTWAIT - non-blocking IO.
5203f8829a4aSRandall Stewart 	 * MSG_PEEK - Look don't touch :-D (only valid with OUT mbuf copy
5204f8829a4aSRandall Stewart 	 * mp=NULL thus uio is the copy method to userland) MSG_WAITALL - ??
5205f8829a4aSRandall Stewart 	 * On the way out we may send out any combination of:
5206f8829a4aSRandall Stewart 	 * MSG_NOTIFICATION MSG_EOR
5207f8829a4aSRandall Stewart 	 *
5208f8829a4aSRandall Stewart 	 */
5209f8829a4aSRandall Stewart 	struct sctp_inpcb *inp = NULL;
5210f8829a4aSRandall Stewart 	int my_len = 0;
5211f8829a4aSRandall Stewart 	int cp_len = 0, error = 0;
5212f8829a4aSRandall Stewart 	struct sctp_queued_to_read *control = NULL, *ctl = NULL, *nxt = NULL;
521394b0d969SMichael Tuexen 	struct mbuf *m = NULL;
5214f8829a4aSRandall Stewart 	struct sctp_tcb *stcb = NULL;
5215f8829a4aSRandall Stewart 	int wakeup_read_socket = 0;
5216f8829a4aSRandall Stewart 	int freecnt_applied = 0;
5217f8829a4aSRandall Stewart 	int out_flags = 0, in_flags = 0;
5218f8829a4aSRandall Stewart 	int block_allowed = 1;
52194c9179adSRandall Stewart 	uint32_t freed_so_far = 0;
522081aca91aSRandall Stewart 	uint32_t copied_so_far = 0;
522193164cf9SRandall Stewart 	int in_eeor_mode = 0;
5222f8829a4aSRandall Stewart 	int no_rcv_needed = 0;
5223f8829a4aSRandall Stewart 	uint32_t rwnd_req = 0;
5224f8829a4aSRandall Stewart 	int hold_sblock = 0;
5225f8829a4aSRandall Stewart 	int hold_rlock = 0;
52269a8e3088SMichael Tuexen 	ssize_t slen = 0;
52274c9179adSRandall Stewart 	uint32_t held_length = 0;
52287abab911SRobert Watson 	int sockbuf_lock = 0;
5229f8829a4aSRandall Stewart 
523017205eccSRandall Stewart 	if (uio == NULL) {
5231c4739e2fSRandall Stewart 		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
523217205eccSRandall Stewart 		return (EINVAL);
523317205eccSRandall Stewart 	}
5234f8829a4aSRandall Stewart 	if (msg_flags) {
5235f8829a4aSRandall Stewart 		in_flags = *msg_flags;
5236c105859eSRandall Stewart 		if (in_flags & MSG_PEEK)
5237c105859eSRandall Stewart 			SCTP_STAT_INCR(sctps_read_peeks);
5238f8829a4aSRandall Stewart 	} else {
5239f8829a4aSRandall Stewart 		in_flags = 0;
5240f8829a4aSRandall Stewart 	}
5241f8829a4aSRandall Stewart 	slen = uio->uio_resid;
524217205eccSRandall Stewart 
5243f8829a4aSRandall Stewart 	/* Pull in and set up our int flags */
5244f8829a4aSRandall Stewart 	if (in_flags & MSG_OOB) {
5245f8829a4aSRandall Stewart 		/* Out of band's NOT supported */
5246f8829a4aSRandall Stewart 		return (EOPNOTSUPP);
5247f8829a4aSRandall Stewart 	}
5248f8829a4aSRandall Stewart 	if ((in_flags & MSG_PEEK) && (mp != NULL)) {
5249c4739e2fSRandall Stewart 		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
5250f8829a4aSRandall Stewart 		return (EINVAL);
5251f8829a4aSRandall Stewart 	}
5252f8829a4aSRandall Stewart 	if ((in_flags & (MSG_DONTWAIT
5253f8829a4aSRandall Stewart 	    | MSG_NBIO
5254f8829a4aSRandall Stewart 	    )) ||
525542551e99SRandall Stewart 	    SCTP_SO_IS_NBIO(so)) {
5256f8829a4aSRandall Stewart 		block_allowed = 0;
5257f8829a4aSRandall Stewart 	}
5258f8829a4aSRandall Stewart 	/* setup the endpoint */
5259f8829a4aSRandall Stewart 	inp = (struct sctp_inpcb *)so->so_pcb;
5260f8829a4aSRandall Stewart 	if (inp == NULL) {
5261c4739e2fSRandall Stewart 		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EFAULT);
5262f8829a4aSRandall Stewart 		return (EFAULT);
5263f8829a4aSRandall Stewart 	}
526462c1ff9cSRandall Stewart 	rwnd_req = (SCTP_SB_LIMIT_RCV(so) >> SCTP_RWND_HIWAT_SHIFT);
5265f8829a4aSRandall Stewart 	/* Must be at least a MTU's worth */
5266f8829a4aSRandall Stewart 	if (rwnd_req < SCTP_MIN_RWND)
5267f8829a4aSRandall Stewart 		rwnd_req = SCTP_MIN_RWND;
5268f8829a4aSRandall Stewart 	in_eeor_mode = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR);
5269b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RECV_RWND_LOGGING_ENABLE) {
5270f8829a4aSRandall Stewart 		sctp_misc_ints(SCTP_SORECV_ENTER,
52719a8e3088SMichael Tuexen 		    rwnd_req, in_eeor_mode, so->so_rcv.sb_cc, (uint32_t)uio->uio_resid);
527280fefe0aSRandall Stewart 	}
5273b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RECV_RWND_LOGGING_ENABLE) {
5274f8829a4aSRandall Stewart 		sctp_misc_ints(SCTP_SORECV_ENTERPL,
52759a8e3088SMichael Tuexen 		    rwnd_req, block_allowed, so->so_rcv.sb_cc, (uint32_t)uio->uio_resid);
527680fefe0aSRandall Stewart 	}
5277265de5bbSRobert Watson 	error = sblock(&so->so_rcv, (block_allowed ? SBL_WAIT : 0));
5278f8829a4aSRandall Stewart 	if (error) {
5279f8829a4aSRandall Stewart 		goto release_unlocked;
5280f8829a4aSRandall Stewart 	}
52818e1e6e5fSMateusz Guzik 	sockbuf_lock = 1;
5282f8829a4aSRandall Stewart restart:
52837abab911SRobert Watson 
5284f8829a4aSRandall Stewart 
5285f8829a4aSRandall Stewart restart_nosblocks:
5286f8829a4aSRandall Stewart 	if (hold_sblock == 0) {
5287f8829a4aSRandall Stewart 		SOCKBUF_LOCK(&so->so_rcv);
5288f8829a4aSRandall Stewart 		hold_sblock = 1;
5289f8829a4aSRandall Stewart 	}
5290f8829a4aSRandall Stewart 	if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
5291f8829a4aSRandall Stewart 	    (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE)) {
5292f8829a4aSRandall Stewart 		goto out;
5293f8829a4aSRandall Stewart 	}
52944e88d37aSMichael Tuexen 	if ((so->so_rcv.sb_state & SBS_CANTRCVMORE) && (so->so_rcv.sb_cc == 0)) {
5295f8829a4aSRandall Stewart 		if (so->so_error) {
5296f8829a4aSRandall Stewart 			error = so->so_error;
529744b7479bSRandall Stewart 			if ((in_flags & MSG_PEEK) == 0)
529844b7479bSRandall Stewart 				so->so_error = 0;
52999f22f500SRandall Stewart 			goto out;
5300f8829a4aSRandall Stewart 		} else {
53014e88d37aSMichael Tuexen 			if (so->so_rcv.sb_cc == 0) {
53027924093fSRandall Stewart 				/* indicate EOF */
53037924093fSRandall Stewart 				error = 0;
5304f8829a4aSRandall Stewart 				goto out;
5305f8829a4aSRandall Stewart 			}
53069f22f500SRandall Stewart 		}
53079f22f500SRandall Stewart 	}
53089de217ceSMichael Tuexen 	if (so->so_rcv.sb_cc <= held_length) {
53099de217ceSMichael Tuexen 		if (so->so_error) {
53109de217ceSMichael Tuexen 			error = so->so_error;
53119de217ceSMichael Tuexen 			if ((in_flags & MSG_PEEK) == 0) {
53129de217ceSMichael Tuexen 				so->so_error = 0;
53139de217ceSMichael Tuexen 			}
53149de217ceSMichael Tuexen 			goto out;
53159de217ceSMichael Tuexen 		}
53164e88d37aSMichael Tuexen 		if ((so->so_rcv.sb_cc == 0) &&
5317f8829a4aSRandall Stewart 		    ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5318f8829a4aSRandall Stewart 		    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) {
5319f8829a4aSRandall Stewart 			if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0) {
5320f8829a4aSRandall Stewart 				/*
5321f8829a4aSRandall Stewart 				 * For active open side clear flags for
5322f8829a4aSRandall Stewart 				 * re-use passive open is blocked by
5323f8829a4aSRandall Stewart 				 * connect.
5324f8829a4aSRandall Stewart 				 */
5325f8829a4aSRandall Stewart 				if (inp->sctp_flags & SCTP_PCB_FLAGS_WAS_ABORTED) {
5326b7b84c0eSMichael Tuexen 					/*
5327b7b84c0eSMichael Tuexen 					 * You were aborted, passive side
5328b7b84c0eSMichael Tuexen 					 * always hits here
5329b7b84c0eSMichael Tuexen 					 */
5330c4739e2fSRandall Stewart 					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET);
5331f8829a4aSRandall Stewart 					error = ECONNRESET;
5332f8829a4aSRandall Stewart 				}
5333f8829a4aSRandall Stewart 				so->so_state &= ~(SS_ISCONNECTING |
5334f8829a4aSRandall Stewart 				    SS_ISDISCONNECTING |
5335f8829a4aSRandall Stewart 				    SS_ISCONFIRMING |
5336f8829a4aSRandall Stewart 				    SS_ISCONNECTED);
5337f8829a4aSRandall Stewart 				if (error == 0) {
5338f8829a4aSRandall Stewart 					if ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) == 0) {
5339c4739e2fSRandall Stewart 						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOTCONN);
5340f8829a4aSRandall Stewart 						error = ENOTCONN;
5341f8829a4aSRandall Stewart 					}
5342f8829a4aSRandall Stewart 				}
5343f8829a4aSRandall Stewart 				goto out;
5344f8829a4aSRandall Stewart 			}
5345f8829a4aSRandall Stewart 		}
53469de217ceSMichael Tuexen 		if (block_allowed) {
5347f8829a4aSRandall Stewart 			error = sbwait(&so->so_rcv);
5348f8829a4aSRandall Stewart 			if (error) {
5349f8829a4aSRandall Stewart 				goto out;
5350f8829a4aSRandall Stewart 			}
5351f8829a4aSRandall Stewart 			held_length = 0;
5352f8829a4aSRandall Stewart 			goto restart_nosblocks;
535344b7479bSRandall Stewart 		} else {
5354c4739e2fSRandall Stewart 			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EWOULDBLOCK);
5355f8829a4aSRandall Stewart 			error = EWOULDBLOCK;
5356f8829a4aSRandall Stewart 			goto out;
5357f8829a4aSRandall Stewart 		}
53589de217ceSMichael Tuexen 	}
5359d06c82f1SRandall Stewart 	if (hold_sblock == 1) {
5360d06c82f1SRandall Stewart 		SOCKBUF_UNLOCK(&so->so_rcv);
5361d06c82f1SRandall Stewart 		hold_sblock = 0;
5362d06c82f1SRandall Stewart 	}
5363f8829a4aSRandall Stewart 	/* we possibly have data we can read */
53643c503c28SRandall Stewart 	/* sa_ignore FREED_MEMORY */
5365f8829a4aSRandall Stewart 	control = TAILQ_FIRST(&inp->read_queue);
5366f8829a4aSRandall Stewart 	if (control == NULL) {
5367f8829a4aSRandall Stewart 		/*
5368f8829a4aSRandall Stewart 		 * This could be happening since the appender did the
5369f8829a4aSRandall Stewart 		 * increment but as not yet did the tailq insert onto the
5370f8829a4aSRandall Stewart 		 * read_queue
5371f8829a4aSRandall Stewart 		 */
5372f8829a4aSRandall Stewart 		if (hold_rlock == 0) {
5373f8829a4aSRandall Stewart 			SCTP_INP_READ_LOCK(inp);
5374f8829a4aSRandall Stewart 		}
5375f8829a4aSRandall Stewart 		control = TAILQ_FIRST(&inp->read_queue);
53764e88d37aSMichael Tuexen 		if ((control == NULL) && (so->so_rcv.sb_cc != 0)) {
5377a5d547adSRandall Stewart #ifdef INVARIANTS
5378f8829a4aSRandall Stewart 			panic("Huh, its non zero and nothing on control?");
5379f8829a4aSRandall Stewart #endif
53804e88d37aSMichael Tuexen 			so->so_rcv.sb_cc = 0;
5381f8829a4aSRandall Stewart 		}
5382f8829a4aSRandall Stewart 		SCTP_INP_READ_UNLOCK(inp);
5383f8829a4aSRandall Stewart 		hold_rlock = 0;
5384f8829a4aSRandall Stewart 		goto restart;
5385f8829a4aSRandall Stewart 	}
5386f8829a4aSRandall Stewart 	if ((control->length == 0) &&
5387f8829a4aSRandall Stewart 	    (control->do_not_ref_stcb)) {
5388f8829a4aSRandall Stewart 		/*
5389f8829a4aSRandall Stewart 		 * Clean up code for freeing assoc that left behind a
5390f8829a4aSRandall Stewart 		 * pdapi.. maybe a peer in EEOR that just closed after
5391f8829a4aSRandall Stewart 		 * sending and never indicated a EOR.
5392f8829a4aSRandall Stewart 		 */
5393f8829a4aSRandall Stewart 		if (hold_rlock == 0) {
5394f8829a4aSRandall Stewart 			hold_rlock = 1;
5395f8829a4aSRandall Stewart 			SCTP_INP_READ_LOCK(inp);
5396f8829a4aSRandall Stewart 		}
5397f8829a4aSRandall Stewart 		control->held_length = 0;
5398f8829a4aSRandall Stewart 		if (control->data) {
5399f8829a4aSRandall Stewart 			/* Hmm there is data here .. fix */
54004c9179adSRandall Stewart 			struct mbuf *m_tmp;
5401f8829a4aSRandall Stewart 			int cnt = 0;
5402f8829a4aSRandall Stewart 
54034c9179adSRandall Stewart 			m_tmp = control->data;
54044c9179adSRandall Stewart 			while (m_tmp) {
54054c9179adSRandall Stewart 				cnt += SCTP_BUF_LEN(m_tmp);
54064c9179adSRandall Stewart 				if (SCTP_BUF_NEXT(m_tmp) == NULL) {
54074c9179adSRandall Stewart 					control->tail_mbuf = m_tmp;
5408f8829a4aSRandall Stewart 					control->end_added = 1;
5409f8829a4aSRandall Stewart 				}
54104c9179adSRandall Stewart 				m_tmp = SCTP_BUF_NEXT(m_tmp);
5411f8829a4aSRandall Stewart 			}
5412f8829a4aSRandall Stewart 			control->length = cnt;
5413f8829a4aSRandall Stewart 		} else {
5414f8829a4aSRandall Stewart 			/* remove it */
5415f8829a4aSRandall Stewart 			TAILQ_REMOVE(&inp->read_queue, control, next);
5416f8829a4aSRandall Stewart 			/* Add back any hiddend data */
5417f8829a4aSRandall Stewart 			sctp_free_remote_addr(control->whoFrom);
5418f8829a4aSRandall Stewart 			sctp_free_a_readq(stcb, control);
5419f8829a4aSRandall Stewart 		}
5420f8829a4aSRandall Stewart 		if (hold_rlock) {
5421f8829a4aSRandall Stewart 			hold_rlock = 0;
5422f8829a4aSRandall Stewart 			SCTP_INP_READ_UNLOCK(inp);
5423f8829a4aSRandall Stewart 		}
5424f8829a4aSRandall Stewart 		goto restart;
5425f8829a4aSRandall Stewart 	}
5426810ec536SMichael Tuexen 	if ((control->length == 0) &&
5427810ec536SMichael Tuexen 	    (control->end_added == 1)) {
5428b7b84c0eSMichael Tuexen 		/*
5429b7b84c0eSMichael Tuexen 		 * Do we also need to check for (control->pdapi_aborted ==
5430b7b84c0eSMichael Tuexen 		 * 1)?
5431b7b84c0eSMichael Tuexen 		 */
5432810ec536SMichael Tuexen 		if (hold_rlock == 0) {
5433810ec536SMichael Tuexen 			hold_rlock = 1;
5434810ec536SMichael Tuexen 			SCTP_INP_READ_LOCK(inp);
5435810ec536SMichael Tuexen 		}
5436810ec536SMichael Tuexen 		TAILQ_REMOVE(&inp->read_queue, control, next);
5437810ec536SMichael Tuexen 		if (control->data) {
5438810ec536SMichael Tuexen #ifdef INVARIANTS
5439810ec536SMichael Tuexen 			panic("control->data not null but control->length == 0");
5440810ec536SMichael Tuexen #else
5441810ec536SMichael Tuexen 			SCTP_PRINTF("Strange, data left in the control buffer. Cleaning up.\n");
5442810ec536SMichael Tuexen 			sctp_m_freem(control->data);
5443810ec536SMichael Tuexen 			control->data = NULL;
5444810ec536SMichael Tuexen #endif
5445810ec536SMichael Tuexen 		}
5446810ec536SMichael Tuexen 		if (control->aux_data) {
5447810ec536SMichael Tuexen 			sctp_m_free(control->aux_data);
5448810ec536SMichael Tuexen 			control->aux_data = NULL;
5449810ec536SMichael Tuexen 		}
545098d5fd97SMichael Tuexen #ifdef INVARIANTS
545144249214SRandall Stewart 		if (control->on_strm_q) {
545244249214SRandall Stewart 			panic("About to free ctl:%p so:%p and its in %d",
545344249214SRandall Stewart 			    control, so, control->on_strm_q);
545444249214SRandall Stewart 		}
545598d5fd97SMichael Tuexen #endif
5456810ec536SMichael Tuexen 		sctp_free_remote_addr(control->whoFrom);
5457810ec536SMichael Tuexen 		sctp_free_a_readq(stcb, control);
5458810ec536SMichael Tuexen 		if (hold_rlock) {
5459810ec536SMichael Tuexen 			hold_rlock = 0;
5460810ec536SMichael Tuexen 			SCTP_INP_READ_UNLOCK(inp);
5461810ec536SMichael Tuexen 		}
5462810ec536SMichael Tuexen 		goto restart;
5463810ec536SMichael Tuexen 	}
5464f8829a4aSRandall Stewart 	if (control->length == 0) {
5465f8829a4aSRandall Stewart 		if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) &&
5466f8829a4aSRandall Stewart 		    (filling_sinfo)) {
5467f8829a4aSRandall Stewart 			/* find a more suitable one then this */
5468f8829a4aSRandall Stewart 			ctl = TAILQ_NEXT(control, next);
5469f8829a4aSRandall Stewart 			while (ctl) {
54709a6142d8SRandall Stewart 				if ((ctl->stcb != control->stcb) && (ctl->length) &&
54719a6142d8SRandall Stewart 				    (ctl->some_taken ||
54726114cd96SRandall Stewart 				    (ctl->spec_flags & M_NOTIFICATION) ||
54739a6142d8SRandall Stewart 				    ((ctl->do_not_ref_stcb == 0) &&
54749a6142d8SRandall Stewart 				    (ctl->stcb->asoc.strmin[ctl->sinfo_stream].delivery_started == 0)))
54759a6142d8SRandall Stewart 				    ) {
54769a6142d8SRandall Stewart 					/*-
54779a6142d8SRandall Stewart 					 * If we have a different TCB next, and there is data
54789a6142d8SRandall Stewart 					 * present. If we have already taken some (pdapi), OR we can
54799a6142d8SRandall Stewart 					 * ref the tcb and no delivery as started on this stream, we
548017205eccSRandall Stewart 					 * take it. Note we allow a notification on a different
548117205eccSRandall Stewart 					 * assoc to be delivered..
54829a6142d8SRandall Stewart 					 */
54839a6142d8SRandall Stewart 					control = ctl;
54849a6142d8SRandall Stewart 					goto found_one;
54859a6142d8SRandall Stewart 				} else if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS)) &&
54869a6142d8SRandall Stewart 					    (ctl->length) &&
54879a6142d8SRandall Stewart 					    ((ctl->some_taken) ||
54889a6142d8SRandall Stewart 					    ((ctl->do_not_ref_stcb == 0) &&
548917205eccSRandall Stewart 					    ((ctl->spec_flags & M_NOTIFICATION) == 0) &&
5490b5c16493SMichael Tuexen 				    (ctl->stcb->asoc.strmin[ctl->sinfo_stream].delivery_started == 0)))) {
54919a6142d8SRandall Stewart 					/*-
54929a6142d8SRandall Stewart 					 * If we have the same tcb, and there is data present, and we
54939a6142d8SRandall Stewart 					 * have the strm interleave feature present. Then if we have
54949a6142d8SRandall Stewart 					 * taken some (pdapi) or we can refer to tht tcb AND we have
54959a6142d8SRandall Stewart 					 * not started a delivery for this stream, we can take it.
549617205eccSRandall Stewart 					 * Note we do NOT allow a notificaiton on the same assoc to
549717205eccSRandall Stewart 					 * be delivered.
54989a6142d8SRandall Stewart 					 */
5499f8829a4aSRandall Stewart 					control = ctl;
5500f8829a4aSRandall Stewart 					goto found_one;
5501f8829a4aSRandall Stewart 				}
5502f8829a4aSRandall Stewart 				ctl = TAILQ_NEXT(ctl, next);
5503f8829a4aSRandall Stewart 			}
5504f8829a4aSRandall Stewart 		}
5505f8829a4aSRandall Stewart 		/*
5506f8829a4aSRandall Stewart 		 * if we reach here, not suitable replacement is available
55074e88d37aSMichael Tuexen 		 * <or> fragment interleave is NOT on. So stuff the sb_cc
5508f8829a4aSRandall Stewart 		 * into the our held count, and its time to sleep again.
5509f8829a4aSRandall Stewart 		 */
55104e88d37aSMichael Tuexen 		held_length = so->so_rcv.sb_cc;
55114e88d37aSMichael Tuexen 		control->held_length = so->so_rcv.sb_cc;
5512f8829a4aSRandall Stewart 		goto restart;
5513f8829a4aSRandall Stewart 	}
5514f8829a4aSRandall Stewart 	/* Clear the held length since there is something to read */
5515f8829a4aSRandall Stewart 	control->held_length = 0;
5516f8829a4aSRandall Stewart found_one:
5517f8829a4aSRandall Stewart 	/*
5518f8829a4aSRandall Stewart 	 * If we reach here, control has a some data for us to read off.
5519f8829a4aSRandall Stewart 	 * Note that stcb COULD be NULL.
5520f8829a4aSRandall Stewart 	 */
55219c5ca6f2SMichael Tuexen 	if (hold_rlock == 0) {
55229c5ca6f2SMichael Tuexen 		hold_rlock = 1;
55239c5ca6f2SMichael Tuexen 		SCTP_INP_READ_LOCK(inp);
5524f8829a4aSRandall Stewart 	}
55259c5ca6f2SMichael Tuexen 	control->some_taken++;
5526f8829a4aSRandall Stewart 	stcb = control->stcb;
5527f8829a4aSRandall Stewart 	if (stcb) {
55280696e120SRandall Stewart 		if ((control->do_not_ref_stcb == 0) &&
55290696e120SRandall Stewart 		    (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED)) {
553050cec919SRandall Stewart 			if (freecnt_applied == 0)
5531f8829a4aSRandall Stewart 				stcb = NULL;
5532f8829a4aSRandall Stewart 		} else if (control->do_not_ref_stcb == 0) {
5533f8829a4aSRandall Stewart 			/* you can't free it on me please */
5534f8829a4aSRandall Stewart 			/*
5535f8829a4aSRandall Stewart 			 * The lock on the socket buffer protects us so the
5536f8829a4aSRandall Stewart 			 * free code will stop. But since we used the
5537f8829a4aSRandall Stewart 			 * socketbuf lock and the sender uses the tcb_lock
5538f8829a4aSRandall Stewart 			 * to increment, we need to use the atomic add to
5539f8829a4aSRandall Stewart 			 * the refcnt
5540f8829a4aSRandall Stewart 			 */
5541d55b0b1bSRandall Stewart 			if (freecnt_applied) {
5542d55b0b1bSRandall Stewart #ifdef INVARIANTS
5543207304d4SRandall Stewart 				panic("refcnt already incremented");
5544d55b0b1bSRandall Stewart #else
5545cd3fd531SMichael Tuexen 				SCTP_PRINTF("refcnt already incremented?\n");
5546d55b0b1bSRandall Stewart #endif
5547d55b0b1bSRandall Stewart 			} else {
554850cec919SRandall Stewart 				atomic_add_int(&stcb->asoc.refcnt, 1);
5549f8829a4aSRandall Stewart 				freecnt_applied = 1;
5550d55b0b1bSRandall Stewart 			}
5551f8829a4aSRandall Stewart 			/*
5552f8829a4aSRandall Stewart 			 * Setup to remember how much we have not yet told
5553f8829a4aSRandall Stewart 			 * the peer our rwnd has opened up. Note we grab the
5554f8829a4aSRandall Stewart 			 * value from the tcb from last time. Note too that
55550696e120SRandall Stewart 			 * sack sending clears this when a sack is sent,
5556f8829a4aSRandall Stewart 			 * which is fine. Once we hit the rwnd_req, we then
5557f8829a4aSRandall Stewart 			 * will go to the sctp_user_rcvd() that will not
5558f8829a4aSRandall Stewart 			 * lock until it KNOWs it MUST send a WUP-SACK.
5559f8829a4aSRandall Stewart 			 */
5560f8829a4aSRandall Stewart 			freed_so_far = stcb->freed_by_sorcv_sincelast;
5561f8829a4aSRandall Stewart 			stcb->freed_by_sorcv_sincelast = 0;
5562f8829a4aSRandall Stewart 		}
5563f8829a4aSRandall Stewart 	}
55646114cd96SRandall Stewart 	if (stcb &&
55656114cd96SRandall Stewart 	    ((control->spec_flags & M_NOTIFICATION) == 0) &&
55666114cd96SRandall Stewart 	    control->do_not_ref_stcb == 0) {
5567d06c82f1SRandall Stewart 		stcb->asoc.strmin[control->sinfo_stream].delivery_started = 1;
5568d06c82f1SRandall Stewart 	}
5569f8829a4aSRandall Stewart 	/* First lets get off the sinfo and sockaddr info */
55705f05199cSMichael Tuexen 	if ((sinfo != NULL) && (filling_sinfo != 0)) {
55715f05199cSMichael Tuexen 		sinfo->sinfo_stream = control->sinfo_stream;
557249656eefSMichael Tuexen 		sinfo->sinfo_ssn = (uint16_t)control->mid;
55735f05199cSMichael Tuexen 		sinfo->sinfo_flags = control->sinfo_flags;
55745f05199cSMichael Tuexen 		sinfo->sinfo_ppid = control->sinfo_ppid;
55755f05199cSMichael Tuexen 		sinfo->sinfo_context = control->sinfo_context;
55765f05199cSMichael Tuexen 		sinfo->sinfo_timetolive = control->sinfo_timetolive;
55775f05199cSMichael Tuexen 		sinfo->sinfo_tsn = control->sinfo_tsn;
55785f05199cSMichael Tuexen 		sinfo->sinfo_cumtsn = control->sinfo_cumtsn;
55795f05199cSMichael Tuexen 		sinfo->sinfo_assoc_id = control->sinfo_assoc_id;
5580f8829a4aSRandall Stewart 		nxt = TAILQ_NEXT(control, next);
5581e2e7c62eSMichael Tuexen 		if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO) ||
5582e2e7c62eSMichael Tuexen 		    sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO)) {
5583f8829a4aSRandall Stewart 			struct sctp_extrcvinfo *s_extra;
5584f8829a4aSRandall Stewart 
5585f8829a4aSRandall Stewart 			s_extra = (struct sctp_extrcvinfo *)sinfo;
55869a6142d8SRandall Stewart 			if ((nxt) &&
55879a6142d8SRandall Stewart 			    (nxt->length)) {
5588b70b526dSMichael Tuexen 				s_extra->serinfo_next_flags = SCTP_NEXT_MSG_AVAIL;
5589f8829a4aSRandall Stewart 				if (nxt->sinfo_flags & SCTP_UNORDERED) {
5590b70b526dSMichael Tuexen 					s_extra->serinfo_next_flags |= SCTP_NEXT_MSG_IS_UNORDERED;
5591f8829a4aSRandall Stewart 				}
5592f42a358aSRandall Stewart 				if (nxt->spec_flags & M_NOTIFICATION) {
5593b70b526dSMichael Tuexen 					s_extra->serinfo_next_flags |= SCTP_NEXT_MSG_IS_NOTIFICATION;
5594f42a358aSRandall Stewart 				}
5595b70b526dSMichael Tuexen 				s_extra->serinfo_next_aid = nxt->sinfo_assoc_id;
5596b70b526dSMichael Tuexen 				s_extra->serinfo_next_length = nxt->length;
5597b70b526dSMichael Tuexen 				s_extra->serinfo_next_ppid = nxt->sinfo_ppid;
5598b70b526dSMichael Tuexen 				s_extra->serinfo_next_stream = nxt->sinfo_stream;
5599f8829a4aSRandall Stewart 				if (nxt->tail_mbuf != NULL) {
5600139bc87fSRandall Stewart 					if (nxt->end_added) {
5601b70b526dSMichael Tuexen 						s_extra->serinfo_next_flags |= SCTP_NEXT_MSG_ISCOMPLETE;
5602f8829a4aSRandall Stewart 					}
5603f8829a4aSRandall Stewart 				}
5604f8829a4aSRandall Stewart 			} else {
5605f8829a4aSRandall Stewart 				/*
5606f8829a4aSRandall Stewart 				 * we explicitly 0 this, since the memcpy
5607f8829a4aSRandall Stewart 				 * got some other things beyond the older
5608f8829a4aSRandall Stewart 				 * sinfo_ that is on the control's structure
5609f8829a4aSRandall Stewart 				 * :-D
5610f8829a4aSRandall Stewart 				 */
56119a6142d8SRandall Stewart 				nxt = NULL;
5612b70b526dSMichael Tuexen 				s_extra->serinfo_next_flags = SCTP_NO_NEXT_MSG;
5613b70b526dSMichael Tuexen 				s_extra->serinfo_next_aid = 0;
5614b70b526dSMichael Tuexen 				s_extra->serinfo_next_length = 0;
5615b70b526dSMichael Tuexen 				s_extra->serinfo_next_ppid = 0;
5616b70b526dSMichael Tuexen 				s_extra->serinfo_next_stream = 0;
5617f8829a4aSRandall Stewart 			}
5618f8829a4aSRandall Stewart 		}
5619f8829a4aSRandall Stewart 		/*
5620f8829a4aSRandall Stewart 		 * update off the real current cum-ack, if we have an stcb.
5621f8829a4aSRandall Stewart 		 */
56220696e120SRandall Stewart 		if ((control->do_not_ref_stcb == 0) && stcb)
5623f8829a4aSRandall Stewart 			sinfo->sinfo_cumtsn = stcb->asoc.cumulative_tsn;
5624f8829a4aSRandall Stewart 		/*
5625f8829a4aSRandall Stewart 		 * mask off the high bits, we keep the actual chunk bits in
5626f8829a4aSRandall Stewart 		 * there.
5627f8829a4aSRandall Stewart 		 */
5628f8829a4aSRandall Stewart 		sinfo->sinfo_flags &= 0x00ff;
56295f26a41dSRandall Stewart 		if ((control->sinfo_flags >> 8) & SCTP_DATA_UNORDERED) {
56305f26a41dSRandall Stewart 			sinfo->sinfo_flags |= SCTP_UNORDERED;
56315f26a41dSRandall Stewart 		}
5632f8829a4aSRandall Stewart 	}
563318e198d3SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS
563418e198d3SRandall Stewart 	{
563518e198d3SRandall Stewart 		int index, newindex;
563618e198d3SRandall Stewart 		struct sctp_pcbtsn_rlog *entry;
563718e198d3SRandall Stewart 
563818e198d3SRandall Stewart 		do {
563918e198d3SRandall Stewart 			index = inp->readlog_index;
564018e198d3SRandall Stewart 			newindex = index + 1;
564118e198d3SRandall Stewart 			if (newindex >= SCTP_READ_LOG_SIZE) {
564218e198d3SRandall Stewart 				newindex = 0;
564318e198d3SRandall Stewart 			}
564418e198d3SRandall Stewart 		} while (atomic_cmpset_int(&inp->readlog_index, index, newindex) == 0);
564518e198d3SRandall Stewart 		entry = &inp->readlog[index];
564618e198d3SRandall Stewart 		entry->vtag = control->sinfo_assoc_id;
564718e198d3SRandall Stewart 		entry->strm = control->sinfo_stream;
564849656eefSMichael Tuexen 		entry->seq = (uint16_t)control->mid;
564918e198d3SRandall Stewart 		entry->sz = control->length;
565018e198d3SRandall Stewart 		entry->flgs = control->sinfo_flags;
565118e198d3SRandall Stewart 	}
565218e198d3SRandall Stewart #endif
5653d59107f7SMichael Tuexen 	if ((fromlen > 0) && (from != NULL)) {
5654d59107f7SMichael Tuexen 		union sctp_sockstore store;
5655d59107f7SMichael Tuexen 		size_t len;
5656d59107f7SMichael Tuexen 
5657b5b6e5c2SMichael Tuexen 		switch (control->whoFrom->ro._l_addr.sa.sa_family) {
5658b5b6e5c2SMichael Tuexen #ifdef INET6
5659b5b6e5c2SMichael Tuexen 		case AF_INET6:
5660d59107f7SMichael Tuexen 			len = sizeof(struct sockaddr_in6);
5661d59107f7SMichael Tuexen 			store.sin6 = control->whoFrom->ro._l_addr.sin6;
5662d59107f7SMichael Tuexen 			store.sin6.sin6_port = control->port_from;
5663b5b6e5c2SMichael Tuexen 			break;
5664f8829a4aSRandall Stewart #endif
5665b5b6e5c2SMichael Tuexen #ifdef INET
5666b5b6e5c2SMichael Tuexen 		case AF_INET:
5667d59107f7SMichael Tuexen #ifdef INET6
5668d59107f7SMichael Tuexen 			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
5669d59107f7SMichael Tuexen 				len = sizeof(struct sockaddr_in6);
5670d59107f7SMichael Tuexen 				in6_sin_2_v4mapsin6(&control->whoFrom->ro._l_addr.sin,
5671d59107f7SMichael Tuexen 				    &store.sin6);
5672d59107f7SMichael Tuexen 				store.sin6.sin6_port = control->port_from;
5673d59107f7SMichael Tuexen 			} else {
5674d59107f7SMichael Tuexen 				len = sizeof(struct sockaddr_in);
5675d59107f7SMichael Tuexen 				store.sin = control->whoFrom->ro._l_addr.sin;
5676d59107f7SMichael Tuexen 				store.sin.sin_port = control->port_from;
5677d59107f7SMichael Tuexen 			}
5678d59107f7SMichael Tuexen #else
5679d59107f7SMichael Tuexen 			len = sizeof(struct sockaddr_in);
5680d59107f7SMichael Tuexen 			store.sin = control->whoFrom->ro._l_addr.sin;
5681d59107f7SMichael Tuexen 			store.sin.sin_port = control->port_from;
5682d59107f7SMichael Tuexen #endif
5683b5b6e5c2SMichael Tuexen 			break;
5684b5b6e5c2SMichael Tuexen #endif
5685b5b6e5c2SMichael Tuexen 		default:
5686d59107f7SMichael Tuexen 			len = 0;
5687b5b6e5c2SMichael Tuexen 			break;
5688b5b6e5c2SMichael Tuexen 		}
5689d59107f7SMichael Tuexen 		memcpy(from, &store, min((size_t)fromlen, len));
5690e0e00a4dSMichael Tuexen #ifdef INET6
5691f8829a4aSRandall Stewart 		{
5692b5b6e5c2SMichael Tuexen 			struct sockaddr_in6 lsa6, *from6;
5693f8829a4aSRandall Stewart 
5694b5b6e5c2SMichael Tuexen 			from6 = (struct sockaddr_in6 *)from;
5695b5b6e5c2SMichael Tuexen 			sctp_recover_scope_mac(from6, (&lsa6));
5696f8829a4aSRandall Stewart 		}
5697f8829a4aSRandall Stewart #endif
5698f8829a4aSRandall Stewart 	}
56999c5ca6f2SMichael Tuexen 	if (hold_rlock) {
57009c5ca6f2SMichael Tuexen 		SCTP_INP_READ_UNLOCK(inp);
57019c5ca6f2SMichael Tuexen 		hold_rlock = 0;
57029c5ca6f2SMichael Tuexen 	}
57039c5ca6f2SMichael Tuexen 	if (hold_sblock) {
57049c5ca6f2SMichael Tuexen 		SOCKBUF_UNLOCK(&so->so_rcv);
57059c5ca6f2SMichael Tuexen 		hold_sblock = 0;
57069c5ca6f2SMichael Tuexen 	}
5707f8829a4aSRandall Stewart 	/* now copy out what data we can */
5708f8829a4aSRandall Stewart 	if (mp == NULL) {
5709f8829a4aSRandall Stewart 		/* copy out each mbuf in the chain up to length */
5710f8829a4aSRandall Stewart get_more_data:
5711f8829a4aSRandall Stewart 		m = control->data;
5712f8829a4aSRandall Stewart 		while (m) {
5713f8829a4aSRandall Stewart 			/* Move out all we can */
5714f8829a4aSRandall Stewart 			cp_len = (int)uio->uio_resid;
5715139bc87fSRandall Stewart 			my_len = (int)SCTP_BUF_LEN(m);
5716f8829a4aSRandall Stewart 			if (cp_len > my_len) {
5717f8829a4aSRandall Stewart 				/* not enough in this buf */
5718f8829a4aSRandall Stewart 				cp_len = my_len;
5719f8829a4aSRandall Stewart 			}
5720f8829a4aSRandall Stewart 			if (hold_rlock) {
5721f8829a4aSRandall Stewart 				SCTP_INP_READ_UNLOCK(inp);
5722f8829a4aSRandall Stewart 				hold_rlock = 0;
5723f8829a4aSRandall Stewart 			}
5724f8829a4aSRandall Stewart 			if (cp_len > 0)
5725f8829a4aSRandall Stewart 				error = uiomove(mtod(m, char *), cp_len, uio);
5726f8829a4aSRandall Stewart 			/* re-read */
5727f8829a4aSRandall Stewart 			if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
5728f8829a4aSRandall Stewart 				goto release;
5729f8829a4aSRandall Stewart 			}
57300696e120SRandall Stewart 			if ((control->do_not_ref_stcb == 0) && stcb &&
5731f8829a4aSRandall Stewart 			    stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
5732f8829a4aSRandall Stewart 				no_rcv_needed = 1;
5733f8829a4aSRandall Stewart 			}
5734f8829a4aSRandall Stewart 			if (error) {
5735f8829a4aSRandall Stewart 				/* error we are out of here */
5736f8829a4aSRandall Stewart 				goto release;
5737f8829a4aSRandall Stewart 			}
5738f8829a4aSRandall Stewart 			SCTP_INP_READ_LOCK(inp);
5739f8829a4aSRandall Stewart 			hold_rlock = 1;
5740139bc87fSRandall Stewart 			if (cp_len == SCTP_BUF_LEN(m)) {
5741139bc87fSRandall Stewart 				if ((SCTP_BUF_NEXT(m) == NULL) &&
5742139bc87fSRandall Stewart 				    (control->end_added)) {
5743f8829a4aSRandall Stewart 					out_flags |= MSG_EOR;
574452129fcdSRandall Stewart 					if ((control->do_not_ref_stcb == 0) &&
574552129fcdSRandall Stewart 					    (control->stcb != NULL) &&
574652129fcdSRandall Stewart 					    ((control->spec_flags & M_NOTIFICATION) == 0))
5747ee7f9857SRandall Stewart 						control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0;
5748f8829a4aSRandall Stewart 				}
5749139bc87fSRandall Stewart 				if (control->spec_flags & M_NOTIFICATION) {
5750f8829a4aSRandall Stewart 					out_flags |= MSG_NOTIFICATION;
5751f8829a4aSRandall Stewart 				}
5752f8829a4aSRandall Stewart 				/* we ate up the mbuf */
5753f8829a4aSRandall Stewart 				if (in_flags & MSG_PEEK) {
5754f8829a4aSRandall Stewart 					/* just looking */
5755139bc87fSRandall Stewart 					m = SCTP_BUF_NEXT(m);
5756f8829a4aSRandall Stewart 					copied_so_far += cp_len;
5757f8829a4aSRandall Stewart 				} else {
5758f8829a4aSRandall Stewart 					/* dispose of the mbuf */
5759b3f1ea41SRandall Stewart 					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
5760f8829a4aSRandall Stewart 						sctp_sblog(&so->so_rcv,
5761139bc87fSRandall Stewart 						    control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m));
576280fefe0aSRandall Stewart 					}
5763f8829a4aSRandall Stewart 					sctp_sbfree(control, stcb, &so->so_rcv, m);
5764b3f1ea41SRandall Stewart 					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
5765f8829a4aSRandall Stewart 						sctp_sblog(&so->so_rcv,
5766f8829a4aSRandall Stewart 						    control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0);
576780fefe0aSRandall Stewart 					}
5768f8829a4aSRandall Stewart 					copied_so_far += cp_len;
5769f8829a4aSRandall Stewart 					freed_so_far += cp_len;
5770c4739e2fSRandall Stewart 					freed_so_far += MSIZE;
577118e198d3SRandall Stewart 					atomic_subtract_int(&control->length, cp_len);
5772f8829a4aSRandall Stewart 					control->data = sctp_m_free(m);
5773f8829a4aSRandall Stewart 					m = control->data;
5774b7b84c0eSMichael Tuexen 					/*
5775b7b84c0eSMichael Tuexen 					 * been through it all, must hold sb
5776b7b84c0eSMichael Tuexen 					 * lock ok to null tail
5777b7b84c0eSMichael Tuexen 					 */
5778f8829a4aSRandall Stewart 					if (control->data == NULL) {
5779a5d547adSRandall Stewart #ifdef INVARIANTS
5780f8829a4aSRandall Stewart 						if ((control->end_added == 0) ||
5781f8829a4aSRandall Stewart 						    (TAILQ_NEXT(control, next) == NULL)) {
5782f8829a4aSRandall Stewart 							/*
5783f8829a4aSRandall Stewart 							 * If the end is not
5784f8829a4aSRandall Stewart 							 * added, OR the
5785f8829a4aSRandall Stewart 							 * next is NOT null
5786f8829a4aSRandall Stewart 							 * we MUST have the
5787f8829a4aSRandall Stewart 							 * lock.
5788f8829a4aSRandall Stewart 							 */
5789f8829a4aSRandall Stewart 							if (mtx_owned(&inp->inp_rdata_mtx) == 0) {
5790f8829a4aSRandall Stewart 								panic("Hmm we don't own the lock?");
5791f8829a4aSRandall Stewart 							}
5792f8829a4aSRandall Stewart 						}
5793f8829a4aSRandall Stewart #endif
5794f8829a4aSRandall Stewart 						control->tail_mbuf = NULL;
5795a5d547adSRandall Stewart #ifdef INVARIANTS
5796f8829a4aSRandall Stewart 						if ((control->end_added) && ((out_flags & MSG_EOR) == 0)) {
5797f8829a4aSRandall Stewart 							panic("end_added, nothing left and no MSG_EOR");
5798f8829a4aSRandall Stewart 						}
5799f8829a4aSRandall Stewart #endif
5800f8829a4aSRandall Stewart 					}
5801f8829a4aSRandall Stewart 				}
5802f8829a4aSRandall Stewart 			} else {
5803f8829a4aSRandall Stewart 				/* Do we need to trim the mbuf? */
5804139bc87fSRandall Stewart 				if (control->spec_flags & M_NOTIFICATION) {
5805f8829a4aSRandall Stewart 					out_flags |= MSG_NOTIFICATION;
5806f8829a4aSRandall Stewart 				}
5807f8829a4aSRandall Stewart 				if ((in_flags & MSG_PEEK) == 0) {
5808139bc87fSRandall Stewart 					SCTP_BUF_RESV_UF(m, cp_len);
5809139bc87fSRandall Stewart 					SCTP_BUF_LEN(m) -= cp_len;
5810b3f1ea41SRandall Stewart 					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
5811f8829a4aSRandall Stewart 						sctp_sblog(&so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, cp_len);
581280fefe0aSRandall Stewart 					}
58134e88d37aSMichael Tuexen 					atomic_subtract_int(&so->so_rcv.sb_cc, cp_len);
58140696e120SRandall Stewart 					if ((control->do_not_ref_stcb == 0) &&
58150696e120SRandall Stewart 					    stcb) {
58164e88d37aSMichael Tuexen 						atomic_subtract_int(&stcb->asoc.sb_cc, cp_len);
5817f8829a4aSRandall Stewart 					}
5818f8829a4aSRandall Stewart 					copied_so_far += cp_len;
5819f8829a4aSRandall Stewart 					freed_so_far += cp_len;
5820c4739e2fSRandall Stewart 					freed_so_far += MSIZE;
5821b3f1ea41SRandall Stewart 					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
5822f8829a4aSRandall Stewart 						sctp_sblog(&so->so_rcv, control->do_not_ref_stcb ? NULL : stcb,
5823f8829a4aSRandall Stewart 						    SCTP_LOG_SBRESULT, 0);
582480fefe0aSRandall Stewart 					}
582518e198d3SRandall Stewart 					atomic_subtract_int(&control->length, cp_len);
5826f8829a4aSRandall Stewart 				} else {
5827f8829a4aSRandall Stewart 					copied_so_far += cp_len;
5828f8829a4aSRandall Stewart 				}
5829f8829a4aSRandall Stewart 			}
5830d61a0ae0SRandall Stewart 			if ((out_flags & MSG_EOR) || (uio->uio_resid == 0)) {
5831f8829a4aSRandall Stewart 				break;
5832f8829a4aSRandall Stewart 			}
5833f8829a4aSRandall Stewart 			if (((stcb) && (in_flags & MSG_PEEK) == 0) &&
5834f8829a4aSRandall Stewart 			    (control->do_not_ref_stcb == 0) &&
5835f8829a4aSRandall Stewart 			    (freed_so_far >= rwnd_req)) {
5836f8829a4aSRandall Stewart 				sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req);
5837f8829a4aSRandall Stewart 			}
5838f8829a4aSRandall Stewart 		}		/* end while(m) */
5839f8829a4aSRandall Stewart 		/*
5840f8829a4aSRandall Stewart 		 * At this point we have looked at it all and we either have
5841f8829a4aSRandall Stewart 		 * a MSG_EOR/or read all the user wants... <OR>
5842f8829a4aSRandall Stewart 		 * control->length == 0.
5843f8829a4aSRandall Stewart 		 */
5844d61a0ae0SRandall Stewart 		if ((out_flags & MSG_EOR) && ((in_flags & MSG_PEEK) == 0)) {
5845f8829a4aSRandall Stewart 			/* we are done with this control */
5846f8829a4aSRandall Stewart 			if (control->length == 0) {
5847f8829a4aSRandall Stewart 				if (control->data) {
5848a5d547adSRandall Stewart #ifdef INVARIANTS
5849f8829a4aSRandall Stewart 					panic("control->data not null at read eor?");
5850f8829a4aSRandall Stewart #else
5851ad81507eSRandall Stewart 					SCTP_PRINTF("Strange, data left in the control buffer .. invarients would panic?\n");
5852f8829a4aSRandall Stewart 					sctp_m_freem(control->data);
5853f8829a4aSRandall Stewart 					control->data = NULL;
5854f8829a4aSRandall Stewart #endif
5855f8829a4aSRandall Stewart 				}
5856f8829a4aSRandall Stewart 		done_with_control:
5857f8829a4aSRandall Stewart 				if (hold_rlock == 0) {
5858f8829a4aSRandall Stewart 					SCTP_INP_READ_LOCK(inp);
5859f8829a4aSRandall Stewart 					hold_rlock = 1;
5860f8829a4aSRandall Stewart 				}
5861f8829a4aSRandall Stewart 				TAILQ_REMOVE(&inp->read_queue, control, next);
5862f8829a4aSRandall Stewart 				/* Add back any hiddend data */
5863f8829a4aSRandall Stewart 				if (control->held_length) {
5864f8829a4aSRandall Stewart 					held_length = 0;
5865f8829a4aSRandall Stewart 					control->held_length = 0;
5866f8829a4aSRandall Stewart 					wakeup_read_socket = 1;
5867f8829a4aSRandall Stewart 				}
586817205eccSRandall Stewart 				if (control->aux_data) {
586917205eccSRandall Stewart 					sctp_m_free(control->aux_data);
587017205eccSRandall Stewart 					control->aux_data = NULL;
587117205eccSRandall Stewart 				}
5872f8829a4aSRandall Stewart 				no_rcv_needed = control->do_not_ref_stcb;
5873f8829a4aSRandall Stewart 				sctp_free_remote_addr(control->whoFrom);
5874f8829a4aSRandall Stewart 				control->data = NULL;
587598d5fd97SMichael Tuexen #ifdef INVARIANTS
587644249214SRandall Stewart 				if (control->on_strm_q) {
587744249214SRandall Stewart 					panic("About to free ctl:%p so:%p and its in %d",
587844249214SRandall Stewart 					    control, so, control->on_strm_q);
587944249214SRandall Stewart 				}
588098d5fd97SMichael Tuexen #endif
5881f8829a4aSRandall Stewart 				sctp_free_a_readq(stcb, control);
5882f8829a4aSRandall Stewart 				control = NULL;
58830696e120SRandall Stewart 				if ((freed_so_far >= rwnd_req) &&
58840696e120SRandall Stewart 				    (no_rcv_needed == 0))
5885f8829a4aSRandall Stewart 					sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req);
5886f8829a4aSRandall Stewart 
5887f8829a4aSRandall Stewart 			} else {
5888f8829a4aSRandall Stewart 				/*
5889f8829a4aSRandall Stewart 				 * The user did not read all of this
5890f8829a4aSRandall Stewart 				 * message, turn off the returned MSG_EOR
5891f8829a4aSRandall Stewart 				 * since we are leaving more behind on the
5892f8829a4aSRandall Stewart 				 * control to read.
5893f8829a4aSRandall Stewart 				 */
5894a5d547adSRandall Stewart #ifdef INVARIANTS
58950696e120SRandall Stewart 				if (control->end_added &&
58960696e120SRandall Stewart 				    (control->data == NULL) &&
5897f8829a4aSRandall Stewart 				    (control->tail_mbuf == NULL)) {
5898f8829a4aSRandall Stewart 					panic("Gak, control->length is corrupt?");
5899f8829a4aSRandall Stewart 				}
5900f8829a4aSRandall Stewart #endif
5901f8829a4aSRandall Stewart 				no_rcv_needed = control->do_not_ref_stcb;
5902f8829a4aSRandall Stewart 				out_flags &= ~MSG_EOR;
5903f8829a4aSRandall Stewart 			}
5904f8829a4aSRandall Stewart 		}
5905f8829a4aSRandall Stewart 		if (out_flags & MSG_EOR) {
5906f8829a4aSRandall Stewart 			goto release;
5907f8829a4aSRandall Stewart 		}
5908f8829a4aSRandall Stewart 		if ((uio->uio_resid == 0) ||
590904aab884SMichael Tuexen 		    ((in_eeor_mode) &&
591004aab884SMichael Tuexen 		    (copied_so_far >= (uint32_t)max(so->so_rcv.sb_lowat, 1)))) {
5911f8829a4aSRandall Stewart 			goto release;
5912f8829a4aSRandall Stewart 		}
5913f8829a4aSRandall Stewart 		/*
5914f8829a4aSRandall Stewart 		 * If I hit here the receiver wants more and this message is
5915f8829a4aSRandall Stewart 		 * NOT done (pd-api). So two questions. Can we block? if not
5916f8829a4aSRandall Stewart 		 * we are done. Did the user NOT set MSG_WAITALL?
5917f8829a4aSRandall Stewart 		 */
5918f8829a4aSRandall Stewart 		if (block_allowed == 0) {
5919f8829a4aSRandall Stewart 			goto release;
5920f8829a4aSRandall Stewart 		}
5921f8829a4aSRandall Stewart 		/*
5922f8829a4aSRandall Stewart 		 * We need to wait for more data a few things: - We don't
5923f8829a4aSRandall Stewart 		 * sbunlock() so we don't get someone else reading. - We
5924f8829a4aSRandall Stewart 		 * must be sure to account for the case where what is added
5925f8829a4aSRandall Stewart 		 * is NOT to our control when we wakeup.
5926f8829a4aSRandall Stewart 		 */
5927f8829a4aSRandall Stewart 
5928f8829a4aSRandall Stewart 		/*
5929f8829a4aSRandall Stewart 		 * Do we need to tell the transport a rwnd update might be
5930f8829a4aSRandall Stewart 		 * needed before we go to sleep?
5931f8829a4aSRandall Stewart 		 */
5932f8829a4aSRandall Stewart 		if (((stcb) && (in_flags & MSG_PEEK) == 0) &&
5933f8829a4aSRandall Stewart 		    ((freed_so_far >= rwnd_req) &&
5934f8829a4aSRandall Stewart 		    (control->do_not_ref_stcb == 0) &&
5935f8829a4aSRandall Stewart 		    (no_rcv_needed == 0))) {
5936f8829a4aSRandall Stewart 			sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req);
5937f8829a4aSRandall Stewart 		}
5938f8829a4aSRandall Stewart wait_some_more:
593944b7479bSRandall Stewart 		if (so->so_rcv.sb_state & SBS_CANTRCVMORE) {
5940f8829a4aSRandall Stewart 			goto release;
5941f8829a4aSRandall Stewart 		}
5942f8829a4aSRandall Stewart 		if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)
5943f8829a4aSRandall Stewart 			goto release;
5944f8829a4aSRandall Stewart 
5945f8829a4aSRandall Stewart 		if (hold_rlock == 1) {
5946f8829a4aSRandall Stewart 			SCTP_INP_READ_UNLOCK(inp);
5947f8829a4aSRandall Stewart 			hold_rlock = 0;
5948f8829a4aSRandall Stewart 		}
5949f8829a4aSRandall Stewart 		if (hold_sblock == 0) {
5950f8829a4aSRandall Stewart 			SOCKBUF_LOCK(&so->so_rcv);
5951f8829a4aSRandall Stewart 			hold_sblock = 1;
5952f8829a4aSRandall Stewart 		}
5953851b7298SRandall Stewart 		if ((copied_so_far) && (control->length == 0) &&
5954b5c16493SMichael Tuexen 		    (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE))) {
5955851b7298SRandall Stewart 			goto release;
5956851b7298SRandall Stewart 		}
59574e88d37aSMichael Tuexen 		if (so->so_rcv.sb_cc <= control->held_length) {
5958f8829a4aSRandall Stewart 			error = sbwait(&so->so_rcv);
5959f8829a4aSRandall Stewart 			if (error) {
5960f8829a4aSRandall Stewart 				goto release;
5961f8829a4aSRandall Stewart 			}
5962f8829a4aSRandall Stewart 			control->held_length = 0;
5963f8829a4aSRandall Stewart 		}
5964f8829a4aSRandall Stewart 		if (hold_sblock) {
5965f8829a4aSRandall Stewart 			SOCKBUF_UNLOCK(&so->so_rcv);
5966f8829a4aSRandall Stewart 			hold_sblock = 0;
5967f8829a4aSRandall Stewart 		}
5968f8829a4aSRandall Stewart 		if (control->length == 0) {
5969f8829a4aSRandall Stewart 			/* still nothing here */
5970f8829a4aSRandall Stewart 			if (control->end_added == 1) {
5971f8829a4aSRandall Stewart 				/* he aborted, or is done i.e.did a shutdown */
5972f8829a4aSRandall Stewart 				out_flags |= MSG_EOR;
59739a6142d8SRandall Stewart 				if (control->pdapi_aborted) {
59746114cd96SRandall Stewart 					if ((control->do_not_ref_stcb == 0) && ((control->spec_flags & M_NOTIFICATION) == 0))
5975ee7f9857SRandall Stewart 						control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0;
59769a6142d8SRandall Stewart 
597703b0b021SRandall Stewart 					out_flags |= MSG_TRUNC;
59789a6142d8SRandall Stewart 				} else {
59796114cd96SRandall Stewart 					if ((control->do_not_ref_stcb == 0) && ((control->spec_flags & M_NOTIFICATION) == 0))
5980ee7f9857SRandall Stewart 						control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0;
59819a6142d8SRandall Stewart 				}
5982f8829a4aSRandall Stewart 				goto done_with_control;
5983f8829a4aSRandall Stewart 			}
59844e88d37aSMichael Tuexen 			if (so->so_rcv.sb_cc > held_length) {
59854e88d37aSMichael Tuexen 				control->held_length = so->so_rcv.sb_cc;
5986f8829a4aSRandall Stewart 				held_length = 0;
5987f8829a4aSRandall Stewart 			}
5988f8829a4aSRandall Stewart 			goto wait_some_more;
5989f8829a4aSRandall Stewart 		} else if (control->data == NULL) {
599050cec919SRandall Stewart 			/*
599150cec919SRandall Stewart 			 * we must re-sync since data is probably being
599250cec919SRandall Stewart 			 * added
599350cec919SRandall Stewart 			 */
599450cec919SRandall Stewart 			SCTP_INP_READ_LOCK(inp);
599550cec919SRandall Stewart 			if ((control->length > 0) && (control->data == NULL)) {
5996b7b84c0eSMichael Tuexen 				/*
5997b7b84c0eSMichael Tuexen 				 * big trouble.. we have the lock and its
5998b7b84c0eSMichael Tuexen 				 * corrupt?
5999b7b84c0eSMichael Tuexen 				 */
60009c04b296SRandall Stewart #ifdef INVARIANTS
60019d18771fSRandall Stewart 				panic("Impossible data==NULL length !=0");
60029c04b296SRandall Stewart #endif
60039c04b296SRandall Stewart 				out_flags |= MSG_EOR;
60049c04b296SRandall Stewart 				out_flags |= MSG_TRUNC;
60059c04b296SRandall Stewart 				control->length = 0;
60069c04b296SRandall Stewart 				SCTP_INP_READ_UNLOCK(inp);
60079c04b296SRandall Stewart 				goto done_with_control;
6008f8829a4aSRandall Stewart 			}
600950cec919SRandall Stewart 			SCTP_INP_READ_UNLOCK(inp);
601050cec919SRandall Stewart 			/* We will fall around to get more data */
601150cec919SRandall Stewart 		}
6012f8829a4aSRandall Stewart 		goto get_more_data;
6013f8829a4aSRandall Stewart 	} else {
601417205eccSRandall Stewart 		/*-
601517205eccSRandall Stewart 		 * Give caller back the mbuf chain,
601617205eccSRandall Stewart 		 * store in uio_resid the length
6017f8829a4aSRandall Stewart 		 */
601817205eccSRandall Stewart 		wakeup_read_socket = 0;
6019f8829a4aSRandall Stewart 		if ((control->end_added == 0) ||
6020f8829a4aSRandall Stewart 		    (TAILQ_NEXT(control, next) == NULL)) {
6021f8829a4aSRandall Stewart 			/* Need to get rlock */
6022f8829a4aSRandall Stewart 			if (hold_rlock == 0) {
6023f8829a4aSRandall Stewart 				SCTP_INP_READ_LOCK(inp);
6024f8829a4aSRandall Stewart 				hold_rlock = 1;
6025f8829a4aSRandall Stewart 			}
6026f8829a4aSRandall Stewart 		}
6027139bc87fSRandall Stewart 		if (control->end_added) {
6028f8829a4aSRandall Stewart 			out_flags |= MSG_EOR;
602960990c0cSMichael Tuexen 			if ((control->do_not_ref_stcb == 0) &&
603060990c0cSMichael Tuexen 			    (control->stcb != NULL) &&
603160990c0cSMichael Tuexen 			    ((control->spec_flags & M_NOTIFICATION) == 0))
6032ee7f9857SRandall Stewart 				control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0;
6033f8829a4aSRandall Stewart 		}
6034139bc87fSRandall Stewart 		if (control->spec_flags & M_NOTIFICATION) {
6035f8829a4aSRandall Stewart 			out_flags |= MSG_NOTIFICATION;
6036f8829a4aSRandall Stewart 		}
603717205eccSRandall Stewart 		uio->uio_resid = control->length;
6038f8829a4aSRandall Stewart 		*mp = control->data;
6039f8829a4aSRandall Stewart 		m = control->data;
6040f8829a4aSRandall Stewart 		while (m) {
6041b3f1ea41SRandall Stewart 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
6042f8829a4aSRandall Stewart 				sctp_sblog(&so->so_rcv,
6043139bc87fSRandall Stewart 				    control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m));
604480fefe0aSRandall Stewart 			}
6045f8829a4aSRandall Stewart 			sctp_sbfree(control, stcb, &so->so_rcv, m);
6046139bc87fSRandall Stewart 			freed_so_far += SCTP_BUF_LEN(m);
6047c4739e2fSRandall Stewart 			freed_so_far += MSIZE;
6048b3f1ea41SRandall Stewart 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
6049f8829a4aSRandall Stewart 				sctp_sblog(&so->so_rcv,
6050f8829a4aSRandall Stewart 				    control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0);
605180fefe0aSRandall Stewart 			}
6052139bc87fSRandall Stewart 			m = SCTP_BUF_NEXT(m);
6053f8829a4aSRandall Stewart 		}
6054f8829a4aSRandall Stewart 		control->data = control->tail_mbuf = NULL;
6055f8829a4aSRandall Stewart 		control->length = 0;
6056f8829a4aSRandall Stewart 		if (out_flags & MSG_EOR) {
6057f8829a4aSRandall Stewart 			/* Done with this control */
6058f8829a4aSRandall Stewart 			goto done_with_control;
6059f8829a4aSRandall Stewart 		}
6060f8829a4aSRandall Stewart 	}
6061f8829a4aSRandall Stewart release:
6062f8829a4aSRandall Stewart 	if (hold_rlock == 1) {
6063f8829a4aSRandall Stewart 		SCTP_INP_READ_UNLOCK(inp);
6064f8829a4aSRandall Stewart 		hold_rlock = 0;
6065f8829a4aSRandall Stewart 	}
60667abab911SRobert Watson 	if (hold_sblock == 1) {
60677abab911SRobert Watson 		SOCKBUF_UNLOCK(&so->so_rcv);
60687abab911SRobert Watson 		hold_sblock = 0;
6069f8829a4aSRandall Stewart 	}
6070f8829a4aSRandall Stewart 	sbunlock(&so->so_rcv);
60717abab911SRobert Watson 	sockbuf_lock = 0;
6072f8829a4aSRandall Stewart 
6073f8829a4aSRandall Stewart release_unlocked:
6074f8829a4aSRandall Stewart 	if (hold_sblock) {
6075f8829a4aSRandall Stewart 		SOCKBUF_UNLOCK(&so->so_rcv);
6076f8829a4aSRandall Stewart 		hold_sblock = 0;
6077f8829a4aSRandall Stewart 	}
6078f8829a4aSRandall Stewart 	if ((stcb) && (in_flags & MSG_PEEK) == 0) {
6079f8829a4aSRandall Stewart 		if ((freed_so_far >= rwnd_req) &&
6080f8829a4aSRandall Stewart 		    (control && (control->do_not_ref_stcb == 0)) &&
6081f8829a4aSRandall Stewart 		    (no_rcv_needed == 0))
6082f8829a4aSRandall Stewart 			sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req);
6083f8829a4aSRandall Stewart 	}
6084f8829a4aSRandall Stewart out:
60851b9f62a0SRandall Stewart 	if (msg_flags) {
60861b9f62a0SRandall Stewart 		*msg_flags = out_flags;
60871b9f62a0SRandall Stewart 	}
60889a6142d8SRandall Stewart 	if (((out_flags & MSG_EOR) == 0) &&
60899a6142d8SRandall Stewart 	    ((in_flags & MSG_PEEK) == 0) &&
60909a6142d8SRandall Stewart 	    (sinfo) &&
6091e2e7c62eSMichael Tuexen 	    (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO) ||
6092e2e7c62eSMichael Tuexen 	    sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO))) {
60939a6142d8SRandall Stewart 		struct sctp_extrcvinfo *s_extra;
60949a6142d8SRandall Stewart 
60959a6142d8SRandall Stewart 		s_extra = (struct sctp_extrcvinfo *)sinfo;
6096b70b526dSMichael Tuexen 		s_extra->serinfo_next_flags = SCTP_NO_NEXT_MSG;
60979a6142d8SRandall Stewart 	}
6098f8829a4aSRandall Stewart 	if (hold_rlock == 1) {
6099f8829a4aSRandall Stewart 		SCTP_INP_READ_UNLOCK(inp);
6100f8829a4aSRandall Stewart 	}
6101f8829a4aSRandall Stewart 	if (hold_sblock) {
6102f8829a4aSRandall Stewart 		SOCKBUF_UNLOCK(&so->so_rcv);
6103f8829a4aSRandall Stewart 	}
61047abab911SRobert Watson 	if (sockbuf_lock) {
61057abab911SRobert Watson 		sbunlock(&so->so_rcv);
61067abab911SRobert Watson 	}
610750cec919SRandall Stewart 	if (freecnt_applied) {
6108f8829a4aSRandall Stewart 		/*
6109f8829a4aSRandall Stewart 		 * The lock on the socket buffer protects us so the free
6110f8829a4aSRandall Stewart 		 * code will stop. But since we used the socketbuf lock and
6111f8829a4aSRandall Stewart 		 * the sender uses the tcb_lock to increment, we need to use
6112f8829a4aSRandall Stewart 		 * the atomic add to the refcnt.
6113f8829a4aSRandall Stewart 		 */
611450cec919SRandall Stewart 		if (stcb == NULL) {
6115df6e0cc3SRandall Stewart #ifdef INVARIANTS
611650cec919SRandall Stewart 			panic("stcb for refcnt has gone NULL?");
6117df6e0cc3SRandall Stewart 			goto stage_left;
6118df6e0cc3SRandall Stewart #else
6119df6e0cc3SRandall Stewart 			goto stage_left;
6120df6e0cc3SRandall Stewart #endif
612150cec919SRandall Stewart 		}
6122f8829a4aSRandall Stewart 		/* Save the value back for next time */
6123f8829a4aSRandall Stewart 		stcb->freed_by_sorcv_sincelast = freed_so_far;
6124cf46caceSMichael Tuexen 		atomic_add_int(&stcb->asoc.refcnt, -1);
6125f8829a4aSRandall Stewart 	}
6126b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RECV_RWND_LOGGING_ENABLE) {
6127f8829a4aSRandall Stewart 		if (stcb) {
6128f8829a4aSRandall Stewart 			sctp_misc_ints(SCTP_SORECV_DONE,
6129f8829a4aSRandall Stewart 			    freed_so_far,
61309a8e3088SMichael Tuexen 			    (uint32_t)((uio) ? (slen - uio->uio_resid) : slen),
6131f8829a4aSRandall Stewart 			    stcb->asoc.my_rwnd,
61324e88d37aSMichael Tuexen 			    so->so_rcv.sb_cc);
6133f8829a4aSRandall Stewart 		} else {
6134f8829a4aSRandall Stewart 			sctp_misc_ints(SCTP_SORECV_DONE,
6135f8829a4aSRandall Stewart 			    freed_so_far,
61369a8e3088SMichael Tuexen 			    (uint32_t)((uio) ? (slen - uio->uio_resid) : slen),
6137f8829a4aSRandall Stewart 			    0,
61384e88d37aSMichael Tuexen 			    so->so_rcv.sb_cc);
6139f8829a4aSRandall Stewart 		}
614080fefe0aSRandall Stewart 	}
6141df6e0cc3SRandall Stewart stage_left:
6142f8829a4aSRandall Stewart 	if (wakeup_read_socket) {
6143f8829a4aSRandall Stewart 		sctp_sorwakeup(inp, so);
6144f8829a4aSRandall Stewart 	}
6145f8829a4aSRandall Stewart 	return (error);
6146f8829a4aSRandall Stewart }
6147f8829a4aSRandall Stewart 
6148f8829a4aSRandall Stewart 
6149f8829a4aSRandall Stewart #ifdef SCTP_MBUF_LOGGING
6150f8829a4aSRandall Stewart struct mbuf *
6151f8829a4aSRandall Stewart sctp_m_free(struct mbuf *m)
6152f8829a4aSRandall Stewart {
6153b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
6154f8829a4aSRandall Stewart 		sctp_log_mb(m, SCTP_MBUF_IFREE);
6155f8829a4aSRandall Stewart 	}
6156f8829a4aSRandall Stewart 	return (m_free(m));
6157f8829a4aSRandall Stewart }
6158f8829a4aSRandall Stewart 
6159f8829a4aSRandall Stewart void
6160f8829a4aSRandall Stewart sctp_m_freem(struct mbuf *mb)
6161f8829a4aSRandall Stewart {
6162f8829a4aSRandall Stewart 	while (mb != NULL)
6163f8829a4aSRandall Stewart 		mb = sctp_m_free(mb);
6164f8829a4aSRandall Stewart }
6165f8829a4aSRandall Stewart 
6166f8829a4aSRandall Stewart #endif
6167f8829a4aSRandall Stewart 
616842551e99SRandall Stewart int
616942551e99SRandall Stewart sctp_dynamic_set_primary(struct sockaddr *sa, uint32_t vrf_id)
617042551e99SRandall Stewart {
617142551e99SRandall Stewart 	/*
617242551e99SRandall Stewart 	 * Given a local address. For all associations that holds the
617342551e99SRandall Stewart 	 * address, request a peer-set-primary.
617442551e99SRandall Stewart 	 */
617542551e99SRandall Stewart 	struct sctp_ifa *ifa;
617642551e99SRandall Stewart 	struct sctp_laddr *wi;
617742551e99SRandall Stewart 
617842551e99SRandall Stewart 	ifa = sctp_find_ifa_by_addr(sa, vrf_id, 0);
617942551e99SRandall Stewart 	if (ifa == NULL) {
6180c4739e2fSRandall Stewart 		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EADDRNOTAVAIL);
618142551e99SRandall Stewart 		return (EADDRNOTAVAIL);
618242551e99SRandall Stewart 	}
618342551e99SRandall Stewart 	/*
618442551e99SRandall Stewart 	 * Now that we have the ifa we must awaken the iterator with this
618542551e99SRandall Stewart 	 * message.
618642551e99SRandall Stewart 	 */
6187b3f1ea41SRandall Stewart 	wi = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_laddr), struct sctp_laddr);
618842551e99SRandall Stewart 	if (wi == NULL) {
6189c4739e2fSRandall Stewart 		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOMEM);
619042551e99SRandall Stewart 		return (ENOMEM);
619142551e99SRandall Stewart 	}
619242551e99SRandall Stewart 	/* Now incr the count and int wi structure */
619342551e99SRandall Stewart 	SCTP_INCR_LADDR_COUNT();
61945ba7f91fSMichael Tuexen 	memset(wi, 0, sizeof(*wi));
6195d61a0ae0SRandall Stewart 	(void)SCTP_GETTIME_TIMEVAL(&wi->start_time);
619642551e99SRandall Stewart 	wi->ifa = ifa;
619742551e99SRandall Stewart 	wi->action = SCTP_SET_PRIM_ADDR;
619842551e99SRandall Stewart 	atomic_add_int(&ifa->refcount, 1);
619942551e99SRandall Stewart 
620042551e99SRandall Stewart 	/* Now add it to the work queue */
6201f7517433SRandall Stewart 	SCTP_WQ_ADDR_LOCK();
620242551e99SRandall Stewart 	/*
620342551e99SRandall Stewart 	 * Should this really be a tailq? As it is we will process the
620442551e99SRandall Stewart 	 * newest first :-0
620542551e99SRandall Stewart 	 */
6206b3f1ea41SRandall Stewart 	LIST_INSERT_HEAD(&SCTP_BASE_INFO(addr_wq), wi, sctp_nxt_addr);
620742551e99SRandall Stewart 	sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ,
620842551e99SRandall Stewart 	    (struct sctp_inpcb *)NULL,
620942551e99SRandall Stewart 	    (struct sctp_tcb *)NULL,
621042551e99SRandall Stewart 	    (struct sctp_nets *)NULL);
62112c62ba73SMichael Tuexen 	SCTP_WQ_ADDR_UNLOCK();
621242551e99SRandall Stewart 	return (0);
621342551e99SRandall Stewart }
621442551e99SRandall Stewart 
621542551e99SRandall Stewart 
6216f8829a4aSRandall Stewart int
621717205eccSRandall Stewart sctp_soreceive(struct socket *so,
621817205eccSRandall Stewart     struct sockaddr **psa,
621917205eccSRandall Stewart     struct uio *uio,
622017205eccSRandall Stewart     struct mbuf **mp0,
622117205eccSRandall Stewart     struct mbuf **controlp,
622217205eccSRandall Stewart     int *flagsp)
6223f8829a4aSRandall Stewart {
6224f8829a4aSRandall Stewart 	int error, fromlen;
6225f8829a4aSRandall Stewart 	uint8_t sockbuf[256];
6226f8829a4aSRandall Stewart 	struct sockaddr *from;
6227f8829a4aSRandall Stewart 	struct sctp_extrcvinfo sinfo;
6228f8829a4aSRandall Stewart 	int filling_sinfo = 1;
622946bf534cSMichael Tuexen 	int flags;
6230f8829a4aSRandall Stewart 	struct sctp_inpcb *inp;
6231f8829a4aSRandall Stewart 
6232f8829a4aSRandall Stewart 	inp = (struct sctp_inpcb *)so->so_pcb;
6233f8829a4aSRandall Stewart 	/* pickup the assoc we are reading from */
6234f8829a4aSRandall Stewart 	if (inp == NULL) {
6235c4739e2fSRandall Stewart 		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6236f8829a4aSRandall Stewart 		return (EINVAL);
6237f8829a4aSRandall Stewart 	}
6238e2e7c62eSMichael Tuexen 	if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT) &&
6239e2e7c62eSMichael Tuexen 	    sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVRCVINFO) &&
6240e2e7c62eSMichael Tuexen 	    sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVNXTINFO)) ||
6241f8829a4aSRandall Stewart 	    (controlp == NULL)) {
6242f8829a4aSRandall Stewart 		/* user does not want the sndrcv ctl */
6243f8829a4aSRandall Stewart 		filling_sinfo = 0;
6244f8829a4aSRandall Stewart 	}
6245f8829a4aSRandall Stewart 	if (psa) {
6246f8829a4aSRandall Stewart 		from = (struct sockaddr *)sockbuf;
6247f8829a4aSRandall Stewart 		fromlen = sizeof(sockbuf);
6248f8829a4aSRandall Stewart 		from->sa_len = 0;
6249f8829a4aSRandall Stewart 	} else {
6250f8829a4aSRandall Stewart 		from = NULL;
6251f8829a4aSRandall Stewart 		fromlen = 0;
6252f8829a4aSRandall Stewart 	}
6253f8829a4aSRandall Stewart 
6254e432298aSXin LI 	if (filling_sinfo) {
6255e432298aSXin LI 		memset(&sinfo, 0, sizeof(struct sctp_extrcvinfo));
6256e432298aSXin LI 	}
625746bf534cSMichael Tuexen 	if (flagsp != NULL) {
625846bf534cSMichael Tuexen 		flags = *flagsp;
625946bf534cSMichael Tuexen 	} else {
626046bf534cSMichael Tuexen 		flags = 0;
626146bf534cSMichael Tuexen 	}
626246bf534cSMichael Tuexen 	error = sctp_sorecvmsg(so, uio, mp0, from, fromlen, &flags,
6263f8829a4aSRandall Stewart 	    (struct sctp_sndrcvinfo *)&sinfo, filling_sinfo);
626446bf534cSMichael Tuexen 	if (flagsp != NULL) {
626546bf534cSMichael Tuexen 		*flagsp = flags;
626646bf534cSMichael Tuexen 	}
6267e432298aSXin LI 	if (controlp != NULL) {
6268f8829a4aSRandall Stewart 		/* copy back the sinfo in a CMSG format */
626946bf534cSMichael Tuexen 		if (filling_sinfo && ((flags & MSG_NOTIFICATION) == 0)) {
6270f8829a4aSRandall Stewart 			*controlp = sctp_build_ctl_nchunk(inp,
6271f8829a4aSRandall Stewart 			    (struct sctp_sndrcvinfo *)&sinfo);
627246bf534cSMichael Tuexen 		} else {
6273f8829a4aSRandall Stewart 			*controlp = NULL;
6274f8829a4aSRandall Stewart 		}
627546bf534cSMichael Tuexen 	}
6276f8829a4aSRandall Stewart 	if (psa) {
6277f8829a4aSRandall Stewart 		/* copy back the address info */
6278f8829a4aSRandall Stewart 		if (from && from->sa_len) {
6279f8829a4aSRandall Stewart 			*psa = sodupsockaddr(from, M_NOWAIT);
6280f8829a4aSRandall Stewart 		} else {
6281f8829a4aSRandall Stewart 			*psa = NULL;
6282f8829a4aSRandall Stewart 		}
6283f8829a4aSRandall Stewart 	}
6284f8829a4aSRandall Stewart 	return (error);
6285f8829a4aSRandall Stewart }
628617205eccSRandall Stewart 
628717205eccSRandall Stewart 
628817205eccSRandall Stewart 
628917205eccSRandall Stewart 
629017205eccSRandall Stewart 
629117205eccSRandall Stewart int
6292d61a0ae0SRandall Stewart sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr,
6293d61a0ae0SRandall Stewart     int totaddr, int *error)
629417205eccSRandall Stewart {
629517205eccSRandall Stewart 	int added = 0;
629617205eccSRandall Stewart 	int i;
629717205eccSRandall Stewart 	struct sctp_inpcb *inp;
629817205eccSRandall Stewart 	struct sockaddr *sa;
629917205eccSRandall Stewart 	size_t incr = 0;
630092776dfdSMichael Tuexen #ifdef INET
630192776dfdSMichael Tuexen 	struct sockaddr_in *sin;
630292776dfdSMichael Tuexen #endif
630392776dfdSMichael Tuexen #ifdef INET6
630492776dfdSMichael Tuexen 	struct sockaddr_in6 *sin6;
630592776dfdSMichael Tuexen #endif
630692776dfdSMichael Tuexen 
630717205eccSRandall Stewart 	sa = addr;
630817205eccSRandall Stewart 	inp = stcb->sctp_ep;
630917205eccSRandall Stewart 	*error = 0;
631017205eccSRandall Stewart 	for (i = 0; i < totaddr; i++) {
6311ea5eba11SMichael Tuexen 		switch (sa->sa_family) {
6312ea5eba11SMichael Tuexen #ifdef INET
6313ea5eba11SMichael Tuexen 		case AF_INET:
631417205eccSRandall Stewart 			incr = sizeof(struct sockaddr_in);
631592776dfdSMichael Tuexen 			sin = (struct sockaddr_in *)sa;
631692776dfdSMichael Tuexen 			if ((sin->sin_addr.s_addr == INADDR_ANY) ||
631792776dfdSMichael Tuexen 			    (sin->sin_addr.s_addr == INADDR_BROADCAST) ||
631892776dfdSMichael Tuexen 			    IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
631992776dfdSMichael Tuexen 				SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6320ba785902SMichael Tuexen 				(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
6321ba785902SMichael Tuexen 				    SCTP_FROM_SCTPUTIL + SCTP_LOC_7);
632292776dfdSMichael Tuexen 				*error = EINVAL;
632392776dfdSMichael Tuexen 				goto out_now;
632492776dfdSMichael Tuexen 			}
63257154bf4aSMichael Tuexen 			if (sctp_add_remote_addr(stcb, sa, NULL, stcb->asoc.port,
63267154bf4aSMichael Tuexen 			    SCTP_DONOT_SETSCOPE,
63277154bf4aSMichael Tuexen 			    SCTP_ADDR_IS_CONFIRMED)) {
632817205eccSRandall Stewart 				/* assoc gone no un-lock */
6329c4739e2fSRandall Stewart 				SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS);
6330ba785902SMichael Tuexen 				(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
6331ba785902SMichael Tuexen 				    SCTP_FROM_SCTPUTIL + SCTP_LOC_8);
633217205eccSRandall Stewart 				*error = ENOBUFS;
633317205eccSRandall Stewart 				goto out_now;
633417205eccSRandall Stewart 			}
633517205eccSRandall Stewart 			added++;
6336ea5eba11SMichael Tuexen 			break;
6337ea5eba11SMichael Tuexen #endif
6338ea5eba11SMichael Tuexen #ifdef INET6
6339ea5eba11SMichael Tuexen 		case AF_INET6:
634017205eccSRandall Stewart 			incr = sizeof(struct sockaddr_in6);
634192776dfdSMichael Tuexen 			sin6 = (struct sockaddr_in6 *)sa;
634292776dfdSMichael Tuexen 			if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) ||
634392776dfdSMichael Tuexen 			    IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
634492776dfdSMichael Tuexen 				SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6345ba785902SMichael Tuexen 				(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
6346ba785902SMichael Tuexen 				    SCTP_FROM_SCTPUTIL + SCTP_LOC_9);
634792776dfdSMichael Tuexen 				*error = EINVAL;
634892776dfdSMichael Tuexen 				goto out_now;
634992776dfdSMichael Tuexen 			}
63507154bf4aSMichael Tuexen 			if (sctp_add_remote_addr(stcb, sa, NULL, stcb->asoc.port,
63517154bf4aSMichael Tuexen 			    SCTP_DONOT_SETSCOPE,
63527154bf4aSMichael Tuexen 			    SCTP_ADDR_IS_CONFIRMED)) {
635317205eccSRandall Stewart 				/* assoc gone no un-lock */
6354c4739e2fSRandall Stewart 				SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS);
6355ba785902SMichael Tuexen 				(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
6356ba785902SMichael Tuexen 				    SCTP_FROM_SCTPUTIL + SCTP_LOC_10);
635717205eccSRandall Stewart 				*error = ENOBUFS;
635817205eccSRandall Stewart 				goto out_now;
635917205eccSRandall Stewart 			}
636017205eccSRandall Stewart 			added++;
6361ea5eba11SMichael Tuexen 			break;
6362ea5eba11SMichael Tuexen #endif
6363ea5eba11SMichael Tuexen 		default:
6364ea5eba11SMichael Tuexen 			break;
636517205eccSRandall Stewart 		}
636617205eccSRandall Stewart 		sa = (struct sockaddr *)((caddr_t)sa + incr);
636717205eccSRandall Stewart 	}
636817205eccSRandall Stewart out_now:
636917205eccSRandall Stewart 	return (added);
637017205eccSRandall Stewart }
637117205eccSRandall Stewart 
637217205eccSRandall Stewart struct sctp_tcb *
6373d61a0ae0SRandall Stewart sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr,
63749a8e3088SMichael Tuexen     unsigned int *totaddr,
63759a8e3088SMichael Tuexen     unsigned int *num_v4, unsigned int *num_v6, int *error,
63769a8e3088SMichael Tuexen     unsigned int limit, int *bad_addr)
637717205eccSRandall Stewart {
637817205eccSRandall Stewart 	struct sockaddr *sa;
637917205eccSRandall Stewart 	struct sctp_tcb *stcb = NULL;
63809a8e3088SMichael Tuexen 	unsigned int incr, at, i;
638117205eccSRandall Stewart 
6382e1949767SMichael Tuexen 	at = 0;
638317205eccSRandall Stewart 	sa = addr;
638417205eccSRandall Stewart 	*error = *num_v6 = *num_v4 = 0;
638517205eccSRandall Stewart 	/* account and validate addresses */
63869a8e3088SMichael Tuexen 	for (i = 0; i < *totaddr; i++) {
6387ea5eba11SMichael Tuexen 		switch (sa->sa_family) {
6388ea5eba11SMichael Tuexen #ifdef INET
6389ea5eba11SMichael Tuexen 		case AF_INET:
6390e1949767SMichael Tuexen 			incr = (unsigned int)sizeof(struct sockaddr_in);
6391d61a0ae0SRandall Stewart 			if (sa->sa_len != incr) {
6392c4739e2fSRandall Stewart 				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6393d61a0ae0SRandall Stewart 				*error = EINVAL;
6394d61a0ae0SRandall Stewart 				*bad_addr = 1;
6395d61a0ae0SRandall Stewart 				return (NULL);
6396d61a0ae0SRandall Stewart 			}
63979a8e3088SMichael Tuexen 			(*num_v4) += 1;
6398ea5eba11SMichael Tuexen 			break;
6399ea5eba11SMichael Tuexen #endif
6400ea5eba11SMichael Tuexen #ifdef INET6
6401ea5eba11SMichael Tuexen 		case AF_INET6:
6402ea5eba11SMichael Tuexen 			{
640317205eccSRandall Stewart 				struct sockaddr_in6 *sin6;
640417205eccSRandall Stewart 
640517205eccSRandall Stewart 				sin6 = (struct sockaddr_in6 *)sa;
640617205eccSRandall Stewart 				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
640717205eccSRandall Stewart 					/* Must be non-mapped for connectx */
6408c4739e2fSRandall Stewart 					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
640917205eccSRandall Stewart 					*error = EINVAL;
6410d61a0ae0SRandall Stewart 					*bad_addr = 1;
641117205eccSRandall Stewart 					return (NULL);
641217205eccSRandall Stewart 				}
6413e1949767SMichael Tuexen 				incr = (unsigned int)sizeof(struct sockaddr_in6);
6414d61a0ae0SRandall Stewart 				if (sa->sa_len != incr) {
6415c4739e2fSRandall Stewart 					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6416d61a0ae0SRandall Stewart 					*error = EINVAL;
6417d61a0ae0SRandall Stewart 					*bad_addr = 1;
6418d61a0ae0SRandall Stewart 					return (NULL);
6419d61a0ae0SRandall Stewart 				}
64209a8e3088SMichael Tuexen 				(*num_v6) += 1;
6421ea5eba11SMichael Tuexen 				break;
6422ea5eba11SMichael Tuexen 			}
6423ea5eba11SMichael Tuexen #endif
6424ea5eba11SMichael Tuexen 		default:
642517205eccSRandall Stewart 			*totaddr = i;
6426884d8c53SMichael Tuexen 			incr = 0;
642717205eccSRandall Stewart 			/* we are done */
642817205eccSRandall Stewart 			break;
642917205eccSRandall Stewart 		}
64309a8e3088SMichael Tuexen 		if (i == *totaddr) {
6431ea5eba11SMichael Tuexen 			break;
6432ea5eba11SMichael Tuexen 		}
6433d61a0ae0SRandall Stewart 		SCTP_INP_INCR_REF(inp);
643417205eccSRandall Stewart 		stcb = sctp_findassociation_ep_addr(&inp, sa, NULL, NULL, NULL);
643517205eccSRandall Stewart 		if (stcb != NULL) {
643617205eccSRandall Stewart 			/* Already have or am bring up an association */
643717205eccSRandall Stewart 			return (stcb);
6438d61a0ae0SRandall Stewart 		} else {
6439d61a0ae0SRandall Stewart 			SCTP_INP_DECR_REF(inp);
644017205eccSRandall Stewart 		}
64419a8e3088SMichael Tuexen 		if ((at + incr) > limit) {
644217205eccSRandall Stewart 			*totaddr = i;
644317205eccSRandall Stewart 			break;
644417205eccSRandall Stewart 		}
644517205eccSRandall Stewart 		sa = (struct sockaddr *)((caddr_t)sa + incr);
644617205eccSRandall Stewart 	}
644717205eccSRandall Stewart 	return ((struct sctp_tcb *)NULL);
644817205eccSRandall Stewart }
644935918f85SRandall Stewart 
645035918f85SRandall Stewart /*
645135918f85SRandall Stewart  * sctp_bindx(ADD) for one address.
645235918f85SRandall Stewart  * assumes all arguments are valid/checked by caller.
645335918f85SRandall Stewart  */
645435918f85SRandall Stewart void
645535918f85SRandall Stewart sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp,
645635918f85SRandall Stewart     struct sockaddr *sa, sctp_assoc_t assoc_id,
645735918f85SRandall Stewart     uint32_t vrf_id, int *error, void *p)
645835918f85SRandall Stewart {
645935918f85SRandall Stewart 	struct sockaddr *addr_touse;
6460d59107f7SMichael Tuexen #if defined(INET) && defined(INET6)
646135918f85SRandall Stewart 	struct sockaddr_in sin;
64625e2c2d87SRandall Stewart #endif
64635e2c2d87SRandall Stewart 
646435918f85SRandall Stewart 	/* see if we're bound all already! */
646535918f85SRandall Stewart 	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
6466c4739e2fSRandall Stewart 		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
646735918f85SRandall Stewart 		*error = EINVAL;
646835918f85SRandall Stewart 		return;
646935918f85SRandall Stewart 	}
647035918f85SRandall Stewart 	addr_touse = sa;
6471ea5eba11SMichael Tuexen #ifdef INET6
647235918f85SRandall Stewart 	if (sa->sa_family == AF_INET6) {
6473d59107f7SMichael Tuexen #ifdef INET
647435918f85SRandall Stewart 		struct sockaddr_in6 *sin6;
647535918f85SRandall Stewart 
6476d59107f7SMichael Tuexen #endif
647735918f85SRandall Stewart 		if (sa->sa_len != sizeof(struct sockaddr_in6)) {
6478c4739e2fSRandall Stewart 			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
647935918f85SRandall Stewart 			*error = EINVAL;
648035918f85SRandall Stewart 			return;
648135918f85SRandall Stewart 		}
6482db4fd95bSRandall Stewart 		if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
6483db4fd95bSRandall Stewart 			/* can only bind v6 on PF_INET6 sockets */
6484c4739e2fSRandall Stewart 			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6485db4fd95bSRandall Stewart 			*error = EINVAL;
6486db4fd95bSRandall Stewart 			return;
6487db4fd95bSRandall Stewart 		}
6488d59107f7SMichael Tuexen #ifdef INET
648935918f85SRandall Stewart 		sin6 = (struct sockaddr_in6 *)addr_touse;
649035918f85SRandall Stewart 		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
6491db4fd95bSRandall Stewart 			if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
6492db4fd95bSRandall Stewart 			    SCTP_IPV6_V6ONLY(inp)) {
6493db4fd95bSRandall Stewart 				/* can't bind v4-mapped on PF_INET sockets */
6494c4739e2fSRandall Stewart 				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6495db4fd95bSRandall Stewart 				*error = EINVAL;
6496db4fd95bSRandall Stewart 				return;
6497db4fd95bSRandall Stewart 			}
649835918f85SRandall Stewart 			in6_sin6_2_sin(&sin, sin6);
649935918f85SRandall Stewart 			addr_touse = (struct sockaddr *)&sin;
650035918f85SRandall Stewart 		}
6501d59107f7SMichael Tuexen #endif
650235918f85SRandall Stewart 	}
650335918f85SRandall Stewart #endif
6504ea5eba11SMichael Tuexen #ifdef INET
650535918f85SRandall Stewart 	if (sa->sa_family == AF_INET) {
650635918f85SRandall Stewart 		if (sa->sa_len != sizeof(struct sockaddr_in)) {
6507c4739e2fSRandall Stewart 			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
650835918f85SRandall Stewart 			*error = EINVAL;
650935918f85SRandall Stewart 			return;
651035918f85SRandall Stewart 		}
6511db4fd95bSRandall Stewart 		if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
6512db4fd95bSRandall Stewart 		    SCTP_IPV6_V6ONLY(inp)) {
6513db4fd95bSRandall Stewart 			/* can't bind v4 on PF_INET sockets */
6514c4739e2fSRandall Stewart 			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6515db4fd95bSRandall Stewart 			*error = EINVAL;
6516db4fd95bSRandall Stewart 			return;
6517db4fd95bSRandall Stewart 		}
651835918f85SRandall Stewart 	}
6519ea5eba11SMichael Tuexen #endif
652035918f85SRandall Stewart 	if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) {
652135918f85SRandall Stewart 		if (p == NULL) {
652235918f85SRandall Stewart 			/* Can't get proc for Net/Open BSD */
6523c4739e2fSRandall Stewart 			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
652435918f85SRandall Stewart 			*error = EINVAL;
652535918f85SRandall Stewart 			return;
652635918f85SRandall Stewart 		}
65271b649582SRandall Stewart 		*error = sctp_inpcb_bind(so, addr_touse, NULL, p);
652835918f85SRandall Stewart 		return;
652935918f85SRandall Stewart 	}
653035918f85SRandall Stewart 	/*
653135918f85SRandall Stewart 	 * No locks required here since bind and mgmt_ep_sa all do their own
653235918f85SRandall Stewart 	 * locking. If we do something for the FIX: below we may need to
653335918f85SRandall Stewart 	 * lock in that case.
653435918f85SRandall Stewart 	 */
653535918f85SRandall Stewart 	if (assoc_id == 0) {
653635918f85SRandall Stewart 		/* add the address */
653735918f85SRandall Stewart 		struct sctp_inpcb *lep;
653897c76f10SRandall Stewart 		struct sockaddr_in *lsin = (struct sockaddr_in *)addr_touse;
653935918f85SRandall Stewart 
654097c76f10SRandall Stewart 		/* validate the incoming port */
654197c76f10SRandall Stewart 		if ((lsin->sin_port != 0) &&
654297c76f10SRandall Stewart 		    (lsin->sin_port != inp->sctp_lport)) {
6543c4739e2fSRandall Stewart 			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
654497c76f10SRandall Stewart 			*error = EINVAL;
654597c76f10SRandall Stewart 			return;
654697c76f10SRandall Stewart 		} else {
654797c76f10SRandall Stewart 			/* user specified 0 port, set it to existing port */
654897c76f10SRandall Stewart 			lsin->sin_port = inp->sctp_lport;
654997c76f10SRandall Stewart 		}
655097c76f10SRandall Stewart 
655135918f85SRandall Stewart 		lep = sctp_pcb_findep(addr_touse, 1, 0, vrf_id);
655235918f85SRandall Stewart 		if (lep != NULL) {
655335918f85SRandall Stewart 			/*
655435918f85SRandall Stewart 			 * We must decrement the refcount since we have the
655535918f85SRandall Stewart 			 * ep already and are binding. No remove going on
655635918f85SRandall Stewart 			 * here.
655735918f85SRandall Stewart 			 */
65586d9e8f2bSRandall Stewart 			SCTP_INP_DECR_REF(lep);
655935918f85SRandall Stewart 		}
656035918f85SRandall Stewart 		if (lep == inp) {
656135918f85SRandall Stewart 			/* already bound to it.. ok */
656235918f85SRandall Stewart 			return;
656335918f85SRandall Stewart 		} else if (lep == NULL) {
656435918f85SRandall Stewart 			((struct sockaddr_in *)addr_touse)->sin_port = 0;
656535918f85SRandall Stewart 			*error = sctp_addr_mgmt_ep_sa(inp, addr_touse,
656635918f85SRandall Stewart 			    SCTP_ADD_IP_ADDRESS,
656780fefe0aSRandall Stewart 			    vrf_id, NULL);
656835918f85SRandall Stewart 		} else {
656935918f85SRandall Stewart 			*error = EADDRINUSE;
657035918f85SRandall Stewart 		}
657135918f85SRandall Stewart 		if (*error)
657235918f85SRandall Stewart 			return;
657335918f85SRandall Stewart 	} else {
657435918f85SRandall Stewart 		/*
657535918f85SRandall Stewart 		 * FIX: decide whether we allow assoc based bindx
657635918f85SRandall Stewart 		 */
657735918f85SRandall Stewart 	}
657835918f85SRandall Stewart }
657935918f85SRandall Stewart 
658035918f85SRandall Stewart /*
658135918f85SRandall Stewart  * sctp_bindx(DELETE) for one address.
658235918f85SRandall Stewart  * assumes all arguments are valid/checked by caller.
658335918f85SRandall Stewart  */
658435918f85SRandall Stewart void
65857215cc1bSMichael Tuexen sctp_bindx_delete_address(struct sctp_inpcb *inp,
658635918f85SRandall Stewart     struct sockaddr *sa, sctp_assoc_t assoc_id,
658735918f85SRandall Stewart     uint32_t vrf_id, int *error)
658835918f85SRandall Stewart {
658935918f85SRandall Stewart 	struct sockaddr *addr_touse;
6590d59107f7SMichael Tuexen #if defined(INET) && defined(INET6)
659135918f85SRandall Stewart 	struct sockaddr_in sin;
65925e2c2d87SRandall Stewart #endif
65935e2c2d87SRandall Stewart 
659435918f85SRandall Stewart 	/* see if we're bound all already! */
659535918f85SRandall Stewart 	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
6596c4739e2fSRandall Stewart 		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
659735918f85SRandall Stewart 		*error = EINVAL;
659835918f85SRandall Stewart 		return;
659935918f85SRandall Stewart 	}
660035918f85SRandall Stewart 	addr_touse = sa;
6601e0e00a4dSMichael Tuexen #ifdef INET6
660235918f85SRandall Stewart 	if (sa->sa_family == AF_INET6) {
6603d59107f7SMichael Tuexen #ifdef INET
660435918f85SRandall Stewart 		struct sockaddr_in6 *sin6;
6605d59107f7SMichael Tuexen #endif
6606d59107f7SMichael Tuexen 
660735918f85SRandall Stewart 		if (sa->sa_len != sizeof(struct sockaddr_in6)) {
6608c4739e2fSRandall Stewart 			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
660935918f85SRandall Stewart 			*error = EINVAL;
661035918f85SRandall Stewart 			return;
661135918f85SRandall Stewart 		}
6612db4fd95bSRandall Stewart 		if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
6613db4fd95bSRandall Stewart 			/* can only bind v6 on PF_INET6 sockets */
6614c4739e2fSRandall Stewart 			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6615db4fd95bSRandall Stewart 			*error = EINVAL;
6616db4fd95bSRandall Stewart 			return;
6617db4fd95bSRandall Stewart 		}
6618d59107f7SMichael Tuexen #ifdef INET
661935918f85SRandall Stewart 		sin6 = (struct sockaddr_in6 *)addr_touse;
662035918f85SRandall Stewart 		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
6621db4fd95bSRandall Stewart 			if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
6622db4fd95bSRandall Stewart 			    SCTP_IPV6_V6ONLY(inp)) {
6623db4fd95bSRandall Stewart 				/* can't bind mapped-v4 on PF_INET sockets */
6624c4739e2fSRandall Stewart 				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6625db4fd95bSRandall Stewart 				*error = EINVAL;
6626db4fd95bSRandall Stewart 				return;
6627db4fd95bSRandall Stewart 			}
662835918f85SRandall Stewart 			in6_sin6_2_sin(&sin, sin6);
662935918f85SRandall Stewart 			addr_touse = (struct sockaddr *)&sin;
663035918f85SRandall Stewart 		}
6631d59107f7SMichael Tuexen #endif
663235918f85SRandall Stewart 	}
663335918f85SRandall Stewart #endif
6634ea5eba11SMichael Tuexen #ifdef INET
663535918f85SRandall Stewart 	if (sa->sa_family == AF_INET) {
663635918f85SRandall Stewart 		if (sa->sa_len != sizeof(struct sockaddr_in)) {
6637c4739e2fSRandall Stewart 			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
663835918f85SRandall Stewart 			*error = EINVAL;
663935918f85SRandall Stewart 			return;
664035918f85SRandall Stewart 		}
6641db4fd95bSRandall Stewart 		if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
6642db4fd95bSRandall Stewart 		    SCTP_IPV6_V6ONLY(inp)) {
6643db4fd95bSRandall Stewart 			/* can't bind v4 on PF_INET sockets */
6644c4739e2fSRandall Stewart 			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6645db4fd95bSRandall Stewart 			*error = EINVAL;
6646db4fd95bSRandall Stewart 			return;
6647db4fd95bSRandall Stewart 		}
664835918f85SRandall Stewart 	}
6649ea5eba11SMichael Tuexen #endif
665035918f85SRandall Stewart 	/*
665135918f85SRandall Stewart 	 * No lock required mgmt_ep_sa does its own locking. If the FIX:
665235918f85SRandall Stewart 	 * below is ever changed we may need to lock before calling
665335918f85SRandall Stewart 	 * association level binding.
665435918f85SRandall Stewart 	 */
665535918f85SRandall Stewart 	if (assoc_id == 0) {
665635918f85SRandall Stewart 		/* delete the address */
665735918f85SRandall Stewart 		*error = sctp_addr_mgmt_ep_sa(inp, addr_touse,
665835918f85SRandall Stewart 		    SCTP_DEL_IP_ADDRESS,
665980fefe0aSRandall Stewart 		    vrf_id, NULL);
666035918f85SRandall Stewart 	} else {
666135918f85SRandall Stewart 		/*
666235918f85SRandall Stewart 		 * FIX: decide whether we allow assoc based bindx
666335918f85SRandall Stewart 		 */
666435918f85SRandall Stewart 	}
666535918f85SRandall Stewart }
66661b649582SRandall Stewart 
66671b649582SRandall Stewart /*
66681b649582SRandall Stewart  * returns the valid local address count for an assoc, taking into account
66691b649582SRandall Stewart  * all scoping rules
66701b649582SRandall Stewart  */
66711b649582SRandall Stewart int
66721b649582SRandall Stewart sctp_local_addr_count(struct sctp_tcb *stcb)
66731b649582SRandall Stewart {
6674b54ddf22SMichael Tuexen 	int loopback_scope;
6675b54ddf22SMichael Tuexen #if defined(INET)
6676b54ddf22SMichael Tuexen 	int ipv4_local_scope, ipv4_addr_legal;
6677b54ddf22SMichael Tuexen #endif
6678b54ddf22SMichael Tuexen #if defined (INET6)
6679b54ddf22SMichael Tuexen 	int local_scope, site_scope, ipv6_addr_legal;
6680b54ddf22SMichael Tuexen #endif
66811b649582SRandall Stewart 	struct sctp_vrf *vrf;
66821b649582SRandall Stewart 	struct sctp_ifn *sctp_ifn;
66831b649582SRandall Stewart 	struct sctp_ifa *sctp_ifa;
66841b649582SRandall Stewart 	int count = 0;
66851b649582SRandall Stewart 
66861b649582SRandall Stewart 	/* Turn on all the appropriate scopes */
6687a1cb341bSMichael Tuexen 	loopback_scope = stcb->asoc.scope.loopback_scope;
6688b54ddf22SMichael Tuexen #if defined(INET)
6689a1cb341bSMichael Tuexen 	ipv4_local_scope = stcb->asoc.scope.ipv4_local_scope;
6690b54ddf22SMichael Tuexen 	ipv4_addr_legal = stcb->asoc.scope.ipv4_addr_legal;
6691b54ddf22SMichael Tuexen #endif
6692b54ddf22SMichael Tuexen #if defined(INET6)
6693a1cb341bSMichael Tuexen 	local_scope = stcb->asoc.scope.local_scope;
6694a1cb341bSMichael Tuexen 	site_scope = stcb->asoc.scope.site_scope;
6695a1cb341bSMichael Tuexen 	ipv6_addr_legal = stcb->asoc.scope.ipv6_addr_legal;
6696b54ddf22SMichael Tuexen #endif
6697c99efcf6SRandall Stewart 	SCTP_IPI_ADDR_RLOCK();
66981b649582SRandall Stewart 	vrf = sctp_find_vrf(stcb->asoc.vrf_id);
66991b649582SRandall Stewart 	if (vrf == NULL) {
67001b649582SRandall Stewart 		/* no vrf, no addresses */
6701c99efcf6SRandall Stewart 		SCTP_IPI_ADDR_RUNLOCK();
67021b649582SRandall Stewart 		return (0);
67031b649582SRandall Stewart 	}
67041b649582SRandall Stewart 	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
67051b649582SRandall Stewart 		/*
67061b649582SRandall Stewart 		 * bound all case: go through all ifns on the vrf
67071b649582SRandall Stewart 		 */
67081b649582SRandall Stewart 		LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
67091b649582SRandall Stewart 			if ((loopback_scope == 0) &&
67101b649582SRandall Stewart 			    SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
67111b649582SRandall Stewart 				continue;
67121b649582SRandall Stewart 			}
67131b649582SRandall Stewart 			LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
67141b649582SRandall Stewart 				if (sctp_is_addr_restricted(stcb, sctp_ifa))
67151b649582SRandall Stewart 					continue;
67165e2c2d87SRandall Stewart 				switch (sctp_ifa->address.sa.sa_family) {
6717ea5eba11SMichael Tuexen #ifdef INET
67185e2c2d87SRandall Stewart 				case AF_INET:
67195e2c2d87SRandall Stewart 					if (ipv4_addr_legal) {
67201b649582SRandall Stewart 						struct sockaddr_in *sin;
67211b649582SRandall Stewart 
672224aaac8dSMichael Tuexen 						sin = &sctp_ifa->address.sin;
67231b649582SRandall Stewart 						if (sin->sin_addr.s_addr == 0) {
6724b7b84c0eSMichael Tuexen 							/*
6725b7b84c0eSMichael Tuexen 							 * skip unspecified
6726b7b84c0eSMichael Tuexen 							 * addrs
6727b7b84c0eSMichael Tuexen 							 */
67281b649582SRandall Stewart 							continue;
67291b649582SRandall Stewart 						}
67306ba22f19SMichael Tuexen 						if (prison_check_ip4(stcb->sctp_ep->ip_inp.inp.inp_cred,
67316ba22f19SMichael Tuexen 						    &sin->sin_addr) != 0) {
67326ba22f19SMichael Tuexen 							continue;
67336ba22f19SMichael Tuexen 						}
67341b649582SRandall Stewart 						if ((ipv4_local_scope == 0) &&
67351b649582SRandall Stewart 						    (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) {
67361b649582SRandall Stewart 							continue;
67371b649582SRandall Stewart 						}
67381b649582SRandall Stewart 						/* count this one */
67391b649582SRandall Stewart 						count++;
67405e2c2d87SRandall Stewart 					} else {
67415e2c2d87SRandall Stewart 						continue;
67425e2c2d87SRandall Stewart 					}
67435e2c2d87SRandall Stewart 					break;
6744ea5eba11SMichael Tuexen #endif
67455e2c2d87SRandall Stewart #ifdef INET6
67465e2c2d87SRandall Stewart 				case AF_INET6:
67475e2c2d87SRandall Stewart 					if (ipv6_addr_legal) {
67481b649582SRandall Stewart 						struct sockaddr_in6 *sin6;
67491b649582SRandall Stewart 
675024aaac8dSMichael Tuexen 						sin6 = &sctp_ifa->address.sin6;
67511b649582SRandall Stewart 						if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
67521b649582SRandall Stewart 							continue;
67531b649582SRandall Stewart 						}
67546ba22f19SMichael Tuexen 						if (prison_check_ip6(stcb->sctp_ep->ip_inp.inp.inp_cred,
67556ba22f19SMichael Tuexen 						    &sin6->sin6_addr) != 0) {
67566ba22f19SMichael Tuexen 							continue;
67576ba22f19SMichael Tuexen 						}
67581b649582SRandall Stewart 						if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
67591b649582SRandall Stewart 							if (local_scope == 0)
67601b649582SRandall Stewart 								continue;
67611b649582SRandall Stewart 							if (sin6->sin6_scope_id == 0) {
67621b649582SRandall Stewart 								if (sa6_recoverscope(sin6) != 0)
67631b649582SRandall Stewart 									/*
67645e2c2d87SRandall Stewart 									 *
67655e2c2d87SRandall Stewart 									 * bad
67665b495f17SMichael Tuexen 									 * link
67675e2c2d87SRandall Stewart 									 *
67685b495f17SMichael Tuexen 									 * local
67695e2c2d87SRandall Stewart 									 *
67705b495f17SMichael Tuexen 									 * address
67715b495f17SMichael Tuexen 									 */
67721b649582SRandall Stewart 									continue;
67731b649582SRandall Stewart 							}
67741b649582SRandall Stewart 						}
67751b649582SRandall Stewart 						if ((site_scope == 0) &&
67761b649582SRandall Stewart 						    (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) {
67771b649582SRandall Stewart 							continue;
67781b649582SRandall Stewart 						}
67791b649582SRandall Stewart 						/* count this one */
67801b649582SRandall Stewart 						count++;
67811b649582SRandall Stewart 					}
67825e2c2d87SRandall Stewart 					break;
67835e2c2d87SRandall Stewart #endif
67845e2c2d87SRandall Stewart 				default:
67855e2c2d87SRandall Stewart 					/* TSNH */
67865e2c2d87SRandall Stewart 					break;
67875e2c2d87SRandall Stewart 				}
67881b649582SRandall Stewart 			}
67891b649582SRandall Stewart 		}
67901b649582SRandall Stewart 	} else {
67911b649582SRandall Stewart 		/*
67921b649582SRandall Stewart 		 * subset bound case
67931b649582SRandall Stewart 		 */
67941b649582SRandall Stewart 		struct sctp_laddr *laddr;
67951b649582SRandall Stewart 
67961b649582SRandall Stewart 		LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list,
67971b649582SRandall Stewart 		    sctp_nxt_addr) {
67981b649582SRandall Stewart 			if (sctp_is_addr_restricted(stcb, laddr->ifa)) {
67991b649582SRandall Stewart 				continue;
68001b649582SRandall Stewart 			}
68011b649582SRandall Stewart 			/* count this one */
68021b649582SRandall Stewart 			count++;
68031b649582SRandall Stewart 		}
68041b649582SRandall Stewart 	}
6805c99efcf6SRandall Stewart 	SCTP_IPI_ADDR_RUNLOCK();
68061b649582SRandall Stewart 	return (count);
68071b649582SRandall Stewart }
6808c4739e2fSRandall Stewart 
6809c4739e2fSRandall Stewart #if defined(SCTP_LOCAL_TRACE_BUF)
6810c4739e2fSRandall Stewart 
6811c4739e2fSRandall Stewart void
6812b27a6b7dSRandall Stewart sctp_log_trace(uint32_t subsys, const char *str SCTP_UNUSED, uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t e, uint32_t f)
6813c4739e2fSRandall Stewart {
6814b27a6b7dSRandall Stewart 	uint32_t saveindex, newindex;
6815c4739e2fSRandall Stewart 
6816c4739e2fSRandall Stewart 	do {
6817b3f1ea41SRandall Stewart 		saveindex = SCTP_BASE_SYSCTL(sctp_log).index;
6818c4739e2fSRandall Stewart 		if (saveindex >= SCTP_MAX_LOGGING_SIZE) {
6819c4739e2fSRandall Stewart 			newindex = 1;
6820c4739e2fSRandall Stewart 		} else {
6821c4739e2fSRandall Stewart 			newindex = saveindex + 1;
6822c4739e2fSRandall Stewart 		}
6823b3f1ea41SRandall Stewart 	} while (atomic_cmpset_int(&SCTP_BASE_SYSCTL(sctp_log).index, saveindex, newindex) == 0);
6824c4739e2fSRandall Stewart 	if (saveindex >= SCTP_MAX_LOGGING_SIZE) {
6825c4739e2fSRandall Stewart 		saveindex = 0;
6826c4739e2fSRandall Stewart 	}
6827b3f1ea41SRandall Stewart 	SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].timestamp = SCTP_GET_CYCLECOUNT;
6828b3f1ea41SRandall Stewart 	SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].subsys = subsys;
6829b3f1ea41SRandall Stewart 	SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[0] = a;
6830b3f1ea41SRandall Stewart 	SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[1] = b;
6831b3f1ea41SRandall Stewart 	SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[2] = c;
6832b3f1ea41SRandall Stewart 	SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[3] = d;
6833b3f1ea41SRandall Stewart 	SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[4] = e;
6834b3f1ea41SRandall Stewart 	SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[5] = f;
6835c4739e2fSRandall Stewart }
6836c4739e2fSRandall Stewart 
6837c4739e2fSRandall Stewart #endif
6838a99b6783SRandall Stewart static void
68397cca1775SRandall Stewart sctp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *inp,
684081d3ec17SBryan Venteicher     const struct sockaddr *sa SCTP_UNUSED, void *ctx SCTP_UNUSED)
6841a99b6783SRandall Stewart {
6842a99b6783SRandall Stewart 	struct ip *iph;
68433a51a264SMichael Tuexen #ifdef INET6
68443a51a264SMichael Tuexen 	struct ip6_hdr *ip6;
68453a51a264SMichael Tuexen #endif
6846a99b6783SRandall Stewart 	struct mbuf *sp, *last;
6847a99b6783SRandall Stewart 	struct udphdr *uhdr;
6848285052f0SMichael Tuexen 	uint16_t port;
6849a99b6783SRandall Stewart 
6850a99b6783SRandall Stewart 	if ((m->m_flags & M_PKTHDR) == 0) {
6851a99b6783SRandall Stewart 		/* Can't handle one that is not a pkt hdr */
6852a99b6783SRandall Stewart 		goto out;
6853a99b6783SRandall Stewart 	}
6854285052f0SMichael Tuexen 	/* Pull the src port */
6855a99b6783SRandall Stewart 	iph = mtod(m, struct ip *);
6856a99b6783SRandall Stewart 	uhdr = (struct udphdr *)((caddr_t)iph + off);
6857a99b6783SRandall Stewart 	port = uhdr->uh_sport;
6858285052f0SMichael Tuexen 	/*
6859285052f0SMichael Tuexen 	 * Split out the mbuf chain. Leave the IP header in m, place the
6860285052f0SMichael Tuexen 	 * rest in the sp.
6861285052f0SMichael Tuexen 	 */
6862eb1b1807SGleb Smirnoff 	sp = m_split(m, off, M_NOWAIT);
6863a99b6783SRandall Stewart 	if (sp == NULL) {
6864a99b6783SRandall Stewart 		/* Gak, drop packet, we can't do a split */
6865a99b6783SRandall Stewart 		goto out;
6866a99b6783SRandall Stewart 	}
6867285052f0SMichael Tuexen 	if (sp->m_pkthdr.len < sizeof(struct udphdr) + sizeof(struct sctphdr)) {
6868285052f0SMichael Tuexen 		/* Gak, packet can't have an SCTP header in it - too small */
6869a99b6783SRandall Stewart 		m_freem(sp);
6870a99b6783SRandall Stewart 		goto out;
6871a99b6783SRandall Stewart 	}
6872285052f0SMichael Tuexen 	/* Now pull up the UDP header and SCTP header together */
6873285052f0SMichael Tuexen 	sp = m_pullup(sp, sizeof(struct udphdr) + sizeof(struct sctphdr));
6874a99b6783SRandall Stewart 	if (sp == NULL) {
6875a99b6783SRandall Stewart 		/* Gak pullup failed */
6876a99b6783SRandall Stewart 		goto out;
6877a99b6783SRandall Stewart 	}
6878285052f0SMichael Tuexen 	/* Trim out the UDP header */
6879a99b6783SRandall Stewart 	m_adj(sp, sizeof(struct udphdr));
6880a99b6783SRandall Stewart 
6881a99b6783SRandall Stewart 	/* Now reconstruct the mbuf chain */
6882285052f0SMichael Tuexen 	for (last = m; last->m_next; last = last->m_next);
6883a99b6783SRandall Stewart 	last->m_next = sp;
6884a99b6783SRandall Stewart 	m->m_pkthdr.len += sp->m_pkthdr.len;
688552f175beSMichael Tuexen 	/*
688652f175beSMichael Tuexen 	 * The CSUM_DATA_VALID flags indicates that the HW checked the UDP
688752f175beSMichael Tuexen 	 * checksum and it was valid. Since CSUM_DATA_VALID ==
688852f175beSMichael Tuexen 	 * CSUM_SCTP_VALID this would imply that the HW also verified the
688952f175beSMichael Tuexen 	 * SCTP checksum. Therefore, clear the bit.
689052f175beSMichael Tuexen 	 */
689152f175beSMichael Tuexen 	SCTPDBG(SCTP_DEBUG_CRCOFFLOAD,
689252f175beSMichael Tuexen 	    "sctp_recv_udp_tunneled_packet(): Packet of length %d received on %s with csum_flags 0x%b.\n",
689352f175beSMichael Tuexen 	    m->m_pkthdr.len,
689452f175beSMichael Tuexen 	    if_name(m->m_pkthdr.rcvif),
689552f175beSMichael Tuexen 	    (int)m->m_pkthdr.csum_flags, CSUM_BITS);
689652f175beSMichael Tuexen 	m->m_pkthdr.csum_flags &= ~CSUM_DATA_VALID;
6897a99b6783SRandall Stewart 	iph = mtod(m, struct ip *);
6898a99b6783SRandall Stewart 	switch (iph->ip_v) {
6899e6194c2eSMichael Tuexen #ifdef INET
6900a99b6783SRandall Stewart 	case IPVERSION:
690109c1c856SMichael Tuexen 		iph->ip_len = htons(ntohs(iph->ip_len) - sizeof(struct udphdr));
6902a99b6783SRandall Stewart 		sctp_input_with_port(m, off, port);
6903a99b6783SRandall Stewart 		break;
6904e6194c2eSMichael Tuexen #endif
6905a99b6783SRandall Stewart #ifdef INET6
6906a99b6783SRandall Stewart 	case IPV6_VERSION >> 4:
69073a51a264SMichael Tuexen 		ip6 = mtod(m, struct ip6_hdr *);
69083a51a264SMichael Tuexen 		ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - sizeof(struct udphdr));
69093a51a264SMichael Tuexen 		sctp6_input_with_port(&m, &off, port);
6910a99b6783SRandall Stewart 		break;
6911a99b6783SRandall Stewart #endif
6912a99b6783SRandall Stewart 	default:
6913285052f0SMichael Tuexen 		goto out;
6914a99b6783SRandall Stewart 		break;
6915a99b6783SRandall Stewart 	}
6916a99b6783SRandall Stewart 	return;
6917a99b6783SRandall Stewart out:
6918a99b6783SRandall Stewart 	m_freem(m);
6919a99b6783SRandall Stewart }
6920c54a18d2SRandall Stewart 
6921fd7af143SMichael Tuexen #ifdef INET
6922fd7af143SMichael Tuexen static void
6923fd7af143SMichael Tuexen sctp_recv_icmp_tunneled_packet(int cmd, struct sockaddr *sa, void *vip, void *ctx SCTP_UNUSED)
6924fd7af143SMichael Tuexen {
6925fd7af143SMichael Tuexen 	struct ip *outer_ip, *inner_ip;
6926fd7af143SMichael Tuexen 	struct sctphdr *sh;
6927fd7af143SMichael Tuexen 	struct icmp *icmp;
6928fd7af143SMichael Tuexen 	struct udphdr *udp;
6929fd7af143SMichael Tuexen 	struct sctp_inpcb *inp;
6930fd7af143SMichael Tuexen 	struct sctp_tcb *stcb;
6931fd7af143SMichael Tuexen 	struct sctp_nets *net;
6932fd7af143SMichael Tuexen 	struct sctp_init_chunk *ch;
6933fd7af143SMichael Tuexen 	struct sockaddr_in src, dst;
6934fd7af143SMichael Tuexen 	uint8_t type, code;
6935fd7af143SMichael Tuexen 
6936fd7af143SMichael Tuexen 	inner_ip = (struct ip *)vip;
6937fd7af143SMichael Tuexen 	icmp = (struct icmp *)((caddr_t)inner_ip -
6938fd7af143SMichael Tuexen 	    (sizeof(struct icmp) - sizeof(struct ip)));
6939fd7af143SMichael Tuexen 	outer_ip = (struct ip *)((caddr_t)icmp - sizeof(struct ip));
6940fd7af143SMichael Tuexen 	if (ntohs(outer_ip->ip_len) <
6941fd7af143SMichael Tuexen 	    sizeof(struct ip) + 8 + (inner_ip->ip_hl << 2) + sizeof(struct udphdr) + 8) {
6942fd7af143SMichael Tuexen 		return;
6943fd7af143SMichael Tuexen 	}
6944fd7af143SMichael Tuexen 	udp = (struct udphdr *)((caddr_t)inner_ip + (inner_ip->ip_hl << 2));
6945fd7af143SMichael Tuexen 	sh = (struct sctphdr *)(udp + 1);
6946fd7af143SMichael Tuexen 	memset(&src, 0, sizeof(struct sockaddr_in));
6947fd7af143SMichael Tuexen 	src.sin_family = AF_INET;
6948fd7af143SMichael Tuexen 	src.sin_len = sizeof(struct sockaddr_in);
6949fd7af143SMichael Tuexen 	src.sin_port = sh->src_port;
6950fd7af143SMichael Tuexen 	src.sin_addr = inner_ip->ip_src;
6951fd7af143SMichael Tuexen 	memset(&dst, 0, sizeof(struct sockaddr_in));
6952fd7af143SMichael Tuexen 	dst.sin_family = AF_INET;
6953fd7af143SMichael Tuexen 	dst.sin_len = sizeof(struct sockaddr_in);
6954fd7af143SMichael Tuexen 	dst.sin_port = sh->dest_port;
6955fd7af143SMichael Tuexen 	dst.sin_addr = inner_ip->ip_dst;
6956fd7af143SMichael Tuexen 	/*
6957fd7af143SMichael Tuexen 	 * 'dst' holds the dest of the packet that failed to be sent. 'src'
6958fd7af143SMichael Tuexen 	 * holds our local endpoint address. Thus we reverse the dst and the
6959fd7af143SMichael Tuexen 	 * src in the lookup.
6960fd7af143SMichael Tuexen 	 */
6961fd7af143SMichael Tuexen 	inp = NULL;
6962fd7af143SMichael Tuexen 	net = NULL;
6963fd7af143SMichael Tuexen 	stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst,
6964fd7af143SMichael Tuexen 	    (struct sockaddr *)&src,
6965fd7af143SMichael Tuexen 	    &inp, &net, 1,
6966fd7af143SMichael Tuexen 	    SCTP_DEFAULT_VRFID);
6967fd7af143SMichael Tuexen 	if ((stcb != NULL) &&
6968fd7af143SMichael Tuexen 	    (net != NULL) &&
696955b8cd93SMichael Tuexen 	    (inp != NULL)) {
6970fd7af143SMichael Tuexen 		/* Check the UDP port numbers */
6971fd7af143SMichael Tuexen 		if ((udp->uh_dport != net->port) ||
6972fd7af143SMichael Tuexen 		    (udp->uh_sport != htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)))) {
6973fd7af143SMichael Tuexen 			SCTP_TCB_UNLOCK(stcb);
6974fd7af143SMichael Tuexen 			return;
6975fd7af143SMichael Tuexen 		}
6976fd7af143SMichael Tuexen 		/* Check the verification tag */
6977fd7af143SMichael Tuexen 		if (ntohl(sh->v_tag) != 0) {
6978fd7af143SMichael Tuexen 			/*
6979fd7af143SMichael Tuexen 			 * This must be the verification tag used for
6980fd7af143SMichael Tuexen 			 * sending out packets. We don't consider packets
6981fd7af143SMichael Tuexen 			 * reflecting the verification tag.
6982fd7af143SMichael Tuexen 			 */
6983fd7af143SMichael Tuexen 			if (ntohl(sh->v_tag) != stcb->asoc.peer_vtag) {
6984fd7af143SMichael Tuexen 				SCTP_TCB_UNLOCK(stcb);
6985fd7af143SMichael Tuexen 				return;
6986fd7af143SMichael Tuexen 			}
6987fd7af143SMichael Tuexen 		} else {
6988fd7af143SMichael Tuexen 			if (ntohs(outer_ip->ip_len) >=
6989fd7af143SMichael Tuexen 			    sizeof(struct ip) +
6990fd7af143SMichael Tuexen 			    8 + (inner_ip->ip_hl << 2) + 8 + 20) {
6991fd7af143SMichael Tuexen 				/*
6992fd7af143SMichael Tuexen 				 * In this case we can check if we got an
6993fd7af143SMichael Tuexen 				 * INIT chunk and if the initiate tag
6994fd7af143SMichael Tuexen 				 * matches.
6995fd7af143SMichael Tuexen 				 */
6996fd7af143SMichael Tuexen 				ch = (struct sctp_init_chunk *)(sh + 1);
6997fd7af143SMichael Tuexen 				if ((ch->ch.chunk_type != SCTP_INITIATION) ||
6998fd7af143SMichael Tuexen 				    (ntohl(ch->init.initiate_tag) != stcb->asoc.my_vtag)) {
6999fd7af143SMichael Tuexen 					SCTP_TCB_UNLOCK(stcb);
7000fd7af143SMichael Tuexen 					return;
7001fd7af143SMichael Tuexen 				}
7002fd7af143SMichael Tuexen 			} else {
7003fd7af143SMichael Tuexen 				SCTP_TCB_UNLOCK(stcb);
7004fd7af143SMichael Tuexen 				return;
7005fd7af143SMichael Tuexen 			}
7006fd7af143SMichael Tuexen 		}
7007fd7af143SMichael Tuexen 		type = icmp->icmp_type;
7008fd7af143SMichael Tuexen 		code = icmp->icmp_code;
70093c3f9e2aSMichael Tuexen 		if ((type == ICMP_UNREACH) &&
70103c3f9e2aSMichael Tuexen 		    (code == ICMP_UNREACH_PORT)) {
7011fd7af143SMichael Tuexen 			code = ICMP_UNREACH_PROTOCOL;
7012fd7af143SMichael Tuexen 		}
7013fd7af143SMichael Tuexen 		sctp_notify(inp, stcb, net, type, code,
7014fd7af143SMichael Tuexen 		    ntohs(inner_ip->ip_len),
70156ebfa5eeSMichael Tuexen 		    (uint32_t)ntohs(icmp->icmp_nextmtu));
7016fd7af143SMichael Tuexen 	} else {
7017fd7af143SMichael Tuexen 		if ((stcb == NULL) && (inp != NULL)) {
7018fd7af143SMichael Tuexen 			/* reduce ref-count */
7019fd7af143SMichael Tuexen 			SCTP_INP_WLOCK(inp);
7020fd7af143SMichael Tuexen 			SCTP_INP_DECR_REF(inp);
7021fd7af143SMichael Tuexen 			SCTP_INP_WUNLOCK(inp);
7022fd7af143SMichael Tuexen 		}
7023fd7af143SMichael Tuexen 		if (stcb) {
7024fd7af143SMichael Tuexen 			SCTP_TCB_UNLOCK(stcb);
7025fd7af143SMichael Tuexen 		}
7026fd7af143SMichael Tuexen 	}
7027fd7af143SMichael Tuexen 	return;
7028fd7af143SMichael Tuexen }
7029fd7af143SMichael Tuexen #endif
7030fd7af143SMichael Tuexen 
7031fd7af143SMichael Tuexen #ifdef INET6
7032fd7af143SMichael Tuexen static void
7033fd7af143SMichael Tuexen sctp_recv_icmp6_tunneled_packet(int cmd, struct sockaddr *sa, void *d, void *ctx SCTP_UNUSED)
7034fd7af143SMichael Tuexen {
7035fd7af143SMichael Tuexen 	struct ip6ctlparam *ip6cp;
7036fd7af143SMichael Tuexen 	struct sctp_inpcb *inp;
7037fd7af143SMichael Tuexen 	struct sctp_tcb *stcb;
7038fd7af143SMichael Tuexen 	struct sctp_nets *net;
7039fd7af143SMichael Tuexen 	struct sctphdr sh;
7040fd7af143SMichael Tuexen 	struct udphdr udp;
7041fd7af143SMichael Tuexen 	struct sockaddr_in6 src, dst;
7042fd7af143SMichael Tuexen 	uint8_t type, code;
7043fd7af143SMichael Tuexen 
7044fd7af143SMichael Tuexen 	ip6cp = (struct ip6ctlparam *)d;
7045fd7af143SMichael Tuexen 	/*
7046fd7af143SMichael Tuexen 	 * XXX: We assume that when IPV6 is non NULL, M and OFF are valid.
7047fd7af143SMichael Tuexen 	 */
7048fd7af143SMichael Tuexen 	if (ip6cp->ip6c_m == NULL) {
7049fd7af143SMichael Tuexen 		return;
7050fd7af143SMichael Tuexen 	}
7051fd7af143SMichael Tuexen 	/*
7052fd7af143SMichael Tuexen 	 * Check if we can safely examine the ports and the verification tag
7053fd7af143SMichael Tuexen 	 * of the SCTP common header.
7054fd7af143SMichael Tuexen 	 */
7055fd7af143SMichael Tuexen 	if (ip6cp->ip6c_m->m_pkthdr.len <
7056fd7af143SMichael Tuexen 	    ip6cp->ip6c_off + sizeof(struct udphdr) + offsetof(struct sctphdr, checksum)) {
7057fd7af143SMichael Tuexen 		return;
7058fd7af143SMichael Tuexen 	}
7059fd7af143SMichael Tuexen 	/* Copy out the UDP header. */
7060fd7af143SMichael Tuexen 	memset(&udp, 0, sizeof(struct udphdr));
7061fd7af143SMichael Tuexen 	m_copydata(ip6cp->ip6c_m,
7062fd7af143SMichael Tuexen 	    ip6cp->ip6c_off,
7063fd7af143SMichael Tuexen 	    sizeof(struct udphdr),
7064fd7af143SMichael Tuexen 	    (caddr_t)&udp);
7065fd7af143SMichael Tuexen 	/* Copy out the port numbers and the verification tag. */
7066fd7af143SMichael Tuexen 	memset(&sh, 0, sizeof(struct sctphdr));
7067fd7af143SMichael Tuexen 	m_copydata(ip6cp->ip6c_m,
7068fd7af143SMichael Tuexen 	    ip6cp->ip6c_off + sizeof(struct udphdr),
7069fd7af143SMichael Tuexen 	    sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t),
7070fd7af143SMichael Tuexen 	    (caddr_t)&sh);
7071fd7af143SMichael Tuexen 	memset(&src, 0, sizeof(struct sockaddr_in6));
7072fd7af143SMichael Tuexen 	src.sin6_family = AF_INET6;
7073fd7af143SMichael Tuexen 	src.sin6_len = sizeof(struct sockaddr_in6);
7074fd7af143SMichael Tuexen 	src.sin6_port = sh.src_port;
7075fd7af143SMichael Tuexen 	src.sin6_addr = ip6cp->ip6c_ip6->ip6_src;
7076fd7af143SMichael Tuexen 	if (in6_setscope(&src.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) {
7077fd7af143SMichael Tuexen 		return;
7078fd7af143SMichael Tuexen 	}
7079fd7af143SMichael Tuexen 	memset(&dst, 0, sizeof(struct sockaddr_in6));
7080fd7af143SMichael Tuexen 	dst.sin6_family = AF_INET6;
7081fd7af143SMichael Tuexen 	dst.sin6_len = sizeof(struct sockaddr_in6);
7082fd7af143SMichael Tuexen 	dst.sin6_port = sh.dest_port;
7083fd7af143SMichael Tuexen 	dst.sin6_addr = ip6cp->ip6c_ip6->ip6_dst;
7084fd7af143SMichael Tuexen 	if (in6_setscope(&dst.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) {
7085fd7af143SMichael Tuexen 		return;
7086fd7af143SMichael Tuexen 	}
7087fd7af143SMichael Tuexen 	inp = NULL;
7088fd7af143SMichael Tuexen 	net = NULL;
7089fd7af143SMichael Tuexen 	stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst,
7090fd7af143SMichael Tuexen 	    (struct sockaddr *)&src,
7091fd7af143SMichael Tuexen 	    &inp, &net, 1, SCTP_DEFAULT_VRFID);
7092fd7af143SMichael Tuexen 	if ((stcb != NULL) &&
7093fd7af143SMichael Tuexen 	    (net != NULL) &&
709455b8cd93SMichael Tuexen 	    (inp != NULL)) {
7095fd7af143SMichael Tuexen 		/* Check the UDP port numbers */
7096fd7af143SMichael Tuexen 		if ((udp.uh_dport != net->port) ||
7097fd7af143SMichael Tuexen 		    (udp.uh_sport != htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)))) {
7098fd7af143SMichael Tuexen 			SCTP_TCB_UNLOCK(stcb);
7099fd7af143SMichael Tuexen 			return;
7100fd7af143SMichael Tuexen 		}
7101fd7af143SMichael Tuexen 		/* Check the verification tag */
7102fd7af143SMichael Tuexen 		if (ntohl(sh.v_tag) != 0) {
7103fd7af143SMichael Tuexen 			/*
7104fd7af143SMichael Tuexen 			 * This must be the verification tag used for
7105fd7af143SMichael Tuexen 			 * sending out packets. We don't consider packets
7106fd7af143SMichael Tuexen 			 * reflecting the verification tag.
7107fd7af143SMichael Tuexen 			 */
7108fd7af143SMichael Tuexen 			if (ntohl(sh.v_tag) != stcb->asoc.peer_vtag) {
7109fd7af143SMichael Tuexen 				SCTP_TCB_UNLOCK(stcb);
7110fd7af143SMichael Tuexen 				return;
7111fd7af143SMichael Tuexen 			}
7112fd7af143SMichael Tuexen 		} else {
7113fd7af143SMichael Tuexen 			if (ip6cp->ip6c_m->m_pkthdr.len >=
7114fd7af143SMichael Tuexen 			    ip6cp->ip6c_off + sizeof(struct udphdr) +
7115fd7af143SMichael Tuexen 			    sizeof(struct sctphdr) +
7116fd7af143SMichael Tuexen 			    sizeof(struct sctp_chunkhdr) +
7117fd7af143SMichael Tuexen 			    offsetof(struct sctp_init, a_rwnd)) {
7118fd7af143SMichael Tuexen 				/*
7119fd7af143SMichael Tuexen 				 * In this case we can check if we got an
7120fd7af143SMichael Tuexen 				 * INIT chunk and if the initiate tag
7121fd7af143SMichael Tuexen 				 * matches.
7122fd7af143SMichael Tuexen 				 */
7123fd7af143SMichael Tuexen 				uint32_t initiate_tag;
7124fd7af143SMichael Tuexen 				uint8_t chunk_type;
7125fd7af143SMichael Tuexen 
7126fd7af143SMichael Tuexen 				m_copydata(ip6cp->ip6c_m,
7127fd7af143SMichael Tuexen 				    ip6cp->ip6c_off +
7128fd7af143SMichael Tuexen 				    sizeof(struct udphdr) +
7129fd7af143SMichael Tuexen 				    sizeof(struct sctphdr),
7130fd7af143SMichael Tuexen 				    sizeof(uint8_t),
7131fd7af143SMichael Tuexen 				    (caddr_t)&chunk_type);
7132fd7af143SMichael Tuexen 				m_copydata(ip6cp->ip6c_m,
7133fd7af143SMichael Tuexen 				    ip6cp->ip6c_off +
7134fd7af143SMichael Tuexen 				    sizeof(struct udphdr) +
7135fd7af143SMichael Tuexen 				    sizeof(struct sctphdr) +
7136fd7af143SMichael Tuexen 				    sizeof(struct sctp_chunkhdr),
7137fd7af143SMichael Tuexen 				    sizeof(uint32_t),
7138fd7af143SMichael Tuexen 				    (caddr_t)&initiate_tag);
7139fd7af143SMichael Tuexen 				if ((chunk_type != SCTP_INITIATION) ||
7140fd7af143SMichael Tuexen 				    (ntohl(initiate_tag) != stcb->asoc.my_vtag)) {
7141fd7af143SMichael Tuexen 					SCTP_TCB_UNLOCK(stcb);
7142fd7af143SMichael Tuexen 					return;
7143fd7af143SMichael Tuexen 				}
7144fd7af143SMichael Tuexen 			} else {
7145fd7af143SMichael Tuexen 				SCTP_TCB_UNLOCK(stcb);
7146fd7af143SMichael Tuexen 				return;
7147fd7af143SMichael Tuexen 			}
7148fd7af143SMichael Tuexen 		}
7149fd7af143SMichael Tuexen 		type = ip6cp->ip6c_icmp6->icmp6_type;
7150fd7af143SMichael Tuexen 		code = ip6cp->ip6c_icmp6->icmp6_code;
7151fd7af143SMichael Tuexen 		if ((type == ICMP6_DST_UNREACH) &&
7152fd7af143SMichael Tuexen 		    (code == ICMP6_DST_UNREACH_NOPORT)) {
7153fd7af143SMichael Tuexen 			type = ICMP6_PARAM_PROB;
7154fd7af143SMichael Tuexen 			code = ICMP6_PARAMPROB_NEXTHEADER;
7155fd7af143SMichael Tuexen 		}
7156fd7af143SMichael Tuexen 		sctp6_notify(inp, stcb, net, type, code,
71576ebfa5eeSMichael Tuexen 		    ntohl(ip6cp->ip6c_icmp6->icmp6_mtu));
7158fd7af143SMichael Tuexen 	} else {
7159fd7af143SMichael Tuexen 		if ((stcb == NULL) && (inp != NULL)) {
7160fd7af143SMichael Tuexen 			/* reduce inp's ref-count */
7161fd7af143SMichael Tuexen 			SCTP_INP_WLOCK(inp);
7162fd7af143SMichael Tuexen 			SCTP_INP_DECR_REF(inp);
7163fd7af143SMichael Tuexen 			SCTP_INP_WUNLOCK(inp);
7164fd7af143SMichael Tuexen 		}
7165fd7af143SMichael Tuexen 		if (stcb) {
7166fd7af143SMichael Tuexen 			SCTP_TCB_UNLOCK(stcb);
7167fd7af143SMichael Tuexen 		}
7168fd7af143SMichael Tuexen 	}
7169fd7af143SMichael Tuexen }
7170fd7af143SMichael Tuexen #endif
7171fd7af143SMichael Tuexen 
7172c54a18d2SRandall Stewart void
7173c54a18d2SRandall Stewart sctp_over_udp_stop(void)
7174c54a18d2SRandall Stewart {
7175a99b6783SRandall Stewart 	/*
7176a99b6783SRandall Stewart 	 * This function assumes sysctl caller holds sctp_sysctl_info_lock()
7177a99b6783SRandall Stewart 	 * for writting!
7178a99b6783SRandall Stewart 	 */
71793a51a264SMichael Tuexen #ifdef INET
71803a51a264SMichael Tuexen 	if (SCTP_BASE_INFO(udp4_tun_socket) != NULL) {
71813a51a264SMichael Tuexen 		soclose(SCTP_BASE_INFO(udp4_tun_socket));
71823a51a264SMichael Tuexen 		SCTP_BASE_INFO(udp4_tun_socket) = NULL;
7183c54a18d2SRandall Stewart 	}
71843a51a264SMichael Tuexen #endif
71853a51a264SMichael Tuexen #ifdef INET6
71863a51a264SMichael Tuexen 	if (SCTP_BASE_INFO(udp6_tun_socket) != NULL) {
71873a51a264SMichael Tuexen 		soclose(SCTP_BASE_INFO(udp6_tun_socket));
71883a51a264SMichael Tuexen 		SCTP_BASE_INFO(udp6_tun_socket) = NULL;
71893a51a264SMichael Tuexen 	}
71903a51a264SMichael Tuexen #endif
7191a99b6783SRandall Stewart }
7192ea5eba11SMichael Tuexen 
7193c54a18d2SRandall Stewart int
7194c54a18d2SRandall Stewart sctp_over_udp_start(void)
7195c54a18d2SRandall Stewart {
7196a99b6783SRandall Stewart 	uint16_t port;
7197a99b6783SRandall Stewart 	int ret;
71983a51a264SMichael Tuexen #ifdef INET
71993a51a264SMichael Tuexen 	struct sockaddr_in sin;
72003a51a264SMichael Tuexen #endif
72013a51a264SMichael Tuexen #ifdef INET6
72023a51a264SMichael Tuexen 	struct sockaddr_in6 sin6;
72033a51a264SMichael Tuexen #endif
7204a99b6783SRandall Stewart 	/*
7205a99b6783SRandall Stewart 	 * This function assumes sysctl caller holds sctp_sysctl_info_lock()
7206a99b6783SRandall Stewart 	 * for writting!
7207a99b6783SRandall Stewart 	 */
7208a99b6783SRandall Stewart 	port = SCTP_BASE_SYSCTL(sctp_udp_tunneling_port);
72093a51a264SMichael Tuexen 	if (ntohs(port) == 0) {
7210a99b6783SRandall Stewart 		/* Must have a port set */
7211a99b6783SRandall Stewart 		return (EINVAL);
7212a99b6783SRandall Stewart 	}
72133a51a264SMichael Tuexen #ifdef INET
72143a51a264SMichael Tuexen 	if (SCTP_BASE_INFO(udp4_tun_socket) != NULL) {
7215a99b6783SRandall Stewart 		/* Already running -- must stop first */
7216a99b6783SRandall Stewart 		return (EALREADY);
7217a99b6783SRandall Stewart 	}
72183a51a264SMichael Tuexen #endif
72193a51a264SMichael Tuexen #ifdef INET6
72203a51a264SMichael Tuexen 	if (SCTP_BASE_INFO(udp6_tun_socket) != NULL) {
72213a51a264SMichael Tuexen 		/* Already running -- must stop first */
72223a51a264SMichael Tuexen 		return (EALREADY);
7223a99b6783SRandall Stewart 	}
72243a51a264SMichael Tuexen #endif
72253a51a264SMichael Tuexen #ifdef INET
72263a51a264SMichael Tuexen 	if ((ret = socreate(PF_INET, &SCTP_BASE_INFO(udp4_tun_socket),
72273a51a264SMichael Tuexen 	    SOCK_DGRAM, IPPROTO_UDP,
72283a51a264SMichael Tuexen 	    curthread->td_ucred, curthread))) {
7229a99b6783SRandall Stewart 		sctp_over_udp_stop();
7230a99b6783SRandall Stewart 		return (ret);
7231a99b6783SRandall Stewart 	}
72323a51a264SMichael Tuexen 	/* Call the special UDP hook. */
72333a51a264SMichael Tuexen 	if ((ret = udp_set_kernel_tunneling(SCTP_BASE_INFO(udp4_tun_socket),
7234fd7af143SMichael Tuexen 	    sctp_recv_udp_tunneled_packet,
7235fd7af143SMichael Tuexen 	    sctp_recv_icmp_tunneled_packet,
7236fd7af143SMichael Tuexen 	    NULL))) {
72373a51a264SMichael Tuexen 		sctp_over_udp_stop();
72383a51a264SMichael Tuexen 		return (ret);
72393a51a264SMichael Tuexen 	}
72403a51a264SMichael Tuexen 	/* Ok, we have a socket, bind it to the port. */
72413a51a264SMichael Tuexen 	memset(&sin, 0, sizeof(struct sockaddr_in));
72423a51a264SMichael Tuexen 	sin.sin_len = sizeof(struct sockaddr_in);
72433a51a264SMichael Tuexen 	sin.sin_family = AF_INET;
72443a51a264SMichael Tuexen 	sin.sin_port = htons(port);
72453a51a264SMichael Tuexen 	if ((ret = sobind(SCTP_BASE_INFO(udp4_tun_socket),
72463a51a264SMichael Tuexen 	    (struct sockaddr *)&sin, curthread))) {
72473a51a264SMichael Tuexen 		sctp_over_udp_stop();
72483a51a264SMichael Tuexen 		return (ret);
72493a51a264SMichael Tuexen 	}
72503a51a264SMichael Tuexen #endif
72513a51a264SMichael Tuexen #ifdef INET6
72523a51a264SMichael Tuexen 	if ((ret = socreate(PF_INET6, &SCTP_BASE_INFO(udp6_tun_socket),
72533a51a264SMichael Tuexen 	    SOCK_DGRAM, IPPROTO_UDP,
72543a51a264SMichael Tuexen 	    curthread->td_ucred, curthread))) {
72553a51a264SMichael Tuexen 		sctp_over_udp_stop();
72563a51a264SMichael Tuexen 		return (ret);
72573a51a264SMichael Tuexen 	}
72583a51a264SMichael Tuexen 	/* Call the special UDP hook. */
72593a51a264SMichael Tuexen 	if ((ret = udp_set_kernel_tunneling(SCTP_BASE_INFO(udp6_tun_socket),
7260fd7af143SMichael Tuexen 	    sctp_recv_udp_tunneled_packet,
7261fd7af143SMichael Tuexen 	    sctp_recv_icmp6_tunneled_packet,
7262fd7af143SMichael Tuexen 	    NULL))) {
72633a51a264SMichael Tuexen 		sctp_over_udp_stop();
72643a51a264SMichael Tuexen 		return (ret);
72653a51a264SMichael Tuexen 	}
72663a51a264SMichael Tuexen 	/* Ok, we have a socket, bind it to the port. */
72673a51a264SMichael Tuexen 	memset(&sin6, 0, sizeof(struct sockaddr_in6));
72683a51a264SMichael Tuexen 	sin6.sin6_len = sizeof(struct sockaddr_in6);
72693a51a264SMichael Tuexen 	sin6.sin6_family = AF_INET6;
72703a51a264SMichael Tuexen 	sin6.sin6_port = htons(port);
72713a51a264SMichael Tuexen 	if ((ret = sobind(SCTP_BASE_INFO(udp6_tun_socket),
72723a51a264SMichael Tuexen 	    (struct sockaddr *)&sin6, curthread))) {
72733a51a264SMichael Tuexen 		sctp_over_udp_stop();
72743a51a264SMichael Tuexen 		return (ret);
72753a51a264SMichael Tuexen 	}
72763a51a264SMichael Tuexen #endif
7277a99b6783SRandall Stewart 	return (0);
7278c54a18d2SRandall Stewart }
727910e0318aSMichael Tuexen 
728010e0318aSMichael Tuexen /*
728110e0318aSMichael Tuexen  * sctp_min_mtu ()returns the minimum of all non-zero arguments.
728210e0318aSMichael Tuexen  * If all arguments are zero, zero is returned.
728310e0318aSMichael Tuexen  */
728410e0318aSMichael Tuexen uint32_t
7285*b0471b4bSMichael Tuexen sctp_min_mtu(uint32_t mtu1, uint32_t mtu2, uint32_t mtu3)
7286*b0471b4bSMichael Tuexen {
728710e0318aSMichael Tuexen 	if (mtu1 > 0) {
728810e0318aSMichael Tuexen 		if (mtu2 > 0) {
728910e0318aSMichael Tuexen 			if (mtu3 > 0) {
729010e0318aSMichael Tuexen 				return (min(mtu1, min(mtu2, mtu3)));
729110e0318aSMichael Tuexen 			} else {
729210e0318aSMichael Tuexen 				return (min(mtu1, mtu2));
729310e0318aSMichael Tuexen 			}
729410e0318aSMichael Tuexen 		} else {
729510e0318aSMichael Tuexen 			if (mtu3 > 0) {
729610e0318aSMichael Tuexen 				return (min(mtu1, mtu3));
729710e0318aSMichael Tuexen 			} else {
729810e0318aSMichael Tuexen 				return (mtu1);
729910e0318aSMichael Tuexen 			}
730010e0318aSMichael Tuexen 		}
730110e0318aSMichael Tuexen 	} else {
730210e0318aSMichael Tuexen 		if (mtu2 > 0) {
730310e0318aSMichael Tuexen 			if (mtu3 > 0) {
730410e0318aSMichael Tuexen 				return (min(mtu2, mtu3));
730510e0318aSMichael Tuexen 			} else {
730610e0318aSMichael Tuexen 				return (mtu2);
730710e0318aSMichael Tuexen 			}
730810e0318aSMichael Tuexen 		} else {
730910e0318aSMichael Tuexen 			return (mtu3);
731010e0318aSMichael Tuexen 		}
731110e0318aSMichael Tuexen 	}
731210e0318aSMichael Tuexen }
731310e0318aSMichael Tuexen 
731410e0318aSMichael Tuexen void
731510e0318aSMichael Tuexen sctp_hc_set_mtu(union sctp_sockstore *addr, uint16_t fibnum, uint32_t mtu)
731610e0318aSMichael Tuexen {
731710e0318aSMichael Tuexen 	struct in_conninfo inc;
731810e0318aSMichael Tuexen 
731910e0318aSMichael Tuexen 	memset(&inc, 0, sizeof(struct in_conninfo));
732010e0318aSMichael Tuexen 	inc.inc_fibnum = fibnum;
732110e0318aSMichael Tuexen 	switch (addr->sa.sa_family) {
732210e0318aSMichael Tuexen #ifdef INET
732310e0318aSMichael Tuexen 	case AF_INET:
732410e0318aSMichael Tuexen 		inc.inc_faddr = addr->sin.sin_addr;
732510e0318aSMichael Tuexen 		break;
732610e0318aSMichael Tuexen #endif
732710e0318aSMichael Tuexen #ifdef INET6
732810e0318aSMichael Tuexen 	case AF_INET6:
732910e0318aSMichael Tuexen 		inc.inc_flags |= INC_ISIPV6;
733010e0318aSMichael Tuexen 		inc.inc6_faddr = addr->sin6.sin6_addr;
733110e0318aSMichael Tuexen 		break;
733210e0318aSMichael Tuexen #endif
733310e0318aSMichael Tuexen 	default:
733410e0318aSMichael Tuexen 		return;
733510e0318aSMichael Tuexen 	}
733610e0318aSMichael Tuexen 	tcp_hc_updatemtu(&inc, (u_long)mtu);
733710e0318aSMichael Tuexen }
733810e0318aSMichael Tuexen 
733910e0318aSMichael Tuexen uint32_t
7340*b0471b4bSMichael Tuexen sctp_hc_get_mtu(union sctp_sockstore *addr, uint16_t fibnum)
7341*b0471b4bSMichael Tuexen {
734210e0318aSMichael Tuexen 	struct in_conninfo inc;
734310e0318aSMichael Tuexen 
734410e0318aSMichael Tuexen 	memset(&inc, 0, sizeof(struct in_conninfo));
734510e0318aSMichael Tuexen 	inc.inc_fibnum = fibnum;
734610e0318aSMichael Tuexen 	switch (addr->sa.sa_family) {
734710e0318aSMichael Tuexen #ifdef INET
734810e0318aSMichael Tuexen 	case AF_INET:
734910e0318aSMichael Tuexen 		inc.inc_faddr = addr->sin.sin_addr;
735010e0318aSMichael Tuexen 		break;
735110e0318aSMichael Tuexen #endif
735210e0318aSMichael Tuexen #ifdef INET6
735310e0318aSMichael Tuexen 	case AF_INET6:
735410e0318aSMichael Tuexen 		inc.inc_flags |= INC_ISIPV6;
735510e0318aSMichael Tuexen 		inc.inc6_faddr = addr->sin6.sin6_addr;
735610e0318aSMichael Tuexen 		break;
735710e0318aSMichael Tuexen #endif
735810e0318aSMichael Tuexen 	default:
735910e0318aSMichael Tuexen 		return (0);
736010e0318aSMichael Tuexen 	}
736110e0318aSMichael Tuexen 	return ((uint32_t)tcp_hc_getmtu(&inc));
736210e0318aSMichael Tuexen }
7363