xref: /freebsd/sys/netinet/sctputil.c (revision a412576e36a98396ad91cffee1bcdb51cac50c73)
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>
54776cd558SMichael Tuexen #include <netinet/sctp_kdtrace.h>
5510e0318aSMichael Tuexen #if defined(INET6) || defined(INET)
5610e0318aSMichael Tuexen #include <netinet/tcp_var.h>
5710e0318aSMichael Tuexen #endif
583a51a264SMichael Tuexen #include <netinet/udp.h>
593a51a264SMichael Tuexen #include <netinet/udp_var.h>
603a51a264SMichael Tuexen #include <sys/proc.h>
61fd7af143SMichael Tuexen #ifdef INET6
62fd7af143SMichael Tuexen #include <netinet/icmp6.h>
63fd7af143SMichael Tuexen #endif
64f8829a4aSRandall Stewart 
65f8829a4aSRandall Stewart 
66b9e7085aSRandall Stewart #ifndef KTR_SCTP
67b9e7085aSRandall Stewart #define KTR_SCTP KTR_SUBSYS
6880fefe0aSRandall Stewart #endif
69f8829a4aSRandall Stewart 
70ed654363SMichael Tuexen extern const struct sctp_cc_functions sctp_cc_functions[];
71ed654363SMichael Tuexen extern const struct sctp_ss_functions sctp_ss_functions[];
720e9a9c10SMichael Tuexen 
73f8829a4aSRandall Stewart void
74dcb68fbaSMichael Tuexen sctp_sblog(struct sockbuf *sb, struct sctp_tcb *stcb, int from, int incr)
75f8829a4aSRandall Stewart {
76c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
77c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
78f8829a4aSRandall Stewart 
7980fefe0aSRandall Stewart 	sctp_clog.x.sb.stcb = stcb;
804e88d37aSMichael Tuexen 	sctp_clog.x.sb.so_sbcc = sb->sb_cc;
81f8829a4aSRandall Stewart 	if (stcb)
824e88d37aSMichael Tuexen 		sctp_clog.x.sb.stcb_sbcc = stcb->asoc.sb_cc;
83f8829a4aSRandall Stewart 	else
8480fefe0aSRandall Stewart 		sctp_clog.x.sb.stcb_sbcc = 0;
8580fefe0aSRandall Stewart 	sctp_clog.x.sb.incr = incr;
86c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
8780fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_SB,
8880fefe0aSRandall Stewart 	    from,
8980fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
9080fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
9180fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
9280fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
93c692df45SMichael Tuexen #endif
94f8829a4aSRandall Stewart }
95f8829a4aSRandall Stewart 
96f8829a4aSRandall Stewart void
97f8829a4aSRandall Stewart sctp_log_closing(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int16_t loc)
98f8829a4aSRandall Stewart {
99c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
100c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
101f8829a4aSRandall Stewart 
10280fefe0aSRandall Stewart 	sctp_clog.x.close.inp = (void *)inp;
10380fefe0aSRandall Stewart 	sctp_clog.x.close.sctp_flags = inp->sctp_flags;
104f8829a4aSRandall Stewart 	if (stcb) {
10580fefe0aSRandall Stewart 		sctp_clog.x.close.stcb = (void *)stcb;
10680fefe0aSRandall Stewart 		sctp_clog.x.close.state = (uint16_t)stcb->asoc.state;
107f8829a4aSRandall Stewart 	} else {
10880fefe0aSRandall Stewart 		sctp_clog.x.close.stcb = 0;
10980fefe0aSRandall Stewart 		sctp_clog.x.close.state = 0;
110f8829a4aSRandall Stewart 	}
11180fefe0aSRandall Stewart 	sctp_clog.x.close.loc = loc;
112c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
11380fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_CLOSE,
11480fefe0aSRandall Stewart 	    0,
11580fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
11680fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
11780fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
11880fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
119c692df45SMichael Tuexen #endif
120f8829a4aSRandall Stewart }
121f8829a4aSRandall Stewart 
122f8829a4aSRandall Stewart void
123f8829a4aSRandall Stewart rto_logging(struct sctp_nets *net, int from)
124f8829a4aSRandall Stewart {
125c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
126c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
127f8829a4aSRandall Stewart 
128bfefd190SRandall Stewart 	memset(&sctp_clog, 0, sizeof(sctp_clog));
12980fefe0aSRandall Stewart 	sctp_clog.x.rto.net = (void *)net;
130be1d9176SMichael Tuexen 	sctp_clog.x.rto.rtt = net->rtt / 1000;
131c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
13280fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_RTT,
13380fefe0aSRandall Stewart 	    from,
13480fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
13580fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
13680fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
13780fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
138c692df45SMichael Tuexen #endif
139f8829a4aSRandall Stewart }
140f8829a4aSRandall Stewart 
141f8829a4aSRandall Stewart void
1426a91f103SRandall Stewart sctp_log_strm_del_alt(struct sctp_tcb *stcb, uint32_t tsn, uint16_t sseq, uint16_t stream, int from)
143f8829a4aSRandall Stewart {
144c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
145c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
146f8829a4aSRandall Stewart 
14780fefe0aSRandall Stewart 	sctp_clog.x.strlog.stcb = stcb;
14880fefe0aSRandall Stewart 	sctp_clog.x.strlog.n_tsn = tsn;
14980fefe0aSRandall Stewart 	sctp_clog.x.strlog.n_sseq = sseq;
15080fefe0aSRandall Stewart 	sctp_clog.x.strlog.e_tsn = 0;
15180fefe0aSRandall Stewart 	sctp_clog.x.strlog.e_sseq = 0;
15280fefe0aSRandall Stewart 	sctp_clog.x.strlog.strm = stream;
153c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
15480fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_STRM,
15580fefe0aSRandall Stewart 	    from,
15680fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
15780fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
15880fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
15980fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
160c692df45SMichael Tuexen #endif
161f8829a4aSRandall Stewart }
162f8829a4aSRandall Stewart 
163f8829a4aSRandall Stewart void
164f8829a4aSRandall Stewart sctp_log_nagle_event(struct sctp_tcb *stcb, int action)
165f8829a4aSRandall Stewart {
166c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
167c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
168f8829a4aSRandall Stewart 
16980fefe0aSRandall Stewart 	sctp_clog.x.nagle.stcb = (void *)stcb;
17080fefe0aSRandall Stewart 	sctp_clog.x.nagle.total_flight = stcb->asoc.total_flight;
17180fefe0aSRandall Stewart 	sctp_clog.x.nagle.total_in_queue = stcb->asoc.total_output_queue_size;
17280fefe0aSRandall Stewart 	sctp_clog.x.nagle.count_in_queue = stcb->asoc.chunks_on_out_queue;
17380fefe0aSRandall Stewart 	sctp_clog.x.nagle.count_in_flight = stcb->asoc.total_flight_count;
174c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
17580fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_NAGLE,
17680fefe0aSRandall Stewart 	    action,
17780fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
17880fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
17980fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
18080fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
181c692df45SMichael Tuexen #endif
182f8829a4aSRandall Stewart }
183f8829a4aSRandall Stewart 
184f8829a4aSRandall Stewart void
185f8829a4aSRandall Stewart sctp_log_sack(uint32_t old_cumack, uint32_t cumack, uint32_t tsn, uint16_t gaps, uint16_t dups, int from)
186f8829a4aSRandall Stewart {
187c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
188c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
189f8829a4aSRandall Stewart 
19080fefe0aSRandall Stewart 	sctp_clog.x.sack.cumack = cumack;
19180fefe0aSRandall Stewart 	sctp_clog.x.sack.oldcumack = old_cumack;
19280fefe0aSRandall Stewart 	sctp_clog.x.sack.tsn = tsn;
19380fefe0aSRandall Stewart 	sctp_clog.x.sack.numGaps = gaps;
19480fefe0aSRandall Stewart 	sctp_clog.x.sack.numDups = dups;
195c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
19680fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_SACK,
19780fefe0aSRandall Stewart 	    from,
19880fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
19980fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
20080fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
20180fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
202c692df45SMichael Tuexen #endif
203f8829a4aSRandall Stewart }
204f8829a4aSRandall Stewart 
205f8829a4aSRandall Stewart void
206f8829a4aSRandall Stewart sctp_log_map(uint32_t map, uint32_t cum, uint32_t high, int from)
207f8829a4aSRandall Stewart {
208c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
209c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
210f8829a4aSRandall Stewart 
211bfefd190SRandall Stewart 	memset(&sctp_clog, 0, sizeof(sctp_clog));
21280fefe0aSRandall Stewart 	sctp_clog.x.map.base = map;
21380fefe0aSRandall Stewart 	sctp_clog.x.map.cum = cum;
21480fefe0aSRandall Stewart 	sctp_clog.x.map.high = high;
215c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
21680fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_MAP,
21780fefe0aSRandall Stewart 	    from,
21880fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
21980fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
22080fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
22180fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
222c692df45SMichael Tuexen #endif
223f8829a4aSRandall Stewart }
224f8829a4aSRandall Stewart 
225f8829a4aSRandall Stewart void
226dcb68fbaSMichael Tuexen sctp_log_fr(uint32_t biggest_tsn, uint32_t biggest_new_tsn, uint32_t tsn, int from)
227f8829a4aSRandall Stewart {
228c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
229c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
230f8829a4aSRandall Stewart 
231bfefd190SRandall Stewart 	memset(&sctp_clog, 0, sizeof(sctp_clog));
23280fefe0aSRandall Stewart 	sctp_clog.x.fr.largest_tsn = biggest_tsn;
23380fefe0aSRandall Stewart 	sctp_clog.x.fr.largest_new_tsn = biggest_new_tsn;
23480fefe0aSRandall Stewart 	sctp_clog.x.fr.tsn = tsn;
235c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
23680fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_FR,
23780fefe0aSRandall Stewart 	    from,
23880fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
23980fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
24080fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
24180fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
242c692df45SMichael Tuexen #endif
243f8829a4aSRandall Stewart }
244f8829a4aSRandall Stewart 
2454be807c4SMichael Tuexen #ifdef SCTP_MBUF_LOGGING
246f8829a4aSRandall Stewart void
247f8829a4aSRandall Stewart sctp_log_mb(struct mbuf *m, int from)
248f8829a4aSRandall Stewart {
249c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
250c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
251f8829a4aSRandall Stewart 
25280fefe0aSRandall Stewart 	sctp_clog.x.mb.mp = m;
25380fefe0aSRandall Stewart 	sctp_clog.x.mb.mbuf_flags = (uint8_t)(SCTP_BUF_GET_FLAGS(m));
25480fefe0aSRandall Stewart 	sctp_clog.x.mb.size = (uint16_t)(SCTP_BUF_LEN(m));
25580fefe0aSRandall Stewart 	sctp_clog.x.mb.data = SCTP_BUF_AT(m, 0);
256139bc87fSRandall Stewart 	if (SCTP_BUF_IS_EXTENDED(m)) {
25780fefe0aSRandall Stewart 		sctp_clog.x.mb.ext = SCTP_BUF_EXTEND_BASE(m);
25880fefe0aSRandall Stewart 		sctp_clog.x.mb.refcnt = (uint8_t)(SCTP_BUF_EXTEND_REFCNT(m));
259f8829a4aSRandall Stewart 	} else {
26080fefe0aSRandall Stewart 		sctp_clog.x.mb.ext = 0;
26180fefe0aSRandall Stewart 		sctp_clog.x.mb.refcnt = 0;
262f8829a4aSRandall Stewart 	}
263c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
26480fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_MBUF,
26580fefe0aSRandall Stewart 	    from,
26680fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
26780fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
26880fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
26980fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
270c692df45SMichael Tuexen #endif
271f8829a4aSRandall Stewart }
272f8829a4aSRandall Stewart 
273f8829a4aSRandall Stewart void
2744be807c4SMichael Tuexen sctp_log_mbc(struct mbuf *m, int from)
2754be807c4SMichael Tuexen {
2764be807c4SMichael Tuexen 	struct mbuf *mat;
2774be807c4SMichael Tuexen 
2784be807c4SMichael Tuexen 	for (mat = m; mat; mat = SCTP_BUF_NEXT(mat)) {
2794be807c4SMichael Tuexen 		sctp_log_mb(mat, from);
2804be807c4SMichael Tuexen 	}
2814be807c4SMichael Tuexen }
2824be807c4SMichael Tuexen #endif
2834be807c4SMichael Tuexen 
2844be807c4SMichael Tuexen void
285dcb68fbaSMichael Tuexen sctp_log_strm_del(struct sctp_queued_to_read *control, struct sctp_queued_to_read *poschk, int from)
286f8829a4aSRandall Stewart {
287c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
288c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
289f8829a4aSRandall Stewart 
290f8829a4aSRandall Stewart 	if (control == NULL) {
291ad81507eSRandall Stewart 		SCTP_PRINTF("Gak log of NULL?\n");
292f8829a4aSRandall Stewart 		return;
293f8829a4aSRandall Stewart 	}
29480fefe0aSRandall Stewart 	sctp_clog.x.strlog.stcb = control->stcb;
29580fefe0aSRandall Stewart 	sctp_clog.x.strlog.n_tsn = control->sinfo_tsn;
29649656eefSMichael Tuexen 	sctp_clog.x.strlog.n_sseq = (uint16_t)control->mid;
29780fefe0aSRandall Stewart 	sctp_clog.x.strlog.strm = control->sinfo_stream;
298f8829a4aSRandall Stewart 	if (poschk != NULL) {
29980fefe0aSRandall Stewart 		sctp_clog.x.strlog.e_tsn = poschk->sinfo_tsn;
30049656eefSMichael Tuexen 		sctp_clog.x.strlog.e_sseq = (uint16_t)poschk->mid;
301f8829a4aSRandall Stewart 	} else {
30280fefe0aSRandall Stewart 		sctp_clog.x.strlog.e_tsn = 0;
30380fefe0aSRandall Stewart 		sctp_clog.x.strlog.e_sseq = 0;
304f8829a4aSRandall Stewart 	}
305c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
30680fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_STRM,
30780fefe0aSRandall Stewart 	    from,
30880fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
30980fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
31080fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
31180fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
312c692df45SMichael Tuexen #endif
313f8829a4aSRandall Stewart }
314f8829a4aSRandall Stewart 
315f8829a4aSRandall Stewart void
316f8829a4aSRandall Stewart sctp_log_cwnd(struct sctp_tcb *stcb, struct sctp_nets *net, int augment, uint8_t from)
317f8829a4aSRandall Stewart {
318c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
319c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
320f8829a4aSRandall Stewart 
32180fefe0aSRandall Stewart 	sctp_clog.x.cwnd.net = net;
322f8829a4aSRandall Stewart 	if (stcb->asoc.send_queue_cnt > 255)
32380fefe0aSRandall Stewart 		sctp_clog.x.cwnd.cnt_in_send = 255;
324f8829a4aSRandall Stewart 	else
32580fefe0aSRandall Stewart 		sctp_clog.x.cwnd.cnt_in_send = stcb->asoc.send_queue_cnt;
326f8829a4aSRandall Stewart 	if (stcb->asoc.stream_queue_cnt > 255)
32780fefe0aSRandall Stewart 		sctp_clog.x.cwnd.cnt_in_str = 255;
328f8829a4aSRandall Stewart 	else
32980fefe0aSRandall Stewart 		sctp_clog.x.cwnd.cnt_in_str = stcb->asoc.stream_queue_cnt;
330f8829a4aSRandall Stewart 
331f8829a4aSRandall Stewart 	if (net) {
33280fefe0aSRandall Stewart 		sctp_clog.x.cwnd.cwnd_new_value = net->cwnd;
33380fefe0aSRandall Stewart 		sctp_clog.x.cwnd.inflight = net->flight_size;
33480fefe0aSRandall Stewart 		sctp_clog.x.cwnd.pseudo_cumack = net->pseudo_cumack;
33580fefe0aSRandall Stewart 		sctp_clog.x.cwnd.meets_pseudo_cumack = net->new_pseudo_cumack;
33680fefe0aSRandall Stewart 		sctp_clog.x.cwnd.need_new_pseudo_cumack = net->find_pseudo_cumack;
337f8829a4aSRandall Stewart 	}
338f8829a4aSRandall Stewart 	if (SCTP_CWNDLOG_PRESEND == from) {
33980fefe0aSRandall Stewart 		sctp_clog.x.cwnd.meets_pseudo_cumack = stcb->asoc.peers_rwnd;
340f8829a4aSRandall Stewart 	}
34180fefe0aSRandall Stewart 	sctp_clog.x.cwnd.cwnd_augment = augment;
342c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
34380fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_CWND,
34480fefe0aSRandall Stewart 	    from,
34580fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
34680fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
34780fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
34880fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
349c692df45SMichael Tuexen #endif
350f8829a4aSRandall Stewart }
351f8829a4aSRandall Stewart 
352f8829a4aSRandall Stewart void
353f8829a4aSRandall Stewart sctp_log_lock(struct sctp_inpcb *inp, struct sctp_tcb *stcb, uint8_t from)
354f8829a4aSRandall Stewart {
355c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
356c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
357f8829a4aSRandall Stewart 
358bfefd190SRandall Stewart 	memset(&sctp_clog, 0, sizeof(sctp_clog));
35903b0b021SRandall Stewart 	if (inp) {
36080fefe0aSRandall Stewart 		sctp_clog.x.lock.sock = (void *)inp->sctp_socket;
36103b0b021SRandall Stewart 
36203b0b021SRandall Stewart 	} else {
36380fefe0aSRandall Stewart 		sctp_clog.x.lock.sock = (void *)NULL;
36403b0b021SRandall Stewart 	}
36580fefe0aSRandall Stewart 	sctp_clog.x.lock.inp = (void *)inp;
366f8829a4aSRandall Stewart 	if (stcb) {
36780fefe0aSRandall Stewart 		sctp_clog.x.lock.tcb_lock = mtx_owned(&stcb->tcb_mtx);
368f8829a4aSRandall Stewart 	} else {
36980fefe0aSRandall Stewart 		sctp_clog.x.lock.tcb_lock = SCTP_LOCK_UNKNOWN;
370f8829a4aSRandall Stewart 	}
371f8829a4aSRandall Stewart 	if (inp) {
37280fefe0aSRandall Stewart 		sctp_clog.x.lock.inp_lock = mtx_owned(&inp->inp_mtx);
37380fefe0aSRandall Stewart 		sctp_clog.x.lock.create_lock = mtx_owned(&inp->inp_create_mtx);
374f8829a4aSRandall Stewart 	} else {
37580fefe0aSRandall Stewart 		sctp_clog.x.lock.inp_lock = SCTP_LOCK_UNKNOWN;
37680fefe0aSRandall Stewart 		sctp_clog.x.lock.create_lock = SCTP_LOCK_UNKNOWN;
377f8829a4aSRandall Stewart 	}
378b3f1ea41SRandall Stewart 	sctp_clog.x.lock.info_lock = rw_wowned(&SCTP_BASE_INFO(ipi_ep_mtx));
37952129fcdSRandall Stewart 	if (inp && (inp->sctp_socket)) {
38080fefe0aSRandall Stewart 		sctp_clog.x.lock.sock_lock = mtx_owned(&(inp->sctp_socket->so_rcv.sb_mtx));
38180fefe0aSRandall Stewart 		sctp_clog.x.lock.sockrcvbuf_lock = mtx_owned(&(inp->sctp_socket->so_rcv.sb_mtx));
38280fefe0aSRandall Stewart 		sctp_clog.x.lock.socksndbuf_lock = mtx_owned(&(inp->sctp_socket->so_snd.sb_mtx));
383f8829a4aSRandall Stewart 	} else {
38480fefe0aSRandall Stewart 		sctp_clog.x.lock.sock_lock = SCTP_LOCK_UNKNOWN;
38580fefe0aSRandall Stewart 		sctp_clog.x.lock.sockrcvbuf_lock = SCTP_LOCK_UNKNOWN;
38680fefe0aSRandall Stewart 		sctp_clog.x.lock.socksndbuf_lock = SCTP_LOCK_UNKNOWN;
387f8829a4aSRandall Stewart 	}
388c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
38980fefe0aSRandall Stewart 	    SCTP_LOG_LOCK_EVENT,
39080fefe0aSRandall Stewart 	    from,
39180fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
39280fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
39380fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
39480fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
395c692df45SMichael Tuexen #endif
396f8829a4aSRandall Stewart }
397f8829a4aSRandall Stewart 
398f8829a4aSRandall Stewart void
399f8829a4aSRandall Stewart sctp_log_maxburst(struct sctp_tcb *stcb, struct sctp_nets *net, int error, int burst, uint8_t from)
400f8829a4aSRandall Stewart {
401c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
402c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
403f8829a4aSRandall Stewart 
404bfefd190SRandall Stewart 	memset(&sctp_clog, 0, sizeof(sctp_clog));
40580fefe0aSRandall Stewart 	sctp_clog.x.cwnd.net = net;
40680fefe0aSRandall Stewart 	sctp_clog.x.cwnd.cwnd_new_value = error;
40780fefe0aSRandall Stewart 	sctp_clog.x.cwnd.inflight = net->flight_size;
40880fefe0aSRandall Stewart 	sctp_clog.x.cwnd.cwnd_augment = burst;
409f8829a4aSRandall Stewart 	if (stcb->asoc.send_queue_cnt > 255)
41080fefe0aSRandall Stewart 		sctp_clog.x.cwnd.cnt_in_send = 255;
411f8829a4aSRandall Stewart 	else
41280fefe0aSRandall Stewart 		sctp_clog.x.cwnd.cnt_in_send = stcb->asoc.send_queue_cnt;
413f8829a4aSRandall Stewart 	if (stcb->asoc.stream_queue_cnt > 255)
41480fefe0aSRandall Stewart 		sctp_clog.x.cwnd.cnt_in_str = 255;
415f8829a4aSRandall Stewart 	else
41680fefe0aSRandall Stewart 		sctp_clog.x.cwnd.cnt_in_str = stcb->asoc.stream_queue_cnt;
417c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
41880fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_MAXBURST,
41980fefe0aSRandall Stewart 	    from,
42080fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
42180fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
42280fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
42380fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
424c692df45SMichael Tuexen #endif
425f8829a4aSRandall Stewart }
426f8829a4aSRandall Stewart 
427f8829a4aSRandall Stewart void
428f8829a4aSRandall Stewart sctp_log_rwnd(uint8_t from, uint32_t peers_rwnd, uint32_t snd_size, uint32_t overhead)
429f8829a4aSRandall Stewart {
430c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
431c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
432f8829a4aSRandall Stewart 
43380fefe0aSRandall Stewart 	sctp_clog.x.rwnd.rwnd = peers_rwnd;
43480fefe0aSRandall Stewart 	sctp_clog.x.rwnd.send_size = snd_size;
43580fefe0aSRandall Stewart 	sctp_clog.x.rwnd.overhead = overhead;
43680fefe0aSRandall Stewart 	sctp_clog.x.rwnd.new_rwnd = 0;
437c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
43880fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_RWND,
43980fefe0aSRandall Stewart 	    from,
44080fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
44180fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
44280fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
44380fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
444c692df45SMichael Tuexen #endif
445f8829a4aSRandall Stewart }
446f8829a4aSRandall Stewart 
447f8829a4aSRandall Stewart void
448f8829a4aSRandall Stewart sctp_log_rwnd_set(uint8_t from, uint32_t peers_rwnd, uint32_t flight_size, uint32_t overhead, uint32_t a_rwndval)
449f8829a4aSRandall Stewart {
450c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
451c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
452f8829a4aSRandall Stewart 
45380fefe0aSRandall Stewart 	sctp_clog.x.rwnd.rwnd = peers_rwnd;
45480fefe0aSRandall Stewart 	sctp_clog.x.rwnd.send_size = flight_size;
45580fefe0aSRandall Stewart 	sctp_clog.x.rwnd.overhead = overhead;
45680fefe0aSRandall Stewart 	sctp_clog.x.rwnd.new_rwnd = a_rwndval;
457c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
45880fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_RWND,
45980fefe0aSRandall Stewart 	    from,
46080fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
46180fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
46280fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
46380fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
464c692df45SMichael Tuexen #endif
465f8829a4aSRandall Stewart }
466f8829a4aSRandall Stewart 
4674be807c4SMichael Tuexen #ifdef SCTP_MBCNT_LOGGING
4684be807c4SMichael Tuexen static void
469f8829a4aSRandall Stewart sctp_log_mbcnt(uint8_t from, uint32_t total_oq, uint32_t book, uint32_t total_mbcnt_q, uint32_t mbcnt)
470f8829a4aSRandall Stewart {
471c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
472c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
473f8829a4aSRandall Stewart 
47480fefe0aSRandall Stewart 	sctp_clog.x.mbcnt.total_queue_size = total_oq;
47580fefe0aSRandall Stewart 	sctp_clog.x.mbcnt.size_change = book;
47680fefe0aSRandall Stewart 	sctp_clog.x.mbcnt.total_queue_mb_size = total_mbcnt_q;
47780fefe0aSRandall Stewart 	sctp_clog.x.mbcnt.mbcnt_change = mbcnt;
478c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
47980fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_MBCNT,
48080fefe0aSRandall Stewart 	    from,
48180fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
48280fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
48380fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
48480fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
485c692df45SMichael Tuexen #endif
486f8829a4aSRandall Stewart }
4874be807c4SMichael Tuexen #endif
4884be807c4SMichael Tuexen 
489f8829a4aSRandall Stewart void
490f8829a4aSRandall Stewart sctp_misc_ints(uint8_t from, uint32_t a, uint32_t b, uint32_t c, uint32_t d)
491f8829a4aSRandall Stewart {
492c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
493c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
49480fefe0aSRandall Stewart 	    SCTP_LOG_MISC_EVENT,
49580fefe0aSRandall Stewart 	    from,
49680fefe0aSRandall Stewart 	    a, b, c, d);
497c692df45SMichael Tuexen #endif
498f8829a4aSRandall Stewart }
499f8829a4aSRandall Stewart 
500f8829a4aSRandall Stewart void
5017215cc1bSMichael Tuexen sctp_wakeup_log(struct sctp_tcb *stcb, uint32_t wake_cnt, int from)
502f8829a4aSRandall Stewart {
503c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
504c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
505f8829a4aSRandall Stewart 
50680fefe0aSRandall Stewart 	sctp_clog.x.wake.stcb = (void *)stcb;
50780fefe0aSRandall Stewart 	sctp_clog.x.wake.wake_cnt = wake_cnt;
50880fefe0aSRandall Stewart 	sctp_clog.x.wake.flight = stcb->asoc.total_flight_count;
50980fefe0aSRandall Stewart 	sctp_clog.x.wake.send_q = stcb->asoc.send_queue_cnt;
51080fefe0aSRandall Stewart 	sctp_clog.x.wake.sent_q = stcb->asoc.sent_queue_cnt;
511f8829a4aSRandall Stewart 
512f8829a4aSRandall Stewart 	if (stcb->asoc.stream_queue_cnt < 0xff)
51380fefe0aSRandall Stewart 		sctp_clog.x.wake.stream_qcnt = (uint8_t)stcb->asoc.stream_queue_cnt;
514f8829a4aSRandall Stewart 	else
51580fefe0aSRandall Stewart 		sctp_clog.x.wake.stream_qcnt = 0xff;
516f8829a4aSRandall Stewart 
517f8829a4aSRandall Stewart 	if (stcb->asoc.chunks_on_out_queue < 0xff)
51880fefe0aSRandall Stewart 		sctp_clog.x.wake.chunks_on_oque = (uint8_t)stcb->asoc.chunks_on_out_queue;
519f8829a4aSRandall Stewart 	else
52080fefe0aSRandall Stewart 		sctp_clog.x.wake.chunks_on_oque = 0xff;
521f8829a4aSRandall Stewart 
52280fefe0aSRandall Stewart 	sctp_clog.x.wake.sctpflags = 0;
523f8829a4aSRandall Stewart 	/* set in the defered mode stuff */
524f8829a4aSRandall Stewart 	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE)
52580fefe0aSRandall Stewart 		sctp_clog.x.wake.sctpflags |= 1;
526f8829a4aSRandall Stewart 	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT)
52780fefe0aSRandall Stewart 		sctp_clog.x.wake.sctpflags |= 2;
528f8829a4aSRandall Stewart 	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT)
52980fefe0aSRandall Stewart 		sctp_clog.x.wake.sctpflags |= 4;
530f8829a4aSRandall Stewart 	/* what about the sb */
531f8829a4aSRandall Stewart 	if (stcb->sctp_socket) {
532f8829a4aSRandall Stewart 		struct socket *so = stcb->sctp_socket;
533f8829a4aSRandall Stewart 
53480fefe0aSRandall Stewart 		sctp_clog.x.wake.sbflags = (uint8_t)((so->so_snd.sb_flags & 0x00ff));
535f8829a4aSRandall Stewart 	} else {
53680fefe0aSRandall Stewart 		sctp_clog.x.wake.sbflags = 0xff;
537f8829a4aSRandall Stewart 	}
538c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
53980fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_WAKE,
54080fefe0aSRandall Stewart 	    from,
54180fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
54280fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
54380fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
54480fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
545c692df45SMichael Tuexen #endif
546f8829a4aSRandall Stewart }
547f8829a4aSRandall Stewart 
548f8829a4aSRandall Stewart void
54958e6eeefSMichael Tuexen sctp_log_block(uint8_t from, struct sctp_association *asoc, ssize_t sendlen)
550f8829a4aSRandall Stewart {
551c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF)
552c692df45SMichael Tuexen 	struct sctp_cwnd_log sctp_clog;
553f8829a4aSRandall Stewart 
55480fefe0aSRandall Stewart 	sctp_clog.x.blk.onsb = asoc->total_output_queue_size;
55580fefe0aSRandall Stewart 	sctp_clog.x.blk.send_sent_qcnt = (uint16_t)(asoc->send_queue_cnt + asoc->sent_queue_cnt);
55680fefe0aSRandall Stewart 	sctp_clog.x.blk.peer_rwnd = asoc->peers_rwnd;
55780fefe0aSRandall Stewart 	sctp_clog.x.blk.stream_qcnt = (uint16_t)asoc->stream_queue_cnt;
55880fefe0aSRandall Stewart 	sctp_clog.x.blk.chunks_on_oque = (uint16_t)asoc->chunks_on_out_queue;
55980fefe0aSRandall Stewart 	sctp_clog.x.blk.flight_size = (uint16_t)(asoc->total_flight / 1024);
5609a8e3088SMichael Tuexen 	sctp_clog.x.blk.sndlen = (uint32_t)sendlen;
561c4739e2fSRandall Stewart 	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
56280fefe0aSRandall Stewart 	    SCTP_LOG_EVENT_BLOCK,
56380fefe0aSRandall Stewart 	    from,
56480fefe0aSRandall Stewart 	    sctp_clog.x.misc.log1,
56580fefe0aSRandall Stewart 	    sctp_clog.x.misc.log2,
56680fefe0aSRandall Stewart 	    sctp_clog.x.misc.log3,
56780fefe0aSRandall Stewart 	    sctp_clog.x.misc.log4);
568c692df45SMichael Tuexen #endif
569f8829a4aSRandall Stewart }
570f8829a4aSRandall Stewart 
571f8829a4aSRandall Stewart int
5727215cc1bSMichael Tuexen sctp_fill_stat_log(void *optval SCTP_UNUSED, size_t *optsize SCTP_UNUSED)
573f8829a4aSRandall Stewart {
57480fefe0aSRandall Stewart 	/* May need to fix this if ktrdump does not work */
575f8829a4aSRandall Stewart 	return (0);
576f8829a4aSRandall Stewart }
577f8829a4aSRandall Stewart 
578f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED
579f8829a4aSRandall Stewart uint8_t sctp_audit_data[SCTP_AUDIT_SIZE][2];
580f8829a4aSRandall Stewart static int sctp_audit_indx = 0;
581f8829a4aSRandall Stewart 
582f8829a4aSRandall Stewart static
583f8829a4aSRandall Stewart void
584f8829a4aSRandall Stewart sctp_print_audit_report(void)
585f8829a4aSRandall Stewart {
586f8829a4aSRandall Stewart 	int i;
587f8829a4aSRandall Stewart 	int cnt;
588f8829a4aSRandall Stewart 
589f8829a4aSRandall Stewart 	cnt = 0;
590f8829a4aSRandall Stewart 	for (i = sctp_audit_indx; i < SCTP_AUDIT_SIZE; i++) {
591f8829a4aSRandall Stewart 		if ((sctp_audit_data[i][0] == 0xe0) &&
592f8829a4aSRandall Stewart 		    (sctp_audit_data[i][1] == 0x01)) {
593f8829a4aSRandall Stewart 			cnt = 0;
594ad81507eSRandall Stewart 			SCTP_PRINTF("\n");
595f8829a4aSRandall Stewart 		} else if (sctp_audit_data[i][0] == 0xf0) {
596f8829a4aSRandall Stewart 			cnt = 0;
597ad81507eSRandall Stewart 			SCTP_PRINTF("\n");
598f8829a4aSRandall Stewart 		} else if ((sctp_audit_data[i][0] == 0xc0) &&
599f8829a4aSRandall Stewart 		    (sctp_audit_data[i][1] == 0x01)) {
600ad81507eSRandall Stewart 			SCTP_PRINTF("\n");
601f8829a4aSRandall Stewart 			cnt = 0;
602f8829a4aSRandall Stewart 		}
603ad81507eSRandall Stewart 		SCTP_PRINTF("%2.2x%2.2x ", (uint32_t)sctp_audit_data[i][0],
604f8829a4aSRandall Stewart 		    (uint32_t)sctp_audit_data[i][1]);
605f8829a4aSRandall Stewart 		cnt++;
606f8829a4aSRandall Stewart 		if ((cnt % 14) == 0)
607ad81507eSRandall Stewart 			SCTP_PRINTF("\n");
608f8829a4aSRandall Stewart 	}
609f8829a4aSRandall Stewart 	for (i = 0; i < sctp_audit_indx; i++) {
610f8829a4aSRandall Stewart 		if ((sctp_audit_data[i][0] == 0xe0) &&
611f8829a4aSRandall Stewart 		    (sctp_audit_data[i][1] == 0x01)) {
612f8829a4aSRandall Stewart 			cnt = 0;
613ad81507eSRandall Stewart 			SCTP_PRINTF("\n");
614f8829a4aSRandall Stewart 		} else if (sctp_audit_data[i][0] == 0xf0) {
615f8829a4aSRandall Stewart 			cnt = 0;
616ad81507eSRandall Stewart 			SCTP_PRINTF("\n");
617f8829a4aSRandall Stewart 		} else if ((sctp_audit_data[i][0] == 0xc0) &&
618f8829a4aSRandall Stewart 		    (sctp_audit_data[i][1] == 0x01)) {
619ad81507eSRandall Stewart 			SCTP_PRINTF("\n");
620f8829a4aSRandall Stewart 			cnt = 0;
621f8829a4aSRandall Stewart 		}
622ad81507eSRandall Stewart 		SCTP_PRINTF("%2.2x%2.2x ", (uint32_t)sctp_audit_data[i][0],
623f8829a4aSRandall Stewart 		    (uint32_t)sctp_audit_data[i][1]);
624f8829a4aSRandall Stewart 		cnt++;
625f8829a4aSRandall Stewart 		if ((cnt % 14) == 0)
626ad81507eSRandall Stewart 			SCTP_PRINTF("\n");
627f8829a4aSRandall Stewart 	}
628ad81507eSRandall Stewart 	SCTP_PRINTF("\n");
629f8829a4aSRandall Stewart }
630f8829a4aSRandall Stewart 
631f8829a4aSRandall Stewart void
632f8829a4aSRandall Stewart sctp_auditing(int from, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
633f8829a4aSRandall Stewart     struct sctp_nets *net)
634f8829a4aSRandall Stewart {
635f8829a4aSRandall Stewart 	int resend_cnt, tot_out, rep, tot_book_cnt;
636f8829a4aSRandall Stewart 	struct sctp_nets *lnet;
637f8829a4aSRandall Stewart 	struct sctp_tmit_chunk *chk;
638f8829a4aSRandall Stewart 
639f8829a4aSRandall Stewart 	sctp_audit_data[sctp_audit_indx][0] = 0xAA;
640f8829a4aSRandall Stewart 	sctp_audit_data[sctp_audit_indx][1] = 0x000000ff & from;
641f8829a4aSRandall Stewart 	sctp_audit_indx++;
642f8829a4aSRandall Stewart 	if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
643f8829a4aSRandall Stewart 		sctp_audit_indx = 0;
644f8829a4aSRandall Stewart 	}
645f8829a4aSRandall Stewart 	if (inp == NULL) {
646f8829a4aSRandall Stewart 		sctp_audit_data[sctp_audit_indx][0] = 0xAF;
647f8829a4aSRandall Stewart 		sctp_audit_data[sctp_audit_indx][1] = 0x01;
648f8829a4aSRandall Stewart 		sctp_audit_indx++;
649f8829a4aSRandall Stewart 		if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
650f8829a4aSRandall Stewart 			sctp_audit_indx = 0;
651f8829a4aSRandall Stewart 		}
652f8829a4aSRandall Stewart 		return;
653f8829a4aSRandall Stewart 	}
654f8829a4aSRandall Stewart 	if (stcb == NULL) {
655f8829a4aSRandall Stewart 		sctp_audit_data[sctp_audit_indx][0] = 0xAF;
656f8829a4aSRandall Stewart 		sctp_audit_data[sctp_audit_indx][1] = 0x02;
657f8829a4aSRandall Stewart 		sctp_audit_indx++;
658f8829a4aSRandall Stewart 		if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
659f8829a4aSRandall Stewart 			sctp_audit_indx = 0;
660f8829a4aSRandall Stewart 		}
661f8829a4aSRandall Stewart 		return;
662f8829a4aSRandall Stewart 	}
663f8829a4aSRandall Stewart 	sctp_audit_data[sctp_audit_indx][0] = 0xA1;
664f8829a4aSRandall Stewart 	sctp_audit_data[sctp_audit_indx][1] =
665f8829a4aSRandall Stewart 	    (0x000000ff & stcb->asoc.sent_queue_retran_cnt);
666f8829a4aSRandall Stewart 	sctp_audit_indx++;
667f8829a4aSRandall Stewart 	if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
668f8829a4aSRandall Stewart 		sctp_audit_indx = 0;
669f8829a4aSRandall Stewart 	}
670f8829a4aSRandall Stewart 	rep = 0;
671f8829a4aSRandall Stewart 	tot_book_cnt = 0;
672f8829a4aSRandall Stewart 	resend_cnt = tot_out = 0;
673f8829a4aSRandall Stewart 	TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
674f8829a4aSRandall Stewart 		if (chk->sent == SCTP_DATAGRAM_RESEND) {
675f8829a4aSRandall Stewart 			resend_cnt++;
676f8829a4aSRandall Stewart 		} else if (chk->sent < SCTP_DATAGRAM_RESEND) {
677f8829a4aSRandall Stewart 			tot_out += chk->book_size;
678f8829a4aSRandall Stewart 			tot_book_cnt++;
679f8829a4aSRandall Stewart 		}
680f8829a4aSRandall Stewart 	}
681f8829a4aSRandall Stewart 	if (resend_cnt != stcb->asoc.sent_queue_retran_cnt) {
682f8829a4aSRandall Stewart 		sctp_audit_data[sctp_audit_indx][0] = 0xAF;
683f8829a4aSRandall Stewart 		sctp_audit_data[sctp_audit_indx][1] = 0xA1;
684f8829a4aSRandall Stewart 		sctp_audit_indx++;
685f8829a4aSRandall Stewart 		if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
686f8829a4aSRandall Stewart 			sctp_audit_indx = 0;
687f8829a4aSRandall Stewart 		}
688ad81507eSRandall Stewart 		SCTP_PRINTF("resend_cnt:%d asoc-tot:%d\n",
689f8829a4aSRandall Stewart 		    resend_cnt, stcb->asoc.sent_queue_retran_cnt);
690f8829a4aSRandall Stewart 		rep = 1;
691f8829a4aSRandall Stewart 		stcb->asoc.sent_queue_retran_cnt = resend_cnt;
692f8829a4aSRandall Stewart 		sctp_audit_data[sctp_audit_indx][0] = 0xA2;
693f8829a4aSRandall Stewart 		sctp_audit_data[sctp_audit_indx][1] =
694f8829a4aSRandall Stewart 		    (0x000000ff & stcb->asoc.sent_queue_retran_cnt);
695f8829a4aSRandall Stewart 		sctp_audit_indx++;
696f8829a4aSRandall Stewart 		if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
697f8829a4aSRandall Stewart 			sctp_audit_indx = 0;
698f8829a4aSRandall Stewart 		}
699f8829a4aSRandall Stewart 	}
700f8829a4aSRandall Stewart 	if (tot_out != stcb->asoc.total_flight) {
701f8829a4aSRandall Stewart 		sctp_audit_data[sctp_audit_indx][0] = 0xAF;
702f8829a4aSRandall Stewart 		sctp_audit_data[sctp_audit_indx][1] = 0xA2;
703f8829a4aSRandall Stewart 		sctp_audit_indx++;
704f8829a4aSRandall Stewart 		if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
705f8829a4aSRandall Stewart 			sctp_audit_indx = 0;
706f8829a4aSRandall Stewart 		}
707f8829a4aSRandall Stewart 		rep = 1;
708ad81507eSRandall Stewart 		SCTP_PRINTF("tot_flt:%d asoc_tot:%d\n", tot_out,
709f8829a4aSRandall Stewart 		    (int)stcb->asoc.total_flight);
710f8829a4aSRandall Stewart 		stcb->asoc.total_flight = tot_out;
711f8829a4aSRandall Stewart 	}
712f8829a4aSRandall Stewart 	if (tot_book_cnt != stcb->asoc.total_flight_count) {
713f8829a4aSRandall Stewart 		sctp_audit_data[sctp_audit_indx][0] = 0xAF;
714f8829a4aSRandall Stewart 		sctp_audit_data[sctp_audit_indx][1] = 0xA5;
715f8829a4aSRandall Stewart 		sctp_audit_indx++;
716f8829a4aSRandall Stewart 		if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
717f8829a4aSRandall Stewart 			sctp_audit_indx = 0;
718f8829a4aSRandall Stewart 		}
719f8829a4aSRandall Stewart 		rep = 1;
720f31e6c7fSMichael Tuexen 		SCTP_PRINTF("tot_flt_book:%d\n", tot_book_cnt);
721f8829a4aSRandall Stewart 
722f8829a4aSRandall Stewart 		stcb->asoc.total_flight_count = tot_book_cnt;
723f8829a4aSRandall Stewart 	}
724f8829a4aSRandall Stewart 	tot_out = 0;
725f8829a4aSRandall Stewart 	TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
726f8829a4aSRandall Stewart 		tot_out += lnet->flight_size;
727f8829a4aSRandall Stewart 	}
728f8829a4aSRandall Stewart 	if (tot_out != stcb->asoc.total_flight) {
729f8829a4aSRandall Stewart 		sctp_audit_data[sctp_audit_indx][0] = 0xAF;
730f8829a4aSRandall Stewart 		sctp_audit_data[sctp_audit_indx][1] = 0xA3;
731f8829a4aSRandall Stewart 		sctp_audit_indx++;
732f8829a4aSRandall Stewart 		if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
733f8829a4aSRandall Stewart 			sctp_audit_indx = 0;
734f8829a4aSRandall Stewart 		}
735f8829a4aSRandall Stewart 		rep = 1;
736ad81507eSRandall Stewart 		SCTP_PRINTF("real flight:%d net total was %d\n",
737f8829a4aSRandall Stewart 		    stcb->asoc.total_flight, tot_out);
738f8829a4aSRandall Stewart 		/* now corrective action */
739f8829a4aSRandall Stewart 		TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
740f8829a4aSRandall Stewart 
741f8829a4aSRandall Stewart 			tot_out = 0;
742f8829a4aSRandall Stewart 			TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
743f8829a4aSRandall Stewart 				if ((chk->whoTo == lnet) &&
744f8829a4aSRandall Stewart 				    (chk->sent < SCTP_DATAGRAM_RESEND)) {
745f8829a4aSRandall Stewart 					tot_out += chk->book_size;
746f8829a4aSRandall Stewart 				}
747f8829a4aSRandall Stewart 			}
748f8829a4aSRandall Stewart 			if (lnet->flight_size != tot_out) {
749f31e6c7fSMichael Tuexen 				SCTP_PRINTF("net:%p flight was %d corrected to %d\n",
750dd294dceSMichael Tuexen 				    (void *)lnet, lnet->flight_size,
751ad81507eSRandall Stewart 				    tot_out);
752f8829a4aSRandall Stewart 				lnet->flight_size = tot_out;
753f8829a4aSRandall Stewart 			}
754f8829a4aSRandall Stewart 		}
755f8829a4aSRandall Stewart 	}
756f8829a4aSRandall Stewart 	if (rep) {
757f8829a4aSRandall Stewart 		sctp_print_audit_report();
758f8829a4aSRandall Stewart 	}
759f8829a4aSRandall Stewart }
760f8829a4aSRandall Stewart 
761f8829a4aSRandall Stewart void
762f8829a4aSRandall Stewart sctp_audit_log(uint8_t ev, uint8_t fd)
763f8829a4aSRandall Stewart {
764f8829a4aSRandall Stewart 
765f8829a4aSRandall Stewart 	sctp_audit_data[sctp_audit_indx][0] = ev;
766f8829a4aSRandall Stewart 	sctp_audit_data[sctp_audit_indx][1] = fd;
767f8829a4aSRandall Stewart 	sctp_audit_indx++;
768f8829a4aSRandall Stewart 	if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
769f8829a4aSRandall Stewart 		sctp_audit_indx = 0;
770f8829a4aSRandall Stewart 	}
771f8829a4aSRandall Stewart }
772f8829a4aSRandall Stewart 
773f8829a4aSRandall Stewart #endif
774f8829a4aSRandall Stewart 
775f8829a4aSRandall Stewart /*
77612af6654SMichael Tuexen  * sctp_stop_timers_for_shutdown() should be called
77712af6654SMichael Tuexen  * when entering the SHUTDOWN_SENT or SHUTDOWN_ACK_SENT
77812af6654SMichael Tuexen  * state to make sure that all timers are stopped.
77912af6654SMichael Tuexen  */
78012af6654SMichael Tuexen void
78112af6654SMichael Tuexen sctp_stop_timers_for_shutdown(struct sctp_tcb *stcb)
78212af6654SMichael Tuexen {
7835555400aSMichael Tuexen 	struct sctp_inpcb *inp;
78412af6654SMichael Tuexen 	struct sctp_nets *net;
78512af6654SMichael Tuexen 
7865555400aSMichael Tuexen 	inp = stcb->sctp_ep;
78712af6654SMichael Tuexen 
7885555400aSMichael Tuexen 	sctp_timer_stop(SCTP_TIMER_TYPE_RECV, inp, stcb, NULL,
7895555400aSMichael Tuexen 	    SCTP_FROM_SCTPUTIL + SCTP_LOC_12);
7905555400aSMichael Tuexen 	sctp_timer_stop(SCTP_TIMER_TYPE_STRRESET, inp, stcb, NULL,
7915555400aSMichael Tuexen 	    SCTP_FROM_SCTPUTIL + SCTP_LOC_13);
7925555400aSMichael Tuexen 	sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, inp, stcb, NULL,
7935555400aSMichael Tuexen 	    SCTP_FROM_SCTPUTIL + SCTP_LOC_14);
7945555400aSMichael Tuexen 	sctp_timer_stop(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb, NULL,
7955555400aSMichael Tuexen 	    SCTP_FROM_SCTPUTIL + SCTP_LOC_15);
7965555400aSMichael Tuexen 	TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
7975555400aSMichael Tuexen 		sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
7985555400aSMichael Tuexen 		    SCTP_FROM_SCTPUTIL + SCTP_LOC_16);
7995555400aSMichael Tuexen 		sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
8005555400aSMichael Tuexen 		    SCTP_FROM_SCTPUTIL + SCTP_LOC_17);
8015555400aSMichael Tuexen 	}
8025555400aSMichael Tuexen }
8035555400aSMichael Tuexen 
8045555400aSMichael Tuexen void
8058803350dSMichael Tuexen sctp_stop_association_timers(struct sctp_tcb *stcb, bool stop_assoc_kill_timer)
8065555400aSMichael Tuexen {
8075555400aSMichael Tuexen 	struct sctp_inpcb *inp;
8085555400aSMichael Tuexen 	struct sctp_nets *net;
8095555400aSMichael Tuexen 
8105555400aSMichael Tuexen 	inp = stcb->sctp_ep;
8115555400aSMichael Tuexen 	sctp_timer_stop(SCTP_TIMER_TYPE_RECV, inp, stcb, NULL,
8125555400aSMichael Tuexen 	    SCTP_FROM_SCTPUTIL + SCTP_LOC_18);
8135555400aSMichael Tuexen 	sctp_timer_stop(SCTP_TIMER_TYPE_STRRESET, inp, stcb, NULL,
8145555400aSMichael Tuexen 	    SCTP_FROM_SCTPUTIL + SCTP_LOC_19);
8158803350dSMichael Tuexen 	if (stop_assoc_kill_timer) {
8165555400aSMichael Tuexen 		sctp_timer_stop(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL,
8175555400aSMichael Tuexen 		    SCTP_FROM_SCTPUTIL + SCTP_LOC_20);
8185555400aSMichael Tuexen 	}
8195555400aSMichael Tuexen 	sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, inp, stcb, NULL,
8205555400aSMichael Tuexen 	    SCTP_FROM_SCTPUTIL + SCTP_LOC_21);
8215555400aSMichael Tuexen 	sctp_timer_stop(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb, NULL,
8225555400aSMichael Tuexen 	    SCTP_FROM_SCTPUTIL + SCTP_LOC_22);
8235555400aSMichael Tuexen 	sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWNGUARD, inp, stcb, NULL,
8245555400aSMichael Tuexen 	    SCTP_FROM_SCTPUTIL + SCTP_LOC_23);
8255555400aSMichael Tuexen 	/* Mobility adaptation */
8265555400aSMichael Tuexen 	sctp_timer_stop(SCTP_TIMER_TYPE_PRIM_DELETED, inp, stcb, NULL,
8275555400aSMichael Tuexen 	    SCTP_FROM_SCTPUTIL + SCTP_LOC_24);
8285555400aSMichael Tuexen 	TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
8295555400aSMichael Tuexen 		sctp_timer_stop(SCTP_TIMER_TYPE_SEND, inp, stcb, net,
8305555400aSMichael Tuexen 		    SCTP_FROM_SCTPUTIL + SCTP_LOC_25);
8315555400aSMichael Tuexen 		sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, net,
8325555400aSMichael Tuexen 		    SCTP_FROM_SCTPUTIL + SCTP_LOC_26);
8335555400aSMichael Tuexen 		sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWN, inp, stcb, net,
8345555400aSMichael Tuexen 		    SCTP_FROM_SCTPUTIL + SCTP_LOC_27);
8355555400aSMichael Tuexen 		sctp_timer_stop(SCTP_TIMER_TYPE_COOKIE, inp, stcb, net,
8365555400aSMichael Tuexen 		    SCTP_FROM_SCTPUTIL + SCTP_LOC_28);
8375555400aSMichael Tuexen 		sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWNACK, inp, stcb, net,
8385555400aSMichael Tuexen 		    SCTP_FROM_SCTPUTIL + SCTP_LOC_29);
8395555400aSMichael Tuexen 		sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
8405555400aSMichael Tuexen 		    SCTP_FROM_SCTPUTIL + SCTP_LOC_30);
8415555400aSMichael Tuexen 		sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
8425555400aSMichael Tuexen 		    SCTP_FROM_SCTPUTIL + SCTP_LOC_31);
84312af6654SMichael Tuexen 	}
84412af6654SMichael Tuexen }
84512af6654SMichael Tuexen 
84612af6654SMichael Tuexen /*
847589c42c2SMichael Tuexen  * A list of sizes based on typical mtu's, used only if next hop size not
848589c42c2SMichael Tuexen  * returned. These values MUST be multiples of 4 and MUST be ordered.
849f8829a4aSRandall Stewart  */
850437fc91aSMichael Tuexen static uint32_t sctp_mtu_sizes[] = {
851f8829a4aSRandall Stewart 	68,
852f8829a4aSRandall Stewart 	296,
853f8829a4aSRandall Stewart 	508,
854f8829a4aSRandall Stewart 	512,
855f8829a4aSRandall Stewart 	544,
856f8829a4aSRandall Stewart 	576,
857589c42c2SMichael Tuexen 	1004,
858f8829a4aSRandall Stewart 	1492,
859f8829a4aSRandall Stewart 	1500,
860f8829a4aSRandall Stewart 	1536,
861589c42c2SMichael Tuexen 	2000,
862f8829a4aSRandall Stewart 	2048,
863f8829a4aSRandall Stewart 	4352,
864f8829a4aSRandall Stewart 	4464,
86542078d5aSMichael Tuexen 	8168,
866589c42c2SMichael Tuexen 	17912,
867f8829a4aSRandall Stewart 	32000,
868589c42c2SMichael Tuexen 	65532
869f8829a4aSRandall Stewart };
870f8829a4aSRandall Stewart 
871f8829a4aSRandall Stewart /*
872589c42c2SMichael Tuexen  * Return the largest MTU in sctp_mtu_sizes smaller than val.
873589c42c2SMichael Tuexen  * If val is smaller than the minimum, just return the largest
874589c42c2SMichael Tuexen  * multiple of 4 smaller or equal to val.
875589c42c2SMichael Tuexen  * Ensure that the result is a multiple of 4.
876f8829a4aSRandall Stewart  */
877437fc91aSMichael Tuexen uint32_t
878b0471b4bSMichael Tuexen sctp_get_prev_mtu(uint32_t val)
879b0471b4bSMichael Tuexen {
880437fc91aSMichael Tuexen 	uint32_t i;
881437fc91aSMichael Tuexen 
882eef8d4a9SMichael Tuexen 	val &= 0xfffffffc;
883437fc91aSMichael Tuexen 	if (val <= sctp_mtu_sizes[0]) {
884437fc91aSMichael Tuexen 		return (val);
885437fc91aSMichael Tuexen 	}
886437fc91aSMichael Tuexen 	for (i = 1; i < (sizeof(sctp_mtu_sizes) / sizeof(uint32_t)); i++) {
887437fc91aSMichael Tuexen 		if (val <= sctp_mtu_sizes[i]) {
888f8829a4aSRandall Stewart 			break;
889f8829a4aSRandall Stewart 		}
890f8829a4aSRandall Stewart 	}
891589c42c2SMichael Tuexen 	KASSERT((sctp_mtu_sizes[i - 1] & 0x00000003) == 0,
892589c42c2SMichael Tuexen 	    ("sctp_mtu_sizes[%u] not a multiple of 4", i - 1));
893437fc91aSMichael Tuexen 	return (sctp_mtu_sizes[i - 1]);
894437fc91aSMichael Tuexen }
895437fc91aSMichael Tuexen 
896437fc91aSMichael Tuexen /*
897589c42c2SMichael Tuexen  * Return the smallest MTU in sctp_mtu_sizes larger than val.
898589c42c2SMichael Tuexen  * If val is larger than the maximum, just return the largest multiple of 4 smaller
899589c42c2SMichael Tuexen  * or equal to val.
900589c42c2SMichael Tuexen  * Ensure that the result is a multiple of 4.
901437fc91aSMichael Tuexen  */
902437fc91aSMichael Tuexen uint32_t
903b0471b4bSMichael Tuexen sctp_get_next_mtu(uint32_t val)
904b0471b4bSMichael Tuexen {
905437fc91aSMichael Tuexen 	/* select another MTU that is just bigger than this one */
906437fc91aSMichael Tuexen 	uint32_t i;
907437fc91aSMichael Tuexen 
908eef8d4a9SMichael Tuexen 	val &= 0xfffffffc;
909437fc91aSMichael Tuexen 	for (i = 0; i < (sizeof(sctp_mtu_sizes) / sizeof(uint32_t)); i++) {
910437fc91aSMichael Tuexen 		if (val < sctp_mtu_sizes[i]) {
911589c42c2SMichael Tuexen 			KASSERT((sctp_mtu_sizes[i] & 0x00000003) == 0,
912589c42c2SMichael Tuexen 			    ("sctp_mtu_sizes[%u] not a multiple of 4", i));
913437fc91aSMichael Tuexen 			return (sctp_mtu_sizes[i]);
914437fc91aSMichael Tuexen 		}
915437fc91aSMichael Tuexen 	}
916437fc91aSMichael Tuexen 	return (val);
917f8829a4aSRandall Stewart }
918f8829a4aSRandall Stewart 
919f8829a4aSRandall Stewart void
920f8829a4aSRandall Stewart sctp_fill_random_store(struct sctp_pcb *m)
921f8829a4aSRandall Stewart {
922f8829a4aSRandall Stewart 	/*
923f8829a4aSRandall Stewart 	 * Here we use the MD5/SHA-1 to hash with our good randomNumbers and
924f8829a4aSRandall Stewart 	 * our counter. The result becomes our good random numbers and we
925f8829a4aSRandall Stewart 	 * then setup to give these out. Note that we do no locking to
926f8829a4aSRandall Stewart 	 * protect this. This is ok, since if competing folks call this we
92717205eccSRandall Stewart 	 * will get more gobbled gook in the random store which is what we
928f8829a4aSRandall Stewart 	 * want. There is a danger that two guys will use the same random
929f8829a4aSRandall Stewart 	 * numbers, but thats ok too since that is random as well :->
930f8829a4aSRandall Stewart 	 */
931f8829a4aSRandall Stewart 	m->store_at = 0;
932ad81507eSRandall Stewart 	(void)sctp_hmac(SCTP_HMAC, (uint8_t *)m->random_numbers,
933f8829a4aSRandall Stewart 	    sizeof(m->random_numbers), (uint8_t *)&m->random_counter,
934f8829a4aSRandall Stewart 	    sizeof(m->random_counter), (uint8_t *)m->random_store);
935f8829a4aSRandall Stewart 	m->random_counter++;
936f8829a4aSRandall Stewart }
937f8829a4aSRandall Stewart 
938f8829a4aSRandall Stewart uint32_t
939b0471b4bSMichael Tuexen sctp_select_initial_TSN(struct sctp_pcb *inp)
940b0471b4bSMichael Tuexen {
941f8829a4aSRandall Stewart 	/*
942f8829a4aSRandall Stewart 	 * A true implementation should use random selection process to get
943f8829a4aSRandall Stewart 	 * the initial stream sequence number, using RFC1750 as a good
944f8829a4aSRandall Stewart 	 * guideline
945f8829a4aSRandall Stewart 	 */
946139bc87fSRandall Stewart 	uint32_t x, *xp;
947f8829a4aSRandall Stewart 	uint8_t *p;
948851b7298SRandall Stewart 	int store_at, new_store;
949f8829a4aSRandall Stewart 
950851b7298SRandall Stewart 	if (inp->initial_sequence_debug != 0) {
951f8829a4aSRandall Stewart 		uint32_t ret;
952f8829a4aSRandall Stewart 
953851b7298SRandall Stewart 		ret = inp->initial_sequence_debug;
954851b7298SRandall Stewart 		inp->initial_sequence_debug++;
955f8829a4aSRandall Stewart 		return (ret);
956f8829a4aSRandall Stewart 	}
957851b7298SRandall Stewart retry:
958851b7298SRandall Stewart 	store_at = inp->store_at;
959851b7298SRandall Stewart 	new_store = store_at + sizeof(uint32_t);
960851b7298SRandall Stewart 	if (new_store >= (SCTP_SIGNATURE_SIZE - 3)) {
961851b7298SRandall Stewart 		new_store = 0;
962f8829a4aSRandall Stewart 	}
963851b7298SRandall Stewart 	if (!atomic_cmpset_int(&inp->store_at, store_at, new_store)) {
964851b7298SRandall Stewart 		goto retry;
965851b7298SRandall Stewart 	}
966851b7298SRandall Stewart 	if (new_store == 0) {
967851b7298SRandall Stewart 		/* Refill the random store */
968851b7298SRandall Stewart 		sctp_fill_random_store(inp);
969851b7298SRandall Stewart 	}
970851b7298SRandall Stewart 	p = &inp->random_store[store_at];
971139bc87fSRandall Stewart 	xp = (uint32_t *)p;
972f8829a4aSRandall Stewart 	x = *xp;
973f8829a4aSRandall Stewart 	return (x);
974f8829a4aSRandall Stewart }
975f8829a4aSRandall Stewart 
976f8829a4aSRandall Stewart uint32_t
977b0471b4bSMichael Tuexen sctp_select_a_tag(struct sctp_inpcb *inp, uint16_t lport, uint16_t rport, int check)
978b0471b4bSMichael Tuexen {
9797215cc1bSMichael Tuexen 	uint32_t x;
980f8829a4aSRandall Stewart 	struct timeval now;
981f8829a4aSRandall Stewart 
9827215cc1bSMichael Tuexen 	if (check) {
9836e55db54SRandall Stewart 		(void)SCTP_GETTIME_TIMEVAL(&now);
9847215cc1bSMichael Tuexen 	}
9857215cc1bSMichael Tuexen 	for (;;) {
986851b7298SRandall Stewart 		x = sctp_select_initial_TSN(&inp->sctp_ep);
987f8829a4aSRandall Stewart 		if (x == 0) {
988f8829a4aSRandall Stewart 			/* we never use 0 */
989f8829a4aSRandall Stewart 			continue;
990f8829a4aSRandall Stewart 		}
9917215cc1bSMichael Tuexen 		if (!check || sctp_is_vtag_good(x, lport, rport, &now)) {
9927215cc1bSMichael Tuexen 			break;
993f8829a4aSRandall Stewart 		}
994f8829a4aSRandall Stewart 	}
995f8829a4aSRandall Stewart 	return (x);
996f8829a4aSRandall Stewart }
997f8829a4aSRandall Stewart 
998e92c2a8dSMichael Tuexen int32_t
999b0471b4bSMichael Tuexen sctp_map_assoc_state(int kernel_state)
1000b0471b4bSMichael Tuexen {
1001e92c2a8dSMichael Tuexen 	int32_t user_state;
1002e92c2a8dSMichael Tuexen 
1003e92c2a8dSMichael Tuexen 	if (kernel_state & SCTP_STATE_WAS_ABORTED) {
1004e92c2a8dSMichael Tuexen 		user_state = SCTP_CLOSED;
1005e92c2a8dSMichael Tuexen 	} else if (kernel_state & SCTP_STATE_SHUTDOWN_PENDING) {
1006e92c2a8dSMichael Tuexen 		user_state = SCTP_SHUTDOWN_PENDING;
1007e92c2a8dSMichael Tuexen 	} else {
1008e92c2a8dSMichael Tuexen 		switch (kernel_state & SCTP_STATE_MASK) {
1009e92c2a8dSMichael Tuexen 		case SCTP_STATE_EMPTY:
1010e92c2a8dSMichael Tuexen 			user_state = SCTP_CLOSED;
1011e92c2a8dSMichael Tuexen 			break;
1012e92c2a8dSMichael Tuexen 		case SCTP_STATE_INUSE:
1013e92c2a8dSMichael Tuexen 			user_state = SCTP_CLOSED;
1014e92c2a8dSMichael Tuexen 			break;
1015e92c2a8dSMichael Tuexen 		case SCTP_STATE_COOKIE_WAIT:
1016e92c2a8dSMichael Tuexen 			user_state = SCTP_COOKIE_WAIT;
1017e92c2a8dSMichael Tuexen 			break;
1018e92c2a8dSMichael Tuexen 		case SCTP_STATE_COOKIE_ECHOED:
1019e92c2a8dSMichael Tuexen 			user_state = SCTP_COOKIE_ECHOED;
1020e92c2a8dSMichael Tuexen 			break;
1021e92c2a8dSMichael Tuexen 		case SCTP_STATE_OPEN:
1022e92c2a8dSMichael Tuexen 			user_state = SCTP_ESTABLISHED;
1023e92c2a8dSMichael Tuexen 			break;
1024e92c2a8dSMichael Tuexen 		case SCTP_STATE_SHUTDOWN_SENT:
1025e92c2a8dSMichael Tuexen 			user_state = SCTP_SHUTDOWN_SENT;
1026e92c2a8dSMichael Tuexen 			break;
1027e92c2a8dSMichael Tuexen 		case SCTP_STATE_SHUTDOWN_RECEIVED:
1028e92c2a8dSMichael Tuexen 			user_state = SCTP_SHUTDOWN_RECEIVED;
1029e92c2a8dSMichael Tuexen 			break;
1030e92c2a8dSMichael Tuexen 		case SCTP_STATE_SHUTDOWN_ACK_SENT:
1031e92c2a8dSMichael Tuexen 			user_state = SCTP_SHUTDOWN_ACK_SENT;
1032e92c2a8dSMichael Tuexen 			break;
1033e92c2a8dSMichael Tuexen 		default:
1034e92c2a8dSMichael Tuexen 			user_state = SCTP_CLOSED;
1035e92c2a8dSMichael Tuexen 			break;
1036e92c2a8dSMichael Tuexen 		}
1037e92c2a8dSMichael Tuexen 	}
1038e92c2a8dSMichael Tuexen 	return (user_state);
1039e92c2a8dSMichael Tuexen }
1040e92c2a8dSMichael Tuexen 
1041f8829a4aSRandall Stewart int
1042a1cb341bSMichael Tuexen sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
1043c979034bSMichael Tuexen     uint32_t override_tag, uint32_t vrf_id, uint16_t o_strms)
1044f8829a4aSRandall Stewart {
10450696e120SRandall Stewart 	struct sctp_association *asoc;
10460696e120SRandall Stewart 
1047f8829a4aSRandall Stewart 	/*
1048f8829a4aSRandall Stewart 	 * Anything set to zero is taken care of by the allocation routine's
1049f8829a4aSRandall Stewart 	 * bzero
1050f8829a4aSRandall Stewart 	 */
1051f8829a4aSRandall Stewart 
1052f8829a4aSRandall Stewart 	/*
1053f8829a4aSRandall Stewart 	 * Up front select what scoping to apply on addresses I tell my peer
1054f8829a4aSRandall Stewart 	 * Not sure what to do with these right now, we will need to come up
1055f8829a4aSRandall Stewart 	 * with a way to set them. We may need to pass them through from the
1056f8829a4aSRandall Stewart 	 * caller in the sctp_aloc_assoc() function.
1057f8829a4aSRandall Stewart 	 */
1058f8829a4aSRandall Stewart 	int i;
1059f0396ad1SMichael Tuexen #if defined(SCTP_DETAILED_STR_STATS)
1060f0396ad1SMichael Tuexen 	int j;
1061f0396ad1SMichael Tuexen #endif
1062f0396ad1SMichael Tuexen 
10630696e120SRandall Stewart 	asoc = &stcb->asoc;
1064f8829a4aSRandall Stewart 	/* init all variables to a known value. */
1065839d21d6SMichael Tuexen 	SCTP_SET_STATE(stcb, SCTP_STATE_INUSE);
1066a1cb341bSMichael Tuexen 	asoc->max_burst = inp->sctp_ep.max_burst;
1067a1cb341bSMichael Tuexen 	asoc->fr_max_burst = inp->sctp_ep.fr_max_burst;
1068a1cb341bSMichael Tuexen 	asoc->heart_beat_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]);
1069a1cb341bSMichael Tuexen 	asoc->cookie_life = inp->sctp_ep.def_cookie_life;
1070a1cb341bSMichael Tuexen 	asoc->sctp_cmt_on_off = inp->sctp_cmt_on_off;
1071f342355aSMichael Tuexen 	asoc->ecn_supported = inp->ecn_supported;
1072dd973b0eSMichael Tuexen 	asoc->prsctp_supported = inp->prsctp_supported;
107344249214SRandall Stewart 	asoc->idata_supported = inp->idata_supported;
1074c79bec9cSMichael Tuexen 	asoc->auth_supported = inp->auth_supported;
1075c79bec9cSMichael Tuexen 	asoc->asconf_supported = inp->asconf_supported;
1076317e00efSMichael Tuexen 	asoc->reconfig_supported = inp->reconfig_supported;
1077caea9879SMichael Tuexen 	asoc->nrsack_supported = inp->nrsack_supported;
1078cb9b8e6fSMichael Tuexen 	asoc->pktdrop_supported = inp->pktdrop_supported;
107944249214SRandall Stewart 	asoc->idata_supported = inp->idata_supported;
1080ca85e948SMichael Tuexen 	asoc->sctp_cmt_pf = (uint8_t)0;
1081a1cb341bSMichael Tuexen 	asoc->sctp_frag_point = inp->sctp_frag_point;
1082a1cb341bSMichael Tuexen 	asoc->sctp_features = inp->sctp_features;
1083a1cb341bSMichael Tuexen 	asoc->default_dscp = inp->sctp_ep.default_dscp;
108459b6d5beSMichael Tuexen 	asoc->max_cwnd = inp->max_cwnd;
108542551e99SRandall Stewart #ifdef INET6
1086a1cb341bSMichael Tuexen 	if (inp->sctp_ep.default_flowlabel) {
1087a1cb341bSMichael Tuexen 		asoc->default_flowlabel = inp->sctp_ep.default_flowlabel;
108858bdb691SMichael Tuexen 	} else {
1089a1cb341bSMichael Tuexen 		if (inp->ip_inp.inp.inp_flags & IN6P_AUTOFLOWLABEL) {
1090a1cb341bSMichael Tuexen 			asoc->default_flowlabel = sctp_select_initial_TSN(&inp->sctp_ep);
109158bdb691SMichael Tuexen 			asoc->default_flowlabel &= 0x000fffff;
109258bdb691SMichael Tuexen 			asoc->default_flowlabel |= 0x80000000;
109358bdb691SMichael Tuexen 		} else {
1094f8829a4aSRandall Stewart 			asoc->default_flowlabel = 0;
109558bdb691SMichael Tuexen 		}
109658bdb691SMichael Tuexen 	}
1097f8829a4aSRandall Stewart #endif
10989f22f500SRandall Stewart 	asoc->sb_send_resv = 0;
1099f8829a4aSRandall Stewart 	if (override_tag) {
1100f8829a4aSRandall Stewart 		asoc->my_vtag = override_tag;
1101f8829a4aSRandall Stewart 	} else {
1102a1cb341bSMichael Tuexen 		asoc->my_vtag = sctp_select_a_tag(inp, stcb->sctp_ep->sctp_lport, stcb->rport, 1);
1103f8829a4aSRandall Stewart 	}
1104de0e935bSRandall Stewart 	/* Get the nonce tags */
1105a1cb341bSMichael Tuexen 	asoc->my_vtag_nonce = sctp_select_a_tag(inp, stcb->sctp_ep->sctp_lport, stcb->rport, 0);
1106a1cb341bSMichael Tuexen 	asoc->peer_vtag_nonce = sctp_select_a_tag(inp, stcb->sctp_ep->sctp_lport, stcb->rport, 0);
110742551e99SRandall Stewart 	asoc->vrf_id = vrf_id;
1108de0e935bSRandall Stewart 
110918e198d3SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS
111018e198d3SRandall Stewart 	asoc->tsn_in_at = 0;
111118e198d3SRandall Stewart 	asoc->tsn_out_at = 0;
111218e198d3SRandall Stewart 	asoc->tsn_in_wrapped = 0;
111318e198d3SRandall Stewart 	asoc->tsn_out_wrapped = 0;
111418e198d3SRandall Stewart 	asoc->cumack_log_at = 0;
1115b201f536SRandall Stewart 	asoc->cumack_log_atsnt = 0;
111618e198d3SRandall Stewart #endif
111718e198d3SRandall Stewart #ifdef SCTP_FS_SPEC_LOG
111818e198d3SRandall Stewart 	asoc->fs_index = 0;
111918e198d3SRandall Stewart #endif
1120f8829a4aSRandall Stewart 	asoc->refcnt = 0;
1121f8829a4aSRandall Stewart 	asoc->assoc_up_sent = 0;
1122f8829a4aSRandall Stewart 	asoc->asconf_seq_out = asoc->str_reset_seq_out = asoc->init_seq_number = asoc->sending_seq =
1123a1cb341bSMichael Tuexen 	    sctp_select_initial_TSN(&inp->sctp_ep);
1124c54a18d2SRandall Stewart 	asoc->asconf_seq_out_acked = asoc->asconf_seq_out - 1;
1125f8829a4aSRandall Stewart 	/* we are optimisitic here */
1126830d754dSRandall Stewart 	asoc->peer_supports_nat = 0;
1127f8829a4aSRandall Stewart 	asoc->sent_queue_retran_cnt = 0;
1128f8829a4aSRandall Stewart 
1129f8829a4aSRandall Stewart 	/* for CMT */
11308933fa13SRandall Stewart 	asoc->last_net_cmt_send_started = NULL;
1131f8829a4aSRandall Stewart 
1132f8829a4aSRandall Stewart 	/* This will need to be adjusted */
1133f8829a4aSRandall Stewart 	asoc->last_acked_seq = asoc->init_seq_number - 1;
1134f8829a4aSRandall Stewart 	asoc->advanced_peer_ack_point = asoc->last_acked_seq;
1135f8829a4aSRandall Stewart 	asoc->asconf_seq_in = asoc->last_acked_seq;
1136f8829a4aSRandall Stewart 
1137f8829a4aSRandall Stewart 	/* here we are different, we hold the next one we expect */
1138f8829a4aSRandall Stewart 	asoc->str_reset_seq_in = asoc->last_acked_seq + 1;
1139f8829a4aSRandall Stewart 
1140a1cb341bSMichael Tuexen 	asoc->initial_init_rto_max = inp->sctp_ep.initial_init_rto_max;
1141a1cb341bSMichael Tuexen 	asoc->initial_rto = inp->sctp_ep.initial_rto;
1142f8829a4aSRandall Stewart 
114328a6addeSMichael Tuexen 	asoc->default_mtu = inp->sctp_ep.default_mtu;
1144a1cb341bSMichael Tuexen 	asoc->max_init_times = inp->sctp_ep.max_init_times;
1145a1cb341bSMichael Tuexen 	asoc->max_send_times = inp->sctp_ep.max_send_times;
1146a1cb341bSMichael Tuexen 	asoc->def_net_failure = inp->sctp_ep.def_net_failure;
1147a1cb341bSMichael Tuexen 	asoc->def_net_pf_threshold = inp->sctp_ep.def_net_pf_threshold;
1148f8829a4aSRandall Stewart 	asoc->free_chunk_cnt = 0;
1149f8829a4aSRandall Stewart 
1150f8829a4aSRandall Stewart 	asoc->iam_blocking = 0;
1151a1cb341bSMichael Tuexen 	asoc->context = inp->sctp_context;
1152a1cb341bSMichael Tuexen 	asoc->local_strreset_support = inp->local_strreset_support;
1153a1cb341bSMichael Tuexen 	asoc->def_send = inp->def_send;
1154a1cb341bSMichael Tuexen 	asoc->delayed_ack = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]);
1155a1cb341bSMichael Tuexen 	asoc->sack_freq = inp->sctp_ep.sctp_sack_freq;
1156f8829a4aSRandall Stewart 	asoc->pr_sctp_cnt = 0;
1157f8829a4aSRandall Stewart 	asoc->total_output_queue_size = 0;
1158f8829a4aSRandall Stewart 
1159a1cb341bSMichael Tuexen 	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
1160a1cb341bSMichael Tuexen 		asoc->scope.ipv6_addr_legal = 1;
1161a1cb341bSMichael Tuexen 		if (SCTP_IPV6_V6ONLY(inp) == 0) {
1162a1cb341bSMichael Tuexen 			asoc->scope.ipv4_addr_legal = 1;
1163f8829a4aSRandall Stewart 		} else {
1164a1cb341bSMichael Tuexen 			asoc->scope.ipv4_addr_legal = 0;
1165f8829a4aSRandall Stewart 		}
1166f8829a4aSRandall Stewart 	} else {
1167a1cb341bSMichael Tuexen 		asoc->scope.ipv6_addr_legal = 0;
1168a1cb341bSMichael Tuexen 		asoc->scope.ipv4_addr_legal = 1;
1169f8829a4aSRandall Stewart 	}
1170f8829a4aSRandall Stewart 
1171a1cb341bSMichael Tuexen 	asoc->my_rwnd = max(SCTP_SB_LIMIT_RCV(inp->sctp_socket), SCTP_MINIMAL_RWND);
1172a1cb341bSMichael Tuexen 	asoc->peers_rwnd = SCTP_SB_LIMIT_RCV(inp->sctp_socket);
1173f8829a4aSRandall Stewart 
1174a1cb341bSMichael Tuexen 	asoc->smallest_mtu = inp->sctp_frag_point;
1175a1cb341bSMichael Tuexen 	asoc->minrto = inp->sctp_ep.sctp_minrto;
1176a1cb341bSMichael Tuexen 	asoc->maxrto = inp->sctp_ep.sctp_maxrto;
1177f8829a4aSRandall Stewart 
1178f8829a4aSRandall Stewart 	asoc->stream_locked_on = 0;
1179f8829a4aSRandall Stewart 	asoc->ecn_echo_cnt_onq = 0;
1180f8829a4aSRandall Stewart 	asoc->stream_locked = 0;
1181f8829a4aSRandall Stewart 
118242551e99SRandall Stewart 	asoc->send_sack = 1;
118342551e99SRandall Stewart 
118442551e99SRandall Stewart 	LIST_INIT(&asoc->sctp_restricted_addrs);
118542551e99SRandall Stewart 
1186f8829a4aSRandall Stewart 	TAILQ_INIT(&asoc->nets);
1187f8829a4aSRandall Stewart 	TAILQ_INIT(&asoc->pending_reply_queue);
11882afb3e84SRandall Stewart 	TAILQ_INIT(&asoc->asconf_ack_sent);
1189f8829a4aSRandall Stewart 	/* Setup to fill the hb random cache at first HB */
1190f8829a4aSRandall Stewart 	asoc->hb_random_idx = 4;
1191f8829a4aSRandall Stewart 
1192a1cb341bSMichael Tuexen 	asoc->sctp_autoclose_ticks = inp->sctp_ep.auto_close_time;
1193f8829a4aSRandall Stewart 
1194a1cb341bSMichael Tuexen 	stcb->asoc.congestion_control_module = inp->sctp_ep.sctp_default_cc_module;
1195a1cb341bSMichael Tuexen 	stcb->asoc.cc_functions = sctp_cc_functions[inp->sctp_ep.sctp_default_cc_module];
1196b54d3a6cSRandall Stewart 
1197a1cb341bSMichael Tuexen 	stcb->asoc.stream_scheduling_module = inp->sctp_ep.sctp_default_ss_module;
1198a1cb341bSMichael Tuexen 	stcb->asoc.ss_functions = sctp_ss_functions[inp->sctp_ep.sctp_default_ss_module];
1199f7a77f6fSMichael Tuexen 
1200b54d3a6cSRandall Stewart 	/*
1201f8829a4aSRandall Stewart 	 * Now the stream parameters, here we allocate space for all streams
1202f8829a4aSRandall Stewart 	 * that we request by default.
1203f8829a4aSRandall Stewart 	 */
1204ea44232bSRandall Stewart 	asoc->strm_realoutsize = asoc->streamoutcnt = asoc->pre_open_streams =
1205c979034bSMichael Tuexen 	    o_strms;
1206f8829a4aSRandall Stewart 	SCTP_MALLOC(asoc->strmout, struct sctp_stream_out *,
1207f8829a4aSRandall Stewart 	    asoc->streamoutcnt * sizeof(struct sctp_stream_out),
1208207304d4SRandall Stewart 	    SCTP_M_STRMO);
1209f8829a4aSRandall Stewart 	if (asoc->strmout == NULL) {
1210f8829a4aSRandall Stewart 		/* big trouble no memory */
1211c4739e2fSRandall Stewart 		SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM);
1212f8829a4aSRandall Stewart 		return (ENOMEM);
1213f8829a4aSRandall Stewart 	}
1214f8829a4aSRandall Stewart 	for (i = 0; i < asoc->streamoutcnt; i++) {
1215f8829a4aSRandall Stewart 		/*
1216f8829a4aSRandall Stewart 		 * inbound side must be set to 0xffff, also NOTE when we get
1217f8829a4aSRandall Stewart 		 * the INIT-ACK back (for INIT sender) we MUST reduce the
1218f8829a4aSRandall Stewart 		 * count (streamoutcnt) but first check if we sent to any of
1219f8829a4aSRandall Stewart 		 * the upper streams that were dropped (if some were). Those
1220f8829a4aSRandall Stewart 		 * that were dropped must be notified to the upper layer as
1221f8829a4aSRandall Stewart 		 * failed to send.
1222f8829a4aSRandall Stewart 		 */
122363d5b568SMichael Tuexen 		asoc->strmout[i].next_mid_ordered = 0;
122463d5b568SMichael Tuexen 		asoc->strmout[i].next_mid_unordered = 0;
1225f8829a4aSRandall Stewart 		TAILQ_INIT(&asoc->strmout[i].outqueue);
1226325c8c46SMichael Tuexen 		asoc->strmout[i].chunks_on_queues = 0;
1227f0396ad1SMichael Tuexen #if defined(SCTP_DETAILED_STR_STATS)
1228f0396ad1SMichael Tuexen 		for (j = 0; j < SCTP_PR_SCTP_MAX + 1; j++) {
1229f0396ad1SMichael Tuexen 			asoc->strmout[i].abandoned_sent[j] = 0;
1230f0396ad1SMichael Tuexen 			asoc->strmout[i].abandoned_unsent[j] = 0;
1231f0396ad1SMichael Tuexen 		}
1232f0396ad1SMichael Tuexen #else
1233f0396ad1SMichael Tuexen 		asoc->strmout[i].abandoned_sent[0] = 0;
1234f0396ad1SMichael Tuexen 		asoc->strmout[i].abandoned_unsent[0] = 0;
1235f0396ad1SMichael Tuexen #endif
123649656eefSMichael Tuexen 		asoc->strmout[i].sid = i;
1237f8829a4aSRandall Stewart 		asoc->strmout[i].last_msg_incomplete = 0;
12387cca1775SRandall Stewart 		asoc->strmout[i].state = SCTP_STREAM_OPENING;
1239d1ea5fa9SMichael Tuexen 		asoc->ss_functions.sctp_ss_init_stream(stcb, &asoc->strmout[i], NULL);
1240f8829a4aSRandall Stewart 	}
1241f7a77f6fSMichael Tuexen 	asoc->ss_functions.sctp_ss_init(stcb, asoc, 0);
1242f7a77f6fSMichael Tuexen 
1243f8829a4aSRandall Stewart 	/* Now the mapping array */
1244f8829a4aSRandall Stewart 	asoc->mapping_array_size = SCTP_INITIAL_MAPPING_ARRAY;
1245f8829a4aSRandall Stewart 	SCTP_MALLOC(asoc->mapping_array, uint8_t *, asoc->mapping_array_size,
1246207304d4SRandall Stewart 	    SCTP_M_MAP);
1247f8829a4aSRandall Stewart 	if (asoc->mapping_array == NULL) {
1248207304d4SRandall Stewart 		SCTP_FREE(asoc->strmout, SCTP_M_STRMO);
1249c4739e2fSRandall Stewart 		SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM);
1250f8829a4aSRandall Stewart 		return (ENOMEM);
1251f8829a4aSRandall Stewart 	}
1252f8829a4aSRandall Stewart 	memset(asoc->mapping_array, 0, asoc->mapping_array_size);
1253b5c16493SMichael Tuexen 	SCTP_MALLOC(asoc->nr_mapping_array, uint8_t *, asoc->mapping_array_size,
1254830d754dSRandall Stewart 	    SCTP_M_MAP);
1255bf1be571SRandall Stewart 	if (asoc->nr_mapping_array == NULL) {
1256bf1be571SRandall Stewart 		SCTP_FREE(asoc->strmout, SCTP_M_STRMO);
1257bf1be571SRandall Stewart 		SCTP_FREE(asoc->mapping_array, SCTP_M_MAP);
1258bf1be571SRandall Stewart 		SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM);
1259bf1be571SRandall Stewart 		return (ENOMEM);
1260bf1be571SRandall Stewart 	}
1261b5c16493SMichael Tuexen 	memset(asoc->nr_mapping_array, 0, asoc->mapping_array_size);
1262830d754dSRandall Stewart 
1263f8829a4aSRandall Stewart 	/* Now the init of the other outqueues */
1264f8829a4aSRandall Stewart 	TAILQ_INIT(&asoc->free_chunks);
1265f8829a4aSRandall Stewart 	TAILQ_INIT(&asoc->control_send_queue);
1266c54a18d2SRandall Stewart 	TAILQ_INIT(&asoc->asconf_send_queue);
1267f8829a4aSRandall Stewart 	TAILQ_INIT(&asoc->send_queue);
1268f8829a4aSRandall Stewart 	TAILQ_INIT(&asoc->sent_queue);
1269f8829a4aSRandall Stewart 	TAILQ_INIT(&asoc->resetHead);
1270a1cb341bSMichael Tuexen 	asoc->max_inbound_streams = inp->sctp_ep.max_open_streams_intome;
1271f8829a4aSRandall Stewart 	TAILQ_INIT(&asoc->asconf_queue);
1272f8829a4aSRandall Stewart 	/* authentication fields */
1273f8829a4aSRandall Stewart 	asoc->authinfo.random = NULL;
1274830d754dSRandall Stewart 	asoc->authinfo.active_keyid = 0;
1275f8829a4aSRandall Stewart 	asoc->authinfo.assoc_key = NULL;
1276f8829a4aSRandall Stewart 	asoc->authinfo.assoc_keyid = 0;
1277f8829a4aSRandall Stewart 	asoc->authinfo.recv_key = NULL;
1278f8829a4aSRandall Stewart 	asoc->authinfo.recv_keyid = 0;
1279f8829a4aSRandall Stewart 	LIST_INIT(&asoc->shared_keys);
1280f42a358aSRandall Stewart 	asoc->marked_retrans = 0;
1281a1cb341bSMichael Tuexen 	asoc->port = inp->sctp_ep.port;
1282f42a358aSRandall Stewart 	asoc->timoinit = 0;
1283f42a358aSRandall Stewart 	asoc->timodata = 0;
1284f42a358aSRandall Stewart 	asoc->timosack = 0;
1285f42a358aSRandall Stewart 	asoc->timoshutdown = 0;
1286f42a358aSRandall Stewart 	asoc->timoheartbeat = 0;
1287f42a358aSRandall Stewart 	asoc->timocookie = 0;
1288f42a358aSRandall Stewart 	asoc->timoshutdownack = 0;
12896e55db54SRandall Stewart 	(void)SCTP_GETTIME_TIMEVAL(&asoc->start_time);
12906e55db54SRandall Stewart 	asoc->discontinuity_time = asoc->start_time;
1291f0396ad1SMichael Tuexen 	for (i = 0; i < SCTP_PR_SCTP_MAX + 1; i++) {
1292f0396ad1SMichael Tuexen 		asoc->abandoned_unsent[i] = 0;
1293f0396ad1SMichael Tuexen 		asoc->abandoned_sent[i] = 0;
1294f0396ad1SMichael Tuexen 	}
1295eacc51c5SRandall Stewart 	/*
1296eacc51c5SRandall Stewart 	 * sa_ignore MEMLEAK {memory is put in the assoc mapping array and
129777acdc25SRandall Stewart 	 * freed later when the association is freed.
1298eacc51c5SRandall Stewart 	 */
1299f8829a4aSRandall Stewart 	return (0);
1300f8829a4aSRandall Stewart }
1301f8829a4aSRandall Stewart 
13020e13104dSRandall Stewart void
13030e13104dSRandall Stewart sctp_print_mapping_array(struct sctp_association *asoc)
13040e13104dSRandall Stewart {
1305aed5947cSMichael Tuexen 	unsigned int i, limit;
13060e13104dSRandall Stewart 
1307cd3fd531SMichael Tuexen 	SCTP_PRINTF("Mapping array size: %d, baseTSN: %8.8x, cumAck: %8.8x, highestTSN: (%8.8x, %8.8x).\n",
13080e13104dSRandall Stewart 	    asoc->mapping_array_size,
13090e13104dSRandall Stewart 	    asoc->mapping_array_base_tsn,
13100e13104dSRandall Stewart 	    asoc->cumulative_tsn,
1311aed5947cSMichael Tuexen 	    asoc->highest_tsn_inside_map,
1312aed5947cSMichael Tuexen 	    asoc->highest_tsn_inside_nr_map);
1313aed5947cSMichael Tuexen 	for (limit = asoc->mapping_array_size; limit > 1; limit--) {
131460990c0cSMichael Tuexen 		if (asoc->mapping_array[limit - 1] != 0) {
131577acdc25SRandall Stewart 			break;
131677acdc25SRandall Stewart 		}
131777acdc25SRandall Stewart 	}
1318cd3fd531SMichael Tuexen 	SCTP_PRINTF("Renegable mapping array (last %d entries are zero):\n", asoc->mapping_array_size - limit);
131977acdc25SRandall Stewart 	for (i = 0; i < limit; i++) {
1320cd3fd531SMichael Tuexen 		SCTP_PRINTF("%2.2x%c", asoc->mapping_array[i], ((i + 1) % 16) ? ' ' : '\n');
132177acdc25SRandall Stewart 	}
1322aed5947cSMichael Tuexen 	if (limit % 16)
1323cd3fd531SMichael Tuexen 		SCTP_PRINTF("\n");
1324aed5947cSMichael Tuexen 	for (limit = asoc->mapping_array_size; limit > 1; limit--) {
1325aed5947cSMichael Tuexen 		if (asoc->nr_mapping_array[limit - 1]) {
132677acdc25SRandall Stewart 			break;
132777acdc25SRandall Stewart 		}
132877acdc25SRandall Stewart 	}
1329cd3fd531SMichael Tuexen 	SCTP_PRINTF("Non renegable mapping array (last %d entries are zero):\n", asoc->mapping_array_size - limit);
133077acdc25SRandall Stewart 	for (i = 0; i < limit; i++) {
1331cd3fd531SMichael Tuexen 		SCTP_PRINTF("%2.2x%c", asoc->nr_mapping_array[i], ((i + 1) % 16) ? ' ' : '\n');
13320e13104dSRandall Stewart 	}
1333aed5947cSMichael Tuexen 	if (limit % 16)
1334cd3fd531SMichael Tuexen 		SCTP_PRINTF("\n");
13350e13104dSRandall Stewart }
13360e13104dSRandall Stewart 
1337f8829a4aSRandall Stewart int
13380696e120SRandall Stewart sctp_expand_mapping_array(struct sctp_association *asoc, uint32_t needed)
1339f8829a4aSRandall Stewart {
1340f8829a4aSRandall Stewart 	/* mapping array needs to grow */
1341b5c16493SMichael Tuexen 	uint8_t *new_array1, *new_array2;
13420696e120SRandall Stewart 	uint32_t new_size;
1343f8829a4aSRandall Stewart 
13440696e120SRandall Stewart 	new_size = asoc->mapping_array_size + ((needed + 7) / 8 + SCTP_MAPPING_ARRAY_INCR);
1345b5c16493SMichael Tuexen 	SCTP_MALLOC(new_array1, uint8_t *, new_size, SCTP_M_MAP);
1346b5c16493SMichael Tuexen 	SCTP_MALLOC(new_array2, uint8_t *, new_size, SCTP_M_MAP);
1347b5c16493SMichael Tuexen 	if ((new_array1 == NULL) || (new_array2 == NULL)) {
1348f8829a4aSRandall Stewart 		/* can't get more, forget it */
1349b5c16493SMichael Tuexen 		SCTP_PRINTF("No memory for expansion of SCTP mapping array %d\n", new_size);
1350b5c16493SMichael Tuexen 		if (new_array1) {
1351b5c16493SMichael Tuexen 			SCTP_FREE(new_array1, SCTP_M_MAP);
1352b5c16493SMichael Tuexen 		}
1353b5c16493SMichael Tuexen 		if (new_array2) {
1354b5c16493SMichael Tuexen 			SCTP_FREE(new_array2, SCTP_M_MAP);
1355b5c16493SMichael Tuexen 		}
1356f8829a4aSRandall Stewart 		return (-1);
1357f8829a4aSRandall Stewart 	}
1358b5c16493SMichael Tuexen 	memset(new_array1, 0, new_size);
1359b5c16493SMichael Tuexen 	memset(new_array2, 0, new_size);
1360b5c16493SMichael Tuexen 	memcpy(new_array1, asoc->mapping_array, asoc->mapping_array_size);
1361b5c16493SMichael Tuexen 	memcpy(new_array2, asoc->nr_mapping_array, asoc->mapping_array_size);
1362207304d4SRandall Stewart 	SCTP_FREE(asoc->mapping_array, SCTP_M_MAP);
1363830d754dSRandall Stewart 	SCTP_FREE(asoc->nr_mapping_array, SCTP_M_MAP);
1364b5c16493SMichael Tuexen 	asoc->mapping_array = new_array1;
1365b5c16493SMichael Tuexen 	asoc->nr_mapping_array = new_array2;
1366b5c16493SMichael Tuexen 	asoc->mapping_array_size = new_size;
1367830d754dSRandall Stewart 	return (0);
1368830d754dSRandall Stewart }
1369830d754dSRandall Stewart 
13708933fa13SRandall Stewart 
137142551e99SRandall Stewart static void
137242551e99SRandall Stewart sctp_iterator_work(struct sctp_iterator *it)
137342551e99SRandall Stewart {
1374868b51f2SMichael Tuexen 	struct epoch_tracker et;
1375868b51f2SMichael Tuexen 	struct sctp_inpcb *tinp;
137642551e99SRandall Stewart 	int iteration_count = 0;
137742551e99SRandall Stewart 	int inp_skip = 0;
1378ec4c19fcSRandall Stewart 	int first_in = 1;
137942551e99SRandall Stewart 
1380868b51f2SMichael Tuexen 	NET_EPOCH_ENTER(et);
1381ec4c19fcSRandall Stewart 	SCTP_INP_INFO_RLOCK();
138242551e99SRandall Stewart 	SCTP_ITERATOR_LOCK();
1383dcb436c9SMichael Tuexen 	sctp_it_ctl.cur_it = it;
1384ad81507eSRandall Stewart 	if (it->inp) {
1385ec4c19fcSRandall Stewart 		SCTP_INP_RLOCK(it->inp);
138642551e99SRandall Stewart 		SCTP_INP_DECR_REF(it->inp);
1387ad81507eSRandall Stewart 	}
138842551e99SRandall Stewart 	if (it->inp == NULL) {
138942551e99SRandall Stewart 		/* iterator is complete */
139042551e99SRandall Stewart done_with_iterator:
1391dcb436c9SMichael Tuexen 		sctp_it_ctl.cur_it = NULL;
139242551e99SRandall Stewart 		SCTP_ITERATOR_UNLOCK();
1393ec4c19fcSRandall Stewart 		SCTP_INP_INFO_RUNLOCK();
139442551e99SRandall Stewart 		if (it->function_atend != NULL) {
139542551e99SRandall Stewart 			(*it->function_atend) (it->pointer, it->val);
139642551e99SRandall Stewart 		}
1397207304d4SRandall Stewart 		SCTP_FREE(it, SCTP_M_ITER);
1398868b51f2SMichael Tuexen 		NET_EPOCH_EXIT(et);
139942551e99SRandall Stewart 		return;
140042551e99SRandall Stewart 	}
140142551e99SRandall Stewart select_a_new_ep:
1402ec4c19fcSRandall Stewart 	if (first_in) {
1403ec4c19fcSRandall Stewart 		first_in = 0;
1404ec4c19fcSRandall Stewart 	} else {
1405f7517433SRandall Stewart 		SCTP_INP_RLOCK(it->inp);
1406ec4c19fcSRandall Stewart 	}
140742551e99SRandall Stewart 	while (((it->pcb_flags) &&
140842551e99SRandall Stewart 	    ((it->inp->sctp_flags & it->pcb_flags) != it->pcb_flags)) ||
140942551e99SRandall Stewart 	    ((it->pcb_features) &&
141042551e99SRandall Stewart 	    ((it->inp->sctp_features & it->pcb_features) != it->pcb_features))) {
141142551e99SRandall Stewart 		/* endpoint flags or features don't match, so keep looking */
141242551e99SRandall Stewart 		if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) {
1413f7517433SRandall Stewart 			SCTP_INP_RUNLOCK(it->inp);
141442551e99SRandall Stewart 			goto done_with_iterator;
141542551e99SRandall Stewart 		}
1416ec4c19fcSRandall Stewart 		tinp = it->inp;
141742551e99SRandall Stewart 		it->inp = LIST_NEXT(it->inp, sctp_list);
1418ec4c19fcSRandall Stewart 		SCTP_INP_RUNLOCK(tinp);
141942551e99SRandall Stewart 		if (it->inp == NULL) {
142042551e99SRandall Stewart 			goto done_with_iterator;
142142551e99SRandall Stewart 		}
142242551e99SRandall Stewart 		SCTP_INP_RLOCK(it->inp);
1423f7517433SRandall Stewart 	}
142442551e99SRandall Stewart 	/* now go through each assoc which is in the desired state */
142542551e99SRandall Stewart 	if (it->done_current_ep == 0) {
142642551e99SRandall Stewart 		if (it->function_inp != NULL)
142742551e99SRandall Stewart 			inp_skip = (*it->function_inp) (it->inp, it->pointer, it->val);
142842551e99SRandall Stewart 		it->done_current_ep = 1;
142942551e99SRandall Stewart 	}
143042551e99SRandall Stewart 	if (it->stcb == NULL) {
143142551e99SRandall Stewart 		/* run the per instance function */
143242551e99SRandall Stewart 		it->stcb = LIST_FIRST(&it->inp->sctp_asoc_list);
143342551e99SRandall Stewart 	}
143442551e99SRandall Stewart 	if ((inp_skip) || it->stcb == NULL) {
143542551e99SRandall Stewart 		if (it->function_inp_end != NULL) {
143642551e99SRandall Stewart 			inp_skip = (*it->function_inp_end) (it->inp,
143742551e99SRandall Stewart 			    it->pointer,
143842551e99SRandall Stewart 			    it->val);
143942551e99SRandall Stewart 		}
144042551e99SRandall Stewart 		SCTP_INP_RUNLOCK(it->inp);
144142551e99SRandall Stewart 		goto no_stcb;
144242551e99SRandall Stewart 	}
144342551e99SRandall Stewart 	while (it->stcb) {
144442551e99SRandall Stewart 		SCTP_TCB_LOCK(it->stcb);
144542551e99SRandall Stewart 		if (it->asoc_state && ((it->stcb->asoc.state & it->asoc_state) != it->asoc_state)) {
144642551e99SRandall Stewart 			/* not in the right state... keep looking */
144742551e99SRandall Stewart 			SCTP_TCB_UNLOCK(it->stcb);
144842551e99SRandall Stewart 			goto next_assoc;
144942551e99SRandall Stewart 		}
145042551e99SRandall Stewart 		/* see if we have limited out the iterator loop */
145142551e99SRandall Stewart 		iteration_count++;
145242551e99SRandall Stewart 		if (iteration_count > SCTP_ITERATOR_MAX_AT_ONCE) {
145342551e99SRandall Stewart 			/* Pause to let others grab the lock */
145442551e99SRandall Stewart 			atomic_add_int(&it->stcb->asoc.refcnt, 1);
145542551e99SRandall Stewart 			SCTP_TCB_UNLOCK(it->stcb);
1456c4739e2fSRandall Stewart 			SCTP_INP_INCR_REF(it->inp);
145742551e99SRandall Stewart 			SCTP_INP_RUNLOCK(it->inp);
145842551e99SRandall Stewart 			SCTP_ITERATOR_UNLOCK();
1459ec4c19fcSRandall Stewart 			SCTP_INP_INFO_RUNLOCK();
1460ec4c19fcSRandall Stewart 			SCTP_INP_INFO_RLOCK();
146142551e99SRandall Stewart 			SCTP_ITERATOR_LOCK();
1462f7517433SRandall Stewart 			if (sctp_it_ctl.iterator_flags) {
1463f7517433SRandall Stewart 				/* We won't be staying here */
1464f7517433SRandall Stewart 				SCTP_INP_DECR_REF(it->inp);
1465f7517433SRandall Stewart 				atomic_add_int(&it->stcb->asoc.refcnt, -1);
1466f7517433SRandall Stewart 				if (sctp_it_ctl.iterator_flags &
1467f7517433SRandall Stewart 				    SCTP_ITERATOR_STOP_CUR_IT) {
1468f7517433SRandall Stewart 					sctp_it_ctl.iterator_flags &= ~SCTP_ITERATOR_STOP_CUR_IT;
1469f7517433SRandall Stewart 					goto done_with_iterator;
1470f7517433SRandall Stewart 				}
1471f7517433SRandall Stewart 				if (sctp_it_ctl.iterator_flags &
1472f7517433SRandall Stewart 				    SCTP_ITERATOR_STOP_CUR_INP) {
1473f7517433SRandall Stewart 					sctp_it_ctl.iterator_flags &= ~SCTP_ITERATOR_STOP_CUR_INP;
1474f7517433SRandall Stewart 					goto no_stcb;
1475f7517433SRandall Stewart 				}
1476f7517433SRandall Stewart 				/* If we reach here huh? */
1477cd3fd531SMichael Tuexen 				SCTP_PRINTF("Unknown it ctl flag %x\n",
1478f7517433SRandall Stewart 				    sctp_it_ctl.iterator_flags);
1479f7517433SRandall Stewart 				sctp_it_ctl.iterator_flags = 0;
1480f7517433SRandall Stewart 			}
148142551e99SRandall Stewart 			SCTP_INP_RLOCK(it->inp);
1482c4739e2fSRandall Stewart 			SCTP_INP_DECR_REF(it->inp);
148342551e99SRandall Stewart 			SCTP_TCB_LOCK(it->stcb);
148442551e99SRandall Stewart 			atomic_add_int(&it->stcb->asoc.refcnt, -1);
148542551e99SRandall Stewart 			iteration_count = 0;
148642551e99SRandall Stewart 		}
14870053ed28SMichael Tuexen 
148842551e99SRandall Stewart 		/* run function on this one */
148942551e99SRandall Stewart 		(*it->function_assoc) (it->inp, it->stcb, it->pointer, it->val);
149042551e99SRandall Stewart 
149142551e99SRandall Stewart 		/*
149242551e99SRandall Stewart 		 * we lie here, it really needs to have its own type but
149342551e99SRandall Stewart 		 * first I must verify that this won't effect things :-0
149442551e99SRandall Stewart 		 */
149542551e99SRandall Stewart 		if (it->no_chunk_output == 0)
1496ceaad40aSRandall Stewart 			sctp_chunk_output(it->inp, it->stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
149742551e99SRandall Stewart 
149842551e99SRandall Stewart 		SCTP_TCB_UNLOCK(it->stcb);
149942551e99SRandall Stewart next_assoc:
150042551e99SRandall Stewart 		it->stcb = LIST_NEXT(it->stcb, sctp_tcblist);
150142551e99SRandall Stewart 		if (it->stcb == NULL) {
150242551e99SRandall Stewart 			/* Run last function */
150342551e99SRandall Stewart 			if (it->function_inp_end != NULL) {
150442551e99SRandall Stewart 				inp_skip = (*it->function_inp_end) (it->inp,
150542551e99SRandall Stewart 				    it->pointer,
150642551e99SRandall Stewart 				    it->val);
150742551e99SRandall Stewart 			}
150842551e99SRandall Stewart 		}
150942551e99SRandall Stewart 	}
151042551e99SRandall Stewart 	SCTP_INP_RUNLOCK(it->inp);
151142551e99SRandall Stewart no_stcb:
151242551e99SRandall Stewart 	/* done with all assocs on this endpoint, move on to next endpoint */
151342551e99SRandall Stewart 	it->done_current_ep = 0;
151442551e99SRandall Stewart 	if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) {
151542551e99SRandall Stewart 		it->inp = NULL;
151642551e99SRandall Stewart 	} else {
151742551e99SRandall Stewart 		it->inp = LIST_NEXT(it->inp, sctp_list);
151842551e99SRandall Stewart 	}
151942551e99SRandall Stewart 	if (it->inp == NULL) {
152042551e99SRandall Stewart 		goto done_with_iterator;
152142551e99SRandall Stewart 	}
152242551e99SRandall Stewart 	goto select_a_new_ep;
152342551e99SRandall Stewart }
152442551e99SRandall Stewart 
152542551e99SRandall Stewart void
152642551e99SRandall Stewart sctp_iterator_worker(void)
152742551e99SRandall Stewart {
1528397b1c94SMichael Tuexen 	struct sctp_iterator *it;
152942551e99SRandall Stewart 
153042551e99SRandall Stewart 	/* This function is called with the WQ lock in place */
1531f7517433SRandall Stewart 	sctp_it_ctl.iterator_running = 1;
1532397b1c94SMichael Tuexen 	while ((it = TAILQ_FIRST(&sctp_it_ctl.iteratorhead)) != NULL) {
153342551e99SRandall Stewart 		/* now lets work on this one */
1534f7517433SRandall Stewart 		TAILQ_REMOVE(&sctp_it_ctl.iteratorhead, it, sctp_nxt_itr);
153542551e99SRandall Stewart 		SCTP_IPI_ITERATOR_WQ_UNLOCK();
1536f7517433SRandall Stewart 		CURVNET_SET(it->vn);
153742551e99SRandall Stewart 		sctp_iterator_work(it);
1538f7517433SRandall Stewart 		CURVNET_RESTORE();
153942551e99SRandall Stewart 		SCTP_IPI_ITERATOR_WQ_LOCK();
15403c503c28SRandall Stewart 		/* sa_ignore FREED_MEMORY */
154142551e99SRandall Stewart 	}
1542f7517433SRandall Stewart 	sctp_it_ctl.iterator_running = 0;
154342551e99SRandall Stewart 	return;
154442551e99SRandall Stewart }
154542551e99SRandall Stewart 
1546f8829a4aSRandall Stewart 
1547f8829a4aSRandall Stewart static void
1548f8829a4aSRandall Stewart sctp_handle_addr_wq(void)
1549f8829a4aSRandall Stewart {
1550f8829a4aSRandall Stewart 	/* deal with the ADDR wq from the rtsock calls */
15514a9ef3f8SMichael Tuexen 	struct sctp_laddr *wi, *nwi;
155242551e99SRandall Stewart 	struct sctp_asconf_iterator *asc;
1553f8829a4aSRandall Stewart 
155442551e99SRandall Stewart 	SCTP_MALLOC(asc, struct sctp_asconf_iterator *,
1555207304d4SRandall Stewart 	    sizeof(struct sctp_asconf_iterator), SCTP_M_ASC_IT);
155642551e99SRandall Stewart 	if (asc == NULL) {
155742551e99SRandall Stewart 		/* Try later, no memory */
1558f8829a4aSRandall Stewart 		sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ,
1559f8829a4aSRandall Stewart 		    (struct sctp_inpcb *)NULL,
1560f8829a4aSRandall Stewart 		    (struct sctp_tcb *)NULL,
1561f8829a4aSRandall Stewart 		    (struct sctp_nets *)NULL);
156242551e99SRandall Stewart 		return;
1563f8829a4aSRandall Stewart 	}
156442551e99SRandall Stewart 	LIST_INIT(&asc->list_of_work);
156542551e99SRandall Stewart 	asc->cnt = 0;
1566f7517433SRandall Stewart 
15674a9ef3f8SMichael Tuexen 	LIST_FOREACH_SAFE(wi, &SCTP_BASE_INFO(addr_wq), sctp_nxt_addr, nwi) {
156842551e99SRandall Stewart 		LIST_REMOVE(wi, sctp_nxt_addr);
156942551e99SRandall Stewart 		LIST_INSERT_HEAD(&asc->list_of_work, wi, sctp_nxt_addr);
157042551e99SRandall Stewart 		asc->cnt++;
1571f8829a4aSRandall Stewart 	}
1572f7517433SRandall Stewart 
157342551e99SRandall Stewart 	if (asc->cnt == 0) {
1574207304d4SRandall Stewart 		SCTP_FREE(asc, SCTP_M_ASC_IT);
157542551e99SRandall Stewart 	} else {
15762b1c7de4SMichael Tuexen 		int ret;
15772b1c7de4SMichael Tuexen 
15782b1c7de4SMichael Tuexen 		ret = sctp_initiate_iterator(sctp_asconf_iterator_ep,
15791b649582SRandall Stewart 		    sctp_asconf_iterator_stcb,
158042551e99SRandall Stewart 		    NULL,	/* No ep end for boundall */
158142551e99SRandall Stewart 		    SCTP_PCB_FLAGS_BOUNDALL,
158242551e99SRandall Stewart 		    SCTP_PCB_ANY_FEATURES,
15831b649582SRandall Stewart 		    SCTP_ASOC_ANY_STATE,
15841b649582SRandall Stewart 		    (void *)asc, 0,
15851b649582SRandall Stewart 		    sctp_asconf_iterator_end, NULL, 0);
15862b1c7de4SMichael Tuexen 		if (ret) {
15872b1c7de4SMichael Tuexen 			SCTP_PRINTF("Failed to initiate iterator for handle_addr_wq\n");
1588b7b84c0eSMichael Tuexen 			/*
1589b7b84c0eSMichael Tuexen 			 * Freeing if we are stopping or put back on the
1590b7b84c0eSMichael Tuexen 			 * addr_wq.
1591b7b84c0eSMichael Tuexen 			 */
15922b1c7de4SMichael Tuexen 			if (SCTP_BASE_VAR(sctp_pcb_initialized) == 0) {
15932b1c7de4SMichael Tuexen 				sctp_asconf_iterator_end(asc, 0);
15942b1c7de4SMichael Tuexen 			} else {
15952b1c7de4SMichael Tuexen 				LIST_FOREACH(wi, &asc->list_of_work, sctp_nxt_addr) {
15962b1c7de4SMichael Tuexen 					LIST_INSERT_HEAD(&SCTP_BASE_INFO(addr_wq), wi, sctp_nxt_addr);
15972b1c7de4SMichael Tuexen 				}
15982b1c7de4SMichael Tuexen 				SCTP_FREE(asc, SCTP_M_ASC_IT);
15992b1c7de4SMichael Tuexen 			}
16002b1c7de4SMichael Tuexen 		}
160142551e99SRandall Stewart 	}
1602f8829a4aSRandall Stewart }
1603f8829a4aSRandall Stewart 
1604*a412576eSMichael Tuexen /*-
1605*a412576eSMichael Tuexen  * The following table shows which pointers for the inp, stcb, or net are
1606*a412576eSMichael Tuexen  * stored for each timer after it was started.
1607*a412576eSMichael Tuexen  *
1608*a412576eSMichael Tuexen  *|Name                         |Timer                        |inp |stcb|net |
1609*a412576eSMichael Tuexen  *|-----------------------------|-----------------------------|----|----|----|
1610*a412576eSMichael Tuexen  *|SCTP_TIMER_TYPE_SEND         |net->rxt_timer               |Yes |Yes |Yes |
1611*a412576eSMichael Tuexen  *|SCTP_TIMER_TYPE_INIT         |net->rxt_timer               |Yes |Yes |Yes |
1612*a412576eSMichael Tuexen  *|SCTP_TIMER_TYPE_RECV         |stcb->asoc.dack_timer        |Yes |Yes |No  |
1613*a412576eSMichael Tuexen  *|SCTP_TIMER_TYPE_SHUTDOWN     |net->rxt_timer               |Yes |Yes |Yes |
1614*a412576eSMichael Tuexen  *|SCTP_TIMER_TYPE_HEARTBEAT    |net->hb_timer                |Yes |Yes |Yes |
1615*a412576eSMichael Tuexen  *|SCTP_TIMER_TYPE_COOKIE       |net->rxt_timer               |Yes |Yes |Yes |
1616*a412576eSMichael Tuexen  *|SCTP_TIMER_TYPE_NEWCOOKIE    |inp->sctp_ep.signature_change|Yes |No  |No  |
1617*a412576eSMichael Tuexen  *|SCTP_TIMER_TYPE_PATHMTURAISE |net->pmtu_timer              |Yes |Yes |Yes |
1618*a412576eSMichael Tuexen  *|SCTP_TIMER_TYPE_SHUTDOWNACK  |net->rxt_timer               |Yes |Yes |Yes |
1619*a412576eSMichael Tuexen  *|SCTP_TIMER_TYPE_ASCONF       |stcb->asoc.asconf_timer      |Yes |Yes |Yes |
1620*a412576eSMichael Tuexen  *|SCTP_TIMER_TYPE_SHUTDOWNGUARD|stcb->asoc.shut_guard_timer  |Yes |Yes |No  |
1621*a412576eSMichael Tuexen  *|SCTP_TIMER_TYPE_AUTOCLOSE    |stcb->asoc.autoclose_timer   |Yes |Yes |No  |
1622*a412576eSMichael Tuexen  *|SCTP_TIMER_TYPE_STRRESET     |stcb->asoc.strreset_timer    |Yes |Yes |No  |
1623*a412576eSMichael Tuexen  *|SCTP_TIMER_TYPE_INPKILL      |inp->sctp_ep.signature_change|Yes |No  |No  |
1624*a412576eSMichael Tuexen  *|SCTP_TIMER_TYPE_ASOCKILL     |stcb->asoc.strreset_timer    |Yes |Yes |No  |
1625*a412576eSMichael Tuexen  *|SCTP_TIMER_TYPE_ADDR_WQ      |SCTP_BASE_INFO(addr_wq_timer)|No  |No  |No  |
1626*a412576eSMichael Tuexen  *|SCTP_TIMER_TYPE_PRIM_DELETED |stcb->asoc.delete_prim_timer |Yes |Yes |No  |
1627*a412576eSMichael Tuexen  */
1628*a412576eSMichael Tuexen 
1629f8829a4aSRandall Stewart void
1630f8829a4aSRandall Stewart sctp_timeout_handler(void *t)
1631f8829a4aSRandall Stewart {
1632868b51f2SMichael Tuexen 	struct epoch_tracker et;
1633*a412576eSMichael Tuexen 	struct timeval tv;
1634f8829a4aSRandall Stewart 	struct sctp_inpcb *inp;
1635f8829a4aSRandall Stewart 	struct sctp_tcb *stcb;
1636f8829a4aSRandall Stewart 	struct sctp_nets *net;
1637f8829a4aSRandall Stewart 	struct sctp_timer *tmr;
1638267dbe63SMichael Tuexen 	struct mbuf *op_err;
1639ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
1640ceaad40aSRandall Stewart 	struct socket *so;
1641ceaad40aSRandall Stewart #endif
1642548f47a8SMichael Tuexen 	int did_output;
1643fa89f692SMichael Tuexen 	int type;
1644*a412576eSMichael Tuexen 	int i, secret;
1645f8829a4aSRandall Stewart 
1646f8829a4aSRandall Stewart 	tmr = (struct sctp_timer *)t;
1647f8829a4aSRandall Stewart 	inp = (struct sctp_inpcb *)tmr->ep;
1648f8829a4aSRandall Stewart 	stcb = (struct sctp_tcb *)tmr->tcb;
1649f8829a4aSRandall Stewart 	net = (struct sctp_nets *)tmr->net;
16508518270eSMichael Tuexen 	CURVNET_SET((struct vnet *)tmr->vnet);
1651f8829a4aSRandall Stewart 	did_output = 1;
1652f8829a4aSRandall Stewart 
1653f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED
1654f8829a4aSRandall Stewart 	sctp_audit_log(0xF0, (uint8_t)tmr->type);
1655f8829a4aSRandall Stewart 	sctp_auditing(3, inp, stcb, net);
1656f8829a4aSRandall Stewart #endif
1657f8829a4aSRandall Stewart 
1658f8829a4aSRandall Stewart 	/* sanity checks... */
1659*a412576eSMichael Tuexen 	KASSERT(tmr->self == tmr, ("tmr->self corrupted"));
1660*a412576eSMichael Tuexen 	KASSERT(SCTP_IS_TIMER_TYPE_VALID(tmr->type), ("Invalid timer type %d", tmr->type));
1661*a412576eSMichael Tuexen 	type = tmr->type;
1662a5d547adSRandall Stewart 	tmr->stopped_from = 0xa001;
1663f8829a4aSRandall Stewart 	if (inp) {
1664f8829a4aSRandall Stewart 		SCTP_INP_INCR_REF(inp);
1665aa1808b7SMichael Tuexen 		if ((inp->sctp_socket == NULL) &&
1666*a412576eSMichael Tuexen 		    ((type != SCTP_TIMER_TYPE_INPKILL) &&
1667*a412576eSMichael Tuexen 		    (type != SCTP_TIMER_TYPE_INIT) &&
1668*a412576eSMichael Tuexen 		    (type != SCTP_TIMER_TYPE_SEND) &&
1669*a412576eSMichael Tuexen 		    (type != SCTP_TIMER_TYPE_RECV) &&
1670*a412576eSMichael Tuexen 		    (type != SCTP_TIMER_TYPE_HEARTBEAT) &&
1671*a412576eSMichael Tuexen 		    (type != SCTP_TIMER_TYPE_SHUTDOWN) &&
1672*a412576eSMichael Tuexen 		    (type != SCTP_TIMER_TYPE_SHUTDOWNACK) &&
1673*a412576eSMichael Tuexen 		    (type != SCTP_TIMER_TYPE_SHUTDOWNGUARD) &&
1674*a412576eSMichael Tuexen 		    (type != SCTP_TIMER_TYPE_ASOCKILL))) {
1675f8829a4aSRandall Stewart 			SCTP_INP_DECR_REF(inp);
16768518270eSMichael Tuexen 			CURVNET_RESTORE();
1677*a412576eSMichael Tuexen 			SCTPDBG(SCTP_DEBUG_TIMER2,
1678*a412576eSMichael Tuexen 			    "Timer type = %d handler exiting due to closed socket\n",
1679*a412576eSMichael Tuexen 			    type);
1680f8829a4aSRandall Stewart 			return;
1681f8829a4aSRandall Stewart 		}
1682f8829a4aSRandall Stewart 	}
1683*a412576eSMichael Tuexen 	tmr->stopped_from = 0xa002;
1684f8829a4aSRandall Stewart 	if (stcb) {
1685c105859eSRandall Stewart 		atomic_add_int(&stcb->asoc.refcnt, 1);
1686f8829a4aSRandall Stewart 		if (stcb->asoc.state == 0) {
1687c105859eSRandall Stewart 			atomic_add_int(&stcb->asoc.refcnt, -1);
1688f8829a4aSRandall Stewart 			if (inp) {
1689f8829a4aSRandall Stewart 				SCTP_INP_DECR_REF(inp);
1690f8829a4aSRandall Stewart 			}
16918518270eSMichael Tuexen 			CURVNET_RESTORE();
1692*a412576eSMichael Tuexen 			SCTPDBG(SCTP_DEBUG_TIMER2,
1693*a412576eSMichael Tuexen 			    "Timer type = %d handler exiting due to CLOSED association\n",
1694*a412576eSMichael Tuexen 			    type);
1695f8829a4aSRandall Stewart 			return;
1696f8829a4aSRandall Stewart 		}
1697f8829a4aSRandall Stewart 	}
1698*a412576eSMichael Tuexen 	tmr->stopped_from = 0xa003;
1699fa89f692SMichael Tuexen 	SCTPDBG(SCTP_DEBUG_TIMER1, "Timer type %d goes off\n", type);
1700139bc87fSRandall Stewart 	if (!SCTP_OS_TIMER_ACTIVE(&tmr->timer)) {
1701f8829a4aSRandall Stewart 		if (inp) {
1702f8829a4aSRandall Stewart 			SCTP_INP_DECR_REF(inp);
1703f8829a4aSRandall Stewart 		}
1704207304d4SRandall Stewart 		if (stcb) {
1705207304d4SRandall Stewart 			atomic_add_int(&stcb->asoc.refcnt, -1);
1706207304d4SRandall Stewart 		}
17078518270eSMichael Tuexen 		CURVNET_RESTORE();
1708*a412576eSMichael Tuexen 		SCTPDBG(SCTP_DEBUG_TIMER2,
1709*a412576eSMichael Tuexen 		    "Timer type = %d handler exiting due to not being active\n",
1710*a412576eSMichael Tuexen 		    type);
1711f8829a4aSRandall Stewart 		return;
1712f8829a4aSRandall Stewart 	}
1713*a412576eSMichael Tuexen 	tmr->stopped_from = 0xa004;
1714a5d547adSRandall Stewart 
1715f8829a4aSRandall Stewart 	if (stcb) {
1716f8829a4aSRandall Stewart 		SCTP_TCB_LOCK(stcb);
171750cec919SRandall Stewart 		atomic_add_int(&stcb->asoc.refcnt, -1);
1718fa89f692SMichael Tuexen 		if ((type != SCTP_TIMER_TYPE_ASOCKILL) &&
1719b54d3a6cSRandall Stewart 		    ((stcb->asoc.state == 0) ||
1720b54d3a6cSRandall Stewart 		    (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED))) {
1721b54d3a6cSRandall Stewart 			SCTP_TCB_UNLOCK(stcb);
1722b54d3a6cSRandall Stewart 			if (inp) {
1723b54d3a6cSRandall Stewart 				SCTP_INP_DECR_REF(inp);
1724b54d3a6cSRandall Stewart 			}
17258518270eSMichael Tuexen 			CURVNET_RESTORE();
1726*a412576eSMichael Tuexen 			SCTPDBG(SCTP_DEBUG_TIMER2,
1727*a412576eSMichael Tuexen 			    "Timer type = %d handler exiting due to CLOSED association\n",
1728*a412576eSMichael Tuexen 			    type);
1729b54d3a6cSRandall Stewart 			return;
1730b54d3a6cSRandall Stewart 		}
17312c62ba73SMichael Tuexen 	} else if (inp != NULL) {
17322c62ba73SMichael Tuexen 		SCTP_INP_WLOCK(inp);
17332c62ba73SMichael Tuexen 	} else {
17342c62ba73SMichael Tuexen 		SCTP_WQ_ADDR_LOCK();
1735f8829a4aSRandall Stewart 	}
1736cd0a4ff6SPedro F. Giffuni 	/* record in stopped what t-o occurred */
1737fa89f692SMichael Tuexen 	tmr->stopped_from = type;
173844b7479bSRandall Stewart 
1739868b51f2SMichael Tuexen 	NET_EPOCH_ENTER(et);
1740f8829a4aSRandall Stewart 	/* mark as being serviced now */
174144b7479bSRandall Stewart 	if (SCTP_OS_TIMER_PENDING(&tmr->timer)) {
174244b7479bSRandall Stewart 		/*
174344b7479bSRandall Stewart 		 * Callout has been rescheduled.
174444b7479bSRandall Stewart 		 */
174544b7479bSRandall Stewart 		goto get_out;
174644b7479bSRandall Stewart 	}
174744b7479bSRandall Stewart 	if (!SCTP_OS_TIMER_ACTIVE(&tmr->timer)) {
174844b7479bSRandall Stewart 		/*
174944b7479bSRandall Stewart 		 * Not active, so no action.
175044b7479bSRandall Stewart 		 */
175144b7479bSRandall Stewart 		goto get_out;
175244b7479bSRandall Stewart 	}
1753139bc87fSRandall Stewart 	SCTP_OS_TIMER_DEACTIVATE(&tmr->timer);
1754f8829a4aSRandall Stewart 
1755f8829a4aSRandall Stewart 	/* call the handler for the appropriate timer type */
1756fa89f692SMichael Tuexen 	switch (type) {
1757f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_SEND:
1758*a412576eSMichael Tuexen 		KASSERT(inp != NULL && stcb != NULL && net != NULL,
1759*a412576eSMichael Tuexen 		    ("timeout of type %d: inp = %p, stcb = %p, net = %p",
1760*a412576eSMichael Tuexen 		    type, inp, stcb, net));
1761f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_timodata);
1762f42a358aSRandall Stewart 		stcb->asoc.timodata++;
1763f8829a4aSRandall Stewart 		stcb->asoc.num_send_timers_up--;
1764f8829a4aSRandall Stewart 		if (stcb->asoc.num_send_timers_up < 0) {
1765f8829a4aSRandall Stewart 			stcb->asoc.num_send_timers_up = 0;
1766f8829a4aSRandall Stewart 		}
1767b54d3a6cSRandall Stewart 		SCTP_TCB_LOCK_ASSERT(stcb);
176860990c0cSMichael Tuexen 		if (sctp_t3rxt_timer(inp, stcb, net)) {
1769f8829a4aSRandall Stewart 			/* no need to unlock on tcb its gone */
1770f8829a4aSRandall Stewart 
1771f8829a4aSRandall Stewart 			goto out_decr;
1772f8829a4aSRandall Stewart 		}
1773b54d3a6cSRandall Stewart 		SCTP_TCB_LOCK_ASSERT(stcb);
1774f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED
1775f8829a4aSRandall Stewart 		sctp_auditing(4, inp, stcb, net);
1776f8829a4aSRandall Stewart #endif
1777ceaad40aSRandall Stewart 		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
1778f8829a4aSRandall Stewart 		if ((stcb->asoc.num_send_timers_up == 0) &&
17794a9ef3f8SMichael Tuexen 		    (stcb->asoc.sent_queue_cnt > 0)) {
1780f8829a4aSRandall Stewart 			struct sctp_tmit_chunk *chk;
1781f8829a4aSRandall Stewart 
1782f8829a4aSRandall Stewart 			/*
1783f8829a4aSRandall Stewart 			 * safeguard. If there on some on the sent queue
1784f8829a4aSRandall Stewart 			 * somewhere but no timers running something is
1785f8829a4aSRandall Stewart 			 * wrong... so we start a timer on the first chunk
1786f8829a4aSRandall Stewart 			 * on the send queue on whatever net it is sent to.
1787f8829a4aSRandall Stewart 			 */
1788f8829a4aSRandall Stewart 			chk = TAILQ_FIRST(&stcb->asoc.sent_queue);
1789f8829a4aSRandall Stewart 			sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb,
1790f8829a4aSRandall Stewart 			    chk->whoTo);
1791f8829a4aSRandall Stewart 		}
1792f8829a4aSRandall Stewart 		break;
1793f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_INIT:
1794*a412576eSMichael Tuexen 		KASSERT(inp != NULL && stcb != NULL && net != NULL,
1795*a412576eSMichael Tuexen 		    ("timeout of type %d: inp = %p, stcb = %p, net = %p",
1796*a412576eSMichael Tuexen 		    type, inp, stcb, net));
1797f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_timoinit);
1798f42a358aSRandall Stewart 		stcb->asoc.timoinit++;
1799f8829a4aSRandall Stewart 		if (sctp_t1init_timer(inp, stcb, net)) {
1800f8829a4aSRandall Stewart 			/* no need to unlock on tcb its gone */
1801f8829a4aSRandall Stewart 			goto out_decr;
1802f8829a4aSRandall Stewart 		}
1803f8829a4aSRandall Stewart 		/* We do output but not here */
1804f8829a4aSRandall Stewart 		did_output = 0;
1805f8829a4aSRandall Stewart 		break;
1806f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_RECV:
1807*a412576eSMichael Tuexen 		KASSERT(inp != NULL && stcb != NULL && net == NULL,
1808*a412576eSMichael Tuexen 		    ("timeout of type %d: inp = %p, stcb = %p, net = %p",
1809*a412576eSMichael Tuexen 		    type, inp, stcb, net));
1810f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_timosack);
1811f42a358aSRandall Stewart 		stcb->asoc.timosack++;
1812689e6a5fSMichael Tuexen 		sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED);
1813f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED
1814*a412576eSMichael Tuexen 		sctp_auditing(4, inp, stcb, NULL);
1815f8829a4aSRandall Stewart #endif
1816ceaad40aSRandall Stewart 		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SACK_TMR, SCTP_SO_NOT_LOCKED);
1817f8829a4aSRandall Stewart 		break;
1818f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_SHUTDOWN:
1819*a412576eSMichael Tuexen 		KASSERT(inp != NULL && stcb != NULL && net != NULL,
1820*a412576eSMichael Tuexen 		    ("timeout of type %d: inp = %p, stcb = %p, net = %p",
1821*a412576eSMichael Tuexen 		    type, inp, stcb, net));
1822*a412576eSMichael Tuexen 		SCTP_STAT_INCR(sctps_timoshutdown);
1823*a412576eSMichael Tuexen 		stcb->asoc.timoshutdown++;
1824f8829a4aSRandall Stewart 		if (sctp_shutdown_timer(inp, stcb, net)) {
1825f8829a4aSRandall Stewart 			/* no need to unlock on tcb its gone */
1826f8829a4aSRandall Stewart 			goto out_decr;
1827f8829a4aSRandall Stewart 		}
1828f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED
1829f8829a4aSRandall Stewart 		sctp_auditing(4, inp, stcb, net);
1830f8829a4aSRandall Stewart #endif
1831ceaad40aSRandall Stewart 		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_TMR, SCTP_SO_NOT_LOCKED);
1832f8829a4aSRandall Stewart 		break;
1833f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_HEARTBEAT:
1834*a412576eSMichael Tuexen 		KASSERT(inp != NULL && stcb != NULL && net != NULL,
1835*a412576eSMichael Tuexen 		    ("timeout of type %d: inp = %p, stcb = %p, net = %p",
1836*a412576eSMichael Tuexen 		    type, inp, stcb, net));
1837f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_timoheartbeat);
1838f42a358aSRandall Stewart 		stcb->asoc.timoheartbeat++;
1839ca85e948SMichael Tuexen 		if (sctp_heartbeat_timer(inp, stcb, net)) {
1840f8829a4aSRandall Stewart 			/* no need to unlock on tcb its gone */
1841f8829a4aSRandall Stewart 			goto out_decr;
1842f8829a4aSRandall Stewart 		}
1843f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED
1844ca85e948SMichael Tuexen 		sctp_auditing(4, inp, stcb, net);
1845f8829a4aSRandall Stewart #endif
1846ca85e948SMichael Tuexen 		if (!(net->dest_state & SCTP_ADDR_NOHB)) {
1847629749b6SMichael Tuexen 			sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
1848ceaad40aSRandall Stewart 			sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_HB_TMR, SCTP_SO_NOT_LOCKED);
1849f8829a4aSRandall Stewart 		}
1850f8829a4aSRandall Stewart 		break;
1851f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_COOKIE:
1852*a412576eSMichael Tuexen 		KASSERT(inp != NULL && stcb != NULL && net != NULL,
1853*a412576eSMichael Tuexen 		    ("timeout of type %d: inp = %p, stcb = %p, net = %p",
1854*a412576eSMichael Tuexen 		    type, inp, stcb, net));
1855*a412576eSMichael Tuexen 		SCTP_STAT_INCR(sctps_timocookie);
1856*a412576eSMichael Tuexen 		stcb->asoc.timocookie++;
1857f8829a4aSRandall Stewart 		if (sctp_cookie_timer(inp, stcb, net)) {
1858f8829a4aSRandall Stewart 			/* no need to unlock on tcb its gone */
1859f8829a4aSRandall Stewart 			goto out_decr;
1860f8829a4aSRandall Stewart 		}
1861f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED
1862f8829a4aSRandall Stewart 		sctp_auditing(4, inp, stcb, net);
1863f8829a4aSRandall Stewart #endif
1864f8829a4aSRandall Stewart 		/*
1865f8829a4aSRandall Stewart 		 * We consider T3 and Cookie timer pretty much the same with
1866f8829a4aSRandall Stewart 		 * respect to where from in chunk_output.
1867f8829a4aSRandall Stewart 		 */
1868ceaad40aSRandall Stewart 		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
1869f8829a4aSRandall Stewart 		break;
1870f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_NEWCOOKIE:
1871*a412576eSMichael Tuexen 		KASSERT(inp != NULL && stcb == NULL && net == NULL,
1872*a412576eSMichael Tuexen 		    ("timeout of type %d: inp = %p, stcb = %p, net = %p",
1873*a412576eSMichael Tuexen 		    type, inp, stcb, net));
1874f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_timosecret);
18756e55db54SRandall Stewart 		(void)SCTP_GETTIME_TIMEVAL(&tv);
1876f8829a4aSRandall Stewart 		inp->sctp_ep.time_of_secret_change = tv.tv_sec;
1877f8829a4aSRandall Stewart 		inp->sctp_ep.last_secret_number =
1878f8829a4aSRandall Stewart 		    inp->sctp_ep.current_secret_number;
1879f8829a4aSRandall Stewart 		inp->sctp_ep.current_secret_number++;
1880f8829a4aSRandall Stewart 		if (inp->sctp_ep.current_secret_number >=
1881f8829a4aSRandall Stewart 		    SCTP_HOW_MANY_SECRETS) {
1882f8829a4aSRandall Stewart 			inp->sctp_ep.current_secret_number = 0;
1883f8829a4aSRandall Stewart 		}
1884f8829a4aSRandall Stewart 		secret = (int)inp->sctp_ep.current_secret_number;
1885f8829a4aSRandall Stewart 		for (i = 0; i < SCTP_NUMBER_OF_SECRETS; i++) {
1886f8829a4aSRandall Stewart 			inp->sctp_ep.secret_key[secret][i] =
1887f8829a4aSRandall Stewart 			    sctp_select_initial_TSN(&inp->sctp_ep);
1888f8829a4aSRandall Stewart 		}
18896fb7b4fbSMichael Tuexen 		sctp_timer_start(SCTP_TIMER_TYPE_NEWCOOKIE, inp, NULL, NULL);
1890f8829a4aSRandall Stewart 		did_output = 0;
1891f8829a4aSRandall Stewart 		break;
1892f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_PATHMTURAISE:
1893*a412576eSMichael Tuexen 		KASSERT(inp != NULL && stcb != NULL && net != NULL,
1894*a412576eSMichael Tuexen 		    ("timeout of type %d: inp = %p, stcb = %p, net = %p",
1895*a412576eSMichael Tuexen 		    type, inp, stcb, net));
1896f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_timopathmtu);
1897f8829a4aSRandall Stewart 		sctp_pathmtu_timer(inp, stcb, net);
1898f8829a4aSRandall Stewart 		did_output = 0;
1899f8829a4aSRandall Stewart 		break;
1900f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_SHUTDOWNACK:
1901*a412576eSMichael Tuexen 		KASSERT(inp != NULL && stcb != NULL && net != NULL,
1902*a412576eSMichael Tuexen 		    ("timeout of type %d: inp = %p, stcb = %p, net = %p",
1903*a412576eSMichael Tuexen 		    type, inp, stcb, net));
1904f8829a4aSRandall Stewart 		if (sctp_shutdownack_timer(inp, stcb, net)) {
1905f8829a4aSRandall Stewart 			/* no need to unlock on tcb its gone */
1906f8829a4aSRandall Stewart 			goto out_decr;
1907f8829a4aSRandall Stewart 		}
1908f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_timoshutdownack);
1909f42a358aSRandall Stewart 		stcb->asoc.timoshutdownack++;
1910f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED
1911f8829a4aSRandall Stewart 		sctp_auditing(4, inp, stcb, net);
1912f8829a4aSRandall Stewart #endif
1913ceaad40aSRandall Stewart 		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_ACK_TMR, SCTP_SO_NOT_LOCKED);
1914f8829a4aSRandall Stewart 		break;
1915f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_ASCONF:
1916*a412576eSMichael Tuexen 		KASSERT(inp != NULL && stcb != NULL && net != NULL,
1917*a412576eSMichael Tuexen 		    ("timeout of type %d: inp = %p, stcb = %p, net = %p",
1918*a412576eSMichael Tuexen 		    type, inp, stcb, net));
1919*a412576eSMichael Tuexen 		SCTP_STAT_INCR(sctps_timoasconf);
1920f8829a4aSRandall Stewart 		if (sctp_asconf_timer(inp, stcb, net)) {
1921f8829a4aSRandall Stewart 			/* no need to unlock on tcb its gone */
1922f8829a4aSRandall Stewart 			goto out_decr;
1923f8829a4aSRandall Stewart 		}
1924f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED
1925f8829a4aSRandall Stewart 		sctp_auditing(4, inp, stcb, net);
1926f8829a4aSRandall Stewart #endif
1927ceaad40aSRandall Stewart 		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_ASCONF_TMR, SCTP_SO_NOT_LOCKED);
1928f8829a4aSRandall Stewart 		break;
19290554e01dSMichael Tuexen 	case SCTP_TIMER_TYPE_SHUTDOWNGUARD:
1930*a412576eSMichael Tuexen 		KASSERT(inp != NULL && stcb != NULL && net == NULL,
1931*a412576eSMichael Tuexen 		    ("timeout of type %d: inp = %p, stcb = %p, net = %p",
1932*a412576eSMichael Tuexen 		    type, inp, stcb, net));
19330554e01dSMichael Tuexen 		SCTP_STAT_INCR(sctps_timoshutdownguard);
19340554e01dSMichael Tuexen 		op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
19350554e01dSMichael Tuexen 		    "Shutdown guard timer expired");
19360554e01dSMichael Tuexen 		sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED);
19370554e01dSMichael Tuexen 		/* no need to unlock on tcb its gone */
19380554e01dSMichael Tuexen 		goto out_decr;
1939f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_AUTOCLOSE:
1940*a412576eSMichael Tuexen 		KASSERT(inp != NULL && stcb != NULL && net == NULL,
1941*a412576eSMichael Tuexen 		    ("timeout of type %d: inp = %p, stcb = %p, net = %p",
1942*a412576eSMichael Tuexen 		    type, inp, stcb, net));
1943f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_timoautoclose);
1944a57fb68bSMichael Tuexen 		sctp_autoclose_timer(inp, stcb);
1945ceaad40aSRandall Stewart 		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_AUTOCLOSE_TMR, SCTP_SO_NOT_LOCKED);
1946f8829a4aSRandall Stewart 		did_output = 0;
1947f8829a4aSRandall Stewart 		break;
19480554e01dSMichael Tuexen 	case SCTP_TIMER_TYPE_STRRESET:
1949*a412576eSMichael Tuexen 		KASSERT(inp != NULL && stcb != NULL && net == NULL,
1950*a412576eSMichael Tuexen 		    ("timeout of type %d: inp = %p, stcb = %p, net = %p",
1951*a412576eSMichael Tuexen 		    type, inp, stcb, net));
1952*a412576eSMichael Tuexen 		SCTP_STAT_INCR(sctps_timostrmrst);
1953e95b3d7fSMichael Tuexen 		if (sctp_strreset_timer(inp, stcb)) {
19540554e01dSMichael Tuexen 			/* no need to unlock on tcb its gone */
19550554e01dSMichael Tuexen 			goto out_decr;
19560554e01dSMichael Tuexen 		}
19570554e01dSMichael Tuexen 		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_TMR, SCTP_SO_NOT_LOCKED);
19580554e01dSMichael Tuexen 		break;
19590554e01dSMichael Tuexen 	case SCTP_TIMER_TYPE_INPKILL:
1960*a412576eSMichael Tuexen 		KASSERT(inp != NULL && stcb == NULL && net == NULL,
1961*a412576eSMichael Tuexen 		    ("timeout of type %d: inp = %p, stcb = %p, net = %p",
1962*a412576eSMichael Tuexen 		    type, inp, stcb, net));
19630554e01dSMichael Tuexen 		SCTP_STAT_INCR(sctps_timoinpkill);
19640554e01dSMichael Tuexen 		/*
19650554e01dSMichael Tuexen 		 * special case, take away our increment since WE are the
19660554e01dSMichael Tuexen 		 * killer
19670554e01dSMichael Tuexen 		 */
19680554e01dSMichael Tuexen 		sctp_timer_stop(SCTP_TIMER_TYPE_INPKILL, inp, NULL, NULL,
19690554e01dSMichael Tuexen 		    SCTP_FROM_SCTPUTIL + SCTP_LOC_3);
1970*a412576eSMichael Tuexen 		SCTP_INP_DECR_REF(inp);
1971*a412576eSMichael Tuexen 		SCTP_INP_WUNLOCK(inp);
19720554e01dSMichael Tuexen 		sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
19730554e01dSMichael Tuexen 		    SCTP_CALLED_FROM_INPKILL_TIMER);
19740554e01dSMichael Tuexen 		inp = NULL;
19750554e01dSMichael Tuexen 		goto out_no_decr;
1976f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_ASOCKILL:
1977*a412576eSMichael Tuexen 		KASSERT(inp != NULL && stcb != NULL && net == NULL,
1978*a412576eSMichael Tuexen 		    ("timeout of type %d: inp = %p, stcb = %p, net = %p",
1979*a412576eSMichael Tuexen 		    type, inp, stcb, net));
1980f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_timoassockill);
1981f8829a4aSRandall Stewart 		/* Can we free it yet? */
1982f8829a4aSRandall Stewart 		SCTP_INP_DECR_REF(inp);
1983ba785902SMichael Tuexen 		sctp_timer_stop(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL,
1984ba785902SMichael Tuexen 		    SCTP_FROM_SCTPUTIL + SCTP_LOC_1);
1985ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
1986ceaad40aSRandall Stewart 		so = SCTP_INP_SO(inp);
1987ceaad40aSRandall Stewart 		atomic_add_int(&stcb->asoc.refcnt, 1);
1988ceaad40aSRandall Stewart 		SCTP_TCB_UNLOCK(stcb);
1989ceaad40aSRandall Stewart 		SCTP_SOCKET_LOCK(so, 1);
1990ceaad40aSRandall Stewart 		SCTP_TCB_LOCK(stcb);
1991ceaad40aSRandall Stewart 		atomic_subtract_int(&stcb->asoc.refcnt, 1);
1992ceaad40aSRandall Stewart #endif
1993ba785902SMichael Tuexen 		(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
1994ba785902SMichael Tuexen 		    SCTP_FROM_SCTPUTIL + SCTP_LOC_2);
1995ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
1996ceaad40aSRandall Stewart 		SCTP_SOCKET_UNLOCK(so, 1);
1997ceaad40aSRandall Stewart #endif
1998f8829a4aSRandall Stewart 		/*
1999f8829a4aSRandall Stewart 		 * free asoc, always unlocks (or destroy's) so prevent
2000f8829a4aSRandall Stewart 		 * duplicate unlock or unlock of a free mtx :-0
2001f8829a4aSRandall Stewart 		 */
2002f8829a4aSRandall Stewart 		stcb = NULL;
2003f8829a4aSRandall Stewart 		goto out_no_decr;
20040554e01dSMichael Tuexen 	case SCTP_TIMER_TYPE_ADDR_WQ:
2005*a412576eSMichael Tuexen 		KASSERT(inp == NULL && stcb == NULL && net == NULL,
2006*a412576eSMichael Tuexen 		    ("timeout of type %d: inp = %p, stcb = %p, net = %p",
2007*a412576eSMichael Tuexen 		    type, inp, stcb, net));
20080554e01dSMichael Tuexen 		sctp_handle_addr_wq();
20090554e01dSMichael Tuexen 		break;
20100554e01dSMichael Tuexen 	case SCTP_TIMER_TYPE_PRIM_DELETED:
2011*a412576eSMichael Tuexen 		KASSERT(inp != NULL && stcb != NULL && net == NULL,
2012*a412576eSMichael Tuexen 		    ("timeout of type %d: inp = %p, stcb = %p, net = %p",
2013*a412576eSMichael Tuexen 		    type, inp, stcb, net));
20140554e01dSMichael Tuexen 		SCTP_STAT_INCR(sctps_timodelprim);
2015*a412576eSMichael Tuexen 		sctp_delete_prim_timer(inp, stcb);
20160554e01dSMichael Tuexen 		break;
2017f8829a4aSRandall Stewart 	default:
2018*a412576eSMichael Tuexen 		panic("Unknown timer type %d", type);
201960990c0cSMichael Tuexen 	}
2020f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED
2021fa89f692SMichael Tuexen 	sctp_audit_log(0xF1, (uint8_t)type);
2022f8829a4aSRandall Stewart 	if (inp)
2023f8829a4aSRandall Stewart 		sctp_auditing(5, inp, stcb, net);
2024f8829a4aSRandall Stewart #endif
2025f8829a4aSRandall Stewart 	if ((did_output) && stcb) {
2026f8829a4aSRandall Stewart 		/*
2027f8829a4aSRandall Stewart 		 * Now we need to clean up the control chunk chain if an
2028f8829a4aSRandall Stewart 		 * ECNE is on it. It must be marked as UNSENT again so next
2029f8829a4aSRandall Stewart 		 * call will continue to send it until such time that we get
2030f8829a4aSRandall Stewart 		 * a CWR, to remove it. It is, however, less likely that we
2031f8829a4aSRandall Stewart 		 * will find a ecn echo on the chain though.
2032f8829a4aSRandall Stewart 		 */
2033f8829a4aSRandall Stewart 		sctp_fix_ecn_echo(&stcb->asoc);
2034f8829a4aSRandall Stewart 	}
203544b7479bSRandall Stewart get_out:
2036f8829a4aSRandall Stewart 	if (stcb) {
2037f8829a4aSRandall Stewart 		SCTP_TCB_UNLOCK(stcb);
20382c62ba73SMichael Tuexen 	} else if (inp != NULL) {
20392c62ba73SMichael Tuexen 		SCTP_INP_WUNLOCK(inp);
20402c62ba73SMichael Tuexen 	} else {
20412c62ba73SMichael Tuexen 		SCTP_WQ_ADDR_UNLOCK();
2042f8829a4aSRandall Stewart 	}
20432c62ba73SMichael Tuexen 
2044f8829a4aSRandall Stewart out_decr:
2045f8829a4aSRandall Stewart 	if (inp) {
2046f8829a4aSRandall Stewart 		SCTP_INP_DECR_REF(inp);
2047f8829a4aSRandall Stewart 	}
20480053ed28SMichael Tuexen 
2049f8829a4aSRandall Stewart out_no_decr:
2050*a412576eSMichael Tuexen 	SCTPDBG(SCTP_DEBUG_TIMER2, "Timer type = %d handler finished\n", type);
20518518270eSMichael Tuexen 	CURVNET_RESTORE();
2052868b51f2SMichael Tuexen 	NET_EPOCH_EXIT(et);
2053f8829a4aSRandall Stewart }
2054f8829a4aSRandall Stewart 
2055*a412576eSMichael Tuexen /*-
2056*a412576eSMichael Tuexen  * The following table shows which parameters must be provided
2057*a412576eSMichael Tuexen  * when calling sctp_timer_start(). For parameters not being
2058*a412576eSMichael Tuexen  * provided, NULL must be used.
2059*a412576eSMichael Tuexen  *
2060*a412576eSMichael Tuexen  * |Name                         |inp |stcb|net |
2061*a412576eSMichael Tuexen  * |-----------------------------|----|----|----|
2062*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_SEND         |Yes |Yes |Yes |
2063*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_INIT         |Yes |Yes |Yes |
2064*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_RECV         |Yes |Yes |No  |
2065*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_SHUTDOWN     |Yes |Yes |Yes |
2066*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_HEARTBEAT    |Yes |Yes |Yes |
2067*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_COOKIE       |Yes |Yes |Yes |
2068*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_NEWCOOKIE    |Yes |No  |No  |
2069*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_PATHMTURAISE |Yes |Yes |Yes |
2070*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_SHUTDOWNACK  |Yes |Yes |Yes |
2071*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_ASCONF       |Yes |Yes |Yes |
2072*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_SHUTDOWNGUARD|Yes |Yes |No  |
2073*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_AUTOCLOSE    |Yes |Yes |No  |
2074*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_STRRESET     |Yes |Yes |Yes |
2075*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_INPKILL      |Yes |No  |No  |
2076*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_ASOCKILL     |Yes |Yes |No  |
2077*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_ADDR_WQ      |No  |No  |No  |
2078*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_PRIM_DELETED |Yes |Yes |No  |
2079*a412576eSMichael Tuexen  *
2080*a412576eSMichael Tuexen  */
2081*a412576eSMichael Tuexen 
2082ad81507eSRandall Stewart void
2083f8829a4aSRandall Stewart sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
2084f8829a4aSRandall Stewart     struct sctp_nets *net)
2085f8829a4aSRandall Stewart {
2086f8829a4aSRandall Stewart 	struct sctp_timer *tmr;
2087*a412576eSMichael Tuexen 	uint32_t to_ticks;
2088*a412576eSMichael Tuexen 	uint32_t rndval, jitter;
2089f8829a4aSRandall Stewart 
2090f8829a4aSRandall Stewart 	tmr = NULL;
2091*a412576eSMichael Tuexen 	to_ticks = 0;
2092*a412576eSMichael Tuexen 	if (stcb != NULL) {
2093f8829a4aSRandall Stewart 		SCTP_TCB_LOCK_ASSERT(stcb);
2094*a412576eSMichael Tuexen 	} else if (inp != NULL) {
2095*a412576eSMichael Tuexen 		SCTP_INP_WLOCK_ASSERT(inp);
2096*a412576eSMichael Tuexen 	} else {
2097*a412576eSMichael Tuexen 		SCTP_WQ_ADDR_LOCK_ASSERT();
2098*a412576eSMichael Tuexen 	}
2099*a412576eSMichael Tuexen 	if (stcb != NULL) {
2100*a412576eSMichael Tuexen 		/*
2101*a412576eSMichael Tuexen 		 * Don't restart timer on association that's about to be
2102*a412576eSMichael Tuexen 		 * killed.
2103*a412576eSMichael Tuexen 		 */
2104*a412576eSMichael Tuexen 		if ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) &&
2105*a412576eSMichael Tuexen 		    (t_type != SCTP_TIMER_TYPE_ASOCKILL)) {
2106*a412576eSMichael Tuexen 			SCTPDBG(SCTP_DEBUG_TIMER2,
2107*a412576eSMichael Tuexen 			    "timer type %d not started: inp=%p, stcb=%p, net=%p (stcb deleted).\n",
2108*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2109*a412576eSMichael Tuexen 			return;
2110f8829a4aSRandall Stewart 		}
21119803f01cSMichael Tuexen 		/* Don't restart timer on net that's been removed. */
21129803f01cSMichael Tuexen 		if (net != NULL && (net->dest_state & SCTP_ADDR_BEING_DELETED)) {
2113*a412576eSMichael Tuexen 			SCTPDBG(SCTP_DEBUG_TIMER2,
2114*a412576eSMichael Tuexen 			    "timer type %d not started: inp=%p, stcb=%p, net=%p (net deleted).\n",
2115*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
21169803f01cSMichael Tuexen 			return;
21179803f01cSMichael Tuexen 		}
2118*a412576eSMichael Tuexen 	}
2119f8829a4aSRandall Stewart 	switch (t_type) {
2120f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_SEND:
2121*a412576eSMichael Tuexen 		/* Here we use the RTO timer. */
2122*a412576eSMichael Tuexen 		if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
2123*a412576eSMichael Tuexen #ifdef INVARIANTS
2124*a412576eSMichael Tuexen 			panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
2125*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2126*a412576eSMichael Tuexen #else
2127ad81507eSRandall Stewart 			return;
2128*a412576eSMichael Tuexen #endif
2129f8829a4aSRandall Stewart 		}
2130f8829a4aSRandall Stewart 		tmr = &net->rxt_timer;
2131f8829a4aSRandall Stewart 		if (net->RTO == 0) {
2132*a412576eSMichael Tuexen 			to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
2133f8829a4aSRandall Stewart 		} else {
2134*a412576eSMichael Tuexen 			to_ticks = MSEC_TO_TICKS(net->RTO);
2135f8829a4aSRandall Stewart 		}
2136f8829a4aSRandall Stewart 		break;
2137f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_INIT:
2138f8829a4aSRandall Stewart 		/*
2139f8829a4aSRandall Stewart 		 * Here we use the INIT timer default usually about 1
2140*a412576eSMichael Tuexen 		 * second.
2141f8829a4aSRandall Stewart 		 */
2142*a412576eSMichael Tuexen 		if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
2143*a412576eSMichael Tuexen #ifdef INVARIANTS
2144*a412576eSMichael Tuexen 			panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
2145*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2146*a412576eSMichael Tuexen #else
2147ad81507eSRandall Stewart 			return;
2148*a412576eSMichael Tuexen #endif
2149f8829a4aSRandall Stewart 		}
2150f8829a4aSRandall Stewart 		tmr = &net->rxt_timer;
2151f8829a4aSRandall Stewart 		if (net->RTO == 0) {
2152f8829a4aSRandall Stewart 			to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
2153f8829a4aSRandall Stewart 		} else {
2154f8829a4aSRandall Stewart 			to_ticks = MSEC_TO_TICKS(net->RTO);
2155f8829a4aSRandall Stewart 		}
2156f8829a4aSRandall Stewart 		break;
2157f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_RECV:
2158f8829a4aSRandall Stewart 		/*
2159*a412576eSMichael Tuexen 		 * Here we use the Delayed-Ack timer value from the inp,
2160f8829a4aSRandall Stewart 		 * ususually about 200ms.
2161f8829a4aSRandall Stewart 		 */
2162*a412576eSMichael Tuexen 		if ((inp == NULL) || (stcb == NULL) || (net != NULL)) {
2163*a412576eSMichael Tuexen #ifdef INVARIANTS
2164*a412576eSMichael Tuexen 			panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
2165*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2166*a412576eSMichael Tuexen #else
2167ad81507eSRandall Stewart 			return;
2168*a412576eSMichael Tuexen #endif
2169f8829a4aSRandall Stewart 		}
2170f8829a4aSRandall Stewart 		tmr = &stcb->asoc.dack_timer;
2171f8829a4aSRandall Stewart 		to_ticks = MSEC_TO_TICKS(stcb->asoc.delayed_ack);
2172f8829a4aSRandall Stewart 		break;
2173f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_SHUTDOWN:
2174f8829a4aSRandall Stewart 		/* Here we use the RTO of the destination. */
2175*a412576eSMichael Tuexen 		if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
2176*a412576eSMichael Tuexen #ifdef INVARIANTS
2177*a412576eSMichael Tuexen 			panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
2178*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2179*a412576eSMichael Tuexen #else
2180ad81507eSRandall Stewart 			return;
2181*a412576eSMichael Tuexen #endif
2182f8829a4aSRandall Stewart 		}
2183*a412576eSMichael Tuexen 		tmr = &net->rxt_timer;
2184f8829a4aSRandall Stewart 		if (net->RTO == 0) {
2185f8829a4aSRandall Stewart 			to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
2186f8829a4aSRandall Stewart 		} else {
2187f8829a4aSRandall Stewart 			to_ticks = MSEC_TO_TICKS(net->RTO);
2188f8829a4aSRandall Stewart 		}
2189f8829a4aSRandall Stewart 		break;
2190f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_HEARTBEAT:
2191f8829a4aSRandall Stewart 		/*
2192*a412576eSMichael Tuexen 		 * The net is used here so that we can add in the RTO. Even
2193f8829a4aSRandall Stewart 		 * though we use a different timer. We also add the HB timer
2194f8829a4aSRandall Stewart 		 * PLUS a random jitter.
2195f8829a4aSRandall Stewart 		 */
2196*a412576eSMichael Tuexen 		if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
2197*a412576eSMichael Tuexen #ifdef INVARIANTS
2198*a412576eSMichael Tuexen 			panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
2199*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2200*a412576eSMichael Tuexen #else
2201ad81507eSRandall Stewart 			return;
2202*a412576eSMichael Tuexen #endif
2203*a412576eSMichael Tuexen 		}
2204ca85e948SMichael Tuexen 		if ((net->dest_state & SCTP_ADDR_NOHB) &&
2205ca85e948SMichael Tuexen 		    !(net->dest_state & SCTP_ADDR_UNCONFIRMED)) {
2206*a412576eSMichael Tuexen 			SCTPDBG(SCTP_DEBUG_TIMER2,
2207*a412576eSMichael Tuexen 			    "timer type %d not started: inp=%p, stcb=%p, net=%p.\n",
2208*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2209ad81507eSRandall Stewart 			return;
2210f8829a4aSRandall Stewart 		}
2211*a412576eSMichael Tuexen 		tmr = &net->hb_timer;
2212f8829a4aSRandall Stewart 		if (net->RTO == 0) {
2213ca85e948SMichael Tuexen 			to_ticks = stcb->asoc.initial_rto;
2214f8829a4aSRandall Stewart 		} else {
2215ca85e948SMichael Tuexen 			to_ticks = net->RTO;
2216f8829a4aSRandall Stewart 		}
2217ca85e948SMichael Tuexen 		rndval = sctp_select_initial_TSN(&inp->sctp_ep);
2218ca85e948SMichael Tuexen 		jitter = rndval % to_ticks;
2219ca85e948SMichael Tuexen 		if (jitter >= (to_ticks >> 1)) {
2220ca85e948SMichael Tuexen 			to_ticks = to_ticks + (jitter - (to_ticks >> 1));
2221f8829a4aSRandall Stewart 		} else {
2222ca85e948SMichael Tuexen 			to_ticks = to_ticks - jitter;
2223f8829a4aSRandall Stewart 		}
2224ca85e948SMichael Tuexen 		if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED) &&
2225ca85e948SMichael Tuexen 		    !(net->dest_state & SCTP_ADDR_PF)) {
2226ca85e948SMichael Tuexen 			to_ticks += net->heart_beat_delay;
2227f8829a4aSRandall Stewart 		}
2228f8829a4aSRandall Stewart 		/*
2229*a412576eSMichael Tuexen 		 * Now we must convert the to_ticks that are now in ms to
2230*a412576eSMichael Tuexen 		 * ticks.
2231f8829a4aSRandall Stewart 		 */
2232f8829a4aSRandall Stewart 		to_ticks = MSEC_TO_TICKS(to_ticks);
2233f8829a4aSRandall Stewart 		break;
2234f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_COOKIE:
2235f8829a4aSRandall Stewart 		/*
2236f8829a4aSRandall Stewart 		 * Here we can use the RTO timer from the network since one
2237*a412576eSMichael Tuexen 		 * RTT was complete. If a retransmission happened then we
2238*a412576eSMichael Tuexen 		 * will be using the RTO initial value.
2239f8829a4aSRandall Stewart 		 */
2240*a412576eSMichael Tuexen 		if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
2241*a412576eSMichael Tuexen #ifdef INVARIANTS
2242*a412576eSMichael Tuexen 			panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
2243*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2244*a412576eSMichael Tuexen #else
2245ad81507eSRandall Stewart 			return;
2246*a412576eSMichael Tuexen #endif
2247f8829a4aSRandall Stewart 		}
2248*a412576eSMichael Tuexen 		tmr = &net->rxt_timer;
2249f8829a4aSRandall Stewart 		if (net->RTO == 0) {
2250f8829a4aSRandall Stewart 			to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
2251f8829a4aSRandall Stewart 		} else {
2252f8829a4aSRandall Stewart 			to_ticks = MSEC_TO_TICKS(net->RTO);
2253f8829a4aSRandall Stewart 		}
2254f8829a4aSRandall Stewart 		break;
2255f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_NEWCOOKIE:
2256f8829a4aSRandall Stewart 		/*
2257*a412576eSMichael Tuexen 		 * Nothing needed but the endpoint here ususually about 60
2258f8829a4aSRandall Stewart 		 * minutes.
2259f8829a4aSRandall Stewart 		 */
2260*a412576eSMichael Tuexen 		if ((inp == NULL) || (stcb != NULL) || (net != NULL)) {
2261*a412576eSMichael Tuexen #ifdef INVARIANTS
2262*a412576eSMichael Tuexen 			panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
2263*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2264*a412576eSMichael Tuexen #else
2265*a412576eSMichael Tuexen 			return;
2266*a412576eSMichael Tuexen #endif
2267*a412576eSMichael Tuexen 		}
2268f8829a4aSRandall Stewart 		tmr = &inp->sctp_ep.signature_change;
2269f8829a4aSRandall Stewart 		to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_SIGNATURE];
2270f8829a4aSRandall Stewart 		break;
2271f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_PATHMTURAISE:
2272f8829a4aSRandall Stewart 		/*
2273*a412576eSMichael Tuexen 		 * Here we use the value found in the EP for PMTUD,
2274*a412576eSMichael Tuexen 		 * ususually about 10 minutes.
2275f8829a4aSRandall Stewart 		 */
2276*a412576eSMichael Tuexen 		if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
2277*a412576eSMichael Tuexen #ifdef INVARIANTS
2278*a412576eSMichael Tuexen 			panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
2279*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2280*a412576eSMichael Tuexen #else
2281ad81507eSRandall Stewart 			return;
2282*a412576eSMichael Tuexen #endif
2283f8829a4aSRandall Stewart 		}
228480c79bbeSMichael Tuexen 		if (net->dest_state & SCTP_ADDR_NO_PMTUD) {
2285*a412576eSMichael Tuexen 			SCTPDBG(SCTP_DEBUG_TIMER2,
2286*a412576eSMichael Tuexen 			    "timer type %d not started: inp=%p, stcb=%p, net=%p.\n",
2287*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
228880c79bbeSMichael Tuexen 			return;
228980c79bbeSMichael Tuexen 		}
2290f8829a4aSRandall Stewart 		tmr = &net->pmtu_timer;
2291*a412576eSMichael Tuexen 		to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_PMTU];
2292f8829a4aSRandall Stewart 		break;
2293f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_SHUTDOWNACK:
2294*a412576eSMichael Tuexen 		/* Here we use the RTO of the destination. */
2295*a412576eSMichael Tuexen 		if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
2296*a412576eSMichael Tuexen #ifdef INVARIANTS
2297*a412576eSMichael Tuexen 			panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
2298*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2299*a412576eSMichael Tuexen #else
2300ad81507eSRandall Stewart 			return;
2301*a412576eSMichael Tuexen #endif
2302f8829a4aSRandall Stewart 		}
2303*a412576eSMichael Tuexen 		tmr = &net->rxt_timer;
2304f8829a4aSRandall Stewart 		if (net->RTO == 0) {
2305f8829a4aSRandall Stewart 			to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
2306f8829a4aSRandall Stewart 		} else {
2307f8829a4aSRandall Stewart 			to_ticks = MSEC_TO_TICKS(net->RTO);
2308f8829a4aSRandall Stewart 		}
2309f8829a4aSRandall Stewart 		break;
23100554e01dSMichael Tuexen 	case SCTP_TIMER_TYPE_ASCONF:
23110554e01dSMichael Tuexen 		/*
23120554e01dSMichael Tuexen 		 * Here the timer comes from the stcb but its value is from
23130554e01dSMichael Tuexen 		 * the net's RTO.
23140554e01dSMichael Tuexen 		 */
2315*a412576eSMichael Tuexen 		if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
2316*a412576eSMichael Tuexen #ifdef INVARIANTS
2317*a412576eSMichael Tuexen 			panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
2318*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2319*a412576eSMichael Tuexen #else
23200554e01dSMichael Tuexen 			return;
2321*a412576eSMichael Tuexen #endif
23220554e01dSMichael Tuexen 		}
2323*a412576eSMichael Tuexen 		tmr = &stcb->asoc.asconf_timer;
23240554e01dSMichael Tuexen 		if (net->RTO == 0) {
23250554e01dSMichael Tuexen 			to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
23260554e01dSMichael Tuexen 		} else {
23270554e01dSMichael Tuexen 			to_ticks = MSEC_TO_TICKS(net->RTO);
23280554e01dSMichael Tuexen 		}
23290554e01dSMichael Tuexen 		break;
2330f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_SHUTDOWNGUARD:
2331f8829a4aSRandall Stewart 		/*
2332f8829a4aSRandall Stewart 		 * Here we use the endpoints shutdown guard timer usually
2333f8829a4aSRandall Stewart 		 * about 3 minutes.
2334f8829a4aSRandall Stewart 		 */
2335*a412576eSMichael Tuexen 		if ((inp == NULL) || (stcb == NULL) || (net != NULL)) {
2336*a412576eSMichael Tuexen #ifdef INVARIANTS
2337*a412576eSMichael Tuexen 			panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
2338*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2339*a412576eSMichael Tuexen #else
2340ad81507eSRandall Stewart 			return;
2341*a412576eSMichael Tuexen #endif
2342f8829a4aSRandall Stewart 		}
2343*a412576eSMichael Tuexen 		tmr = &stcb->asoc.shut_guard_timer;
23442e2d6794SMichael Tuexen 		if (inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_MAXSHUTDOWN] == 0) {
23452e2d6794SMichael Tuexen 			to_ticks = 5 * MSEC_TO_TICKS(stcb->asoc.maxrto);
23462e2d6794SMichael Tuexen 		} else {
2347f8829a4aSRandall Stewart 			to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_MAXSHUTDOWN];
23482e2d6794SMichael Tuexen 		}
2349f8829a4aSRandall Stewart 		break;
23500554e01dSMichael Tuexen 	case SCTP_TIMER_TYPE_AUTOCLOSE:
2351*a412576eSMichael Tuexen 		if ((inp == NULL) || (stcb == NULL) || (net != NULL)) {
2352*a412576eSMichael Tuexen #ifdef INVARIANTS
2353*a412576eSMichael Tuexen 			panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
2354*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2355*a412576eSMichael Tuexen #else
23560554e01dSMichael Tuexen 			return;
2357*a412576eSMichael Tuexen #endif
23580554e01dSMichael Tuexen 		}
23590554e01dSMichael Tuexen 		tmr = &stcb->asoc.autoclose_timer;
2360*a412576eSMichael Tuexen 		to_ticks = stcb->asoc.sctp_autoclose_ticks;
23610554e01dSMichael Tuexen 		break;
2362f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_STRRESET:
2363f8829a4aSRandall Stewart 		/*
23641b649582SRandall Stewart 		 * Here the timer comes from the stcb but its value is from
23651b649582SRandall Stewart 		 * the net's RTO.
2366f8829a4aSRandall Stewart 		 */
2367*a412576eSMichael Tuexen 		if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
2368*a412576eSMichael Tuexen #ifdef INVARIANTS
2369*a412576eSMichael Tuexen 			panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
2370*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2371*a412576eSMichael Tuexen #else
2372ad81507eSRandall Stewart 			return;
2373*a412576eSMichael Tuexen #endif
2374f8829a4aSRandall Stewart 		}
2375*a412576eSMichael Tuexen 		tmr = &stcb->asoc.strreset_timer;
2376f8829a4aSRandall Stewart 		if (net->RTO == 0) {
2377f8829a4aSRandall Stewart 			to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
2378f8829a4aSRandall Stewart 		} else {
2379f8829a4aSRandall Stewart 			to_ticks = MSEC_TO_TICKS(net->RTO);
2380f8829a4aSRandall Stewart 		}
2381f8829a4aSRandall Stewart 		break;
23820554e01dSMichael Tuexen 	case SCTP_TIMER_TYPE_INPKILL:
2383f8829a4aSRandall Stewart 		/*
23840554e01dSMichael Tuexen 		 * The inp is setup to die. We re-use the signature_chage
23850554e01dSMichael Tuexen 		 * timer since that has stopped and we are in the GONE
23860554e01dSMichael Tuexen 		 * state.
2387f8829a4aSRandall Stewart 		 */
2388*a412576eSMichael Tuexen 		if ((inp == NULL) || (stcb != NULL) || (net != NULL)) {
2389*a412576eSMichael Tuexen #ifdef INVARIANTS
2390*a412576eSMichael Tuexen 			panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
2391*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2392*a412576eSMichael Tuexen #else
2393*a412576eSMichael Tuexen 			return;
2394*a412576eSMichael Tuexen #endif
2395*a412576eSMichael Tuexen 		}
23960554e01dSMichael Tuexen 		tmr = &inp->sctp_ep.signature_change;
23970554e01dSMichael Tuexen 		to_ticks = MSEC_TO_TICKS(SCTP_INP_KILL_TIMEOUT);
23980554e01dSMichael Tuexen 		break;
23990554e01dSMichael Tuexen 	case SCTP_TIMER_TYPE_ASOCKILL:
2400*a412576eSMichael Tuexen 		if ((inp == NULL) || (stcb == NULL) || (net != NULL)) {
2401*a412576eSMichael Tuexen #ifdef INVARIANTS
2402*a412576eSMichael Tuexen 			panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
2403*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2404*a412576eSMichael Tuexen #else
2405ad81507eSRandall Stewart 			return;
2406*a412576eSMichael Tuexen #endif
2407f8829a4aSRandall Stewart 		}
24080554e01dSMichael Tuexen 		tmr = &stcb->asoc.strreset_timer;
24090554e01dSMichael Tuexen 		to_ticks = MSEC_TO_TICKS(SCTP_ASOC_KILL_TIMEOUT);
24100554e01dSMichael Tuexen 		break;
24110554e01dSMichael Tuexen 	case SCTP_TIMER_TYPE_ADDR_WQ:
2412*a412576eSMichael Tuexen 		if ((inp != NULL) || (stcb != NULL) || (net != NULL)) {
2413*a412576eSMichael Tuexen #ifdef INVARIANTS
2414*a412576eSMichael Tuexen 			panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
2415*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2416*a412576eSMichael Tuexen #else
2417*a412576eSMichael Tuexen 			return;
2418*a412576eSMichael Tuexen #endif
2419*a412576eSMichael Tuexen 		}
24200554e01dSMichael Tuexen 		/* Only 1 tick away :-) */
24210554e01dSMichael Tuexen 		tmr = &SCTP_BASE_INFO(addr_wq_timer);
24220554e01dSMichael Tuexen 		to_ticks = SCTP_ADDRESS_TICK_DELAY;
2423f8829a4aSRandall Stewart 		break;
2424851b7298SRandall Stewart 	case SCTP_TIMER_TYPE_PRIM_DELETED:
2425*a412576eSMichael Tuexen 		if ((inp == NULL) || (stcb == NULL) || (net != NULL)) {
2426*a412576eSMichael Tuexen #ifdef INVARIANTS
2427*a412576eSMichael Tuexen 			panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p",
2428*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2429*a412576eSMichael Tuexen #else
2430851b7298SRandall Stewart 			return;
2431*a412576eSMichael Tuexen #endif
2432851b7298SRandall Stewart 		}
2433851b7298SRandall Stewart 		tmr = &stcb->asoc.delete_prim_timer;
2434*a412576eSMichael Tuexen 		to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
2435851b7298SRandall Stewart 		break;
2436f8829a4aSRandall Stewart 	default:
2437*a412576eSMichael Tuexen 		panic("Unknown timer type %d", t_type);
243860990c0cSMichael Tuexen 	}
2439*a412576eSMichael Tuexen 	KASSERT(tmr != NULL, ("tmr is NULL for timer type %d", t_type));
2440*a412576eSMichael Tuexen 	KASSERT(to_ticks > 0, ("to_ticks == 0 for timer type %d", t_type));
2441139bc87fSRandall Stewart 	if (SCTP_OS_TIMER_PENDING(&tmr->timer)) {
2442f8829a4aSRandall Stewart 		/*
2443*a412576eSMichael Tuexen 		 * We do NOT allow you to have it already running. If it is,
2444*a412576eSMichael Tuexen 		 * we leave the current one up unchanged.
2445f8829a4aSRandall Stewart 		 */
2446*a412576eSMichael Tuexen 		SCTPDBG(SCTP_DEBUG_TIMER2,
2447*a412576eSMichael Tuexen 		    "timer type %d already running: inp=%p, stcb=%p, net=%p.\n",
2448*a412576eSMichael Tuexen 		    t_type, inp, stcb, net);
2449ad81507eSRandall Stewart 		return;
2450f8829a4aSRandall Stewart 	}
2451*a412576eSMichael Tuexen 	/* At this point we can proceed. */
2452f8829a4aSRandall Stewart 	if (t_type == SCTP_TIMER_TYPE_SEND) {
2453f8829a4aSRandall Stewart 		stcb->asoc.num_send_timers_up++;
2454f8829a4aSRandall Stewart 	}
2455a5d547adSRandall Stewart 	tmr->stopped_from = 0;
2456f8829a4aSRandall Stewart 	tmr->type = t_type;
2457f8829a4aSRandall Stewart 	tmr->ep = (void *)inp;
2458f8829a4aSRandall Stewart 	tmr->tcb = (void *)stcb;
2459*a412576eSMichael Tuexen 	if (t_type == SCTP_TIMER_TYPE_STRRESET) {
2460*a412576eSMichael Tuexen 		tmr->net = NULL;
2461*a412576eSMichael Tuexen 	} else {
2462f8829a4aSRandall Stewart 		tmr->net = (void *)net;
2463*a412576eSMichael Tuexen 	}
2464f8829a4aSRandall Stewart 	tmr->self = (void *)tmr;
24658518270eSMichael Tuexen 	tmr->vnet = (void *)curvnet;
2466c4739e2fSRandall Stewart 	tmr->ticks = sctp_get_tick_count();
2467*a412576eSMichael Tuexen 	if (SCTP_OS_TIMER_START(&tmr->timer, to_ticks, sctp_timeout_handler, tmr) == 0) {
2468*a412576eSMichael Tuexen 		SCTPDBG(SCTP_DEBUG_TIMER2,
2469*a412576eSMichael Tuexen 		    "timer type %d started: ticks=%u, inp=%p, stcb=%p, net=%p.\n",
2470*a412576eSMichael Tuexen 		    t_type, to_ticks, inp, stcb, net);
2471*a412576eSMichael Tuexen 	} else {
2472*a412576eSMichael Tuexen 		/*
2473*a412576eSMichael Tuexen 		 * This should not happen, since we checked for pending
2474*a412576eSMichael Tuexen 		 * above.
2475*a412576eSMichael Tuexen 		 */
2476*a412576eSMichael Tuexen 		SCTPDBG(SCTP_DEBUG_TIMER2,
2477*a412576eSMichael Tuexen 		    "timer type %d restarted: ticks=%u, inp=%p, stcb=%p, net=%p.\n",
2478*a412576eSMichael Tuexen 		    t_type, to_ticks, inp, stcb, net);
2479*a412576eSMichael Tuexen 	}
2480ad81507eSRandall Stewart 	return;
2481f8829a4aSRandall Stewart }
2482f8829a4aSRandall Stewart 
2483*a412576eSMichael Tuexen /*-
2484*a412576eSMichael Tuexen  * The following table shows which parameters must be provided
2485*a412576eSMichael Tuexen  * when calling sctp_timer_stop(). For parameters not being
2486*a412576eSMichael Tuexen  * provided, NULL must be used.
2487*a412576eSMichael Tuexen  *
2488*a412576eSMichael Tuexen  * |Name                         |inp |stcb|net |
2489*a412576eSMichael Tuexen  * |-----------------------------|----|----|----|
2490*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_SEND         |Yes |Yes |Yes |
2491*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_INIT         |Yes |Yes |Yes |
2492*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_RECV         |Yes |Yes |No  |
2493*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_SHUTDOWN     |Yes |Yes |Yes |
2494*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_HEARTBEAT    |Yes |Yes |Yes |
2495*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_COOKIE       |Yes |Yes |Yes |
2496*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_NEWCOOKIE    |Yes |No  |No  |
2497*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_PATHMTURAISE |Yes |Yes |Yes |
2498*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_SHUTDOWNACK  |Yes |Yes |Yes |
2499*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_ASCONF       |Yes |Yes |No  |
2500*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_SHUTDOWNGUARD|Yes |Yes |No  |
2501*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_AUTOCLOSE    |Yes |Yes |No  |
2502*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_STRRESET     |Yes |Yes |No  |
2503*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_INPKILL      |Yes |No  |No  |
2504*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_ASOCKILL     |Yes |Yes |No  |
2505*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_ADDR_WQ      |No  |No  |No  |
2506*a412576eSMichael Tuexen  * |SCTP_TIMER_TYPE_PRIM_DELETED |Yes |Yes |No  |
2507*a412576eSMichael Tuexen  *
2508*a412576eSMichael Tuexen  */
2509*a412576eSMichael Tuexen 
25106e55db54SRandall Stewart void
2511f8829a4aSRandall Stewart sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
2512a5d547adSRandall Stewart     struct sctp_nets *net, uint32_t from)
2513f8829a4aSRandall Stewart {
2514f8829a4aSRandall Stewart 	struct sctp_timer *tmr;
2515f8829a4aSRandall Stewart 
2516*a412576eSMichael Tuexen 	if (stcb != NULL) {
2517f8829a4aSRandall Stewart 		SCTP_TCB_LOCK_ASSERT(stcb);
2518*a412576eSMichael Tuexen 	} else if (inp != NULL) {
2519*a412576eSMichael Tuexen 		SCTP_INP_WLOCK_ASSERT(inp);
2520*a412576eSMichael Tuexen 	} else {
2521*a412576eSMichael Tuexen 		SCTP_WQ_ADDR_LOCK_ASSERT();
2522f8829a4aSRandall Stewart 	}
2523*a412576eSMichael Tuexen 	tmr = NULL;
2524f8829a4aSRandall Stewart 	switch (t_type) {
2525f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_SEND:
2526*a412576eSMichael Tuexen 		if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
2527*a412576eSMichael Tuexen #ifdef INVARIANTS
2528*a412576eSMichael Tuexen 			panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
2529*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2530*a412576eSMichael Tuexen #else
25316e55db54SRandall Stewart 			return;
2532*a412576eSMichael Tuexen #endif
2533f8829a4aSRandall Stewart 		}
2534f8829a4aSRandall Stewart 		tmr = &net->rxt_timer;
2535f8829a4aSRandall Stewart 		break;
2536f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_INIT:
2537*a412576eSMichael Tuexen 		if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
2538*a412576eSMichael Tuexen #ifdef INVARIANTS
2539*a412576eSMichael Tuexen 			panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
2540*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2541*a412576eSMichael Tuexen #else
25426e55db54SRandall Stewart 			return;
2543*a412576eSMichael Tuexen #endif
2544f8829a4aSRandall Stewart 		}
2545f8829a4aSRandall Stewart 		tmr = &net->rxt_timer;
2546f8829a4aSRandall Stewart 		break;
2547f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_RECV:
2548*a412576eSMichael Tuexen 		if ((inp == NULL) || (stcb == NULL) || (net != NULL)) {
2549*a412576eSMichael Tuexen #ifdef INVARIANTS
2550*a412576eSMichael Tuexen 			panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
2551*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2552*a412576eSMichael Tuexen #else
25536e55db54SRandall Stewart 			return;
2554*a412576eSMichael Tuexen #endif
2555f8829a4aSRandall Stewart 		}
2556f8829a4aSRandall Stewart 		tmr = &stcb->asoc.dack_timer;
2557f8829a4aSRandall Stewart 		break;
2558f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_SHUTDOWN:
2559*a412576eSMichael Tuexen 		if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
2560*a412576eSMichael Tuexen #ifdef INVARIANTS
2561*a412576eSMichael Tuexen 			panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
2562*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2563*a412576eSMichael Tuexen #else
25646e55db54SRandall Stewart 			return;
2565*a412576eSMichael Tuexen #endif
2566f8829a4aSRandall Stewart 		}
2567f8829a4aSRandall Stewart 		tmr = &net->rxt_timer;
2568f8829a4aSRandall Stewart 		break;
2569f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_HEARTBEAT:
2570*a412576eSMichael Tuexen 		if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
2571*a412576eSMichael Tuexen #ifdef INVARIANTS
2572*a412576eSMichael Tuexen 			panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
2573*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2574*a412576eSMichael Tuexen #else
25756e55db54SRandall Stewart 			return;
2576*a412576eSMichael Tuexen #endif
2577f8829a4aSRandall Stewart 		}
2578ca85e948SMichael Tuexen 		tmr = &net->hb_timer;
2579f8829a4aSRandall Stewart 		break;
2580f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_COOKIE:
2581*a412576eSMichael Tuexen 		if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
2582*a412576eSMichael Tuexen #ifdef INVARIANTS
2583*a412576eSMichael Tuexen 			panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
2584*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2585*a412576eSMichael Tuexen #else
25866e55db54SRandall Stewart 			return;
2587*a412576eSMichael Tuexen #endif
2588f8829a4aSRandall Stewart 		}
2589f8829a4aSRandall Stewart 		tmr = &net->rxt_timer;
2590f8829a4aSRandall Stewart 		break;
2591f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_NEWCOOKIE:
2592*a412576eSMichael Tuexen 		if ((inp == NULL) || (stcb != NULL) || (net != NULL)) {
2593*a412576eSMichael Tuexen #ifdef INVARIANTS
2594*a412576eSMichael Tuexen 			panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
2595*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2596*a412576eSMichael Tuexen #else
2597*a412576eSMichael Tuexen 			return;
2598*a412576eSMichael Tuexen #endif
2599*a412576eSMichael Tuexen 		}
2600f8829a4aSRandall Stewart 		tmr = &inp->sctp_ep.signature_change;
2601f8829a4aSRandall Stewart 		break;
2602f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_PATHMTURAISE:
2603*a412576eSMichael Tuexen 		if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
2604*a412576eSMichael Tuexen #ifdef INVARIANTS
2605*a412576eSMichael Tuexen 			panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
2606*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2607*a412576eSMichael Tuexen #else
26086e55db54SRandall Stewart 			return;
2609*a412576eSMichael Tuexen #endif
2610f8829a4aSRandall Stewart 		}
2611f8829a4aSRandall Stewart 		tmr = &net->pmtu_timer;
2612f8829a4aSRandall Stewart 		break;
2613f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_SHUTDOWNACK:
2614*a412576eSMichael Tuexen 		if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
2615*a412576eSMichael Tuexen #ifdef INVARIANTS
2616*a412576eSMichael Tuexen 			panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
2617*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2618*a412576eSMichael Tuexen #else
26196e55db54SRandall Stewart 			return;
2620*a412576eSMichael Tuexen #endif
2621f8829a4aSRandall Stewart 		}
2622f8829a4aSRandall Stewart 		tmr = &net->rxt_timer;
2623f8829a4aSRandall Stewart 		break;
26240554e01dSMichael Tuexen 	case SCTP_TIMER_TYPE_ASCONF:
2625*a412576eSMichael Tuexen 		if ((inp == NULL) || (stcb == NULL) || (net != NULL)) {
2626*a412576eSMichael Tuexen #ifdef INVARIANTS
2627*a412576eSMichael Tuexen 			panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
2628*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2629*a412576eSMichael Tuexen #else
26300554e01dSMichael Tuexen 			return;
2631*a412576eSMichael Tuexen #endif
26320554e01dSMichael Tuexen 		}
26330554e01dSMichael Tuexen 		tmr = &stcb->asoc.asconf_timer;
26340554e01dSMichael Tuexen 		break;
2635f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_SHUTDOWNGUARD:
2636*a412576eSMichael Tuexen 		if ((inp == NULL) || (stcb == NULL) || (net != NULL)) {
2637*a412576eSMichael Tuexen #ifdef INVARIANTS
2638*a412576eSMichael Tuexen 			panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
2639*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2640*a412576eSMichael Tuexen #else
26416e55db54SRandall Stewart 			return;
2642*a412576eSMichael Tuexen #endif
2643f8829a4aSRandall Stewart 		}
2644f8829a4aSRandall Stewart 		tmr = &stcb->asoc.shut_guard_timer;
2645f8829a4aSRandall Stewart 		break;
26460554e01dSMichael Tuexen 	case SCTP_TIMER_TYPE_AUTOCLOSE:
2647*a412576eSMichael Tuexen 		if ((inp == NULL) || (stcb == NULL) || (net != NULL)) {
2648*a412576eSMichael Tuexen #ifdef INVARIANTS
2649*a412576eSMichael Tuexen 			panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
2650*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2651*a412576eSMichael Tuexen #else
26520554e01dSMichael Tuexen 			return;
2653*a412576eSMichael Tuexen #endif
26540554e01dSMichael Tuexen 		}
26550554e01dSMichael Tuexen 		tmr = &stcb->asoc.autoclose_timer;
26560554e01dSMichael Tuexen 		break;
2657f8829a4aSRandall Stewart 	case SCTP_TIMER_TYPE_STRRESET:
2658*a412576eSMichael Tuexen 		if ((inp == NULL) || (stcb == NULL) || (net != NULL)) {
2659*a412576eSMichael Tuexen #ifdef INVARIANTS
2660*a412576eSMichael Tuexen 			panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
2661*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2662*a412576eSMichael Tuexen #else
26636e55db54SRandall Stewart 			return;
2664*a412576eSMichael Tuexen #endif
2665f8829a4aSRandall Stewart 		}
2666f8829a4aSRandall Stewart 		tmr = &stcb->asoc.strreset_timer;
2667f8829a4aSRandall Stewart 		break;
26680554e01dSMichael Tuexen 	case SCTP_TIMER_TYPE_INPKILL:
26690554e01dSMichael Tuexen 		/*
26700554e01dSMichael Tuexen 		 * The inp is setup to die. We re-use the signature_chage
26710554e01dSMichael Tuexen 		 * timer since that has stopped and we are in the GONE
26720554e01dSMichael Tuexen 		 * state.
26730554e01dSMichael Tuexen 		 */
2674*a412576eSMichael Tuexen 		if ((inp == NULL) || (stcb != NULL) || (net != NULL)) {
2675*a412576eSMichael Tuexen #ifdef INVARIANTS
2676*a412576eSMichael Tuexen 			panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
2677*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2678*a412576eSMichael Tuexen #else
2679*a412576eSMichael Tuexen 			return;
2680*a412576eSMichael Tuexen #endif
2681*a412576eSMichael Tuexen 		}
26820554e01dSMichael Tuexen 		tmr = &inp->sctp_ep.signature_change;
26830554e01dSMichael Tuexen 		break;
26840554e01dSMichael Tuexen 	case SCTP_TIMER_TYPE_ASOCKILL:
2685*a412576eSMichael Tuexen 		if ((inp == NULL) || (stcb == NULL) || (net != NULL)) {
2686*a412576eSMichael Tuexen #ifdef INVARIANTS
2687*a412576eSMichael Tuexen 			panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
2688*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2689*a412576eSMichael Tuexen #else
26906e55db54SRandall Stewart 			return;
2691*a412576eSMichael Tuexen #endif
2692f8829a4aSRandall Stewart 		}
26930554e01dSMichael Tuexen 		tmr = &stcb->asoc.strreset_timer;
26940554e01dSMichael Tuexen 		break;
26950554e01dSMichael Tuexen 	case SCTP_TIMER_TYPE_ADDR_WQ:
2696*a412576eSMichael Tuexen 		if ((inp != NULL) || (stcb != NULL) || (net != NULL)) {
2697*a412576eSMichael Tuexen #ifdef INVARIANTS
2698*a412576eSMichael Tuexen 			panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
2699*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2700*a412576eSMichael Tuexen #else
2701*a412576eSMichael Tuexen 			return;
2702*a412576eSMichael Tuexen #endif
2703*a412576eSMichael Tuexen 		}
27040554e01dSMichael Tuexen 		tmr = &SCTP_BASE_INFO(addr_wq_timer);
2705f8829a4aSRandall Stewart 		break;
2706851b7298SRandall Stewart 	case SCTP_TIMER_TYPE_PRIM_DELETED:
2707*a412576eSMichael Tuexen 		if ((inp == NULL) || (stcb == NULL) || (net != NULL)) {
2708*a412576eSMichael Tuexen #ifdef INVARIANTS
2709*a412576eSMichael Tuexen 			panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p",
2710*a412576eSMichael Tuexen 			    t_type, inp, stcb, net);
2711*a412576eSMichael Tuexen #else
2712851b7298SRandall Stewart 			return;
2713*a412576eSMichael Tuexen #endif
2714851b7298SRandall Stewart 		}
2715851b7298SRandall Stewart 		tmr = &stcb->asoc.delete_prim_timer;
2716851b7298SRandall Stewart 		break;
2717f8829a4aSRandall Stewart 	default:
2718*a412576eSMichael Tuexen 		panic("Unknown timer type %d", t_type);
271960990c0cSMichael Tuexen 	}
2720*a412576eSMichael Tuexen 	KASSERT(tmr != NULL, ("tmr is NULL for timer type %d", t_type));
2721*a412576eSMichael Tuexen 	if ((tmr->type != SCTP_TIMER_TYPE_NONE) &&
2722*a412576eSMichael Tuexen 	    (tmr->type != t_type)) {
2723f8829a4aSRandall Stewart 		/*
2724f8829a4aSRandall Stewart 		 * Ok we have a timer that is under joint use. Cookie timer
2725f8829a4aSRandall Stewart 		 * per chance with the SEND timer. We therefore are NOT
2726f8829a4aSRandall Stewart 		 * running the timer that the caller wants stopped.  So just
2727f8829a4aSRandall Stewart 		 * return.
2728f8829a4aSRandall Stewart 		 */
2729*a412576eSMichael Tuexen 		SCTPDBG(SCTP_DEBUG_TIMER2,
2730*a412576eSMichael Tuexen 		    "shared timer type %d not running: inp=%p, stcb=%p, net=%p.\n",
2731*a412576eSMichael Tuexen 		    t_type, inp, stcb, net);
27326e55db54SRandall Stewart 		return;
2733f8829a4aSRandall Stewart 	}
2734ad81507eSRandall Stewart 	if ((t_type == SCTP_TIMER_TYPE_SEND) && (stcb != NULL)) {
2735f8829a4aSRandall Stewart 		stcb->asoc.num_send_timers_up--;
2736f8829a4aSRandall Stewart 		if (stcb->asoc.num_send_timers_up < 0) {
2737f8829a4aSRandall Stewart 			stcb->asoc.num_send_timers_up = 0;
2738f8829a4aSRandall Stewart 		}
2739f8829a4aSRandall Stewart 	}
2740f8829a4aSRandall Stewart 	tmr->self = NULL;
2741a5d547adSRandall Stewart 	tmr->stopped_from = from;
2742*a412576eSMichael Tuexen 	if (SCTP_OS_TIMER_STOP(&tmr->timer) == 1) {
2743*a412576eSMichael Tuexen 		KASSERT(tmr->ep == inp,
2744*a412576eSMichael Tuexen 		    ("sctp_timer_stop of type %d: inp = %p, tmr->inp = %p",
2745*a412576eSMichael Tuexen 		    t_type, inp, tmr->ep));
2746*a412576eSMichael Tuexen 		KASSERT(tmr->tcb == stcb,
2747*a412576eSMichael Tuexen 		    ("sctp_timer_stop of type %d: stcb = %p, tmr->stcb = %p",
2748*a412576eSMichael Tuexen 		    t_type, stcb, tmr->tcb));
2749*a412576eSMichael Tuexen 		KASSERT(((t_type == SCTP_TIMER_TYPE_ASCONF) && (tmr->net != NULL)) ||
2750*a412576eSMichael Tuexen 		    ((t_type != SCTP_TIMER_TYPE_ASCONF) && (tmr->net == net)),
2751*a412576eSMichael Tuexen 		    ("sctp_timer_stop of type %d: net = %p, tmr->net = %p",
2752*a412576eSMichael Tuexen 		    t_type, net, tmr->net));
2753*a412576eSMichael Tuexen 		SCTPDBG(SCTP_DEBUG_TIMER2,
2754*a412576eSMichael Tuexen 		    "timer type %d stopped: inp=%p, stcb=%p, net=%p.\n",
2755*a412576eSMichael Tuexen 		    t_type, inp, stcb, net);
2756*a412576eSMichael Tuexen 		tmr->ep = NULL;
2757*a412576eSMichael Tuexen 		tmr->tcb = NULL;
2758*a412576eSMichael Tuexen 		tmr->net = NULL;
2759*a412576eSMichael Tuexen 	} else {
2760*a412576eSMichael Tuexen 		SCTPDBG(SCTP_DEBUG_TIMER2,
2761*a412576eSMichael Tuexen 		    "timer type %d not stopped: inp=%p, stcb=%p, net=%p.\n",
2762*a412576eSMichael Tuexen 		    t_type, inp, stcb, net);
2763*a412576eSMichael Tuexen 	}
27646e55db54SRandall Stewart 	return;
2765f8829a4aSRandall Stewart }
2766f8829a4aSRandall Stewart 
2767f8829a4aSRandall Stewart uint32_t
2768b0471b4bSMichael Tuexen sctp_calculate_len(struct mbuf *m)
2769b0471b4bSMichael Tuexen {
2770f8829a4aSRandall Stewart 	uint32_t tlen = 0;
2771f8829a4aSRandall Stewart 	struct mbuf *at;
2772f8829a4aSRandall Stewart 
2773f8829a4aSRandall Stewart 	at = m;
2774f8829a4aSRandall Stewart 	while (at) {
2775139bc87fSRandall Stewart 		tlen += SCTP_BUF_LEN(at);
2776139bc87fSRandall Stewart 		at = SCTP_BUF_NEXT(at);
2777f8829a4aSRandall Stewart 	}
2778f8829a4aSRandall Stewart 	return (tlen);
2779f8829a4aSRandall Stewart }
2780f8829a4aSRandall Stewart 
2781f8829a4aSRandall Stewart void
2782f8829a4aSRandall Stewart sctp_mtu_size_reset(struct sctp_inpcb *inp,
278344b7479bSRandall Stewart     struct sctp_association *asoc, uint32_t mtu)
2784f8829a4aSRandall Stewart {
2785f8829a4aSRandall Stewart 	/*
2786f8829a4aSRandall Stewart 	 * Reset the P-MTU size on this association, this involves changing
2787f8829a4aSRandall Stewart 	 * the asoc MTU, going through ANY chunk+overhead larger than mtu to
2788f8829a4aSRandall Stewart 	 * allow the DF flag to be cleared.
2789f8829a4aSRandall Stewart 	 */
2790f8829a4aSRandall Stewart 	struct sctp_tmit_chunk *chk;
2791f8829a4aSRandall Stewart 	unsigned int eff_mtu, ovh;
2792f8829a4aSRandall Stewart 
2793f8829a4aSRandall Stewart 	asoc->smallest_mtu = mtu;
2794f8829a4aSRandall Stewart 	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
2795f8829a4aSRandall Stewart 		ovh = SCTP_MIN_OVERHEAD;
2796f8829a4aSRandall Stewart 	} else {
2797f8829a4aSRandall Stewart 		ovh = SCTP_MIN_V4_OVERHEAD;
2798f8829a4aSRandall Stewart 	}
2799f8829a4aSRandall Stewart 	eff_mtu = mtu - ovh;
2800f8829a4aSRandall Stewart 	TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) {
2801f8829a4aSRandall Stewart 		if (chk->send_size > eff_mtu) {
2802f8829a4aSRandall Stewart 			chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
2803f8829a4aSRandall Stewart 		}
2804f8829a4aSRandall Stewart 	}
2805f8829a4aSRandall Stewart 	TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) {
2806f8829a4aSRandall Stewart 		if (chk->send_size > eff_mtu) {
2807f8829a4aSRandall Stewart 			chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
2808f8829a4aSRandall Stewart 		}
2809f8829a4aSRandall Stewart 	}
2810f8829a4aSRandall Stewart }
2811f8829a4aSRandall Stewart 
2812f8829a4aSRandall Stewart 
2813f8829a4aSRandall Stewart /*
281444f2a327SMichael Tuexen  * Given an association and starting time of the current RTT period, update
281544f2a327SMichael Tuexen  * RTO in number of msecs. net should point to the current network.
281644f2a327SMichael Tuexen  * Return 1, if an RTO update was performed, return 0 if no update was
281744f2a327SMichael Tuexen  * performed due to invalid starting point.
2818f8829a4aSRandall Stewart  */
2819899288aeSRandall Stewart 
282044f2a327SMichael Tuexen int
2821f8829a4aSRandall Stewart sctp_calculate_rto(struct sctp_tcb *stcb,
2822f8829a4aSRandall Stewart     struct sctp_association *asoc,
2823f8829a4aSRandall Stewart     struct sctp_nets *net,
28248c8e10b7SMichael Tuexen     struct timeval *old,
2825b0471b4bSMichael Tuexen     int rtt_from_sack)
2826b0471b4bSMichael Tuexen {
282744f2a327SMichael Tuexen 	struct timeval now;
282844f2a327SMichael Tuexen 	uint64_t rtt_us;	/* RTT in us */
2829be1d9176SMichael Tuexen 	int32_t rtt;		/* RTT in ms */
2830be1d9176SMichael Tuexen 	uint32_t new_rto;
2831f8829a4aSRandall Stewart 	int first_measure = 0;
2832f8829a4aSRandall Stewart 
2833f8829a4aSRandall Stewart 	/************************/
2834f8829a4aSRandall Stewart 	/* 1. calculate new RTT */
2835f8829a4aSRandall Stewart 	/************************/
2836f8829a4aSRandall Stewart 	/* get the current time */
2837299108c5SRandall Stewart 	if (stcb->asoc.use_precise_time) {
2838299108c5SRandall Stewart 		(void)SCTP_GETPTIME_TIMEVAL(&now);
2839299108c5SRandall Stewart 	} else {
28406e55db54SRandall Stewart 		(void)SCTP_GETTIME_TIMEVAL(&now);
2841299108c5SRandall Stewart 	}
284244f2a327SMichael Tuexen 	if ((old->tv_sec > now.tv_sec) ||
284344f2a327SMichael Tuexen 	    ((old->tv_sec == now.tv_sec) && (old->tv_sec > now.tv_sec))) {
284444f2a327SMichael Tuexen 		/* The starting point is in the future. */
284544f2a327SMichael Tuexen 		return (0);
284644f2a327SMichael Tuexen 	}
2847be1d9176SMichael Tuexen 	timevalsub(&now, old);
284844f2a327SMichael Tuexen 	rtt_us = (uint64_t)1000000 * (uint64_t)now.tv_sec + (uint64_t)now.tv_usec;
284944f2a327SMichael Tuexen 	if (rtt_us > SCTP_RTO_UPPER_BOUND * 1000) {
285044f2a327SMichael Tuexen 		/* The RTT is larger than a sane value. */
285144f2a327SMichael Tuexen 		return (0);
285244f2a327SMichael Tuexen 	}
2853be1d9176SMichael Tuexen 	/* store the current RTT in us */
285444f2a327SMichael Tuexen 	net->rtt = rtt_us;
2855b60b0fe6SMichael Tuexen 	/* compute rtt in ms */
2856b60b0fe6SMichael Tuexen 	rtt = (int32_t)(net->rtt / 1000);
2857f79aab18SRandall Stewart 	if ((asoc->cc_functions.sctp_rtt_calculated) && (rtt_from_sack == SCTP_RTT_FROM_DATA)) {
2858b7b84c0eSMichael Tuexen 		/*
2859b7b84c0eSMichael Tuexen 		 * Tell the CC module that a new update has just occurred
2860b7b84c0eSMichael Tuexen 		 * from a sack
2861b7b84c0eSMichael Tuexen 		 */
2862f79aab18SRandall Stewart 		(*asoc->cc_functions.sctp_rtt_calculated) (stcb, net, &now);
2863f79aab18SRandall Stewart 	}
2864f79aab18SRandall Stewart 	/*
2865f79aab18SRandall Stewart 	 * Do we need to determine the lan? We do this only on sacks i.e.
2866f79aab18SRandall Stewart 	 * RTT being determined from data not non-data (HB/INIT->INITACK).
2867f79aab18SRandall Stewart 	 */
2868f79aab18SRandall Stewart 	if ((rtt_from_sack == SCTP_RTT_FROM_DATA) &&
2869be1d9176SMichael Tuexen 	    (net->lan_type == SCTP_LAN_UNKNOWN)) {
2870be1d9176SMichael Tuexen 		if (net->rtt > SCTP_LOCAL_LAN_RTT) {
2871899288aeSRandall Stewart 			net->lan_type = SCTP_LAN_INTERNET;
2872899288aeSRandall Stewart 		} else {
2873899288aeSRandall Stewart 			net->lan_type = SCTP_LAN_LOCAL;
2874899288aeSRandall Stewart 		}
2875899288aeSRandall Stewart 	}
28760053ed28SMichael Tuexen 
2877f8829a4aSRandall Stewart 	/***************************/
2878f8829a4aSRandall Stewart 	/* 2. update RTTVAR & SRTT */
2879f8829a4aSRandall Stewart 	/***************************/
2880be1d9176SMichael Tuexen 	/*-
2881be1d9176SMichael Tuexen 	 * Compute the scaled average lastsa and the
2882be1d9176SMichael Tuexen 	 * scaled variance lastsv as described in van Jacobson
2883be1d9176SMichael Tuexen 	 * Paper "Congestion Avoidance and Control", Annex A.
2884be1d9176SMichael Tuexen 	 *
2885be1d9176SMichael Tuexen 	 * (net->lastsa >> SCTP_RTT_SHIFT) is the srtt
288644f2a327SMichael Tuexen 	 * (net->lastsv >> SCTP_RTT_VAR_SHIFT) is the rttvar
2887be1d9176SMichael Tuexen 	 */
28889a972525SRandall Stewart 	if (net->RTO_measured) {
2889be1d9176SMichael Tuexen 		rtt -= (net->lastsa >> SCTP_RTT_SHIFT);
2890be1d9176SMichael Tuexen 		net->lastsa += rtt;
2891be1d9176SMichael Tuexen 		if (rtt < 0) {
2892be1d9176SMichael Tuexen 			rtt = -rtt;
2893be1d9176SMichael Tuexen 		}
2894be1d9176SMichael Tuexen 		rtt -= (net->lastsv >> SCTP_RTT_VAR_SHIFT);
2895be1d9176SMichael Tuexen 		net->lastsv += rtt;
2896b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RTTVAR_LOGGING_ENABLE) {
2897f8829a4aSRandall Stewart 			rto_logging(net, SCTP_LOG_RTTVAR);
289880fefe0aSRandall Stewart 		}
2899f8829a4aSRandall Stewart 	} else {
2900f8829a4aSRandall Stewart 		/* First RTO measurment */
29019a972525SRandall Stewart 		net->RTO_measured = 1;
2902f8829a4aSRandall Stewart 		first_measure = 1;
2903be1d9176SMichael Tuexen 		net->lastsa = rtt << SCTP_RTT_SHIFT;
2904be1d9176SMichael Tuexen 		net->lastsv = (rtt / 2) << SCTP_RTT_VAR_SHIFT;
2905b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RTTVAR_LOGGING_ENABLE) {
2906f8829a4aSRandall Stewart 			rto_logging(net, SCTP_LOG_INITIAL_RTT);
290780fefe0aSRandall Stewart 		}
2908f8829a4aSRandall Stewart 	}
2909be1d9176SMichael Tuexen 	if (net->lastsv == 0) {
2910be1d9176SMichael Tuexen 		net->lastsv = SCTP_CLOCK_GRANULARITY;
2911be1d9176SMichael Tuexen 	}
2912108df27cSRandall Stewart 	new_rto = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv;
2913f8829a4aSRandall Stewart 	if ((new_rto > SCTP_SAT_NETWORK_MIN) &&
2914f8829a4aSRandall Stewart 	    (stcb->asoc.sat_network_lockout == 0)) {
2915f8829a4aSRandall Stewart 		stcb->asoc.sat_network = 1;
2916f8829a4aSRandall Stewart 	} else if ((!first_measure) && stcb->asoc.sat_network) {
2917f8829a4aSRandall Stewart 		stcb->asoc.sat_network = 0;
2918f8829a4aSRandall Stewart 		stcb->asoc.sat_network_lockout = 1;
2919f8829a4aSRandall Stewart 	}
2920f8829a4aSRandall Stewart 	/* bound it, per C6/C7 in Section 5.3.1 */
2921f8829a4aSRandall Stewart 	if (new_rto < stcb->asoc.minrto) {
2922f8829a4aSRandall Stewart 		new_rto = stcb->asoc.minrto;
2923f8829a4aSRandall Stewart 	}
2924f8829a4aSRandall Stewart 	if (new_rto > stcb->asoc.maxrto) {
2925f8829a4aSRandall Stewart 		new_rto = stcb->asoc.maxrto;
2926f8829a4aSRandall Stewart 	}
292744f2a327SMichael Tuexen 	net->RTO = new_rto;
292844f2a327SMichael Tuexen 	return (1);
2929f8829a4aSRandall Stewart }
2930f8829a4aSRandall Stewart 
2931f8829a4aSRandall Stewart /*
2932f8829a4aSRandall Stewart  * return a pointer to a contiguous piece of data from the given mbuf chain
2933f8829a4aSRandall Stewart  * starting at 'off' for 'len' bytes.  If the desired piece spans more than
2934f8829a4aSRandall Stewart  * one mbuf, a copy is made at 'ptr'. caller must ensure that the buffer size
2935f8829a4aSRandall Stewart  * is >= 'len' returns NULL if there there isn't 'len' bytes in the chain.
2936f8829a4aSRandall Stewart  */
293772fb6fdbSRandall Stewart caddr_t
2938f8829a4aSRandall Stewart sctp_m_getptr(struct mbuf *m, int off, int len, uint8_t *in_ptr)
2939f8829a4aSRandall Stewart {
2940f8829a4aSRandall Stewart 	uint32_t count;
2941f8829a4aSRandall Stewart 	uint8_t *ptr;
2942f8829a4aSRandall Stewart 
2943f8829a4aSRandall Stewart 	ptr = in_ptr;
2944f8829a4aSRandall Stewart 	if ((off < 0) || (len <= 0))
2945f8829a4aSRandall Stewart 		return (NULL);
2946f8829a4aSRandall Stewart 
2947f8829a4aSRandall Stewart 	/* find the desired start location */
2948f8829a4aSRandall Stewart 	while ((m != NULL) && (off > 0)) {
2949139bc87fSRandall Stewart 		if (off < SCTP_BUF_LEN(m))
2950f8829a4aSRandall Stewart 			break;
2951139bc87fSRandall Stewart 		off -= SCTP_BUF_LEN(m);
2952139bc87fSRandall Stewart 		m = SCTP_BUF_NEXT(m);
2953f8829a4aSRandall Stewart 	}
2954f8829a4aSRandall Stewart 	if (m == NULL)
2955f8829a4aSRandall Stewart 		return (NULL);
2956f8829a4aSRandall Stewart 
2957f8829a4aSRandall Stewart 	/* is the current mbuf large enough (eg. contiguous)? */
2958139bc87fSRandall Stewart 	if ((SCTP_BUF_LEN(m) - off) >= len) {
2959f8829a4aSRandall Stewart 		return (mtod(m, caddr_t)+off);
2960f8829a4aSRandall Stewart 	} else {
2961f8829a4aSRandall Stewart 		/* else, it spans more than one mbuf, so save a temp copy... */
2962f8829a4aSRandall Stewart 		while ((m != NULL) && (len > 0)) {
2963139bc87fSRandall Stewart 			count = min(SCTP_BUF_LEN(m) - off, len);
29645ba7f91fSMichael Tuexen 			memcpy(ptr, mtod(m, caddr_t)+off, count);
2965f8829a4aSRandall Stewart 			len -= count;
2966f8829a4aSRandall Stewart 			ptr += count;
2967f8829a4aSRandall Stewart 			off = 0;
2968139bc87fSRandall Stewart 			m = SCTP_BUF_NEXT(m);
2969f8829a4aSRandall Stewart 		}
2970f8829a4aSRandall Stewart 		if ((m == NULL) && (len > 0))
2971f8829a4aSRandall Stewart 			return (NULL);
2972f8829a4aSRandall Stewart 		else
2973f8829a4aSRandall Stewart 			return ((caddr_t)in_ptr);
2974f8829a4aSRandall Stewart 	}
2975f8829a4aSRandall Stewart }
2976f8829a4aSRandall Stewart 
2977f8829a4aSRandall Stewart 
297844b7479bSRandall Stewart 
2979f8829a4aSRandall Stewart struct sctp_paramhdr *
2980f8829a4aSRandall Stewart sctp_get_next_param(struct mbuf *m,
2981f8829a4aSRandall Stewart     int offset,
2982f8829a4aSRandall Stewart     struct sctp_paramhdr *pull,
2983f8829a4aSRandall Stewart     int pull_limit)
2984f8829a4aSRandall Stewart {
2985f8829a4aSRandall Stewart 	/* This just provides a typed signature to Peter's Pull routine */
2986f8829a4aSRandall Stewart 	return ((struct sctp_paramhdr *)sctp_m_getptr(m, offset, pull_limit,
2987f8829a4aSRandall Stewart 	    (uint8_t *)pull));
2988f8829a4aSRandall Stewart }
2989f8829a4aSRandall Stewart 
2990f8829a4aSRandall Stewart 
2991ce11b842SMichael Tuexen struct mbuf *
2992f8829a4aSRandall Stewart sctp_add_pad_tombuf(struct mbuf *m, int padlen)
2993f8829a4aSRandall Stewart {
2994ce11b842SMichael Tuexen 	struct mbuf *m_last;
2995ce11b842SMichael Tuexen 	caddr_t dp;
2996f8829a4aSRandall Stewart 
2997f8829a4aSRandall Stewart 	if (padlen > 3) {
2998ce11b842SMichael Tuexen 		return (NULL);
2999f8829a4aSRandall Stewart 	}
300041eee555SRandall Stewart 	if (padlen <= M_TRAILINGSPACE(m)) {
3001f8829a4aSRandall Stewart 		/*
3002f8829a4aSRandall Stewart 		 * The easy way. We hope the majority of the time we hit
3003f8829a4aSRandall Stewart 		 * here :)
3004f8829a4aSRandall Stewart 		 */
3005ce11b842SMichael Tuexen 		m_last = m;
3006f8829a4aSRandall Stewart 	} else {
3007ce11b842SMichael Tuexen 		/* Hard way we must grow the mbuf chain */
3008ce11b842SMichael Tuexen 		m_last = sctp_get_mbuf_for_msg(padlen, 0, M_NOWAIT, 1, MT_DATA);
3009ce11b842SMichael Tuexen 		if (m_last == NULL) {
3010ce11b842SMichael Tuexen 			return (NULL);
3011f8829a4aSRandall Stewart 		}
3012ce11b842SMichael Tuexen 		SCTP_BUF_LEN(m_last) = 0;
3013ce11b842SMichael Tuexen 		SCTP_BUF_NEXT(m_last) = NULL;
3014ce11b842SMichael Tuexen 		SCTP_BUF_NEXT(m) = m_last;
3015f8829a4aSRandall Stewart 	}
3016ce11b842SMichael Tuexen 	dp = mtod(m_last, caddr_t)+SCTP_BUF_LEN(m_last);
3017ce11b842SMichael Tuexen 	SCTP_BUF_LEN(m_last) += padlen;
3018ce11b842SMichael Tuexen 	memset(dp, 0, padlen);
3019ce11b842SMichael Tuexen 	return (m_last);
3020f8829a4aSRandall Stewart }
3021f8829a4aSRandall Stewart 
3022ce11b842SMichael Tuexen struct mbuf *
3023f8829a4aSRandall Stewart sctp_pad_lastmbuf(struct mbuf *m, int padval, struct mbuf *last_mbuf)
3024f8829a4aSRandall Stewart {
3025f8829a4aSRandall Stewart 	/* find the last mbuf in chain and pad it */
3026f8829a4aSRandall Stewart 	struct mbuf *m_at;
3027f8829a4aSRandall Stewart 
3028ce11b842SMichael Tuexen 	if (last_mbuf != NULL) {
3029f8829a4aSRandall Stewart 		return (sctp_add_pad_tombuf(last_mbuf, padval));
3030f8829a4aSRandall Stewart 	} else {
303117267b32SMichael Tuexen 		for (m_at = m; m_at; m_at = SCTP_BUF_NEXT(m_at)) {
3032139bc87fSRandall Stewart 			if (SCTP_BUF_NEXT(m_at) == NULL) {
3033f8829a4aSRandall Stewart 				return (sctp_add_pad_tombuf(m_at, padval));
3034f8829a4aSRandall Stewart 			}
3035f8829a4aSRandall Stewart 		}
3036f8829a4aSRandall Stewart 	}
3037ce11b842SMichael Tuexen 	return (NULL);
3038f8829a4aSRandall Stewart }
3039f8829a4aSRandall Stewart 
3040f8829a4aSRandall Stewart static void
3041c5b5675dSMichael Tuexen sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb,
3042410a3b1eSMichael Tuexen     uint16_t error, struct sctp_abort_chunk *abort, uint8_t from_peer, int so_locked
3043ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
3044ceaad40aSRandall Stewart     SCTP_UNUSED
3045ceaad40aSRandall Stewart #endif
3046ceaad40aSRandall Stewart )
3047f8829a4aSRandall Stewart {
3048f8829a4aSRandall Stewart 	struct mbuf *m_notify;
3049f8829a4aSRandall Stewart 	struct sctp_assoc_change *sac;
3050f8829a4aSRandall Stewart 	struct sctp_queued_to_read *control;
30519a8e3088SMichael Tuexen 	unsigned int notif_len;
30529a8e3088SMichael Tuexen 	uint16_t abort_len;
3053e06b67c7SMichael Tuexen 	unsigned int i;
3054ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
3055ceaad40aSRandall Stewart 	struct socket *so;
3056ceaad40aSRandall Stewart #endif
3057ceaad40aSRandall Stewart 
305859713bbfSMichael Tuexen 	if (stcb == NULL) {
305959713bbfSMichael Tuexen 		return;
306059713bbfSMichael Tuexen 	}
306158411b08SMichael Tuexen 	if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT)) {
30629a8e3088SMichael Tuexen 		notif_len = (unsigned int)sizeof(struct sctp_assoc_change);
3063a2b42326SMichael Tuexen 		if (abort != NULL) {
3064c9eb4473SMichael Tuexen 			abort_len = ntohs(abort->ch.chunk_length);
30659669e724SMichael Tuexen 			/*
30669669e724SMichael Tuexen 			 * Only SCTP_CHUNK_BUFFER_SIZE are guaranteed to be
306745d41de5SMichael Tuexen 			 * contiguous.
30689669e724SMichael Tuexen 			 */
30699669e724SMichael Tuexen 			if (abort_len > SCTP_CHUNK_BUFFER_SIZE) {
30709669e724SMichael Tuexen 				abort_len = SCTP_CHUNK_BUFFER_SIZE;
30719669e724SMichael Tuexen 			}
3072a2b42326SMichael Tuexen 		} else {
3073a2b42326SMichael Tuexen 			abort_len = 0;
3074c5b5675dSMichael Tuexen 		}
3075a2b42326SMichael Tuexen 		if ((state == SCTP_COMM_UP) || (state == SCTP_RESTART)) {
3076a2b42326SMichael Tuexen 			notif_len += SCTP_ASSOC_SUPPORTS_MAX;
3077a2b42326SMichael Tuexen 		} else if ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC)) {
3078a2b42326SMichael Tuexen 			notif_len += abort_len;
3079a2b42326SMichael Tuexen 		}
3080eb1b1807SGleb Smirnoff 		m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA);
3081a2b42326SMichael Tuexen 		if (m_notify == NULL) {
3082a2b42326SMichael Tuexen 			/* Retry with smaller value. */
30839a8e3088SMichael Tuexen 			notif_len = (unsigned int)sizeof(struct sctp_assoc_change);
3084eb1b1807SGleb Smirnoff 			m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA);
3085a2b42326SMichael Tuexen 			if (m_notify == NULL) {
308658411b08SMichael Tuexen 				goto set_error;
3087a2b42326SMichael Tuexen 			}
3088a2b42326SMichael Tuexen 		}
3089a2b42326SMichael Tuexen 		SCTP_BUF_NEXT(m_notify) = NULL;
3090f8829a4aSRandall Stewart 		sac = mtod(m_notify, struct sctp_assoc_change *);
3091e432298aSXin LI 		memset(sac, 0, notif_len);
3092f8829a4aSRandall Stewart 		sac->sac_type = SCTP_ASSOC_CHANGE;
3093f8829a4aSRandall Stewart 		sac->sac_flags = 0;
3094f8829a4aSRandall Stewart 		sac->sac_length = sizeof(struct sctp_assoc_change);
3095c5b5675dSMichael Tuexen 		sac->sac_state = state;
3096f8829a4aSRandall Stewart 		sac->sac_error = error;
3097f8829a4aSRandall Stewart 		/* XXX verify these stream counts */
3098f8829a4aSRandall Stewart 		sac->sac_outbound_streams = stcb->asoc.streamoutcnt;
3099f8829a4aSRandall Stewart 		sac->sac_inbound_streams = stcb->asoc.streamincnt;
3100f8829a4aSRandall Stewart 		sac->sac_assoc_id = sctp_get_associd(stcb);
3101a2b42326SMichael Tuexen 		if (notif_len > sizeof(struct sctp_assoc_change)) {
3102c5b5675dSMichael Tuexen 			if ((state == SCTP_COMM_UP) || (state == SCTP_RESTART)) {
3103e06b67c7SMichael Tuexen 				i = 0;
3104c79bec9cSMichael Tuexen 				if (stcb->asoc.prsctp_supported == 1) {
3105e06b67c7SMichael Tuexen 					sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_PR;
3106e06b67c7SMichael Tuexen 				}
3107c79bec9cSMichael Tuexen 				if (stcb->asoc.auth_supported == 1) {
3108e06b67c7SMichael Tuexen 					sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_AUTH;
3109e06b67c7SMichael Tuexen 				}
3110c79bec9cSMichael Tuexen 				if (stcb->asoc.asconf_supported == 1) {
3111e06b67c7SMichael Tuexen 					sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_ASCONF;
3112e06b67c7SMichael Tuexen 				}
311344249214SRandall Stewart 				if (stcb->asoc.idata_supported == 1) {
311444249214SRandall Stewart 					sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_INTERLEAVING;
311544249214SRandall Stewart 				}
3116e06b67c7SMichael Tuexen 				sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_MULTIBUF;
3117c79bec9cSMichael Tuexen 				if (stcb->asoc.reconfig_supported == 1) {
3118e06b67c7SMichael Tuexen 					sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_RE_CONFIG;
3119e06b67c7SMichael Tuexen 				}
3120e06b67c7SMichael Tuexen 				sac->sac_length += i;
3121a2b42326SMichael Tuexen 			} else if ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC)) {
3122a2b42326SMichael Tuexen 				memcpy(sac->sac_info, abort, abort_len);
3123a2b42326SMichael Tuexen 				sac->sac_length += abort_len;
3124a2b42326SMichael Tuexen 			}
3125c5b5675dSMichael Tuexen 		}
3126e06b67c7SMichael Tuexen 		SCTP_BUF_LEN(m_notify) = sac->sac_length;
3127f8829a4aSRandall Stewart 		control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
31287215cc1bSMichael Tuexen 		    0, 0, stcb->asoc.context, 0, 0, 0,
3129f8829a4aSRandall Stewart 		    m_notify);
313058411b08SMichael Tuexen 		if (control != NULL) {
3131139bc87fSRandall Stewart 			control->length = SCTP_BUF_LEN(m_notify);
313228cd0699SMichael Tuexen 			control->spec_flags = M_NOTIFICATION;
3133f8829a4aSRandall Stewart 			/* not that we need this */
3134f8829a4aSRandall Stewart 			control->tail_mbuf = m_notify;
3135f8829a4aSRandall Stewart 			sctp_add_to_readq(stcb->sctp_ep, stcb,
3136f8829a4aSRandall Stewart 			    control,
3137cfde3ff7SRandall Stewart 			    &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD,
3138cfde3ff7SRandall Stewart 			    so_locked);
313958411b08SMichael Tuexen 		} else {
314058411b08SMichael Tuexen 			sctp_m_freem(m_notify);
314158411b08SMichael Tuexen 		}
314258411b08SMichael Tuexen 	}
314358411b08SMichael Tuexen 	/*
314458411b08SMichael Tuexen 	 * For 1-to-1 style sockets, we send up and error when an ABORT
314558411b08SMichael Tuexen 	 * comes in.
314658411b08SMichael Tuexen 	 */
314758411b08SMichael Tuexen set_error:
314858411b08SMichael Tuexen 	if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
314958411b08SMichael Tuexen 	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) &&
315058411b08SMichael Tuexen 	    ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC))) {
3151e045904fSMichael Tuexen 		SOCK_LOCK(stcb->sctp_socket);
3152410a3b1eSMichael Tuexen 		if (from_peer) {
3153839d21d6SMichael Tuexen 			if (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) {
315458411b08SMichael Tuexen 				SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNREFUSED);
315558411b08SMichael Tuexen 				stcb->sctp_socket->so_error = ECONNREFUSED;
315658411b08SMichael Tuexen 			} else {
315758411b08SMichael Tuexen 				SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET);
315858411b08SMichael Tuexen 				stcb->sctp_socket->so_error = ECONNRESET;
315958411b08SMichael Tuexen 			}
3160410a3b1eSMichael Tuexen 		} else {
3161839d21d6SMichael Tuexen 			if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) ||
3162839d21d6SMichael Tuexen 			    (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) {
3163553bb068SMichael Tuexen 				SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ETIMEDOUT);
3164553bb068SMichael Tuexen 				stcb->sctp_socket->so_error = ETIMEDOUT;
3165553bb068SMichael Tuexen 			} else {
3166410a3b1eSMichael Tuexen 				SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNABORTED);
3167410a3b1eSMichael Tuexen 				stcb->sctp_socket->so_error = ECONNABORTED;
3168410a3b1eSMichael Tuexen 			}
316958411b08SMichael Tuexen 		}
31703acfe1e1SGleb Smirnoff 		SOCK_UNLOCK(stcb->sctp_socket);
3171553bb068SMichael Tuexen 	}
317258411b08SMichael Tuexen 	/* Wake ANY sleepers */
3173ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
3174ceaad40aSRandall Stewart 	so = SCTP_INP_SO(stcb->sctp_ep);
3175ceaad40aSRandall Stewart 	if (!so_locked) {
3176ceaad40aSRandall Stewart 		atomic_add_int(&stcb->asoc.refcnt, 1);
3177ceaad40aSRandall Stewart 		SCTP_TCB_UNLOCK(stcb);
3178ceaad40aSRandall Stewart 		SCTP_SOCKET_LOCK(so, 1);
3179ceaad40aSRandall Stewart 		SCTP_TCB_LOCK(stcb);
3180ceaad40aSRandall Stewart 		atomic_subtract_int(&stcb->asoc.refcnt, 1);
3181ceaad40aSRandall Stewart 		if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
3182ceaad40aSRandall Stewart 			SCTP_SOCKET_UNLOCK(so, 1);
3183ceaad40aSRandall Stewart 			return;
3184ceaad40aSRandall Stewart 		}
3185ceaad40aSRandall Stewart 	}
3186ceaad40aSRandall Stewart #endif
318758411b08SMichael Tuexen 	if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
318858411b08SMichael Tuexen 	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) &&
318958411b08SMichael Tuexen 	    ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC))) {
31903acfe1e1SGleb Smirnoff 		socantrcvmore(stcb->sctp_socket);
319158411b08SMichael Tuexen 	}
319258411b08SMichael Tuexen 	sorwakeup(stcb->sctp_socket);
319358411b08SMichael Tuexen 	sowwakeup(stcb->sctp_socket);
3194ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
3195ceaad40aSRandall Stewart 	if (!so_locked) {
3196ceaad40aSRandall Stewart 		SCTP_SOCKET_UNLOCK(so, 1);
3197ceaad40aSRandall Stewart 	}
3198ceaad40aSRandall Stewart #endif
3199f8829a4aSRandall Stewart }
3200f8829a4aSRandall Stewart 
3201f8829a4aSRandall Stewart static void
3202f8829a4aSRandall Stewart sctp_notify_peer_addr_change(struct sctp_tcb *stcb, uint32_t state,
32033cb3567dSMichael Tuexen     struct sockaddr *sa, uint32_t error, int so_locked
32043cb3567dSMichael Tuexen #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
32053cb3567dSMichael Tuexen     SCTP_UNUSED
32063cb3567dSMichael Tuexen #endif
32073cb3567dSMichael Tuexen )
3208f8829a4aSRandall Stewart {
3209f8829a4aSRandall Stewart 	struct mbuf *m_notify;
3210f8829a4aSRandall Stewart 	struct sctp_paddr_change *spc;
3211f8829a4aSRandall Stewart 	struct sctp_queued_to_read *control;
3212f8829a4aSRandall Stewart 
321360990c0cSMichael Tuexen 	if ((stcb == NULL) ||
321460990c0cSMichael Tuexen 	    sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT)) {
3215f8829a4aSRandall Stewart 		/* event not enabled */
3216f8829a4aSRandall Stewart 		return;
3217830d754dSRandall Stewart 	}
3218eb1b1807SGleb Smirnoff 	m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_paddr_change), 0, M_NOWAIT, 1, MT_DATA);
3219f8829a4aSRandall Stewart 	if (m_notify == NULL)
3220f8829a4aSRandall Stewart 		return;
3221139bc87fSRandall Stewart 	SCTP_BUF_LEN(m_notify) = 0;
3222f8829a4aSRandall Stewart 	spc = mtod(m_notify, struct sctp_paddr_change *);
322356711f94SMichael Tuexen 	memset(spc, 0, sizeof(struct sctp_paddr_change));
3224f8829a4aSRandall Stewart 	spc->spc_type = SCTP_PEER_ADDR_CHANGE;
3225f8829a4aSRandall Stewart 	spc->spc_flags = 0;
3226f8829a4aSRandall Stewart 	spc->spc_length = sizeof(struct sctp_paddr_change);
32275e2c2d87SRandall Stewart 	switch (sa->sa_family) {
3228ea5eba11SMichael Tuexen #ifdef INET
32295e2c2d87SRandall Stewart 	case AF_INET:
3230d59107f7SMichael Tuexen #ifdef INET6
3231d59107f7SMichael Tuexen 		if (sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
3232d59107f7SMichael Tuexen 			in6_sin_2_v4mapsin6((struct sockaddr_in *)sa,
3233d59107f7SMichael Tuexen 			    (struct sockaddr_in6 *)&spc->spc_aaddr);
3234d59107f7SMichael Tuexen 		} else {
3235f8829a4aSRandall Stewart 			memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in));
3236d59107f7SMichael Tuexen 		}
3237d59107f7SMichael Tuexen #else
3238d59107f7SMichael Tuexen 		memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in));
3239d59107f7SMichael Tuexen #endif
32405e2c2d87SRandall Stewart 		break;
3241ea5eba11SMichael Tuexen #endif
32425e2c2d87SRandall Stewart #ifdef INET6
32435e2c2d87SRandall Stewart 	case AF_INET6:
32445e2c2d87SRandall Stewart 		{
3245f42a358aSRandall Stewart 			struct sockaddr_in6 *sin6;
3246f42a358aSRandall Stewart 
3247f8829a4aSRandall Stewart 			memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in6));
3248f42a358aSRandall Stewart 
3249f42a358aSRandall Stewart 			sin6 = (struct sockaddr_in6 *)&spc->spc_aaddr;
3250f42a358aSRandall Stewart 			if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) {
325142551e99SRandall Stewart 				if (sin6->sin6_scope_id == 0) {
325242551e99SRandall Stewart 					/* recover scope_id for user */
3253f42a358aSRandall Stewart 					(void)sa6_recoverscope(sin6);
325442551e99SRandall Stewart 				} else {
325542551e99SRandall Stewart 					/* clear embedded scope_id for user */
325642551e99SRandall Stewart 					in6_clearscope(&sin6->sin6_addr);
325742551e99SRandall Stewart 				}
3258f42a358aSRandall Stewart 			}
32595e2c2d87SRandall Stewart 			break;
32605e2c2d87SRandall Stewart 		}
32615e2c2d87SRandall Stewart #endif
32625e2c2d87SRandall Stewart 	default:
32635e2c2d87SRandall Stewart 		/* TSNH */
32645e2c2d87SRandall Stewart 		break;
3265f8829a4aSRandall Stewart 	}
3266f8829a4aSRandall Stewart 	spc->spc_state = state;
3267f8829a4aSRandall Stewart 	spc->spc_error = error;
3268f8829a4aSRandall Stewart 	spc->spc_assoc_id = sctp_get_associd(stcb);
3269f8829a4aSRandall Stewart 
3270139bc87fSRandall Stewart 	SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_paddr_change);
3271139bc87fSRandall Stewart 	SCTP_BUF_NEXT(m_notify) = NULL;
3272f8829a4aSRandall Stewart 
3273f8829a4aSRandall Stewart 	/* append to socket */
3274f8829a4aSRandall Stewart 	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
32757215cc1bSMichael Tuexen 	    0, 0, stcb->asoc.context, 0, 0, 0,
3276f8829a4aSRandall Stewart 	    m_notify);
3277f8829a4aSRandall Stewart 	if (control == NULL) {
3278f8829a4aSRandall Stewart 		/* no memory */
3279f8829a4aSRandall Stewart 		sctp_m_freem(m_notify);
3280f8829a4aSRandall Stewart 		return;
3281f8829a4aSRandall Stewart 	}
3282139bc87fSRandall Stewart 	control->length = SCTP_BUF_LEN(m_notify);
3283139bc87fSRandall Stewart 	control->spec_flags = M_NOTIFICATION;
3284f8829a4aSRandall Stewart 	/* not that we need this */
3285f8829a4aSRandall Stewart 	control->tail_mbuf = m_notify;
3286f8829a4aSRandall Stewart 	sctp_add_to_readq(stcb->sctp_ep, stcb,
3287f8829a4aSRandall Stewart 	    control,
3288cfde3ff7SRandall Stewart 	    &stcb->sctp_socket->so_rcv, 1,
3289cfde3ff7SRandall Stewart 	    SCTP_READ_LOCK_NOT_HELD,
32903cb3567dSMichael Tuexen 	    so_locked);
3291f8829a4aSRandall Stewart }
3292f8829a4aSRandall Stewart 
3293f8829a4aSRandall Stewart 
3294f8829a4aSRandall Stewart static void
32951edc9dbaSMichael Tuexen sctp_notify_send_failed(struct sctp_tcb *stcb, uint8_t sent, uint32_t error,
3296ceaad40aSRandall Stewart     struct sctp_tmit_chunk *chk, int so_locked
3297ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
3298ceaad40aSRandall Stewart     SCTP_UNUSED
3299ceaad40aSRandall Stewart #endif
3300ceaad40aSRandall Stewart )
3301f8829a4aSRandall Stewart {
3302830d754dSRandall Stewart 	struct mbuf *m_notify;
3303f8829a4aSRandall Stewart 	struct sctp_send_failed *ssf;
33049935403aSMichael Tuexen 	struct sctp_send_failed_event *ssfe;
3305f8829a4aSRandall Stewart 	struct sctp_queued_to_read *control;
3306ab337314SMichael Tuexen 	struct sctp_chunkhdr *chkhdr;
3307ab337314SMichael Tuexen 	int notifhdr_len, chk_len, chkhdr_len, padding_len, payload_len;
3308f8829a4aSRandall Stewart 
330960990c0cSMichael Tuexen 	if ((stcb == NULL) ||
33109935403aSMichael Tuexen 	    (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT) &&
33119935403aSMichael Tuexen 	    sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT))) {
3312f8829a4aSRandall Stewart 		/* event not enabled */
3313f8829a4aSRandall Stewart 		return;
3314830d754dSRandall Stewart 	}
33150053ed28SMichael Tuexen 
33169935403aSMichael Tuexen 	if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) {
3317ab337314SMichael Tuexen 		notifhdr_len = sizeof(struct sctp_send_failed_event);
33189935403aSMichael Tuexen 	} else {
3319ab337314SMichael Tuexen 		notifhdr_len = sizeof(struct sctp_send_failed);
33209935403aSMichael Tuexen 	}
3321ab337314SMichael Tuexen 	m_notify = sctp_get_mbuf_for_msg(notifhdr_len, 0, M_NOWAIT, 1, MT_DATA);
3322f8829a4aSRandall Stewart 	if (m_notify == NULL)
3323f8829a4aSRandall Stewart 		/* no space left */
3324f8829a4aSRandall Stewart 		return;
3325ab337314SMichael Tuexen 	SCTP_BUF_LEN(m_notify) = notifhdr_len;
3326ab337314SMichael Tuexen 	if (stcb->asoc.idata_supported) {
3327ab337314SMichael Tuexen 		chkhdr_len = sizeof(struct sctp_idata_chunk);
3328ab337314SMichael Tuexen 	} else {
3329ab337314SMichael Tuexen 		chkhdr_len = sizeof(struct sctp_data_chunk);
3330ab337314SMichael Tuexen 	}
3331ab337314SMichael Tuexen 	/* Use some defaults in case we can't access the chunk header */
3332ab337314SMichael Tuexen 	if (chk->send_size >= chkhdr_len) {
3333ab337314SMichael Tuexen 		payload_len = chk->send_size - chkhdr_len;
3334ab337314SMichael Tuexen 	} else {
3335ab337314SMichael Tuexen 		payload_len = 0;
3336ab337314SMichael Tuexen 	}
3337ab337314SMichael Tuexen 	padding_len = 0;
3338ab337314SMichael Tuexen 	if (chk->data != NULL) {
3339ab337314SMichael Tuexen 		chkhdr = mtod(chk->data, struct sctp_chunkhdr *);
3340ab337314SMichael Tuexen 		if (chkhdr != NULL) {
3341ab337314SMichael Tuexen 			chk_len = ntohs(chkhdr->chunk_length);
3342ab337314SMichael Tuexen 			if ((chk_len >= chkhdr_len) &&
3343ab337314SMichael Tuexen 			    (chk->send_size >= chk_len) &&
3344ab337314SMichael Tuexen 			    (chk->send_size - chk_len < 4)) {
3345ab337314SMichael Tuexen 				padding_len = chk->send_size - chk_len;
3346ab337314SMichael Tuexen 				payload_len = chk->send_size - chkhdr_len - padding_len;
3347ab337314SMichael Tuexen 			}
3348ab337314SMichael Tuexen 		}
3349ab337314SMichael Tuexen 	}
33509935403aSMichael Tuexen 	if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) {
33519935403aSMichael Tuexen 		ssfe = mtod(m_notify, struct sctp_send_failed_event *);
3352ab337314SMichael Tuexen 		memset(ssfe, 0, notifhdr_len);
33539935403aSMichael Tuexen 		ssfe->ssfe_type = SCTP_SEND_FAILED_EVENT;
33541edc9dbaSMichael Tuexen 		if (sent) {
33559935403aSMichael Tuexen 			ssfe->ssfe_flags = SCTP_DATA_SENT;
33561edc9dbaSMichael Tuexen 		} else {
33571edc9dbaSMichael Tuexen 			ssfe->ssfe_flags = SCTP_DATA_UNSENT;
33581edc9dbaSMichael Tuexen 		}
3359ab337314SMichael Tuexen 		ssfe->ssfe_length = (uint32_t)(notifhdr_len + payload_len);
33609935403aSMichael Tuexen 		ssfe->ssfe_error = error;
33619935403aSMichael Tuexen 		/* not exactly what the user sent in, but should be close :) */
336249656eefSMichael Tuexen 		ssfe->ssfe_info.snd_sid = chk->rec.data.sid;
33639935403aSMichael Tuexen 		ssfe->ssfe_info.snd_flags = chk->rec.data.rcv_flags;
336449656eefSMichael Tuexen 		ssfe->ssfe_info.snd_ppid = chk->rec.data.ppid;
33659935403aSMichael Tuexen 		ssfe->ssfe_info.snd_context = chk->rec.data.context;
33669935403aSMichael Tuexen 		ssfe->ssfe_info.snd_assoc_id = sctp_get_associd(stcb);
33679935403aSMichael Tuexen 		ssfe->ssfe_assoc_id = sctp_get_associd(stcb);
33689935403aSMichael Tuexen 	} else {
3369f8829a4aSRandall Stewart 		ssf = mtod(m_notify, struct sctp_send_failed *);
3370ab337314SMichael Tuexen 		memset(ssf, 0, notifhdr_len);
3371f8829a4aSRandall Stewart 		ssf->ssf_type = SCTP_SEND_FAILED;
33721edc9dbaSMichael Tuexen 		if (sent) {
3373f8829a4aSRandall Stewart 			ssf->ssf_flags = SCTP_DATA_SENT;
33741edc9dbaSMichael Tuexen 		} else {
33751edc9dbaSMichael Tuexen 			ssf->ssf_flags = SCTP_DATA_UNSENT;
33761edc9dbaSMichael Tuexen 		}
3377ab337314SMichael Tuexen 		ssf->ssf_length = (uint32_t)(notifhdr_len + payload_len);
3378f8829a4aSRandall Stewart 		ssf->ssf_error = error;
3379f8829a4aSRandall Stewart 		/* not exactly what the user sent in, but should be close :) */
338049656eefSMichael Tuexen 		ssf->ssf_info.sinfo_stream = chk->rec.data.sid;
338149656eefSMichael Tuexen 		ssf->ssf_info.sinfo_ssn = (uint16_t)chk->rec.data.mid;
3382f8829a4aSRandall Stewart 		ssf->ssf_info.sinfo_flags = chk->rec.data.rcv_flags;
338349656eefSMichael Tuexen 		ssf->ssf_info.sinfo_ppid = chk->rec.data.ppid;
3384f8829a4aSRandall Stewart 		ssf->ssf_info.sinfo_context = chk->rec.data.context;
3385f8829a4aSRandall Stewart 		ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb);
3386f8829a4aSRandall Stewart 		ssf->ssf_assoc_id = sctp_get_associd(stcb);
33879935403aSMichael Tuexen 	}
3388ab337314SMichael Tuexen 	if (chk->data != NULL) {
3389ab337314SMichael Tuexen 		/* Trim off the sctp chunk header (it should be there) */
3390ab337314SMichael Tuexen 		if (chk->send_size == chkhdr_len + payload_len + padding_len) {
3391ab337314SMichael Tuexen 			m_adj(chk->data, chkhdr_len);
3392ab337314SMichael Tuexen 			m_adj(chk->data, -padding_len);
3393830d754dSRandall Stewart 			sctp_mbuf_crush(chk->data);
3394ab337314SMichael Tuexen 			chk->send_size -= (chkhdr_len + padding_len);
3395830d754dSRandall Stewart 		}
3396830d754dSRandall Stewart 	}
3397810ec536SMichael Tuexen 	SCTP_BUF_NEXT(m_notify) = chk->data;
3398f8829a4aSRandall Stewart 	/* Steal off the mbuf */
3399f8829a4aSRandall Stewart 	chk->data = NULL;
3400f8829a4aSRandall Stewart 	/*
3401f8829a4aSRandall Stewart 	 * For this case, we check the actual socket buffer, since the assoc
3402f8829a4aSRandall Stewart 	 * is going away we don't want to overfill the socket buffer for a
3403f8829a4aSRandall Stewart 	 * non-reader
3404f8829a4aSRandall Stewart 	 */
3405139bc87fSRandall Stewart 	if (sctp_sbspace_failedmsgs(&stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) {
3406f8829a4aSRandall Stewart 		sctp_m_freem(m_notify);
3407f8829a4aSRandall Stewart 		return;
3408f8829a4aSRandall Stewart 	}
3409f8829a4aSRandall Stewart 	/* append to socket */
3410f8829a4aSRandall Stewart 	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
34117215cc1bSMichael Tuexen 	    0, 0, stcb->asoc.context, 0, 0, 0,
3412f8829a4aSRandall Stewart 	    m_notify);
3413f8829a4aSRandall Stewart 	if (control == NULL) {
3414f8829a4aSRandall Stewart 		/* no memory */
3415f8829a4aSRandall Stewart 		sctp_m_freem(m_notify);
3416f8829a4aSRandall Stewart 		return;
3417f8829a4aSRandall Stewart 	}
341828cd0699SMichael Tuexen 	control->length = SCTP_BUF_LEN(m_notify);
3419139bc87fSRandall Stewart 	control->spec_flags = M_NOTIFICATION;
342028cd0699SMichael Tuexen 	/* not that we need this */
342128cd0699SMichael Tuexen 	control->tail_mbuf = m_notify;
3422f8829a4aSRandall Stewart 	sctp_add_to_readq(stcb->sctp_ep, stcb,
3423f8829a4aSRandall Stewart 	    control,
3424cfde3ff7SRandall Stewart 	    &stcb->sctp_socket->so_rcv, 1,
3425cfde3ff7SRandall Stewart 	    SCTP_READ_LOCK_NOT_HELD,
3426cfde3ff7SRandall Stewart 	    so_locked);
3427f8829a4aSRandall Stewart }
3428f8829a4aSRandall Stewart 
3429f8829a4aSRandall Stewart 
3430f8829a4aSRandall Stewart static void
3431f8829a4aSRandall Stewart sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error,
3432ceaad40aSRandall Stewart     struct sctp_stream_queue_pending *sp, int so_locked
3433ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
3434ceaad40aSRandall Stewart     SCTP_UNUSED
3435ceaad40aSRandall Stewart #endif
3436ceaad40aSRandall Stewart )
3437f8829a4aSRandall Stewart {
3438f8829a4aSRandall Stewart 	struct mbuf *m_notify;
3439f8829a4aSRandall Stewart 	struct sctp_send_failed *ssf;
34409935403aSMichael Tuexen 	struct sctp_send_failed_event *ssfe;
3441f8829a4aSRandall Stewart 	struct sctp_queued_to_read *control;
3442ab337314SMichael Tuexen 	int notifhdr_len;
3443f8829a4aSRandall Stewart 
344460990c0cSMichael Tuexen 	if ((stcb == NULL) ||
34459935403aSMichael Tuexen 	    (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT) &&
34469935403aSMichael Tuexen 	    sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT))) {
3447f8829a4aSRandall Stewart 		/* event not enabled */
3448f8829a4aSRandall Stewart 		return;
3449830d754dSRandall Stewart 	}
34509935403aSMichael Tuexen 	if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) {
3451ab337314SMichael Tuexen 		notifhdr_len = sizeof(struct sctp_send_failed_event);
34529935403aSMichael Tuexen 	} else {
3453ab337314SMichael Tuexen 		notifhdr_len = sizeof(struct sctp_send_failed);
34549935403aSMichael Tuexen 	}
3455ab337314SMichael Tuexen 	m_notify = sctp_get_mbuf_for_msg(notifhdr_len, 0, M_NOWAIT, 1, MT_DATA);
34569935403aSMichael Tuexen 	if (m_notify == NULL) {
3457f8829a4aSRandall Stewart 		/* no space left */
3458f8829a4aSRandall Stewart 		return;
34599935403aSMichael Tuexen 	}
3460ab337314SMichael Tuexen 	SCTP_BUF_LEN(m_notify) = notifhdr_len;
34619935403aSMichael Tuexen 	if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) {
34629935403aSMichael Tuexen 		ssfe = mtod(m_notify, struct sctp_send_failed_event *);
3463ab337314SMichael Tuexen 		memset(ssfe, 0, notifhdr_len);
3464ad83c8a5SMichael Tuexen 		ssfe->ssfe_type = SCTP_SEND_FAILED_EVENT;
34659935403aSMichael Tuexen 		ssfe->ssfe_flags = SCTP_DATA_UNSENT;
3466ab337314SMichael Tuexen 		ssfe->ssfe_length = (uint32_t)(notifhdr_len + sp->length);
34679935403aSMichael Tuexen 		ssfe->ssfe_error = error;
34689935403aSMichael Tuexen 		/* not exactly what the user sent in, but should be close :) */
346949656eefSMichael Tuexen 		ssfe->ssfe_info.snd_sid = sp->sid;
34709935403aSMichael Tuexen 		if (sp->some_taken) {
34719935403aSMichael Tuexen 			ssfe->ssfe_info.snd_flags = SCTP_DATA_LAST_FRAG;
34729935403aSMichael Tuexen 		} else {
34739935403aSMichael Tuexen 			ssfe->ssfe_info.snd_flags = SCTP_DATA_NOT_FRAG;
34749935403aSMichael Tuexen 		}
34759935403aSMichael Tuexen 		ssfe->ssfe_info.snd_ppid = sp->ppid;
34769935403aSMichael Tuexen 		ssfe->ssfe_info.snd_context = sp->context;
34779935403aSMichael Tuexen 		ssfe->ssfe_info.snd_assoc_id = sctp_get_associd(stcb);
34789935403aSMichael Tuexen 		ssfe->ssfe_assoc_id = sctp_get_associd(stcb);
34799935403aSMichael Tuexen 	} else {
3480f8829a4aSRandall Stewart 		ssf = mtod(m_notify, struct sctp_send_failed *);
3481ab337314SMichael Tuexen 		memset(ssf, 0, notifhdr_len);
3482f8829a4aSRandall Stewart 		ssf->ssf_type = SCTP_SEND_FAILED;
3483f8829a4aSRandall Stewart 		ssf->ssf_flags = SCTP_DATA_UNSENT;
3484ab337314SMichael Tuexen 		ssf->ssf_length = (uint32_t)(notifhdr_len + sp->length);
3485f8829a4aSRandall Stewart 		ssf->ssf_error = error;
3486f8829a4aSRandall Stewart 		/* not exactly what the user sent in, but should be close :) */
348749656eefSMichael Tuexen 		ssf->ssf_info.sinfo_stream = sp->sid;
3488f3b05218SMichael Tuexen 		ssf->ssf_info.sinfo_ssn = 0;
3489fc14de76SRandall Stewart 		if (sp->some_taken) {
3490fc14de76SRandall Stewart 			ssf->ssf_info.sinfo_flags = SCTP_DATA_LAST_FRAG;
3491fc14de76SRandall Stewart 		} else {
3492fc14de76SRandall Stewart 			ssf->ssf_info.sinfo_flags = SCTP_DATA_NOT_FRAG;
3493fc14de76SRandall Stewart 		}
3494f8829a4aSRandall Stewart 		ssf->ssf_info.sinfo_ppid = sp->ppid;
3495f8829a4aSRandall Stewart 		ssf->ssf_info.sinfo_context = sp->context;
3496f8829a4aSRandall Stewart 		ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb);
3497f8829a4aSRandall Stewart 		ssf->ssf_assoc_id = sctp_get_associd(stcb);
34989935403aSMichael Tuexen 	}
34999935403aSMichael Tuexen 	SCTP_BUF_NEXT(m_notify) = sp->data;
3500f8829a4aSRandall Stewart 
3501f8829a4aSRandall Stewart 	/* Steal off the mbuf */
3502f8829a4aSRandall Stewart 	sp->data = NULL;
3503f8829a4aSRandall Stewart 	/*
3504f8829a4aSRandall Stewart 	 * For this case, we check the actual socket buffer, since the assoc
3505f8829a4aSRandall Stewart 	 * is going away we don't want to overfill the socket buffer for a
3506f8829a4aSRandall Stewart 	 * non-reader
3507f8829a4aSRandall Stewart 	 */
3508139bc87fSRandall Stewart 	if (sctp_sbspace_failedmsgs(&stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) {
3509f8829a4aSRandall Stewart 		sctp_m_freem(m_notify);
3510f8829a4aSRandall Stewart 		return;
3511f8829a4aSRandall Stewart 	}
3512f8829a4aSRandall Stewart 	/* append to socket */
3513f8829a4aSRandall Stewart 	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
35147215cc1bSMichael Tuexen 	    0, 0, stcb->asoc.context, 0, 0, 0,
3515f8829a4aSRandall Stewart 	    m_notify);
3516f8829a4aSRandall Stewart 	if (control == NULL) {
3517f8829a4aSRandall Stewart 		/* no memory */
3518f8829a4aSRandall Stewart 		sctp_m_freem(m_notify);
3519f8829a4aSRandall Stewart 		return;
3520f8829a4aSRandall Stewart 	}
352128cd0699SMichael Tuexen 	control->length = SCTP_BUF_LEN(m_notify);
3522139bc87fSRandall Stewart 	control->spec_flags = M_NOTIFICATION;
352328cd0699SMichael Tuexen 	/* not that we need this */
352428cd0699SMichael Tuexen 	control->tail_mbuf = m_notify;
3525f8829a4aSRandall Stewart 	sctp_add_to_readq(stcb->sctp_ep, stcb,
3526f8829a4aSRandall Stewart 	    control,
3527cfde3ff7SRandall Stewart 	    &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, so_locked);
3528f8829a4aSRandall Stewart }
3529f8829a4aSRandall Stewart 
3530f8829a4aSRandall Stewart 
3531f8829a4aSRandall Stewart 
3532f8829a4aSRandall Stewart static void
35337215cc1bSMichael Tuexen sctp_notify_adaptation_layer(struct sctp_tcb *stcb)
3534f8829a4aSRandall Stewart {
3535f8829a4aSRandall Stewart 	struct mbuf *m_notify;
3536f8829a4aSRandall Stewart 	struct sctp_adaptation_event *sai;
3537f8829a4aSRandall Stewart 	struct sctp_queued_to_read *control;
3538f8829a4aSRandall Stewart 
353960990c0cSMichael Tuexen 	if ((stcb == NULL) ||
354060990c0cSMichael Tuexen 	    sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT)) {
3541f8829a4aSRandall Stewart 		/* event not enabled */
3542f8829a4aSRandall Stewart 		return;
3543830d754dSRandall Stewart 	}
35440053ed28SMichael Tuexen 
3545eb1b1807SGleb Smirnoff 	m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_adaption_event), 0, M_NOWAIT, 1, MT_DATA);
3546f8829a4aSRandall Stewart 	if (m_notify == NULL)
3547f8829a4aSRandall Stewart 		/* no space left */
3548f8829a4aSRandall Stewart 		return;
3549139bc87fSRandall Stewart 	SCTP_BUF_LEN(m_notify) = 0;
3550f8829a4aSRandall Stewart 	sai = mtod(m_notify, struct sctp_adaptation_event *);
3551e432298aSXin LI 	memset(sai, 0, sizeof(struct sctp_adaptation_event));
3552f8829a4aSRandall Stewart 	sai->sai_type = SCTP_ADAPTATION_INDICATION;
3553f8829a4aSRandall Stewart 	sai->sai_flags = 0;
3554f8829a4aSRandall Stewart 	sai->sai_length = sizeof(struct sctp_adaptation_event);
35552afb3e84SRandall Stewart 	sai->sai_adaptation_ind = stcb->asoc.peers_adaptation;
3556f8829a4aSRandall Stewart 	sai->sai_assoc_id = sctp_get_associd(stcb);
3557f8829a4aSRandall Stewart 
3558139bc87fSRandall Stewart 	SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_adaptation_event);
3559139bc87fSRandall Stewart 	SCTP_BUF_NEXT(m_notify) = NULL;
3560f8829a4aSRandall Stewart 
3561f8829a4aSRandall Stewart 	/* append to socket */
3562f8829a4aSRandall Stewart 	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
35637215cc1bSMichael Tuexen 	    0, 0, stcb->asoc.context, 0, 0, 0,
3564f8829a4aSRandall Stewart 	    m_notify);
3565f8829a4aSRandall Stewart 	if (control == NULL) {
3566f8829a4aSRandall Stewart 		/* no memory */
3567f8829a4aSRandall Stewart 		sctp_m_freem(m_notify);
3568f8829a4aSRandall Stewart 		return;
3569f8829a4aSRandall Stewart 	}
3570139bc87fSRandall Stewart 	control->length = SCTP_BUF_LEN(m_notify);
3571139bc87fSRandall Stewart 	control->spec_flags = M_NOTIFICATION;
3572f8829a4aSRandall Stewart 	/* not that we need this */
3573f8829a4aSRandall Stewart 	control->tail_mbuf = m_notify;
3574f8829a4aSRandall Stewart 	sctp_add_to_readq(stcb->sctp_ep, stcb,
3575f8829a4aSRandall Stewart 	    control,
3576cfde3ff7SRandall Stewart 	    &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
3577f8829a4aSRandall Stewart }
3578f8829a4aSRandall Stewart 
357903b0b021SRandall Stewart /* This always must be called with the read-queue LOCKED in the INP */
3580810ec536SMichael Tuexen static void
35812dad8a55SRandall Stewart sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, uint32_t error,
3582810ec536SMichael Tuexen     uint32_t val, int so_locked
3583810ec536SMichael Tuexen #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
3584810ec536SMichael Tuexen     SCTP_UNUSED
3585810ec536SMichael Tuexen #endif
3586810ec536SMichael Tuexen )
3587f8829a4aSRandall Stewart {
3588f8829a4aSRandall Stewart 	struct mbuf *m_notify;
3589f8829a4aSRandall Stewart 	struct sctp_pdapi_event *pdapi;
3590f8829a4aSRandall Stewart 	struct sctp_queued_to_read *control;
359103b0b021SRandall Stewart 	struct sockbuf *sb;
3592f8829a4aSRandall Stewart 
359360990c0cSMichael Tuexen 	if ((stcb == NULL) ||
359460990c0cSMichael Tuexen 	    sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_PDAPIEVNT)) {
3595f8829a4aSRandall Stewart 		/* event not enabled */
3596f8829a4aSRandall Stewart 		return;
3597830d754dSRandall Stewart 	}
3598cd1386abSMichael Tuexen 	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_CANT_READ) {
3599cd1386abSMichael Tuexen 		return;
3600cd1386abSMichael Tuexen 	}
36010053ed28SMichael Tuexen 
3602eb1b1807SGleb Smirnoff 	m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_pdapi_event), 0, M_NOWAIT, 1, MT_DATA);
3603f8829a4aSRandall Stewart 	if (m_notify == NULL)
3604f8829a4aSRandall Stewart 		/* no space left */
3605f8829a4aSRandall Stewart 		return;
3606139bc87fSRandall Stewart 	SCTP_BUF_LEN(m_notify) = 0;
3607f8829a4aSRandall Stewart 	pdapi = mtod(m_notify, struct sctp_pdapi_event *);
3608e432298aSXin LI 	memset(pdapi, 0, sizeof(struct sctp_pdapi_event));
3609f8829a4aSRandall Stewart 	pdapi->pdapi_type = SCTP_PARTIAL_DELIVERY_EVENT;
3610f8829a4aSRandall Stewart 	pdapi->pdapi_flags = 0;
3611f8829a4aSRandall Stewart 	pdapi->pdapi_length = sizeof(struct sctp_pdapi_event);
3612f8829a4aSRandall Stewart 	pdapi->pdapi_indication = error;
36139a6142d8SRandall Stewart 	pdapi->pdapi_stream = (val >> 16);
36149a6142d8SRandall Stewart 	pdapi->pdapi_seq = (val & 0x0000ffff);
3615f8829a4aSRandall Stewart 	pdapi->pdapi_assoc_id = sctp_get_associd(stcb);
3616f8829a4aSRandall Stewart 
3617139bc87fSRandall Stewart 	SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_pdapi_event);
3618139bc87fSRandall Stewart 	SCTP_BUF_NEXT(m_notify) = NULL;
3619f8829a4aSRandall Stewart 	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
36207215cc1bSMichael Tuexen 	    0, 0, stcb->asoc.context, 0, 0, 0,
3621f8829a4aSRandall Stewart 	    m_notify);
3622f8829a4aSRandall Stewart 	if (control == NULL) {
3623f8829a4aSRandall Stewart 		/* no memory */
3624f8829a4aSRandall Stewart 		sctp_m_freem(m_notify);
3625f8829a4aSRandall Stewart 		return;
3626f8829a4aSRandall Stewart 	}
3627139bc87fSRandall Stewart 	control->length = SCTP_BUF_LEN(m_notify);
362828cd0699SMichael Tuexen 	control->spec_flags = M_NOTIFICATION;
3629f8829a4aSRandall Stewart 	/* not that we need this */
3630f8829a4aSRandall Stewart 	control->tail_mbuf = m_notify;
363103b0b021SRandall Stewart 	sb = &stcb->sctp_socket->so_rcv;
3632b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
3633139bc87fSRandall Stewart 		sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(m_notify));
363480fefe0aSRandall Stewart 	}
363503b0b021SRandall Stewart 	sctp_sballoc(stcb, sb, m_notify);
3636b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
363703b0b021SRandall Stewart 		sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0);
363880fefe0aSRandall Stewart 	}
363903b0b021SRandall Stewart 	control->end_added = 1;
364003b0b021SRandall Stewart 	if (stcb->asoc.control_pdapi)
364103b0b021SRandall Stewart 		TAILQ_INSERT_AFTER(&stcb->sctp_ep->read_queue, stcb->asoc.control_pdapi, control, next);
364203b0b021SRandall Stewart 	else {
364303b0b021SRandall Stewart 		/* we really should not see this case */
364403b0b021SRandall Stewart 		TAILQ_INSERT_TAIL(&stcb->sctp_ep->read_queue, control, next);
364503b0b021SRandall Stewart 	}
364603b0b021SRandall Stewart 	if (stcb->sctp_ep && stcb->sctp_socket) {
364703b0b021SRandall Stewart 		/* This should always be the case */
3648810ec536SMichael Tuexen #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
3649810ec536SMichael Tuexen 		struct socket *so;
3650810ec536SMichael Tuexen 
3651810ec536SMichael Tuexen 		so = SCTP_INP_SO(stcb->sctp_ep);
3652810ec536SMichael Tuexen 		if (!so_locked) {
3653810ec536SMichael Tuexen 			atomic_add_int(&stcb->asoc.refcnt, 1);
3654810ec536SMichael Tuexen 			SCTP_TCB_UNLOCK(stcb);
3655810ec536SMichael Tuexen 			SCTP_SOCKET_LOCK(so, 1);
3656810ec536SMichael Tuexen 			SCTP_TCB_LOCK(stcb);
3657810ec536SMichael Tuexen 			atomic_subtract_int(&stcb->asoc.refcnt, 1);
3658810ec536SMichael Tuexen 			if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
3659810ec536SMichael Tuexen 				SCTP_SOCKET_UNLOCK(so, 1);
3660810ec536SMichael Tuexen 				return;
3661810ec536SMichael Tuexen 			}
3662810ec536SMichael Tuexen 		}
3663810ec536SMichael Tuexen #endif
366403b0b021SRandall Stewart 		sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
3665810ec536SMichael Tuexen #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
3666810ec536SMichael Tuexen 		if (!so_locked) {
3667810ec536SMichael Tuexen 			SCTP_SOCKET_UNLOCK(so, 1);
3668810ec536SMichael Tuexen 		}
3669810ec536SMichael Tuexen #endif
3670f8829a4aSRandall Stewart 	}
3671f8829a4aSRandall Stewart }
3672f8829a4aSRandall Stewart 
3673f8829a4aSRandall Stewart static void
3674f8829a4aSRandall Stewart sctp_notify_shutdown_event(struct sctp_tcb *stcb)
3675f8829a4aSRandall Stewart {
3676f8829a4aSRandall Stewart 	struct mbuf *m_notify;
3677f8829a4aSRandall Stewart 	struct sctp_shutdown_event *sse;
3678f8829a4aSRandall Stewart 	struct sctp_queued_to_read *control;
3679f8829a4aSRandall Stewart 
3680f8829a4aSRandall Stewart 	/*
3681f8829a4aSRandall Stewart 	 * For TCP model AND UDP connected sockets we will send an error up
3682f8829a4aSRandall Stewart 	 * when an SHUTDOWN completes
3683f8829a4aSRandall Stewart 	 */
3684f8829a4aSRandall Stewart 	if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3685f8829a4aSRandall Stewart 	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
3686f8829a4aSRandall Stewart 		/* mark socket closed for read/write and wakeup! */
3687ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
3688ceaad40aSRandall Stewart 		struct socket *so;
3689ceaad40aSRandall Stewart 
3690ceaad40aSRandall Stewart 		so = SCTP_INP_SO(stcb->sctp_ep);
3691ceaad40aSRandall Stewart 		atomic_add_int(&stcb->asoc.refcnt, 1);
3692ceaad40aSRandall Stewart 		SCTP_TCB_UNLOCK(stcb);
3693ceaad40aSRandall Stewart 		SCTP_SOCKET_LOCK(so, 1);
3694ceaad40aSRandall Stewart 		SCTP_TCB_LOCK(stcb);
3695ceaad40aSRandall Stewart 		atomic_subtract_int(&stcb->asoc.refcnt, 1);
3696ceaad40aSRandall Stewart 		if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
3697ceaad40aSRandall Stewart 			SCTP_SOCKET_UNLOCK(so, 1);
3698ceaad40aSRandall Stewart 			return;
3699ceaad40aSRandall Stewart 		}
3700ceaad40aSRandall Stewart #endif
3701f8829a4aSRandall Stewart 		socantsendmore(stcb->sctp_socket);
3702ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
3703ceaad40aSRandall Stewart 		SCTP_SOCKET_UNLOCK(so, 1);
3704ceaad40aSRandall Stewart #endif
3705f8829a4aSRandall Stewart 	}
3706e2e7c62eSMichael Tuexen 	if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT)) {
3707f8829a4aSRandall Stewart 		/* event not enabled */
3708f8829a4aSRandall Stewart 		return;
3709830d754dSRandall Stewart 	}
37100053ed28SMichael Tuexen 
3711eb1b1807SGleb Smirnoff 	m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_shutdown_event), 0, M_NOWAIT, 1, MT_DATA);
3712f8829a4aSRandall Stewart 	if (m_notify == NULL)
3713f8829a4aSRandall Stewart 		/* no space left */
3714f8829a4aSRandall Stewart 		return;
3715f8829a4aSRandall Stewart 	sse = mtod(m_notify, struct sctp_shutdown_event *);
3716e432298aSXin LI 	memset(sse, 0, sizeof(struct sctp_shutdown_event));
3717f8829a4aSRandall Stewart 	sse->sse_type = SCTP_SHUTDOWN_EVENT;
3718f8829a4aSRandall Stewart 	sse->sse_flags = 0;
3719f8829a4aSRandall Stewart 	sse->sse_length = sizeof(struct sctp_shutdown_event);
3720f8829a4aSRandall Stewart 	sse->sse_assoc_id = sctp_get_associd(stcb);
3721f8829a4aSRandall Stewart 
3722139bc87fSRandall Stewart 	SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_shutdown_event);
3723139bc87fSRandall Stewart 	SCTP_BUF_NEXT(m_notify) = NULL;
3724f8829a4aSRandall Stewart 
3725f8829a4aSRandall Stewart 	/* append to socket */
3726f8829a4aSRandall Stewart 	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
37277215cc1bSMichael Tuexen 	    0, 0, stcb->asoc.context, 0, 0, 0,
3728f8829a4aSRandall Stewart 	    m_notify);
3729f8829a4aSRandall Stewart 	if (control == NULL) {
3730f8829a4aSRandall Stewart 		/* no memory */
3731f8829a4aSRandall Stewart 		sctp_m_freem(m_notify);
3732f8829a4aSRandall Stewart 		return;
3733f8829a4aSRandall Stewart 	}
3734139bc87fSRandall Stewart 	control->length = SCTP_BUF_LEN(m_notify);
373528cd0699SMichael Tuexen 	control->spec_flags = M_NOTIFICATION;
3736f8829a4aSRandall Stewart 	/* not that we need this */
3737f8829a4aSRandall Stewart 	control->tail_mbuf = m_notify;
3738f8829a4aSRandall Stewart 	sctp_add_to_readq(stcb->sctp_ep, stcb,
3739f8829a4aSRandall Stewart 	    control,
3740cfde3ff7SRandall Stewart 	    &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
3741f8829a4aSRandall Stewart }
3742f8829a4aSRandall Stewart 
3743f8829a4aSRandall Stewart static void
3744830d754dSRandall Stewart sctp_notify_sender_dry_event(struct sctp_tcb *stcb,
3745830d754dSRandall Stewart     int so_locked
3746830d754dSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
3747830d754dSRandall Stewart     SCTP_UNUSED
3748830d754dSRandall Stewart #endif
3749830d754dSRandall Stewart )
3750830d754dSRandall Stewart {
3751830d754dSRandall Stewart 	struct mbuf *m_notify;
3752830d754dSRandall Stewart 	struct sctp_sender_dry_event *event;
3753830d754dSRandall Stewart 	struct sctp_queued_to_read *control;
3754830d754dSRandall Stewart 
375560990c0cSMichael Tuexen 	if ((stcb == NULL) ||
375660990c0cSMichael Tuexen 	    sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_DRYEVNT)) {
3757830d754dSRandall Stewart 		/* event not enabled */
3758830d754dSRandall Stewart 		return;
3759830d754dSRandall Stewart 	}
37600053ed28SMichael Tuexen 
3761eb1b1807SGleb Smirnoff 	m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_sender_dry_event), 0, M_NOWAIT, 1, MT_DATA);
3762830d754dSRandall Stewart 	if (m_notify == NULL) {
3763830d754dSRandall Stewart 		/* no space left */
3764830d754dSRandall Stewart 		return;
3765830d754dSRandall Stewart 	}
3766830d754dSRandall Stewart 	SCTP_BUF_LEN(m_notify) = 0;
3767830d754dSRandall Stewart 	event = mtod(m_notify, struct sctp_sender_dry_event *);
3768e432298aSXin LI 	memset(event, 0, sizeof(struct sctp_sender_dry_event));
3769830d754dSRandall Stewart 	event->sender_dry_type = SCTP_SENDER_DRY_EVENT;
3770830d754dSRandall Stewart 	event->sender_dry_flags = 0;
3771830d754dSRandall Stewart 	event->sender_dry_length = sizeof(struct sctp_sender_dry_event);
3772830d754dSRandall Stewart 	event->sender_dry_assoc_id = sctp_get_associd(stcb);
3773830d754dSRandall Stewart 
3774830d754dSRandall Stewart 	SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_sender_dry_event);
3775830d754dSRandall Stewart 	SCTP_BUF_NEXT(m_notify) = NULL;
3776830d754dSRandall Stewart 
3777830d754dSRandall Stewart 	/* append to socket */
3778830d754dSRandall Stewart 	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
37797215cc1bSMichael Tuexen 	    0, 0, stcb->asoc.context, 0, 0, 0,
37807215cc1bSMichael Tuexen 	    m_notify);
3781830d754dSRandall Stewart 	if (control == NULL) {
3782830d754dSRandall Stewart 		/* no memory */
3783830d754dSRandall Stewart 		sctp_m_freem(m_notify);
3784830d754dSRandall Stewart 		return;
3785830d754dSRandall Stewart 	}
3786830d754dSRandall Stewart 	control->length = SCTP_BUF_LEN(m_notify);
3787830d754dSRandall Stewart 	control->spec_flags = M_NOTIFICATION;
3788830d754dSRandall Stewart 	/* not that we need this */
3789830d754dSRandall Stewart 	control->tail_mbuf = m_notify;
3790830d754dSRandall Stewart 	sctp_add_to_readq(stcb->sctp_ep, stcb, control,
3791cfde3ff7SRandall Stewart 	    &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, so_locked);
3792830d754dSRandall Stewart }
3793830d754dSRandall Stewart 
3794ea44232bSRandall Stewart 
3795c4e848b7SRandall Stewart void
3796c4e848b7SRandall Stewart sctp_notify_stream_reset_add(struct sctp_tcb *stcb, uint16_t numberin, uint16_t numberout, int flag)
3797ea44232bSRandall Stewart {
3798ea44232bSRandall Stewart 	struct mbuf *m_notify;
3799ea44232bSRandall Stewart 	struct sctp_queued_to_read *control;
3800c4e848b7SRandall Stewart 	struct sctp_stream_change_event *stradd;
3801ea44232bSRandall Stewart 
38028c501e51SMichael Tuexen 	if ((stcb == NULL) ||
38038c501e51SMichael Tuexen 	    (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_STREAM_CHANGEEVNT))) {
3804ea44232bSRandall Stewart 		/* event not enabled */
3805ea44232bSRandall Stewart 		return;
3806ea44232bSRandall Stewart 	}
3807c4e848b7SRandall Stewart 	if ((stcb->asoc.peer_req_out) && flag) {
3808c4e848b7SRandall Stewart 		/* Peer made the request, don't tell the local user */
3809c4e848b7SRandall Stewart 		stcb->asoc.peer_req_out = 0;
3810c4e848b7SRandall Stewart 		return;
3811c4e848b7SRandall Stewart 	}
3812c4e848b7SRandall Stewart 	stcb->asoc.peer_req_out = 0;
3813e432298aSXin LI 	m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_stream_change_event), 0, M_NOWAIT, 1, MT_DATA);
3814ea44232bSRandall Stewart 	if (m_notify == NULL)
3815ea44232bSRandall Stewart 		/* no space left */
3816ea44232bSRandall Stewart 		return;
3817ea44232bSRandall Stewart 	SCTP_BUF_LEN(m_notify) = 0;
3818c4e848b7SRandall Stewart 	stradd = mtod(m_notify, struct sctp_stream_change_event *);
3819e432298aSXin LI 	memset(stradd, 0, sizeof(struct sctp_stream_change_event));
3820c4e848b7SRandall Stewart 	stradd->strchange_type = SCTP_STREAM_CHANGE_EVENT;
3821c4e848b7SRandall Stewart 	stradd->strchange_flags = flag;
3822e432298aSXin LI 	stradd->strchange_length = sizeof(struct sctp_stream_change_event);
3823c4e848b7SRandall Stewart 	stradd->strchange_assoc_id = sctp_get_associd(stcb);
3824c4e848b7SRandall Stewart 	stradd->strchange_instrms = numberin;
3825c4e848b7SRandall Stewart 	stradd->strchange_outstrms = numberout;
3826e432298aSXin LI 	SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_stream_change_event);
3827ea44232bSRandall Stewart 	SCTP_BUF_NEXT(m_notify) = NULL;
3828ea44232bSRandall Stewart 	if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) {
3829ea44232bSRandall Stewart 		/* no space */
3830ea44232bSRandall Stewart 		sctp_m_freem(m_notify);
3831ea44232bSRandall Stewart 		return;
3832ea44232bSRandall Stewart 	}
3833ea44232bSRandall Stewart 	/* append to socket */
3834ea44232bSRandall Stewart 	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
38357215cc1bSMichael Tuexen 	    0, 0, stcb->asoc.context, 0, 0, 0,
3836ea44232bSRandall Stewart 	    m_notify);
3837ea44232bSRandall Stewart 	if (control == NULL) {
3838ea44232bSRandall Stewart 		/* no memory */
3839ea44232bSRandall Stewart 		sctp_m_freem(m_notify);
3840ea44232bSRandall Stewart 		return;
3841ea44232bSRandall Stewart 	}
3842ea44232bSRandall Stewart 	control->length = SCTP_BUF_LEN(m_notify);
384328cd0699SMichael Tuexen 	control->spec_flags = M_NOTIFICATION;
3844ea44232bSRandall Stewart 	/* not that we need this */
3845ea44232bSRandall Stewart 	control->tail_mbuf = m_notify;
3846ea44232bSRandall Stewart 	sctp_add_to_readq(stcb->sctp_ep, stcb,
3847ea44232bSRandall Stewart 	    control,
3848cfde3ff7SRandall Stewart 	    &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
3849ea44232bSRandall Stewart }
3850ea44232bSRandall Stewart 
3851c4e848b7SRandall Stewart void
3852c4e848b7SRandall Stewart sctp_notify_stream_reset_tsn(struct sctp_tcb *stcb, uint32_t sending_tsn, uint32_t recv_tsn, int flag)
3853c4e848b7SRandall Stewart {
3854c4e848b7SRandall Stewart 	struct mbuf *m_notify;
3855c4e848b7SRandall Stewart 	struct sctp_queued_to_read *control;
3856c4e848b7SRandall Stewart 	struct sctp_assoc_reset_event *strasoc;
3857c4e848b7SRandall Stewart 
38588c501e51SMichael Tuexen 	if ((stcb == NULL) ||
38598c501e51SMichael Tuexen 	    (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_ASSOC_RESETEVNT))) {
3860c4e848b7SRandall Stewart 		/* event not enabled */
3861c4e848b7SRandall Stewart 		return;
3862c4e848b7SRandall Stewart 	}
3863e432298aSXin LI 	m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_assoc_reset_event), 0, M_NOWAIT, 1, MT_DATA);
3864c4e848b7SRandall Stewart 	if (m_notify == NULL)
3865c4e848b7SRandall Stewart 		/* no space left */
3866c4e848b7SRandall Stewart 		return;
3867c4e848b7SRandall Stewart 	SCTP_BUF_LEN(m_notify) = 0;
3868c4e848b7SRandall Stewart 	strasoc = mtod(m_notify, struct sctp_assoc_reset_event *);
3869e432298aSXin LI 	memset(strasoc, 0, sizeof(struct sctp_assoc_reset_event));
3870c4e848b7SRandall Stewart 	strasoc->assocreset_type = SCTP_ASSOC_RESET_EVENT;
3871c4e848b7SRandall Stewart 	strasoc->assocreset_flags = flag;
3872e432298aSXin LI 	strasoc->assocreset_length = sizeof(struct sctp_assoc_reset_event);
3873c4e848b7SRandall Stewart 	strasoc->assocreset_assoc_id = sctp_get_associd(stcb);
3874c4e848b7SRandall Stewart 	strasoc->assocreset_local_tsn = sending_tsn;
3875c4e848b7SRandall Stewart 	strasoc->assocreset_remote_tsn = recv_tsn;
3876e432298aSXin LI 	SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_assoc_reset_event);
3877c4e848b7SRandall Stewart 	SCTP_BUF_NEXT(m_notify) = NULL;
3878c4e848b7SRandall Stewart 	if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) {
3879c4e848b7SRandall Stewart 		/* no space */
3880c4e848b7SRandall Stewart 		sctp_m_freem(m_notify);
3881c4e848b7SRandall Stewart 		return;
3882c4e848b7SRandall Stewart 	}
3883c4e848b7SRandall Stewart 	/* append to socket */
3884c4e848b7SRandall Stewart 	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
3885c4e848b7SRandall Stewart 	    0, 0, stcb->asoc.context, 0, 0, 0,
3886c4e848b7SRandall Stewart 	    m_notify);
3887c4e848b7SRandall Stewart 	if (control == NULL) {
3888c4e848b7SRandall Stewart 		/* no memory */
3889c4e848b7SRandall Stewart 		sctp_m_freem(m_notify);
3890c4e848b7SRandall Stewart 		return;
3891c4e848b7SRandall Stewart 	}
3892c4e848b7SRandall Stewart 	control->length = SCTP_BUF_LEN(m_notify);
389328cd0699SMichael Tuexen 	control->spec_flags = M_NOTIFICATION;
3894c4e848b7SRandall Stewart 	/* not that we need this */
3895c4e848b7SRandall Stewart 	control->tail_mbuf = m_notify;
3896c4e848b7SRandall Stewart 	sctp_add_to_readq(stcb->sctp_ep, stcb,
3897c4e848b7SRandall Stewart 	    control,
3898c4e848b7SRandall Stewart 	    &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
3899c4e848b7SRandall Stewart }
3900c4e848b7SRandall Stewart 
3901c4e848b7SRandall Stewart 
3902ea44232bSRandall Stewart 
3903830d754dSRandall Stewart static void
3904f8829a4aSRandall Stewart sctp_notify_stream_reset(struct sctp_tcb *stcb,
3905f8829a4aSRandall Stewart     int number_entries, uint16_t *list, int flag)
3906f8829a4aSRandall Stewart {
3907f8829a4aSRandall Stewart 	struct mbuf *m_notify;
3908f8829a4aSRandall Stewart 	struct sctp_queued_to_read *control;
3909f8829a4aSRandall Stewart 	struct sctp_stream_reset_event *strreset;
3910f8829a4aSRandall Stewart 	int len;
3911f8829a4aSRandall Stewart 
39128c501e51SMichael Tuexen 	if ((stcb == NULL) ||
39138c501e51SMichael Tuexen 	    (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT))) {
3914f8829a4aSRandall Stewart 		/* event not enabled */
3915f8829a4aSRandall Stewart 		return;
3916830d754dSRandall Stewart 	}
39170053ed28SMichael Tuexen 
3918eb1b1807SGleb Smirnoff 	m_notify = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA);
3919f8829a4aSRandall Stewart 	if (m_notify == NULL)
3920f8829a4aSRandall Stewart 		/* no space left */
3921f8829a4aSRandall Stewart 		return;
3922139bc87fSRandall Stewart 	SCTP_BUF_LEN(m_notify) = 0;
3923f8829a4aSRandall Stewart 	len = sizeof(struct sctp_stream_reset_event) + (number_entries * sizeof(uint16_t));
3924f8829a4aSRandall Stewart 	if (len > M_TRAILINGSPACE(m_notify)) {
3925f8829a4aSRandall Stewart 		/* never enough room */
3926f8829a4aSRandall Stewart 		sctp_m_freem(m_notify);
3927f8829a4aSRandall Stewart 		return;
3928f8829a4aSRandall Stewart 	}
3929f8829a4aSRandall Stewart 	strreset = mtod(m_notify, struct sctp_stream_reset_event *);
3930e432298aSXin LI 	memset(strreset, 0, len);
3931f8829a4aSRandall Stewart 	strreset->strreset_type = SCTP_STREAM_RESET_EVENT;
3932c4e848b7SRandall Stewart 	strreset->strreset_flags = flag;
3933f8829a4aSRandall Stewart 	strreset->strreset_length = len;
3934f8829a4aSRandall Stewart 	strreset->strreset_assoc_id = sctp_get_associd(stcb);
3935f8829a4aSRandall Stewart 	if (number_entries) {
3936f8829a4aSRandall Stewart 		int i;
3937f8829a4aSRandall Stewart 
3938f8829a4aSRandall Stewart 		for (i = 0; i < number_entries; i++) {
3939c4e848b7SRandall Stewart 			strreset->strreset_stream_list[i] = ntohs(list[i]);
3940f8829a4aSRandall Stewart 		}
3941f8829a4aSRandall Stewart 	}
3942139bc87fSRandall Stewart 	SCTP_BUF_LEN(m_notify) = len;
3943139bc87fSRandall Stewart 	SCTP_BUF_NEXT(m_notify) = NULL;
3944139bc87fSRandall Stewart 	if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) {
3945f8829a4aSRandall Stewart 		/* no space */
3946f8829a4aSRandall Stewart 		sctp_m_freem(m_notify);
3947f8829a4aSRandall Stewart 		return;
3948f8829a4aSRandall Stewart 	}
3949f8829a4aSRandall Stewart 	/* append to socket */
3950f8829a4aSRandall Stewart 	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
39517215cc1bSMichael Tuexen 	    0, 0, stcb->asoc.context, 0, 0, 0,
3952f8829a4aSRandall Stewart 	    m_notify);
3953f8829a4aSRandall Stewart 	if (control == NULL) {
3954f8829a4aSRandall Stewart 		/* no memory */
3955f8829a4aSRandall Stewart 		sctp_m_freem(m_notify);
3956f8829a4aSRandall Stewart 		return;
3957f8829a4aSRandall Stewart 	}
3958139bc87fSRandall Stewart 	control->length = SCTP_BUF_LEN(m_notify);
395928cd0699SMichael Tuexen 	control->spec_flags = M_NOTIFICATION;
3960f8829a4aSRandall Stewart 	/* not that we need this */
3961f8829a4aSRandall Stewart 	control->tail_mbuf = m_notify;
3962f8829a4aSRandall Stewart 	sctp_add_to_readq(stcb->sctp_ep, stcb,
3963f8829a4aSRandall Stewart 	    control,
3964cfde3ff7SRandall Stewart 	    &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
3965f8829a4aSRandall Stewart }
3966f8829a4aSRandall Stewart 
3967f8829a4aSRandall Stewart 
3968389b1b11SMichael Tuexen static void
3969389b1b11SMichael Tuexen sctp_notify_remote_error(struct sctp_tcb *stcb, uint16_t error, struct sctp_error_chunk *chunk)
3970389b1b11SMichael Tuexen {
3971389b1b11SMichael Tuexen 	struct mbuf *m_notify;
3972389b1b11SMichael Tuexen 	struct sctp_remote_error *sre;
3973389b1b11SMichael Tuexen 	struct sctp_queued_to_read *control;
39749a8e3088SMichael Tuexen 	unsigned int notif_len;
39759a8e3088SMichael Tuexen 	uint16_t chunk_len;
3976389b1b11SMichael Tuexen 
3977389b1b11SMichael Tuexen 	if ((stcb == NULL) ||
3978389b1b11SMichael Tuexen 	    sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVPEERERR)) {
3979389b1b11SMichael Tuexen 		return;
3980389b1b11SMichael Tuexen 	}
3981389b1b11SMichael Tuexen 	if (chunk != NULL) {
3982c9eb4473SMichael Tuexen 		chunk_len = ntohs(chunk->ch.chunk_length);
39839669e724SMichael Tuexen 		/*
39849669e724SMichael Tuexen 		 * Only SCTP_CHUNK_BUFFER_SIZE are guaranteed to be
398545d41de5SMichael Tuexen 		 * contiguous.
39869669e724SMichael Tuexen 		 */
39879669e724SMichael Tuexen 		if (chunk_len > SCTP_CHUNK_BUFFER_SIZE) {
39889669e724SMichael Tuexen 			chunk_len = SCTP_CHUNK_BUFFER_SIZE;
39899669e724SMichael Tuexen 		}
3990389b1b11SMichael Tuexen 	} else {
3991389b1b11SMichael Tuexen 		chunk_len = 0;
3992389b1b11SMichael Tuexen 	}
39939a8e3088SMichael Tuexen 	notif_len = (unsigned int)(sizeof(struct sctp_remote_error) + chunk_len);
3994eb1b1807SGleb Smirnoff 	m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA);
3995389b1b11SMichael Tuexen 	if (m_notify == NULL) {
3996389b1b11SMichael Tuexen 		/* Retry with smaller value. */
39979a8e3088SMichael Tuexen 		notif_len = (unsigned int)sizeof(struct sctp_remote_error);
3998eb1b1807SGleb Smirnoff 		m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA);
3999389b1b11SMichael Tuexen 		if (m_notify == NULL) {
4000389b1b11SMichael Tuexen 			return;
4001389b1b11SMichael Tuexen 		}
4002389b1b11SMichael Tuexen 	}
4003389b1b11SMichael Tuexen 	SCTP_BUF_NEXT(m_notify) = NULL;
4004389b1b11SMichael Tuexen 	sre = mtod(m_notify, struct sctp_remote_error *);
400556711f94SMichael Tuexen 	memset(sre, 0, notif_len);
4006389b1b11SMichael Tuexen 	sre->sre_type = SCTP_REMOTE_ERROR;
4007389b1b11SMichael Tuexen 	sre->sre_flags = 0;
4008389b1b11SMichael Tuexen 	sre->sre_length = sizeof(struct sctp_remote_error);
4009389b1b11SMichael Tuexen 	sre->sre_error = error;
4010389b1b11SMichael Tuexen 	sre->sre_assoc_id = sctp_get_associd(stcb);
4011389b1b11SMichael Tuexen 	if (notif_len > sizeof(struct sctp_remote_error)) {
4012389b1b11SMichael Tuexen 		memcpy(sre->sre_data, chunk, chunk_len);
4013389b1b11SMichael Tuexen 		sre->sre_length += chunk_len;
4014389b1b11SMichael Tuexen 	}
4015389b1b11SMichael Tuexen 	SCTP_BUF_LEN(m_notify) = sre->sre_length;
4016389b1b11SMichael Tuexen 	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
4017389b1b11SMichael Tuexen 	    0, 0, stcb->asoc.context, 0, 0, 0,
4018389b1b11SMichael Tuexen 	    m_notify);
4019389b1b11SMichael Tuexen 	if (control != NULL) {
4020389b1b11SMichael Tuexen 		control->length = SCTP_BUF_LEN(m_notify);
402128cd0699SMichael Tuexen 		control->spec_flags = M_NOTIFICATION;
4022389b1b11SMichael Tuexen 		/* not that we need this */
4023389b1b11SMichael Tuexen 		control->tail_mbuf = m_notify;
4024389b1b11SMichael Tuexen 		sctp_add_to_readq(stcb->sctp_ep, stcb,
4025389b1b11SMichael Tuexen 		    control,
4026389b1b11SMichael Tuexen 		    &stcb->sctp_socket->so_rcv, 1,
4027389b1b11SMichael Tuexen 		    SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
4028389b1b11SMichael Tuexen 	} else {
4029389b1b11SMichael Tuexen 		sctp_m_freem(m_notify);
4030389b1b11SMichael Tuexen 	}
4031389b1b11SMichael Tuexen }
4032389b1b11SMichael Tuexen 
4033389b1b11SMichael Tuexen 
4034f8829a4aSRandall Stewart void
4035f8829a4aSRandall Stewart sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
4036ceaad40aSRandall Stewart     uint32_t error, void *data, int so_locked
4037ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
4038ceaad40aSRandall Stewart     SCTP_UNUSED
4039ceaad40aSRandall Stewart #endif
4040ceaad40aSRandall Stewart )
4041f8829a4aSRandall Stewart {
4042830d754dSRandall Stewart 	if ((stcb == NULL) ||
4043830d754dSRandall Stewart 	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
4044f8829a4aSRandall Stewart 	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
4045830d754dSRandall Stewart 	    (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) {
4046830d754dSRandall Stewart 		/* If the socket is gone we are out of here */
4047f8829a4aSRandall Stewart 		return;
4048f8829a4aSRandall Stewart 	}
4049a99b6783SRandall Stewart 	if (stcb->sctp_socket->so_rcv.sb_state & SBS_CANTRCVMORE) {
4050a99b6783SRandall Stewart 		return;
4051a99b6783SRandall Stewart 	}
4052839d21d6SMichael Tuexen 	if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) ||
4053839d21d6SMichael Tuexen 	    (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) {
405417205eccSRandall Stewart 		if ((notification == SCTP_NOTIFY_INTERFACE_DOWN) ||
405517205eccSRandall Stewart 		    (notification == SCTP_NOTIFY_INTERFACE_UP) ||
405617205eccSRandall Stewart 		    (notification == SCTP_NOTIFY_INTERFACE_CONFIRMED)) {
405717205eccSRandall Stewart 			/* Don't report these in front states */
405817205eccSRandall Stewart 			return;
405917205eccSRandall Stewart 		}
406017205eccSRandall Stewart 	}
4061f8829a4aSRandall Stewart 	switch (notification) {
4062f8829a4aSRandall Stewart 	case SCTP_NOTIFY_ASSOC_UP:
4063f8829a4aSRandall Stewart 		if (stcb->asoc.assoc_up_sent == 0) {
4064410a3b1eSMichael Tuexen 			sctp_notify_assoc_change(SCTP_COMM_UP, stcb, error, NULL, 0, so_locked);
4065f8829a4aSRandall Stewart 			stcb->asoc.assoc_up_sent = 1;
4066f8829a4aSRandall Stewart 		}
40672afb3e84SRandall Stewart 		if (stcb->asoc.adaptation_needed && (stcb->asoc.adaptation_sent == 0)) {
40687215cc1bSMichael Tuexen 			sctp_notify_adaptation_layer(stcb);
40692afb3e84SRandall Stewart 		}
4070c79bec9cSMichael Tuexen 		if (stcb->asoc.auth_supported == 0) {
4071830d754dSRandall Stewart 			sctp_ulp_notify(SCTP_NOTIFY_NO_PEER_AUTH, stcb, 0,
4072830d754dSRandall Stewart 			    NULL, so_locked);
4073830d754dSRandall Stewart 		}
4074f8829a4aSRandall Stewart 		break;
4075f8829a4aSRandall Stewart 	case SCTP_NOTIFY_ASSOC_DOWN:
4076410a3b1eSMichael Tuexen 		sctp_notify_assoc_change(SCTP_SHUTDOWN_COMP, stcb, error, NULL, 0, so_locked);
4077f8829a4aSRandall Stewart 		break;
4078f8829a4aSRandall Stewart 	case SCTP_NOTIFY_INTERFACE_DOWN:
4079f8829a4aSRandall Stewart 		{
4080f8829a4aSRandall Stewart 			struct sctp_nets *net;
4081f8829a4aSRandall Stewart 
4082f8829a4aSRandall Stewart 			net = (struct sctp_nets *)data;
4083f8829a4aSRandall Stewart 			sctp_notify_peer_addr_change(stcb, SCTP_ADDR_UNREACHABLE,
40843cb3567dSMichael Tuexen 			    (struct sockaddr *)&net->ro._l_addr, error, so_locked);
4085f8829a4aSRandall Stewart 			break;
4086f8829a4aSRandall Stewart 		}
4087f8829a4aSRandall Stewart 	case SCTP_NOTIFY_INTERFACE_UP:
4088f8829a4aSRandall Stewart 		{
4089f8829a4aSRandall Stewart 			struct sctp_nets *net;
4090f8829a4aSRandall Stewart 
4091f8829a4aSRandall Stewart 			net = (struct sctp_nets *)data;
4092f8829a4aSRandall Stewart 			sctp_notify_peer_addr_change(stcb, SCTP_ADDR_AVAILABLE,
40933cb3567dSMichael Tuexen 			    (struct sockaddr *)&net->ro._l_addr, error, so_locked);
4094f8829a4aSRandall Stewart 			break;
4095f8829a4aSRandall Stewart 		}
4096f8829a4aSRandall Stewart 	case SCTP_NOTIFY_INTERFACE_CONFIRMED:
4097f8829a4aSRandall Stewart 		{
4098f8829a4aSRandall Stewart 			struct sctp_nets *net;
4099f8829a4aSRandall Stewart 
4100f8829a4aSRandall Stewart 			net = (struct sctp_nets *)data;
4101f8829a4aSRandall Stewart 			sctp_notify_peer_addr_change(stcb, SCTP_ADDR_CONFIRMED,
41023cb3567dSMichael Tuexen 			    (struct sockaddr *)&net->ro._l_addr, error, so_locked);
4103f8829a4aSRandall Stewart 			break;
4104f8829a4aSRandall Stewart 		}
4105f8829a4aSRandall Stewart 	case SCTP_NOTIFY_SPECIAL_SP_FAIL:
4106f8829a4aSRandall Stewart 		sctp_notify_send_failed2(stcb, error,
4107ceaad40aSRandall Stewart 		    (struct sctp_stream_queue_pending *)data, so_locked);
4108f8829a4aSRandall Stewart 		break;
41091edc9dbaSMichael Tuexen 	case SCTP_NOTIFY_SENT_DG_FAIL:
41101edc9dbaSMichael Tuexen 		sctp_notify_send_failed(stcb, 1, error,
41111edc9dbaSMichael Tuexen 		    (struct sctp_tmit_chunk *)data, so_locked);
41121edc9dbaSMichael Tuexen 		break;
41131edc9dbaSMichael Tuexen 	case SCTP_NOTIFY_UNSENT_DG_FAIL:
41141edc9dbaSMichael Tuexen 		sctp_notify_send_failed(stcb, 0, error,
4115ceaad40aSRandall Stewart 		    (struct sctp_tmit_chunk *)data, so_locked);
4116f8829a4aSRandall Stewart 		break;
4117f8829a4aSRandall Stewart 	case SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION:
41189a6142d8SRandall Stewart 		{
41199a6142d8SRandall Stewart 			uint32_t val;
41209a6142d8SRandall Stewart 
41219a6142d8SRandall Stewart 			val = *((uint32_t *)data);
41229a6142d8SRandall Stewart 
4123810ec536SMichael Tuexen 			sctp_notify_partial_delivery_indication(stcb, error, val, so_locked);
4124f8829a4aSRandall Stewart 			break;
4125810ec536SMichael Tuexen 		}
4126410a3b1eSMichael Tuexen 	case SCTP_NOTIFY_ASSOC_LOC_ABORTED:
4127839d21d6SMichael Tuexen 		if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) ||
4128839d21d6SMichael Tuexen 		    (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) {
4129410a3b1eSMichael Tuexen 			sctp_notify_assoc_change(SCTP_CANT_STR_ASSOC, stcb, error, data, 0, so_locked);
4130c105859eSRandall Stewart 		} else {
4131410a3b1eSMichael Tuexen 			sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error, data, 0, so_locked);
4132410a3b1eSMichael Tuexen 		}
4133410a3b1eSMichael Tuexen 		break;
4134410a3b1eSMichael Tuexen 	case SCTP_NOTIFY_ASSOC_REM_ABORTED:
4135839d21d6SMichael Tuexen 		if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) ||
4136839d21d6SMichael Tuexen 		    (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) {
4137410a3b1eSMichael Tuexen 			sctp_notify_assoc_change(SCTP_CANT_STR_ASSOC, stcb, error, data, 1, so_locked);
4138410a3b1eSMichael Tuexen 		} else {
4139410a3b1eSMichael Tuexen 			sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error, data, 1, so_locked);
4140c105859eSRandall Stewart 		}
4141f8829a4aSRandall Stewart 		break;
4142f8829a4aSRandall Stewart 	case SCTP_NOTIFY_ASSOC_RESTART:
4143410a3b1eSMichael Tuexen 		sctp_notify_assoc_change(SCTP_RESTART, stcb, error, NULL, 0, so_locked);
4144c79bec9cSMichael Tuexen 		if (stcb->asoc.auth_supported == 0) {
4145830d754dSRandall Stewart 			sctp_ulp_notify(SCTP_NOTIFY_NO_PEER_AUTH, stcb, 0,
4146830d754dSRandall Stewart 			    NULL, so_locked);
4147830d754dSRandall Stewart 		}
4148f8829a4aSRandall Stewart 		break;
4149f8829a4aSRandall Stewart 	case SCTP_NOTIFY_STR_RESET_SEND:
4150d7714577SMichael Tuexen 		sctp_notify_stream_reset(stcb, error, ((uint16_t *)data), SCTP_STREAM_RESET_OUTGOING_SSN);
4151f8829a4aSRandall Stewart 		break;
4152f8829a4aSRandall Stewart 	case SCTP_NOTIFY_STR_RESET_RECV:
4153d7714577SMichael Tuexen 		sctp_notify_stream_reset(stcb, error, ((uint16_t *)data), SCTP_STREAM_RESET_INCOMING);
4154f8829a4aSRandall Stewart 		break;
4155f8829a4aSRandall Stewart 	case SCTP_NOTIFY_STR_RESET_FAILED_OUT:
4156c4e848b7SRandall Stewart 		sctp_notify_stream_reset(stcb, error, ((uint16_t *)data),
4157d7714577SMichael Tuexen 		    (SCTP_STREAM_RESET_OUTGOING_SSN | SCTP_STREAM_RESET_FAILED));
4158f8829a4aSRandall Stewart 		break;
4159d4260646SMichael Tuexen 	case SCTP_NOTIFY_STR_RESET_DENIED_OUT:
4160d4260646SMichael Tuexen 		sctp_notify_stream_reset(stcb, error, ((uint16_t *)data),
4161d4260646SMichael Tuexen 		    (SCTP_STREAM_RESET_OUTGOING_SSN | SCTP_STREAM_RESET_DENIED));
4162d4260646SMichael Tuexen 		break;
4163f8829a4aSRandall Stewart 	case SCTP_NOTIFY_STR_RESET_FAILED_IN:
4164c4e848b7SRandall Stewart 		sctp_notify_stream_reset(stcb, error, ((uint16_t *)data),
4165d7714577SMichael Tuexen 		    (SCTP_STREAM_RESET_INCOMING | SCTP_STREAM_RESET_FAILED));
4166f8829a4aSRandall Stewart 		break;
4167d4260646SMichael Tuexen 	case SCTP_NOTIFY_STR_RESET_DENIED_IN:
4168d4260646SMichael Tuexen 		sctp_notify_stream_reset(stcb, error, ((uint16_t *)data),
4169d4260646SMichael Tuexen 		    (SCTP_STREAM_RESET_INCOMING | SCTP_STREAM_RESET_DENIED));
4170d4260646SMichael Tuexen 		break;
4171f8829a4aSRandall Stewart 	case SCTP_NOTIFY_ASCONF_ADD_IP:
4172f8829a4aSRandall Stewart 		sctp_notify_peer_addr_change(stcb, SCTP_ADDR_ADDED, data,
41733cb3567dSMichael Tuexen 		    error, so_locked);
4174f8829a4aSRandall Stewart 		break;
4175f8829a4aSRandall Stewart 	case SCTP_NOTIFY_ASCONF_DELETE_IP:
4176f8829a4aSRandall Stewart 		sctp_notify_peer_addr_change(stcb, SCTP_ADDR_REMOVED, data,
41773cb3567dSMichael Tuexen 		    error, so_locked);
4178f8829a4aSRandall Stewart 		break;
4179f8829a4aSRandall Stewart 	case SCTP_NOTIFY_ASCONF_SET_PRIMARY:
4180f8829a4aSRandall Stewart 		sctp_notify_peer_addr_change(stcb, SCTP_ADDR_MADE_PRIM, data,
41813cb3567dSMichael Tuexen 		    error, so_locked);
4182f8829a4aSRandall Stewart 		break;
4183f8829a4aSRandall Stewart 	case SCTP_NOTIFY_PEER_SHUTDOWN:
4184f8829a4aSRandall Stewart 		sctp_notify_shutdown_event(stcb);
4185f8829a4aSRandall Stewart 		break;
4186f8829a4aSRandall Stewart 	case SCTP_NOTIFY_AUTH_NEW_KEY:
418778f28045SMichael Tuexen 		sctp_notify_authentication(stcb, SCTP_AUTH_NEW_KEY, error,
4188830d754dSRandall Stewart 		    (uint16_t)(uintptr_t)data,
4189830d754dSRandall Stewart 		    so_locked);
4190f8829a4aSRandall Stewart 		break;
4191830d754dSRandall Stewart 	case SCTP_NOTIFY_AUTH_FREE_KEY:
4192830d754dSRandall Stewart 		sctp_notify_authentication(stcb, SCTP_AUTH_FREE_KEY, error,
4193830d754dSRandall Stewart 		    (uint16_t)(uintptr_t)data,
4194830d754dSRandall Stewart 		    so_locked);
4195f8829a4aSRandall Stewart 		break;
4196830d754dSRandall Stewart 	case SCTP_NOTIFY_NO_PEER_AUTH:
4197830d754dSRandall Stewart 		sctp_notify_authentication(stcb, SCTP_AUTH_NO_AUTH, error,
4198830d754dSRandall Stewart 		    (uint16_t)(uintptr_t)data,
4199830d754dSRandall Stewart 		    so_locked);
4200830d754dSRandall Stewart 		break;
4201830d754dSRandall Stewart 	case SCTP_NOTIFY_SENDER_DRY:
4202830d754dSRandall Stewart 		sctp_notify_sender_dry_event(stcb, so_locked);
4203830d754dSRandall Stewart 		break;
4204389b1b11SMichael Tuexen 	case SCTP_NOTIFY_REMOTE_ERROR:
4205389b1b11SMichael Tuexen 		sctp_notify_remote_error(stcb, error, data);
4206389b1b11SMichael Tuexen 		break;
4207f8829a4aSRandall Stewart 	default:
4208ad81507eSRandall Stewart 		SCTPDBG(SCTP_DEBUG_UTIL1, "%s: unknown notification %xh (%u)\n",
42096e9c45e0SMichael Tuexen 		    __func__, notification, notification);
4210f8829a4aSRandall Stewart 		break;
4211f8829a4aSRandall Stewart 	}			/* end switch */
4212f8829a4aSRandall Stewart }
4213f8829a4aSRandall Stewart 
4214f8829a4aSRandall Stewart void
42151edc9dbaSMichael Tuexen sctp_report_all_outbound(struct sctp_tcb *stcb, uint16_t error, int holds_lock, int so_locked
4216ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
4217ceaad40aSRandall Stewart     SCTP_UNUSED
4218ceaad40aSRandall Stewart #endif
4219ceaad40aSRandall Stewart )
4220f8829a4aSRandall Stewart {
4221f8829a4aSRandall Stewart 	struct sctp_association *asoc;
4222f8829a4aSRandall Stewart 	struct sctp_stream_out *outs;
42234a9ef3f8SMichael Tuexen 	struct sctp_tmit_chunk *chk, *nchk;
42244a9ef3f8SMichael Tuexen 	struct sctp_stream_queue_pending *sp, *nsp;
42257f34832bSRandall Stewart 	int i;
4226f8829a4aSRandall Stewart 
4227ad81507eSRandall Stewart 	if (stcb == NULL) {
4228ad81507eSRandall Stewart 		return;
4229ad81507eSRandall Stewart 	}
42304a9ef3f8SMichael Tuexen 	asoc = &stcb->asoc;
42314a9ef3f8SMichael Tuexen 	if (asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) {
4232478fbccbSRandall Stewart 		/* already being freed */
4233478fbccbSRandall Stewart 		return;
4234478fbccbSRandall Stewart 	}
4235f8829a4aSRandall Stewart 	if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
4236f8829a4aSRandall Stewart 	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
42374a9ef3f8SMichael Tuexen 	    (asoc->state & SCTP_STATE_CLOSED_SOCKET)) {
4238f8829a4aSRandall Stewart 		return;
4239f8829a4aSRandall Stewart 	}
4240f8829a4aSRandall Stewart 	/* now through all the gunk freeing chunks */
4241ad81507eSRandall Stewart 	if (holds_lock == 0) {
42427f34832bSRandall Stewart 		SCTP_TCB_SEND_LOCK(stcb);
4243ad81507eSRandall Stewart 	}
4244d00aff5dSRandall Stewart 	/* sent queue SHOULD be empty */
42454a9ef3f8SMichael Tuexen 	TAILQ_FOREACH_SAFE(chk, &asoc->sent_queue, sctp_next, nchk) {
4246d00aff5dSRandall Stewart 		TAILQ_REMOVE(&asoc->sent_queue, chk, sctp_next);
4247d00aff5dSRandall Stewart 		asoc->sent_queue_cnt--;
4248325c8c46SMichael Tuexen 		if (chk->sent != SCTP_DATAGRAM_NR_ACKED) {
424949656eefSMichael Tuexen 			if (asoc->strmout[chk->rec.data.sid].chunks_on_queues > 0) {
425049656eefSMichael Tuexen 				asoc->strmout[chk->rec.data.sid].chunks_on_queues--;
4251a7ad6026SMichael Tuexen #ifdef INVARIANTS
4252a7ad6026SMichael Tuexen 			} else {
425349656eefSMichael Tuexen 				panic("No chunks on the queues for sid %u.", chk->rec.data.sid);
4254a7ad6026SMichael Tuexen #endif
4255a7ad6026SMichael Tuexen 			}
4256a7ad6026SMichael Tuexen 		}
42570c0982b8SRandall Stewart 		if (chk->data != NULL) {
4258d00aff5dSRandall Stewart 			sctp_free_bufspace(stcb, asoc, chk, 1);
42591edc9dbaSMichael Tuexen 			sctp_ulp_notify(SCTP_NOTIFY_SENT_DG_FAIL, stcb,
42601edc9dbaSMichael Tuexen 			    error, chk, so_locked);
4261810ec536SMichael Tuexen 			if (chk->data) {
4262d00aff5dSRandall Stewart 				sctp_m_freem(chk->data);
4263d00aff5dSRandall Stewart 				chk->data = NULL;
4264d00aff5dSRandall Stewart 			}
4265810ec536SMichael Tuexen 		}
4266689e6a5fSMichael Tuexen 		sctp_free_a_chunk(stcb, chk, so_locked);
4267d00aff5dSRandall Stewart 		/* sa_ignore FREED_MEMORY */
4268d00aff5dSRandall Stewart 	}
4269d00aff5dSRandall Stewart 	/* pending send queue SHOULD be empty */
42704a9ef3f8SMichael Tuexen 	TAILQ_FOREACH_SAFE(chk, &asoc->send_queue, sctp_next, nchk) {
4271d00aff5dSRandall Stewart 		TAILQ_REMOVE(&asoc->send_queue, chk, sctp_next);
4272d00aff5dSRandall Stewart 		asoc->send_queue_cnt--;
427349656eefSMichael Tuexen 		if (asoc->strmout[chk->rec.data.sid].chunks_on_queues > 0) {
427449656eefSMichael Tuexen 			asoc->strmout[chk->rec.data.sid].chunks_on_queues--;
4275a7ad6026SMichael Tuexen #ifdef INVARIANTS
4276a7ad6026SMichael Tuexen 		} else {
427749656eefSMichael Tuexen 			panic("No chunks on the queues for sid %u.", chk->rec.data.sid);
4278a7ad6026SMichael Tuexen #endif
4279a7ad6026SMichael Tuexen 		}
42800c0982b8SRandall Stewart 		if (chk->data != NULL) {
4281d00aff5dSRandall Stewart 			sctp_free_bufspace(stcb, asoc, chk, 1);
42821edc9dbaSMichael Tuexen 			sctp_ulp_notify(SCTP_NOTIFY_UNSENT_DG_FAIL, stcb,
42831edc9dbaSMichael Tuexen 			    error, chk, so_locked);
4284810ec536SMichael Tuexen 			if (chk->data) {
4285d00aff5dSRandall Stewart 				sctp_m_freem(chk->data);
4286d00aff5dSRandall Stewart 				chk->data = NULL;
4287d00aff5dSRandall Stewart 			}
4288810ec536SMichael Tuexen 		}
4289689e6a5fSMichael Tuexen 		sctp_free_a_chunk(stcb, chk, so_locked);
4290d00aff5dSRandall Stewart 		/* sa_ignore FREED_MEMORY */
4291d00aff5dSRandall Stewart 	}
42924a9ef3f8SMichael Tuexen 	for (i = 0; i < asoc->streamoutcnt; i++) {
42937f34832bSRandall Stewart 		/* For each stream */
42944a9ef3f8SMichael Tuexen 		outs = &asoc->strmout[i];
42957f34832bSRandall Stewart 		/* clean up any sends there */
42964a9ef3f8SMichael Tuexen 		TAILQ_FOREACH_SAFE(sp, &outs->outqueue, next, nsp) {
42974d58b0c3SMichael Tuexen 			atomic_subtract_int(&asoc->stream_queue_cnt, 1);
4298f8829a4aSRandall Stewart 			TAILQ_REMOVE(&outs->outqueue, sp, next);
4299d9707e43SMichael Tuexen 			stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, outs, sp, 1);
4300f8829a4aSRandall Stewart 			sctp_free_spbufspace(stcb, asoc, sp);
4301478fbccbSRandall Stewart 			if (sp->data) {
4302f8829a4aSRandall Stewart 				sctp_ulp_notify(SCTP_NOTIFY_SPECIAL_SP_FAIL, stcb,
43031edc9dbaSMichael Tuexen 				    error, (void *)sp, so_locked);
4304f8829a4aSRandall Stewart 				if (sp->data) {
4305f8829a4aSRandall Stewart 					sctp_m_freem(sp->data);
4306f8829a4aSRandall Stewart 					sp->data = NULL;
4307d07b2ac6SMichael Tuexen 					sp->tail_mbuf = NULL;
4308d07b2ac6SMichael Tuexen 					sp->length = 0;
4309f8829a4aSRandall Stewart 				}
4310478fbccbSRandall Stewart 			}
43119eea4a2dSMichael Tuexen 			if (sp->net) {
4312f8829a4aSRandall Stewart 				sctp_free_remote_addr(sp->net);
4313f8829a4aSRandall Stewart 				sp->net = NULL;
43149eea4a2dSMichael Tuexen 			}
4315f8829a4aSRandall Stewart 			/* Free the chunk */
4316689e6a5fSMichael Tuexen 			sctp_free_a_strmoq(stcb, sp, so_locked);
43173c503c28SRandall Stewart 			/* sa_ignore FREED_MEMORY */
4318f8829a4aSRandall Stewart 		}
4319f8829a4aSRandall Stewart 	}
4320f8829a4aSRandall Stewart 
4321ad81507eSRandall Stewart 	if (holds_lock == 0) {
43227f34832bSRandall Stewart 		SCTP_TCB_SEND_UNLOCK(stcb);
4323f8829a4aSRandall Stewart 	}
4324ad81507eSRandall Stewart }
4325f8829a4aSRandall Stewart 
4326f8829a4aSRandall Stewart void
4327410a3b1eSMichael Tuexen sctp_abort_notification(struct sctp_tcb *stcb, uint8_t from_peer, uint16_t error,
4328a2b42326SMichael Tuexen     struct sctp_abort_chunk *abort, int so_locked
4329ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
4330ceaad40aSRandall Stewart     SCTP_UNUSED
4331ceaad40aSRandall Stewart #endif
4332ceaad40aSRandall Stewart )
4333f8829a4aSRandall Stewart {
4334ad81507eSRandall Stewart 	if (stcb == NULL) {
4335ad81507eSRandall Stewart 		return;
4336ad81507eSRandall Stewart 	}
4337c55b70ceSMichael Tuexen 	if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4338c55b70ceSMichael Tuexen 	    ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
4339c55b70ceSMichael Tuexen 	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED))) {
4340c55b70ceSMichael Tuexen 		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_WAS_ABORTED;
4341c55b70ceSMichael Tuexen 	}
4342f8829a4aSRandall Stewart 	if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
4343f8829a4aSRandall Stewart 	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
4344f8829a4aSRandall Stewart 	    (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) {
4345f8829a4aSRandall Stewart 		return;
4346f8829a4aSRandall Stewart 	}
4347f8829a4aSRandall Stewart 	/* Tell them we lost the asoc */
43486982c0faSMichael Tuexen 	sctp_report_all_outbound(stcb, error, 0, so_locked);
4349410a3b1eSMichael Tuexen 	if (from_peer) {
4350410a3b1eSMichael Tuexen 		sctp_ulp_notify(SCTP_NOTIFY_ASSOC_REM_ABORTED, stcb, error, abort, so_locked);
4351410a3b1eSMichael Tuexen 	} else {
4352410a3b1eSMichael Tuexen 		sctp_ulp_notify(SCTP_NOTIFY_ASSOC_LOC_ABORTED, stcb, error, abort, so_locked);
4353410a3b1eSMichael Tuexen 	}
4354f8829a4aSRandall Stewart }
4355f8829a4aSRandall Stewart 
4356f8829a4aSRandall Stewart void
4357f8829a4aSRandall Stewart sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
4358b1754ad1SMichael Tuexen     struct mbuf *m, int iphlen,
4359b1754ad1SMichael Tuexen     struct sockaddr *src, struct sockaddr *dst,
4360b1754ad1SMichael Tuexen     struct sctphdr *sh, struct mbuf *op_err,
4361457b4b88SMichael Tuexen     uint8_t mflowtype, uint32_t mflowid,
4362c54a18d2SRandall Stewart     uint32_t vrf_id, uint16_t port)
4363f8829a4aSRandall Stewart {
4364f8829a4aSRandall Stewart 	uint32_t vtag;
4365ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
4366ceaad40aSRandall Stewart 	struct socket *so;
4367ceaad40aSRandall Stewart #endif
4368ceaad40aSRandall Stewart 
4369f8829a4aSRandall Stewart 	vtag = 0;
4370f8829a4aSRandall Stewart 	if (stcb != NULL) {
4371f8829a4aSRandall Stewart 		vtag = stcb->asoc.peer_vtag;
437217205eccSRandall Stewart 		vrf_id = stcb->asoc.vrf_id;
4373f8829a4aSRandall Stewart 	}
4374b1754ad1SMichael Tuexen 	sctp_send_abort(m, iphlen, src, dst, sh, vtag, op_err,
4375d089f9b9SMichael Tuexen 	    mflowtype, mflowid, inp->fibnum,
4376f30ac432SMichael Tuexen 	    vrf_id, port);
4377f8829a4aSRandall Stewart 	if (stcb != NULL) {
4378884d8c53SMichael Tuexen 		/* We have a TCB to abort, send notification too */
4379884d8c53SMichael Tuexen 		sctp_abort_notification(stcb, 0, 0, NULL, SCTP_SO_NOT_LOCKED);
4380839d21d6SMichael Tuexen 		SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_WAS_ABORTED);
4381f8829a4aSRandall Stewart 		/* Ok, now lets free it */
4382ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
4383ceaad40aSRandall Stewart 		so = SCTP_INP_SO(inp);
4384ceaad40aSRandall Stewart 		atomic_add_int(&stcb->asoc.refcnt, 1);
4385ceaad40aSRandall Stewart 		SCTP_TCB_UNLOCK(stcb);
4386ceaad40aSRandall Stewart 		SCTP_SOCKET_LOCK(so, 1);
4387ceaad40aSRandall Stewart 		SCTP_TCB_LOCK(stcb);
4388ceaad40aSRandall Stewart 		atomic_subtract_int(&stcb->asoc.refcnt, 1);
4389ceaad40aSRandall Stewart #endif
43900271d0cdSMichael Tuexen 		SCTP_STAT_INCR_COUNTER32(sctps_aborted);
4391839d21d6SMichael Tuexen 		if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
4392839d21d6SMichael Tuexen 		    (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
43930271d0cdSMichael Tuexen 			SCTP_STAT_DECR_GAUGE32(sctps_currestab);
43940271d0cdSMichael Tuexen 		}
4395ba785902SMichael Tuexen 		(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
4396ba785902SMichael Tuexen 		    SCTP_FROM_SCTPUTIL + SCTP_LOC_4);
4397ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
4398ceaad40aSRandall Stewart 		SCTP_SOCKET_UNLOCK(so, 1);
4399ceaad40aSRandall Stewart #endif
4400f8829a4aSRandall Stewart 	}
4401f8829a4aSRandall Stewart }
4402f1f73e57SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS
4403f1f73e57SRandall Stewart void
4404f1f73e57SRandall Stewart sctp_print_out_track_log(struct sctp_tcb *stcb)
4405f1f73e57SRandall Stewart {
440618e198d3SRandall Stewart #ifdef NOSIY_PRINTS
4407f1f73e57SRandall Stewart 	int i;
4408f1f73e57SRandall Stewart 
4409ad81507eSRandall Stewart 	SCTP_PRINTF("Last ep reason:%x\n", stcb->sctp_ep->last_abort_code);
4410ad81507eSRandall Stewart 	SCTP_PRINTF("IN bound TSN log-aaa\n");
4411f1f73e57SRandall Stewart 	if ((stcb->asoc.tsn_in_at == 0) && (stcb->asoc.tsn_in_wrapped == 0)) {
4412ad81507eSRandall Stewart 		SCTP_PRINTF("None rcvd\n");
4413f1f73e57SRandall Stewart 		goto none_in;
4414f1f73e57SRandall Stewart 	}
4415f1f73e57SRandall Stewart 	if (stcb->asoc.tsn_in_wrapped) {
4416f1f73e57SRandall Stewart 		for (i = stcb->asoc.tsn_in_at; i < SCTP_TSN_LOG_SIZE; i++) {
4417ad81507eSRandall Stewart 			SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n",
4418f1f73e57SRandall Stewart 			    stcb->asoc.in_tsnlog[i].tsn,
4419f1f73e57SRandall Stewart 			    stcb->asoc.in_tsnlog[i].strm,
4420f1f73e57SRandall Stewart 			    stcb->asoc.in_tsnlog[i].seq,
4421f1f73e57SRandall Stewart 			    stcb->asoc.in_tsnlog[i].flgs,
4422f1f73e57SRandall Stewart 			    stcb->asoc.in_tsnlog[i].sz);
4423f1f73e57SRandall Stewart 		}
4424f1f73e57SRandall Stewart 	}
4425f1f73e57SRandall Stewart 	if (stcb->asoc.tsn_in_at) {
4426f1f73e57SRandall Stewart 		for (i = 0; i < stcb->asoc.tsn_in_at; i++) {
4427ad81507eSRandall Stewart 			SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n",
4428f1f73e57SRandall Stewart 			    stcb->asoc.in_tsnlog[i].tsn,
4429f1f73e57SRandall Stewart 			    stcb->asoc.in_tsnlog[i].strm,
4430f1f73e57SRandall Stewart 			    stcb->asoc.in_tsnlog[i].seq,
4431f1f73e57SRandall Stewart 			    stcb->asoc.in_tsnlog[i].flgs,
4432f1f73e57SRandall Stewart 			    stcb->asoc.in_tsnlog[i].sz);
4433f1f73e57SRandall Stewart 		}
4434f1f73e57SRandall Stewart 	}
4435f1f73e57SRandall Stewart none_in:
4436ad81507eSRandall Stewart 	SCTP_PRINTF("OUT bound TSN log-aaa\n");
4437ad81507eSRandall Stewart 	if ((stcb->asoc.tsn_out_at == 0) &&
4438ad81507eSRandall Stewart 	    (stcb->asoc.tsn_out_wrapped == 0)) {
4439ad81507eSRandall Stewart 		SCTP_PRINTF("None sent\n");
4440f1f73e57SRandall Stewart 	}
4441f1f73e57SRandall Stewart 	if (stcb->asoc.tsn_out_wrapped) {
4442f1f73e57SRandall Stewart 		for (i = stcb->asoc.tsn_out_at; i < SCTP_TSN_LOG_SIZE; i++) {
4443ad81507eSRandall Stewart 			SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n",
4444f1f73e57SRandall Stewart 			    stcb->asoc.out_tsnlog[i].tsn,
4445f1f73e57SRandall Stewart 			    stcb->asoc.out_tsnlog[i].strm,
4446f1f73e57SRandall Stewart 			    stcb->asoc.out_tsnlog[i].seq,
4447f1f73e57SRandall Stewart 			    stcb->asoc.out_tsnlog[i].flgs,
4448f1f73e57SRandall Stewart 			    stcb->asoc.out_tsnlog[i].sz);
4449f1f73e57SRandall Stewart 		}
4450f1f73e57SRandall Stewart 	}
4451f1f73e57SRandall Stewart 	if (stcb->asoc.tsn_out_at) {
4452f1f73e57SRandall Stewart 		for (i = 0; i < stcb->asoc.tsn_out_at; i++) {
4453ad81507eSRandall Stewart 			SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n",
4454f1f73e57SRandall Stewart 			    stcb->asoc.out_tsnlog[i].tsn,
4455f1f73e57SRandall Stewart 			    stcb->asoc.out_tsnlog[i].strm,
4456f1f73e57SRandall Stewart 			    stcb->asoc.out_tsnlog[i].seq,
4457f1f73e57SRandall Stewart 			    stcb->asoc.out_tsnlog[i].flgs,
4458f1f73e57SRandall Stewart 			    stcb->asoc.out_tsnlog[i].sz);
4459f1f73e57SRandall Stewart 		}
4460f1f73e57SRandall Stewart 	}
446118e198d3SRandall Stewart #endif
4462f1f73e57SRandall Stewart }
4463f1f73e57SRandall Stewart #endif
4464f1f73e57SRandall Stewart 
4465f8829a4aSRandall Stewart void
4466f8829a4aSRandall Stewart sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
4467a2b42326SMichael Tuexen     struct mbuf *op_err,
4468ceaad40aSRandall Stewart     int so_locked
4469ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
4470ceaad40aSRandall Stewart     SCTP_UNUSED
4471ceaad40aSRandall Stewart #endif
4472ceaad40aSRandall Stewart )
4473f8829a4aSRandall Stewart {
4474ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
4475ceaad40aSRandall Stewart 	struct socket *so;
4476ceaad40aSRandall Stewart #endif
4477ceaad40aSRandall Stewart 
4478ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
4479ceaad40aSRandall Stewart 	so = SCTP_INP_SO(inp);
4480ceaad40aSRandall Stewart #endif
4481f8829a4aSRandall Stewart 	if (stcb == NULL) {
4482f8829a4aSRandall Stewart 		/* Got to have a TCB */
4483f8829a4aSRandall Stewart 		if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
4484fe1831e0SMichael Tuexen 			if (LIST_EMPTY(&inp->sctp_asoc_list)) {
4485b0552ae2SRandall Stewart 				sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
4486b0552ae2SRandall Stewart 				    SCTP_CALLED_DIRECTLY_NOCMPSET);
4487f8829a4aSRandall Stewart 			}
4488f8829a4aSRandall Stewart 		}
4489f8829a4aSRandall Stewart 		return;
449063981c2bSRandall Stewart 	} else {
4491839d21d6SMichael Tuexen 		SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_WAS_ABORTED);
4492f8829a4aSRandall Stewart 	}
4493f8829a4aSRandall Stewart 	/* notify the peer */
4494ceaad40aSRandall Stewart 	sctp_send_abort_tcb(stcb, op_err, so_locked);
4495f8829a4aSRandall Stewart 	SCTP_STAT_INCR_COUNTER32(sctps_aborted);
4496839d21d6SMichael Tuexen 	if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
4497839d21d6SMichael Tuexen 	    (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
4498f8829a4aSRandall Stewart 		SCTP_STAT_DECR_GAUGE32(sctps_currestab);
4499f8829a4aSRandall Stewart 	}
4500884d8c53SMichael Tuexen 	/* notify the ulp */
4501884d8c53SMichael Tuexen 	if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
4502884d8c53SMichael Tuexen 		sctp_abort_notification(stcb, 0, 0, NULL, so_locked);
4503884d8c53SMichael Tuexen 	}
4504f8829a4aSRandall Stewart 	/* now free the asoc */
4505f1f73e57SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS
4506f1f73e57SRandall Stewart 	sctp_print_out_track_log(stcb);
4507f1f73e57SRandall Stewart #endif
4508ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
4509ceaad40aSRandall Stewart 	if (!so_locked) {
4510ceaad40aSRandall Stewart 		atomic_add_int(&stcb->asoc.refcnt, 1);
4511ceaad40aSRandall Stewart 		SCTP_TCB_UNLOCK(stcb);
4512ceaad40aSRandall Stewart 		SCTP_SOCKET_LOCK(so, 1);
4513ceaad40aSRandall Stewart 		SCTP_TCB_LOCK(stcb);
4514ceaad40aSRandall Stewart 		atomic_subtract_int(&stcb->asoc.refcnt, 1);
4515ceaad40aSRandall Stewart 	}
4516ceaad40aSRandall Stewart #endif
4517ba785902SMichael Tuexen 	(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
4518ba785902SMichael Tuexen 	    SCTP_FROM_SCTPUTIL + SCTP_LOC_5);
4519ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
4520ceaad40aSRandall Stewart 	if (!so_locked) {
4521ceaad40aSRandall Stewart 		SCTP_SOCKET_UNLOCK(so, 1);
4522ceaad40aSRandall Stewart 	}
4523ceaad40aSRandall Stewart #endif
4524f8829a4aSRandall Stewart }
4525f8829a4aSRandall Stewart 
4526f8829a4aSRandall Stewart void
4527b1754ad1SMichael Tuexen sctp_handle_ootb(struct mbuf *m, int iphlen, int offset,
4528b1754ad1SMichael Tuexen     struct sockaddr *src, struct sockaddr *dst,
4529b1754ad1SMichael Tuexen     struct sctphdr *sh, struct sctp_inpcb *inp,
4530ff1ffd74SMichael Tuexen     struct mbuf *cause,
4531d089f9b9SMichael Tuexen     uint8_t mflowtype, uint32_t mflowid, uint16_t fibnum,
4532f30ac432SMichael Tuexen     uint32_t vrf_id, uint16_t port)
4533f8829a4aSRandall Stewart {
4534f8829a4aSRandall Stewart 	struct sctp_chunkhdr *ch, chunk_buf;
4535f8829a4aSRandall Stewart 	unsigned int chk_length;
4536c58e60beSMichael Tuexen 	int contains_init_chunk;
4537f8829a4aSRandall Stewart 
4538f8829a4aSRandall Stewart 	SCTP_STAT_INCR_COUNTER32(sctps_outoftheblue);
4539f8829a4aSRandall Stewart 	/* Generate a TO address for future reference */
4540f8829a4aSRandall Stewart 	if (inp && (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
4541fe1831e0SMichael Tuexen 		if (LIST_EMPTY(&inp->sctp_asoc_list)) {
4542b0552ae2SRandall Stewart 			sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
4543b0552ae2SRandall Stewart 			    SCTP_CALLED_DIRECTLY_NOCMPSET);
4544f8829a4aSRandall Stewart 		}
4545f8829a4aSRandall Stewart 	}
4546c58e60beSMichael Tuexen 	contains_init_chunk = 0;
4547f8829a4aSRandall Stewart 	ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset,
4548f8829a4aSRandall Stewart 	    sizeof(*ch), (uint8_t *)&chunk_buf);
4549f8829a4aSRandall Stewart 	while (ch != NULL) {
4550f8829a4aSRandall Stewart 		chk_length = ntohs(ch->chunk_length);
4551f8829a4aSRandall Stewart 		if (chk_length < sizeof(*ch)) {
4552f8829a4aSRandall Stewart 			/* break to abort land */
4553f8829a4aSRandall Stewart 			break;
4554f8829a4aSRandall Stewart 		}
4555f8829a4aSRandall Stewart 		switch (ch->chunk_type) {
4556c58e60beSMichael Tuexen 		case SCTP_INIT:
4557c58e60beSMichael Tuexen 			contains_init_chunk = 1;
4558c58e60beSMichael Tuexen 			break;
4559f8829a4aSRandall Stewart 		case SCTP_PACKET_DROPPED:
4560f8829a4aSRandall Stewart 			/* we don't respond to pkt-dropped */
4561f8829a4aSRandall Stewart 			return;
4562f8829a4aSRandall Stewart 		case SCTP_ABORT_ASSOCIATION:
4563f8829a4aSRandall Stewart 			/* we don't respond with an ABORT to an ABORT */
4564f8829a4aSRandall Stewart 			return;
4565f8829a4aSRandall Stewart 		case SCTP_SHUTDOWN_COMPLETE:
4566f8829a4aSRandall Stewart 			/*
4567f8829a4aSRandall Stewart 			 * we ignore it since we are not waiting for it and
4568f8829a4aSRandall Stewart 			 * peer is gone
4569f8829a4aSRandall Stewart 			 */
4570f8829a4aSRandall Stewart 			return;
4571f8829a4aSRandall Stewart 		case SCTP_SHUTDOWN_ACK:
4572b1754ad1SMichael Tuexen 			sctp_send_shutdown_complete2(src, dst, sh,
4573d089f9b9SMichael Tuexen 			    mflowtype, mflowid, fibnum,
4574f30ac432SMichael Tuexen 			    vrf_id, port);
4575f8829a4aSRandall Stewart 			return;
4576f8829a4aSRandall Stewart 		default:
4577f8829a4aSRandall Stewart 			break;
4578f8829a4aSRandall Stewart 		}
4579f8829a4aSRandall Stewart 		offset += SCTP_SIZE32(chk_length);
4580f8829a4aSRandall Stewart 		ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset,
4581f8829a4aSRandall Stewart 		    sizeof(*ch), (uint8_t *)&chunk_buf);
4582f8829a4aSRandall Stewart 	}
4583c58e60beSMichael Tuexen 	if ((SCTP_BASE_SYSCTL(sctp_blackhole) == 0) ||
4584c58e60beSMichael Tuexen 	    ((SCTP_BASE_SYSCTL(sctp_blackhole) == 1) &&
4585c58e60beSMichael Tuexen 	    (contains_init_chunk == 0))) {
4586ff1ffd74SMichael Tuexen 		sctp_send_abort(m, iphlen, src, dst, sh, 0, cause,
4587d089f9b9SMichael Tuexen 		    mflowtype, mflowid, fibnum,
4588f30ac432SMichael Tuexen 		    vrf_id, port);
4589f8829a4aSRandall Stewart 	}
4590c58e60beSMichael Tuexen }
4591f8829a4aSRandall Stewart 
4592f8829a4aSRandall Stewart /*
4593f8829a4aSRandall Stewart  * check the inbound datagram to make sure there is not an abort inside it,
4594f8829a4aSRandall Stewart  * if there is return 1, else return 0.
4595f8829a4aSRandall Stewart  */
4596f8829a4aSRandall Stewart int
4597f8829a4aSRandall Stewart sctp_is_there_an_abort_here(struct mbuf *m, int iphlen, uint32_t *vtagfill)
4598f8829a4aSRandall Stewart {
4599f8829a4aSRandall Stewart 	struct sctp_chunkhdr *ch;
4600f8829a4aSRandall Stewart 	struct sctp_init_chunk *init_chk, chunk_buf;
4601f8829a4aSRandall Stewart 	int offset;
4602f8829a4aSRandall Stewart 	unsigned int chk_length;
4603f8829a4aSRandall Stewart 
4604f8829a4aSRandall Stewart 	offset = iphlen + sizeof(struct sctphdr);
4605f8829a4aSRandall Stewart 	ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, sizeof(*ch),
4606f8829a4aSRandall Stewart 	    (uint8_t *)&chunk_buf);
4607f8829a4aSRandall Stewart 	while (ch != NULL) {
4608f8829a4aSRandall Stewart 		chk_length = ntohs(ch->chunk_length);
4609f8829a4aSRandall Stewart 		if (chk_length < sizeof(*ch)) {
4610f8829a4aSRandall Stewart 			/* packet is probably corrupt */
4611f8829a4aSRandall Stewart 			break;
4612f8829a4aSRandall Stewart 		}
4613f8829a4aSRandall Stewart 		/* we seem to be ok, is it an abort? */
4614f8829a4aSRandall Stewart 		if (ch->chunk_type == SCTP_ABORT_ASSOCIATION) {
4615f8829a4aSRandall Stewart 			/* yep, tell them */
4616f8829a4aSRandall Stewart 			return (1);
4617f8829a4aSRandall Stewart 		}
4618f8829a4aSRandall Stewart 		if (ch->chunk_type == SCTP_INITIATION) {
4619f8829a4aSRandall Stewart 			/* need to update the Vtag */
4620f8829a4aSRandall Stewart 			init_chk = (struct sctp_init_chunk *)sctp_m_getptr(m,
4621f8829a4aSRandall Stewart 			    offset, sizeof(*init_chk), (uint8_t *)&chunk_buf);
4622f8829a4aSRandall Stewart 			if (init_chk != NULL) {
4623f8829a4aSRandall Stewart 				*vtagfill = ntohl(init_chk->init.initiate_tag);
4624f8829a4aSRandall Stewart 			}
4625f8829a4aSRandall Stewart 		}
4626f8829a4aSRandall Stewart 		/* Nope, move to the next chunk */
4627f8829a4aSRandall Stewart 		offset += SCTP_SIZE32(chk_length);
4628f8829a4aSRandall Stewart 		ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset,
4629f8829a4aSRandall Stewart 		    sizeof(*ch), (uint8_t *)&chunk_buf);
4630f8829a4aSRandall Stewart 	}
4631f8829a4aSRandall Stewart 	return (0);
4632f8829a4aSRandall Stewart }
4633f8829a4aSRandall Stewart 
4634f8829a4aSRandall Stewart /*
4635f8829a4aSRandall Stewart  * currently (2/02), ifa_addr embeds scope_id's and don't have sin6_scope_id
4636f8829a4aSRandall Stewart  * set (i.e. it's 0) so, create this function to compare link local scopes
4637f8829a4aSRandall Stewart  */
46385e2c2d87SRandall Stewart #ifdef INET6
4639f8829a4aSRandall Stewart uint32_t
4640b0471b4bSMichael Tuexen sctp_is_same_scope(struct sockaddr_in6 *addr1, struct sockaddr_in6 *addr2)
4641b0471b4bSMichael Tuexen {
4642f8829a4aSRandall Stewart 	struct sockaddr_in6 a, b;
4643f8829a4aSRandall Stewart 
4644f8829a4aSRandall Stewart 	/* save copies */
4645f8829a4aSRandall Stewart 	a = *addr1;
4646f8829a4aSRandall Stewart 	b = *addr2;
4647f8829a4aSRandall Stewart 
4648f8829a4aSRandall Stewart 	if (a.sin6_scope_id == 0)
4649f8829a4aSRandall Stewart 		if (sa6_recoverscope(&a)) {
4650f8829a4aSRandall Stewart 			/* can't get scope, so can't match */
4651f8829a4aSRandall Stewart 			return (0);
4652f8829a4aSRandall Stewart 		}
4653f8829a4aSRandall Stewart 	if (b.sin6_scope_id == 0)
4654f8829a4aSRandall Stewart 		if (sa6_recoverscope(&b)) {
4655f8829a4aSRandall Stewart 			/* can't get scope, so can't match */
4656f8829a4aSRandall Stewart 			return (0);
4657f8829a4aSRandall Stewart 		}
4658f8829a4aSRandall Stewart 	if (a.sin6_scope_id != b.sin6_scope_id)
4659f8829a4aSRandall Stewart 		return (0);
4660f8829a4aSRandall Stewart 
4661f8829a4aSRandall Stewart 	return (1);
4662f8829a4aSRandall Stewart }
4663f8829a4aSRandall Stewart 
4664f8829a4aSRandall Stewart /*
4665f8829a4aSRandall Stewart  * returns a sockaddr_in6 with embedded scope recovered and removed
4666f8829a4aSRandall Stewart  */
4667f8829a4aSRandall Stewart struct sockaddr_in6 *
4668f8829a4aSRandall Stewart sctp_recover_scope(struct sockaddr_in6 *addr, struct sockaddr_in6 *store)
4669f8829a4aSRandall Stewart {
4670f8829a4aSRandall Stewart 	/* check and strip embedded scope junk */
4671f8829a4aSRandall Stewart 	if (addr->sin6_family == AF_INET6) {
4672f8829a4aSRandall Stewart 		if (IN6_IS_SCOPE_LINKLOCAL(&addr->sin6_addr)) {
4673f8829a4aSRandall Stewart 			if (addr->sin6_scope_id == 0) {
4674f8829a4aSRandall Stewart 				*store = *addr;
4675f8829a4aSRandall Stewart 				if (!sa6_recoverscope(store)) {
4676f8829a4aSRandall Stewart 					/* use the recovered scope */
4677f8829a4aSRandall Stewart 					addr = store;
4678f8829a4aSRandall Stewart 				}
4679f42a358aSRandall Stewart 			} else {
4680f8829a4aSRandall Stewart 				/* else, return the original "to" addr */
4681f42a358aSRandall Stewart 				in6_clearscope(&addr->sin6_addr);
4682f8829a4aSRandall Stewart 			}
4683f8829a4aSRandall Stewart 		}
4684f8829a4aSRandall Stewart 	}
4685f8829a4aSRandall Stewart 	return (addr);
4686f8829a4aSRandall Stewart }
46875e2c2d87SRandall Stewart #endif
46885e2c2d87SRandall Stewart 
4689f8829a4aSRandall Stewart /*
4690f8829a4aSRandall Stewart  * are the two addresses the same?  currently a "scopeless" check returns: 1
4691f8829a4aSRandall Stewart  * if same, 0 if not
4692f8829a4aSRandall Stewart  */
469372fb6fdbSRandall Stewart int
4694f8829a4aSRandall Stewart sctp_cmpaddr(struct sockaddr *sa1, struct sockaddr *sa2)
4695f8829a4aSRandall Stewart {
4696f8829a4aSRandall Stewart 
4697f8829a4aSRandall Stewart 	/* must be valid */
4698f8829a4aSRandall Stewart 	if (sa1 == NULL || sa2 == NULL)
4699f8829a4aSRandall Stewart 		return (0);
4700f8829a4aSRandall Stewart 
4701f8829a4aSRandall Stewart 	/* must be the same family */
4702f8829a4aSRandall Stewart 	if (sa1->sa_family != sa2->sa_family)
4703f8829a4aSRandall Stewart 		return (0);
4704f8829a4aSRandall Stewart 
47055e2c2d87SRandall Stewart 	switch (sa1->sa_family) {
47065e2c2d87SRandall Stewart #ifdef INET6
47075e2c2d87SRandall Stewart 	case AF_INET6:
47085e2c2d87SRandall Stewart 		{
4709f8829a4aSRandall Stewart 			/* IPv6 addresses */
4710f8829a4aSRandall Stewart 			struct sockaddr_in6 *sin6_1, *sin6_2;
4711f8829a4aSRandall Stewart 
4712f8829a4aSRandall Stewart 			sin6_1 = (struct sockaddr_in6 *)sa1;
4713f8829a4aSRandall Stewart 			sin6_2 = (struct sockaddr_in6 *)sa2;
4714c54a18d2SRandall Stewart 			return (SCTP6_ARE_ADDR_EQUAL(sin6_1,
4715c54a18d2SRandall Stewart 			    sin6_2));
47165e2c2d87SRandall Stewart 		}
47175e2c2d87SRandall Stewart #endif
4718ea5eba11SMichael Tuexen #ifdef INET
47195e2c2d87SRandall Stewart 	case AF_INET:
47205e2c2d87SRandall Stewart 		{
4721f8829a4aSRandall Stewart 			/* IPv4 addresses */
4722f8829a4aSRandall Stewart 			struct sockaddr_in *sin_1, *sin_2;
4723f8829a4aSRandall Stewart 
4724f8829a4aSRandall Stewart 			sin_1 = (struct sockaddr_in *)sa1;
4725f8829a4aSRandall Stewart 			sin_2 = (struct sockaddr_in *)sa2;
4726f8829a4aSRandall Stewart 			return (sin_1->sin_addr.s_addr == sin_2->sin_addr.s_addr);
47275e2c2d87SRandall Stewart 		}
4728ea5eba11SMichael Tuexen #endif
47295e2c2d87SRandall Stewart 	default:
4730f8829a4aSRandall Stewart 		/* we don't do these... */
4731f8829a4aSRandall Stewart 		return (0);
4732f8829a4aSRandall Stewart 	}
4733f8829a4aSRandall Stewart }
4734f8829a4aSRandall Stewart 
4735f8829a4aSRandall Stewart void
4736f8829a4aSRandall Stewart sctp_print_address(struct sockaddr *sa)
4737f8829a4aSRandall Stewart {
47385e2c2d87SRandall Stewart #ifdef INET6
47397d32aa0cSBjoern A. Zeeb 	char ip6buf[INET6_ADDRSTRLEN];
47405e2c2d87SRandall Stewart #endif
47415e2c2d87SRandall Stewart 
47425e2c2d87SRandall Stewart 	switch (sa->sa_family) {
47435e2c2d87SRandall Stewart #ifdef INET6
47445e2c2d87SRandall Stewart 	case AF_INET6:
47455e2c2d87SRandall Stewart 		{
4746ad81507eSRandall Stewart 			struct sockaddr_in6 *sin6;
4747ad81507eSRandall Stewart 
4748f8829a4aSRandall Stewart 			sin6 = (struct sockaddr_in6 *)sa;
4749ad81507eSRandall Stewart 			SCTP_PRINTF("IPv6 address: %s:port:%d scope:%u\n",
47507d32aa0cSBjoern A. Zeeb 			    ip6_sprintf(ip6buf, &sin6->sin6_addr),
47517d32aa0cSBjoern A. Zeeb 			    ntohs(sin6->sin6_port),
4752f8829a4aSRandall Stewart 			    sin6->sin6_scope_id);
47535e2c2d87SRandall Stewart 			break;
47545e2c2d87SRandall Stewart 		}
47555e2c2d87SRandall Stewart #endif
4756ea5eba11SMichael Tuexen #ifdef INET
47575e2c2d87SRandall Stewart 	case AF_INET:
47585e2c2d87SRandall Stewart 		{
4759f8829a4aSRandall Stewart 			struct sockaddr_in *sin;
4760f8829a4aSRandall Stewart 			unsigned char *p;
4761f8829a4aSRandall Stewart 
4762f8829a4aSRandall Stewart 			sin = (struct sockaddr_in *)sa;
4763f8829a4aSRandall Stewart 			p = (unsigned char *)&sin->sin_addr;
4764ad81507eSRandall Stewart 			SCTP_PRINTF("IPv4 address: %u.%u.%u.%u:%d\n",
4765f8829a4aSRandall Stewart 			    p[0], p[1], p[2], p[3], ntohs(sin->sin_port));
47665e2c2d87SRandall Stewart 			break;
47675e2c2d87SRandall Stewart 		}
4768ea5eba11SMichael Tuexen #endif
47695e2c2d87SRandall Stewart 	default:
4770ad81507eSRandall Stewart 		SCTP_PRINTF("?\n");
47715e2c2d87SRandall Stewart 		break;
4772f8829a4aSRandall Stewart 	}
4773f8829a4aSRandall Stewart }
4774f8829a4aSRandall Stewart 
4775f8829a4aSRandall Stewart void
4776f8829a4aSRandall Stewart sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp,
4777f8829a4aSRandall Stewart     struct sctp_inpcb *new_inp,
4778d06c82f1SRandall Stewart     struct sctp_tcb *stcb,
4779d06c82f1SRandall Stewart     int waitflags)
4780f8829a4aSRandall Stewart {
4781f8829a4aSRandall Stewart 	/*
4782f8829a4aSRandall Stewart 	 * go through our old INP and pull off any control structures that
4783f8829a4aSRandall Stewart 	 * belong to stcb and move then to the new inp.
4784f8829a4aSRandall Stewart 	 */
4785f8829a4aSRandall Stewart 	struct socket *old_so, *new_so;
4786f8829a4aSRandall Stewart 	struct sctp_queued_to_read *control, *nctl;
4787f8829a4aSRandall Stewart 	struct sctp_readhead tmp_queue;
4788f8829a4aSRandall Stewart 	struct mbuf *m;
4789bff64a4dSRandall Stewart 	int error = 0;
4790f8829a4aSRandall Stewart 
4791f8829a4aSRandall Stewart 	old_so = old_inp->sctp_socket;
4792f8829a4aSRandall Stewart 	new_so = new_inp->sctp_socket;
4793f8829a4aSRandall Stewart 	TAILQ_INIT(&tmp_queue);
4794d06c82f1SRandall Stewart 	error = sblock(&old_so->so_rcv, waitflags);
4795f8829a4aSRandall Stewart 	if (error) {
4796f8829a4aSRandall Stewart 		/*
4797f8829a4aSRandall Stewart 		 * Gak, can't get sblock, we have a problem. data will be
4798f8829a4aSRandall Stewart 		 * left stranded.. and we don't dare look at it since the
4799f8829a4aSRandall Stewart 		 * other thread may be reading something. Oh well, its a
4800f8829a4aSRandall Stewart 		 * screwed up app that does a peeloff OR a accept while
4801f8829a4aSRandall Stewart 		 * reading from the main socket... actually its only the
4802f8829a4aSRandall Stewart 		 * peeloff() case, since I think read will fail on a
4803f8829a4aSRandall Stewart 		 * listening socket..
4804f8829a4aSRandall Stewart 		 */
4805f8829a4aSRandall Stewart 		return;
4806f8829a4aSRandall Stewart 	}
4807f8829a4aSRandall Stewart 	/* lock the socket buffers */
4808f8829a4aSRandall Stewart 	SCTP_INP_READ_LOCK(old_inp);
48094a9ef3f8SMichael Tuexen 	TAILQ_FOREACH_SAFE(control, &old_inp->read_queue, next, nctl) {
4810f8829a4aSRandall Stewart 		/* Pull off all for out target stcb */
4811f8829a4aSRandall Stewart 		if (control->stcb == stcb) {
4812f8829a4aSRandall Stewart 			/* remove it we want it */
4813f8829a4aSRandall Stewart 			TAILQ_REMOVE(&old_inp->read_queue, control, next);
4814f8829a4aSRandall Stewart 			TAILQ_INSERT_TAIL(&tmp_queue, control, next);
4815f8829a4aSRandall Stewart 			m = control->data;
4816f8829a4aSRandall Stewart 			while (m) {
4817b3f1ea41SRandall Stewart 				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
4818139bc87fSRandall Stewart 					sctp_sblog(&old_so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m));
481980fefe0aSRandall Stewart 				}
4820f8829a4aSRandall Stewart 				sctp_sbfree(control, stcb, &old_so->so_rcv, m);
4821b3f1ea41SRandall Stewart 				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
4822f8829a4aSRandall Stewart 					sctp_sblog(&old_so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0);
482380fefe0aSRandall Stewart 				}
4824139bc87fSRandall Stewart 				m = SCTP_BUF_NEXT(m);
4825f8829a4aSRandall Stewart 			}
4826f8829a4aSRandall Stewart 		}
4827f8829a4aSRandall Stewart 	}
4828f8829a4aSRandall Stewart 	SCTP_INP_READ_UNLOCK(old_inp);
4829f8829a4aSRandall Stewart 	/* Remove the sb-lock on the old socket */
4830f8829a4aSRandall Stewart 
4831f8829a4aSRandall Stewart 	sbunlock(&old_so->so_rcv);
4832f8829a4aSRandall Stewart 	/* Now we move them over to the new socket buffer */
4833f8829a4aSRandall Stewart 	SCTP_INP_READ_LOCK(new_inp);
48344a9ef3f8SMichael Tuexen 	TAILQ_FOREACH_SAFE(control, &tmp_queue, next, nctl) {
4835f8829a4aSRandall Stewart 		TAILQ_INSERT_TAIL(&new_inp->read_queue, control, next);
4836f8829a4aSRandall Stewart 		m = control->data;
4837f8829a4aSRandall Stewart 		while (m) {
4838b3f1ea41SRandall Stewart 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
4839139bc87fSRandall Stewart 				sctp_sblog(&new_so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(m));
484080fefe0aSRandall Stewart 			}
4841f8829a4aSRandall Stewart 			sctp_sballoc(stcb, &new_so->so_rcv, m);
4842b3f1ea41SRandall Stewart 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
4843f8829a4aSRandall Stewart 				sctp_sblog(&new_so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0);
484480fefe0aSRandall Stewart 			}
4845139bc87fSRandall Stewart 			m = SCTP_BUF_NEXT(m);
4846f8829a4aSRandall Stewart 		}
4847f8829a4aSRandall Stewart 	}
4848f8829a4aSRandall Stewart 	SCTP_INP_READ_UNLOCK(new_inp);
4849f8829a4aSRandall Stewart }
4850f8829a4aSRandall Stewart 
4851f8829a4aSRandall Stewart void
4852b1deed45SMichael Tuexen sctp_wakeup_the_read_socket(struct sctp_inpcb *inp,
4853b1deed45SMichael Tuexen     struct sctp_tcb *stcb,
4854b1deed45SMichael Tuexen     int so_locked
4855b1deed45SMichael Tuexen #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
4856b1deed45SMichael Tuexen     SCTP_UNUSED
4857b1deed45SMichael Tuexen #endif
4858b1deed45SMichael Tuexen )
485944249214SRandall Stewart {
4860b1deed45SMichael Tuexen 	if ((inp != NULL) && (inp->sctp_socket != NULL)) {
486144249214SRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
486244249214SRandall Stewart 		struct socket *so;
486344249214SRandall Stewart 
486444249214SRandall Stewart 		so = SCTP_INP_SO(inp);
486544249214SRandall Stewart 		if (!so_locked) {
486644249214SRandall Stewart 			if (stcb) {
486744249214SRandall Stewart 				atomic_add_int(&stcb->asoc.refcnt, 1);
486844249214SRandall Stewart 				SCTP_TCB_UNLOCK(stcb);
486944249214SRandall Stewart 			}
487044249214SRandall Stewart 			SCTP_SOCKET_LOCK(so, 1);
487144249214SRandall Stewart 			if (stcb) {
487244249214SRandall Stewart 				SCTP_TCB_LOCK(stcb);
487344249214SRandall Stewart 				atomic_subtract_int(&stcb->asoc.refcnt, 1);
487444249214SRandall Stewart 			}
487544249214SRandall Stewart 			if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
487644249214SRandall Stewart 				SCTP_SOCKET_UNLOCK(so, 1);
487744249214SRandall Stewart 				return;
487844249214SRandall Stewart 			}
487944249214SRandall Stewart 		}
488044249214SRandall Stewart #endif
488144249214SRandall Stewart 		sctp_sorwakeup(inp, inp->sctp_socket);
488244249214SRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
488344249214SRandall Stewart 		if (!so_locked) {
488444249214SRandall Stewart 			SCTP_SOCKET_UNLOCK(so, 1);
488544249214SRandall Stewart 		}
488644249214SRandall Stewart #endif
488744249214SRandall Stewart 	}
488844249214SRandall Stewart }
488944249214SRandall Stewart 
489044249214SRandall Stewart void
4891f8829a4aSRandall Stewart sctp_add_to_readq(struct sctp_inpcb *inp,
4892f8829a4aSRandall Stewart     struct sctp_tcb *stcb,
4893f8829a4aSRandall Stewart     struct sctp_queued_to_read *control,
4894f8829a4aSRandall Stewart     struct sockbuf *sb,
4895ceaad40aSRandall Stewart     int end,
4896cfde3ff7SRandall Stewart     int inp_read_lock_held,
4897ceaad40aSRandall Stewart     int so_locked
4898ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
4899ceaad40aSRandall Stewart     SCTP_UNUSED
4900ceaad40aSRandall Stewart #endif
4901ceaad40aSRandall Stewart )
4902f8829a4aSRandall Stewart {
4903f8829a4aSRandall Stewart 	/*
4904f8829a4aSRandall Stewart 	 * Here we must place the control on the end of the socket read
49054e88d37aSMichael Tuexen 	 * queue AND increment sb_cc so that select will work properly on
4906f8829a4aSRandall Stewart 	 * read.
4907f8829a4aSRandall Stewart 	 */
4908f8829a4aSRandall Stewart 	struct mbuf *m, *prev = NULL;
4909f8829a4aSRandall Stewart 
491003b0b021SRandall Stewart 	if (inp == NULL) {
491103b0b021SRandall Stewart 		/* Gak, TSNH!! */
4912a5d547adSRandall Stewart #ifdef INVARIANTS
491303b0b021SRandall Stewart 		panic("Gak, inp NULL on add_to_readq");
491403b0b021SRandall Stewart #endif
491503b0b021SRandall Stewart 		return;
491603b0b021SRandall Stewart 	}
4917cfde3ff7SRandall Stewart 	if (inp_read_lock_held == 0)
4918f8829a4aSRandall Stewart 		SCTP_INP_READ_LOCK(inp);
4919cd1386abSMichael Tuexen 	if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_CANT_READ) {
49208a3cfbffSMichael Tuexen 		if (!control->on_strm_q) {
4921cd1386abSMichael Tuexen 			sctp_free_remote_addr(control->whoFrom);
4922cd1386abSMichael Tuexen 			if (control->data) {
4923cd1386abSMichael Tuexen 				sctp_m_freem(control->data);
4924cd1386abSMichael Tuexen 				control->data = NULL;
4925cd1386abSMichael Tuexen 			}
492644249214SRandall Stewart 			sctp_free_a_readq(stcb, control);
49278a3cfbffSMichael Tuexen 		}
4928cd1386abSMichael Tuexen 		if (inp_read_lock_held == 0)
4929cd1386abSMichael Tuexen 			SCTP_INP_READ_UNLOCK(inp);
4930cd1386abSMichael Tuexen 		return;
4931cd1386abSMichael Tuexen 	}
493242551e99SRandall Stewart 	if (!(control->spec_flags & M_NOTIFICATION)) {
4933a5d547adSRandall Stewart 		atomic_add_int(&inp->total_recvs, 1);
493442551e99SRandall Stewart 		if (!control->do_not_ref_stcb) {
4935a5d547adSRandall Stewart 			atomic_add_int(&stcb->total_recvs, 1);
493642551e99SRandall Stewart 		}
493742551e99SRandall Stewart 	}
4938f8829a4aSRandall Stewart 	m = control->data;
4939f8829a4aSRandall Stewart 	control->held_length = 0;
4940f8829a4aSRandall Stewart 	control->length = 0;
4941f8829a4aSRandall Stewart 	while (m) {
4942139bc87fSRandall Stewart 		if (SCTP_BUF_LEN(m) == 0) {
4943f8829a4aSRandall Stewart 			/* Skip mbufs with NO length */
4944f8829a4aSRandall Stewart 			if (prev == NULL) {
4945f8829a4aSRandall Stewart 				/* First one */
4946f8829a4aSRandall Stewart 				control->data = sctp_m_free(m);
4947f8829a4aSRandall Stewart 				m = control->data;
4948f8829a4aSRandall Stewart 			} else {
4949139bc87fSRandall Stewart 				SCTP_BUF_NEXT(prev) = sctp_m_free(m);
4950139bc87fSRandall Stewart 				m = SCTP_BUF_NEXT(prev);
4951f8829a4aSRandall Stewart 			}
4952f8829a4aSRandall Stewart 			if (m == NULL) {
4953c2ede4b3SMartin Blapp 				control->tail_mbuf = prev;
4954f8829a4aSRandall Stewart 			}
4955f8829a4aSRandall Stewart 			continue;
4956f8829a4aSRandall Stewart 		}
4957f8829a4aSRandall Stewart 		prev = m;
4958b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
4959139bc87fSRandall Stewart 			sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(m));
496080fefe0aSRandall Stewart 		}
4961f8829a4aSRandall Stewart 		sctp_sballoc(stcb, sb, m);
4962b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
4963f8829a4aSRandall Stewart 			sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0);
496480fefe0aSRandall Stewart 		}
4965139bc87fSRandall Stewart 		atomic_add_int(&control->length, SCTP_BUF_LEN(m));
4966139bc87fSRandall Stewart 		m = SCTP_BUF_NEXT(m);
4967f8829a4aSRandall Stewart 	}
4968f8829a4aSRandall Stewart 	if (prev != NULL) {
4969f8829a4aSRandall Stewart 		control->tail_mbuf = prev;
4970f8829a4aSRandall Stewart 	} else {
4971139bc87fSRandall Stewart 		/* Everything got collapsed out?? */
49728a3cfbffSMichael Tuexen 		if (!control->on_strm_q) {
4973cd1386abSMichael Tuexen 			sctp_free_remote_addr(control->whoFrom);
497444249214SRandall Stewart 			sctp_free_a_readq(stcb, control);
49758a3cfbffSMichael Tuexen 		}
4976cfde3ff7SRandall Stewart 		if (inp_read_lock_held == 0)
497747a490cbSMichael Tuexen 			SCTP_INP_READ_UNLOCK(inp);
4978f8829a4aSRandall Stewart 		return;
4979f8829a4aSRandall Stewart 	}
4980f8829a4aSRandall Stewart 	if (end) {
4981f8829a4aSRandall Stewart 		control->end_added = 1;
4982f8829a4aSRandall Stewart 	}
4983f8829a4aSRandall Stewart 	TAILQ_INSERT_TAIL(&inp->read_queue, control, next);
498444249214SRandall Stewart 	control->on_read_q = 1;
4985cfde3ff7SRandall Stewart 	if (inp_read_lock_held == 0)
4986f8829a4aSRandall Stewart 		SCTP_INP_READ_UNLOCK(inp);
4987f8829a4aSRandall Stewart 	if (inp && inp->sctp_socket) {
4988b1deed45SMichael Tuexen 		sctp_wakeup_the_read_socket(inp, stcb, so_locked);
4989f8829a4aSRandall Stewart 	}
4990f8829a4aSRandall Stewart }
4991f8829a4aSRandall Stewart 
4992f8829a4aSRandall Stewart /*************HOLD THIS COMMENT FOR PATCH FILE OF
4993f8829a4aSRandall Stewart  *************ALTERNATE ROUTING CODE
4994f8829a4aSRandall Stewart  */
4995f8829a4aSRandall Stewart 
4996f8829a4aSRandall Stewart /*************HOLD THIS COMMENT FOR END OF PATCH FILE OF
4997f8829a4aSRandall Stewart  *************ALTERNATE ROUTING CODE
4998f8829a4aSRandall Stewart  */
4999f8829a4aSRandall Stewart 
5000f8829a4aSRandall Stewart struct mbuf *
5001ff1ffd74SMichael Tuexen sctp_generate_cause(uint16_t code, char *info)
5002f8829a4aSRandall Stewart {
5003f8829a4aSRandall Stewart 	struct mbuf *m;
5004ff1ffd74SMichael Tuexen 	struct sctp_gen_error_cause *cause;
50059a8e3088SMichael Tuexen 	size_t info_len;
50069a8e3088SMichael Tuexen 	uint16_t len;
5007f8829a4aSRandall Stewart 
5008ff1ffd74SMichael Tuexen 	if ((code == 0) || (info == NULL)) {
5009ff1ffd74SMichael Tuexen 		return (NULL);
5010ff1ffd74SMichael Tuexen 	}
5011ff1ffd74SMichael Tuexen 	info_len = strlen(info);
50129a8e3088SMichael Tuexen 	if (info_len > (SCTP_MAX_CAUSE_LENGTH - sizeof(struct sctp_paramhdr))) {
50139a8e3088SMichael Tuexen 		return (NULL);
50149a8e3088SMichael Tuexen 	}
50159a8e3088SMichael Tuexen 	len = (uint16_t)(sizeof(struct sctp_paramhdr) + info_len);
5016ff1ffd74SMichael Tuexen 	m = sctp_get_mbuf_for_msg(len, 0, M_NOWAIT, 1, MT_DATA);
5017ff1ffd74SMichael Tuexen 	if (m != NULL) {
5018ff1ffd74SMichael Tuexen 		SCTP_BUF_LEN(m) = len;
5019ff1ffd74SMichael Tuexen 		cause = mtod(m, struct sctp_gen_error_cause *);
5020ff1ffd74SMichael Tuexen 		cause->code = htons(code);
50219a8e3088SMichael Tuexen 		cause->length = htons(len);
5022ff1ffd74SMichael Tuexen 		memcpy(cause->info, info, info_len);
5023f8829a4aSRandall Stewart 	}
5024f8829a4aSRandall Stewart 	return (m);
5025f8829a4aSRandall Stewart }
5026f8829a4aSRandall Stewart 
502732451da4SMichael Tuexen struct mbuf *
502832451da4SMichael Tuexen sctp_generate_no_user_data_cause(uint32_t tsn)
502932451da4SMichael Tuexen {
503032451da4SMichael Tuexen 	struct mbuf *m;
503132451da4SMichael Tuexen 	struct sctp_error_no_user_data *no_user_data_cause;
50329a8e3088SMichael Tuexen 	uint16_t len;
503332451da4SMichael Tuexen 
50349a8e3088SMichael Tuexen 	len = (uint16_t)sizeof(struct sctp_error_no_user_data);
503532451da4SMichael Tuexen 	m = sctp_get_mbuf_for_msg(len, 0, M_NOWAIT, 1, MT_DATA);
503632451da4SMichael Tuexen 	if (m != NULL) {
503732451da4SMichael Tuexen 		SCTP_BUF_LEN(m) = len;
503832451da4SMichael Tuexen 		no_user_data_cause = mtod(m, struct sctp_error_no_user_data *);
503932451da4SMichael Tuexen 		no_user_data_cause->cause.code = htons(SCTP_CAUSE_NO_USER_DATA);
50409a8e3088SMichael Tuexen 		no_user_data_cause->cause.length = htons(len);
50418b9c95f4SMichael Tuexen 		no_user_data_cause->tsn = htonl(tsn);
504232451da4SMichael Tuexen 	}
504332451da4SMichael Tuexen 	return (m);
504432451da4SMichael Tuexen }
504532451da4SMichael Tuexen 
5046f8829a4aSRandall Stewart #ifdef SCTP_MBCNT_LOGGING
5047f8829a4aSRandall Stewart void
5048f8829a4aSRandall Stewart sctp_free_bufspace(struct sctp_tcb *stcb, struct sctp_association *asoc,
5049f8829a4aSRandall Stewart     struct sctp_tmit_chunk *tp1, int chk_cnt)
5050f8829a4aSRandall Stewart {
5051f8829a4aSRandall Stewart 	if (tp1->data == NULL) {
5052f8829a4aSRandall Stewart 		return;
5053f8829a4aSRandall Stewart 	}
5054f8829a4aSRandall Stewart 	asoc->chunks_on_out_queue -= chk_cnt;
5055b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBCNT_LOGGING_ENABLE) {
5056f8829a4aSRandall Stewart 		sctp_log_mbcnt(SCTP_LOG_MBCNT_DECREASE,
5057f8829a4aSRandall Stewart 		    asoc->total_output_queue_size,
5058f8829a4aSRandall Stewart 		    tp1->book_size,
5059f8829a4aSRandall Stewart 		    0,
5060f8829a4aSRandall Stewart 		    tp1->mbcnt);
506180fefe0aSRandall Stewart 	}
5062f8829a4aSRandall Stewart 	if (asoc->total_output_queue_size >= tp1->book_size) {
506344b7479bSRandall Stewart 		atomic_add_int(&asoc->total_output_queue_size, -tp1->book_size);
5064f8829a4aSRandall Stewart 	} else {
5065f8829a4aSRandall Stewart 		asoc->total_output_queue_size = 0;
5066f8829a4aSRandall Stewart 	}
5067f8829a4aSRandall Stewart 
5068f8829a4aSRandall Stewart 	if (stcb->sctp_socket && (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) ||
5069f8829a4aSRandall Stewart 	    ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE)))) {
50704e88d37aSMichael Tuexen 		if (stcb->sctp_socket->so_snd.sb_cc >= tp1->book_size) {
50714e88d37aSMichael Tuexen 			stcb->sctp_socket->so_snd.sb_cc -= tp1->book_size;
5072f8829a4aSRandall Stewart 		} else {
50734e88d37aSMichael Tuexen 			stcb->sctp_socket->so_snd.sb_cc = 0;
5074f8829a4aSRandall Stewart 
5075f8829a4aSRandall Stewart 		}
5076f8829a4aSRandall Stewart 	}
5077f8829a4aSRandall Stewart }
5078f8829a4aSRandall Stewart 
5079f8829a4aSRandall Stewart #endif
5080f8829a4aSRandall Stewart 
5081f8829a4aSRandall Stewart int
5082f8829a4aSRandall Stewart sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1,
50831edc9dbaSMichael Tuexen     uint8_t sent, int so_locked
5084ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
5085ceaad40aSRandall Stewart     SCTP_UNUSED
5086ceaad40aSRandall Stewart #endif
5087ceaad40aSRandall Stewart )
5088f8829a4aSRandall Stewart {
50890c0982b8SRandall Stewart 	struct sctp_stream_out *strq;
50904a9ef3f8SMichael Tuexen 	struct sctp_tmit_chunk *chk = NULL, *tp2;
50910c0982b8SRandall Stewart 	struct sctp_stream_queue_pending *sp;
509249656eefSMichael Tuexen 	uint32_t mid;
509349656eefSMichael Tuexen 	uint16_t sid;
50940c0982b8SRandall Stewart 	uint8_t foundeom = 0;
5095f8829a4aSRandall Stewart 	int ret_sz = 0;
5096f8829a4aSRandall Stewart 	int notdone;
50970c0982b8SRandall Stewart 	int do_wakeup_routine = 0;
5098f8829a4aSRandall Stewart 
509949656eefSMichael Tuexen 	sid = tp1->rec.data.sid;
510049656eefSMichael Tuexen 	mid = tp1->rec.data.mid;
5101f0396ad1SMichael Tuexen 	if (sent || !(tp1->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG)) {
5102f0396ad1SMichael Tuexen 		stcb->asoc.abandoned_sent[0]++;
5103f0396ad1SMichael Tuexen 		stcb->asoc.abandoned_sent[PR_SCTP_POLICY(tp1->flags)]++;
510449656eefSMichael Tuexen 		stcb->asoc.strmout[sid].abandoned_sent[0]++;
5105f0396ad1SMichael Tuexen #if defined(SCTP_DETAILED_STR_STATS)
5106ad15e154SMichael Tuexen 		stcb->asoc.strmout[sid].abandoned_sent[PR_SCTP_POLICY(tp1->flags)]++;
5107f0396ad1SMichael Tuexen #endif
5108f0396ad1SMichael Tuexen 	} else {
5109f0396ad1SMichael Tuexen 		stcb->asoc.abandoned_unsent[0]++;
5110f0396ad1SMichael Tuexen 		stcb->asoc.abandoned_unsent[PR_SCTP_POLICY(tp1->flags)]++;
511149656eefSMichael Tuexen 		stcb->asoc.strmout[sid].abandoned_unsent[0]++;
5112f0396ad1SMichael Tuexen #if defined(SCTP_DETAILED_STR_STATS)
5113ad15e154SMichael Tuexen 		stcb->asoc.strmout[sid].abandoned_unsent[PR_SCTP_POLICY(tp1->flags)]++;
5114f0396ad1SMichael Tuexen #endif
5115f0396ad1SMichael Tuexen 	}
5116f8829a4aSRandall Stewart 	do {
5117f8829a4aSRandall Stewart 		ret_sz += tp1->book_size;
51180c0982b8SRandall Stewart 		if (tp1->data != NULL) {
51198933fa13SRandall Stewart 			if (tp1->sent < SCTP_DATAGRAM_RESEND) {
5120830d754dSRandall Stewart 				sctp_flight_size_decrease(tp1);
5121830d754dSRandall Stewart 				sctp_total_flight_decrease(stcb, tp1);
51228933fa13SRandall Stewart 			}
51238933fa13SRandall Stewart 			sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1);
51240c0982b8SRandall Stewart 			stcb->asoc.peers_rwnd += tp1->send_size;
51250c0982b8SRandall Stewart 			stcb->asoc.peers_rwnd += SCTP_BASE_SYSCTL(sctp_peer_chunk_oh);
51261edc9dbaSMichael Tuexen 			if (sent) {
51271edc9dbaSMichael Tuexen 				sctp_ulp_notify(SCTP_NOTIFY_SENT_DG_FAIL, stcb, 0, tp1, so_locked);
51281edc9dbaSMichael Tuexen 			} else {
51291edc9dbaSMichael Tuexen 				sctp_ulp_notify(SCTP_NOTIFY_UNSENT_DG_FAIL, stcb, 0, tp1, so_locked);
51301edc9dbaSMichael Tuexen 			}
51312f99457bSMichael Tuexen 			if (tp1->data) {
5132f8829a4aSRandall Stewart 				sctp_m_freem(tp1->data);
5133f8829a4aSRandall Stewart 				tp1->data = NULL;
51342f99457bSMichael Tuexen 			}
51350c0982b8SRandall Stewart 			do_wakeup_routine = 1;
5136f8829a4aSRandall Stewart 			if (PR_SCTP_BUF_ENABLED(tp1->flags)) {
5137f8829a4aSRandall Stewart 				stcb->asoc.sent_queue_cnt_removeable--;
5138f8829a4aSRandall Stewart 			}
5139f8829a4aSRandall Stewart 		}
51408933fa13SRandall Stewart 		tp1->sent = SCTP_FORWARD_TSN_SKIP;
5141f8829a4aSRandall Stewart 		if ((tp1->rec.data.rcv_flags & SCTP_DATA_NOT_FRAG) ==
5142f8829a4aSRandall Stewart 		    SCTP_DATA_NOT_FRAG) {
5143f8829a4aSRandall Stewart 			/* not frag'ed we ae done   */
5144f8829a4aSRandall Stewart 			notdone = 0;
5145f8829a4aSRandall Stewart 			foundeom = 1;
5146f8829a4aSRandall Stewart 		} else if (tp1->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) {
5147f8829a4aSRandall Stewart 			/* end of frag, we are done */
5148f8829a4aSRandall Stewart 			notdone = 0;
5149f8829a4aSRandall Stewart 			foundeom = 1;
5150f8829a4aSRandall Stewart 		} else {
5151f8829a4aSRandall Stewart 			/*
5152f8829a4aSRandall Stewart 			 * Its a begin or middle piece, we must mark all of
5153f8829a4aSRandall Stewart 			 * it
5154f8829a4aSRandall Stewart 			 */
5155f8829a4aSRandall Stewart 			notdone = 1;
5156f8829a4aSRandall Stewart 			tp1 = TAILQ_NEXT(tp1, sctp_next);
5157f8829a4aSRandall Stewart 		}
5158f8829a4aSRandall Stewart 	} while (tp1 && notdone);
51590c0982b8SRandall Stewart 	if (foundeom == 0) {
5160f8829a4aSRandall Stewart 		/*
5161f8829a4aSRandall Stewart 		 * The multi-part message was scattered across the send and
5162f8829a4aSRandall Stewart 		 * sent queue.
5163f8829a4aSRandall Stewart 		 */
51644a9ef3f8SMichael Tuexen 		TAILQ_FOREACH_SAFE(tp1, &stcb->asoc.send_queue, sctp_next, tp2) {
516549656eefSMichael Tuexen 			if ((tp1->rec.data.sid != sid) ||
516649656eefSMichael Tuexen 			    (!SCTP_MID_EQ(stcb->asoc.idata_supported, tp1->rec.data.mid, mid))) {
51674a9ef3f8SMichael Tuexen 				break;
51684a9ef3f8SMichael Tuexen 			}
51690c0982b8SRandall Stewart 			/*
51700c0982b8SRandall Stewart 			 * save to chk in case we have some on stream out
51710c0982b8SRandall Stewart 			 * queue. If so and we have an un-transmitted one we
51720c0982b8SRandall Stewart 			 * don't have to fudge the TSN.
51730c0982b8SRandall Stewart 			 */
51740c0982b8SRandall Stewart 			chk = tp1;
51750c0982b8SRandall Stewart 			ret_sz += tp1->book_size;
51760c0982b8SRandall Stewart 			sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1);
51771edc9dbaSMichael Tuexen 			if (sent) {
51781edc9dbaSMichael Tuexen 				sctp_ulp_notify(SCTP_NOTIFY_SENT_DG_FAIL, stcb, 0, tp1, so_locked);
51791edc9dbaSMichael Tuexen 			} else {
51801edc9dbaSMichael Tuexen 				sctp_ulp_notify(SCTP_NOTIFY_UNSENT_DG_FAIL, stcb, 0, tp1, so_locked);
51811edc9dbaSMichael Tuexen 			}
51822f99457bSMichael Tuexen 			if (tp1->data) {
51830c0982b8SRandall Stewart 				sctp_m_freem(tp1->data);
51842f99457bSMichael Tuexen 				tp1->data = NULL;
51852f99457bSMichael Tuexen 			}
51868933fa13SRandall Stewart 			/* No flight involved here book the size to 0 */
51878933fa13SRandall Stewart 			tp1->book_size = 0;
51880c0982b8SRandall Stewart 			if (tp1->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) {
51890c0982b8SRandall Stewart 				foundeom = 1;
5190f8829a4aSRandall Stewart 			}
51910c0982b8SRandall Stewart 			do_wakeup_routine = 1;
51920c0982b8SRandall Stewart 			tp1->sent = SCTP_FORWARD_TSN_SKIP;
51930c0982b8SRandall Stewart 			TAILQ_REMOVE(&stcb->asoc.send_queue, tp1, sctp_next);
5194b7b84c0eSMichael Tuexen 			/*
5195b7b84c0eSMichael Tuexen 			 * on to the sent queue so we can wait for it to be
5196b7b84c0eSMichael Tuexen 			 * passed by.
5197b7b84c0eSMichael Tuexen 			 */
51980c0982b8SRandall Stewart 			TAILQ_INSERT_TAIL(&stcb->asoc.sent_queue, tp1,
51990c0982b8SRandall Stewart 			    sctp_next);
52000c0982b8SRandall Stewart 			stcb->asoc.send_queue_cnt--;
52010c0982b8SRandall Stewart 			stcb->asoc.sent_queue_cnt++;
52020c0982b8SRandall Stewart 		}
52030c0982b8SRandall Stewart 	}
52040c0982b8SRandall Stewart 	if (foundeom == 0) {
52050c0982b8SRandall Stewart 		/*
52060c0982b8SRandall Stewart 		 * Still no eom found. That means there is stuff left on the
52070c0982b8SRandall Stewart 		 * stream out queue.. yuck.
52080c0982b8SRandall Stewart 		 */
52090c0982b8SRandall Stewart 		SCTP_TCB_SEND_LOCK(stcb);
521049656eefSMichael Tuexen 		strq = &stcb->asoc.strmout[sid];
5211f3b05218SMichael Tuexen 		sp = TAILQ_FIRST(&strq->outqueue);
5212f3b05218SMichael Tuexen 		if (sp != NULL) {
52130c0982b8SRandall Stewart 			sp->discard_rest = 1;
52140c0982b8SRandall Stewart 			/*
5215f3b05218SMichael Tuexen 			 * We may need to put a chunk on the queue that
5216f3b05218SMichael Tuexen 			 * holds the TSN that would have been sent with the
5217f3b05218SMichael Tuexen 			 * LAST bit.
52180c0982b8SRandall Stewart 			 */
52190c0982b8SRandall Stewart 			if (chk == NULL) {
52200c0982b8SRandall Stewart 				/* Yep, we have to */
52210c0982b8SRandall Stewart 				sctp_alloc_a_chunk(stcb, chk);
52220c0982b8SRandall Stewart 				if (chk == NULL) {
52230c0982b8SRandall Stewart 					/*
5224f3b05218SMichael Tuexen 					 * we are hosed. All we can do is
5225f3b05218SMichael Tuexen 					 * nothing.. which will cause an
5226f3b05218SMichael Tuexen 					 * abort if the peer is paying
52270c0982b8SRandall Stewart 					 * attention.
52280c0982b8SRandall Stewart 					 */
52290c0982b8SRandall Stewart 					goto oh_well;
52300c0982b8SRandall Stewart 				}
52310c0982b8SRandall Stewart 				memset(chk, 0, sizeof(*chk));
523263d5b568SMichael Tuexen 				chk->rec.data.rcv_flags = 0;
52330c0982b8SRandall Stewart 				chk->sent = SCTP_FORWARD_TSN_SKIP;
52340c0982b8SRandall Stewart 				chk->asoc = &stcb->asoc;
523563d5b568SMichael Tuexen 				if (stcb->asoc.idata_supported == 0) {
523663d5b568SMichael Tuexen 					if (sp->sinfo_flags & SCTP_UNORDERED) {
523749656eefSMichael Tuexen 						chk->rec.data.mid = 0;
523863d5b568SMichael Tuexen 					} else {
523949656eefSMichael Tuexen 						chk->rec.data.mid = strq->next_mid_ordered;
524063d5b568SMichael Tuexen 					}
524163d5b568SMichael Tuexen 				} else {
524263d5b568SMichael Tuexen 					if (sp->sinfo_flags & SCTP_UNORDERED) {
524349656eefSMichael Tuexen 						chk->rec.data.mid = strq->next_mid_unordered;
524463d5b568SMichael Tuexen 					} else {
524549656eefSMichael Tuexen 						chk->rec.data.mid = strq->next_mid_ordered;
524663d5b568SMichael Tuexen 					}
524763d5b568SMichael Tuexen 				}
524849656eefSMichael Tuexen 				chk->rec.data.sid = sp->sid;
524949656eefSMichael Tuexen 				chk->rec.data.ppid = sp->ppid;
52500c0982b8SRandall Stewart 				chk->rec.data.context = sp->context;
52510c0982b8SRandall Stewart 				chk->flags = sp->act_flags;
52527fd5b436SMichael Tuexen 				chk->whoTo = NULL;
525349656eefSMichael Tuexen 				chk->rec.data.tsn = atomic_fetchadd_int(&stcb->asoc.sending_seq, 1);
52547fd5b436SMichael Tuexen 				strq->chunks_on_queues++;
52550c0982b8SRandall Stewart 				TAILQ_INSERT_TAIL(&stcb->asoc.sent_queue, chk, sctp_next);
52560c0982b8SRandall Stewart 				stcb->asoc.sent_queue_cnt++;
52578933fa13SRandall Stewart 				stcb->asoc.pr_sctp_cnt++;
52580c0982b8SRandall Stewart 			}
525963d5b568SMichael Tuexen 			chk->rec.data.rcv_flags |= SCTP_DATA_LAST_FRAG;
5260d1ea5fa9SMichael Tuexen 			if (sp->sinfo_flags & SCTP_UNORDERED) {
5261d1ea5fa9SMichael Tuexen 				chk->rec.data.rcv_flags |= SCTP_DATA_UNORDERED;
5262d1ea5fa9SMichael Tuexen 			}
526363d5b568SMichael Tuexen 			if (stcb->asoc.idata_supported == 0) {
526463d5b568SMichael Tuexen 				if ((sp->sinfo_flags & SCTP_UNORDERED) == 0) {
526563d5b568SMichael Tuexen 					strq->next_mid_ordered++;
526663d5b568SMichael Tuexen 				}
526763d5b568SMichael Tuexen 			} else {
526863d5b568SMichael Tuexen 				if (sp->sinfo_flags & SCTP_UNORDERED) {
526963d5b568SMichael Tuexen 					strq->next_mid_unordered++;
527063d5b568SMichael Tuexen 				} else {
527163d5b568SMichael Tuexen 					strq->next_mid_ordered++;
527263d5b568SMichael Tuexen 				}
527363d5b568SMichael Tuexen 			}
52740c0982b8SRandall Stewart 	oh_well:
52750c0982b8SRandall Stewart 			if (sp->data) {
52760c0982b8SRandall Stewart 				/*
5277f3b05218SMichael Tuexen 				 * Pull any data to free up the SB and allow
5278f3b05218SMichael Tuexen 				 * sender to "add more" while we will throw
5279f3b05218SMichael Tuexen 				 * away :-)
52800c0982b8SRandall Stewart 				 */
5281f3b05218SMichael Tuexen 				sctp_free_spbufspace(stcb, &stcb->asoc, sp);
52820c0982b8SRandall Stewart 				ret_sz += sp->length;
52830c0982b8SRandall Stewart 				do_wakeup_routine = 1;
52840c0982b8SRandall Stewart 				sp->some_taken = 1;
52850c0982b8SRandall Stewart 				sctp_m_freem(sp->data);
52860c0982b8SRandall Stewart 				sp->data = NULL;
52870c0982b8SRandall Stewart 				sp->tail_mbuf = NULL;
5288d07b2ac6SMichael Tuexen 				sp->length = 0;
52890c0982b8SRandall Stewart 			}
52900c0982b8SRandall Stewart 		}
52910c0982b8SRandall Stewart 		SCTP_TCB_SEND_UNLOCK(stcb);
52920c0982b8SRandall Stewart 	}
52930c0982b8SRandall Stewart 	if (do_wakeup_routine) {
52940c0982b8SRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
52958933fa13SRandall Stewart 		struct socket *so;
52968933fa13SRandall Stewart 
52970c0982b8SRandall Stewart 		so = SCTP_INP_SO(stcb->sctp_ep);
52980c0982b8SRandall Stewart 		if (!so_locked) {
52990c0982b8SRandall Stewart 			atomic_add_int(&stcb->asoc.refcnt, 1);
53000c0982b8SRandall Stewart 			SCTP_TCB_UNLOCK(stcb);
53010c0982b8SRandall Stewart 			SCTP_SOCKET_LOCK(so, 1);
53020c0982b8SRandall Stewart 			SCTP_TCB_LOCK(stcb);
53030c0982b8SRandall Stewart 			atomic_subtract_int(&stcb->asoc.refcnt, 1);
53040c0982b8SRandall Stewart 			if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
53050c0982b8SRandall Stewart 				/* assoc was freed while we were unlocked */
53060c0982b8SRandall Stewart 				SCTP_SOCKET_UNLOCK(so, 1);
53070c0982b8SRandall Stewart 				return (ret_sz);
53080c0982b8SRandall Stewart 			}
53090c0982b8SRandall Stewart 		}
53100c0982b8SRandall Stewart #endif
53110c0982b8SRandall Stewart 		sctp_sowwakeup(stcb->sctp_ep, stcb->sctp_socket);
53120c0982b8SRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
53130c0982b8SRandall Stewart 		if (!so_locked) {
53140c0982b8SRandall Stewart 			SCTP_SOCKET_UNLOCK(so, 1);
53150c0982b8SRandall Stewart 		}
53160c0982b8SRandall Stewart #endif
5317f8829a4aSRandall Stewart 	}
5318f8829a4aSRandall Stewart 	return (ret_sz);
5319f8829a4aSRandall Stewart }
5320f8829a4aSRandall Stewart 
5321f8829a4aSRandall Stewart /*
5322f8829a4aSRandall Stewart  * checks to see if the given address, sa, is one that is currently known by
5323f8829a4aSRandall Stewart  * the kernel note: can't distinguish the same address on multiple interfaces
5324f8829a4aSRandall Stewart  * and doesn't handle multiple addresses with different zone/scope id's note:
5325f8829a4aSRandall Stewart  * ifa_ifwithaddr() compares the entire sockaddr struct
5326f8829a4aSRandall Stewart  */
532742551e99SRandall Stewart struct sctp_ifa *
532880fefe0aSRandall Stewart sctp_find_ifa_in_ep(struct sctp_inpcb *inp, struct sockaddr *addr,
532980fefe0aSRandall Stewart     int holds_lock)
5330f8829a4aSRandall Stewart {
533142551e99SRandall Stewart 	struct sctp_laddr *laddr;
5332f8829a4aSRandall Stewart 
5333ad81507eSRandall Stewart 	if (holds_lock == 0) {
533442551e99SRandall Stewart 		SCTP_INP_RLOCK(inp);
5335ad81507eSRandall Stewart 	}
53360053ed28SMichael Tuexen 
533742551e99SRandall Stewart 	LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
533842551e99SRandall Stewart 		if (laddr->ifa == NULL)
5339f8829a4aSRandall Stewart 			continue;
534042551e99SRandall Stewart 		if (addr->sa_family != laddr->ifa->address.sa.sa_family)
534142551e99SRandall Stewart 			continue;
5342e6194c2eSMichael Tuexen #ifdef INET
534342551e99SRandall Stewart 		if (addr->sa_family == AF_INET) {
534442551e99SRandall Stewart 			if (((struct sockaddr_in *)addr)->sin_addr.s_addr ==
534542551e99SRandall Stewart 			    laddr->ifa->address.sin.sin_addr.s_addr) {
534642551e99SRandall Stewart 				/* found him. */
5347ad81507eSRandall Stewart 				if (holds_lock == 0) {
534842551e99SRandall Stewart 					SCTP_INP_RUNLOCK(inp);
5349ad81507eSRandall Stewart 				}
535042551e99SRandall Stewart 				return (laddr->ifa);
535142551e99SRandall Stewart 				break;
535242551e99SRandall Stewart 			}
53535e2c2d87SRandall Stewart 		}
5354e6194c2eSMichael Tuexen #endif
53555e2c2d87SRandall Stewart #ifdef INET6
53565e2c2d87SRandall Stewart 		if (addr->sa_family == AF_INET6) {
5357c54a18d2SRandall Stewart 			if (SCTP6_ARE_ADDR_EQUAL((struct sockaddr_in6 *)addr,
5358c54a18d2SRandall Stewart 			    &laddr->ifa->address.sin6)) {
535942551e99SRandall Stewart 				/* found him. */
5360ad81507eSRandall Stewart 				if (holds_lock == 0) {
536142551e99SRandall Stewart 					SCTP_INP_RUNLOCK(inp);
5362ad81507eSRandall Stewart 				}
536342551e99SRandall Stewart 				return (laddr->ifa);
536442551e99SRandall Stewart 				break;
536542551e99SRandall Stewart 			}
536642551e99SRandall Stewart 		}
53675e2c2d87SRandall Stewart #endif
536842551e99SRandall Stewart 	}
5369ad81507eSRandall Stewart 	if (holds_lock == 0) {
537042551e99SRandall Stewart 		SCTP_INP_RUNLOCK(inp);
5371ad81507eSRandall Stewart 	}
537242551e99SRandall Stewart 	return (NULL);
537342551e99SRandall Stewart }
5374f8829a4aSRandall Stewart 
53756a27c376SRandall Stewart uint32_t
5376b0471b4bSMichael Tuexen sctp_get_ifa_hash_val(struct sockaddr *addr)
5377b0471b4bSMichael Tuexen {
5378ea5eba11SMichael Tuexen 	switch (addr->sa_family) {
5379ea5eba11SMichael Tuexen #ifdef INET
5380ea5eba11SMichael Tuexen 	case AF_INET:
5381ea5eba11SMichael Tuexen 		{
53826a27c376SRandall Stewart 			struct sockaddr_in *sin;
53836a27c376SRandall Stewart 
53846a27c376SRandall Stewart 			sin = (struct sockaddr_in *)addr;
53856a27c376SRandall Stewart 			return (sin->sin_addr.s_addr ^ (sin->sin_addr.s_addr >> 16));
5386ea5eba11SMichael Tuexen 		}
5387ea5eba11SMichael Tuexen #endif
5388ea5eba11SMichael Tuexen #ifdef INET6
53892c2e3218SMichael Tuexen 	case AF_INET6:
5390ea5eba11SMichael Tuexen 		{
53916a27c376SRandall Stewart 			struct sockaddr_in6 *sin6;
53926a27c376SRandall Stewart 			uint32_t hash_of_addr;
53936a27c376SRandall Stewart 
53946a27c376SRandall Stewart 			sin6 = (struct sockaddr_in6 *)addr;
53956a27c376SRandall Stewart 			hash_of_addr = (sin6->sin6_addr.s6_addr32[0] +
53966a27c376SRandall Stewart 			    sin6->sin6_addr.s6_addr32[1] +
53976a27c376SRandall Stewart 			    sin6->sin6_addr.s6_addr32[2] +
53986a27c376SRandall Stewart 			    sin6->sin6_addr.s6_addr32[3]);
53996a27c376SRandall Stewart 			hash_of_addr = (hash_of_addr ^ (hash_of_addr >> 16));
54006a27c376SRandall Stewart 			return (hash_of_addr);
54016a27c376SRandall Stewart 		}
5402ea5eba11SMichael Tuexen #endif
5403ea5eba11SMichael Tuexen 	default:
5404ea5eba11SMichael Tuexen 		break;
5405ea5eba11SMichael Tuexen 	}
54066a27c376SRandall Stewart 	return (0);
54076a27c376SRandall Stewart }
54086a27c376SRandall Stewart 
540942551e99SRandall Stewart struct sctp_ifa *
541042551e99SRandall Stewart sctp_find_ifa_by_addr(struct sockaddr *addr, uint32_t vrf_id, int holds_lock)
541142551e99SRandall Stewart {
541242551e99SRandall Stewart 	struct sctp_ifa *sctp_ifap;
541342551e99SRandall Stewart 	struct sctp_vrf *vrf;
54146a27c376SRandall Stewart 	struct sctp_ifalist *hash_head;
54156a27c376SRandall Stewart 	uint32_t hash_of_addr;
541642551e99SRandall Stewart 
541742551e99SRandall Stewart 	if (holds_lock == 0)
5418c99efcf6SRandall Stewart 		SCTP_IPI_ADDR_RLOCK();
541942551e99SRandall Stewart 
5420bff64a4dSRandall Stewart 	vrf = sctp_find_vrf(vrf_id);
5421bff64a4dSRandall Stewart 	if (vrf == NULL) {
5422bff64a4dSRandall Stewart 		if (holds_lock == 0)
5423c99efcf6SRandall Stewart 			SCTP_IPI_ADDR_RUNLOCK();
5424bff64a4dSRandall Stewart 		return (NULL);
5425bff64a4dSRandall Stewart 	}
54260053ed28SMichael Tuexen 
5427bff64a4dSRandall Stewart 	hash_of_addr = sctp_get_ifa_hash_val(addr);
5428bff64a4dSRandall Stewart 
542917205eccSRandall Stewart 	hash_head = &vrf->vrf_addr_hash[(hash_of_addr & vrf->vrf_addr_hashmark)];
5430bff64a4dSRandall Stewart 	if (hash_head == NULL) {
5431ad81507eSRandall Stewart 		SCTP_PRINTF("hash_of_addr:%x mask:%x table:%x - ",
5432c99efcf6SRandall Stewart 		    hash_of_addr, (uint32_t)vrf->vrf_addr_hashmark,
5433c99efcf6SRandall Stewart 		    (uint32_t)(hash_of_addr & vrf->vrf_addr_hashmark));
5434bff64a4dSRandall Stewart 		sctp_print_address(addr);
5435ad81507eSRandall Stewart 		SCTP_PRINTF("No such bucket for address\n");
5436bff64a4dSRandall Stewart 		if (holds_lock == 0)
5437c99efcf6SRandall Stewart 			SCTP_IPI_ADDR_RUNLOCK();
5438bff64a4dSRandall Stewart 
5439bff64a4dSRandall Stewart 		return (NULL);
5440bff64a4dSRandall Stewart 	}
54416a27c376SRandall Stewart 	LIST_FOREACH(sctp_ifap, hash_head, next_bucket) {
54426a27c376SRandall Stewart 		if (addr->sa_family != sctp_ifap->address.sa.sa_family)
54436a27c376SRandall Stewart 			continue;
5444e6194c2eSMichael Tuexen #ifdef INET
54456a27c376SRandall Stewart 		if (addr->sa_family == AF_INET) {
54466a27c376SRandall Stewart 			if (((struct sockaddr_in *)addr)->sin_addr.s_addr ==
54476a27c376SRandall Stewart 			    sctp_ifap->address.sin.sin_addr.s_addr) {
54486a27c376SRandall Stewart 				/* found him. */
544942551e99SRandall Stewart 				if (holds_lock == 0)
5450c99efcf6SRandall Stewart 					SCTP_IPI_ADDR_RUNLOCK();
545142551e99SRandall Stewart 				return (sctp_ifap);
54526a27c376SRandall Stewart 				break;
54536a27c376SRandall Stewart 			}
54545e2c2d87SRandall Stewart 		}
5455e6194c2eSMichael Tuexen #endif
54565e2c2d87SRandall Stewart #ifdef INET6
54575e2c2d87SRandall Stewart 		if (addr->sa_family == AF_INET6) {
5458c54a18d2SRandall Stewart 			if (SCTP6_ARE_ADDR_EQUAL((struct sockaddr_in6 *)addr,
5459c54a18d2SRandall Stewart 			    &sctp_ifap->address.sin6)) {
54606a27c376SRandall Stewart 				/* found him. */
54616a27c376SRandall Stewart 				if (holds_lock == 0)
5462c99efcf6SRandall Stewart 					SCTP_IPI_ADDR_RUNLOCK();
54636a27c376SRandall Stewart 				return (sctp_ifap);
54646a27c376SRandall Stewart 				break;
54656a27c376SRandall Stewart 			}
546642551e99SRandall Stewart 		}
54675e2c2d87SRandall Stewart #endif
546842551e99SRandall Stewart 	}
546942551e99SRandall Stewart 	if (holds_lock == 0)
5470c99efcf6SRandall Stewart 		SCTP_IPI_ADDR_RUNLOCK();
5471f8829a4aSRandall Stewart 	return (NULL);
5472f8829a4aSRandall Stewart }
5473f8829a4aSRandall Stewart 
5474f8829a4aSRandall Stewart static void
54754c9179adSRandall Stewart sctp_user_rcvd(struct sctp_tcb *stcb, uint32_t *freed_so_far, int hold_rlock,
5476f8829a4aSRandall Stewart     uint32_t rwnd_req)
5477f8829a4aSRandall Stewart {
5478f8829a4aSRandall Stewart 	/* User pulled some data, do we need a rwnd update? */
5479868b51f2SMichael Tuexen 	struct epoch_tracker et;
5480f8829a4aSRandall Stewart 	int r_unlocked = 0;
5481f8829a4aSRandall Stewart 	uint32_t dif, rwnd;
5482f8829a4aSRandall Stewart 	struct socket *so = NULL;
5483f8829a4aSRandall Stewart 
5484f8829a4aSRandall Stewart 	if (stcb == NULL)
5485f8829a4aSRandall Stewart 		return;
5486f8829a4aSRandall Stewart 
548750cec919SRandall Stewart 	atomic_add_int(&stcb->asoc.refcnt, 1);
5488f8829a4aSRandall Stewart 
5489839d21d6SMichael Tuexen 	if ((SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_ACK_SENT) ||
549061a21880SMichael Tuexen 	    (stcb->asoc.state & (SCTP_STATE_ABOUT_TO_BE_FREED | SCTP_STATE_SHUTDOWN_RECEIVED))) {
5491f8829a4aSRandall Stewart 		/* Pre-check If we are freeing no update */
5492f8829a4aSRandall Stewart 		goto no_lock;
5493f8829a4aSRandall Stewart 	}
5494f8829a4aSRandall Stewart 	SCTP_INP_INCR_REF(stcb->sctp_ep);
5495f8829a4aSRandall Stewart 	if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
5496f8829a4aSRandall Stewart 	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE)) {
5497f8829a4aSRandall Stewart 		goto out;
5498f8829a4aSRandall Stewart 	}
5499f8829a4aSRandall Stewart 	so = stcb->sctp_socket;
5500f8829a4aSRandall Stewart 	if (so == NULL) {
5501f8829a4aSRandall Stewart 		goto out;
5502f8829a4aSRandall Stewart 	}
5503f8829a4aSRandall Stewart 	atomic_add_int(&stcb->freed_by_sorcv_sincelast, *freed_so_far);
5504f8829a4aSRandall Stewart 	/* Have you have freed enough to look */
5505f8829a4aSRandall Stewart 	*freed_so_far = 0;
5506f8829a4aSRandall Stewart 	/* Yep, its worth a look and the lock overhead */
5507f8829a4aSRandall Stewart 
5508f8829a4aSRandall Stewart 	/* Figure out what the rwnd would be */
5509f8829a4aSRandall Stewart 	rwnd = sctp_calc_rwnd(stcb, &stcb->asoc);
5510f8829a4aSRandall Stewart 	if (rwnd >= stcb->asoc.my_last_reported_rwnd) {
5511f8829a4aSRandall Stewart 		dif = rwnd - stcb->asoc.my_last_reported_rwnd;
5512f8829a4aSRandall Stewart 	} else {
5513f8829a4aSRandall Stewart 		dif = 0;
5514f8829a4aSRandall Stewart 	}
5515f8829a4aSRandall Stewart 	if (dif >= rwnd_req) {
5516f8829a4aSRandall Stewart 		if (hold_rlock) {
5517f8829a4aSRandall Stewart 			SCTP_INP_READ_UNLOCK(stcb->sctp_ep);
5518f8829a4aSRandall Stewart 			r_unlocked = 1;
5519f8829a4aSRandall Stewart 		}
5520f8829a4aSRandall Stewart 		if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
5521f8829a4aSRandall Stewart 			/*
5522f8829a4aSRandall Stewart 			 * One last check before we allow the guy possibly
5523f8829a4aSRandall Stewart 			 * to get in. There is a race, where the guy has not
5524f8829a4aSRandall Stewart 			 * reached the gate. In that case
5525f8829a4aSRandall Stewart 			 */
5526f8829a4aSRandall Stewart 			goto out;
5527f8829a4aSRandall Stewart 		}
5528f8829a4aSRandall Stewart 		SCTP_TCB_LOCK(stcb);
5529f8829a4aSRandall Stewart 		if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
5530f8829a4aSRandall Stewart 			/* No reports here */
5531f8829a4aSRandall Stewart 			SCTP_TCB_UNLOCK(stcb);
5532f8829a4aSRandall Stewart 			goto out;
5533f8829a4aSRandall Stewart 		}
5534f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_wu_sacks_sent);
5535868b51f2SMichael Tuexen 		NET_EPOCH_ENTER(et);
5536689e6a5fSMichael Tuexen 		sctp_send_sack(stcb, SCTP_SO_LOCKED);
5537830d754dSRandall Stewart 
5538f8829a4aSRandall Stewart 		sctp_chunk_output(stcb->sctp_ep, stcb,
5539ceaad40aSRandall Stewart 		    SCTP_OUTPUT_FROM_USR_RCVD, SCTP_SO_LOCKED);
5540f8829a4aSRandall Stewart 		/* make sure no timer is running */
5541868b51f2SMichael Tuexen 		NET_EPOCH_EXIT(et);
5542ba785902SMichael Tuexen 		sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL,
5543ba785902SMichael Tuexen 		    SCTP_FROM_SCTPUTIL + SCTP_LOC_6);
5544f8829a4aSRandall Stewart 		SCTP_TCB_UNLOCK(stcb);
5545f8829a4aSRandall Stewart 	} else {
5546f8829a4aSRandall Stewart 		/* Update how much we have pending */
5547f8829a4aSRandall Stewart 		stcb->freed_by_sorcv_sincelast = dif;
5548f8829a4aSRandall Stewart 	}
5549f8829a4aSRandall Stewart out:
5550f8829a4aSRandall Stewart 	if (so && r_unlocked && hold_rlock) {
5551f8829a4aSRandall Stewart 		SCTP_INP_READ_LOCK(stcb->sctp_ep);
5552f8829a4aSRandall Stewart 	}
55530053ed28SMichael Tuexen 
5554f8829a4aSRandall Stewart 	SCTP_INP_DECR_REF(stcb->sctp_ep);
5555f8829a4aSRandall Stewart no_lock:
555650cec919SRandall Stewart 	atomic_add_int(&stcb->asoc.refcnt, -1);
5557f8829a4aSRandall Stewart 	return;
5558f8829a4aSRandall Stewart }
5559f8829a4aSRandall Stewart 
5560f8829a4aSRandall Stewart int
5561f8829a4aSRandall Stewart sctp_sorecvmsg(struct socket *so,
5562f8829a4aSRandall Stewart     struct uio *uio,
5563f8829a4aSRandall Stewart     struct mbuf **mp,
5564f8829a4aSRandall Stewart     struct sockaddr *from,
5565f8829a4aSRandall Stewart     int fromlen,
5566f8829a4aSRandall Stewart     int *msg_flags,
5567f8829a4aSRandall Stewart     struct sctp_sndrcvinfo *sinfo,
5568f8829a4aSRandall Stewart     int filling_sinfo)
5569f8829a4aSRandall Stewart {
5570f8829a4aSRandall Stewart 	/*
5571f8829a4aSRandall Stewart 	 * MSG flags we will look at MSG_DONTWAIT - non-blocking IO.
5572f8829a4aSRandall Stewart 	 * MSG_PEEK - Look don't touch :-D (only valid with OUT mbuf copy
5573f8829a4aSRandall Stewart 	 * mp=NULL thus uio is the copy method to userland) MSG_WAITALL - ??
5574f8829a4aSRandall Stewart 	 * On the way out we may send out any combination of:
5575f8829a4aSRandall Stewart 	 * MSG_NOTIFICATION MSG_EOR
5576f8829a4aSRandall Stewart 	 *
5577f8829a4aSRandall Stewart 	 */
5578f8829a4aSRandall Stewart 	struct sctp_inpcb *inp = NULL;
557958e6eeefSMichael Tuexen 	ssize_t my_len = 0;
558058e6eeefSMichael Tuexen 	ssize_t cp_len = 0;
55810d3cf13dSMichael Tuexen 	int error = 0;
5582f8829a4aSRandall Stewart 	struct sctp_queued_to_read *control = NULL, *ctl = NULL, *nxt = NULL;
558394b0d969SMichael Tuexen 	struct mbuf *m = NULL;
5584f8829a4aSRandall Stewart 	struct sctp_tcb *stcb = NULL;
5585f8829a4aSRandall Stewart 	int wakeup_read_socket = 0;
5586f8829a4aSRandall Stewart 	int freecnt_applied = 0;
5587f8829a4aSRandall Stewart 	int out_flags = 0, in_flags = 0;
5588f8829a4aSRandall Stewart 	int block_allowed = 1;
55894c9179adSRandall Stewart 	uint32_t freed_so_far = 0;
559058e6eeefSMichael Tuexen 	ssize_t copied_so_far = 0;
559193164cf9SRandall Stewart 	int in_eeor_mode = 0;
5592f8829a4aSRandall Stewart 	int no_rcv_needed = 0;
5593f8829a4aSRandall Stewart 	uint32_t rwnd_req = 0;
5594f8829a4aSRandall Stewart 	int hold_sblock = 0;
5595f8829a4aSRandall Stewart 	int hold_rlock = 0;
55969a8e3088SMichael Tuexen 	ssize_t slen = 0;
55974c9179adSRandall Stewart 	uint32_t held_length = 0;
55987abab911SRobert Watson 	int sockbuf_lock = 0;
5599f8829a4aSRandall Stewart 
560017205eccSRandall Stewart 	if (uio == NULL) {
5601c4739e2fSRandall Stewart 		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
560217205eccSRandall Stewart 		return (EINVAL);
560317205eccSRandall Stewart 	}
56040053ed28SMichael Tuexen 
5605f8829a4aSRandall Stewart 	if (msg_flags) {
5606f8829a4aSRandall Stewart 		in_flags = *msg_flags;
5607c105859eSRandall Stewart 		if (in_flags & MSG_PEEK)
5608c105859eSRandall Stewart 			SCTP_STAT_INCR(sctps_read_peeks);
5609f8829a4aSRandall Stewart 	} else {
5610f8829a4aSRandall Stewart 		in_flags = 0;
5611f8829a4aSRandall Stewart 	}
5612f8829a4aSRandall Stewart 	slen = uio->uio_resid;
561317205eccSRandall Stewart 
5614f8829a4aSRandall Stewart 	/* Pull in and set up our int flags */
5615f8829a4aSRandall Stewart 	if (in_flags & MSG_OOB) {
5616f8829a4aSRandall Stewart 		/* Out of band's NOT supported */
5617f8829a4aSRandall Stewart 		return (EOPNOTSUPP);
5618f8829a4aSRandall Stewart 	}
5619f8829a4aSRandall Stewart 	if ((in_flags & MSG_PEEK) && (mp != NULL)) {
5620c4739e2fSRandall Stewart 		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
5621f8829a4aSRandall Stewart 		return (EINVAL);
5622f8829a4aSRandall Stewart 	}
5623f8829a4aSRandall Stewart 	if ((in_flags & (MSG_DONTWAIT
5624f8829a4aSRandall Stewart 	    | MSG_NBIO
5625f8829a4aSRandall Stewart 	    )) ||
562642551e99SRandall Stewart 	    SCTP_SO_IS_NBIO(so)) {
5627f8829a4aSRandall Stewart 		block_allowed = 0;
5628f8829a4aSRandall Stewart 	}
5629f8829a4aSRandall Stewart 	/* setup the endpoint */
5630f8829a4aSRandall Stewart 	inp = (struct sctp_inpcb *)so->so_pcb;
5631f8829a4aSRandall Stewart 	if (inp == NULL) {
5632c4739e2fSRandall Stewart 		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EFAULT);
5633f8829a4aSRandall Stewart 		return (EFAULT);
5634f8829a4aSRandall Stewart 	}
563562c1ff9cSRandall Stewart 	rwnd_req = (SCTP_SB_LIMIT_RCV(so) >> SCTP_RWND_HIWAT_SHIFT);
5636f8829a4aSRandall Stewart 	/* Must be at least a MTU's worth */
5637f8829a4aSRandall Stewart 	if (rwnd_req < SCTP_MIN_RWND)
5638f8829a4aSRandall Stewart 		rwnd_req = SCTP_MIN_RWND;
5639f8829a4aSRandall Stewart 	in_eeor_mode = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR);
5640b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RECV_RWND_LOGGING_ENABLE) {
5641f8829a4aSRandall Stewart 		sctp_misc_ints(SCTP_SORECV_ENTER,
56429a8e3088SMichael Tuexen 		    rwnd_req, in_eeor_mode, so->so_rcv.sb_cc, (uint32_t)uio->uio_resid);
564380fefe0aSRandall Stewart 	}
5644b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RECV_RWND_LOGGING_ENABLE) {
5645f8829a4aSRandall Stewart 		sctp_misc_ints(SCTP_SORECV_ENTERPL,
56469a8e3088SMichael Tuexen 		    rwnd_req, block_allowed, so->so_rcv.sb_cc, (uint32_t)uio->uio_resid);
564780fefe0aSRandall Stewart 	}
56480053ed28SMichael Tuexen 
56490053ed28SMichael Tuexen 
5650265de5bbSRobert Watson 	error = sblock(&so->so_rcv, (block_allowed ? SBL_WAIT : 0));
5651f8829a4aSRandall Stewart 	if (error) {
5652f8829a4aSRandall Stewart 		goto release_unlocked;
5653f8829a4aSRandall Stewart 	}
56548e1e6e5fSMateusz Guzik 	sockbuf_lock = 1;
5655f8829a4aSRandall Stewart restart:
56567abab911SRobert Watson 
5657f8829a4aSRandall Stewart 
5658f8829a4aSRandall Stewart restart_nosblocks:
5659f8829a4aSRandall Stewart 	if (hold_sblock == 0) {
5660f8829a4aSRandall Stewart 		SOCKBUF_LOCK(&so->so_rcv);
5661f8829a4aSRandall Stewart 		hold_sblock = 1;
5662f8829a4aSRandall Stewart 	}
5663f8829a4aSRandall Stewart 	if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
5664f8829a4aSRandall Stewart 	    (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE)) {
5665f8829a4aSRandall Stewart 		goto out;
5666f8829a4aSRandall Stewart 	}
56674e88d37aSMichael Tuexen 	if ((so->so_rcv.sb_state & SBS_CANTRCVMORE) && (so->so_rcv.sb_cc == 0)) {
5668f8829a4aSRandall Stewart 		if (so->so_error) {
5669f8829a4aSRandall Stewart 			error = so->so_error;
567044b7479bSRandall Stewart 			if ((in_flags & MSG_PEEK) == 0)
567144b7479bSRandall Stewart 				so->so_error = 0;
56729f22f500SRandall Stewart 			goto out;
5673f8829a4aSRandall Stewart 		} else {
56744e88d37aSMichael Tuexen 			if (so->so_rcv.sb_cc == 0) {
56757924093fSRandall Stewart 				/* indicate EOF */
56767924093fSRandall Stewart 				error = 0;
5677f8829a4aSRandall Stewart 				goto out;
5678f8829a4aSRandall Stewart 			}
56799f22f500SRandall Stewart 		}
56809f22f500SRandall Stewart 	}
56819de217ceSMichael Tuexen 	if (so->so_rcv.sb_cc <= held_length) {
56829de217ceSMichael Tuexen 		if (so->so_error) {
56839de217ceSMichael Tuexen 			error = so->so_error;
56849de217ceSMichael Tuexen 			if ((in_flags & MSG_PEEK) == 0) {
56859de217ceSMichael Tuexen 				so->so_error = 0;
56869de217ceSMichael Tuexen 			}
56879de217ceSMichael Tuexen 			goto out;
56889de217ceSMichael Tuexen 		}
56894e88d37aSMichael Tuexen 		if ((so->so_rcv.sb_cc == 0) &&
5690f8829a4aSRandall Stewart 		    ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5691f8829a4aSRandall Stewart 		    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) {
5692f8829a4aSRandall Stewart 			if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0) {
5693f8829a4aSRandall Stewart 				/*
5694f8829a4aSRandall Stewart 				 * For active open side clear flags for
5695f8829a4aSRandall Stewart 				 * re-use passive open is blocked by
5696f8829a4aSRandall Stewart 				 * connect.
5697f8829a4aSRandall Stewart 				 */
5698f8829a4aSRandall Stewart 				if (inp->sctp_flags & SCTP_PCB_FLAGS_WAS_ABORTED) {
5699b7b84c0eSMichael Tuexen 					/*
5700b7b84c0eSMichael Tuexen 					 * You were aborted, passive side
5701b7b84c0eSMichael Tuexen 					 * always hits here
5702b7b84c0eSMichael Tuexen 					 */
5703c4739e2fSRandall Stewart 					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET);
5704f8829a4aSRandall Stewart 					error = ECONNRESET;
5705f8829a4aSRandall Stewart 				}
5706f8829a4aSRandall Stewart 				so->so_state &= ~(SS_ISCONNECTING |
5707f8829a4aSRandall Stewart 				    SS_ISDISCONNECTING |
5708f8829a4aSRandall Stewart 				    SS_ISCONFIRMING |
5709f8829a4aSRandall Stewart 				    SS_ISCONNECTED);
5710f8829a4aSRandall Stewart 				if (error == 0) {
5711f8829a4aSRandall Stewart 					if ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) == 0) {
5712c4739e2fSRandall Stewart 						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOTCONN);
5713f8829a4aSRandall Stewart 						error = ENOTCONN;
5714f8829a4aSRandall Stewart 					}
5715f8829a4aSRandall Stewart 				}
5716f8829a4aSRandall Stewart 				goto out;
5717f8829a4aSRandall Stewart 			}
5718f8829a4aSRandall Stewart 		}
57199de217ceSMichael Tuexen 		if (block_allowed) {
5720f8829a4aSRandall Stewart 			error = sbwait(&so->so_rcv);
5721f8829a4aSRandall Stewart 			if (error) {
5722f8829a4aSRandall Stewart 				goto out;
5723f8829a4aSRandall Stewart 			}
5724f8829a4aSRandall Stewart 			held_length = 0;
5725f8829a4aSRandall Stewart 			goto restart_nosblocks;
572644b7479bSRandall Stewart 		} else {
5727c4739e2fSRandall Stewart 			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EWOULDBLOCK);
5728f8829a4aSRandall Stewart 			error = EWOULDBLOCK;
5729f8829a4aSRandall Stewart 			goto out;
5730f8829a4aSRandall Stewart 		}
57319de217ceSMichael Tuexen 	}
5732d06c82f1SRandall Stewart 	if (hold_sblock == 1) {
5733d06c82f1SRandall Stewart 		SOCKBUF_UNLOCK(&so->so_rcv);
5734d06c82f1SRandall Stewart 		hold_sblock = 0;
5735d06c82f1SRandall Stewart 	}
5736f8829a4aSRandall Stewart 	/* we possibly have data we can read */
57373c503c28SRandall Stewart 	/* sa_ignore FREED_MEMORY */
5738f8829a4aSRandall Stewart 	control = TAILQ_FIRST(&inp->read_queue);
5739f8829a4aSRandall Stewart 	if (control == NULL) {
5740f8829a4aSRandall Stewart 		/*
5741f8829a4aSRandall Stewart 		 * This could be happening since the appender did the
5742f8829a4aSRandall Stewart 		 * increment but as not yet did the tailq insert onto the
5743f8829a4aSRandall Stewart 		 * read_queue
5744f8829a4aSRandall Stewart 		 */
5745f8829a4aSRandall Stewart 		if (hold_rlock == 0) {
5746f8829a4aSRandall Stewart 			SCTP_INP_READ_LOCK(inp);
5747f8829a4aSRandall Stewart 		}
5748f8829a4aSRandall Stewart 		control = TAILQ_FIRST(&inp->read_queue);
57494e88d37aSMichael Tuexen 		if ((control == NULL) && (so->so_rcv.sb_cc != 0)) {
5750a5d547adSRandall Stewart #ifdef INVARIANTS
5751f8829a4aSRandall Stewart 			panic("Huh, its non zero and nothing on control?");
5752f8829a4aSRandall Stewart #endif
57534e88d37aSMichael Tuexen 			so->so_rcv.sb_cc = 0;
5754f8829a4aSRandall Stewart 		}
5755f8829a4aSRandall Stewart 		SCTP_INP_READ_UNLOCK(inp);
5756f8829a4aSRandall Stewart 		hold_rlock = 0;
5757f8829a4aSRandall Stewart 		goto restart;
5758f8829a4aSRandall Stewart 	}
57590053ed28SMichael Tuexen 
5760f8829a4aSRandall Stewart 	if ((control->length == 0) &&
5761f8829a4aSRandall Stewart 	    (control->do_not_ref_stcb)) {
5762f8829a4aSRandall Stewart 		/*
5763f8829a4aSRandall Stewart 		 * Clean up code for freeing assoc that left behind a
5764f8829a4aSRandall Stewart 		 * pdapi.. maybe a peer in EEOR that just closed after
5765f8829a4aSRandall Stewart 		 * sending and never indicated a EOR.
5766f8829a4aSRandall Stewart 		 */
5767f8829a4aSRandall Stewart 		if (hold_rlock == 0) {
5768f8829a4aSRandall Stewart 			hold_rlock = 1;
5769f8829a4aSRandall Stewart 			SCTP_INP_READ_LOCK(inp);
5770f8829a4aSRandall Stewart 		}
5771f8829a4aSRandall Stewart 		control->held_length = 0;
5772f8829a4aSRandall Stewart 		if (control->data) {
5773f8829a4aSRandall Stewart 			/* Hmm there is data here .. fix */
57744c9179adSRandall Stewart 			struct mbuf *m_tmp;
5775f8829a4aSRandall Stewart 			int cnt = 0;
5776f8829a4aSRandall Stewart 
57774c9179adSRandall Stewart 			m_tmp = control->data;
57784c9179adSRandall Stewart 			while (m_tmp) {
57794c9179adSRandall Stewart 				cnt += SCTP_BUF_LEN(m_tmp);
57804c9179adSRandall Stewart 				if (SCTP_BUF_NEXT(m_tmp) == NULL) {
57814c9179adSRandall Stewart 					control->tail_mbuf = m_tmp;
5782f8829a4aSRandall Stewart 					control->end_added = 1;
5783f8829a4aSRandall Stewart 				}
57844c9179adSRandall Stewart 				m_tmp = SCTP_BUF_NEXT(m_tmp);
5785f8829a4aSRandall Stewart 			}
5786f8829a4aSRandall Stewart 			control->length = cnt;
5787f8829a4aSRandall Stewart 		} else {
5788f8829a4aSRandall Stewart 			/* remove it */
5789f8829a4aSRandall Stewart 			TAILQ_REMOVE(&inp->read_queue, control, next);
5790f8829a4aSRandall Stewart 			/* Add back any hiddend data */
5791f8829a4aSRandall Stewart 			sctp_free_remote_addr(control->whoFrom);
5792f8829a4aSRandall Stewart 			sctp_free_a_readq(stcb, control);
5793f8829a4aSRandall Stewart 		}
5794f8829a4aSRandall Stewart 		if (hold_rlock) {
5795f8829a4aSRandall Stewart 			hold_rlock = 0;
5796f8829a4aSRandall Stewart 			SCTP_INP_READ_UNLOCK(inp);
5797f8829a4aSRandall Stewart 		}
5798f8829a4aSRandall Stewart 		goto restart;
5799f8829a4aSRandall Stewart 	}
5800810ec536SMichael Tuexen 	if ((control->length == 0) &&
5801810ec536SMichael Tuexen 	    (control->end_added == 1)) {
5802b7b84c0eSMichael Tuexen 		/*
5803b7b84c0eSMichael Tuexen 		 * Do we also need to check for (control->pdapi_aborted ==
5804b7b84c0eSMichael Tuexen 		 * 1)?
5805b7b84c0eSMichael Tuexen 		 */
5806810ec536SMichael Tuexen 		if (hold_rlock == 0) {
5807810ec536SMichael Tuexen 			hold_rlock = 1;
5808810ec536SMichael Tuexen 			SCTP_INP_READ_LOCK(inp);
5809810ec536SMichael Tuexen 		}
5810810ec536SMichael Tuexen 		TAILQ_REMOVE(&inp->read_queue, control, next);
5811810ec536SMichael Tuexen 		if (control->data) {
5812810ec536SMichael Tuexen #ifdef INVARIANTS
5813810ec536SMichael Tuexen 			panic("control->data not null but control->length == 0");
5814810ec536SMichael Tuexen #else
5815810ec536SMichael Tuexen 			SCTP_PRINTF("Strange, data left in the control buffer. Cleaning up.\n");
5816810ec536SMichael Tuexen 			sctp_m_freem(control->data);
5817810ec536SMichael Tuexen 			control->data = NULL;
5818810ec536SMichael Tuexen #endif
5819810ec536SMichael Tuexen 		}
5820810ec536SMichael Tuexen 		if (control->aux_data) {
5821810ec536SMichael Tuexen 			sctp_m_free(control->aux_data);
5822810ec536SMichael Tuexen 			control->aux_data = NULL;
5823810ec536SMichael Tuexen 		}
582498d5fd97SMichael Tuexen #ifdef INVARIANTS
582544249214SRandall Stewart 		if (control->on_strm_q) {
582644249214SRandall Stewart 			panic("About to free ctl:%p so:%p and its in %d",
582744249214SRandall Stewart 			    control, so, control->on_strm_q);
582844249214SRandall Stewart 		}
582998d5fd97SMichael Tuexen #endif
5830810ec536SMichael Tuexen 		sctp_free_remote_addr(control->whoFrom);
5831810ec536SMichael Tuexen 		sctp_free_a_readq(stcb, control);
5832810ec536SMichael Tuexen 		if (hold_rlock) {
5833810ec536SMichael Tuexen 			hold_rlock = 0;
5834810ec536SMichael Tuexen 			SCTP_INP_READ_UNLOCK(inp);
5835810ec536SMichael Tuexen 		}
5836810ec536SMichael Tuexen 		goto restart;
5837810ec536SMichael Tuexen 	}
5838f8829a4aSRandall Stewart 	if (control->length == 0) {
5839f8829a4aSRandall Stewart 		if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) &&
5840f8829a4aSRandall Stewart 		    (filling_sinfo)) {
5841f8829a4aSRandall Stewart 			/* find a more suitable one then this */
5842f8829a4aSRandall Stewart 			ctl = TAILQ_NEXT(control, next);
5843f8829a4aSRandall Stewart 			while (ctl) {
58449a6142d8SRandall Stewart 				if ((ctl->stcb != control->stcb) && (ctl->length) &&
58459a6142d8SRandall Stewart 				    (ctl->some_taken ||
58466114cd96SRandall Stewart 				    (ctl->spec_flags & M_NOTIFICATION) ||
58479a6142d8SRandall Stewart 				    ((ctl->do_not_ref_stcb == 0) &&
58489a6142d8SRandall Stewart 				    (ctl->stcb->asoc.strmin[ctl->sinfo_stream].delivery_started == 0)))
58499a6142d8SRandall Stewart 				    ) {
58509a6142d8SRandall Stewart 					/*-
58519a6142d8SRandall Stewart 					 * If we have a different TCB next, and there is data
58529a6142d8SRandall Stewart 					 * present. If we have already taken some (pdapi), OR we can
58539a6142d8SRandall Stewart 					 * ref the tcb and no delivery as started on this stream, we
585417205eccSRandall Stewart 					 * take it. Note we allow a notification on a different
585517205eccSRandall Stewart 					 * assoc to be delivered..
58569a6142d8SRandall Stewart 					 */
58579a6142d8SRandall Stewart 					control = ctl;
58589a6142d8SRandall Stewart 					goto found_one;
58599a6142d8SRandall Stewart 				} else if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS)) &&
58609a6142d8SRandall Stewart 					    (ctl->length) &&
58619a6142d8SRandall Stewart 					    ((ctl->some_taken) ||
58629a6142d8SRandall Stewart 					    ((ctl->do_not_ref_stcb == 0) &&
586317205eccSRandall Stewart 					    ((ctl->spec_flags & M_NOTIFICATION) == 0) &&
5864b5c16493SMichael Tuexen 				    (ctl->stcb->asoc.strmin[ctl->sinfo_stream].delivery_started == 0)))) {
58659a6142d8SRandall Stewart 					/*-
58669a6142d8SRandall Stewart 					 * If we have the same tcb, and there is data present, and we
58679a6142d8SRandall Stewart 					 * have the strm interleave feature present. Then if we have
58689a6142d8SRandall Stewart 					 * taken some (pdapi) or we can refer to tht tcb AND we have
58699a6142d8SRandall Stewart 					 * not started a delivery for this stream, we can take it.
587017205eccSRandall Stewart 					 * Note we do NOT allow a notificaiton on the same assoc to
587117205eccSRandall Stewart 					 * be delivered.
58729a6142d8SRandall Stewart 					 */
5873f8829a4aSRandall Stewart 					control = ctl;
5874f8829a4aSRandall Stewart 					goto found_one;
5875f8829a4aSRandall Stewart 				}
5876f8829a4aSRandall Stewart 				ctl = TAILQ_NEXT(ctl, next);
5877f8829a4aSRandall Stewart 			}
5878f8829a4aSRandall Stewart 		}
5879f8829a4aSRandall Stewart 		/*
5880f8829a4aSRandall Stewart 		 * if we reach here, not suitable replacement is available
58814e88d37aSMichael Tuexen 		 * <or> fragment interleave is NOT on. So stuff the sb_cc
5882f8829a4aSRandall Stewart 		 * into the our held count, and its time to sleep again.
5883f8829a4aSRandall Stewart 		 */
58844e88d37aSMichael Tuexen 		held_length = so->so_rcv.sb_cc;
58854e88d37aSMichael Tuexen 		control->held_length = so->so_rcv.sb_cc;
5886f8829a4aSRandall Stewart 		goto restart;
5887f8829a4aSRandall Stewart 	}
5888f8829a4aSRandall Stewart 	/* Clear the held length since there is something to read */
5889f8829a4aSRandall Stewart 	control->held_length = 0;
5890f8829a4aSRandall Stewart found_one:
5891f8829a4aSRandall Stewart 	/*
5892f8829a4aSRandall Stewart 	 * If we reach here, control has a some data for us to read off.
5893f8829a4aSRandall Stewart 	 * Note that stcb COULD be NULL.
5894f8829a4aSRandall Stewart 	 */
58959c5ca6f2SMichael Tuexen 	if (hold_rlock == 0) {
58969c5ca6f2SMichael Tuexen 		hold_rlock = 1;
58979c5ca6f2SMichael Tuexen 		SCTP_INP_READ_LOCK(inp);
5898f8829a4aSRandall Stewart 	}
58999c5ca6f2SMichael Tuexen 	control->some_taken++;
5900f8829a4aSRandall Stewart 	stcb = control->stcb;
5901f8829a4aSRandall Stewart 	if (stcb) {
59020696e120SRandall Stewart 		if ((control->do_not_ref_stcb == 0) &&
59030696e120SRandall Stewart 		    (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED)) {
590450cec919SRandall Stewart 			if (freecnt_applied == 0)
5905f8829a4aSRandall Stewart 				stcb = NULL;
5906f8829a4aSRandall Stewart 		} else if (control->do_not_ref_stcb == 0) {
5907f8829a4aSRandall Stewart 			/* you can't free it on me please */
5908f8829a4aSRandall Stewart 			/*
5909f8829a4aSRandall Stewart 			 * The lock on the socket buffer protects us so the
5910f8829a4aSRandall Stewart 			 * free code will stop. But since we used the
5911f8829a4aSRandall Stewart 			 * socketbuf lock and the sender uses the tcb_lock
5912f8829a4aSRandall Stewart 			 * to increment, we need to use the atomic add to
5913f8829a4aSRandall Stewart 			 * the refcnt
5914f8829a4aSRandall Stewart 			 */
5915d55b0b1bSRandall Stewart 			if (freecnt_applied) {
5916d55b0b1bSRandall Stewart #ifdef INVARIANTS
5917207304d4SRandall Stewart 				panic("refcnt already incremented");
5918d55b0b1bSRandall Stewart #else
5919cd3fd531SMichael Tuexen 				SCTP_PRINTF("refcnt already incremented?\n");
5920d55b0b1bSRandall Stewart #endif
5921d55b0b1bSRandall Stewart 			} else {
592250cec919SRandall Stewart 				atomic_add_int(&stcb->asoc.refcnt, 1);
5923f8829a4aSRandall Stewart 				freecnt_applied = 1;
5924d55b0b1bSRandall Stewart 			}
5925f8829a4aSRandall Stewart 			/*
5926f8829a4aSRandall Stewart 			 * Setup to remember how much we have not yet told
5927f8829a4aSRandall Stewart 			 * the peer our rwnd has opened up. Note we grab the
5928f8829a4aSRandall Stewart 			 * value from the tcb from last time. Note too that
59290696e120SRandall Stewart 			 * sack sending clears this when a sack is sent,
5930f8829a4aSRandall Stewart 			 * which is fine. Once we hit the rwnd_req, we then
5931f8829a4aSRandall Stewart 			 * will go to the sctp_user_rcvd() that will not
5932f8829a4aSRandall Stewart 			 * lock until it KNOWs it MUST send a WUP-SACK.
5933f8829a4aSRandall Stewart 			 */
593458e6eeefSMichael Tuexen 			freed_so_far = (uint32_t)stcb->freed_by_sorcv_sincelast;
5935f8829a4aSRandall Stewart 			stcb->freed_by_sorcv_sincelast = 0;
5936f8829a4aSRandall Stewart 		}
5937f8829a4aSRandall Stewart 	}
59386114cd96SRandall Stewart 	if (stcb &&
59396114cd96SRandall Stewart 	    ((control->spec_flags & M_NOTIFICATION) == 0) &&
59406114cd96SRandall Stewart 	    control->do_not_ref_stcb == 0) {
5941d06c82f1SRandall Stewart 		stcb->asoc.strmin[control->sinfo_stream].delivery_started = 1;
5942d06c82f1SRandall Stewart 	}
59430053ed28SMichael Tuexen 
5944f8829a4aSRandall Stewart 	/* First lets get off the sinfo and sockaddr info */
59455f05199cSMichael Tuexen 	if ((sinfo != NULL) && (filling_sinfo != 0)) {
59465f05199cSMichael Tuexen 		sinfo->sinfo_stream = control->sinfo_stream;
594749656eefSMichael Tuexen 		sinfo->sinfo_ssn = (uint16_t)control->mid;
59485f05199cSMichael Tuexen 		sinfo->sinfo_flags = control->sinfo_flags;
59495f05199cSMichael Tuexen 		sinfo->sinfo_ppid = control->sinfo_ppid;
59505f05199cSMichael Tuexen 		sinfo->sinfo_context = control->sinfo_context;
59515f05199cSMichael Tuexen 		sinfo->sinfo_timetolive = control->sinfo_timetolive;
59525f05199cSMichael Tuexen 		sinfo->sinfo_tsn = control->sinfo_tsn;
59535f05199cSMichael Tuexen 		sinfo->sinfo_cumtsn = control->sinfo_cumtsn;
59545f05199cSMichael Tuexen 		sinfo->sinfo_assoc_id = control->sinfo_assoc_id;
5955f8829a4aSRandall Stewart 		nxt = TAILQ_NEXT(control, next);
5956e2e7c62eSMichael Tuexen 		if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO) ||
5957e2e7c62eSMichael Tuexen 		    sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO)) {
5958f8829a4aSRandall Stewart 			struct sctp_extrcvinfo *s_extra;
5959f8829a4aSRandall Stewart 
5960f8829a4aSRandall Stewart 			s_extra = (struct sctp_extrcvinfo *)sinfo;
59619a6142d8SRandall Stewart 			if ((nxt) &&
59629a6142d8SRandall Stewart 			    (nxt->length)) {
5963b70b526dSMichael Tuexen 				s_extra->serinfo_next_flags = SCTP_NEXT_MSG_AVAIL;
5964f8829a4aSRandall Stewart 				if (nxt->sinfo_flags & SCTP_UNORDERED) {
5965b70b526dSMichael Tuexen 					s_extra->serinfo_next_flags |= SCTP_NEXT_MSG_IS_UNORDERED;
5966f8829a4aSRandall Stewart 				}
5967f42a358aSRandall Stewart 				if (nxt->spec_flags & M_NOTIFICATION) {
5968b70b526dSMichael Tuexen 					s_extra->serinfo_next_flags |= SCTP_NEXT_MSG_IS_NOTIFICATION;
5969f42a358aSRandall Stewart 				}
5970b70b526dSMichael Tuexen 				s_extra->serinfo_next_aid = nxt->sinfo_assoc_id;
5971b70b526dSMichael Tuexen 				s_extra->serinfo_next_length = nxt->length;
5972b70b526dSMichael Tuexen 				s_extra->serinfo_next_ppid = nxt->sinfo_ppid;
5973b70b526dSMichael Tuexen 				s_extra->serinfo_next_stream = nxt->sinfo_stream;
5974f8829a4aSRandall Stewart 				if (nxt->tail_mbuf != NULL) {
5975139bc87fSRandall Stewart 					if (nxt->end_added) {
5976b70b526dSMichael Tuexen 						s_extra->serinfo_next_flags |= SCTP_NEXT_MSG_ISCOMPLETE;
5977f8829a4aSRandall Stewart 					}
5978f8829a4aSRandall Stewart 				}
5979f8829a4aSRandall Stewart 			} else {
5980f8829a4aSRandall Stewart 				/*
5981f8829a4aSRandall Stewart 				 * we explicitly 0 this, since the memcpy
5982f8829a4aSRandall Stewart 				 * got some other things beyond the older
5983f8829a4aSRandall Stewart 				 * sinfo_ that is on the control's structure
5984f8829a4aSRandall Stewart 				 * :-D
5985f8829a4aSRandall Stewart 				 */
59869a6142d8SRandall Stewart 				nxt = NULL;
5987b70b526dSMichael Tuexen 				s_extra->serinfo_next_flags = SCTP_NO_NEXT_MSG;
5988b70b526dSMichael Tuexen 				s_extra->serinfo_next_aid = 0;
5989b70b526dSMichael Tuexen 				s_extra->serinfo_next_length = 0;
5990b70b526dSMichael Tuexen 				s_extra->serinfo_next_ppid = 0;
5991b70b526dSMichael Tuexen 				s_extra->serinfo_next_stream = 0;
5992f8829a4aSRandall Stewart 			}
5993f8829a4aSRandall Stewart 		}
5994f8829a4aSRandall Stewart 		/*
5995f8829a4aSRandall Stewart 		 * update off the real current cum-ack, if we have an stcb.
5996f8829a4aSRandall Stewart 		 */
59970696e120SRandall Stewart 		if ((control->do_not_ref_stcb == 0) && stcb)
5998f8829a4aSRandall Stewart 			sinfo->sinfo_cumtsn = stcb->asoc.cumulative_tsn;
5999f8829a4aSRandall Stewart 		/*
6000f8829a4aSRandall Stewart 		 * mask off the high bits, we keep the actual chunk bits in
6001f8829a4aSRandall Stewart 		 * there.
6002f8829a4aSRandall Stewart 		 */
6003f8829a4aSRandall Stewart 		sinfo->sinfo_flags &= 0x00ff;
60045f26a41dSRandall Stewart 		if ((control->sinfo_flags >> 8) & SCTP_DATA_UNORDERED) {
60055f26a41dSRandall Stewart 			sinfo->sinfo_flags |= SCTP_UNORDERED;
60065f26a41dSRandall Stewart 		}
6007f8829a4aSRandall Stewart 	}
600818e198d3SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS
600918e198d3SRandall Stewart 	{
601018e198d3SRandall Stewart 		int index, newindex;
601118e198d3SRandall Stewart 		struct sctp_pcbtsn_rlog *entry;
601218e198d3SRandall Stewart 
601318e198d3SRandall Stewart 		do {
601418e198d3SRandall Stewart 			index = inp->readlog_index;
601518e198d3SRandall Stewart 			newindex = index + 1;
601618e198d3SRandall Stewart 			if (newindex >= SCTP_READ_LOG_SIZE) {
601718e198d3SRandall Stewart 				newindex = 0;
601818e198d3SRandall Stewart 			}
601918e198d3SRandall Stewart 		} while (atomic_cmpset_int(&inp->readlog_index, index, newindex) == 0);
602018e198d3SRandall Stewart 		entry = &inp->readlog[index];
602118e198d3SRandall Stewart 		entry->vtag = control->sinfo_assoc_id;
602218e198d3SRandall Stewart 		entry->strm = control->sinfo_stream;
602349656eefSMichael Tuexen 		entry->seq = (uint16_t)control->mid;
602418e198d3SRandall Stewart 		entry->sz = control->length;
602518e198d3SRandall Stewart 		entry->flgs = control->sinfo_flags;
602618e198d3SRandall Stewart 	}
602718e198d3SRandall Stewart #endif
6028d59107f7SMichael Tuexen 	if ((fromlen > 0) && (from != NULL)) {
6029d59107f7SMichael Tuexen 		union sctp_sockstore store;
6030d59107f7SMichael Tuexen 		size_t len;
6031d59107f7SMichael Tuexen 
6032b5b6e5c2SMichael Tuexen 		switch (control->whoFrom->ro._l_addr.sa.sa_family) {
6033b5b6e5c2SMichael Tuexen #ifdef INET6
6034b5b6e5c2SMichael Tuexen 		case AF_INET6:
6035d59107f7SMichael Tuexen 			len = sizeof(struct sockaddr_in6);
6036d59107f7SMichael Tuexen 			store.sin6 = control->whoFrom->ro._l_addr.sin6;
6037d59107f7SMichael Tuexen 			store.sin6.sin6_port = control->port_from;
6038b5b6e5c2SMichael Tuexen 			break;
6039f8829a4aSRandall Stewart #endif
6040b5b6e5c2SMichael Tuexen #ifdef INET
6041b5b6e5c2SMichael Tuexen 		case AF_INET:
6042d59107f7SMichael Tuexen #ifdef INET6
6043d59107f7SMichael Tuexen 			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
6044d59107f7SMichael Tuexen 				len = sizeof(struct sockaddr_in6);
6045d59107f7SMichael Tuexen 				in6_sin_2_v4mapsin6(&control->whoFrom->ro._l_addr.sin,
6046d59107f7SMichael Tuexen 				    &store.sin6);
6047d59107f7SMichael Tuexen 				store.sin6.sin6_port = control->port_from;
6048d59107f7SMichael Tuexen 			} else {
6049d59107f7SMichael Tuexen 				len = sizeof(struct sockaddr_in);
6050d59107f7SMichael Tuexen 				store.sin = control->whoFrom->ro._l_addr.sin;
6051d59107f7SMichael Tuexen 				store.sin.sin_port = control->port_from;
6052d59107f7SMichael Tuexen 			}
6053d59107f7SMichael Tuexen #else
6054d59107f7SMichael Tuexen 			len = sizeof(struct sockaddr_in);
6055d59107f7SMichael Tuexen 			store.sin = control->whoFrom->ro._l_addr.sin;
6056d59107f7SMichael Tuexen 			store.sin.sin_port = control->port_from;
6057d59107f7SMichael Tuexen #endif
6058b5b6e5c2SMichael Tuexen 			break;
6059b5b6e5c2SMichael Tuexen #endif
6060b5b6e5c2SMichael Tuexen 		default:
6061d59107f7SMichael Tuexen 			len = 0;
6062b5b6e5c2SMichael Tuexen 			break;
6063b5b6e5c2SMichael Tuexen 		}
6064d59107f7SMichael Tuexen 		memcpy(from, &store, min((size_t)fromlen, len));
6065e0e00a4dSMichael Tuexen #ifdef INET6
6066f8829a4aSRandall Stewart 		{
6067b5b6e5c2SMichael Tuexen 			struct sockaddr_in6 lsa6, *from6;
6068f8829a4aSRandall Stewart 
6069b5b6e5c2SMichael Tuexen 			from6 = (struct sockaddr_in6 *)from;
6070b5b6e5c2SMichael Tuexen 			sctp_recover_scope_mac(from6, (&lsa6));
6071f8829a4aSRandall Stewart 		}
6072f8829a4aSRandall Stewart #endif
6073f8829a4aSRandall Stewart 	}
60749c5ca6f2SMichael Tuexen 	if (hold_rlock) {
60759c5ca6f2SMichael Tuexen 		SCTP_INP_READ_UNLOCK(inp);
60769c5ca6f2SMichael Tuexen 		hold_rlock = 0;
60779c5ca6f2SMichael Tuexen 	}
60789c5ca6f2SMichael Tuexen 	if (hold_sblock) {
60799c5ca6f2SMichael Tuexen 		SOCKBUF_UNLOCK(&so->so_rcv);
60809c5ca6f2SMichael Tuexen 		hold_sblock = 0;
60819c5ca6f2SMichael Tuexen 	}
6082f8829a4aSRandall Stewart 	/* now copy out what data we can */
6083f8829a4aSRandall Stewart 	if (mp == NULL) {
6084f8829a4aSRandall Stewart 		/* copy out each mbuf in the chain up to length */
6085f8829a4aSRandall Stewart get_more_data:
6086f8829a4aSRandall Stewart 		m = control->data;
6087f8829a4aSRandall Stewart 		while (m) {
6088f8829a4aSRandall Stewart 			/* Move out all we can */
60890d3cf13dSMichael Tuexen 			cp_len = uio->uio_resid;
60900d3cf13dSMichael Tuexen 			my_len = SCTP_BUF_LEN(m);
6091f8829a4aSRandall Stewart 			if (cp_len > my_len) {
6092f8829a4aSRandall Stewart 				/* not enough in this buf */
6093f8829a4aSRandall Stewart 				cp_len = my_len;
6094f8829a4aSRandall Stewart 			}
6095f8829a4aSRandall Stewart 			if (hold_rlock) {
6096f8829a4aSRandall Stewart 				SCTP_INP_READ_UNLOCK(inp);
6097f8829a4aSRandall Stewart 				hold_rlock = 0;
6098f8829a4aSRandall Stewart 			}
6099f8829a4aSRandall Stewart 			if (cp_len > 0)
610058e6eeefSMichael Tuexen 				error = uiomove(mtod(m, char *), (int)cp_len, uio);
6101f8829a4aSRandall Stewart 			/* re-read */
6102f8829a4aSRandall Stewart 			if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
6103f8829a4aSRandall Stewart 				goto release;
6104f8829a4aSRandall Stewart 			}
61050053ed28SMichael Tuexen 
61060696e120SRandall Stewart 			if ((control->do_not_ref_stcb == 0) && stcb &&
6107f8829a4aSRandall Stewart 			    stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
6108f8829a4aSRandall Stewart 				no_rcv_needed = 1;
6109f8829a4aSRandall Stewart 			}
6110f8829a4aSRandall Stewart 			if (error) {
6111f8829a4aSRandall Stewart 				/* error we are out of here */
6112f8829a4aSRandall Stewart 				goto release;
6113f8829a4aSRandall Stewart 			}
6114f8829a4aSRandall Stewart 			SCTP_INP_READ_LOCK(inp);
6115f8829a4aSRandall Stewart 			hold_rlock = 1;
6116139bc87fSRandall Stewart 			if (cp_len == SCTP_BUF_LEN(m)) {
6117139bc87fSRandall Stewart 				if ((SCTP_BUF_NEXT(m) == NULL) &&
6118139bc87fSRandall Stewart 				    (control->end_added)) {
6119f8829a4aSRandall Stewart 					out_flags |= MSG_EOR;
612052129fcdSRandall Stewart 					if ((control->do_not_ref_stcb == 0) &&
612152129fcdSRandall Stewart 					    (control->stcb != NULL) &&
612252129fcdSRandall Stewart 					    ((control->spec_flags & M_NOTIFICATION) == 0))
6123ee7f9857SRandall Stewart 						control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0;
6124f8829a4aSRandall Stewart 				}
6125139bc87fSRandall Stewart 				if (control->spec_flags & M_NOTIFICATION) {
6126f8829a4aSRandall Stewart 					out_flags |= MSG_NOTIFICATION;
6127f8829a4aSRandall Stewart 				}
6128f8829a4aSRandall Stewart 				/* we ate up the mbuf */
6129f8829a4aSRandall Stewart 				if (in_flags & MSG_PEEK) {
6130f8829a4aSRandall Stewart 					/* just looking */
6131139bc87fSRandall Stewart 					m = SCTP_BUF_NEXT(m);
6132f8829a4aSRandall Stewart 					copied_so_far += cp_len;
6133f8829a4aSRandall Stewart 				} else {
6134f8829a4aSRandall Stewart 					/* dispose of the mbuf */
6135b3f1ea41SRandall Stewart 					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
6136f8829a4aSRandall Stewart 						sctp_sblog(&so->so_rcv,
6137139bc87fSRandall Stewart 						    control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m));
613880fefe0aSRandall Stewart 					}
6139f8829a4aSRandall Stewart 					sctp_sbfree(control, stcb, &so->so_rcv, m);
6140b3f1ea41SRandall Stewart 					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
6141f8829a4aSRandall Stewart 						sctp_sblog(&so->so_rcv,
6142f8829a4aSRandall Stewart 						    control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0);
614380fefe0aSRandall Stewart 					}
6144f8829a4aSRandall Stewart 					copied_so_far += cp_len;
614558e6eeefSMichael Tuexen 					freed_so_far += (uint32_t)cp_len;
6146c4739e2fSRandall Stewart 					freed_so_far += MSIZE;
614718e198d3SRandall Stewart 					atomic_subtract_int(&control->length, cp_len);
6148f8829a4aSRandall Stewart 					control->data = sctp_m_free(m);
6149f8829a4aSRandall Stewart 					m = control->data;
6150b7b84c0eSMichael Tuexen 					/*
6151b7b84c0eSMichael Tuexen 					 * been through it all, must hold sb
6152b7b84c0eSMichael Tuexen 					 * lock ok to null tail
6153b7b84c0eSMichael Tuexen 					 */
6154f8829a4aSRandall Stewart 					if (control->data == NULL) {
6155a5d547adSRandall Stewart #ifdef INVARIANTS
6156f8829a4aSRandall Stewart 						if ((control->end_added == 0) ||
6157f8829a4aSRandall Stewart 						    (TAILQ_NEXT(control, next) == NULL)) {
6158f8829a4aSRandall Stewart 							/*
6159f8829a4aSRandall Stewart 							 * If the end is not
6160f8829a4aSRandall Stewart 							 * added, OR the
6161f8829a4aSRandall Stewart 							 * next is NOT null
6162f8829a4aSRandall Stewart 							 * we MUST have the
6163f8829a4aSRandall Stewart 							 * lock.
6164f8829a4aSRandall Stewart 							 */
6165f8829a4aSRandall Stewart 							if (mtx_owned(&inp->inp_rdata_mtx) == 0) {
6166f8829a4aSRandall Stewart 								panic("Hmm we don't own the lock?");
6167f8829a4aSRandall Stewart 							}
6168f8829a4aSRandall Stewart 						}
6169f8829a4aSRandall Stewart #endif
6170f8829a4aSRandall Stewart 						control->tail_mbuf = NULL;
6171a5d547adSRandall Stewart #ifdef INVARIANTS
6172f8829a4aSRandall Stewart 						if ((control->end_added) && ((out_flags & MSG_EOR) == 0)) {
6173f8829a4aSRandall Stewart 							panic("end_added, nothing left and no MSG_EOR");
6174f8829a4aSRandall Stewart 						}
6175f8829a4aSRandall Stewart #endif
6176f8829a4aSRandall Stewart 					}
6177f8829a4aSRandall Stewart 				}
6178f8829a4aSRandall Stewart 			} else {
6179f8829a4aSRandall Stewart 				/* Do we need to trim the mbuf? */
6180139bc87fSRandall Stewart 				if (control->spec_flags & M_NOTIFICATION) {
6181f8829a4aSRandall Stewart 					out_flags |= MSG_NOTIFICATION;
6182f8829a4aSRandall Stewart 				}
6183f8829a4aSRandall Stewart 				if ((in_flags & MSG_PEEK) == 0) {
6184139bc87fSRandall Stewart 					SCTP_BUF_RESV_UF(m, cp_len);
618558e6eeefSMichael Tuexen 					SCTP_BUF_LEN(m) -= (int)cp_len;
6186b3f1ea41SRandall Stewart 					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
618758e6eeefSMichael Tuexen 						sctp_sblog(&so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, (int)cp_len);
618880fefe0aSRandall Stewart 					}
61894e88d37aSMichael Tuexen 					atomic_subtract_int(&so->so_rcv.sb_cc, cp_len);
61900696e120SRandall Stewart 					if ((control->do_not_ref_stcb == 0) &&
61910696e120SRandall Stewart 					    stcb) {
61924e88d37aSMichael Tuexen 						atomic_subtract_int(&stcb->asoc.sb_cc, cp_len);
6193f8829a4aSRandall Stewart 					}
6194f8829a4aSRandall Stewart 					copied_so_far += cp_len;
619558e6eeefSMichael Tuexen 					freed_so_far += (uint32_t)cp_len;
6196c4739e2fSRandall Stewart 					freed_so_far += MSIZE;
6197b3f1ea41SRandall Stewart 					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
6198f8829a4aSRandall Stewart 						sctp_sblog(&so->so_rcv, control->do_not_ref_stcb ? NULL : stcb,
6199f8829a4aSRandall Stewart 						    SCTP_LOG_SBRESULT, 0);
620080fefe0aSRandall Stewart 					}
620118e198d3SRandall Stewart 					atomic_subtract_int(&control->length, cp_len);
6202f8829a4aSRandall Stewart 				} else {
6203f8829a4aSRandall Stewart 					copied_so_far += cp_len;
6204f8829a4aSRandall Stewart 				}
6205f8829a4aSRandall Stewart 			}
6206d61a0ae0SRandall Stewart 			if ((out_flags & MSG_EOR) || (uio->uio_resid == 0)) {
6207f8829a4aSRandall Stewart 				break;
6208f8829a4aSRandall Stewart 			}
6209f8829a4aSRandall Stewart 			if (((stcb) && (in_flags & MSG_PEEK) == 0) &&
6210f8829a4aSRandall Stewart 			    (control->do_not_ref_stcb == 0) &&
6211f8829a4aSRandall Stewart 			    (freed_so_far >= rwnd_req)) {
6212f8829a4aSRandall Stewart 				sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req);
6213f8829a4aSRandall Stewart 			}
6214f8829a4aSRandall Stewart 		}		/* end while(m) */
6215f8829a4aSRandall Stewart 		/*
6216f8829a4aSRandall Stewart 		 * At this point we have looked at it all and we either have
6217f8829a4aSRandall Stewart 		 * a MSG_EOR/or read all the user wants... <OR>
6218f8829a4aSRandall Stewart 		 * control->length == 0.
6219f8829a4aSRandall Stewart 		 */
6220d61a0ae0SRandall Stewart 		if ((out_flags & MSG_EOR) && ((in_flags & MSG_PEEK) == 0)) {
6221f8829a4aSRandall Stewart 			/* we are done with this control */
6222f8829a4aSRandall Stewart 			if (control->length == 0) {
6223f8829a4aSRandall Stewart 				if (control->data) {
6224a5d547adSRandall Stewart #ifdef INVARIANTS
6225f8829a4aSRandall Stewart 					panic("control->data not null at read eor?");
6226f8829a4aSRandall Stewart #else
6227ad81507eSRandall Stewart 					SCTP_PRINTF("Strange, data left in the control buffer .. invarients would panic?\n");
6228f8829a4aSRandall Stewart 					sctp_m_freem(control->data);
6229f8829a4aSRandall Stewart 					control->data = NULL;
6230f8829a4aSRandall Stewart #endif
6231f8829a4aSRandall Stewart 				}
6232f8829a4aSRandall Stewart 		done_with_control:
6233f8829a4aSRandall Stewart 				if (hold_rlock == 0) {
6234f8829a4aSRandall Stewart 					SCTP_INP_READ_LOCK(inp);
6235f8829a4aSRandall Stewart 					hold_rlock = 1;
6236f8829a4aSRandall Stewart 				}
6237f8829a4aSRandall Stewart 				TAILQ_REMOVE(&inp->read_queue, control, next);
6238f8829a4aSRandall Stewart 				/* Add back any hiddend data */
6239f8829a4aSRandall Stewart 				if (control->held_length) {
6240f8829a4aSRandall Stewart 					held_length = 0;
6241f8829a4aSRandall Stewart 					control->held_length = 0;
6242f8829a4aSRandall Stewart 					wakeup_read_socket = 1;
6243f8829a4aSRandall Stewart 				}
624417205eccSRandall Stewart 				if (control->aux_data) {
624517205eccSRandall Stewart 					sctp_m_free(control->aux_data);
624617205eccSRandall Stewart 					control->aux_data = NULL;
624717205eccSRandall Stewart 				}
6248f8829a4aSRandall Stewart 				no_rcv_needed = control->do_not_ref_stcb;
6249f8829a4aSRandall Stewart 				sctp_free_remote_addr(control->whoFrom);
6250f8829a4aSRandall Stewart 				control->data = NULL;
625198d5fd97SMichael Tuexen #ifdef INVARIANTS
625244249214SRandall Stewart 				if (control->on_strm_q) {
625344249214SRandall Stewart 					panic("About to free ctl:%p so:%p and its in %d",
625444249214SRandall Stewart 					    control, so, control->on_strm_q);
625544249214SRandall Stewart 				}
625698d5fd97SMichael Tuexen #endif
6257f8829a4aSRandall Stewart 				sctp_free_a_readq(stcb, control);
6258f8829a4aSRandall Stewart 				control = NULL;
62590696e120SRandall Stewart 				if ((freed_so_far >= rwnd_req) &&
62600696e120SRandall Stewart 				    (no_rcv_needed == 0))
6261f8829a4aSRandall Stewart 					sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req);
6262f8829a4aSRandall Stewart 
6263f8829a4aSRandall Stewart 			} else {
6264f8829a4aSRandall Stewart 				/*
6265f8829a4aSRandall Stewart 				 * The user did not read all of this
6266f8829a4aSRandall Stewart 				 * message, turn off the returned MSG_EOR
6267f8829a4aSRandall Stewart 				 * since we are leaving more behind on the
6268f8829a4aSRandall Stewart 				 * control to read.
6269f8829a4aSRandall Stewart 				 */
6270a5d547adSRandall Stewart #ifdef INVARIANTS
62710696e120SRandall Stewart 				if (control->end_added &&
62720696e120SRandall Stewart 				    (control->data == NULL) &&
6273f8829a4aSRandall Stewart 				    (control->tail_mbuf == NULL)) {
6274f8829a4aSRandall Stewart 					panic("Gak, control->length is corrupt?");
6275f8829a4aSRandall Stewart 				}
6276f8829a4aSRandall Stewart #endif
6277f8829a4aSRandall Stewart 				no_rcv_needed = control->do_not_ref_stcb;
6278f8829a4aSRandall Stewart 				out_flags &= ~MSG_EOR;
6279f8829a4aSRandall Stewart 			}
6280f8829a4aSRandall Stewart 		}
6281f8829a4aSRandall Stewart 		if (out_flags & MSG_EOR) {
6282f8829a4aSRandall Stewart 			goto release;
6283f8829a4aSRandall Stewart 		}
6284f8829a4aSRandall Stewart 		if ((uio->uio_resid == 0) ||
628504aab884SMichael Tuexen 		    ((in_eeor_mode) &&
628643ecbff2SMichael Tuexen 		    (copied_so_far >= max(so->so_rcv.sb_lowat, 1)))) {
6287f8829a4aSRandall Stewart 			goto release;
6288f8829a4aSRandall Stewart 		}
6289f8829a4aSRandall Stewart 		/*
6290f8829a4aSRandall Stewart 		 * If I hit here the receiver wants more and this message is
6291f8829a4aSRandall Stewart 		 * NOT done (pd-api). So two questions. Can we block? if not
6292f8829a4aSRandall Stewart 		 * we are done. Did the user NOT set MSG_WAITALL?
6293f8829a4aSRandall Stewart 		 */
6294f8829a4aSRandall Stewart 		if (block_allowed == 0) {
6295f8829a4aSRandall Stewart 			goto release;
6296f8829a4aSRandall Stewart 		}
6297f8829a4aSRandall Stewart 		/*
6298f8829a4aSRandall Stewart 		 * We need to wait for more data a few things: - We don't
6299f8829a4aSRandall Stewart 		 * sbunlock() so we don't get someone else reading. - We
6300f8829a4aSRandall Stewart 		 * must be sure to account for the case where what is added
6301f8829a4aSRandall Stewart 		 * is NOT to our control when we wakeup.
6302f8829a4aSRandall Stewart 		 */
6303f8829a4aSRandall Stewart 
6304f8829a4aSRandall Stewart 		/*
6305f8829a4aSRandall Stewart 		 * Do we need to tell the transport a rwnd update might be
6306f8829a4aSRandall Stewart 		 * needed before we go to sleep?
6307f8829a4aSRandall Stewart 		 */
6308f8829a4aSRandall Stewart 		if (((stcb) && (in_flags & MSG_PEEK) == 0) &&
6309f8829a4aSRandall Stewart 		    ((freed_so_far >= rwnd_req) &&
6310f8829a4aSRandall Stewart 		    (control->do_not_ref_stcb == 0) &&
6311f8829a4aSRandall Stewart 		    (no_rcv_needed == 0))) {
6312f8829a4aSRandall Stewart 			sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req);
6313f8829a4aSRandall Stewart 		}
6314f8829a4aSRandall Stewart wait_some_more:
631544b7479bSRandall Stewart 		if (so->so_rcv.sb_state & SBS_CANTRCVMORE) {
6316f8829a4aSRandall Stewart 			goto release;
6317f8829a4aSRandall Stewart 		}
63180053ed28SMichael Tuexen 
6319f8829a4aSRandall Stewart 		if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)
6320f8829a4aSRandall Stewart 			goto release;
6321f8829a4aSRandall Stewart 
6322f8829a4aSRandall Stewart 		if (hold_rlock == 1) {
6323f8829a4aSRandall Stewart 			SCTP_INP_READ_UNLOCK(inp);
6324f8829a4aSRandall Stewart 			hold_rlock = 0;
6325f8829a4aSRandall Stewart 		}
6326f8829a4aSRandall Stewart 		if (hold_sblock == 0) {
6327f8829a4aSRandall Stewart 			SOCKBUF_LOCK(&so->so_rcv);
6328f8829a4aSRandall Stewart 			hold_sblock = 1;
6329f8829a4aSRandall Stewart 		}
6330851b7298SRandall Stewart 		if ((copied_so_far) && (control->length == 0) &&
6331b5c16493SMichael Tuexen 		    (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE))) {
6332851b7298SRandall Stewart 			goto release;
6333851b7298SRandall Stewart 		}
63344e88d37aSMichael Tuexen 		if (so->so_rcv.sb_cc <= control->held_length) {
6335f8829a4aSRandall Stewart 			error = sbwait(&so->so_rcv);
6336f8829a4aSRandall Stewart 			if (error) {
6337f8829a4aSRandall Stewart 				goto release;
6338f8829a4aSRandall Stewart 			}
6339f8829a4aSRandall Stewart 			control->held_length = 0;
6340f8829a4aSRandall Stewart 		}
6341f8829a4aSRandall Stewart 		if (hold_sblock) {
6342f8829a4aSRandall Stewart 			SOCKBUF_UNLOCK(&so->so_rcv);
6343f8829a4aSRandall Stewart 			hold_sblock = 0;
6344f8829a4aSRandall Stewart 		}
6345f8829a4aSRandall Stewart 		if (control->length == 0) {
6346f8829a4aSRandall Stewart 			/* still nothing here */
6347f8829a4aSRandall Stewart 			if (control->end_added == 1) {
6348f8829a4aSRandall Stewart 				/* he aborted, or is done i.e.did a shutdown */
6349f8829a4aSRandall Stewart 				out_flags |= MSG_EOR;
63509a6142d8SRandall Stewart 				if (control->pdapi_aborted) {
63516114cd96SRandall Stewart 					if ((control->do_not_ref_stcb == 0) && ((control->spec_flags & M_NOTIFICATION) == 0))
6352ee7f9857SRandall Stewart 						control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0;
63539a6142d8SRandall Stewart 
635403b0b021SRandall Stewart 					out_flags |= MSG_TRUNC;
63559a6142d8SRandall Stewart 				} else {
63566114cd96SRandall Stewart 					if ((control->do_not_ref_stcb == 0) && ((control->spec_flags & M_NOTIFICATION) == 0))
6357ee7f9857SRandall Stewart 						control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0;
63589a6142d8SRandall Stewart 				}
6359f8829a4aSRandall Stewart 				goto done_with_control;
6360f8829a4aSRandall Stewart 			}
63614e88d37aSMichael Tuexen 			if (so->so_rcv.sb_cc > held_length) {
63624e88d37aSMichael Tuexen 				control->held_length = so->so_rcv.sb_cc;
6363f8829a4aSRandall Stewart 				held_length = 0;
6364f8829a4aSRandall Stewart 			}
6365f8829a4aSRandall Stewart 			goto wait_some_more;
6366f8829a4aSRandall Stewart 		} else if (control->data == NULL) {
636750cec919SRandall Stewart 			/*
636850cec919SRandall Stewart 			 * we must re-sync since data is probably being
636950cec919SRandall Stewart 			 * added
637050cec919SRandall Stewart 			 */
637150cec919SRandall Stewart 			SCTP_INP_READ_LOCK(inp);
637250cec919SRandall Stewart 			if ((control->length > 0) && (control->data == NULL)) {
6373b7b84c0eSMichael Tuexen 				/*
6374b7b84c0eSMichael Tuexen 				 * big trouble.. we have the lock and its
6375b7b84c0eSMichael Tuexen 				 * corrupt?
6376b7b84c0eSMichael Tuexen 				 */
63779c04b296SRandall Stewart #ifdef INVARIANTS
63789d18771fSRandall Stewart 				panic("Impossible data==NULL length !=0");
63799c04b296SRandall Stewart #endif
63809c04b296SRandall Stewart 				out_flags |= MSG_EOR;
63819c04b296SRandall Stewart 				out_flags |= MSG_TRUNC;
63829c04b296SRandall Stewart 				control->length = 0;
63839c04b296SRandall Stewart 				SCTP_INP_READ_UNLOCK(inp);
63849c04b296SRandall Stewart 				goto done_with_control;
6385f8829a4aSRandall Stewart 			}
638650cec919SRandall Stewart 			SCTP_INP_READ_UNLOCK(inp);
638750cec919SRandall Stewart 			/* We will fall around to get more data */
638850cec919SRandall Stewart 		}
6389f8829a4aSRandall Stewart 		goto get_more_data;
6390f8829a4aSRandall Stewart 	} else {
639117205eccSRandall Stewart 		/*-
639217205eccSRandall Stewart 		 * Give caller back the mbuf chain,
639317205eccSRandall Stewart 		 * store in uio_resid the length
6394f8829a4aSRandall Stewart 		 */
639517205eccSRandall Stewart 		wakeup_read_socket = 0;
6396f8829a4aSRandall Stewart 		if ((control->end_added == 0) ||
6397f8829a4aSRandall Stewart 		    (TAILQ_NEXT(control, next) == NULL)) {
6398f8829a4aSRandall Stewart 			/* Need to get rlock */
6399f8829a4aSRandall Stewart 			if (hold_rlock == 0) {
6400f8829a4aSRandall Stewart 				SCTP_INP_READ_LOCK(inp);
6401f8829a4aSRandall Stewart 				hold_rlock = 1;
6402f8829a4aSRandall Stewart 			}
6403f8829a4aSRandall Stewart 		}
6404139bc87fSRandall Stewart 		if (control->end_added) {
6405f8829a4aSRandall Stewart 			out_flags |= MSG_EOR;
640660990c0cSMichael Tuexen 			if ((control->do_not_ref_stcb == 0) &&
640760990c0cSMichael Tuexen 			    (control->stcb != NULL) &&
640860990c0cSMichael Tuexen 			    ((control->spec_flags & M_NOTIFICATION) == 0))
6409ee7f9857SRandall Stewart 				control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0;
6410f8829a4aSRandall Stewart 		}
6411139bc87fSRandall Stewart 		if (control->spec_flags & M_NOTIFICATION) {
6412f8829a4aSRandall Stewart 			out_flags |= MSG_NOTIFICATION;
6413f8829a4aSRandall Stewart 		}
641417205eccSRandall Stewart 		uio->uio_resid = control->length;
6415f8829a4aSRandall Stewart 		*mp = control->data;
6416f8829a4aSRandall Stewart 		m = control->data;
6417f8829a4aSRandall Stewart 		while (m) {
6418b3f1ea41SRandall Stewart 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
6419f8829a4aSRandall Stewart 				sctp_sblog(&so->so_rcv,
6420139bc87fSRandall Stewart 				    control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m));
642180fefe0aSRandall Stewart 			}
6422f8829a4aSRandall Stewart 			sctp_sbfree(control, stcb, &so->so_rcv, m);
642358e6eeefSMichael Tuexen 			freed_so_far += (uint32_t)SCTP_BUF_LEN(m);
6424c4739e2fSRandall Stewart 			freed_so_far += MSIZE;
6425b3f1ea41SRandall Stewart 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
6426f8829a4aSRandall Stewart 				sctp_sblog(&so->so_rcv,
6427f8829a4aSRandall Stewart 				    control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0);
642880fefe0aSRandall Stewart 			}
6429139bc87fSRandall Stewart 			m = SCTP_BUF_NEXT(m);
6430f8829a4aSRandall Stewart 		}
6431f8829a4aSRandall Stewart 		control->data = control->tail_mbuf = NULL;
6432f8829a4aSRandall Stewart 		control->length = 0;
6433f8829a4aSRandall Stewart 		if (out_flags & MSG_EOR) {
6434f8829a4aSRandall Stewart 			/* Done with this control */
6435f8829a4aSRandall Stewart 			goto done_with_control;
6436f8829a4aSRandall Stewart 		}
6437f8829a4aSRandall Stewart 	}
6438f8829a4aSRandall Stewart release:
6439f8829a4aSRandall Stewart 	if (hold_rlock == 1) {
6440f8829a4aSRandall Stewart 		SCTP_INP_READ_UNLOCK(inp);
6441f8829a4aSRandall Stewart 		hold_rlock = 0;
6442f8829a4aSRandall Stewart 	}
64437abab911SRobert Watson 	if (hold_sblock == 1) {
64447abab911SRobert Watson 		SOCKBUF_UNLOCK(&so->so_rcv);
64457abab911SRobert Watson 		hold_sblock = 0;
6446f8829a4aSRandall Stewart 	}
64470053ed28SMichael Tuexen 
6448f8829a4aSRandall Stewart 	sbunlock(&so->so_rcv);
64497abab911SRobert Watson 	sockbuf_lock = 0;
6450f8829a4aSRandall Stewart 
6451f8829a4aSRandall Stewart release_unlocked:
6452f8829a4aSRandall Stewart 	if (hold_sblock) {
6453f8829a4aSRandall Stewart 		SOCKBUF_UNLOCK(&so->so_rcv);
6454f8829a4aSRandall Stewart 		hold_sblock = 0;
6455f8829a4aSRandall Stewart 	}
6456f8829a4aSRandall Stewart 	if ((stcb) && (in_flags & MSG_PEEK) == 0) {
6457f8829a4aSRandall Stewart 		if ((freed_so_far >= rwnd_req) &&
6458f8829a4aSRandall Stewart 		    (control && (control->do_not_ref_stcb == 0)) &&
6459f8829a4aSRandall Stewart 		    (no_rcv_needed == 0))
6460f8829a4aSRandall Stewart 			sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req);
6461f8829a4aSRandall Stewart 	}
6462f8829a4aSRandall Stewart out:
64631b9f62a0SRandall Stewart 	if (msg_flags) {
64641b9f62a0SRandall Stewart 		*msg_flags = out_flags;
64651b9f62a0SRandall Stewart 	}
64669a6142d8SRandall Stewart 	if (((out_flags & MSG_EOR) == 0) &&
64679a6142d8SRandall Stewart 	    ((in_flags & MSG_PEEK) == 0) &&
64689a6142d8SRandall Stewart 	    (sinfo) &&
6469e2e7c62eSMichael Tuexen 	    (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO) ||
6470e2e7c62eSMichael Tuexen 	    sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO))) {
64719a6142d8SRandall Stewart 		struct sctp_extrcvinfo *s_extra;
64729a6142d8SRandall Stewart 
64739a6142d8SRandall Stewart 		s_extra = (struct sctp_extrcvinfo *)sinfo;
6474b70b526dSMichael Tuexen 		s_extra->serinfo_next_flags = SCTP_NO_NEXT_MSG;
64759a6142d8SRandall Stewart 	}
6476f8829a4aSRandall Stewart 	if (hold_rlock == 1) {
6477f8829a4aSRandall Stewart 		SCTP_INP_READ_UNLOCK(inp);
6478f8829a4aSRandall Stewart 	}
6479f8829a4aSRandall Stewart 	if (hold_sblock) {
6480f8829a4aSRandall Stewart 		SOCKBUF_UNLOCK(&so->so_rcv);
6481f8829a4aSRandall Stewart 	}
64827abab911SRobert Watson 	if (sockbuf_lock) {
64837abab911SRobert Watson 		sbunlock(&so->so_rcv);
64847abab911SRobert Watson 	}
64850053ed28SMichael Tuexen 
648650cec919SRandall Stewart 	if (freecnt_applied) {
6487f8829a4aSRandall Stewart 		/*
6488f8829a4aSRandall Stewart 		 * The lock on the socket buffer protects us so the free
6489f8829a4aSRandall Stewart 		 * code will stop. But since we used the socketbuf lock and
6490f8829a4aSRandall Stewart 		 * the sender uses the tcb_lock to increment, we need to use
6491f8829a4aSRandall Stewart 		 * the atomic add to the refcnt.
6492f8829a4aSRandall Stewart 		 */
649350cec919SRandall Stewart 		if (stcb == NULL) {
6494df6e0cc3SRandall Stewart #ifdef INVARIANTS
649550cec919SRandall Stewart 			panic("stcb for refcnt has gone NULL?");
6496df6e0cc3SRandall Stewart 			goto stage_left;
6497df6e0cc3SRandall Stewart #else
6498df6e0cc3SRandall Stewart 			goto stage_left;
6499df6e0cc3SRandall Stewart #endif
650050cec919SRandall Stewart 		}
6501f8829a4aSRandall Stewart 		/* Save the value back for next time */
6502f8829a4aSRandall Stewart 		stcb->freed_by_sorcv_sincelast = freed_so_far;
6503cf46caceSMichael Tuexen 		atomic_add_int(&stcb->asoc.refcnt, -1);
6504f8829a4aSRandall Stewart 	}
6505b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RECV_RWND_LOGGING_ENABLE) {
6506f8829a4aSRandall Stewart 		if (stcb) {
6507f8829a4aSRandall Stewart 			sctp_misc_ints(SCTP_SORECV_DONE,
6508f8829a4aSRandall Stewart 			    freed_so_far,
65099a8e3088SMichael Tuexen 			    (uint32_t)((uio) ? (slen - uio->uio_resid) : slen),
6510f8829a4aSRandall Stewart 			    stcb->asoc.my_rwnd,
65114e88d37aSMichael Tuexen 			    so->so_rcv.sb_cc);
6512f8829a4aSRandall Stewart 		} else {
6513f8829a4aSRandall Stewart 			sctp_misc_ints(SCTP_SORECV_DONE,
6514f8829a4aSRandall Stewart 			    freed_so_far,
65159a8e3088SMichael Tuexen 			    (uint32_t)((uio) ? (slen - uio->uio_resid) : slen),
6516f8829a4aSRandall Stewart 			    0,
65174e88d37aSMichael Tuexen 			    so->so_rcv.sb_cc);
6518f8829a4aSRandall Stewart 		}
651980fefe0aSRandall Stewart 	}
6520df6e0cc3SRandall Stewart stage_left:
6521f8829a4aSRandall Stewart 	if (wakeup_read_socket) {
6522f8829a4aSRandall Stewart 		sctp_sorwakeup(inp, so);
6523f8829a4aSRandall Stewart 	}
6524f8829a4aSRandall Stewart 	return (error);
6525f8829a4aSRandall Stewart }
6526f8829a4aSRandall Stewart 
6527f8829a4aSRandall Stewart 
6528f8829a4aSRandall Stewart #ifdef SCTP_MBUF_LOGGING
6529f8829a4aSRandall Stewart struct mbuf *
6530f8829a4aSRandall Stewart sctp_m_free(struct mbuf *m)
6531f8829a4aSRandall Stewart {
6532b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
6533f8829a4aSRandall Stewart 		sctp_log_mb(m, SCTP_MBUF_IFREE);
6534f8829a4aSRandall Stewart 	}
6535f8829a4aSRandall Stewart 	return (m_free(m));
6536f8829a4aSRandall Stewart }
6537f8829a4aSRandall Stewart 
6538f8829a4aSRandall Stewart void
6539f8829a4aSRandall Stewart sctp_m_freem(struct mbuf *mb)
6540f8829a4aSRandall Stewart {
6541f8829a4aSRandall Stewart 	while (mb != NULL)
6542f8829a4aSRandall Stewart 		mb = sctp_m_free(mb);
6543f8829a4aSRandall Stewart }
6544f8829a4aSRandall Stewart 
6545f8829a4aSRandall Stewart #endif
6546f8829a4aSRandall Stewart 
654742551e99SRandall Stewart int
654842551e99SRandall Stewart sctp_dynamic_set_primary(struct sockaddr *sa, uint32_t vrf_id)
654942551e99SRandall Stewart {
655042551e99SRandall Stewart 	/*
655142551e99SRandall Stewart 	 * Given a local address. For all associations that holds the
655242551e99SRandall Stewart 	 * address, request a peer-set-primary.
655342551e99SRandall Stewart 	 */
655442551e99SRandall Stewart 	struct sctp_ifa *ifa;
655542551e99SRandall Stewart 	struct sctp_laddr *wi;
655642551e99SRandall Stewart 
655742551e99SRandall Stewart 	ifa = sctp_find_ifa_by_addr(sa, vrf_id, 0);
655842551e99SRandall Stewart 	if (ifa == NULL) {
6559c4739e2fSRandall Stewart 		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EADDRNOTAVAIL);
656042551e99SRandall Stewart 		return (EADDRNOTAVAIL);
656142551e99SRandall Stewart 	}
656242551e99SRandall Stewart 	/*
656342551e99SRandall Stewart 	 * Now that we have the ifa we must awaken the iterator with this
656442551e99SRandall Stewart 	 * message.
656542551e99SRandall Stewart 	 */
6566b3f1ea41SRandall Stewart 	wi = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_laddr), struct sctp_laddr);
656742551e99SRandall Stewart 	if (wi == NULL) {
6568c4739e2fSRandall Stewart 		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOMEM);
656942551e99SRandall Stewart 		return (ENOMEM);
657042551e99SRandall Stewart 	}
657142551e99SRandall Stewart 	/* Now incr the count and int wi structure */
657242551e99SRandall Stewart 	SCTP_INCR_LADDR_COUNT();
65735ba7f91fSMichael Tuexen 	memset(wi, 0, sizeof(*wi));
6574d61a0ae0SRandall Stewart 	(void)SCTP_GETTIME_TIMEVAL(&wi->start_time);
657542551e99SRandall Stewart 	wi->ifa = ifa;
657642551e99SRandall Stewart 	wi->action = SCTP_SET_PRIM_ADDR;
657742551e99SRandall Stewart 	atomic_add_int(&ifa->refcount, 1);
657842551e99SRandall Stewart 
657942551e99SRandall Stewart 	/* Now add it to the work queue */
6580f7517433SRandall Stewart 	SCTP_WQ_ADDR_LOCK();
658142551e99SRandall Stewart 	/*
658242551e99SRandall Stewart 	 * Should this really be a tailq? As it is we will process the
658342551e99SRandall Stewart 	 * newest first :-0
658442551e99SRandall Stewart 	 */
6585b3f1ea41SRandall Stewart 	LIST_INSERT_HEAD(&SCTP_BASE_INFO(addr_wq), wi, sctp_nxt_addr);
658642551e99SRandall Stewart 	sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ,
658742551e99SRandall Stewart 	    (struct sctp_inpcb *)NULL,
658842551e99SRandall Stewart 	    (struct sctp_tcb *)NULL,
658942551e99SRandall Stewart 	    (struct sctp_nets *)NULL);
65902c62ba73SMichael Tuexen 	SCTP_WQ_ADDR_UNLOCK();
659142551e99SRandall Stewart 	return (0);
659242551e99SRandall Stewart }
659342551e99SRandall Stewart 
659442551e99SRandall Stewart 
6595f8829a4aSRandall Stewart int
659617205eccSRandall Stewart sctp_soreceive(struct socket *so,
659717205eccSRandall Stewart     struct sockaddr **psa,
659817205eccSRandall Stewart     struct uio *uio,
659917205eccSRandall Stewart     struct mbuf **mp0,
660017205eccSRandall Stewart     struct mbuf **controlp,
660117205eccSRandall Stewart     int *flagsp)
6602f8829a4aSRandall Stewart {
6603f8829a4aSRandall Stewart 	int error, fromlen;
6604f8829a4aSRandall Stewart 	uint8_t sockbuf[256];
6605f8829a4aSRandall Stewart 	struct sockaddr *from;
6606f8829a4aSRandall Stewart 	struct sctp_extrcvinfo sinfo;
6607f8829a4aSRandall Stewart 	int filling_sinfo = 1;
660846bf534cSMichael Tuexen 	int flags;
6609f8829a4aSRandall Stewart 	struct sctp_inpcb *inp;
6610f8829a4aSRandall Stewart 
6611f8829a4aSRandall Stewart 	inp = (struct sctp_inpcb *)so->so_pcb;
6612f8829a4aSRandall Stewart 	/* pickup the assoc we are reading from */
6613f8829a4aSRandall Stewart 	if (inp == NULL) {
6614c4739e2fSRandall Stewart 		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6615f8829a4aSRandall Stewart 		return (EINVAL);
6616f8829a4aSRandall Stewart 	}
6617e2e7c62eSMichael Tuexen 	if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT) &&
6618e2e7c62eSMichael Tuexen 	    sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVRCVINFO) &&
6619e2e7c62eSMichael Tuexen 	    sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVNXTINFO)) ||
6620f8829a4aSRandall Stewart 	    (controlp == NULL)) {
6621f8829a4aSRandall Stewart 		/* user does not want the sndrcv ctl */
6622f8829a4aSRandall Stewart 		filling_sinfo = 0;
6623f8829a4aSRandall Stewart 	}
6624f8829a4aSRandall Stewart 	if (psa) {
6625f8829a4aSRandall Stewart 		from = (struct sockaddr *)sockbuf;
6626f8829a4aSRandall Stewart 		fromlen = sizeof(sockbuf);
6627f8829a4aSRandall Stewart 		from->sa_len = 0;
6628f8829a4aSRandall Stewart 	} else {
6629f8829a4aSRandall Stewart 		from = NULL;
6630f8829a4aSRandall Stewart 		fromlen = 0;
6631f8829a4aSRandall Stewart 	}
6632f8829a4aSRandall Stewart 
6633e432298aSXin LI 	if (filling_sinfo) {
6634e432298aSXin LI 		memset(&sinfo, 0, sizeof(struct sctp_extrcvinfo));
6635e432298aSXin LI 	}
663646bf534cSMichael Tuexen 	if (flagsp != NULL) {
663746bf534cSMichael Tuexen 		flags = *flagsp;
663846bf534cSMichael Tuexen 	} else {
663946bf534cSMichael Tuexen 		flags = 0;
664046bf534cSMichael Tuexen 	}
664146bf534cSMichael Tuexen 	error = sctp_sorecvmsg(so, uio, mp0, from, fromlen, &flags,
6642f8829a4aSRandall Stewart 	    (struct sctp_sndrcvinfo *)&sinfo, filling_sinfo);
664346bf534cSMichael Tuexen 	if (flagsp != NULL) {
664446bf534cSMichael Tuexen 		*flagsp = flags;
664546bf534cSMichael Tuexen 	}
6646e432298aSXin LI 	if (controlp != NULL) {
6647f8829a4aSRandall Stewart 		/* copy back the sinfo in a CMSG format */
664846bf534cSMichael Tuexen 		if (filling_sinfo && ((flags & MSG_NOTIFICATION) == 0)) {
6649f8829a4aSRandall Stewart 			*controlp = sctp_build_ctl_nchunk(inp,
6650f8829a4aSRandall Stewart 			    (struct sctp_sndrcvinfo *)&sinfo);
665146bf534cSMichael Tuexen 		} else {
6652f8829a4aSRandall Stewart 			*controlp = NULL;
6653f8829a4aSRandall Stewart 		}
665446bf534cSMichael Tuexen 	}
6655f8829a4aSRandall Stewart 	if (psa) {
6656f8829a4aSRandall Stewart 		/* copy back the address info */
6657f8829a4aSRandall Stewart 		if (from && from->sa_len) {
6658f8829a4aSRandall Stewart 			*psa = sodupsockaddr(from, M_NOWAIT);
6659f8829a4aSRandall Stewart 		} else {
6660f8829a4aSRandall Stewart 			*psa = NULL;
6661f8829a4aSRandall Stewart 		}
6662f8829a4aSRandall Stewart 	}
6663f8829a4aSRandall Stewart 	return (error);
6664f8829a4aSRandall Stewart }
666517205eccSRandall Stewart 
666617205eccSRandall Stewart 
666717205eccSRandall Stewart 
666817205eccSRandall Stewart 
666917205eccSRandall Stewart 
667017205eccSRandall Stewart int
6671d61a0ae0SRandall Stewart sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr,
6672d61a0ae0SRandall Stewart     int totaddr, int *error)
667317205eccSRandall Stewart {
667417205eccSRandall Stewart 	int added = 0;
667517205eccSRandall Stewart 	int i;
667617205eccSRandall Stewart 	struct sctp_inpcb *inp;
667717205eccSRandall Stewart 	struct sockaddr *sa;
667817205eccSRandall Stewart 	size_t incr = 0;
667992776dfdSMichael Tuexen #ifdef INET
668092776dfdSMichael Tuexen 	struct sockaddr_in *sin;
668192776dfdSMichael Tuexen #endif
668292776dfdSMichael Tuexen #ifdef INET6
668392776dfdSMichael Tuexen 	struct sockaddr_in6 *sin6;
668492776dfdSMichael Tuexen #endif
668592776dfdSMichael Tuexen 
668617205eccSRandall Stewart 	sa = addr;
668717205eccSRandall Stewart 	inp = stcb->sctp_ep;
668817205eccSRandall Stewart 	*error = 0;
668917205eccSRandall Stewart 	for (i = 0; i < totaddr; i++) {
6690ea5eba11SMichael Tuexen 		switch (sa->sa_family) {
6691ea5eba11SMichael Tuexen #ifdef INET
6692ea5eba11SMichael Tuexen 		case AF_INET:
669317205eccSRandall Stewart 			incr = sizeof(struct sockaddr_in);
669492776dfdSMichael Tuexen 			sin = (struct sockaddr_in *)sa;
669592776dfdSMichael Tuexen 			if ((sin->sin_addr.s_addr == INADDR_ANY) ||
669692776dfdSMichael Tuexen 			    (sin->sin_addr.s_addr == INADDR_BROADCAST) ||
669792776dfdSMichael Tuexen 			    IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
669892776dfdSMichael Tuexen 				SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6699ba785902SMichael Tuexen 				(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
6700ba785902SMichael Tuexen 				    SCTP_FROM_SCTPUTIL + SCTP_LOC_7);
670192776dfdSMichael Tuexen 				*error = EINVAL;
670292776dfdSMichael Tuexen 				goto out_now;
670392776dfdSMichael Tuexen 			}
67047154bf4aSMichael Tuexen 			if (sctp_add_remote_addr(stcb, sa, NULL, stcb->asoc.port,
67057154bf4aSMichael Tuexen 			    SCTP_DONOT_SETSCOPE,
67067154bf4aSMichael Tuexen 			    SCTP_ADDR_IS_CONFIRMED)) {
670717205eccSRandall Stewart 				/* assoc gone no un-lock */
6708c4739e2fSRandall Stewart 				SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS);
6709ba785902SMichael Tuexen 				(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
6710ba785902SMichael Tuexen 				    SCTP_FROM_SCTPUTIL + SCTP_LOC_8);
671117205eccSRandall Stewart 				*error = ENOBUFS;
671217205eccSRandall Stewart 				goto out_now;
671317205eccSRandall Stewart 			}
671417205eccSRandall Stewart 			added++;
6715ea5eba11SMichael Tuexen 			break;
6716ea5eba11SMichael Tuexen #endif
6717ea5eba11SMichael Tuexen #ifdef INET6
6718ea5eba11SMichael Tuexen 		case AF_INET6:
671917205eccSRandall Stewart 			incr = sizeof(struct sockaddr_in6);
672092776dfdSMichael Tuexen 			sin6 = (struct sockaddr_in6 *)sa;
672192776dfdSMichael Tuexen 			if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) ||
672292776dfdSMichael Tuexen 			    IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
672392776dfdSMichael Tuexen 				SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6724ba785902SMichael Tuexen 				(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
6725ba785902SMichael Tuexen 				    SCTP_FROM_SCTPUTIL + SCTP_LOC_9);
672692776dfdSMichael Tuexen 				*error = EINVAL;
672792776dfdSMichael Tuexen 				goto out_now;
672892776dfdSMichael Tuexen 			}
67297154bf4aSMichael Tuexen 			if (sctp_add_remote_addr(stcb, sa, NULL, stcb->asoc.port,
67307154bf4aSMichael Tuexen 			    SCTP_DONOT_SETSCOPE,
67317154bf4aSMichael Tuexen 			    SCTP_ADDR_IS_CONFIRMED)) {
673217205eccSRandall Stewart 				/* assoc gone no un-lock */
6733c4739e2fSRandall Stewart 				SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS);
6734ba785902SMichael Tuexen 				(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
6735ba785902SMichael Tuexen 				    SCTP_FROM_SCTPUTIL + SCTP_LOC_10);
673617205eccSRandall Stewart 				*error = ENOBUFS;
673717205eccSRandall Stewart 				goto out_now;
673817205eccSRandall Stewart 			}
673917205eccSRandall Stewart 			added++;
6740ea5eba11SMichael Tuexen 			break;
6741ea5eba11SMichael Tuexen #endif
6742ea5eba11SMichael Tuexen 		default:
6743ea5eba11SMichael Tuexen 			break;
674417205eccSRandall Stewart 		}
674517205eccSRandall Stewart 		sa = (struct sockaddr *)((caddr_t)sa + incr);
674617205eccSRandall Stewart 	}
674717205eccSRandall Stewart out_now:
674817205eccSRandall Stewart 	return (added);
674917205eccSRandall Stewart }
675017205eccSRandall Stewart 
6751fc26bf71SMichael Tuexen int
6752d61a0ae0SRandall Stewart sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr,
6753fc26bf71SMichael Tuexen     unsigned int totaddr,
6754fc26bf71SMichael Tuexen     unsigned int *num_v4, unsigned int *num_v6,
6755fc26bf71SMichael Tuexen     unsigned int limit)
675617205eccSRandall Stewart {
675717205eccSRandall Stewart 	struct sockaddr *sa;
6758fc26bf71SMichael Tuexen 	struct sctp_tcb *stcb;
67599a8e3088SMichael Tuexen 	unsigned int incr, at, i;
676017205eccSRandall Stewart 
6761e1949767SMichael Tuexen 	at = 0;
676217205eccSRandall Stewart 	sa = addr;
6763fc26bf71SMichael Tuexen 	*num_v6 = *num_v4 = 0;
676417205eccSRandall Stewart 	/* account and validate addresses */
6765fc26bf71SMichael Tuexen 	if (totaddr == 0) {
6766fc26bf71SMichael Tuexen 		return (EINVAL);
6767fc26bf71SMichael Tuexen 	}
6768fc26bf71SMichael Tuexen 	for (i = 0; i < totaddr; i++) {
6769fc26bf71SMichael Tuexen 		if (at + sizeof(struct sockaddr) > limit) {
6770fc26bf71SMichael Tuexen 			return (EINVAL);
6771fc26bf71SMichael Tuexen 		}
6772ea5eba11SMichael Tuexen 		switch (sa->sa_family) {
6773ea5eba11SMichael Tuexen #ifdef INET
6774ea5eba11SMichael Tuexen 		case AF_INET:
6775e1949767SMichael Tuexen 			incr = (unsigned int)sizeof(struct sockaddr_in);
6776d61a0ae0SRandall Stewart 			if (sa->sa_len != incr) {
6777fc26bf71SMichael Tuexen 				return (EINVAL);
6778d61a0ae0SRandall Stewart 			}
67799a8e3088SMichael Tuexen 			(*num_v4) += 1;
6780ea5eba11SMichael Tuexen 			break;
6781ea5eba11SMichael Tuexen #endif
6782ea5eba11SMichael Tuexen #ifdef INET6
6783ea5eba11SMichael Tuexen 		case AF_INET6:
6784ea5eba11SMichael Tuexen 			{
678517205eccSRandall Stewart 				struct sockaddr_in6 *sin6;
678617205eccSRandall Stewart 
678717205eccSRandall Stewart 				sin6 = (struct sockaddr_in6 *)sa;
678817205eccSRandall Stewart 				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
678917205eccSRandall Stewart 					/* Must be non-mapped for connectx */
6790fc26bf71SMichael Tuexen 					return (EINVAL);
679117205eccSRandall Stewart 				}
6792e1949767SMichael Tuexen 				incr = (unsigned int)sizeof(struct sockaddr_in6);
6793d61a0ae0SRandall Stewart 				if (sa->sa_len != incr) {
6794fc26bf71SMichael Tuexen 					return (EINVAL);
6795d61a0ae0SRandall Stewart 				}
67969a8e3088SMichael Tuexen 				(*num_v6) += 1;
6797ea5eba11SMichael Tuexen 				break;
6798ea5eba11SMichael Tuexen 			}
6799ea5eba11SMichael Tuexen #endif
6800ea5eba11SMichael Tuexen 		default:
6801fc26bf71SMichael Tuexen 			return (EINVAL);
680217205eccSRandall Stewart 		}
6803fc26bf71SMichael Tuexen 		if ((at + incr) > limit) {
6804fc26bf71SMichael Tuexen 			return (EINVAL);
6805ea5eba11SMichael Tuexen 		}
6806d61a0ae0SRandall Stewart 		SCTP_INP_INCR_REF(inp);
680717205eccSRandall Stewart 		stcb = sctp_findassociation_ep_addr(&inp, sa, NULL, NULL, NULL);
680817205eccSRandall Stewart 		if (stcb != NULL) {
6809fc26bf71SMichael Tuexen 			SCTP_TCB_UNLOCK(stcb);
6810fc26bf71SMichael Tuexen 			return (EALREADY);
6811d61a0ae0SRandall Stewart 		} else {
6812d61a0ae0SRandall Stewart 			SCTP_INP_DECR_REF(inp);
681317205eccSRandall Stewart 		}
6814fc26bf71SMichael Tuexen 		at += incr;
681517205eccSRandall Stewart 		sa = (struct sockaddr *)((caddr_t)sa + incr);
681617205eccSRandall Stewart 	}
6817fc26bf71SMichael Tuexen 	return (0);
681817205eccSRandall Stewart }
681935918f85SRandall Stewart 
682035918f85SRandall Stewart /*
682135918f85SRandall Stewart  * sctp_bindx(ADD) for one address.
682235918f85SRandall Stewart  * assumes all arguments are valid/checked by caller.
682335918f85SRandall Stewart  */
682435918f85SRandall Stewart void
682535918f85SRandall Stewart sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp,
682635918f85SRandall Stewart     struct sockaddr *sa, sctp_assoc_t assoc_id,
682735918f85SRandall Stewart     uint32_t vrf_id, int *error, void *p)
682835918f85SRandall Stewart {
682935918f85SRandall Stewart 	struct sockaddr *addr_touse;
6830d59107f7SMichael Tuexen #if defined(INET) && defined(INET6)
683135918f85SRandall Stewart 	struct sockaddr_in sin;
68325e2c2d87SRandall Stewart #endif
68335e2c2d87SRandall Stewart 
683435918f85SRandall Stewart 	/* see if we're bound all already! */
683535918f85SRandall Stewart 	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
6836c4739e2fSRandall Stewart 		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
683735918f85SRandall Stewart 		*error = EINVAL;
683835918f85SRandall Stewart 		return;
683935918f85SRandall Stewart 	}
684035918f85SRandall Stewart 	addr_touse = sa;
6841ea5eba11SMichael Tuexen #ifdef INET6
684235918f85SRandall Stewart 	if (sa->sa_family == AF_INET6) {
6843d59107f7SMichael Tuexen #ifdef INET
684435918f85SRandall Stewart 		struct sockaddr_in6 *sin6;
684535918f85SRandall Stewart 
6846d59107f7SMichael Tuexen #endif
684735918f85SRandall Stewart 		if (sa->sa_len != sizeof(struct sockaddr_in6)) {
6848c4739e2fSRandall Stewart 			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
684935918f85SRandall Stewart 			*error = EINVAL;
685035918f85SRandall Stewart 			return;
685135918f85SRandall Stewart 		}
6852db4fd95bSRandall Stewart 		if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
6853db4fd95bSRandall Stewart 			/* can only bind v6 on PF_INET6 sockets */
6854c4739e2fSRandall Stewart 			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6855db4fd95bSRandall Stewart 			*error = EINVAL;
6856db4fd95bSRandall Stewart 			return;
6857db4fd95bSRandall Stewart 		}
6858d59107f7SMichael Tuexen #ifdef INET
685935918f85SRandall Stewart 		sin6 = (struct sockaddr_in6 *)addr_touse;
686035918f85SRandall Stewart 		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
6861db4fd95bSRandall Stewart 			if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
6862db4fd95bSRandall Stewart 			    SCTP_IPV6_V6ONLY(inp)) {
6863db4fd95bSRandall Stewart 				/* can't bind v4-mapped on PF_INET sockets */
6864c4739e2fSRandall Stewart 				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6865db4fd95bSRandall Stewart 				*error = EINVAL;
6866db4fd95bSRandall Stewart 				return;
6867db4fd95bSRandall Stewart 			}
686835918f85SRandall Stewart 			in6_sin6_2_sin(&sin, sin6);
686935918f85SRandall Stewart 			addr_touse = (struct sockaddr *)&sin;
687035918f85SRandall Stewart 		}
6871d59107f7SMichael Tuexen #endif
687235918f85SRandall Stewart 	}
687335918f85SRandall Stewart #endif
6874ea5eba11SMichael Tuexen #ifdef INET
687535918f85SRandall Stewart 	if (sa->sa_family == AF_INET) {
687635918f85SRandall Stewart 		if (sa->sa_len != sizeof(struct sockaddr_in)) {
6877c4739e2fSRandall Stewart 			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
687835918f85SRandall Stewart 			*error = EINVAL;
687935918f85SRandall Stewart 			return;
688035918f85SRandall Stewart 		}
6881db4fd95bSRandall Stewart 		if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
6882db4fd95bSRandall Stewart 		    SCTP_IPV6_V6ONLY(inp)) {
6883db4fd95bSRandall Stewart 			/* can't bind v4 on PF_INET sockets */
6884c4739e2fSRandall Stewart 			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6885db4fd95bSRandall Stewart 			*error = EINVAL;
6886db4fd95bSRandall Stewart 			return;
6887db4fd95bSRandall Stewart 		}
688835918f85SRandall Stewart 	}
6889ea5eba11SMichael Tuexen #endif
689035918f85SRandall Stewart 	if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) {
689135918f85SRandall Stewart 		if (p == NULL) {
689235918f85SRandall Stewart 			/* Can't get proc for Net/Open BSD */
6893c4739e2fSRandall Stewart 			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
689435918f85SRandall Stewart 			*error = EINVAL;
689535918f85SRandall Stewart 			return;
689635918f85SRandall Stewart 		}
68971b649582SRandall Stewart 		*error = sctp_inpcb_bind(so, addr_touse, NULL, p);
689835918f85SRandall Stewart 		return;
689935918f85SRandall Stewart 	}
690035918f85SRandall Stewart 	/*
690135918f85SRandall Stewart 	 * No locks required here since bind and mgmt_ep_sa all do their own
690235918f85SRandall Stewart 	 * locking. If we do something for the FIX: below we may need to
690335918f85SRandall Stewart 	 * lock in that case.
690435918f85SRandall Stewart 	 */
690535918f85SRandall Stewart 	if (assoc_id == 0) {
690635918f85SRandall Stewart 		/* add the address */
690735918f85SRandall Stewart 		struct sctp_inpcb *lep;
690897c76f10SRandall Stewart 		struct sockaddr_in *lsin = (struct sockaddr_in *)addr_touse;
690935918f85SRandall Stewart 
691097c76f10SRandall Stewart 		/* validate the incoming port */
691197c76f10SRandall Stewart 		if ((lsin->sin_port != 0) &&
691297c76f10SRandall Stewart 		    (lsin->sin_port != inp->sctp_lport)) {
6913c4739e2fSRandall Stewart 			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
691497c76f10SRandall Stewart 			*error = EINVAL;
691597c76f10SRandall Stewart 			return;
691697c76f10SRandall Stewart 		} else {
691797c76f10SRandall Stewart 			/* user specified 0 port, set it to existing port */
691897c76f10SRandall Stewart 			lsin->sin_port = inp->sctp_lport;
691997c76f10SRandall Stewart 		}
692097c76f10SRandall Stewart 
692135918f85SRandall Stewart 		lep = sctp_pcb_findep(addr_touse, 1, 0, vrf_id);
692235918f85SRandall Stewart 		if (lep != NULL) {
692335918f85SRandall Stewart 			/*
692435918f85SRandall Stewart 			 * We must decrement the refcount since we have the
692535918f85SRandall Stewart 			 * ep already and are binding. No remove going on
692635918f85SRandall Stewart 			 * here.
692735918f85SRandall Stewart 			 */
69286d9e8f2bSRandall Stewart 			SCTP_INP_DECR_REF(lep);
692935918f85SRandall Stewart 		}
693035918f85SRandall Stewart 		if (lep == inp) {
693135918f85SRandall Stewart 			/* already bound to it.. ok */
693235918f85SRandall Stewart 			return;
693335918f85SRandall Stewart 		} else if (lep == NULL) {
693435918f85SRandall Stewart 			((struct sockaddr_in *)addr_touse)->sin_port = 0;
693535918f85SRandall Stewart 			*error = sctp_addr_mgmt_ep_sa(inp, addr_touse,
693635918f85SRandall Stewart 			    SCTP_ADD_IP_ADDRESS,
693780fefe0aSRandall Stewart 			    vrf_id, NULL);
693835918f85SRandall Stewart 		} else {
693935918f85SRandall Stewart 			*error = EADDRINUSE;
694035918f85SRandall Stewart 		}
694135918f85SRandall Stewart 		if (*error)
694235918f85SRandall Stewart 			return;
694335918f85SRandall Stewart 	} else {
694435918f85SRandall Stewart 		/*
694535918f85SRandall Stewart 		 * FIX: decide whether we allow assoc based bindx
694635918f85SRandall Stewart 		 */
694735918f85SRandall Stewart 	}
694835918f85SRandall Stewart }
694935918f85SRandall Stewart 
695035918f85SRandall Stewart /*
695135918f85SRandall Stewart  * sctp_bindx(DELETE) for one address.
695235918f85SRandall Stewart  * assumes all arguments are valid/checked by caller.
695335918f85SRandall Stewart  */
695435918f85SRandall Stewart void
69557215cc1bSMichael Tuexen sctp_bindx_delete_address(struct sctp_inpcb *inp,
695635918f85SRandall Stewart     struct sockaddr *sa, sctp_assoc_t assoc_id,
695735918f85SRandall Stewart     uint32_t vrf_id, int *error)
695835918f85SRandall Stewart {
695935918f85SRandall Stewart 	struct sockaddr *addr_touse;
6960d59107f7SMichael Tuexen #if defined(INET) && defined(INET6)
696135918f85SRandall Stewart 	struct sockaddr_in sin;
69625e2c2d87SRandall Stewart #endif
69635e2c2d87SRandall Stewart 
696435918f85SRandall Stewart 	/* see if we're bound all already! */
696535918f85SRandall Stewart 	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
6966c4739e2fSRandall Stewart 		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
696735918f85SRandall Stewart 		*error = EINVAL;
696835918f85SRandall Stewart 		return;
696935918f85SRandall Stewart 	}
697035918f85SRandall Stewart 	addr_touse = sa;
6971e0e00a4dSMichael Tuexen #ifdef INET6
697235918f85SRandall Stewart 	if (sa->sa_family == AF_INET6) {
6973d59107f7SMichael Tuexen #ifdef INET
697435918f85SRandall Stewart 		struct sockaddr_in6 *sin6;
6975d59107f7SMichael Tuexen #endif
6976d59107f7SMichael Tuexen 
697735918f85SRandall Stewart 		if (sa->sa_len != sizeof(struct sockaddr_in6)) {
6978c4739e2fSRandall Stewart 			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
697935918f85SRandall Stewart 			*error = EINVAL;
698035918f85SRandall Stewart 			return;
698135918f85SRandall Stewart 		}
6982db4fd95bSRandall Stewart 		if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
6983db4fd95bSRandall Stewart 			/* can only bind v6 on PF_INET6 sockets */
6984c4739e2fSRandall Stewart 			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6985db4fd95bSRandall Stewart 			*error = EINVAL;
6986db4fd95bSRandall Stewart 			return;
6987db4fd95bSRandall Stewart 		}
6988d59107f7SMichael Tuexen #ifdef INET
698935918f85SRandall Stewart 		sin6 = (struct sockaddr_in6 *)addr_touse;
699035918f85SRandall Stewart 		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
6991db4fd95bSRandall Stewart 			if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
6992db4fd95bSRandall Stewart 			    SCTP_IPV6_V6ONLY(inp)) {
6993db4fd95bSRandall Stewart 				/* can't bind mapped-v4 on PF_INET sockets */
6994c4739e2fSRandall Stewart 				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6995db4fd95bSRandall Stewart 				*error = EINVAL;
6996db4fd95bSRandall Stewart 				return;
6997db4fd95bSRandall Stewart 			}
699835918f85SRandall Stewart 			in6_sin6_2_sin(&sin, sin6);
699935918f85SRandall Stewart 			addr_touse = (struct sockaddr *)&sin;
700035918f85SRandall Stewart 		}
7001d59107f7SMichael Tuexen #endif
700235918f85SRandall Stewart 	}
700335918f85SRandall Stewart #endif
7004ea5eba11SMichael Tuexen #ifdef INET
700535918f85SRandall Stewart 	if (sa->sa_family == AF_INET) {
700635918f85SRandall Stewart 		if (sa->sa_len != sizeof(struct sockaddr_in)) {
7007c4739e2fSRandall Stewart 			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
700835918f85SRandall Stewart 			*error = EINVAL;
700935918f85SRandall Stewart 			return;
701035918f85SRandall Stewart 		}
7011db4fd95bSRandall Stewart 		if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
7012db4fd95bSRandall Stewart 		    SCTP_IPV6_V6ONLY(inp)) {
7013db4fd95bSRandall Stewart 			/* can't bind v4 on PF_INET sockets */
7014c4739e2fSRandall Stewart 			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
7015db4fd95bSRandall Stewart 			*error = EINVAL;
7016db4fd95bSRandall Stewart 			return;
7017db4fd95bSRandall Stewart 		}
701835918f85SRandall Stewart 	}
7019ea5eba11SMichael Tuexen #endif
702035918f85SRandall Stewart 	/*
702135918f85SRandall Stewart 	 * No lock required mgmt_ep_sa does its own locking. If the FIX:
702235918f85SRandall Stewart 	 * below is ever changed we may need to lock before calling
702335918f85SRandall Stewart 	 * association level binding.
702435918f85SRandall Stewart 	 */
702535918f85SRandall Stewart 	if (assoc_id == 0) {
702635918f85SRandall Stewart 		/* delete the address */
702735918f85SRandall Stewart 		*error = sctp_addr_mgmt_ep_sa(inp, addr_touse,
702835918f85SRandall Stewart 		    SCTP_DEL_IP_ADDRESS,
702980fefe0aSRandall Stewart 		    vrf_id, NULL);
703035918f85SRandall Stewart 	} else {
703135918f85SRandall Stewart 		/*
703235918f85SRandall Stewart 		 * FIX: decide whether we allow assoc based bindx
703335918f85SRandall Stewart 		 */
703435918f85SRandall Stewart 	}
703535918f85SRandall Stewart }
70361b649582SRandall Stewart 
70371b649582SRandall Stewart /*
70381b649582SRandall Stewart  * returns the valid local address count for an assoc, taking into account
70391b649582SRandall Stewart  * all scoping rules
70401b649582SRandall Stewart  */
70411b649582SRandall Stewart int
70421b649582SRandall Stewart sctp_local_addr_count(struct sctp_tcb *stcb)
70431b649582SRandall Stewart {
7044b54ddf22SMichael Tuexen 	int loopback_scope;
7045b54ddf22SMichael Tuexen #if defined(INET)
7046b54ddf22SMichael Tuexen 	int ipv4_local_scope, ipv4_addr_legal;
7047b54ddf22SMichael Tuexen #endif
7048b54ddf22SMichael Tuexen #if defined (INET6)
7049b54ddf22SMichael Tuexen 	int local_scope, site_scope, ipv6_addr_legal;
7050b54ddf22SMichael Tuexen #endif
70511b649582SRandall Stewart 	struct sctp_vrf *vrf;
70521b649582SRandall Stewart 	struct sctp_ifn *sctp_ifn;
70531b649582SRandall Stewart 	struct sctp_ifa *sctp_ifa;
70541b649582SRandall Stewart 	int count = 0;
70551b649582SRandall Stewart 
70561b649582SRandall Stewart 	/* Turn on all the appropriate scopes */
7057a1cb341bSMichael Tuexen 	loopback_scope = stcb->asoc.scope.loopback_scope;
7058b54ddf22SMichael Tuexen #if defined(INET)
7059a1cb341bSMichael Tuexen 	ipv4_local_scope = stcb->asoc.scope.ipv4_local_scope;
7060b54ddf22SMichael Tuexen 	ipv4_addr_legal = stcb->asoc.scope.ipv4_addr_legal;
7061b54ddf22SMichael Tuexen #endif
7062b54ddf22SMichael Tuexen #if defined(INET6)
7063a1cb341bSMichael Tuexen 	local_scope = stcb->asoc.scope.local_scope;
7064a1cb341bSMichael Tuexen 	site_scope = stcb->asoc.scope.site_scope;
7065a1cb341bSMichael Tuexen 	ipv6_addr_legal = stcb->asoc.scope.ipv6_addr_legal;
7066b54ddf22SMichael Tuexen #endif
7067c99efcf6SRandall Stewart 	SCTP_IPI_ADDR_RLOCK();
70681b649582SRandall Stewart 	vrf = sctp_find_vrf(stcb->asoc.vrf_id);
70691b649582SRandall Stewart 	if (vrf == NULL) {
70701b649582SRandall Stewart 		/* no vrf, no addresses */
7071c99efcf6SRandall Stewart 		SCTP_IPI_ADDR_RUNLOCK();
70721b649582SRandall Stewart 		return (0);
70731b649582SRandall Stewart 	}
70740053ed28SMichael Tuexen 
70751b649582SRandall Stewart 	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
70761b649582SRandall Stewart 		/*
70771b649582SRandall Stewart 		 * bound all case: go through all ifns on the vrf
70781b649582SRandall Stewart 		 */
70791b649582SRandall Stewart 		LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
70801b649582SRandall Stewart 			if ((loopback_scope == 0) &&
70811b649582SRandall Stewart 			    SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
70821b649582SRandall Stewart 				continue;
70831b649582SRandall Stewart 			}
70841b649582SRandall Stewart 			LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
70851b649582SRandall Stewart 				if (sctp_is_addr_restricted(stcb, sctp_ifa))
70861b649582SRandall Stewart 					continue;
70875e2c2d87SRandall Stewart 				switch (sctp_ifa->address.sa.sa_family) {
7088ea5eba11SMichael Tuexen #ifdef INET
70895e2c2d87SRandall Stewart 				case AF_INET:
70905e2c2d87SRandall Stewart 					if (ipv4_addr_legal) {
70911b649582SRandall Stewart 						struct sockaddr_in *sin;
70921b649582SRandall Stewart 
709324aaac8dSMichael Tuexen 						sin = &sctp_ifa->address.sin;
70941b649582SRandall Stewart 						if (sin->sin_addr.s_addr == 0) {
7095b7b84c0eSMichael Tuexen 							/*
7096b7b84c0eSMichael Tuexen 							 * skip unspecified
7097b7b84c0eSMichael Tuexen 							 * addrs
7098b7b84c0eSMichael Tuexen 							 */
70991b649582SRandall Stewart 							continue;
71001b649582SRandall Stewart 						}
71016ba22f19SMichael Tuexen 						if (prison_check_ip4(stcb->sctp_ep->ip_inp.inp.inp_cred,
71026ba22f19SMichael Tuexen 						    &sin->sin_addr) != 0) {
71036ba22f19SMichael Tuexen 							continue;
71046ba22f19SMichael Tuexen 						}
71051b649582SRandall Stewart 						if ((ipv4_local_scope == 0) &&
71061b649582SRandall Stewart 						    (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) {
71071b649582SRandall Stewart 							continue;
71081b649582SRandall Stewart 						}
71091b649582SRandall Stewart 						/* count this one */
71101b649582SRandall Stewart 						count++;
71115e2c2d87SRandall Stewart 					} else {
71125e2c2d87SRandall Stewart 						continue;
71135e2c2d87SRandall Stewart 					}
71145e2c2d87SRandall Stewart 					break;
7115ea5eba11SMichael Tuexen #endif
71165e2c2d87SRandall Stewart #ifdef INET6
71175e2c2d87SRandall Stewart 				case AF_INET6:
71185e2c2d87SRandall Stewart 					if (ipv6_addr_legal) {
71191b649582SRandall Stewart 						struct sockaddr_in6 *sin6;
71201b649582SRandall Stewart 
712124aaac8dSMichael Tuexen 						sin6 = &sctp_ifa->address.sin6;
71221b649582SRandall Stewart 						if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
71231b649582SRandall Stewart 							continue;
71241b649582SRandall Stewart 						}
71256ba22f19SMichael Tuexen 						if (prison_check_ip6(stcb->sctp_ep->ip_inp.inp.inp_cred,
71266ba22f19SMichael Tuexen 						    &sin6->sin6_addr) != 0) {
71276ba22f19SMichael Tuexen 							continue;
71286ba22f19SMichael Tuexen 						}
71291b649582SRandall Stewart 						if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
71301b649582SRandall Stewart 							if (local_scope == 0)
71311b649582SRandall Stewart 								continue;
71321b649582SRandall Stewart 							if (sin6->sin6_scope_id == 0) {
71331b649582SRandall Stewart 								if (sa6_recoverscope(sin6) != 0)
71341b649582SRandall Stewart 									/*
71355e2c2d87SRandall Stewart 									 *
71365e2c2d87SRandall Stewart 									 * bad
71375b495f17SMichael Tuexen 									 * link
71385e2c2d87SRandall Stewart 									 *
71395b495f17SMichael Tuexen 									 * local
71405e2c2d87SRandall Stewart 									 *
71415b495f17SMichael Tuexen 									 * address
71425b495f17SMichael Tuexen 									 */
71431b649582SRandall Stewart 									continue;
71441b649582SRandall Stewart 							}
71451b649582SRandall Stewart 						}
71461b649582SRandall Stewart 						if ((site_scope == 0) &&
71471b649582SRandall Stewart 						    (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) {
71481b649582SRandall Stewart 							continue;
71491b649582SRandall Stewart 						}
71501b649582SRandall Stewart 						/* count this one */
71511b649582SRandall Stewart 						count++;
71521b649582SRandall Stewart 					}
71535e2c2d87SRandall Stewart 					break;
71545e2c2d87SRandall Stewart #endif
71555e2c2d87SRandall Stewart 				default:
71565e2c2d87SRandall Stewart 					/* TSNH */
71575e2c2d87SRandall Stewart 					break;
71585e2c2d87SRandall Stewart 				}
71591b649582SRandall Stewart 			}
71601b649582SRandall Stewart 		}
71611b649582SRandall Stewart 	} else {
71621b649582SRandall Stewart 		/*
71631b649582SRandall Stewart 		 * subset bound case
71641b649582SRandall Stewart 		 */
71651b649582SRandall Stewart 		struct sctp_laddr *laddr;
71661b649582SRandall Stewart 
71671b649582SRandall Stewart 		LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list,
71681b649582SRandall Stewart 		    sctp_nxt_addr) {
71691b649582SRandall Stewart 			if (sctp_is_addr_restricted(stcb, laddr->ifa)) {
71701b649582SRandall Stewart 				continue;
71711b649582SRandall Stewart 			}
71721b649582SRandall Stewart 			/* count this one */
71731b649582SRandall Stewart 			count++;
71741b649582SRandall Stewart 		}
71751b649582SRandall Stewart 	}
7176c99efcf6SRandall Stewart 	SCTP_IPI_ADDR_RUNLOCK();
71771b649582SRandall Stewart 	return (count);
71781b649582SRandall Stewart }
7179c4739e2fSRandall Stewart 
7180c4739e2fSRandall Stewart #if defined(SCTP_LOCAL_TRACE_BUF)
7181c4739e2fSRandall Stewart 
7182c4739e2fSRandall Stewart void
7183b27a6b7dSRandall 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)
7184c4739e2fSRandall Stewart {
7185b27a6b7dSRandall Stewart 	uint32_t saveindex, newindex;
7186c4739e2fSRandall Stewart 
7187c4739e2fSRandall Stewart 	do {
7188b3f1ea41SRandall Stewart 		saveindex = SCTP_BASE_SYSCTL(sctp_log).index;
7189c4739e2fSRandall Stewart 		if (saveindex >= SCTP_MAX_LOGGING_SIZE) {
7190c4739e2fSRandall Stewart 			newindex = 1;
7191c4739e2fSRandall Stewart 		} else {
7192c4739e2fSRandall Stewart 			newindex = saveindex + 1;
7193c4739e2fSRandall Stewart 		}
7194b3f1ea41SRandall Stewart 	} while (atomic_cmpset_int(&SCTP_BASE_SYSCTL(sctp_log).index, saveindex, newindex) == 0);
7195c4739e2fSRandall Stewart 	if (saveindex >= SCTP_MAX_LOGGING_SIZE) {
7196c4739e2fSRandall Stewart 		saveindex = 0;
7197c4739e2fSRandall Stewart 	}
7198b3f1ea41SRandall Stewart 	SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].timestamp = SCTP_GET_CYCLECOUNT;
7199b3f1ea41SRandall Stewart 	SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].subsys = subsys;
7200b3f1ea41SRandall Stewart 	SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[0] = a;
7201b3f1ea41SRandall Stewart 	SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[1] = b;
7202b3f1ea41SRandall Stewart 	SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[2] = c;
7203b3f1ea41SRandall Stewart 	SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[3] = d;
7204b3f1ea41SRandall Stewart 	SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[4] = e;
7205b3f1ea41SRandall Stewart 	SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[5] = f;
7206c4739e2fSRandall Stewart }
7207c4739e2fSRandall Stewart 
7208c4739e2fSRandall Stewart #endif
7209a99b6783SRandall Stewart static void
72107cca1775SRandall Stewart sctp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *inp,
721181d3ec17SBryan Venteicher     const struct sockaddr *sa SCTP_UNUSED, void *ctx SCTP_UNUSED)
7212a99b6783SRandall Stewart {
7213a99b6783SRandall Stewart 	struct ip *iph;
72143a51a264SMichael Tuexen #ifdef INET6
72153a51a264SMichael Tuexen 	struct ip6_hdr *ip6;
72163a51a264SMichael Tuexen #endif
7217a99b6783SRandall Stewart 	struct mbuf *sp, *last;
7218a99b6783SRandall Stewart 	struct udphdr *uhdr;
7219285052f0SMichael Tuexen 	uint16_t port;
7220a99b6783SRandall Stewart 
7221a99b6783SRandall Stewart 	if ((m->m_flags & M_PKTHDR) == 0) {
7222a99b6783SRandall Stewart 		/* Can't handle one that is not a pkt hdr */
7223a99b6783SRandall Stewart 		goto out;
7224a99b6783SRandall Stewart 	}
7225285052f0SMichael Tuexen 	/* Pull the src port */
7226a99b6783SRandall Stewart 	iph = mtod(m, struct ip *);
7227a99b6783SRandall Stewart 	uhdr = (struct udphdr *)((caddr_t)iph + off);
7228a99b6783SRandall Stewart 	port = uhdr->uh_sport;
7229285052f0SMichael Tuexen 	/*
7230285052f0SMichael Tuexen 	 * Split out the mbuf chain. Leave the IP header in m, place the
7231285052f0SMichael Tuexen 	 * rest in the sp.
7232285052f0SMichael Tuexen 	 */
7233eb1b1807SGleb Smirnoff 	sp = m_split(m, off, M_NOWAIT);
7234a99b6783SRandall Stewart 	if (sp == NULL) {
7235a99b6783SRandall Stewart 		/* Gak, drop packet, we can't do a split */
7236a99b6783SRandall Stewart 		goto out;
7237a99b6783SRandall Stewart 	}
7238285052f0SMichael Tuexen 	if (sp->m_pkthdr.len < sizeof(struct udphdr) + sizeof(struct sctphdr)) {
7239285052f0SMichael Tuexen 		/* Gak, packet can't have an SCTP header in it - too small */
7240a99b6783SRandall Stewart 		m_freem(sp);
7241a99b6783SRandall Stewart 		goto out;
7242a99b6783SRandall Stewart 	}
7243285052f0SMichael Tuexen 	/* Now pull up the UDP header and SCTP header together */
7244285052f0SMichael Tuexen 	sp = m_pullup(sp, sizeof(struct udphdr) + sizeof(struct sctphdr));
7245a99b6783SRandall Stewart 	if (sp == NULL) {
7246a99b6783SRandall Stewart 		/* Gak pullup failed */
7247a99b6783SRandall Stewart 		goto out;
7248a99b6783SRandall Stewart 	}
7249285052f0SMichael Tuexen 	/* Trim out the UDP header */
7250a99b6783SRandall Stewart 	m_adj(sp, sizeof(struct udphdr));
7251a99b6783SRandall Stewart 
7252a99b6783SRandall Stewart 	/* Now reconstruct the mbuf chain */
7253285052f0SMichael Tuexen 	for (last = m; last->m_next; last = last->m_next);
7254a99b6783SRandall Stewart 	last->m_next = sp;
7255a99b6783SRandall Stewart 	m->m_pkthdr.len += sp->m_pkthdr.len;
725652f175beSMichael Tuexen 	/*
725752f175beSMichael Tuexen 	 * The CSUM_DATA_VALID flags indicates that the HW checked the UDP
725852f175beSMichael Tuexen 	 * checksum and it was valid. Since CSUM_DATA_VALID ==
725952f175beSMichael Tuexen 	 * CSUM_SCTP_VALID this would imply that the HW also verified the
726052f175beSMichael Tuexen 	 * SCTP checksum. Therefore, clear the bit.
726152f175beSMichael Tuexen 	 */
726252f175beSMichael Tuexen 	SCTPDBG(SCTP_DEBUG_CRCOFFLOAD,
726352f175beSMichael Tuexen 	    "sctp_recv_udp_tunneled_packet(): Packet of length %d received on %s with csum_flags 0x%b.\n",
726452f175beSMichael Tuexen 	    m->m_pkthdr.len,
726552f175beSMichael Tuexen 	    if_name(m->m_pkthdr.rcvif),
726652f175beSMichael Tuexen 	    (int)m->m_pkthdr.csum_flags, CSUM_BITS);
726752f175beSMichael Tuexen 	m->m_pkthdr.csum_flags &= ~CSUM_DATA_VALID;
7268a99b6783SRandall Stewart 	iph = mtod(m, struct ip *);
7269a99b6783SRandall Stewart 	switch (iph->ip_v) {
7270e6194c2eSMichael Tuexen #ifdef INET
7271a99b6783SRandall Stewart 	case IPVERSION:
727209c1c856SMichael Tuexen 		iph->ip_len = htons(ntohs(iph->ip_len) - sizeof(struct udphdr));
7273a99b6783SRandall Stewart 		sctp_input_with_port(m, off, port);
7274a99b6783SRandall Stewart 		break;
7275e6194c2eSMichael Tuexen #endif
7276a99b6783SRandall Stewart #ifdef INET6
7277a99b6783SRandall Stewart 	case IPV6_VERSION >> 4:
72783a51a264SMichael Tuexen 		ip6 = mtod(m, struct ip6_hdr *);
72793a51a264SMichael Tuexen 		ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - sizeof(struct udphdr));
72803a51a264SMichael Tuexen 		sctp6_input_with_port(&m, &off, port);
7281a99b6783SRandall Stewart 		break;
7282a99b6783SRandall Stewart #endif
7283a99b6783SRandall Stewart 	default:
7284285052f0SMichael Tuexen 		goto out;
7285a99b6783SRandall Stewart 		break;
7286a99b6783SRandall Stewart 	}
7287a99b6783SRandall Stewart 	return;
7288a99b6783SRandall Stewart out:
7289a99b6783SRandall Stewart 	m_freem(m);
7290a99b6783SRandall Stewart }
7291c54a18d2SRandall Stewart 
7292fd7af143SMichael Tuexen #ifdef INET
7293fd7af143SMichael Tuexen static void
7294fd7af143SMichael Tuexen sctp_recv_icmp_tunneled_packet(int cmd, struct sockaddr *sa, void *vip, void *ctx SCTP_UNUSED)
7295fd7af143SMichael Tuexen {
7296fd7af143SMichael Tuexen 	struct ip *outer_ip, *inner_ip;
7297fd7af143SMichael Tuexen 	struct sctphdr *sh;
7298fd7af143SMichael Tuexen 	struct icmp *icmp;
7299fd7af143SMichael Tuexen 	struct udphdr *udp;
7300fd7af143SMichael Tuexen 	struct sctp_inpcb *inp;
7301fd7af143SMichael Tuexen 	struct sctp_tcb *stcb;
7302fd7af143SMichael Tuexen 	struct sctp_nets *net;
7303fd7af143SMichael Tuexen 	struct sctp_init_chunk *ch;
7304fd7af143SMichael Tuexen 	struct sockaddr_in src, dst;
7305fd7af143SMichael Tuexen 	uint8_t type, code;
7306fd7af143SMichael Tuexen 
7307fd7af143SMichael Tuexen 	inner_ip = (struct ip *)vip;
7308fd7af143SMichael Tuexen 	icmp = (struct icmp *)((caddr_t)inner_ip -
7309fd7af143SMichael Tuexen 	    (sizeof(struct icmp) - sizeof(struct ip)));
7310fd7af143SMichael Tuexen 	outer_ip = (struct ip *)((caddr_t)icmp - sizeof(struct ip));
7311fd7af143SMichael Tuexen 	if (ntohs(outer_ip->ip_len) <
7312fd7af143SMichael Tuexen 	    sizeof(struct ip) + 8 + (inner_ip->ip_hl << 2) + sizeof(struct udphdr) + 8) {
7313fd7af143SMichael Tuexen 		return;
7314fd7af143SMichael Tuexen 	}
7315fd7af143SMichael Tuexen 	udp = (struct udphdr *)((caddr_t)inner_ip + (inner_ip->ip_hl << 2));
7316fd7af143SMichael Tuexen 	sh = (struct sctphdr *)(udp + 1);
7317fd7af143SMichael Tuexen 	memset(&src, 0, sizeof(struct sockaddr_in));
7318fd7af143SMichael Tuexen 	src.sin_family = AF_INET;
7319fd7af143SMichael Tuexen 	src.sin_len = sizeof(struct sockaddr_in);
7320fd7af143SMichael Tuexen 	src.sin_port = sh->src_port;
7321fd7af143SMichael Tuexen 	src.sin_addr = inner_ip->ip_src;
7322fd7af143SMichael Tuexen 	memset(&dst, 0, sizeof(struct sockaddr_in));
7323fd7af143SMichael Tuexen 	dst.sin_family = AF_INET;
7324fd7af143SMichael Tuexen 	dst.sin_len = sizeof(struct sockaddr_in);
7325fd7af143SMichael Tuexen 	dst.sin_port = sh->dest_port;
7326fd7af143SMichael Tuexen 	dst.sin_addr = inner_ip->ip_dst;
7327fd7af143SMichael Tuexen 	/*
7328fd7af143SMichael Tuexen 	 * 'dst' holds the dest of the packet that failed to be sent. 'src'
7329fd7af143SMichael Tuexen 	 * holds our local endpoint address. Thus we reverse the dst and the
7330fd7af143SMichael Tuexen 	 * src in the lookup.
7331fd7af143SMichael Tuexen 	 */
7332fd7af143SMichael Tuexen 	inp = NULL;
7333fd7af143SMichael Tuexen 	net = NULL;
7334fd7af143SMichael Tuexen 	stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst,
7335fd7af143SMichael Tuexen 	    (struct sockaddr *)&src,
7336fd7af143SMichael Tuexen 	    &inp, &net, 1,
7337fd7af143SMichael Tuexen 	    SCTP_DEFAULT_VRFID);
7338fd7af143SMichael Tuexen 	if ((stcb != NULL) &&
7339fd7af143SMichael Tuexen 	    (net != NULL) &&
734055b8cd93SMichael Tuexen 	    (inp != NULL)) {
7341fd7af143SMichael Tuexen 		/* Check the UDP port numbers */
7342fd7af143SMichael Tuexen 		if ((udp->uh_dport != net->port) ||
7343fd7af143SMichael Tuexen 		    (udp->uh_sport != htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)))) {
7344fd7af143SMichael Tuexen 			SCTP_TCB_UNLOCK(stcb);
7345fd7af143SMichael Tuexen 			return;
7346fd7af143SMichael Tuexen 		}
7347fd7af143SMichael Tuexen 		/* Check the verification tag */
7348fd7af143SMichael Tuexen 		if (ntohl(sh->v_tag) != 0) {
7349fd7af143SMichael Tuexen 			/*
7350fd7af143SMichael Tuexen 			 * This must be the verification tag used for
7351fd7af143SMichael Tuexen 			 * sending out packets. We don't consider packets
7352fd7af143SMichael Tuexen 			 * reflecting the verification tag.
7353fd7af143SMichael Tuexen 			 */
7354fd7af143SMichael Tuexen 			if (ntohl(sh->v_tag) != stcb->asoc.peer_vtag) {
7355fd7af143SMichael Tuexen 				SCTP_TCB_UNLOCK(stcb);
7356fd7af143SMichael Tuexen 				return;
7357fd7af143SMichael Tuexen 			}
7358fd7af143SMichael Tuexen 		} else {
7359fd7af143SMichael Tuexen 			if (ntohs(outer_ip->ip_len) >=
7360fd7af143SMichael Tuexen 			    sizeof(struct ip) +
7361fd7af143SMichael Tuexen 			    8 + (inner_ip->ip_hl << 2) + 8 + 20) {
7362fd7af143SMichael Tuexen 				/*
7363fd7af143SMichael Tuexen 				 * In this case we can check if we got an
7364fd7af143SMichael Tuexen 				 * INIT chunk and if the initiate tag
7365fd7af143SMichael Tuexen 				 * matches.
7366fd7af143SMichael Tuexen 				 */
7367fd7af143SMichael Tuexen 				ch = (struct sctp_init_chunk *)(sh + 1);
7368fd7af143SMichael Tuexen 				if ((ch->ch.chunk_type != SCTP_INITIATION) ||
7369fd7af143SMichael Tuexen 				    (ntohl(ch->init.initiate_tag) != stcb->asoc.my_vtag)) {
7370fd7af143SMichael Tuexen 					SCTP_TCB_UNLOCK(stcb);
7371fd7af143SMichael Tuexen 					return;
7372fd7af143SMichael Tuexen 				}
7373fd7af143SMichael Tuexen 			} else {
7374fd7af143SMichael Tuexen 				SCTP_TCB_UNLOCK(stcb);
7375fd7af143SMichael Tuexen 				return;
7376fd7af143SMichael Tuexen 			}
7377fd7af143SMichael Tuexen 		}
7378fd7af143SMichael Tuexen 		type = icmp->icmp_type;
7379fd7af143SMichael Tuexen 		code = icmp->icmp_code;
73803c3f9e2aSMichael Tuexen 		if ((type == ICMP_UNREACH) &&
73813c3f9e2aSMichael Tuexen 		    (code == ICMP_UNREACH_PORT)) {
7382fd7af143SMichael Tuexen 			code = ICMP_UNREACH_PROTOCOL;
7383fd7af143SMichael Tuexen 		}
7384fd7af143SMichael Tuexen 		sctp_notify(inp, stcb, net, type, code,
7385fd7af143SMichael Tuexen 		    ntohs(inner_ip->ip_len),
73866ebfa5eeSMichael Tuexen 		    (uint32_t)ntohs(icmp->icmp_nextmtu));
7387fd7af143SMichael Tuexen 	} else {
7388fd7af143SMichael Tuexen 		if ((stcb == NULL) && (inp != NULL)) {
7389fd7af143SMichael Tuexen 			/* reduce ref-count */
7390fd7af143SMichael Tuexen 			SCTP_INP_WLOCK(inp);
7391fd7af143SMichael Tuexen 			SCTP_INP_DECR_REF(inp);
7392fd7af143SMichael Tuexen 			SCTP_INP_WUNLOCK(inp);
7393fd7af143SMichael Tuexen 		}
7394fd7af143SMichael Tuexen 		if (stcb) {
7395fd7af143SMichael Tuexen 			SCTP_TCB_UNLOCK(stcb);
7396fd7af143SMichael Tuexen 		}
7397fd7af143SMichael Tuexen 	}
7398fd7af143SMichael Tuexen 	return;
7399fd7af143SMichael Tuexen }
7400fd7af143SMichael Tuexen #endif
7401fd7af143SMichael Tuexen 
7402fd7af143SMichael Tuexen #ifdef INET6
7403fd7af143SMichael Tuexen static void
7404fd7af143SMichael Tuexen sctp_recv_icmp6_tunneled_packet(int cmd, struct sockaddr *sa, void *d, void *ctx SCTP_UNUSED)
7405fd7af143SMichael Tuexen {
7406fd7af143SMichael Tuexen 	struct ip6ctlparam *ip6cp;
7407fd7af143SMichael Tuexen 	struct sctp_inpcb *inp;
7408fd7af143SMichael Tuexen 	struct sctp_tcb *stcb;
7409fd7af143SMichael Tuexen 	struct sctp_nets *net;
7410fd7af143SMichael Tuexen 	struct sctphdr sh;
7411fd7af143SMichael Tuexen 	struct udphdr udp;
7412fd7af143SMichael Tuexen 	struct sockaddr_in6 src, dst;
7413fd7af143SMichael Tuexen 	uint8_t type, code;
7414fd7af143SMichael Tuexen 
7415fd7af143SMichael Tuexen 	ip6cp = (struct ip6ctlparam *)d;
7416fd7af143SMichael Tuexen 	/*
7417fd7af143SMichael Tuexen 	 * XXX: We assume that when IPV6 is non NULL, M and OFF are valid.
7418fd7af143SMichael Tuexen 	 */
7419fd7af143SMichael Tuexen 	if (ip6cp->ip6c_m == NULL) {
7420fd7af143SMichael Tuexen 		return;
7421fd7af143SMichael Tuexen 	}
7422fd7af143SMichael Tuexen 	/*
7423fd7af143SMichael Tuexen 	 * Check if we can safely examine the ports and the verification tag
7424fd7af143SMichael Tuexen 	 * of the SCTP common header.
7425fd7af143SMichael Tuexen 	 */
7426fd7af143SMichael Tuexen 	if (ip6cp->ip6c_m->m_pkthdr.len <
7427fd7af143SMichael Tuexen 	    ip6cp->ip6c_off + sizeof(struct udphdr) + offsetof(struct sctphdr, checksum)) {
7428fd7af143SMichael Tuexen 		return;
7429fd7af143SMichael Tuexen 	}
7430fd7af143SMichael Tuexen 	/* Copy out the UDP header. */
7431fd7af143SMichael Tuexen 	memset(&udp, 0, sizeof(struct udphdr));
7432fd7af143SMichael Tuexen 	m_copydata(ip6cp->ip6c_m,
7433fd7af143SMichael Tuexen 	    ip6cp->ip6c_off,
7434fd7af143SMichael Tuexen 	    sizeof(struct udphdr),
7435fd7af143SMichael Tuexen 	    (caddr_t)&udp);
7436fd7af143SMichael Tuexen 	/* Copy out the port numbers and the verification tag. */
7437fd7af143SMichael Tuexen 	memset(&sh, 0, sizeof(struct sctphdr));
7438fd7af143SMichael Tuexen 	m_copydata(ip6cp->ip6c_m,
7439fd7af143SMichael Tuexen 	    ip6cp->ip6c_off + sizeof(struct udphdr),
7440fd7af143SMichael Tuexen 	    sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t),
7441fd7af143SMichael Tuexen 	    (caddr_t)&sh);
7442fd7af143SMichael Tuexen 	memset(&src, 0, sizeof(struct sockaddr_in6));
7443fd7af143SMichael Tuexen 	src.sin6_family = AF_INET6;
7444fd7af143SMichael Tuexen 	src.sin6_len = sizeof(struct sockaddr_in6);
7445fd7af143SMichael Tuexen 	src.sin6_port = sh.src_port;
7446fd7af143SMichael Tuexen 	src.sin6_addr = ip6cp->ip6c_ip6->ip6_src;
7447fd7af143SMichael Tuexen 	if (in6_setscope(&src.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) {
7448fd7af143SMichael Tuexen 		return;
7449fd7af143SMichael Tuexen 	}
7450fd7af143SMichael Tuexen 	memset(&dst, 0, sizeof(struct sockaddr_in6));
7451fd7af143SMichael Tuexen 	dst.sin6_family = AF_INET6;
7452fd7af143SMichael Tuexen 	dst.sin6_len = sizeof(struct sockaddr_in6);
7453fd7af143SMichael Tuexen 	dst.sin6_port = sh.dest_port;
7454fd7af143SMichael Tuexen 	dst.sin6_addr = ip6cp->ip6c_ip6->ip6_dst;
7455fd7af143SMichael Tuexen 	if (in6_setscope(&dst.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) {
7456fd7af143SMichael Tuexen 		return;
7457fd7af143SMichael Tuexen 	}
7458fd7af143SMichael Tuexen 	inp = NULL;
7459fd7af143SMichael Tuexen 	net = NULL;
7460fd7af143SMichael Tuexen 	stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst,
7461fd7af143SMichael Tuexen 	    (struct sockaddr *)&src,
7462fd7af143SMichael Tuexen 	    &inp, &net, 1, SCTP_DEFAULT_VRFID);
7463fd7af143SMichael Tuexen 	if ((stcb != NULL) &&
7464fd7af143SMichael Tuexen 	    (net != NULL) &&
746555b8cd93SMichael Tuexen 	    (inp != NULL)) {
7466fd7af143SMichael Tuexen 		/* Check the UDP port numbers */
7467fd7af143SMichael Tuexen 		if ((udp.uh_dport != net->port) ||
7468fd7af143SMichael Tuexen 		    (udp.uh_sport != htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)))) {
7469fd7af143SMichael Tuexen 			SCTP_TCB_UNLOCK(stcb);
7470fd7af143SMichael Tuexen 			return;
7471fd7af143SMichael Tuexen 		}
7472fd7af143SMichael Tuexen 		/* Check the verification tag */
7473fd7af143SMichael Tuexen 		if (ntohl(sh.v_tag) != 0) {
7474fd7af143SMichael Tuexen 			/*
7475fd7af143SMichael Tuexen 			 * This must be the verification tag used for
7476fd7af143SMichael Tuexen 			 * sending out packets. We don't consider packets
7477fd7af143SMichael Tuexen 			 * reflecting the verification tag.
7478fd7af143SMichael Tuexen 			 */
7479fd7af143SMichael Tuexen 			if (ntohl(sh.v_tag) != stcb->asoc.peer_vtag) {
7480fd7af143SMichael Tuexen 				SCTP_TCB_UNLOCK(stcb);
7481fd7af143SMichael Tuexen 				return;
7482fd7af143SMichael Tuexen 			}
7483fd7af143SMichael Tuexen 		} else {
7484fd7af143SMichael Tuexen 			if (ip6cp->ip6c_m->m_pkthdr.len >=
7485fd7af143SMichael Tuexen 			    ip6cp->ip6c_off + sizeof(struct udphdr) +
7486fd7af143SMichael Tuexen 			    sizeof(struct sctphdr) +
7487fd7af143SMichael Tuexen 			    sizeof(struct sctp_chunkhdr) +
7488fd7af143SMichael Tuexen 			    offsetof(struct sctp_init, a_rwnd)) {
7489fd7af143SMichael Tuexen 				/*
7490fd7af143SMichael Tuexen 				 * In this case we can check if we got an
7491fd7af143SMichael Tuexen 				 * INIT chunk and if the initiate tag
7492fd7af143SMichael Tuexen 				 * matches.
7493fd7af143SMichael Tuexen 				 */
7494fd7af143SMichael Tuexen 				uint32_t initiate_tag;
7495fd7af143SMichael Tuexen 				uint8_t chunk_type;
7496fd7af143SMichael Tuexen 
7497fd7af143SMichael Tuexen 				m_copydata(ip6cp->ip6c_m,
7498fd7af143SMichael Tuexen 				    ip6cp->ip6c_off +
7499fd7af143SMichael Tuexen 				    sizeof(struct udphdr) +
7500fd7af143SMichael Tuexen 				    sizeof(struct sctphdr),
7501fd7af143SMichael Tuexen 				    sizeof(uint8_t),
7502fd7af143SMichael Tuexen 				    (caddr_t)&chunk_type);
7503fd7af143SMichael Tuexen 				m_copydata(ip6cp->ip6c_m,
7504fd7af143SMichael Tuexen 				    ip6cp->ip6c_off +
7505fd7af143SMichael Tuexen 				    sizeof(struct udphdr) +
7506fd7af143SMichael Tuexen 				    sizeof(struct sctphdr) +
7507fd7af143SMichael Tuexen 				    sizeof(struct sctp_chunkhdr),
7508fd7af143SMichael Tuexen 				    sizeof(uint32_t),
7509fd7af143SMichael Tuexen 				    (caddr_t)&initiate_tag);
7510fd7af143SMichael Tuexen 				if ((chunk_type != SCTP_INITIATION) ||
7511fd7af143SMichael Tuexen 				    (ntohl(initiate_tag) != stcb->asoc.my_vtag)) {
7512fd7af143SMichael Tuexen 					SCTP_TCB_UNLOCK(stcb);
7513fd7af143SMichael Tuexen 					return;
7514fd7af143SMichael Tuexen 				}
7515fd7af143SMichael Tuexen 			} else {
7516fd7af143SMichael Tuexen 				SCTP_TCB_UNLOCK(stcb);
7517fd7af143SMichael Tuexen 				return;
7518fd7af143SMichael Tuexen 			}
7519fd7af143SMichael Tuexen 		}
7520fd7af143SMichael Tuexen 		type = ip6cp->ip6c_icmp6->icmp6_type;
7521fd7af143SMichael Tuexen 		code = ip6cp->ip6c_icmp6->icmp6_code;
7522fd7af143SMichael Tuexen 		if ((type == ICMP6_DST_UNREACH) &&
7523fd7af143SMichael Tuexen 		    (code == ICMP6_DST_UNREACH_NOPORT)) {
7524fd7af143SMichael Tuexen 			type = ICMP6_PARAM_PROB;
7525fd7af143SMichael Tuexen 			code = ICMP6_PARAMPROB_NEXTHEADER;
7526fd7af143SMichael Tuexen 		}
7527fd7af143SMichael Tuexen 		sctp6_notify(inp, stcb, net, type, code,
75286ebfa5eeSMichael Tuexen 		    ntohl(ip6cp->ip6c_icmp6->icmp6_mtu));
7529fd7af143SMichael Tuexen 	} else {
7530fd7af143SMichael Tuexen 		if ((stcb == NULL) && (inp != NULL)) {
7531fd7af143SMichael Tuexen 			/* reduce inp's ref-count */
7532fd7af143SMichael Tuexen 			SCTP_INP_WLOCK(inp);
7533fd7af143SMichael Tuexen 			SCTP_INP_DECR_REF(inp);
7534fd7af143SMichael Tuexen 			SCTP_INP_WUNLOCK(inp);
7535fd7af143SMichael Tuexen 		}
7536fd7af143SMichael Tuexen 		if (stcb) {
7537fd7af143SMichael Tuexen 			SCTP_TCB_UNLOCK(stcb);
7538fd7af143SMichael Tuexen 		}
7539fd7af143SMichael Tuexen 	}
7540fd7af143SMichael Tuexen }
7541fd7af143SMichael Tuexen #endif
7542fd7af143SMichael Tuexen 
7543c54a18d2SRandall Stewart void
7544c54a18d2SRandall Stewart sctp_over_udp_stop(void)
7545c54a18d2SRandall Stewart {
7546a99b6783SRandall Stewart 	/*
7547a99b6783SRandall Stewart 	 * This function assumes sysctl caller holds sctp_sysctl_info_lock()
7548a99b6783SRandall Stewart 	 * for writting!
7549a99b6783SRandall Stewart 	 */
75503a51a264SMichael Tuexen #ifdef INET
75513a51a264SMichael Tuexen 	if (SCTP_BASE_INFO(udp4_tun_socket) != NULL) {
75523a51a264SMichael Tuexen 		soclose(SCTP_BASE_INFO(udp4_tun_socket));
75533a51a264SMichael Tuexen 		SCTP_BASE_INFO(udp4_tun_socket) = NULL;
7554c54a18d2SRandall Stewart 	}
75553a51a264SMichael Tuexen #endif
75563a51a264SMichael Tuexen #ifdef INET6
75573a51a264SMichael Tuexen 	if (SCTP_BASE_INFO(udp6_tun_socket) != NULL) {
75583a51a264SMichael Tuexen 		soclose(SCTP_BASE_INFO(udp6_tun_socket));
75593a51a264SMichael Tuexen 		SCTP_BASE_INFO(udp6_tun_socket) = NULL;
75603a51a264SMichael Tuexen 	}
75613a51a264SMichael Tuexen #endif
7562a99b6783SRandall Stewart }
7563ea5eba11SMichael Tuexen 
7564c54a18d2SRandall Stewart int
7565c54a18d2SRandall Stewart sctp_over_udp_start(void)
7566c54a18d2SRandall Stewart {
7567a99b6783SRandall Stewart 	uint16_t port;
7568a99b6783SRandall Stewart 	int ret;
75693a51a264SMichael Tuexen #ifdef INET
75703a51a264SMichael Tuexen 	struct sockaddr_in sin;
75713a51a264SMichael Tuexen #endif
75723a51a264SMichael Tuexen #ifdef INET6
75733a51a264SMichael Tuexen 	struct sockaddr_in6 sin6;
75743a51a264SMichael Tuexen #endif
7575a99b6783SRandall Stewart 	/*
7576a99b6783SRandall Stewart 	 * This function assumes sysctl caller holds sctp_sysctl_info_lock()
7577a99b6783SRandall Stewart 	 * for writting!
7578a99b6783SRandall Stewart 	 */
7579a99b6783SRandall Stewart 	port = SCTP_BASE_SYSCTL(sctp_udp_tunneling_port);
75803a51a264SMichael Tuexen 	if (ntohs(port) == 0) {
7581a99b6783SRandall Stewart 		/* Must have a port set */
7582a99b6783SRandall Stewart 		return (EINVAL);
7583a99b6783SRandall Stewart 	}
75843a51a264SMichael Tuexen #ifdef INET
75853a51a264SMichael Tuexen 	if (SCTP_BASE_INFO(udp4_tun_socket) != NULL) {
7586a99b6783SRandall Stewart 		/* Already running -- must stop first */
7587a99b6783SRandall Stewart 		return (EALREADY);
7588a99b6783SRandall Stewart 	}
75893a51a264SMichael Tuexen #endif
75903a51a264SMichael Tuexen #ifdef INET6
75913a51a264SMichael Tuexen 	if (SCTP_BASE_INFO(udp6_tun_socket) != NULL) {
75923a51a264SMichael Tuexen 		/* Already running -- must stop first */
75933a51a264SMichael Tuexen 		return (EALREADY);
7594a99b6783SRandall Stewart 	}
75953a51a264SMichael Tuexen #endif
75963a51a264SMichael Tuexen #ifdef INET
75973a51a264SMichael Tuexen 	if ((ret = socreate(PF_INET, &SCTP_BASE_INFO(udp4_tun_socket),
75983a51a264SMichael Tuexen 	    SOCK_DGRAM, IPPROTO_UDP,
75993a51a264SMichael Tuexen 	    curthread->td_ucred, curthread))) {
7600a99b6783SRandall Stewart 		sctp_over_udp_stop();
7601a99b6783SRandall Stewart 		return (ret);
7602a99b6783SRandall Stewart 	}
76033a51a264SMichael Tuexen 	/* Call the special UDP hook. */
76043a51a264SMichael Tuexen 	if ((ret = udp_set_kernel_tunneling(SCTP_BASE_INFO(udp4_tun_socket),
7605fd7af143SMichael Tuexen 	    sctp_recv_udp_tunneled_packet,
7606fd7af143SMichael Tuexen 	    sctp_recv_icmp_tunneled_packet,
7607fd7af143SMichael Tuexen 	    NULL))) {
76083a51a264SMichael Tuexen 		sctp_over_udp_stop();
76093a51a264SMichael Tuexen 		return (ret);
76103a51a264SMichael Tuexen 	}
76113a51a264SMichael Tuexen 	/* Ok, we have a socket, bind it to the port. */
76123a51a264SMichael Tuexen 	memset(&sin, 0, sizeof(struct sockaddr_in));
76133a51a264SMichael Tuexen 	sin.sin_len = sizeof(struct sockaddr_in);
76143a51a264SMichael Tuexen 	sin.sin_family = AF_INET;
76153a51a264SMichael Tuexen 	sin.sin_port = htons(port);
76163a51a264SMichael Tuexen 	if ((ret = sobind(SCTP_BASE_INFO(udp4_tun_socket),
76173a51a264SMichael Tuexen 	    (struct sockaddr *)&sin, curthread))) {
76183a51a264SMichael Tuexen 		sctp_over_udp_stop();
76193a51a264SMichael Tuexen 		return (ret);
76203a51a264SMichael Tuexen 	}
76213a51a264SMichael Tuexen #endif
76223a51a264SMichael Tuexen #ifdef INET6
76233a51a264SMichael Tuexen 	if ((ret = socreate(PF_INET6, &SCTP_BASE_INFO(udp6_tun_socket),
76243a51a264SMichael Tuexen 	    SOCK_DGRAM, IPPROTO_UDP,
76253a51a264SMichael Tuexen 	    curthread->td_ucred, curthread))) {
76263a51a264SMichael Tuexen 		sctp_over_udp_stop();
76273a51a264SMichael Tuexen 		return (ret);
76283a51a264SMichael Tuexen 	}
76293a51a264SMichael Tuexen 	/* Call the special UDP hook. */
76303a51a264SMichael Tuexen 	if ((ret = udp_set_kernel_tunneling(SCTP_BASE_INFO(udp6_tun_socket),
7631fd7af143SMichael Tuexen 	    sctp_recv_udp_tunneled_packet,
7632fd7af143SMichael Tuexen 	    sctp_recv_icmp6_tunneled_packet,
7633fd7af143SMichael Tuexen 	    NULL))) {
76343a51a264SMichael Tuexen 		sctp_over_udp_stop();
76353a51a264SMichael Tuexen 		return (ret);
76363a51a264SMichael Tuexen 	}
76373a51a264SMichael Tuexen 	/* Ok, we have a socket, bind it to the port. */
76383a51a264SMichael Tuexen 	memset(&sin6, 0, sizeof(struct sockaddr_in6));
76393a51a264SMichael Tuexen 	sin6.sin6_len = sizeof(struct sockaddr_in6);
76403a51a264SMichael Tuexen 	sin6.sin6_family = AF_INET6;
76413a51a264SMichael Tuexen 	sin6.sin6_port = htons(port);
76423a51a264SMichael Tuexen 	if ((ret = sobind(SCTP_BASE_INFO(udp6_tun_socket),
76433a51a264SMichael Tuexen 	    (struct sockaddr *)&sin6, curthread))) {
76443a51a264SMichael Tuexen 		sctp_over_udp_stop();
76453a51a264SMichael Tuexen 		return (ret);
76463a51a264SMichael Tuexen 	}
76473a51a264SMichael Tuexen #endif
7648a99b6783SRandall Stewart 	return (0);
7649c54a18d2SRandall Stewart }
765010e0318aSMichael Tuexen 
765110e0318aSMichael Tuexen /*
765210e0318aSMichael Tuexen  * sctp_min_mtu ()returns the minimum of all non-zero arguments.
765310e0318aSMichael Tuexen  * If all arguments are zero, zero is returned.
765410e0318aSMichael Tuexen  */
765510e0318aSMichael Tuexen uint32_t
7656b0471b4bSMichael Tuexen sctp_min_mtu(uint32_t mtu1, uint32_t mtu2, uint32_t mtu3)
7657b0471b4bSMichael Tuexen {
765810e0318aSMichael Tuexen 	if (mtu1 > 0) {
765910e0318aSMichael Tuexen 		if (mtu2 > 0) {
766010e0318aSMichael Tuexen 			if (mtu3 > 0) {
766110e0318aSMichael Tuexen 				return (min(mtu1, min(mtu2, mtu3)));
766210e0318aSMichael Tuexen 			} else {
766310e0318aSMichael Tuexen 				return (min(mtu1, mtu2));
766410e0318aSMichael Tuexen 			}
766510e0318aSMichael Tuexen 		} else {
766610e0318aSMichael Tuexen 			if (mtu3 > 0) {
766710e0318aSMichael Tuexen 				return (min(mtu1, mtu3));
766810e0318aSMichael Tuexen 			} else {
766910e0318aSMichael Tuexen 				return (mtu1);
767010e0318aSMichael Tuexen 			}
767110e0318aSMichael Tuexen 		}
767210e0318aSMichael Tuexen 	} else {
767310e0318aSMichael Tuexen 		if (mtu2 > 0) {
767410e0318aSMichael Tuexen 			if (mtu3 > 0) {
767510e0318aSMichael Tuexen 				return (min(mtu2, mtu3));
767610e0318aSMichael Tuexen 			} else {
767710e0318aSMichael Tuexen 				return (mtu2);
767810e0318aSMichael Tuexen 			}
767910e0318aSMichael Tuexen 		} else {
768010e0318aSMichael Tuexen 			return (mtu3);
768110e0318aSMichael Tuexen 		}
768210e0318aSMichael Tuexen 	}
768310e0318aSMichael Tuexen }
768410e0318aSMichael Tuexen 
768510e0318aSMichael Tuexen void
768610e0318aSMichael Tuexen sctp_hc_set_mtu(union sctp_sockstore *addr, uint16_t fibnum, uint32_t mtu)
768710e0318aSMichael Tuexen {
768810e0318aSMichael Tuexen 	struct in_conninfo inc;
768910e0318aSMichael Tuexen 
769010e0318aSMichael Tuexen 	memset(&inc, 0, sizeof(struct in_conninfo));
769110e0318aSMichael Tuexen 	inc.inc_fibnum = fibnum;
769210e0318aSMichael Tuexen 	switch (addr->sa.sa_family) {
769310e0318aSMichael Tuexen #ifdef INET
769410e0318aSMichael Tuexen 	case AF_INET:
769510e0318aSMichael Tuexen 		inc.inc_faddr = addr->sin.sin_addr;
769610e0318aSMichael Tuexen 		break;
769710e0318aSMichael Tuexen #endif
769810e0318aSMichael Tuexen #ifdef INET6
769910e0318aSMichael Tuexen 	case AF_INET6:
770010e0318aSMichael Tuexen 		inc.inc_flags |= INC_ISIPV6;
770110e0318aSMichael Tuexen 		inc.inc6_faddr = addr->sin6.sin6_addr;
770210e0318aSMichael Tuexen 		break;
770310e0318aSMichael Tuexen #endif
770410e0318aSMichael Tuexen 	default:
770510e0318aSMichael Tuexen 		return;
770610e0318aSMichael Tuexen 	}
770710e0318aSMichael Tuexen 	tcp_hc_updatemtu(&inc, (u_long)mtu);
770810e0318aSMichael Tuexen }
770910e0318aSMichael Tuexen 
771010e0318aSMichael Tuexen uint32_t
7711b0471b4bSMichael Tuexen sctp_hc_get_mtu(union sctp_sockstore *addr, uint16_t fibnum)
7712b0471b4bSMichael Tuexen {
771310e0318aSMichael Tuexen 	struct in_conninfo inc;
771410e0318aSMichael Tuexen 
771510e0318aSMichael Tuexen 	memset(&inc, 0, sizeof(struct in_conninfo));
771610e0318aSMichael Tuexen 	inc.inc_fibnum = fibnum;
771710e0318aSMichael Tuexen 	switch (addr->sa.sa_family) {
771810e0318aSMichael Tuexen #ifdef INET
771910e0318aSMichael Tuexen 	case AF_INET:
772010e0318aSMichael Tuexen 		inc.inc_faddr = addr->sin.sin_addr;
772110e0318aSMichael Tuexen 		break;
772210e0318aSMichael Tuexen #endif
772310e0318aSMichael Tuexen #ifdef INET6
772410e0318aSMichael Tuexen 	case AF_INET6:
772510e0318aSMichael Tuexen 		inc.inc_flags |= INC_ISIPV6;
772610e0318aSMichael Tuexen 		inc.inc6_faddr = addr->sin6.sin6_addr;
772710e0318aSMichael Tuexen 		break;
772810e0318aSMichael Tuexen #endif
772910e0318aSMichael Tuexen 	default:
773010e0318aSMichael Tuexen 		return (0);
773110e0318aSMichael Tuexen 	}
773210e0318aSMichael Tuexen 	return ((uint32_t)tcp_hc_getmtu(&inc));
773310e0318aSMichael Tuexen }
77346ef849e6SMichael Tuexen 
77351a0b0216SMichael Tuexen void
77361a0b0216SMichael Tuexen sctp_set_state(struct sctp_tcb *stcb, int new_state)
77371a0b0216SMichael Tuexen {
77381e88cc8bSMichael Tuexen #if defined(KDTRACE_HOOKS)
77391e88cc8bSMichael Tuexen 	int old_state = stcb->asoc.state;
77401e88cc8bSMichael Tuexen #endif
77411e88cc8bSMichael Tuexen 
77421a0b0216SMichael Tuexen 	KASSERT((new_state & ~SCTP_STATE_MASK) == 0,
77431a0b0216SMichael Tuexen 	    ("sctp_set_state: Can't set substate (new_state = %x)",
77441a0b0216SMichael Tuexen 	    new_state));
77451a0b0216SMichael Tuexen 	stcb->asoc.state = (stcb->asoc.state & ~SCTP_STATE_MASK) | new_state;
77461a0b0216SMichael Tuexen 	if ((new_state == SCTP_STATE_SHUTDOWN_RECEIVED) ||
77471a0b0216SMichael Tuexen 	    (new_state == SCTP_STATE_SHUTDOWN_SENT) ||
77481a0b0216SMichael Tuexen 	    (new_state == SCTP_STATE_SHUTDOWN_ACK_SENT)) {
77491a0b0216SMichael Tuexen 		SCTP_CLEAR_SUBSTATE(stcb, SCTP_STATE_SHUTDOWN_PENDING);
77501a0b0216SMichael Tuexen 	}
77511e88cc8bSMichael Tuexen #if defined(KDTRACE_HOOKS)
77521e88cc8bSMichael Tuexen 	if (((old_state & SCTP_STATE_MASK) != new_state) &&
77531e88cc8bSMichael Tuexen 	    !(((old_state & SCTP_STATE_MASK) == SCTP_STATE_EMPTY) &&
77541e88cc8bSMichael Tuexen 	    (new_state == SCTP_STATE_INUSE))) {
77551e88cc8bSMichael Tuexen 		SCTP_PROBE6(state__change, NULL, stcb, NULL, stcb, NULL, old_state);
77561e88cc8bSMichael Tuexen 	}
77571e88cc8bSMichael Tuexen #endif
77581a0b0216SMichael Tuexen }
77591a0b0216SMichael Tuexen 
77601a0b0216SMichael Tuexen void
77611a0b0216SMichael Tuexen sctp_add_substate(struct sctp_tcb *stcb, int substate)
77621a0b0216SMichael Tuexen {
77631e88cc8bSMichael Tuexen #if defined(KDTRACE_HOOKS)
77641e88cc8bSMichael Tuexen 	int old_state = stcb->asoc.state;
77651e88cc8bSMichael Tuexen #endif
77661e88cc8bSMichael Tuexen 
77671a0b0216SMichael Tuexen 	KASSERT((substate & SCTP_STATE_MASK) == 0,
77681a0b0216SMichael Tuexen 	    ("sctp_add_substate: Can't set state (substate = %x)",
77691a0b0216SMichael Tuexen 	    substate));
77701a0b0216SMichael Tuexen 	stcb->asoc.state |= substate;
77711e88cc8bSMichael Tuexen #if defined(KDTRACE_HOOKS)
77721e88cc8bSMichael Tuexen 	if (((substate & SCTP_STATE_ABOUT_TO_BE_FREED) &&
77731e88cc8bSMichael Tuexen 	    ((old_state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0)) ||
77741e88cc8bSMichael Tuexen 	    ((substate & SCTP_STATE_SHUTDOWN_PENDING) &&
77751e88cc8bSMichael Tuexen 	    ((old_state & SCTP_STATE_SHUTDOWN_PENDING) == 0))) {
77761e88cc8bSMichael Tuexen 		SCTP_PROBE6(state__change, NULL, stcb, NULL, stcb, NULL, old_state);
77771e88cc8bSMichael Tuexen 	}
77781e88cc8bSMichael Tuexen #endif
77791a0b0216SMichael Tuexen }
7780