1163953Srrs/*-
2185694Srrs * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved.
3235828Stuexen * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
4235828Stuexen * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
5163953Srrs *
6163953Srrs * Redistribution and use in source and binary forms, with or without
7163953Srrs * modification, are permitted provided that the following conditions are met:
8163953Srrs *
9163953Srrs * a) Redistributions of source code must retain the above copyright notice,
10228653Stuexen *    this list of conditions and the following disclaimer.
11163953Srrs *
12163953Srrs * b) Redistributions in binary form must reproduce the above copyright
13163953Srrs *    notice, this list of conditions and the following disclaimer in
14228653Stuexen *    the documentation and/or other materials provided with the distribution.
15163953Srrs *
16163953Srrs * c) Neither the name of Cisco Systems, Inc. nor the names of its
17163953Srrs *    contributors may be used to endorse or promote products derived
18163953Srrs *    from this software without specific prior written permission.
19163953Srrs *
20163953Srrs * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21163953Srrs * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22163953Srrs * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23163953Srrs * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24163953Srrs * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25163953Srrs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26163953Srrs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27163953Srrs * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28163953Srrs * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29163953Srrs * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30163953Srrs * THE POSSIBILITY OF SUCH DAMAGE.
31163953Srrs */
32163953Srrs
33163953Srrs#include <sys/cdefs.h>
34163953Srrs__FBSDID("$FreeBSD$");
35163953Srrs
36163953Srrs#include <netinet/sctp_os.h>
37163953Srrs#include <netinet/sctp_pcb.h>
38163953Srrs#include <netinet/sctputil.h>
39163953Srrs#include <netinet/sctp_var.h>
40167598Srrs#include <netinet/sctp_sysctl.h>
41163953Srrs#ifdef INET6
42243186Stuexen#include <netinet6/sctp6_var.h>
43163953Srrs#endif
44163953Srrs#include <netinet/sctp_header.h>
45163953Srrs#include <netinet/sctp_output.h>
46163953Srrs#include <netinet/sctp_uio.h>
47163953Srrs#include <netinet/sctp_timer.h>
48163953Srrs#include <netinet/sctp_indata.h>/* for sctp_deliver_data() */
49163953Srrs#include <netinet/sctp_auth.h>
50163953Srrs#include <netinet/sctp_asconf.h>
51208160Srrs#include <netinet/sctp_bsd_addr.h>
52243186Stuexen#include <netinet/udp.h>
53243186Stuexen#include <netinet/udp_var.h>
54243186Stuexen#include <sys/proc.h>
55163953Srrs
56163953Srrs
57170791Srrs#ifndef KTR_SCTP
58170791Srrs#define KTR_SCTP KTR_SUBSYS
59170744Srrs#endif
60163953Srrs
61217611Stuexenextern struct sctp_cc_functions sctp_cc_functions[];
62217760Stuexenextern struct sctp_ss_functions sctp_ss_functions[];
63217611Stuexen
64163953Srrsvoid
65240507Stuexensctp_sblog(struct sockbuf *sb, struct sctp_tcb *stcb, int from, int incr)
66163953Srrs{
67170744Srrs	struct sctp_cwnd_log sctp_clog;
68163953Srrs
69170744Srrs	sctp_clog.x.sb.stcb = stcb;
70170744Srrs	sctp_clog.x.sb.so_sbcc = sb->sb_cc;
71163953Srrs	if (stcb)
72170744Srrs		sctp_clog.x.sb.stcb_sbcc = stcb->asoc.sb_cc;
73163953Srrs	else
74170744Srrs		sctp_clog.x.sb.stcb_sbcc = 0;
75170744Srrs	sctp_clog.x.sb.incr = incr;
76171943Srrs	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
77170744Srrs	    SCTP_LOG_EVENT_SB,
78170744Srrs	    from,
79170744Srrs	    sctp_clog.x.misc.log1,
80170744Srrs	    sctp_clog.x.misc.log2,
81170744Srrs	    sctp_clog.x.misc.log3,
82170744Srrs	    sctp_clog.x.misc.log4);
83163953Srrs}
84163953Srrs
85163953Srrsvoid
86163953Srrssctp_log_closing(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int16_t loc)
87163953Srrs{
88170744Srrs	struct sctp_cwnd_log sctp_clog;
89163953Srrs
90170744Srrs	sctp_clog.x.close.inp = (void *)inp;
91170744Srrs	sctp_clog.x.close.sctp_flags = inp->sctp_flags;
92163953Srrs	if (stcb) {
93170744Srrs		sctp_clog.x.close.stcb = (void *)stcb;
94170744Srrs		sctp_clog.x.close.state = (uint16_t) stcb->asoc.state;
95163953Srrs	} else {
96170744Srrs		sctp_clog.x.close.stcb = 0;
97170744Srrs		sctp_clog.x.close.state = 0;
98163953Srrs	}
99170744Srrs	sctp_clog.x.close.loc = loc;
100171943Srrs	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
101170744Srrs	    SCTP_LOG_EVENT_CLOSE,
102170744Srrs	    0,
103170744Srrs	    sctp_clog.x.misc.log1,
104170744Srrs	    sctp_clog.x.misc.log2,
105170744Srrs	    sctp_clog.x.misc.log3,
106170744Srrs	    sctp_clog.x.misc.log4);
107163953Srrs}
108163953Srrs
109163953Srrsvoid
110163953Srrsrto_logging(struct sctp_nets *net, int from)
111163953Srrs{
112170744Srrs	struct sctp_cwnd_log sctp_clog;
113163953Srrs
114179141Srrs	memset(&sctp_clog, 0, sizeof(sctp_clog));
115170744Srrs	sctp_clog.x.rto.net = (void *)net;
116219013Stuexen	sctp_clog.x.rto.rtt = net->rtt / 1000;
117171943Srrs	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
118170744Srrs	    SCTP_LOG_EVENT_RTT,
119170744Srrs	    from,
120170744Srrs	    sctp_clog.x.misc.log1,
121170744Srrs	    sctp_clog.x.misc.log2,
122170744Srrs	    sctp_clog.x.misc.log3,
123170744Srrs	    sctp_clog.x.misc.log4);
124163953Srrs}
125163953Srrs
126163953Srrsvoid
127164181Srrssctp_log_strm_del_alt(struct sctp_tcb *stcb, uint32_t tsn, uint16_t sseq, uint16_t stream, int from)
128163953Srrs{
129170744Srrs	struct sctp_cwnd_log sctp_clog;
130163953Srrs
131170744Srrs	sctp_clog.x.strlog.stcb = stcb;
132170744Srrs	sctp_clog.x.strlog.n_tsn = tsn;
133170744Srrs	sctp_clog.x.strlog.n_sseq = sseq;
134170744Srrs	sctp_clog.x.strlog.e_tsn = 0;
135170744Srrs	sctp_clog.x.strlog.e_sseq = 0;
136170744Srrs	sctp_clog.x.strlog.strm = stream;
137171943Srrs	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
138170744Srrs	    SCTP_LOG_EVENT_STRM,
139170744Srrs	    from,
140170744Srrs	    sctp_clog.x.misc.log1,
141170744Srrs	    sctp_clog.x.misc.log2,
142170744Srrs	    sctp_clog.x.misc.log3,
143170744Srrs	    sctp_clog.x.misc.log4);
144163953Srrs}
145163953Srrs
146163953Srrsvoid
147163953Srrssctp_log_nagle_event(struct sctp_tcb *stcb, int action)
148163953Srrs{
149170744Srrs	struct sctp_cwnd_log sctp_clog;
150163953Srrs
151170744Srrs	sctp_clog.x.nagle.stcb = (void *)stcb;
152170744Srrs	sctp_clog.x.nagle.total_flight = stcb->asoc.total_flight;
153170744Srrs	sctp_clog.x.nagle.total_in_queue = stcb->asoc.total_output_queue_size;
154170744Srrs	sctp_clog.x.nagle.count_in_queue = stcb->asoc.chunks_on_out_queue;
155170744Srrs	sctp_clog.x.nagle.count_in_flight = stcb->asoc.total_flight_count;
156171943Srrs	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
157170744Srrs	    SCTP_LOG_EVENT_NAGLE,
158170744Srrs	    action,
159170744Srrs	    sctp_clog.x.misc.log1,
160170744Srrs	    sctp_clog.x.misc.log2,
161170744Srrs	    sctp_clog.x.misc.log3,
162170744Srrs	    sctp_clog.x.misc.log4);
163163953Srrs}
164163953Srrs
165163953Srrsvoid
166163953Srrssctp_log_sack(uint32_t old_cumack, uint32_t cumack, uint32_t tsn, uint16_t gaps, uint16_t dups, int from)
167163953Srrs{
168170744Srrs	struct sctp_cwnd_log sctp_clog;
169163953Srrs
170170744Srrs	sctp_clog.x.sack.cumack = cumack;
171170744Srrs	sctp_clog.x.sack.oldcumack = old_cumack;
172170744Srrs	sctp_clog.x.sack.tsn = tsn;
173170744Srrs	sctp_clog.x.sack.numGaps = gaps;
174170744Srrs	sctp_clog.x.sack.numDups = dups;
175171943Srrs	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
176170744Srrs	    SCTP_LOG_EVENT_SACK,
177170744Srrs	    from,
178170744Srrs	    sctp_clog.x.misc.log1,
179170744Srrs	    sctp_clog.x.misc.log2,
180170744Srrs	    sctp_clog.x.misc.log3,
181170744Srrs	    sctp_clog.x.misc.log4);
182163953Srrs}
183163953Srrs
184163953Srrsvoid
185163953Srrssctp_log_map(uint32_t map, uint32_t cum, uint32_t high, int from)
186163953Srrs{
187170744Srrs	struct sctp_cwnd_log sctp_clog;
188163953Srrs
189179141Srrs	memset(&sctp_clog, 0, sizeof(sctp_clog));
190170744Srrs	sctp_clog.x.map.base = map;
191170744Srrs	sctp_clog.x.map.cum = cum;
192170744Srrs	sctp_clog.x.map.high = high;
193171943Srrs	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
194170744Srrs	    SCTP_LOG_EVENT_MAP,
195170744Srrs	    from,
196170744Srrs	    sctp_clog.x.misc.log1,
197170744Srrs	    sctp_clog.x.misc.log2,
198170744Srrs	    sctp_clog.x.misc.log3,
199170744Srrs	    sctp_clog.x.misc.log4);
200163953Srrs}
201163953Srrs
202163953Srrsvoid
203240507Stuexensctp_log_fr(uint32_t biggest_tsn, uint32_t biggest_new_tsn, uint32_t tsn, int from)
204163953Srrs{
205170744Srrs	struct sctp_cwnd_log sctp_clog;
206163953Srrs
207179141Srrs	memset(&sctp_clog, 0, sizeof(sctp_clog));
208170744Srrs	sctp_clog.x.fr.largest_tsn = biggest_tsn;
209170744Srrs	sctp_clog.x.fr.largest_new_tsn = biggest_new_tsn;
210170744Srrs	sctp_clog.x.fr.tsn = tsn;
211171943Srrs	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
212170744Srrs	    SCTP_LOG_EVENT_FR,
213170744Srrs	    from,
214170744Srrs	    sctp_clog.x.misc.log1,
215170744Srrs	    sctp_clog.x.misc.log2,
216170744Srrs	    sctp_clog.x.misc.log3,
217170744Srrs	    sctp_clog.x.misc.log4);
218163953Srrs}
219163953Srrs
220283708Stuexen#ifdef SCTP_MBUF_LOGGING
221163953Srrsvoid
222163953Srrssctp_log_mb(struct mbuf *m, int from)
223163953Srrs{
224170744Srrs	struct sctp_cwnd_log sctp_clog;
225163953Srrs
226170744Srrs	sctp_clog.x.mb.mp = m;
227170744Srrs	sctp_clog.x.mb.mbuf_flags = (uint8_t) (SCTP_BUF_GET_FLAGS(m));
228170744Srrs	sctp_clog.x.mb.size = (uint16_t) (SCTP_BUF_LEN(m));
229170744Srrs	sctp_clog.x.mb.data = SCTP_BUF_AT(m, 0);
230165647Srrs	if (SCTP_BUF_IS_EXTENDED(m)) {
231170744Srrs		sctp_clog.x.mb.ext = SCTP_BUF_EXTEND_BASE(m);
232170744Srrs		sctp_clog.x.mb.refcnt = (uint8_t) (SCTP_BUF_EXTEND_REFCNT(m));
233163953Srrs	} else {
234170744Srrs		sctp_clog.x.mb.ext = 0;
235170744Srrs		sctp_clog.x.mb.refcnt = 0;
236163953Srrs	}
237171943Srrs	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
238170744Srrs	    SCTP_LOG_EVENT_MBUF,
239170744Srrs	    from,
240170744Srrs	    sctp_clog.x.misc.log1,
241170744Srrs	    sctp_clog.x.misc.log2,
242170744Srrs	    sctp_clog.x.misc.log3,
243170744Srrs	    sctp_clog.x.misc.log4);
244163953Srrs}
245163953Srrs
246163953Srrsvoid
247283708Stuexensctp_log_mbc(struct mbuf *m, int from)
248283708Stuexen{
249283708Stuexen	struct mbuf *mat;
250283708Stuexen
251283708Stuexen	for (mat = m; mat; mat = SCTP_BUF_NEXT(mat)) {
252283708Stuexen		sctp_log_mb(mat, from);
253283708Stuexen	}
254283708Stuexen}
255283708Stuexen
256283708Stuexen#endif
257283708Stuexen
258283708Stuexenvoid
259240507Stuexensctp_log_strm_del(struct sctp_queued_to_read *control, struct sctp_queued_to_read *poschk, int from)
260163953Srrs{
261170744Srrs	struct sctp_cwnd_log sctp_clog;
262163953Srrs
263163953Srrs	if (control == NULL) {
264169420Srrs		SCTP_PRINTF("Gak log of NULL?\n");
265163953Srrs		return;
266163953Srrs	}
267170744Srrs	sctp_clog.x.strlog.stcb = control->stcb;
268170744Srrs	sctp_clog.x.strlog.n_tsn = control->sinfo_tsn;
269170744Srrs	sctp_clog.x.strlog.n_sseq = control->sinfo_ssn;
270170744Srrs	sctp_clog.x.strlog.strm = control->sinfo_stream;
271163953Srrs	if (poschk != NULL) {
272170744Srrs		sctp_clog.x.strlog.e_tsn = poschk->sinfo_tsn;
273170744Srrs		sctp_clog.x.strlog.e_sseq = poschk->sinfo_ssn;
274163953Srrs	} else {
275170744Srrs		sctp_clog.x.strlog.e_tsn = 0;
276170744Srrs		sctp_clog.x.strlog.e_sseq = 0;
277163953Srrs	}
278171943Srrs	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
279170744Srrs	    SCTP_LOG_EVENT_STRM,
280170744Srrs	    from,
281170744Srrs	    sctp_clog.x.misc.log1,
282170744Srrs	    sctp_clog.x.misc.log2,
283170744Srrs	    sctp_clog.x.misc.log3,
284170744Srrs	    sctp_clog.x.misc.log4);
285163953Srrs}
286163953Srrs
287163953Srrsvoid
288163953Srrssctp_log_cwnd(struct sctp_tcb *stcb, struct sctp_nets *net, int augment, uint8_t from)
289163953Srrs{
290170744Srrs	struct sctp_cwnd_log sctp_clog;
291163953Srrs
292170744Srrs	sctp_clog.x.cwnd.net = net;
293163953Srrs	if (stcb->asoc.send_queue_cnt > 255)
294170744Srrs		sctp_clog.x.cwnd.cnt_in_send = 255;
295163953Srrs	else
296170744Srrs		sctp_clog.x.cwnd.cnt_in_send = stcb->asoc.send_queue_cnt;
297163953Srrs	if (stcb->asoc.stream_queue_cnt > 255)
298170744Srrs		sctp_clog.x.cwnd.cnt_in_str = 255;
299163953Srrs	else
300170744Srrs		sctp_clog.x.cwnd.cnt_in_str = stcb->asoc.stream_queue_cnt;
301163953Srrs
302163953Srrs	if (net) {
303170744Srrs		sctp_clog.x.cwnd.cwnd_new_value = net->cwnd;
304170744Srrs		sctp_clog.x.cwnd.inflight = net->flight_size;
305170744Srrs		sctp_clog.x.cwnd.pseudo_cumack = net->pseudo_cumack;
306170744Srrs		sctp_clog.x.cwnd.meets_pseudo_cumack = net->new_pseudo_cumack;
307170744Srrs		sctp_clog.x.cwnd.need_new_pseudo_cumack = net->find_pseudo_cumack;
308163953Srrs	}
309163953Srrs	if (SCTP_CWNDLOG_PRESEND == from) {
310170744Srrs		sctp_clog.x.cwnd.meets_pseudo_cumack = stcb->asoc.peers_rwnd;
311163953Srrs	}
312170744Srrs	sctp_clog.x.cwnd.cwnd_augment = augment;
313171943Srrs	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
314170744Srrs	    SCTP_LOG_EVENT_CWND,
315170744Srrs	    from,
316170744Srrs	    sctp_clog.x.misc.log1,
317170744Srrs	    sctp_clog.x.misc.log2,
318170744Srrs	    sctp_clog.x.misc.log3,
319170744Srrs	    sctp_clog.x.misc.log4);
320163953Srrs}
321163953Srrs
322163953Srrsvoid
323163953Srrssctp_log_lock(struct sctp_inpcb *inp, struct sctp_tcb *stcb, uint8_t from)
324163953Srrs{
325170744Srrs	struct sctp_cwnd_log sctp_clog;
326163953Srrs
327179141Srrs	memset(&sctp_clog, 0, sizeof(sctp_clog));
328164085Srrs	if (inp) {
329170744Srrs		sctp_clog.x.lock.sock = (void *)inp->sctp_socket;
330164085Srrs
331164085Srrs	} else {
332170744Srrs		sctp_clog.x.lock.sock = (void *)NULL;
333164085Srrs	}
334170744Srrs	sctp_clog.x.lock.inp = (void *)inp;
335163953Srrs	if (stcb) {
336170744Srrs		sctp_clog.x.lock.tcb_lock = mtx_owned(&stcb->tcb_mtx);
337163953Srrs	} else {
338170744Srrs		sctp_clog.x.lock.tcb_lock = SCTP_LOCK_UNKNOWN;
339163953Srrs	}
340163953Srrs	if (inp) {
341170744Srrs		sctp_clog.x.lock.inp_lock = mtx_owned(&inp->inp_mtx);
342170744Srrs		sctp_clog.x.lock.create_lock = mtx_owned(&inp->inp_create_mtx);
343163953Srrs	} else {
344170744Srrs		sctp_clog.x.lock.inp_lock = SCTP_LOCK_UNKNOWN;
345170744Srrs		sctp_clog.x.lock.create_lock = SCTP_LOCK_UNKNOWN;
346163953Srrs	}
347179783Srrs	sctp_clog.x.lock.info_lock = rw_wowned(&SCTP_BASE_INFO(ipi_ep_mtx));
348212225Srrs	if (inp && (inp->sctp_socket)) {
349170744Srrs		sctp_clog.x.lock.sock_lock = mtx_owned(&(inp->sctp_socket->so_rcv.sb_mtx));
350170744Srrs		sctp_clog.x.lock.sockrcvbuf_lock = mtx_owned(&(inp->sctp_socket->so_rcv.sb_mtx));
351170744Srrs		sctp_clog.x.lock.socksndbuf_lock = mtx_owned(&(inp->sctp_socket->so_snd.sb_mtx));
352163953Srrs	} else {
353170744Srrs		sctp_clog.x.lock.sock_lock = SCTP_LOCK_UNKNOWN;
354170744Srrs		sctp_clog.x.lock.sockrcvbuf_lock = SCTP_LOCK_UNKNOWN;
355170744Srrs		sctp_clog.x.lock.socksndbuf_lock = SCTP_LOCK_UNKNOWN;
356163953Srrs	}
357171943Srrs	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
358170744Srrs	    SCTP_LOG_LOCK_EVENT,
359170744Srrs	    from,
360170744Srrs	    sctp_clog.x.misc.log1,
361170744Srrs	    sctp_clog.x.misc.log2,
362170744Srrs	    sctp_clog.x.misc.log3,
363170744Srrs	    sctp_clog.x.misc.log4);
364163953Srrs}
365163953Srrs
366163953Srrsvoid
367163953Srrssctp_log_maxburst(struct sctp_tcb *stcb, struct sctp_nets *net, int error, int burst, uint8_t from)
368163953Srrs{
369170744Srrs	struct sctp_cwnd_log sctp_clog;
370163953Srrs
371179141Srrs	memset(&sctp_clog, 0, sizeof(sctp_clog));
372170744Srrs	sctp_clog.x.cwnd.net = net;
373170744Srrs	sctp_clog.x.cwnd.cwnd_new_value = error;
374170744Srrs	sctp_clog.x.cwnd.inflight = net->flight_size;
375170744Srrs	sctp_clog.x.cwnd.cwnd_augment = burst;
376163953Srrs	if (stcb->asoc.send_queue_cnt > 255)
377170744Srrs		sctp_clog.x.cwnd.cnt_in_send = 255;
378163953Srrs	else
379170744Srrs		sctp_clog.x.cwnd.cnt_in_send = stcb->asoc.send_queue_cnt;
380163953Srrs	if (stcb->asoc.stream_queue_cnt > 255)
381170744Srrs		sctp_clog.x.cwnd.cnt_in_str = 255;
382163953Srrs	else
383170744Srrs		sctp_clog.x.cwnd.cnt_in_str = stcb->asoc.stream_queue_cnt;
384171943Srrs	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
385170744Srrs	    SCTP_LOG_EVENT_MAXBURST,
386170744Srrs	    from,
387170744Srrs	    sctp_clog.x.misc.log1,
388170744Srrs	    sctp_clog.x.misc.log2,
389170744Srrs	    sctp_clog.x.misc.log3,
390170744Srrs	    sctp_clog.x.misc.log4);
391163953Srrs}
392163953Srrs
393163953Srrsvoid
394163953Srrssctp_log_rwnd(uint8_t from, uint32_t peers_rwnd, uint32_t snd_size, uint32_t overhead)
395163953Srrs{
396170744Srrs	struct sctp_cwnd_log sctp_clog;
397163953Srrs
398170744Srrs	sctp_clog.x.rwnd.rwnd = peers_rwnd;
399170744Srrs	sctp_clog.x.rwnd.send_size = snd_size;
400170744Srrs	sctp_clog.x.rwnd.overhead = overhead;
401170744Srrs	sctp_clog.x.rwnd.new_rwnd = 0;
402171943Srrs	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
403170744Srrs	    SCTP_LOG_EVENT_RWND,
404170744Srrs	    from,
405170744Srrs	    sctp_clog.x.misc.log1,
406170744Srrs	    sctp_clog.x.misc.log2,
407170744Srrs	    sctp_clog.x.misc.log3,
408170744Srrs	    sctp_clog.x.misc.log4);
409163953Srrs}
410163953Srrs
411163953Srrsvoid
412163953Srrssctp_log_rwnd_set(uint8_t from, uint32_t peers_rwnd, uint32_t flight_size, uint32_t overhead, uint32_t a_rwndval)
413163953Srrs{
414170744Srrs	struct sctp_cwnd_log sctp_clog;
415163953Srrs
416170744Srrs	sctp_clog.x.rwnd.rwnd = peers_rwnd;
417170744Srrs	sctp_clog.x.rwnd.send_size = flight_size;
418170744Srrs	sctp_clog.x.rwnd.overhead = overhead;
419170744Srrs	sctp_clog.x.rwnd.new_rwnd = a_rwndval;
420171943Srrs	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
421170744Srrs	    SCTP_LOG_EVENT_RWND,
422170744Srrs	    from,
423170744Srrs	    sctp_clog.x.misc.log1,
424170744Srrs	    sctp_clog.x.misc.log2,
425170744Srrs	    sctp_clog.x.misc.log3,
426170744Srrs	    sctp_clog.x.misc.log4);
427163953Srrs}
428163953Srrs
429283708Stuexen#ifdef SCTP_MBCNT_LOGGING
430283708Stuexenstatic void
431163953Srrssctp_log_mbcnt(uint8_t from, uint32_t total_oq, uint32_t book, uint32_t total_mbcnt_q, uint32_t mbcnt)
432163953Srrs{
433170744Srrs	struct sctp_cwnd_log sctp_clog;
434163953Srrs
435170744Srrs	sctp_clog.x.mbcnt.total_queue_size = total_oq;
436170744Srrs	sctp_clog.x.mbcnt.size_change = book;
437170744Srrs	sctp_clog.x.mbcnt.total_queue_mb_size = total_mbcnt_q;
438170744Srrs	sctp_clog.x.mbcnt.mbcnt_change = mbcnt;
439171943Srrs	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
440170744Srrs	    SCTP_LOG_EVENT_MBCNT,
441170744Srrs	    from,
442170744Srrs	    sctp_clog.x.misc.log1,
443170744Srrs	    sctp_clog.x.misc.log2,
444170744Srrs	    sctp_clog.x.misc.log3,
445170744Srrs	    sctp_clog.x.misc.log4);
446163953Srrs}
447163953Srrs
448283708Stuexen#endif
449283708Stuexen
450163953Srrsvoid
451163953Srrssctp_misc_ints(uint8_t from, uint32_t a, uint32_t b, uint32_t c, uint32_t d)
452163953Srrs{
453171943Srrs	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
454170744Srrs	    SCTP_LOG_MISC_EVENT,
455170744Srrs	    from,
456170744Srrs	    a, b, c, d);
457163953Srrs}
458163953Srrs
459163953Srrsvoid
460228653Stuexensctp_wakeup_log(struct sctp_tcb *stcb, uint32_t wake_cnt, int from)
461163953Srrs{
462170744Srrs	struct sctp_cwnd_log sctp_clog;
463163953Srrs
464170744Srrs	sctp_clog.x.wake.stcb = (void *)stcb;
465170744Srrs	sctp_clog.x.wake.wake_cnt = wake_cnt;
466170744Srrs	sctp_clog.x.wake.flight = stcb->asoc.total_flight_count;
467170744Srrs	sctp_clog.x.wake.send_q = stcb->asoc.send_queue_cnt;
468170744Srrs	sctp_clog.x.wake.sent_q = stcb->asoc.sent_queue_cnt;
469163953Srrs
470163953Srrs	if (stcb->asoc.stream_queue_cnt < 0xff)
471170744Srrs		sctp_clog.x.wake.stream_qcnt = (uint8_t) stcb->asoc.stream_queue_cnt;
472163953Srrs	else
473170744Srrs		sctp_clog.x.wake.stream_qcnt = 0xff;
474163953Srrs
475163953Srrs	if (stcb->asoc.chunks_on_out_queue < 0xff)
476170744Srrs		sctp_clog.x.wake.chunks_on_oque = (uint8_t) stcb->asoc.chunks_on_out_queue;
477163953Srrs	else
478170744Srrs		sctp_clog.x.wake.chunks_on_oque = 0xff;
479163953Srrs
480170744Srrs	sctp_clog.x.wake.sctpflags = 0;
481163953Srrs	/* set in the defered mode stuff */
482163953Srrs	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE)
483170744Srrs		sctp_clog.x.wake.sctpflags |= 1;
484163953Srrs	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT)
485170744Srrs		sctp_clog.x.wake.sctpflags |= 2;
486163953Srrs	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT)
487170744Srrs		sctp_clog.x.wake.sctpflags |= 4;
488163953Srrs	/* what about the sb */
489163953Srrs	if (stcb->sctp_socket) {
490163953Srrs		struct socket *so = stcb->sctp_socket;
491163953Srrs
492170744Srrs		sctp_clog.x.wake.sbflags = (uint8_t) ((so->so_snd.sb_flags & 0x00ff));
493163953Srrs	} else {
494170744Srrs		sctp_clog.x.wake.sbflags = 0xff;
495163953Srrs	}
496171943Srrs	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
497170744Srrs	    SCTP_LOG_EVENT_WAKE,
498170744Srrs	    from,
499170744Srrs	    sctp_clog.x.misc.log1,
500170744Srrs	    sctp_clog.x.misc.log2,
501170744Srrs	    sctp_clog.x.misc.log3,
502170744Srrs	    sctp_clog.x.misc.log4);
503163953Srrs}
504163953Srrs
505163953Srrsvoid
506228653Stuexensctp_log_block(uint8_t from, struct sctp_association *asoc, int sendlen)
507163953Srrs{
508170744Srrs	struct sctp_cwnd_log sctp_clog;
509163953Srrs
510170744Srrs	sctp_clog.x.blk.onsb = asoc->total_output_queue_size;
511170744Srrs	sctp_clog.x.blk.send_sent_qcnt = (uint16_t) (asoc->send_queue_cnt + asoc->sent_queue_cnt);
512170744Srrs	sctp_clog.x.blk.peer_rwnd = asoc->peers_rwnd;
513170744Srrs	sctp_clog.x.blk.stream_qcnt = (uint16_t) asoc->stream_queue_cnt;
514170744Srrs	sctp_clog.x.blk.chunks_on_oque = (uint16_t) asoc->chunks_on_out_queue;
515170744Srrs	sctp_clog.x.blk.flight_size = (uint16_t) (asoc->total_flight / 1024);
516170744Srrs	sctp_clog.x.blk.sndlen = sendlen;
517171943Srrs	SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
518170744Srrs	    SCTP_LOG_EVENT_BLOCK,
519170744Srrs	    from,
520170744Srrs	    sctp_clog.x.misc.log1,
521170744Srrs	    sctp_clog.x.misc.log2,
522170744Srrs	    sctp_clog.x.misc.log3,
523170744Srrs	    sctp_clog.x.misc.log4);
524163953Srrs}
525163953Srrs
526163953Srrsint
527228653Stuexensctp_fill_stat_log(void *optval SCTP_UNUSED, size_t *optsize SCTP_UNUSED)
528163953Srrs{
529170744Srrs	/* May need to fix this if ktrdump does not work */
530163953Srrs	return (0);
531163953Srrs}
532163953Srrs
533163953Srrs#ifdef SCTP_AUDITING_ENABLED
534163953Srrsuint8_t sctp_audit_data[SCTP_AUDIT_SIZE][2];
535163953Srrsstatic int sctp_audit_indx = 0;
536163953Srrs
537163953Srrsstatic
538163953Srrsvoid
539163953Srrssctp_print_audit_report(void)
540163953Srrs{
541163953Srrs	int i;
542163953Srrs	int cnt;
543163953Srrs
544163953Srrs	cnt = 0;
545163953Srrs	for (i = sctp_audit_indx; i < SCTP_AUDIT_SIZE; i++) {
546163953Srrs		if ((sctp_audit_data[i][0] == 0xe0) &&
547163953Srrs		    (sctp_audit_data[i][1] == 0x01)) {
548163953Srrs			cnt = 0;
549169420Srrs			SCTP_PRINTF("\n");
550163953Srrs		} else if (sctp_audit_data[i][0] == 0xf0) {
551163953Srrs			cnt = 0;
552169420Srrs			SCTP_PRINTF("\n");
553163953Srrs		} else if ((sctp_audit_data[i][0] == 0xc0) &&
554163953Srrs		    (sctp_audit_data[i][1] == 0x01)) {
555169420Srrs			SCTP_PRINTF("\n");
556163953Srrs			cnt = 0;
557163953Srrs		}
558169420Srrs		SCTP_PRINTF("%2.2x%2.2x ", (uint32_t) sctp_audit_data[i][0],
559163953Srrs		    (uint32_t) sctp_audit_data[i][1]);
560163953Srrs		cnt++;
561163953Srrs		if ((cnt % 14) == 0)
562169420Srrs			SCTP_PRINTF("\n");
563163953Srrs	}
564163953Srrs	for (i = 0; i < sctp_audit_indx; i++) {
565163953Srrs		if ((sctp_audit_data[i][0] == 0xe0) &&
566163953Srrs		    (sctp_audit_data[i][1] == 0x01)) {
567163953Srrs			cnt = 0;
568169420Srrs			SCTP_PRINTF("\n");
569163953Srrs		} else if (sctp_audit_data[i][0] == 0xf0) {
570163953Srrs			cnt = 0;
571169420Srrs			SCTP_PRINTF("\n");
572163953Srrs		} else if ((sctp_audit_data[i][0] == 0xc0) &&
573163953Srrs		    (sctp_audit_data[i][1] == 0x01)) {
574169420Srrs			SCTP_PRINTF("\n");
575163953Srrs			cnt = 0;
576163953Srrs		}
577169420Srrs		SCTP_PRINTF("%2.2x%2.2x ", (uint32_t) sctp_audit_data[i][0],
578163953Srrs		    (uint32_t) sctp_audit_data[i][1]);
579163953Srrs		cnt++;
580163953Srrs		if ((cnt % 14) == 0)
581169420Srrs			SCTP_PRINTF("\n");
582163953Srrs	}
583169420Srrs	SCTP_PRINTF("\n");
584163953Srrs}
585163953Srrs
586163953Srrsvoid
587163953Srrssctp_auditing(int from, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
588163953Srrs    struct sctp_nets *net)
589163953Srrs{
590163953Srrs	int resend_cnt, tot_out, rep, tot_book_cnt;
591163953Srrs	struct sctp_nets *lnet;
592163953Srrs	struct sctp_tmit_chunk *chk;
593163953Srrs
594163953Srrs	sctp_audit_data[sctp_audit_indx][0] = 0xAA;
595163953Srrs	sctp_audit_data[sctp_audit_indx][1] = 0x000000ff & from;
596163953Srrs	sctp_audit_indx++;
597163953Srrs	if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
598163953Srrs		sctp_audit_indx = 0;
599163953Srrs	}
600163953Srrs	if (inp == NULL) {
601163953Srrs		sctp_audit_data[sctp_audit_indx][0] = 0xAF;
602163953Srrs		sctp_audit_data[sctp_audit_indx][1] = 0x01;
603163953Srrs		sctp_audit_indx++;
604163953Srrs		if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
605163953Srrs			sctp_audit_indx = 0;
606163953Srrs		}
607163953Srrs		return;
608163953Srrs	}
609163953Srrs	if (stcb == NULL) {
610163953Srrs		sctp_audit_data[sctp_audit_indx][0] = 0xAF;
611163953Srrs		sctp_audit_data[sctp_audit_indx][1] = 0x02;
612163953Srrs		sctp_audit_indx++;
613163953Srrs		if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
614163953Srrs			sctp_audit_indx = 0;
615163953Srrs		}
616163953Srrs		return;
617163953Srrs	}
618163953Srrs	sctp_audit_data[sctp_audit_indx][0] = 0xA1;
619163953Srrs	sctp_audit_data[sctp_audit_indx][1] =
620163953Srrs	    (0x000000ff & stcb->asoc.sent_queue_retran_cnt);
621163953Srrs	sctp_audit_indx++;
622163953Srrs	if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
623163953Srrs		sctp_audit_indx = 0;
624163953Srrs	}
625163953Srrs	rep = 0;
626163953Srrs	tot_book_cnt = 0;
627163953Srrs	resend_cnt = tot_out = 0;
628163953Srrs	TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
629163953Srrs		if (chk->sent == SCTP_DATAGRAM_RESEND) {
630163953Srrs			resend_cnt++;
631163953Srrs		} else if (chk->sent < SCTP_DATAGRAM_RESEND) {
632163953Srrs			tot_out += chk->book_size;
633163953Srrs			tot_book_cnt++;
634163953Srrs		}
635163953Srrs	}
636163953Srrs	if (resend_cnt != stcb->asoc.sent_queue_retran_cnt) {
637163953Srrs		sctp_audit_data[sctp_audit_indx][0] = 0xAF;
638163953Srrs		sctp_audit_data[sctp_audit_indx][1] = 0xA1;
639163953Srrs		sctp_audit_indx++;
640163953Srrs		if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
641163953Srrs			sctp_audit_indx = 0;
642163953Srrs		}
643169420Srrs		SCTP_PRINTF("resend_cnt:%d asoc-tot:%d\n",
644163953Srrs		    resend_cnt, stcb->asoc.sent_queue_retran_cnt);
645163953Srrs		rep = 1;
646163953Srrs		stcb->asoc.sent_queue_retran_cnt = resend_cnt;
647163953Srrs		sctp_audit_data[sctp_audit_indx][0] = 0xA2;
648163953Srrs		sctp_audit_data[sctp_audit_indx][1] =
649163953Srrs		    (0x000000ff & stcb->asoc.sent_queue_retran_cnt);
650163953Srrs		sctp_audit_indx++;
651163953Srrs		if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
652163953Srrs			sctp_audit_indx = 0;
653163953Srrs		}
654163953Srrs	}
655163953Srrs	if (tot_out != stcb->asoc.total_flight) {
656163953Srrs		sctp_audit_data[sctp_audit_indx][0] = 0xAF;
657163953Srrs		sctp_audit_data[sctp_audit_indx][1] = 0xA2;
658163953Srrs		sctp_audit_indx++;
659163953Srrs		if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
660163953Srrs			sctp_audit_indx = 0;
661163953Srrs		}
662163953Srrs		rep = 1;
663169420Srrs		SCTP_PRINTF("tot_flt:%d asoc_tot:%d\n", tot_out,
664163953Srrs		    (int)stcb->asoc.total_flight);
665163953Srrs		stcb->asoc.total_flight = tot_out;
666163953Srrs	}
667163953Srrs	if (tot_book_cnt != stcb->asoc.total_flight_count) {
668163953Srrs		sctp_audit_data[sctp_audit_indx][0] = 0xAF;
669163953Srrs		sctp_audit_data[sctp_audit_indx][1] = 0xA5;
670163953Srrs		sctp_audit_indx++;
671163953Srrs		if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
672163953Srrs			sctp_audit_indx = 0;
673163953Srrs		}
674163953Srrs		rep = 1;
675207099Stuexen		SCTP_PRINTF("tot_flt_book:%d\n", tot_book_cnt);
676163953Srrs
677163953Srrs		stcb->asoc.total_flight_count = tot_book_cnt;
678163953Srrs	}
679163953Srrs	tot_out = 0;
680163953Srrs	TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
681163953Srrs		tot_out += lnet->flight_size;
682163953Srrs	}
683163953Srrs	if (tot_out != stcb->asoc.total_flight) {
684163953Srrs		sctp_audit_data[sctp_audit_indx][0] = 0xAF;
685163953Srrs		sctp_audit_data[sctp_audit_indx][1] = 0xA3;
686163953Srrs		sctp_audit_indx++;
687163953Srrs		if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
688163953Srrs			sctp_audit_indx = 0;
689163953Srrs		}
690163953Srrs		rep = 1;
691169420Srrs		SCTP_PRINTF("real flight:%d net total was %d\n",
692163953Srrs		    stcb->asoc.total_flight, tot_out);
693163953Srrs		/* now corrective action */
694163953Srrs		TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
695163953Srrs
696163953Srrs			tot_out = 0;
697163953Srrs			TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
698163953Srrs				if ((chk->whoTo == lnet) &&
699163953Srrs				    (chk->sent < SCTP_DATAGRAM_RESEND)) {
700163953Srrs					tot_out += chk->book_size;
701163953Srrs				}
702163953Srrs			}
703163953Srrs			if (lnet->flight_size != tot_out) {
704207099Stuexen				SCTP_PRINTF("net:%p flight was %d corrected to %d\n",
705240148Stuexen				    (void *)lnet, lnet->flight_size,
706169420Srrs				    tot_out);
707163953Srrs				lnet->flight_size = tot_out;
708163953Srrs			}
709163953Srrs		}
710163953Srrs	}
711163953Srrs	if (rep) {
712163953Srrs		sctp_print_audit_report();
713163953Srrs	}
714163953Srrs}
715163953Srrs
716163953Srrsvoid
717163953Srrssctp_audit_log(uint8_t ev, uint8_t fd)
718163953Srrs{
719163953Srrs
720163953Srrs	sctp_audit_data[sctp_audit_indx][0] = ev;
721163953Srrs	sctp_audit_data[sctp_audit_indx][1] = fd;
722163953Srrs	sctp_audit_indx++;
723163953Srrs	if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
724163953Srrs		sctp_audit_indx = 0;
725163953Srrs	}
726163953Srrs}
727163953Srrs
728163953Srrs#endif
729163953Srrs
730163953Srrs/*
731214918Stuexen * sctp_stop_timers_for_shutdown() should be called
732214918Stuexen * when entering the SHUTDOWN_SENT or SHUTDOWN_ACK_SENT
733214918Stuexen * state to make sure that all timers are stopped.
734214918Stuexen */
735214918Stuexenvoid
736214918Stuexensctp_stop_timers_for_shutdown(struct sctp_tcb *stcb)
737214918Stuexen{
738214918Stuexen	struct sctp_association *asoc;
739214918Stuexen	struct sctp_nets *net;
740214918Stuexen
741214918Stuexen	asoc = &stcb->asoc;
742214918Stuexen
743214918Stuexen	(void)SCTP_OS_TIMER_STOP(&asoc->dack_timer.timer);
744214918Stuexen	(void)SCTP_OS_TIMER_STOP(&asoc->strreset_timer.timer);
745214918Stuexen	(void)SCTP_OS_TIMER_STOP(&asoc->asconf_timer.timer);
746214918Stuexen	(void)SCTP_OS_TIMER_STOP(&asoc->autoclose_timer.timer);
747214918Stuexen	(void)SCTP_OS_TIMER_STOP(&asoc->delayed_event_timer.timer);
748214918Stuexen	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
749214918Stuexen		(void)SCTP_OS_TIMER_STOP(&net->pmtu_timer.timer);
750224641Stuexen		(void)SCTP_OS_TIMER_STOP(&net->hb_timer.timer);
751214918Stuexen	}
752214918Stuexen}
753214918Stuexen
754214918Stuexen/*
755163953Srrs * a list of sizes based on typical mtu's, used only if next hop size not
756163953Srrs * returned.
757163953Srrs */
758214939Stuexenstatic uint32_t sctp_mtu_sizes[] = {
759163953Srrs	68,
760163953Srrs	296,
761163953Srrs	508,
762163953Srrs	512,
763163953Srrs	544,
764163953Srrs	576,
765163953Srrs	1006,
766163953Srrs	1492,
767163953Srrs	1500,
768163953Srrs	1536,
769163953Srrs	2002,
770163953Srrs	2048,
771163953Srrs	4352,
772163953Srrs	4464,
773163953Srrs	8166,
774163953Srrs	17914,
775163953Srrs	32000,
776163953Srrs	65535
777163953Srrs};
778163953Srrs
779214939Stuexen/*
780214939Stuexen * Return the largest MTU smaller than val. If there is no
781214939Stuexen * entry, just return val.
782214939Stuexen */
783214939Stuexenuint32_t
784214939Stuexensctp_get_prev_mtu(uint32_t val)
785163953Srrs{
786214939Stuexen	uint32_t i;
787163953Srrs
788214939Stuexen	if (val <= sctp_mtu_sizes[0]) {
789214939Stuexen		return (val);
790214939Stuexen	}
791214939Stuexen	for (i = 1; i < (sizeof(sctp_mtu_sizes) / sizeof(uint32_t)); i++) {
792214939Stuexen		if (val <= sctp_mtu_sizes[i]) {
793163953Srrs			break;
794163953Srrs		}
795163953Srrs	}
796214939Stuexen	return (sctp_mtu_sizes[i - 1]);
797163953Srrs}
798163953Srrs
799214939Stuexen/*
800214939Stuexen * Return the smallest MTU larger than val. If there is no
801214939Stuexen * entry, just return val.
802214939Stuexen */
803214939Stuexenuint32_t
804228653Stuexensctp_get_next_mtu(uint32_t val)
805214939Stuexen{
806214939Stuexen	/* select another MTU that is just bigger than this one */
807214939Stuexen	uint32_t i;
808214939Stuexen
809214939Stuexen	for (i = 0; i < (sizeof(sctp_mtu_sizes) / sizeof(uint32_t)); i++) {
810214939Stuexen		if (val < sctp_mtu_sizes[i]) {
811214939Stuexen			return (sctp_mtu_sizes[i]);
812214939Stuexen		}
813214939Stuexen	}
814214939Stuexen	return (val);
815214939Stuexen}
816214939Stuexen
817163953Srrsvoid
818163953Srrssctp_fill_random_store(struct sctp_pcb *m)
819163953Srrs{
820163953Srrs	/*
821163953Srrs	 * Here we use the MD5/SHA-1 to hash with our good randomNumbers and
822163953Srrs	 * our counter. The result becomes our good random numbers and we
823163953Srrs	 * then setup to give these out. Note that we do no locking to
824163953Srrs	 * protect this. This is ok, since if competing folks call this we
825169352Srrs	 * will get more gobbled gook in the random store which is what we
826163953Srrs	 * want. There is a danger that two guys will use the same random
827163953Srrs	 * numbers, but thats ok too since that is random as well :->
828163953Srrs	 */
829163953Srrs	m->store_at = 0;
830169420Srrs	(void)sctp_hmac(SCTP_HMAC, (uint8_t *) m->random_numbers,
831163953Srrs	    sizeof(m->random_numbers), (uint8_t *) & m->random_counter,
832163953Srrs	    sizeof(m->random_counter), (uint8_t *) m->random_store);
833163953Srrs	m->random_counter++;
834163953Srrs}
835163953Srrs
836163953Srrsuint32_t
837172091Srrssctp_select_initial_TSN(struct sctp_pcb *inp)
838163953Srrs{
839163953Srrs	/*
840163953Srrs	 * A true implementation should use random selection process to get
841163953Srrs	 * the initial stream sequence number, using RFC1750 as a good
842163953Srrs	 * guideline
843163953Srrs	 */
844165647Srrs	uint32_t x, *xp;
845163953Srrs	uint8_t *p;
846172091Srrs	int store_at, new_store;
847163953Srrs
848172091Srrs	if (inp->initial_sequence_debug != 0) {
849163953Srrs		uint32_t ret;
850163953Srrs
851172091Srrs		ret = inp->initial_sequence_debug;
852172091Srrs		inp->initial_sequence_debug++;
853163953Srrs		return (ret);
854163953Srrs	}
855172091Srrsretry:
856172091Srrs	store_at = inp->store_at;
857172091Srrs	new_store = store_at + sizeof(uint32_t);
858172091Srrs	if (new_store >= (SCTP_SIGNATURE_SIZE - 3)) {
859172091Srrs		new_store = 0;
860172091Srrs	}
861172091Srrs	if (!atomic_cmpset_int(&inp->store_at, store_at, new_store)) {
862172091Srrs		goto retry;
863172091Srrs	}
864172091Srrs	if (new_store == 0) {
865163953Srrs		/* Refill the random store */
866172091Srrs		sctp_fill_random_store(inp);
867163953Srrs	}
868172091Srrs	p = &inp->random_store[store_at];
869165647Srrs	xp = (uint32_t *) p;
870163953Srrs	x = *xp;
871163953Srrs	return (x);
872163953Srrs}
873163953Srrs
874163953Srrsuint32_t
875228653Stuexensctp_select_a_tag(struct sctp_inpcb *inp, uint16_t lport, uint16_t rport, int check)
876163953Srrs{
877228653Stuexen	uint32_t x;
878163953Srrs	struct timeval now;
879163953Srrs
880228653Stuexen	if (check) {
881228653Stuexen		(void)SCTP_GETTIME_TIMEVAL(&now);
882228653Stuexen	}
883228653Stuexen	for (;;) {
884172091Srrs		x = sctp_select_initial_TSN(&inp->sctp_ep);
885163953Srrs		if (x == 0) {
886163953Srrs			/* we never use 0 */
887163953Srrs			continue;
888163953Srrs		}
889228653Stuexen		if (!check || sctp_is_vtag_good(x, lport, rport, &now)) {
890228653Stuexen			break;
891163953Srrs		}
892163953Srrs	}
893163953Srrs	return (x);
894163953Srrs}
895163953Srrs
896294149Stuexenint32_t
897294149Stuexensctp_map_assoc_state(int kernel_state)
898294149Stuexen{
899294149Stuexen	int32_t user_state;
900294149Stuexen
901294149Stuexen	if (kernel_state & SCTP_STATE_WAS_ABORTED) {
902294149Stuexen		user_state = SCTP_CLOSED;
903294149Stuexen	} else if (kernel_state & SCTP_STATE_SHUTDOWN_PENDING) {
904294149Stuexen		user_state = SCTP_SHUTDOWN_PENDING;
905294149Stuexen	} else {
906294149Stuexen		switch (kernel_state & SCTP_STATE_MASK) {
907294149Stuexen		case SCTP_STATE_EMPTY:
908294149Stuexen			user_state = SCTP_CLOSED;
909294149Stuexen			break;
910294149Stuexen		case SCTP_STATE_INUSE:
911294149Stuexen			user_state = SCTP_CLOSED;
912294149Stuexen			break;
913294149Stuexen		case SCTP_STATE_COOKIE_WAIT:
914294149Stuexen			user_state = SCTP_COOKIE_WAIT;
915294149Stuexen			break;
916294149Stuexen		case SCTP_STATE_COOKIE_ECHOED:
917294149Stuexen			user_state = SCTP_COOKIE_ECHOED;
918294149Stuexen			break;
919294149Stuexen		case SCTP_STATE_OPEN:
920294149Stuexen			user_state = SCTP_ESTABLISHED;
921294149Stuexen			break;
922294149Stuexen		case SCTP_STATE_SHUTDOWN_SENT:
923294149Stuexen			user_state = SCTP_SHUTDOWN_SENT;
924294149Stuexen			break;
925294149Stuexen		case SCTP_STATE_SHUTDOWN_RECEIVED:
926294149Stuexen			user_state = SCTP_SHUTDOWN_RECEIVED;
927294149Stuexen			break;
928294149Stuexen		case SCTP_STATE_SHUTDOWN_ACK_SENT:
929294149Stuexen			user_state = SCTP_SHUTDOWN_ACK_SENT;
930294149Stuexen			break;
931294149Stuexen		default:
932294149Stuexen			user_state = SCTP_CLOSED;
933294149Stuexen			break;
934294149Stuexen		}
935294149Stuexen	}
936294149Stuexen	return (user_state);
937294149Stuexen}
938294149Stuexen
939163953Srrsint
940246595Stuexensctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
941294215Stuexen    uint32_t override_tag, uint32_t vrf_id, uint16_t o_strms)
942163953Srrs{
943170138Srrs	struct sctp_association *asoc;
944170138Srrs
945163953Srrs	/*
946163953Srrs	 * Anything set to zero is taken care of by the allocation routine's
947163953Srrs	 * bzero
948163953Srrs	 */
949163953Srrs
950163953Srrs	/*
951163953Srrs	 * Up front select what scoping to apply on addresses I tell my peer
952163953Srrs	 * Not sure what to do with these right now, we will need to come up
953163953Srrs	 * with a way to set them. We may need to pass them through from the
954163953Srrs	 * caller in the sctp_aloc_assoc() function.
955163953Srrs	 */
956163953Srrs	int i;
957163953Srrs
958270363Stuexen#if defined(SCTP_DETAILED_STR_STATS)
959270363Stuexen	int j;
960270363Stuexen
961270363Stuexen#endif
962270363Stuexen
963170138Srrs	asoc = &stcb->asoc;
964163953Srrs	/* init all variables to a known value. */
965171943Srrs	SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_INUSE);
966246595Stuexen	asoc->max_burst = inp->sctp_ep.max_burst;
967246595Stuexen	asoc->fr_max_burst = inp->sctp_ep.fr_max_burst;
968246595Stuexen	asoc->heart_beat_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]);
969246595Stuexen	asoc->cookie_life = inp->sctp_ep.def_cookie_life;
970246595Stuexen	asoc->sctp_cmt_on_off = inp->sctp_cmt_on_off;
971270356Stuexen	asoc->ecn_supported = inp->ecn_supported;
972270357Stuexen	asoc->prsctp_supported = inp->prsctp_supported;
973270362Stuexen	asoc->auth_supported = inp->auth_supported;
974270362Stuexen	asoc->asconf_supported = inp->asconf_supported;
975270361Stuexen	asoc->reconfig_supported = inp->reconfig_supported;
976270359Stuexen	asoc->nrsack_supported = inp->nrsack_supported;
977270360Stuexen	asoc->pktdrop_supported = inp->pktdrop_supported;
978224641Stuexen	asoc->sctp_cmt_pf = (uint8_t) 0;
979246595Stuexen	asoc->sctp_frag_point = inp->sctp_frag_point;
980246595Stuexen	asoc->sctp_features = inp->sctp_features;
981246595Stuexen	asoc->default_dscp = inp->sctp_ep.default_dscp;
982283724Stuexen	asoc->max_cwnd = inp->max_cwnd;
983167598Srrs#ifdef INET6
984246595Stuexen	if (inp->sctp_ep.default_flowlabel) {
985246595Stuexen		asoc->default_flowlabel = inp->sctp_ep.default_flowlabel;
986225549Stuexen	} else {
987246595Stuexen		if (inp->ip_inp.inp.inp_flags & IN6P_AUTOFLOWLABEL) {
988246595Stuexen			asoc->default_flowlabel = sctp_select_initial_TSN(&inp->sctp_ep);
989225549Stuexen			asoc->default_flowlabel &= 0x000fffff;
990225549Stuexen			asoc->default_flowlabel |= 0x80000000;
991225549Stuexen		} else {
992225549Stuexen			asoc->default_flowlabel = 0;
993225549Stuexen		}
994225549Stuexen	}
995163953Srrs#endif
996174257Srrs	asoc->sb_send_resv = 0;
997163953Srrs	if (override_tag) {
998185694Srrs		asoc->my_vtag = override_tag;
999163953Srrs	} else {
1000246595Stuexen		asoc->my_vtag = sctp_select_a_tag(inp, stcb->sctp_ep->sctp_lport, stcb->rport, 1);
1001163953Srrs	}
1002164144Srrs	/* Get the nonce tags */
1003246595Stuexen	asoc->my_vtag_nonce = sctp_select_a_tag(inp, stcb->sctp_ep->sctp_lport, stcb->rport, 0);
1004246595Stuexen	asoc->peer_vtag_nonce = sctp_select_a_tag(inp, stcb->sctp_ep->sctp_lport, stcb->rport, 0);
1005167598Srrs	asoc->vrf_id = vrf_id;
1006164144Srrs
1007171477Srrs#ifdef SCTP_ASOCLOG_OF_TSNS
1008171477Srrs	asoc->tsn_in_at = 0;
1009171477Srrs	asoc->tsn_out_at = 0;
1010171477Srrs	asoc->tsn_in_wrapped = 0;
1011171477Srrs	asoc->tsn_out_wrapped = 0;
1012171477Srrs	asoc->cumack_log_at = 0;
1013172703Srrs	asoc->cumack_log_atsnt = 0;
1014171477Srrs#endif
1015171477Srrs#ifdef SCTP_FS_SPEC_LOG
1016171477Srrs	asoc->fs_index = 0;
1017171477Srrs#endif
1018163953Srrs	asoc->refcnt = 0;
1019163953Srrs	asoc->assoc_up_sent = 0;
1020163953Srrs	asoc->asconf_seq_out = asoc->str_reset_seq_out = asoc->init_seq_number = asoc->sending_seq =
1021246595Stuexen	    sctp_select_initial_TSN(&inp->sctp_ep);
1022179157Srrs	asoc->asconf_seq_out_acked = asoc->asconf_seq_out - 1;
1023163953Srrs	/* we are optimisitic here */
1024185694Srrs	asoc->peer_supports_nat = 0;
1025163953Srrs	asoc->sent_queue_retran_cnt = 0;
1026163953Srrs
1027163953Srrs	/* for CMT */
1028190689Srrs	asoc->last_net_cmt_send_started = NULL;
1029163953Srrs
1030163953Srrs	/* This will need to be adjusted */
1031163953Srrs	asoc->last_acked_seq = asoc->init_seq_number - 1;
1032163953Srrs	asoc->advanced_peer_ack_point = asoc->last_acked_seq;
1033163953Srrs	asoc->asconf_seq_in = asoc->last_acked_seq;
1034163953Srrs
1035163953Srrs	/* here we are different, we hold the next one we expect */
1036163953Srrs	asoc->str_reset_seq_in = asoc->last_acked_seq + 1;
1037163953Srrs
1038246595Stuexen	asoc->initial_init_rto_max = inp->sctp_ep.initial_init_rto_max;
1039246595Stuexen	asoc->initial_rto = inp->sctp_ep.initial_rto;
1040163953Srrs
1041246595Stuexen	asoc->max_init_times = inp->sctp_ep.max_init_times;
1042246595Stuexen	asoc->max_send_times = inp->sctp_ep.max_send_times;
1043246595Stuexen	asoc->def_net_failure = inp->sctp_ep.def_net_failure;
1044246595Stuexen	asoc->def_net_pf_threshold = inp->sctp_ep.def_net_pf_threshold;
1045163953Srrs	asoc->free_chunk_cnt = 0;
1046163953Srrs
1047163953Srrs	asoc->iam_blocking = 0;
1048246595Stuexen	asoc->context = inp->sctp_context;
1049246595Stuexen	asoc->local_strreset_support = inp->local_strreset_support;
1050246595Stuexen	asoc->def_send = inp->def_send;
1051246595Stuexen	asoc->delayed_ack = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]);
1052246595Stuexen	asoc->sack_freq = inp->sctp_ep.sctp_sack_freq;
1053163953Srrs	asoc->pr_sctp_cnt = 0;
1054163953Srrs	asoc->total_output_queue_size = 0;
1055163953Srrs
1056246595Stuexen	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
1057246595Stuexen		asoc->scope.ipv6_addr_legal = 1;
1058246595Stuexen		if (SCTP_IPV6_V6ONLY(inp) == 0) {
1059246595Stuexen			asoc->scope.ipv4_addr_legal = 1;
1060163953Srrs		} else {
1061246595Stuexen			asoc->scope.ipv4_addr_legal = 0;
1062163953Srrs		}
1063163953Srrs	} else {
1064246595Stuexen		asoc->scope.ipv6_addr_legal = 0;
1065246595Stuexen		asoc->scope.ipv4_addr_legal = 1;
1066163953Srrs	}
1067163953Srrs
1068246595Stuexen	asoc->my_rwnd = max(SCTP_SB_LIMIT_RCV(inp->sctp_socket), SCTP_MINIMAL_RWND);
1069246595Stuexen	asoc->peers_rwnd = SCTP_SB_LIMIT_RCV(inp->sctp_socket);
1070163953Srrs
1071246595Stuexen	asoc->smallest_mtu = inp->sctp_frag_point;
1072246595Stuexen	asoc->minrto = inp->sctp_ep.sctp_minrto;
1073246595Stuexen	asoc->maxrto = inp->sctp_ep.sctp_maxrto;
1074163953Srrs
1075163953Srrs	asoc->locked_on_sending = NULL;
1076163953Srrs	asoc->stream_locked_on = 0;
1077163953Srrs	asoc->ecn_echo_cnt_onq = 0;
1078163953Srrs	asoc->stream_locked = 0;
1079163953Srrs
1080167598Srrs	asoc->send_sack = 1;
1081167598Srrs
1082167598Srrs	LIST_INIT(&asoc->sctp_restricted_addrs);
1083167598Srrs
1084163953Srrs	TAILQ_INIT(&asoc->nets);
1085163953Srrs	TAILQ_INIT(&asoc->pending_reply_queue);
1086171990Srrs	TAILQ_INIT(&asoc->asconf_ack_sent);
1087163953Srrs	/* Setup to fill the hb random cache at first HB */
1088163953Srrs	asoc->hb_random_idx = 4;
1089163953Srrs
1090246595Stuexen	asoc->sctp_autoclose_ticks = inp->sctp_ep.auto_close_time;
1091163953Srrs
1092246595Stuexen	stcb->asoc.congestion_control_module = inp->sctp_ep.sctp_default_cc_module;
1093246595Stuexen	stcb->asoc.cc_functions = sctp_cc_functions[inp->sctp_ep.sctp_default_cc_module];
1094171440Srrs
1095246595Stuexen	stcb->asoc.stream_scheduling_module = inp->sctp_ep.sctp_default_ss_module;
1096246595Stuexen	stcb->asoc.ss_functions = sctp_ss_functions[inp->sctp_ep.sctp_default_ss_module];
1097217760Stuexen
1098171440Srrs	/*
1099163953Srrs	 * Now the stream parameters, here we allocate space for all streams
1100163953Srrs	 * that we request by default.
1101163953Srrs	 */
1102188854Srrs	asoc->strm_realoutsize = asoc->streamoutcnt = asoc->pre_open_streams =
1103294215Stuexen	    o_strms;
1104163953Srrs	SCTP_MALLOC(asoc->strmout, struct sctp_stream_out *,
1105163953Srrs	    asoc->streamoutcnt * sizeof(struct sctp_stream_out),
1106170091Srrs	    SCTP_M_STRMO);
1107163953Srrs	if (asoc->strmout == NULL) {
1108163953Srrs		/* big trouble no memory */
1109171943Srrs		SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM);
1110163953Srrs		return (ENOMEM);
1111163953Srrs	}
1112163953Srrs	for (i = 0; i < asoc->streamoutcnt; i++) {
1113163953Srrs		/*
1114163953Srrs		 * inbound side must be set to 0xffff, also NOTE when we get
1115163953Srrs		 * the INIT-ACK back (for INIT sender) we MUST reduce the
1116163953Srrs		 * count (streamoutcnt) but first check if we sent to any of
1117163953Srrs		 * the upper streams that were dropped (if some were). Those
1118163953Srrs		 * that were dropped must be notified to the upper layer as
1119163953Srrs		 * failed to send.
1120163953Srrs		 */
1121242627Stuexen		asoc->strmout[i].next_sequence_send = 0x0;
1122163953Srrs		TAILQ_INIT(&asoc->strmout[i].outqueue);
1123243157Stuexen		asoc->strmout[i].chunks_on_queues = 0;
1124270363Stuexen#if defined(SCTP_DETAILED_STR_STATS)
1125270363Stuexen		for (j = 0; j < SCTP_PR_SCTP_MAX + 1; j++) {
1126270363Stuexen			asoc->strmout[i].abandoned_sent[j] = 0;
1127270363Stuexen			asoc->strmout[i].abandoned_unsent[j] = 0;
1128270363Stuexen		}
1129270363Stuexen#else
1130270363Stuexen		asoc->strmout[i].abandoned_sent[0] = 0;
1131270363Stuexen		asoc->strmout[i].abandoned_unsent[0] = 0;
1132270363Stuexen#endif
1133163953Srrs		asoc->strmout[i].stream_no = i;
1134163953Srrs		asoc->strmout[i].last_msg_incomplete = 0;
1135294140Stuexen		asoc->strmout[i].state = SCTP_STREAM_OPENING;
1136218241Stuexen		asoc->ss_functions.sctp_ss_init_stream(&asoc->strmout[i], NULL);
1137163953Srrs	}
1138217760Stuexen	asoc->ss_functions.sctp_ss_init(stcb, asoc, 0);
1139217760Stuexen
1140163953Srrs	/* Now the mapping array */
1141163953Srrs	asoc->mapping_array_size = SCTP_INITIAL_MAPPING_ARRAY;
1142163953Srrs	SCTP_MALLOC(asoc->mapping_array, uint8_t *, asoc->mapping_array_size,
1143170091Srrs	    SCTP_M_MAP);
1144163953Srrs	if (asoc->mapping_array == NULL) {
1145170091Srrs		SCTP_FREE(asoc->strmout, SCTP_M_STRMO);
1146171943Srrs		SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM);
1147163953Srrs		return (ENOMEM);
1148163953Srrs	}
1149163953Srrs	memset(asoc->mapping_array, 0, asoc->mapping_array_size);
1150206137Stuexen	SCTP_MALLOC(asoc->nr_mapping_array, uint8_t *, asoc->mapping_array_size,
1151185694Srrs	    SCTP_M_MAP);
1152193089Srrs	if (asoc->nr_mapping_array == NULL) {
1153193089Srrs		SCTP_FREE(asoc->strmout, SCTP_M_STRMO);
1154193089Srrs		SCTP_FREE(asoc->mapping_array, SCTP_M_MAP);
1155193089Srrs		SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM);
1156193089Srrs		return (ENOMEM);
1157193089Srrs	}
1158206137Stuexen	memset(asoc->nr_mapping_array, 0, asoc->mapping_array_size);
1159185694Srrs
1160163953Srrs	/* Now the init of the other outqueues */
1161163953Srrs	TAILQ_INIT(&asoc->free_chunks);
1162163953Srrs	TAILQ_INIT(&asoc->control_send_queue);
1163179157Srrs	TAILQ_INIT(&asoc->asconf_send_queue);
1164163953Srrs	TAILQ_INIT(&asoc->send_queue);
1165163953Srrs	TAILQ_INIT(&asoc->sent_queue);
1166163953Srrs	TAILQ_INIT(&asoc->reasmqueue);
1167163953Srrs	TAILQ_INIT(&asoc->resetHead);
1168246595Stuexen	asoc->max_inbound_streams = inp->sctp_ep.max_open_streams_intome;
1169163953Srrs	TAILQ_INIT(&asoc->asconf_queue);
1170163953Srrs	/* authentication fields */
1171163953Srrs	asoc->authinfo.random = NULL;
1172185694Srrs	asoc->authinfo.active_keyid = 0;
1173163953Srrs	asoc->authinfo.assoc_key = NULL;
1174163953Srrs	asoc->authinfo.assoc_keyid = 0;
1175163953Srrs	asoc->authinfo.recv_key = NULL;
1176163953Srrs	asoc->authinfo.recv_keyid = 0;
1177163953Srrs	LIST_INIT(&asoc->shared_keys);
1178166675Srrs	asoc->marked_retrans = 0;
1179246595Stuexen	asoc->port = inp->sctp_ep.port;
1180166675Srrs	asoc->timoinit = 0;
1181166675Srrs	asoc->timodata = 0;
1182166675Srrs	asoc->timosack = 0;
1183166675Srrs	asoc->timoshutdown = 0;
1184166675Srrs	asoc->timoheartbeat = 0;
1185166675Srrs	asoc->timocookie = 0;
1186166675Srrs	asoc->timoshutdownack = 0;
1187169378Srrs	(void)SCTP_GETTIME_TIMEVAL(&asoc->start_time);
1188169378Srrs	asoc->discontinuity_time = asoc->start_time;
1189270363Stuexen	for (i = 0; i < SCTP_PR_SCTP_MAX + 1; i++) {
1190270363Stuexen		asoc->abandoned_unsent[i] = 0;
1191270363Stuexen		asoc->abandoned_sent[i] = 0;
1192270363Stuexen	}
1193170931Srrs	/*
1194170931Srrs	 * sa_ignore MEMLEAK {memory is put in the assoc mapping array and
1195205627Srrs	 * freed later when the association is freed.
1196170931Srrs	 */
1197163953Srrs	return (0);
1198163953Srrs}
1199163953Srrs
1200205502Srrsvoid
1201205502Srrssctp_print_mapping_array(struct sctp_association *asoc)
1202205502Srrs{
1203206281Stuexen	unsigned int i, limit;
1204205502Srrs
1205234995Stuexen	SCTP_PRINTF("Mapping array size: %d, baseTSN: %8.8x, cumAck: %8.8x, highestTSN: (%8.8x, %8.8x).\n",
1206205502Srrs	    asoc->mapping_array_size,
1207205502Srrs	    asoc->mapping_array_base_tsn,
1208205502Srrs	    asoc->cumulative_tsn,
1209206281Stuexen	    asoc->highest_tsn_inside_map,
1210206281Stuexen	    asoc->highest_tsn_inside_nr_map);
1211206281Stuexen	for (limit = asoc->mapping_array_size; limit > 1; limit--) {
1212228907Stuexen		if (asoc->mapping_array[limit - 1] != 0) {
1213205627Srrs			break;
1214205627Srrs		}
1215205627Srrs	}
1216234995Stuexen	SCTP_PRINTF("Renegable mapping array (last %d entries are zero):\n", asoc->mapping_array_size - limit);
1217205627Srrs	for (i = 0; i < limit; i++) {
1218234995Stuexen		SCTP_PRINTF("%2.2x%c", asoc->mapping_array[i], ((i + 1) % 16) ? ' ' : '\n');
1219205502Srrs	}
1220206281Stuexen	if (limit % 16)
1221234995Stuexen		SCTP_PRINTF("\n");
1222206281Stuexen	for (limit = asoc->mapping_array_size; limit > 1; limit--) {
1223206281Stuexen		if (asoc->nr_mapping_array[limit - 1]) {
1224205627Srrs			break;
1225205627Srrs		}
1226205627Srrs	}
1227234995Stuexen	SCTP_PRINTF("Non renegable mapping array (last %d entries are zero):\n", asoc->mapping_array_size - limit);
1228205627Srrs	for (i = 0; i < limit; i++) {
1229234995Stuexen		SCTP_PRINTF("%2.2x%c", asoc->nr_mapping_array[i], ((i + 1) % 16) ? ' ' : '\n');
1230205627Srrs	}
1231206281Stuexen	if (limit % 16)
1232234995Stuexen		SCTP_PRINTF("\n");
1233205502Srrs}
1234205502Srrs
1235163953Srrsint
1236170138Srrssctp_expand_mapping_array(struct sctp_association *asoc, uint32_t needed)
1237163953Srrs{
1238163953Srrs	/* mapping array needs to grow */
1239206137Stuexen	uint8_t *new_array1, *new_array2;
1240170138Srrs	uint32_t new_size;
1241163953Srrs
1242170138Srrs	new_size = asoc->mapping_array_size + ((needed + 7) / 8 + SCTP_MAPPING_ARRAY_INCR);
1243206137Stuexen	SCTP_MALLOC(new_array1, uint8_t *, new_size, SCTP_M_MAP);
1244206137Stuexen	SCTP_MALLOC(new_array2, uint8_t *, new_size, SCTP_M_MAP);
1245206137Stuexen	if ((new_array1 == NULL) || (new_array2 == NULL)) {
1246163953Srrs		/* can't get more, forget it */
1247206137Stuexen		SCTP_PRINTF("No memory for expansion of SCTP mapping array %d\n", new_size);
1248206137Stuexen		if (new_array1) {
1249206137Stuexen			SCTP_FREE(new_array1, SCTP_M_MAP);
1250206137Stuexen		}
1251206137Stuexen		if (new_array2) {
1252206137Stuexen			SCTP_FREE(new_array2, SCTP_M_MAP);
1253206137Stuexen		}
1254163953Srrs		return (-1);
1255163953Srrs	}
1256206137Stuexen	memset(new_array1, 0, new_size);
1257206137Stuexen	memset(new_array2, 0, new_size);
1258206137Stuexen	memcpy(new_array1, asoc->mapping_array, asoc->mapping_array_size);
1259206137Stuexen	memcpy(new_array2, asoc->nr_mapping_array, asoc->mapping_array_size);
1260170091Srrs	SCTP_FREE(asoc->mapping_array, SCTP_M_MAP);
1261206137Stuexen	SCTP_FREE(asoc->nr_mapping_array, SCTP_M_MAP);
1262206137Stuexen	asoc->mapping_array = new_array1;
1263206137Stuexen	asoc->nr_mapping_array = new_array2;
1264163953Srrs	asoc->mapping_array_size = new_size;
1265163953Srrs	return (0);
1266163953Srrs}
1267163953Srrs
1268185694Srrs
1269167598Srrsstatic void
1270167598Srrssctp_iterator_work(struct sctp_iterator *it)
1271167598Srrs{
1272167598Srrs	int iteration_count = 0;
1273167598Srrs	int inp_skip = 0;
1274209029Srrs	int first_in = 1;
1275209029Srrs	struct sctp_inpcb *tinp;
1276163953Srrs
1277209029Srrs	SCTP_INP_INFO_RLOCK();
1278167598Srrs	SCTP_ITERATOR_LOCK();
1279169420Srrs	if (it->inp) {
1280209029Srrs		SCTP_INP_RLOCK(it->inp);
1281167598Srrs		SCTP_INP_DECR_REF(it->inp);
1282169420Srrs	}
1283167598Srrs	if (it->inp == NULL) {
1284167598Srrs		/* iterator is complete */
1285167598Srrsdone_with_iterator:
1286167598Srrs		SCTP_ITERATOR_UNLOCK();
1287209029Srrs		SCTP_INP_INFO_RUNLOCK();
1288167598Srrs		if (it->function_atend != NULL) {
1289167598Srrs			(*it->function_atend) (it->pointer, it->val);
1290167598Srrs		}
1291170091Srrs		SCTP_FREE(it, SCTP_M_ITER);
1292167598Srrs		return;
1293167598Srrs	}
1294167598Srrsselect_a_new_ep:
1295209029Srrs	if (first_in) {
1296209029Srrs		first_in = 0;
1297209029Srrs	} else {
1298209029Srrs		SCTP_INP_RLOCK(it->inp);
1299209029Srrs	}
1300167598Srrs	while (((it->pcb_flags) &&
1301167598Srrs	    ((it->inp->sctp_flags & it->pcb_flags) != it->pcb_flags)) ||
1302167598Srrs	    ((it->pcb_features) &&
1303167598Srrs	    ((it->inp->sctp_features & it->pcb_features) != it->pcb_features))) {
1304167598Srrs		/* endpoint flags or features don't match, so keep looking */
1305167598Srrs		if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) {
1306208160Srrs			SCTP_INP_RUNLOCK(it->inp);
1307167598Srrs			goto done_with_iterator;
1308167598Srrs		}
1309209029Srrs		tinp = it->inp;
1310167598Srrs		it->inp = LIST_NEXT(it->inp, sctp_list);
1311209029Srrs		SCTP_INP_RUNLOCK(tinp);
1312167598Srrs		if (it->inp == NULL) {
1313167598Srrs			goto done_with_iterator;
1314167598Srrs		}
1315208160Srrs		SCTP_INP_RLOCK(it->inp);
1316167598Srrs	}
1317167598Srrs	/* now go through each assoc which is in the desired state */
1318167598Srrs	if (it->done_current_ep == 0) {
1319167598Srrs		if (it->function_inp != NULL)
1320167598Srrs			inp_skip = (*it->function_inp) (it->inp, it->pointer, it->val);
1321167598Srrs		it->done_current_ep = 1;
1322167598Srrs	}
1323167598Srrs	if (it->stcb == NULL) {
1324167598Srrs		/* run the per instance function */
1325167598Srrs		it->stcb = LIST_FIRST(&it->inp->sctp_asoc_list);
1326167598Srrs	}
1327167598Srrs	if ((inp_skip) || it->stcb == NULL) {
1328167598Srrs		if (it->function_inp_end != NULL) {
1329167598Srrs			inp_skip = (*it->function_inp_end) (it->inp,
1330167598Srrs			    it->pointer,
1331167598Srrs			    it->val);
1332167598Srrs		}
1333167598Srrs		SCTP_INP_RUNLOCK(it->inp);
1334167598Srrs		goto no_stcb;
1335167598Srrs	}
1336167598Srrs	while (it->stcb) {
1337167598Srrs		SCTP_TCB_LOCK(it->stcb);
1338167598Srrs		if (it->asoc_state && ((it->stcb->asoc.state & it->asoc_state) != it->asoc_state)) {
1339167598Srrs			/* not in the right state... keep looking */
1340167598Srrs			SCTP_TCB_UNLOCK(it->stcb);
1341167598Srrs			goto next_assoc;
1342167598Srrs		}
1343167598Srrs		/* see if we have limited out the iterator loop */
1344167598Srrs		iteration_count++;
1345167598Srrs		if (iteration_count > SCTP_ITERATOR_MAX_AT_ONCE) {
1346167598Srrs			/* Pause to let others grab the lock */
1347167598Srrs			atomic_add_int(&it->stcb->asoc.refcnt, 1);
1348167598Srrs			SCTP_TCB_UNLOCK(it->stcb);
1349171943Srrs			SCTP_INP_INCR_REF(it->inp);
1350167598Srrs			SCTP_INP_RUNLOCK(it->inp);
1351167598Srrs			SCTP_ITERATOR_UNLOCK();
1352209029Srrs			SCTP_INP_INFO_RUNLOCK();
1353209029Srrs			SCTP_INP_INFO_RLOCK();
1354167598Srrs			SCTP_ITERATOR_LOCK();
1355208160Srrs			if (sctp_it_ctl.iterator_flags) {
1356208160Srrs				/* We won't be staying here */
1357208160Srrs				SCTP_INP_DECR_REF(it->inp);
1358208160Srrs				atomic_add_int(&it->stcb->asoc.refcnt, -1);
1359208160Srrs				if (sctp_it_ctl.iterator_flags &
1360208160Srrs				    SCTP_ITERATOR_STOP_CUR_IT) {
1361208160Srrs					sctp_it_ctl.iterator_flags &= ~SCTP_ITERATOR_STOP_CUR_IT;
1362208160Srrs					goto done_with_iterator;
1363208160Srrs				}
1364208160Srrs				if (sctp_it_ctl.iterator_flags &
1365208160Srrs				    SCTP_ITERATOR_STOP_CUR_INP) {
1366208160Srrs					sctp_it_ctl.iterator_flags &= ~SCTP_ITERATOR_STOP_CUR_INP;
1367208160Srrs					goto no_stcb;
1368208160Srrs				}
1369208160Srrs				/* If we reach here huh? */
1370234995Stuexen				SCTP_PRINTF("Unknown it ctl flag %x\n",
1371208160Srrs				    sctp_it_ctl.iterator_flags);
1372208160Srrs				sctp_it_ctl.iterator_flags = 0;
1373208160Srrs			}
1374167598Srrs			SCTP_INP_RLOCK(it->inp);
1375171943Srrs			SCTP_INP_DECR_REF(it->inp);
1376167598Srrs			SCTP_TCB_LOCK(it->stcb);
1377167598Srrs			atomic_add_int(&it->stcb->asoc.refcnt, -1);
1378167598Srrs			iteration_count = 0;
1379167598Srrs		}
1380167598Srrs		/* run function on this one */
1381167598Srrs		(*it->function_assoc) (it->inp, it->stcb, it->pointer, it->val);
1382167598Srrs
1383167598Srrs		/*
1384167598Srrs		 * we lie here, it really needs to have its own type but
1385167598Srrs		 * first I must verify that this won't effect things :-0
1386167598Srrs		 */
1387167598Srrs		if (it->no_chunk_output == 0)
1388172090Srrs			sctp_chunk_output(it->inp, it->stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
1389167598Srrs
1390167598Srrs		SCTP_TCB_UNLOCK(it->stcb);
1391167598Srrsnext_assoc:
1392167598Srrs		it->stcb = LIST_NEXT(it->stcb, sctp_tcblist);
1393167598Srrs		if (it->stcb == NULL) {
1394167598Srrs			/* Run last function */
1395167598Srrs			if (it->function_inp_end != NULL) {
1396167598Srrs				inp_skip = (*it->function_inp_end) (it->inp,
1397167598Srrs				    it->pointer,
1398167598Srrs				    it->val);
1399167598Srrs			}
1400167598Srrs		}
1401167598Srrs	}
1402167598Srrs	SCTP_INP_RUNLOCK(it->inp);
1403167598Srrsno_stcb:
1404167598Srrs	/* done with all assocs on this endpoint, move on to next endpoint */
1405167598Srrs	it->done_current_ep = 0;
1406167598Srrs	if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) {
1407167598Srrs		it->inp = NULL;
1408167598Srrs	} else {
1409167598Srrs		it->inp = LIST_NEXT(it->inp, sctp_list);
1410167598Srrs	}
1411167598Srrs	if (it->inp == NULL) {
1412167598Srrs		goto done_with_iterator;
1413167598Srrs	}
1414167598Srrs	goto select_a_new_ep;
1415167598Srrs}
1416167598Srrs
1417167598Srrsvoid
1418167598Srrssctp_iterator_worker(void)
1419167598Srrs{
1420216822Stuexen	struct sctp_iterator *it, *nit;
1421167598Srrs
1422167598Srrs	/* This function is called with the WQ lock in place */
1423167598Srrs
1424208160Srrs	sctp_it_ctl.iterator_running = 1;
1425216822Stuexen	TAILQ_FOREACH_SAFE(it, &sctp_it_ctl.iteratorhead, sctp_nxt_itr, nit) {
1426216822Stuexen		sctp_it_ctl.cur_it = it;
1427167598Srrs		/* now lets work on this one */
1428208160Srrs		TAILQ_REMOVE(&sctp_it_ctl.iteratorhead, it, sctp_nxt_itr);
1429167598Srrs		SCTP_IPI_ITERATOR_WQ_UNLOCK();
1430208160Srrs		CURVNET_SET(it->vn);
1431167598Srrs		sctp_iterator_work(it);
1432219397Srrs		sctp_it_ctl.cur_it = NULL;
1433208160Srrs		CURVNET_RESTORE();
1434167598Srrs		SCTP_IPI_ITERATOR_WQ_LOCK();
1435169655Srrs		/* sa_ignore FREED_MEMORY */
1436167598Srrs	}
1437208160Srrs	sctp_it_ctl.iterator_running = 0;
1438167598Srrs	return;
1439167598Srrs}
1440167598Srrs
1441167598Srrs
1442163953Srrsstatic void
1443163953Srrssctp_handle_addr_wq(void)
1444163953Srrs{
1445163953Srrs	/* deal with the ADDR wq from the rtsock calls */
1446216822Stuexen	struct sctp_laddr *wi, *nwi;
1447167598Srrs	struct sctp_asconf_iterator *asc;
1448163953Srrs
1449167598Srrs	SCTP_MALLOC(asc, struct sctp_asconf_iterator *,
1450170091Srrs	    sizeof(struct sctp_asconf_iterator), SCTP_M_ASC_IT);
1451167598Srrs	if (asc == NULL) {
1452167598Srrs		/* Try later, no memory */
1453163953Srrs		sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ,
1454163953Srrs		    (struct sctp_inpcb *)NULL,
1455163953Srrs		    (struct sctp_tcb *)NULL,
1456163953Srrs		    (struct sctp_nets *)NULL);
1457167598Srrs		return;
1458163953Srrs	}
1459167598Srrs	LIST_INIT(&asc->list_of_work);
1460167598Srrs	asc->cnt = 0;
1461208160Srrs
1462208160Srrs	SCTP_WQ_ADDR_LOCK();
1463216822Stuexen	LIST_FOREACH_SAFE(wi, &SCTP_BASE_INFO(addr_wq), sctp_nxt_addr, nwi) {
1464167598Srrs		LIST_REMOVE(wi, sctp_nxt_addr);
1465167598Srrs		LIST_INSERT_HEAD(&asc->list_of_work, wi, sctp_nxt_addr);
1466167598Srrs		asc->cnt++;
1467163953Srrs	}
1468208160Srrs	SCTP_WQ_ADDR_UNLOCK();
1469208160Srrs
1470167598Srrs	if (asc->cnt == 0) {
1471170091Srrs		SCTP_FREE(asc, SCTP_M_ASC_IT);
1472167598Srrs	} else {
1473296052Stuexen		int ret;
1474296052Stuexen
1475296052Stuexen		ret = sctp_initiate_iterator(sctp_asconf_iterator_ep,
1476171572Srrs		    sctp_asconf_iterator_stcb,
1477167598Srrs		    NULL,	/* No ep end for boundall */
1478167598Srrs		    SCTP_PCB_FLAGS_BOUNDALL,
1479167598Srrs		    SCTP_PCB_ANY_FEATURES,
1480171572Srrs		    SCTP_ASOC_ANY_STATE,
1481171572Srrs		    (void *)asc, 0,
1482171572Srrs		    sctp_asconf_iterator_end, NULL, 0);
1483296052Stuexen		if (ret) {
1484296052Stuexen			SCTP_PRINTF("Failed to initiate iterator for handle_addr_wq\n");
1485296052Stuexen			/*
1486296052Stuexen			 * Freeing if we are stopping or put back on the
1487296052Stuexen			 * addr_wq.
1488296052Stuexen			 */
1489296052Stuexen			if (SCTP_BASE_VAR(sctp_pcb_initialized) == 0) {
1490296052Stuexen				sctp_asconf_iterator_end(asc, 0);
1491296052Stuexen			} else {
1492296052Stuexen				SCTP_WQ_ADDR_LOCK();
1493296052Stuexen				LIST_FOREACH(wi, &asc->list_of_work, sctp_nxt_addr) {
1494296052Stuexen					LIST_INSERT_HEAD(&SCTP_BASE_INFO(addr_wq), wi, sctp_nxt_addr);
1495296052Stuexen				}
1496296052Stuexen				SCTP_WQ_ADDR_UNLOCK();
1497296052Stuexen				SCTP_FREE(asc, SCTP_M_ASC_IT);
1498296052Stuexen			}
1499296052Stuexen		}
1500167598Srrs	}
1501163953Srrs}
1502163953Srrs
1503163953Srrsvoid
1504163953Srrssctp_timeout_handler(void *t)
1505163953Srrs{
1506163953Srrs	struct sctp_inpcb *inp;
1507163953Srrs	struct sctp_tcb *stcb;
1508163953Srrs	struct sctp_nets *net;
1509163953Srrs	struct sctp_timer *tmr;
1510294145Stuexen	struct mbuf *op_err;
1511172090Srrs
1512237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
1513172090Srrs	struct socket *so;
1514172090Srrs
1515172090Srrs#endif
1516283821Stuexen	int did_output;
1517294221Stuexen	int type;
1518163953Srrs
1519163953Srrs	tmr = (struct sctp_timer *)t;
1520163953Srrs	inp = (struct sctp_inpcb *)tmr->ep;
1521163953Srrs	stcb = (struct sctp_tcb *)tmr->tcb;
1522163953Srrs	net = (struct sctp_nets *)tmr->net;
1523197326Stuexen	CURVNET_SET((struct vnet *)tmr->vnet);
1524163953Srrs	did_output = 1;
1525163953Srrs
1526163953Srrs#ifdef SCTP_AUDITING_ENABLED
1527163953Srrs	sctp_audit_log(0xF0, (uint8_t) tmr->type);
1528163953Srrs	sctp_auditing(3, inp, stcb, net);
1529163953Srrs#endif
1530163953Srrs
1531163953Srrs	/* sanity checks... */
1532163953Srrs	if (tmr->self != (void *)tmr) {
1533163953Srrs		/*
1534169420Srrs		 * SCTP_PRINTF("Stale SCTP timer fired (%p), ignoring...\n",
1535240148Stuexen		 * (void *)tmr);
1536163953Srrs		 */
1537197326Stuexen		CURVNET_RESTORE();
1538163953Srrs		return;
1539163953Srrs	}
1540165220Srrs	tmr->stopped_from = 0xa001;
1541163953Srrs	if (!SCTP_IS_TIMER_TYPE_VALID(tmr->type)) {
1542163953Srrs		/*
1543169420Srrs		 * SCTP_PRINTF("SCTP timer fired with invalid type: 0x%x\n",
1544163953Srrs		 * tmr->type);
1545163953Srrs		 */
1546197326Stuexen		CURVNET_RESTORE();
1547163953Srrs		return;
1548163953Srrs	}
1549165220Srrs	tmr->stopped_from = 0xa002;
1550163953Srrs	if ((tmr->type != SCTP_TIMER_TYPE_ADDR_WQ) && (inp == NULL)) {
1551197326Stuexen		CURVNET_RESTORE();
1552163953Srrs		return;
1553163953Srrs	}
1554163953Srrs	/* if this is an iterator timeout, get the struct and clear inp */
1555165220Srrs	tmr->stopped_from = 0xa003;
1556163953Srrs	if (inp) {
1557163953Srrs		SCTP_INP_INCR_REF(inp);
1558229729Stuexen		if ((inp->sctp_socket == NULL) &&
1559163953Srrs		    ((tmr->type != SCTP_TIMER_TYPE_INPKILL) &&
1560196260Stuexen		    (tmr->type != SCTP_TIMER_TYPE_INIT) &&
1561184883Srrs		    (tmr->type != SCTP_TIMER_TYPE_SEND) &&
1562184883Srrs		    (tmr->type != SCTP_TIMER_TYPE_RECV) &&
1563184883Srrs		    (tmr->type != SCTP_TIMER_TYPE_HEARTBEAT) &&
1564163953Srrs		    (tmr->type != SCTP_TIMER_TYPE_SHUTDOWN) &&
1565163953Srrs		    (tmr->type != SCTP_TIMER_TYPE_SHUTDOWNACK) &&
1566163953Srrs		    (tmr->type != SCTP_TIMER_TYPE_SHUTDOWNGUARD) &&
1567163953Srrs		    (tmr->type != SCTP_TIMER_TYPE_ASOCKILL))
1568163953Srrs		    ) {
1569163953Srrs			SCTP_INP_DECR_REF(inp);
1570197326Stuexen			CURVNET_RESTORE();
1571163953Srrs			return;
1572163953Srrs		}
1573163953Srrs	}
1574165220Srrs	tmr->stopped_from = 0xa004;
1575163953Srrs	if (stcb) {
1576168709Srrs		atomic_add_int(&stcb->asoc.refcnt, 1);
1577163953Srrs		if (stcb->asoc.state == 0) {
1578168709Srrs			atomic_add_int(&stcb->asoc.refcnt, -1);
1579163953Srrs			if (inp) {
1580163953Srrs				SCTP_INP_DECR_REF(inp);
1581163953Srrs			}
1582197326Stuexen			CURVNET_RESTORE();
1583163953Srrs			return;
1584163953Srrs		}
1585163953Srrs	}
1586294221Stuexen	type = tmr->type;
1587165220Srrs	tmr->stopped_from = 0xa005;
1588294221Stuexen	SCTPDBG(SCTP_DEBUG_TIMER1, "Timer type %d goes off\n", type);
1589165647Srrs	if (!SCTP_OS_TIMER_ACTIVE(&tmr->timer)) {
1590163953Srrs		if (inp) {
1591163953Srrs			SCTP_INP_DECR_REF(inp);
1592163953Srrs		}
1593170091Srrs		if (stcb) {
1594170091Srrs			atomic_add_int(&stcb->asoc.refcnt, -1);
1595170091Srrs		}
1596197326Stuexen		CURVNET_RESTORE();
1597163953Srrs		return;
1598163953Srrs	}
1599165220Srrs	tmr->stopped_from = 0xa006;
1600165220Srrs
1601163953Srrs	if (stcb) {
1602163953Srrs		SCTP_TCB_LOCK(stcb);
1603163996Srrs		atomic_add_int(&stcb->asoc.refcnt, -1);
1604294221Stuexen		if ((type != SCTP_TIMER_TYPE_ASOCKILL) &&
1605171440Srrs		    ((stcb->asoc.state == 0) ||
1606171440Srrs		    (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED))) {
1607171440Srrs			SCTP_TCB_UNLOCK(stcb);
1608171440Srrs			if (inp) {
1609171440Srrs				SCTP_INP_DECR_REF(inp);
1610171440Srrs			}
1611197326Stuexen			CURVNET_RESTORE();
1612171440Srrs			return;
1613171440Srrs		}
1614163953Srrs	}
1615166023Srrs	/* record in stopped what t-o occured */
1616294221Stuexen	tmr->stopped_from = type;
1617166023Srrs
1618163953Srrs	/* mark as being serviced now */
1619166023Srrs	if (SCTP_OS_TIMER_PENDING(&tmr->timer)) {
1620166023Srrs		/*
1621166023Srrs		 * Callout has been rescheduled.
1622166023Srrs		 */
1623166023Srrs		goto get_out;
1624166023Srrs	}
1625166023Srrs	if (!SCTP_OS_TIMER_ACTIVE(&tmr->timer)) {
1626166023Srrs		/*
1627166023Srrs		 * Not active, so no action.
1628166023Srrs		 */
1629166023Srrs		goto get_out;
1630166023Srrs	}
1631165647Srrs	SCTP_OS_TIMER_DEACTIVATE(&tmr->timer);
1632163953Srrs
1633163953Srrs	/* call the handler for the appropriate timer type */
1634294221Stuexen	switch (type) {
1635170056Srrs	case SCTP_TIMER_TYPE_ZERO_COPY:
1636170931Srrs		if (inp == NULL) {
1637170931Srrs			break;
1638170931Srrs		}
1639170056Srrs		if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) {
1640170056Srrs			SCTP_ZERO_COPY_EVENT(inp, inp->sctp_socket);
1641170056Srrs		}
1642170056Srrs		break;
1643170181Srrs	case SCTP_TIMER_TYPE_ZCOPY_SENDQ:
1644170931Srrs		if (inp == NULL) {
1645170931Srrs			break;
1646170931Srrs		}
1647170181Srrs		if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) {
1648170181Srrs			SCTP_ZERO_COPY_SENDQ_EVENT(inp, inp->sctp_socket);
1649170181Srrs		}
1650170181Srrs		break;
1651163953Srrs	case SCTP_TIMER_TYPE_ADDR_WQ:
1652163953Srrs		sctp_handle_addr_wq();
1653163953Srrs		break;
1654163953Srrs	case SCTP_TIMER_TYPE_SEND:
1655169420Srrs		if ((stcb == NULL) || (inp == NULL)) {
1656169420Srrs			break;
1657169420Srrs		}
1658163953Srrs		SCTP_STAT_INCR(sctps_timodata);
1659166675Srrs		stcb->asoc.timodata++;
1660163953Srrs		stcb->asoc.num_send_timers_up--;
1661163953Srrs		if (stcb->asoc.num_send_timers_up < 0) {
1662163953Srrs			stcb->asoc.num_send_timers_up = 0;
1663163953Srrs		}
1664171440Srrs		SCTP_TCB_LOCK_ASSERT(stcb);
1665228907Stuexen		if (sctp_t3rxt_timer(inp, stcb, net)) {
1666163953Srrs			/* no need to unlock on tcb its gone */
1667163953Srrs
1668163953Srrs			goto out_decr;
1669163953Srrs		}
1670171440Srrs		SCTP_TCB_LOCK_ASSERT(stcb);
1671163953Srrs#ifdef SCTP_AUDITING_ENABLED
1672163953Srrs		sctp_auditing(4, inp, stcb, net);
1673163953Srrs#endif
1674172090Srrs		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
1675163953Srrs		if ((stcb->asoc.num_send_timers_up == 0) &&
1676216822Stuexen		    (stcb->asoc.sent_queue_cnt > 0)) {
1677163953Srrs			struct sctp_tmit_chunk *chk;
1678163953Srrs
1679163953Srrs			/*
1680163953Srrs			 * safeguard. If there on some on the sent queue
1681163953Srrs			 * somewhere but no timers running something is
1682163953Srrs			 * wrong... so we start a timer on the first chunk
1683163953Srrs			 * on the send queue on whatever net it is sent to.
1684163953Srrs			 */
1685163953Srrs			chk = TAILQ_FIRST(&stcb->asoc.sent_queue);
1686163953Srrs			sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb,
1687163953Srrs			    chk->whoTo);
1688163953Srrs		}
1689163953Srrs		break;
1690163953Srrs	case SCTP_TIMER_TYPE_INIT:
1691169420Srrs		if ((stcb == NULL) || (inp == NULL)) {
1692169420Srrs			break;
1693169420Srrs		}
1694163953Srrs		SCTP_STAT_INCR(sctps_timoinit);
1695166675Srrs		stcb->asoc.timoinit++;
1696163953Srrs		if (sctp_t1init_timer(inp, stcb, net)) {
1697163953Srrs			/* no need to unlock on tcb its gone */
1698163953Srrs			goto out_decr;
1699163953Srrs		}
1700163953Srrs		/* We do output but not here */
1701163953Srrs		did_output = 0;
1702163953Srrs		break;
1703163953Srrs	case SCTP_TIMER_TYPE_RECV:
1704169420Srrs		if ((stcb == NULL) || (inp == NULL)) {
1705169420Srrs			break;
1706169420Srrs		}
1707224641Stuexen		SCTP_STAT_INCR(sctps_timosack);
1708224641Stuexen		stcb->asoc.timosack++;
1709224641Stuexen		sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED);
1710163953Srrs#ifdef SCTP_AUDITING_ENABLED
1711163953Srrs		sctp_auditing(4, inp, stcb, net);
1712163953Srrs#endif
1713172090Srrs		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SACK_TMR, SCTP_SO_NOT_LOCKED);
1714163953Srrs		break;
1715163953Srrs	case SCTP_TIMER_TYPE_SHUTDOWN:
1716169420Srrs		if ((stcb == NULL) || (inp == NULL)) {
1717169420Srrs			break;
1718169420Srrs		}
1719163953Srrs		if (sctp_shutdown_timer(inp, stcb, net)) {
1720163953Srrs			/* no need to unlock on tcb its gone */
1721163953Srrs			goto out_decr;
1722163953Srrs		}
1723163953Srrs		SCTP_STAT_INCR(sctps_timoshutdown);
1724166675Srrs		stcb->asoc.timoshutdown++;
1725163953Srrs#ifdef SCTP_AUDITING_ENABLED
1726163953Srrs		sctp_auditing(4, inp, stcb, net);
1727163953Srrs#endif
1728172090Srrs		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_TMR, SCTP_SO_NOT_LOCKED);
1729163953Srrs		break;
1730163953Srrs	case SCTP_TIMER_TYPE_HEARTBEAT:
1731224641Stuexen		if ((stcb == NULL) || (inp == NULL) || (net == NULL)) {
1732224641Stuexen			break;
1733224641Stuexen		}
1734224641Stuexen		SCTP_STAT_INCR(sctps_timoheartbeat);
1735224641Stuexen		stcb->asoc.timoheartbeat++;
1736224641Stuexen		if (sctp_heartbeat_timer(inp, stcb, net)) {
1737224641Stuexen			/* no need to unlock on tcb its gone */
1738224641Stuexen			goto out_decr;
1739224641Stuexen		}
1740163953Srrs#ifdef SCTP_AUDITING_ENABLED
1741224641Stuexen		sctp_auditing(4, inp, stcb, net);
1742163953Srrs#endif
1743224641Stuexen		if (!(net->dest_state & SCTP_ADDR_NOHB)) {
1744226168Stuexen			sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
1745172090Srrs			sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_HB_TMR, SCTP_SO_NOT_LOCKED);
1746163953Srrs		}
1747163953Srrs		break;
1748163953Srrs	case SCTP_TIMER_TYPE_COOKIE:
1749169420Srrs		if ((stcb == NULL) || (inp == NULL)) {
1750169420Srrs			break;
1751169420Srrs		}
1752163953Srrs		if (sctp_cookie_timer(inp, stcb, net)) {
1753163953Srrs			/* no need to unlock on tcb its gone */
1754163953Srrs			goto out_decr;
1755163953Srrs		}
1756163953Srrs		SCTP_STAT_INCR(sctps_timocookie);
1757166675Srrs		stcb->asoc.timocookie++;
1758163953Srrs#ifdef SCTP_AUDITING_ENABLED
1759163953Srrs		sctp_auditing(4, inp, stcb, net);
1760163953Srrs#endif
1761163953Srrs		/*
1762163953Srrs		 * We consider T3 and Cookie timer pretty much the same with
1763163953Srrs		 * respect to where from in chunk_output.
1764163953Srrs		 */
1765172090Srrs		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
1766163953Srrs		break;
1767163953Srrs	case SCTP_TIMER_TYPE_NEWCOOKIE:
1768163953Srrs		{
1769163953Srrs			struct timeval tv;
1770163953Srrs			int i, secret;
1771163953Srrs
1772169420Srrs			if (inp == NULL) {
1773169420Srrs				break;
1774169420Srrs			}
1775163953Srrs			SCTP_STAT_INCR(sctps_timosecret);
1776169378Srrs			(void)SCTP_GETTIME_TIMEVAL(&tv);
1777163953Srrs			SCTP_INP_WLOCK(inp);
1778163953Srrs			inp->sctp_ep.time_of_secret_change = tv.tv_sec;
1779163953Srrs			inp->sctp_ep.last_secret_number =
1780163953Srrs			    inp->sctp_ep.current_secret_number;
1781163953Srrs			inp->sctp_ep.current_secret_number++;
1782163953Srrs			if (inp->sctp_ep.current_secret_number >=
1783163953Srrs			    SCTP_HOW_MANY_SECRETS) {
1784163953Srrs				inp->sctp_ep.current_secret_number = 0;
1785163953Srrs			}
1786163953Srrs			secret = (int)inp->sctp_ep.current_secret_number;
1787163953Srrs			for (i = 0; i < SCTP_NUMBER_OF_SECRETS; i++) {
1788163953Srrs				inp->sctp_ep.secret_key[secret][i] =
1789163953Srrs				    sctp_select_initial_TSN(&inp->sctp_ep);
1790163953Srrs			}
1791163953Srrs			SCTP_INP_WUNLOCK(inp);
1792163953Srrs			sctp_timer_start(SCTP_TIMER_TYPE_NEWCOOKIE, inp, stcb, net);
1793163953Srrs		}
1794163953Srrs		did_output = 0;
1795163953Srrs		break;
1796163953Srrs	case SCTP_TIMER_TYPE_PATHMTURAISE:
1797169420Srrs		if ((stcb == NULL) || (inp == NULL)) {
1798169420Srrs			break;
1799169420Srrs		}
1800163953Srrs		SCTP_STAT_INCR(sctps_timopathmtu);
1801163953Srrs		sctp_pathmtu_timer(inp, stcb, net);
1802163953Srrs		did_output = 0;
1803163953Srrs		break;
1804163953Srrs	case SCTP_TIMER_TYPE_SHUTDOWNACK:
1805169420Srrs		if ((stcb == NULL) || (inp == NULL)) {
1806169420Srrs			break;
1807169420Srrs		}
1808163953Srrs		if (sctp_shutdownack_timer(inp, stcb, net)) {
1809163953Srrs			/* no need to unlock on tcb its gone */
1810163953Srrs			goto out_decr;
1811163953Srrs		}
1812163953Srrs		SCTP_STAT_INCR(sctps_timoshutdownack);
1813166675Srrs		stcb->asoc.timoshutdownack++;
1814163953Srrs#ifdef SCTP_AUDITING_ENABLED
1815163953Srrs		sctp_auditing(4, inp, stcb, net);
1816163953Srrs#endif
1817172090Srrs		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_ACK_TMR, SCTP_SO_NOT_LOCKED);
1818163953Srrs		break;
1819163953Srrs	case SCTP_TIMER_TYPE_SHUTDOWNGUARD:
1820169420Srrs		if ((stcb == NULL) || (inp == NULL)) {
1821169420Srrs			break;
1822169420Srrs		}
1823163953Srrs		SCTP_STAT_INCR(sctps_timoshutdownguard);
1824294145Stuexen		op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
1825294145Stuexen		    "Shutdown guard timer expired");
1826294145Stuexen		sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED);
1827163953Srrs		/* no need to unlock on tcb its gone */
1828163953Srrs		goto out_decr;
1829163953Srrs
1830163953Srrs	case SCTP_TIMER_TYPE_STRRESET:
1831169420Srrs		if ((stcb == NULL) || (inp == NULL)) {
1832169420Srrs			break;
1833169420Srrs		}
1834163953Srrs		if (sctp_strreset_timer(inp, stcb, net)) {
1835163953Srrs			/* no need to unlock on tcb its gone */
1836163953Srrs			goto out_decr;
1837163953Srrs		}
1838163953Srrs		SCTP_STAT_INCR(sctps_timostrmrst);
1839172090Srrs		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_TMR, SCTP_SO_NOT_LOCKED);
1840163953Srrs		break;
1841163953Srrs	case SCTP_TIMER_TYPE_ASCONF:
1842169420Srrs		if ((stcb == NULL) || (inp == NULL)) {
1843169420Srrs			break;
1844169420Srrs		}
1845163953Srrs		if (sctp_asconf_timer(inp, stcb, net)) {
1846163953Srrs			/* no need to unlock on tcb its gone */
1847163953Srrs			goto out_decr;
1848163953Srrs		}
1849163953Srrs		SCTP_STAT_INCR(sctps_timoasconf);
1850163953Srrs#ifdef SCTP_AUDITING_ENABLED
1851163953Srrs		sctp_auditing(4, inp, stcb, net);
1852163953Srrs#endif
1853172090Srrs		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_ASCONF_TMR, SCTP_SO_NOT_LOCKED);
1854163953Srrs		break;
1855172091Srrs	case SCTP_TIMER_TYPE_PRIM_DELETED:
1856172091Srrs		if ((stcb == NULL) || (inp == NULL)) {
1857172091Srrs			break;
1858172091Srrs		}
1859172156Srrs		sctp_delete_prim_timer(inp, stcb, net);
1860172091Srrs		SCTP_STAT_INCR(sctps_timodelprim);
1861172091Srrs		break;
1862163953Srrs
1863163953Srrs	case SCTP_TIMER_TYPE_AUTOCLOSE:
1864169420Srrs		if ((stcb == NULL) || (inp == NULL)) {
1865169420Srrs			break;
1866169420Srrs		}
1867163953Srrs		SCTP_STAT_INCR(sctps_timoautoclose);
1868163953Srrs		sctp_autoclose_timer(inp, stcb, net);
1869172090Srrs		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_AUTOCLOSE_TMR, SCTP_SO_NOT_LOCKED);
1870163953Srrs		did_output = 0;
1871163953Srrs		break;
1872163953Srrs	case SCTP_TIMER_TYPE_ASOCKILL:
1873169420Srrs		if ((stcb == NULL) || (inp == NULL)) {
1874169420Srrs			break;
1875169420Srrs		}
1876163953Srrs		SCTP_STAT_INCR(sctps_timoassockill);
1877163953Srrs		/* Can we free it yet? */
1878163953Srrs		SCTP_INP_DECR_REF(inp);
1879283823Stuexen		sctp_timer_stop(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL,
1880283823Stuexen		    SCTP_FROM_SCTPUTIL + SCTP_LOC_1);
1881237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
1882172090Srrs		so = SCTP_INP_SO(inp);
1883172090Srrs		atomic_add_int(&stcb->asoc.refcnt, 1);
1884172090Srrs		SCTP_TCB_UNLOCK(stcb);
1885172090Srrs		SCTP_SOCKET_LOCK(so, 1);
1886172090Srrs		SCTP_TCB_LOCK(stcb);
1887172090Srrs		atomic_subtract_int(&stcb->asoc.refcnt, 1);
1888172090Srrs#endif
1889283823Stuexen		(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
1890283823Stuexen		    SCTP_FROM_SCTPUTIL + SCTP_LOC_2);
1891237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
1892172090Srrs		SCTP_SOCKET_UNLOCK(so, 1);
1893172090Srrs#endif
1894163953Srrs		/*
1895163953Srrs		 * free asoc, always unlocks (or destroy's) so prevent
1896163953Srrs		 * duplicate unlock or unlock of a free mtx :-0
1897163953Srrs		 */
1898163953Srrs		stcb = NULL;
1899163953Srrs		goto out_no_decr;
1900163953Srrs	case SCTP_TIMER_TYPE_INPKILL:
1901163953Srrs		SCTP_STAT_INCR(sctps_timoinpkill);
1902169420Srrs		if (inp == NULL) {
1903169420Srrs			break;
1904169420Srrs		}
1905163953Srrs		/*
1906163953Srrs		 * special case, take away our increment since WE are the
1907163953Srrs		 * killer
1908163953Srrs		 */
1909163953Srrs		SCTP_INP_DECR_REF(inp);
1910283823Stuexen		sctp_timer_stop(SCTP_TIMER_TYPE_INPKILL, inp, NULL, NULL,
1911283823Stuexen		    SCTP_FROM_SCTPUTIL + SCTP_LOC_3);
1912169380Srrs		sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
1913208878Srrs		    SCTP_CALLED_FROM_INPKILL_TIMER);
1914179180Srrs		inp = NULL;
1915163953Srrs		goto out_no_decr;
1916163953Srrs	default:
1917169420Srrs		SCTPDBG(SCTP_DEBUG_TIMER1, "sctp_timeout_handler:unknown timer %d\n",
1918294221Stuexen		    type);
1919163953Srrs		break;
1920228907Stuexen	}
1921163953Srrs#ifdef SCTP_AUDITING_ENABLED
1922294221Stuexen	sctp_audit_log(0xF1, (uint8_t) type);
1923163953Srrs	if (inp)
1924163953Srrs		sctp_auditing(5, inp, stcb, net);
1925163953Srrs#endif
1926163953Srrs	if ((did_output) && stcb) {
1927163953Srrs		/*
1928163953Srrs		 * Now we need to clean up the control chunk chain if an
1929163953Srrs		 * ECNE is on it. It must be marked as UNSENT again so next
1930163953Srrs		 * call will continue to send it until such time that we get
1931163953Srrs		 * a CWR, to remove it. It is, however, less likely that we
1932163953Srrs		 * will find a ecn echo on the chain though.
1933163953Srrs		 */
1934163953Srrs		sctp_fix_ecn_echo(&stcb->asoc);
1935163953Srrs	}
1936166023Srrsget_out:
1937163953Srrs	if (stcb) {
1938163953Srrs		SCTP_TCB_UNLOCK(stcb);
1939163953Srrs	}
1940163953Srrsout_decr:
1941163953Srrs	if (inp) {
1942163953Srrs		SCTP_INP_DECR_REF(inp);
1943163953Srrs	}
1944163953Srrsout_no_decr:
1945294221Stuexen	SCTPDBG(SCTP_DEBUG_TIMER1, "Timer now complete (type = %d)\n", type);
1946197326Stuexen	CURVNET_RESTORE();
1947163953Srrs}
1948163953Srrs
1949169420Srrsvoid
1950163953Srrssctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
1951163953Srrs    struct sctp_nets *net)
1952163953Srrs{
1953224641Stuexen	uint32_t to_ticks;
1954163953Srrs	struct sctp_timer *tmr;
1955163953Srrs
1956165647Srrs	if ((t_type != SCTP_TIMER_TYPE_ADDR_WQ) && (inp == NULL))
1957169420Srrs		return;
1958163953Srrs
1959163953Srrs	tmr = NULL;
1960163953Srrs	if (stcb) {
1961163953Srrs		SCTP_TCB_LOCK_ASSERT(stcb);
1962163953Srrs	}
1963163953Srrs	switch (t_type) {
1964170056Srrs	case SCTP_TIMER_TYPE_ZERO_COPY:
1965170056Srrs		tmr = &inp->sctp_ep.zero_copy_timer;
1966170056Srrs		to_ticks = SCTP_ZERO_COPY_TICK_DELAY;
1967170056Srrs		break;
1968170181Srrs	case SCTP_TIMER_TYPE_ZCOPY_SENDQ:
1969170181Srrs		tmr = &inp->sctp_ep.zero_copy_sendq_timer;
1970170181Srrs		to_ticks = SCTP_ZERO_COPY_SENDQ_TICK_DELAY;
1971170181Srrs		break;
1972163953Srrs	case SCTP_TIMER_TYPE_ADDR_WQ:
1973163953Srrs		/* Only 1 tick away :-) */
1974179783Srrs		tmr = &SCTP_BASE_INFO(addr_wq_timer);
1975167598Srrs		to_ticks = SCTP_ADDRESS_TICK_DELAY;
1976163953Srrs		break;
1977163953Srrs	case SCTP_TIMER_TYPE_SEND:
1978163953Srrs		/* Here we use the RTO timer */
1979163953Srrs		{
1980163953Srrs			int rto_val;
1981163953Srrs
1982163953Srrs			if ((stcb == NULL) || (net == NULL)) {
1983169420Srrs				return;
1984163953Srrs			}
1985163953Srrs			tmr = &net->rxt_timer;
1986163953Srrs			if (net->RTO == 0) {
1987163953Srrs				rto_val = stcb->asoc.initial_rto;
1988163953Srrs			} else {
1989163953Srrs				rto_val = net->RTO;
1990163953Srrs			}
1991163953Srrs			to_ticks = MSEC_TO_TICKS(rto_val);
1992163953Srrs		}
1993163953Srrs		break;
1994163953Srrs	case SCTP_TIMER_TYPE_INIT:
1995163953Srrs		/*
1996163953Srrs		 * Here we use the INIT timer default usually about 1
1997163953Srrs		 * minute.
1998163953Srrs		 */
1999163953Srrs		if ((stcb == NULL) || (net == NULL)) {
2000169420Srrs			return;
2001163953Srrs		}
2002163953Srrs		tmr = &net->rxt_timer;
2003163953Srrs		if (net->RTO == 0) {
2004163953Srrs			to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
2005163953Srrs		} else {
2006163953Srrs			to_ticks = MSEC_TO_TICKS(net->RTO);
2007163953Srrs		}
2008163953Srrs		break;
2009163953Srrs	case SCTP_TIMER_TYPE_RECV:
2010163953Srrs		/*
2011163953Srrs		 * Here we use the Delayed-Ack timer value from the inp
2012163953Srrs		 * ususually about 200ms.
2013163953Srrs		 */
2014163953Srrs		if (stcb == NULL) {
2015169420Srrs			return;
2016163953Srrs		}
2017163953Srrs		tmr = &stcb->asoc.dack_timer;
2018163953Srrs		to_ticks = MSEC_TO_TICKS(stcb->asoc.delayed_ack);
2019163953Srrs		break;
2020163953Srrs	case SCTP_TIMER_TYPE_SHUTDOWN:
2021163953Srrs		/* Here we use the RTO of the destination. */
2022163953Srrs		if ((stcb == NULL) || (net == NULL)) {
2023169420Srrs			return;
2024163953Srrs		}
2025163953Srrs		if (net->RTO == 0) {
2026163953Srrs			to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
2027163953Srrs		} else {
2028163953Srrs			to_ticks = MSEC_TO_TICKS(net->RTO);
2029163953Srrs		}
2030163953Srrs		tmr = &net->rxt_timer;
2031163953Srrs		break;
2032163953Srrs	case SCTP_TIMER_TYPE_HEARTBEAT:
2033163953Srrs		/*
2034163953Srrs		 * the net is used here so that we can add in the RTO. Even
2035163953Srrs		 * though we use a different timer. We also add the HB timer
2036163953Srrs		 * PLUS a random jitter.
2037163953Srrs		 */
2038283707Stuexen		if ((stcb == NULL) || (net == NULL)) {
2039169420Srrs			return;
2040169420Srrs		} else {
2041163953Srrs			uint32_t rndval;
2042224641Stuexen			uint32_t jitter;
2043163953Srrs
2044224641Stuexen			if ((net->dest_state & SCTP_ADDR_NOHB) &&
2045224641Stuexen			    !(net->dest_state & SCTP_ADDR_UNCONFIRMED)) {
2046224641Stuexen				return;
2047163953Srrs			}
2048224641Stuexen			if (net->RTO == 0) {
2049224641Stuexen				to_ticks = stcb->asoc.initial_rto;
2050224641Stuexen			} else {
2051224641Stuexen				to_ticks = net->RTO;
2052163953Srrs			}
2053224641Stuexen			rndval = sctp_select_initial_TSN(&inp->sctp_ep);
2054224641Stuexen			jitter = rndval % to_ticks;
2055224641Stuexen			if (jitter >= (to_ticks >> 1)) {
2056224641Stuexen				to_ticks = to_ticks + (jitter - (to_ticks >> 1));
2057224641Stuexen			} else {
2058224641Stuexen				to_ticks = to_ticks - jitter;
2059163953Srrs			}
2060224641Stuexen			if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED) &&
2061224641Stuexen			    !(net->dest_state & SCTP_ADDR_PF)) {
2062224641Stuexen				to_ticks += net->heart_beat_delay;
2063163953Srrs			}
2064163953Srrs			/*
2065163953Srrs			 * Now we must convert the to_ticks that are now in
2066163953Srrs			 * ms to ticks.
2067163953Srrs			 */
2068163953Srrs			to_ticks = MSEC_TO_TICKS(to_ticks);
2069224641Stuexen			tmr = &net->hb_timer;
2070163953Srrs		}
2071163953Srrs		break;
2072163953Srrs	case SCTP_TIMER_TYPE_COOKIE:
2073163953Srrs		/*
2074163953Srrs		 * Here we can use the RTO timer from the network since one
2075163953Srrs		 * RTT was compelete. If a retran happened then we will be
2076163953Srrs		 * using the RTO initial value.
2077163953Srrs		 */
2078163953Srrs		if ((stcb == NULL) || (net == NULL)) {
2079169420Srrs			return;
2080163953Srrs		}
2081163953Srrs		if (net->RTO == 0) {
2082163953Srrs			to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
2083163953Srrs		} else {
2084163953Srrs			to_ticks = MSEC_TO_TICKS(net->RTO);
2085163953Srrs		}
2086163953Srrs		tmr = &net->rxt_timer;
2087163953Srrs		break;
2088163953Srrs	case SCTP_TIMER_TYPE_NEWCOOKIE:
2089163953Srrs		/*
2090163953Srrs		 * nothing needed but the endpoint here ususually about 60
2091163953Srrs		 * minutes.
2092163953Srrs		 */
2093163953Srrs		tmr = &inp->sctp_ep.signature_change;
2094163953Srrs		to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_SIGNATURE];
2095163953Srrs		break;
2096163953Srrs	case SCTP_TIMER_TYPE_ASOCKILL:
2097163953Srrs		if (stcb == NULL) {
2098169420Srrs			return;
2099163953Srrs		}
2100163953Srrs		tmr = &stcb->asoc.strreset_timer;
2101163953Srrs		to_ticks = MSEC_TO_TICKS(SCTP_ASOC_KILL_TIMEOUT);
2102163953Srrs		break;
2103163953Srrs	case SCTP_TIMER_TYPE_INPKILL:
2104163953Srrs		/*
2105163953Srrs		 * The inp is setup to die. We re-use the signature_chage
2106163953Srrs		 * timer since that has stopped and we are in the GONE
2107163953Srrs		 * state.
2108163953Srrs		 */
2109163953Srrs		tmr = &inp->sctp_ep.signature_change;
2110163953Srrs		to_ticks = MSEC_TO_TICKS(SCTP_INP_KILL_TIMEOUT);
2111163953Srrs		break;
2112163953Srrs	case SCTP_TIMER_TYPE_PATHMTURAISE:
2113163953Srrs		/*
2114163953Srrs		 * Here we use the value found in the EP for PMTU ususually
2115163953Srrs		 * about 10 minutes.
2116163953Srrs		 */
2117283707Stuexen		if ((stcb == NULL) || (net == NULL)) {
2118169420Srrs			return;
2119163953Srrs		}
2120225635Stuexen		if (net->dest_state & SCTP_ADDR_NO_PMTUD) {
2121225635Stuexen			return;
2122225635Stuexen		}
2123163953Srrs		to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_PMTU];
2124163953Srrs		tmr = &net->pmtu_timer;
2125163953Srrs		break;
2126163953Srrs	case SCTP_TIMER_TYPE_SHUTDOWNACK:
2127163953Srrs		/* Here we use the RTO of the destination */
2128163953Srrs		if ((stcb == NULL) || (net == NULL)) {
2129169420Srrs			return;
2130163953Srrs		}
2131163953Srrs		if (net->RTO == 0) {
2132163953Srrs			to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
2133163953Srrs		} else {
2134163953Srrs			to_ticks = MSEC_TO_TICKS(net->RTO);
2135163953Srrs		}
2136163953Srrs		tmr = &net->rxt_timer;
2137163953Srrs		break;
2138163953Srrs	case SCTP_TIMER_TYPE_SHUTDOWNGUARD:
2139163953Srrs		/*
2140163953Srrs		 * Here we use the endpoints shutdown guard timer usually
2141163953Srrs		 * about 3 minutes.
2142163953Srrs		 */
2143283707Stuexen		if (stcb == NULL) {
2144169420Srrs			return;
2145163953Srrs		}
2146294151Stuexen		if (inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_MAXSHUTDOWN] == 0) {
2147294151Stuexen			to_ticks = 5 * MSEC_TO_TICKS(stcb->asoc.maxrto);
2148294151Stuexen		} else {
2149294151Stuexen			to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_MAXSHUTDOWN];
2150294151Stuexen		}
2151163953Srrs		tmr = &stcb->asoc.shut_guard_timer;
2152163953Srrs		break;
2153163953Srrs	case SCTP_TIMER_TYPE_STRRESET:
2154163953Srrs		/*
2155171572Srrs		 * Here the timer comes from the stcb but its value is from
2156171572Srrs		 * the net's RTO.
2157163953Srrs		 */
2158163953Srrs		if ((stcb == NULL) || (net == NULL)) {
2159169420Srrs			return;
2160163953Srrs		}
2161163953Srrs		if (net->RTO == 0) {
2162163953Srrs			to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
2163163953Srrs		} else {
2164163953Srrs			to_ticks = MSEC_TO_TICKS(net->RTO);
2165163953Srrs		}
2166163953Srrs		tmr = &stcb->asoc.strreset_timer;
2167163953Srrs		break;
2168163953Srrs	case SCTP_TIMER_TYPE_ASCONF:
2169163953Srrs		/*
2170171572Srrs		 * Here the timer comes from the stcb but its value is from
2171171572Srrs		 * the net's RTO.
2172163953Srrs		 */
2173163953Srrs		if ((stcb == NULL) || (net == NULL)) {
2174169420Srrs			return;
2175163953Srrs		}
2176163953Srrs		if (net->RTO == 0) {
2177163953Srrs			to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
2178163953Srrs		} else {
2179163953Srrs			to_ticks = MSEC_TO_TICKS(net->RTO);
2180163953Srrs		}
2181163953Srrs		tmr = &stcb->asoc.asconf_timer;
2182163953Srrs		break;
2183172091Srrs	case SCTP_TIMER_TYPE_PRIM_DELETED:
2184172091Srrs		if ((stcb == NULL) || (net != NULL)) {
2185172091Srrs			return;
2186172091Srrs		}
2187172091Srrs		to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
2188172091Srrs		tmr = &stcb->asoc.delete_prim_timer;
2189172091Srrs		break;
2190163953Srrs	case SCTP_TIMER_TYPE_AUTOCLOSE:
2191163953Srrs		if (stcb == NULL) {
2192169420Srrs			return;
2193163953Srrs		}
2194163953Srrs		if (stcb->asoc.sctp_autoclose_ticks == 0) {
2195163953Srrs			/*
2196163953Srrs			 * Really an error since stcb is NOT set to
2197163953Srrs			 * autoclose
2198163953Srrs			 */
2199169420Srrs			return;
2200163953Srrs		}
2201163953Srrs		to_ticks = stcb->asoc.sctp_autoclose_ticks;
2202163953Srrs		tmr = &stcb->asoc.autoclose_timer;
2203163953Srrs		break;
2204163953Srrs	default:
2205169420Srrs		SCTPDBG(SCTP_DEBUG_TIMER1, "%s: Unknown timer type %d\n",
2206294174Stuexen		    __func__, t_type);
2207169420Srrs		return;
2208163953Srrs		break;
2209228907Stuexen	}
2210163953Srrs	if ((to_ticks <= 0) || (tmr == NULL)) {
2211169420Srrs		SCTPDBG(SCTP_DEBUG_TIMER1, "%s: %d:software error to_ticks:%d tmr:%p not set ??\n",
2212294174Stuexen		    __func__, t_type, to_ticks, (void *)tmr);
2213169420Srrs		return;
2214163953Srrs	}
2215165647Srrs	if (SCTP_OS_TIMER_PENDING(&tmr->timer)) {
2216163953Srrs		/*
2217163953Srrs		 * we do NOT allow you to have it already running. if it is
2218163953Srrs		 * we leave the current one up unchanged
2219163953Srrs		 */
2220169420Srrs		return;
2221163953Srrs	}
2222163953Srrs	/* At this point we can proceed */
2223163953Srrs	if (t_type == SCTP_TIMER_TYPE_SEND) {
2224163953Srrs		stcb->asoc.num_send_timers_up++;
2225163953Srrs	}
2226165220Srrs	tmr->stopped_from = 0;
2227163953Srrs	tmr->type = t_type;
2228163953Srrs	tmr->ep = (void *)inp;
2229163953Srrs	tmr->tcb = (void *)stcb;
2230163953Srrs	tmr->net = (void *)net;
2231163953Srrs	tmr->self = (void *)tmr;
2232197326Stuexen	tmr->vnet = (void *)curvnet;
2233171943Srrs	tmr->ticks = sctp_get_tick_count();
2234169420Srrs	(void)SCTP_OS_TIMER_START(&tmr->timer, to_ticks, sctp_timeout_handler, tmr);
2235169420Srrs	return;
2236163953Srrs}
2237163953Srrs
2238169378Srrsvoid
2239163953Srrssctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
2240165220Srrs    struct sctp_nets *net, uint32_t from)
2241163953Srrs{
2242163953Srrs	struct sctp_timer *tmr;
2243163953Srrs
2244163953Srrs	if ((t_type != SCTP_TIMER_TYPE_ADDR_WQ) &&
2245163953Srrs	    (inp == NULL))
2246169378Srrs		return;
2247163953Srrs
2248163953Srrs	tmr = NULL;
2249163953Srrs	if (stcb) {
2250163953Srrs		SCTP_TCB_LOCK_ASSERT(stcb);
2251163953Srrs	}
2252163953Srrs	switch (t_type) {
2253170056Srrs	case SCTP_TIMER_TYPE_ZERO_COPY:
2254170056Srrs		tmr = &inp->sctp_ep.zero_copy_timer;
2255170056Srrs		break;
2256170181Srrs	case SCTP_TIMER_TYPE_ZCOPY_SENDQ:
2257170181Srrs		tmr = &inp->sctp_ep.zero_copy_sendq_timer;
2258170181Srrs		break;
2259163953Srrs	case SCTP_TIMER_TYPE_ADDR_WQ:
2260179783Srrs		tmr = &SCTP_BASE_INFO(addr_wq_timer);
2261163953Srrs		break;
2262163953Srrs	case SCTP_TIMER_TYPE_SEND:
2263163953Srrs		if ((stcb == NULL) || (net == NULL)) {
2264169378Srrs			return;
2265163953Srrs		}
2266163953Srrs		tmr = &net->rxt_timer;
2267163953Srrs		break;
2268163953Srrs	case SCTP_TIMER_TYPE_INIT:
2269163953Srrs		if ((stcb == NULL) || (net == NULL)) {
2270169378Srrs			return;
2271163953Srrs		}
2272163953Srrs		tmr = &net->rxt_timer;
2273163953Srrs		break;
2274163953Srrs	case SCTP_TIMER_TYPE_RECV:
2275163953Srrs		if (stcb == NULL) {
2276169378Srrs			return;
2277163953Srrs		}
2278163953Srrs		tmr = &stcb->asoc.dack_timer;
2279163953Srrs		break;
2280163953Srrs	case SCTP_TIMER_TYPE_SHUTDOWN:
2281163953Srrs		if ((stcb == NULL) || (net == NULL)) {
2282169378Srrs			return;
2283163953Srrs		}
2284163953Srrs		tmr = &net->rxt_timer;
2285163953Srrs		break;
2286163953Srrs	case SCTP_TIMER_TYPE_HEARTBEAT:
2287224641Stuexen		if ((stcb == NULL) || (net == NULL)) {
2288169378Srrs			return;
2289163953Srrs		}
2290224641Stuexen		tmr = &net->hb_timer;
2291163953Srrs		break;
2292163953Srrs	case SCTP_TIMER_TYPE_COOKIE:
2293163953Srrs		if ((stcb == NULL) || (net == NULL)) {
2294169378Srrs			return;
2295163953Srrs		}
2296163953Srrs		tmr = &net->rxt_timer;
2297163953Srrs		break;
2298163953Srrs	case SCTP_TIMER_TYPE_NEWCOOKIE:
2299163953Srrs		/* nothing needed but the endpoint here */
2300163953Srrs		tmr = &inp->sctp_ep.signature_change;
2301163953Srrs		/*
2302163953Srrs		 * We re-use the newcookie timer for the INP kill timer. We
2303163953Srrs		 * must assure that we do not kill it by accident.
2304163953Srrs		 */
2305163953Srrs		break;
2306163953Srrs	case SCTP_TIMER_TYPE_ASOCKILL:
2307163953Srrs		/*
2308163953Srrs		 * Stop the asoc kill timer.
2309163953Srrs		 */
2310163953Srrs		if (stcb == NULL) {
2311169378Srrs			return;
2312163953Srrs		}
2313163953Srrs		tmr = &stcb->asoc.strreset_timer;
2314163953Srrs		break;
2315163953Srrs
2316163953Srrs	case SCTP_TIMER_TYPE_INPKILL:
2317163953Srrs		/*
2318163953Srrs		 * The inp is setup to die. We re-use the signature_chage
2319163953Srrs		 * timer since that has stopped and we are in the GONE
2320163953Srrs		 * state.
2321163953Srrs		 */
2322163953Srrs		tmr = &inp->sctp_ep.signature_change;
2323163953Srrs		break;
2324163953Srrs	case SCTP_TIMER_TYPE_PATHMTURAISE:
2325163953Srrs		if ((stcb == NULL) || (net == NULL)) {
2326169378Srrs			return;
2327163953Srrs		}
2328163953Srrs		tmr = &net->pmtu_timer;
2329163953Srrs		break;
2330163953Srrs	case SCTP_TIMER_TYPE_SHUTDOWNACK:
2331163953Srrs		if ((stcb == NULL) || (net == NULL)) {
2332169378Srrs			return;
2333163953Srrs		}
2334163953Srrs		tmr = &net->rxt_timer;
2335163953Srrs		break;
2336163953Srrs	case SCTP_TIMER_TYPE_SHUTDOWNGUARD:
2337163953Srrs		if (stcb == NULL) {
2338169378Srrs			return;
2339163953Srrs		}
2340163953Srrs		tmr = &stcb->asoc.shut_guard_timer;
2341163953Srrs		break;
2342163953Srrs	case SCTP_TIMER_TYPE_STRRESET:
2343163953Srrs		if (stcb == NULL) {
2344169378Srrs			return;
2345163953Srrs		}
2346163953Srrs		tmr = &stcb->asoc.strreset_timer;
2347163953Srrs		break;
2348163953Srrs	case SCTP_TIMER_TYPE_ASCONF:
2349163953Srrs		if (stcb == NULL) {
2350169378Srrs			return;
2351163953Srrs		}
2352163953Srrs		tmr = &stcb->asoc.asconf_timer;
2353163953Srrs		break;
2354172091Srrs	case SCTP_TIMER_TYPE_PRIM_DELETED:
2355172091Srrs		if (stcb == NULL) {
2356172091Srrs			return;
2357172091Srrs		}
2358172091Srrs		tmr = &stcb->asoc.delete_prim_timer;
2359172091Srrs		break;
2360163953Srrs	case SCTP_TIMER_TYPE_AUTOCLOSE:
2361163953Srrs		if (stcb == NULL) {
2362169378Srrs			return;
2363163953Srrs		}
2364163953Srrs		tmr = &stcb->asoc.autoclose_timer;
2365163953Srrs		break;
2366163953Srrs	default:
2367169420Srrs		SCTPDBG(SCTP_DEBUG_TIMER1, "%s: Unknown timer type %d\n",
2368294174Stuexen		    __func__, t_type);
2369163953Srrs		break;
2370228907Stuexen	}
2371163953Srrs	if (tmr == NULL) {
2372169378Srrs		return;
2373163953Srrs	}
2374163953Srrs	if ((tmr->type != t_type) && tmr->type) {
2375163953Srrs		/*
2376163953Srrs		 * Ok we have a timer that is under joint use. Cookie timer
2377163953Srrs		 * per chance with the SEND timer. We therefore are NOT
2378163953Srrs		 * running the timer that the caller wants stopped.  So just
2379163953Srrs		 * return.
2380163953Srrs		 */
2381169378Srrs		return;
2382163953Srrs	}
2383169420Srrs	if ((t_type == SCTP_TIMER_TYPE_SEND) && (stcb != NULL)) {
2384163953Srrs		stcb->asoc.num_send_timers_up--;
2385163953Srrs		if (stcb->asoc.num_send_timers_up < 0) {
2386163953Srrs			stcb->asoc.num_send_timers_up = 0;
2387163953Srrs		}
2388163953Srrs	}
2389163953Srrs	tmr->self = NULL;
2390165220Srrs	tmr->stopped_from = from;
2391169378Srrs	(void)SCTP_OS_TIMER_STOP(&tmr->timer);
2392169378Srrs	return;
2393163953Srrs}
2394163953Srrs
2395163953Srrsuint32_t
2396163953Srrssctp_calculate_len(struct mbuf *m)
2397163953Srrs{
2398163953Srrs	uint32_t tlen = 0;
2399163953Srrs	struct mbuf *at;
2400163953Srrs
2401163953Srrs	at = m;
2402163953Srrs	while (at) {
2403165647Srrs		tlen += SCTP_BUF_LEN(at);
2404165647Srrs		at = SCTP_BUF_NEXT(at);
2405163953Srrs	}
2406163953Srrs	return (tlen);
2407163953Srrs}
2408163953Srrs
2409163953Srrsvoid
2410163953Srrssctp_mtu_size_reset(struct sctp_inpcb *inp,
2411166023Srrs    struct sctp_association *asoc, uint32_t mtu)
2412163953Srrs{
2413163953Srrs	/*
2414163953Srrs	 * Reset the P-MTU size on this association, this involves changing
2415163953Srrs	 * the asoc MTU, going through ANY chunk+overhead larger than mtu to
2416163953Srrs	 * allow the DF flag to be cleared.
2417163953Srrs	 */
2418163953Srrs	struct sctp_tmit_chunk *chk;
2419163953Srrs	unsigned int eff_mtu, ovh;
2420163953Srrs
2421163953Srrs	asoc->smallest_mtu = mtu;
2422163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
2423163953Srrs		ovh = SCTP_MIN_OVERHEAD;
2424163953Srrs	} else {
2425163953Srrs		ovh = SCTP_MIN_V4_OVERHEAD;
2426163953Srrs	}
2427163953Srrs	eff_mtu = mtu - ovh;
2428163953Srrs	TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) {
2429163953Srrs		if (chk->send_size > eff_mtu) {
2430163953Srrs			chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
2431163953Srrs		}
2432163953Srrs	}
2433163953Srrs	TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) {
2434163953Srrs		if (chk->send_size > eff_mtu) {
2435163953Srrs			chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
2436163953Srrs		}
2437163953Srrs	}
2438163953Srrs}
2439163953Srrs
2440163953Srrs
2441163953Srrs/*
2442163953Srrs * given an association and starting time of the current RTT period return
2443166675Srrs * RTO in number of msecs net should point to the current network
2444163953Srrs */
2445218186Srrs
2446163953Srrsuint32_t
2447163953Srrssctp_calculate_rto(struct sctp_tcb *stcb,
2448163953Srrs    struct sctp_association *asoc,
2449163953Srrs    struct sctp_nets *net,
2450171477Srrs    struct timeval *told,
2451219397Srrs    int safe, int rtt_from_sack)
2452163953Srrs{
2453171477Srrs	/*-
2454163953Srrs	 * given an association and the starting time of the current RTT
2455166675Srrs	 * period (in value1/value2) return RTO in number of msecs.
2456163953Srrs	 */
2457219013Stuexen	int32_t rtt;		/* RTT in ms */
2458219013Stuexen	uint32_t new_rto;
2459163953Srrs	int first_measure = 0;
2460171477Srrs	struct timeval now, then, *old;
2461163953Srrs
2462171477Srrs	/* Copy it out for sparc64 */
2463171477Srrs	if (safe == sctp_align_unsafe_makecopy) {
2464171477Srrs		old = &then;
2465171477Srrs		memcpy(&then, told, sizeof(struct timeval));
2466171477Srrs	} else if (safe == sctp_align_safe_nocopy) {
2467171477Srrs		old = told;
2468171477Srrs	} else {
2469171477Srrs		/* error */
2470171477Srrs		SCTP_PRINTF("Huh, bad rto calc call\n");
2471171477Srrs		return (0);
2472171477Srrs	}
2473163953Srrs	/************************/
2474163953Srrs	/* 1. calculate new RTT */
2475163953Srrs	/************************/
2476163953Srrs	/* get the current time */
2477219057Srrs	if (stcb->asoc.use_precise_time) {
2478219057Srrs		(void)SCTP_GETPTIME_TIMEVAL(&now);
2479219057Srrs	} else {
2480219057Srrs		(void)SCTP_GETTIME_TIMEVAL(&now);
2481219057Srrs	}
2482219013Stuexen	timevalsub(&now, old);
2483219013Stuexen	/* store the current RTT in us */
2484240007Stuexen	net->rtt = (uint64_t) 1000000 *(uint64_t) now.tv_sec +
2485240114Stuexen	        (uint64_t) now.tv_usec;
2486218039Srrs
2487271750Stuexen	/* compute rtt in ms */
2488271750Stuexen	rtt = (int32_t) (net->rtt / 1000);
2489219397Srrs	if ((asoc->cc_functions.sctp_rtt_calculated) && (rtt_from_sack == SCTP_RTT_FROM_DATA)) {
2490219397Srrs		/*
2491219397Srrs		 * Tell the CC module that a new update has just occurred
2492219397Srrs		 * from a sack
2493219397Srrs		 */
2494219397Srrs		(*asoc->cc_functions.sctp_rtt_calculated) (stcb, net, &now);
2495219397Srrs	}
2496219397Srrs	/*
2497219397Srrs	 * Do we need to determine the lan? We do this only on sacks i.e.
2498219397Srrs	 * RTT being determined from data not non-data (HB/INIT->INITACK).
2499219397Srrs	 */
2500219397Srrs	if ((rtt_from_sack == SCTP_RTT_FROM_DATA) &&
2501219013Stuexen	    (net->lan_type == SCTP_LAN_UNKNOWN)) {
2502219013Stuexen		if (net->rtt > SCTP_LOCAL_LAN_RTT) {
2503218186Srrs			net->lan_type = SCTP_LAN_INTERNET;
2504218186Srrs		} else {
2505218186Srrs			net->lan_type = SCTP_LAN_LOCAL;
2506218186Srrs		}
2507218186Srrs	}
2508163953Srrs	/***************************/
2509163953Srrs	/* 2. update RTTVAR & SRTT */
2510163953Srrs	/***************************/
2511219013Stuexen	/*-
2512219013Stuexen	 * Compute the scaled average lastsa and the
2513219013Stuexen	 * scaled variance lastsv as described in van Jacobson
2514219013Stuexen	 * Paper "Congestion Avoidance and Control", Annex A.
2515219013Stuexen	 *
2516219013Stuexen	 * (net->lastsa >> SCTP_RTT_SHIFT) is the srtt
2517219013Stuexen	 * (net->lastsa >> SCTP_RTT_VAR_SHIFT) is the rttvar
2518219013Stuexen	 */
2519170642Srrs	if (net->RTO_measured) {
2520219013Stuexen		rtt -= (net->lastsa >> SCTP_RTT_SHIFT);
2521219013Stuexen		net->lastsa += rtt;
2522219013Stuexen		if (rtt < 0) {
2523219013Stuexen			rtt = -rtt;
2524219013Stuexen		}
2525219013Stuexen		rtt -= (net->lastsv >> SCTP_RTT_VAR_SHIFT);
2526219013Stuexen		net->lastsv += rtt;
2527179783Srrs		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RTTVAR_LOGGING_ENABLE) {
2528170744Srrs			rto_logging(net, SCTP_LOG_RTTVAR);
2529170744Srrs		}
2530163953Srrs	} else {
2531163953Srrs		/* First RTO measurment */
2532170642Srrs		net->RTO_measured = 1;
2533163953Srrs		first_measure = 1;
2534219013Stuexen		net->lastsa = rtt << SCTP_RTT_SHIFT;
2535219013Stuexen		net->lastsv = (rtt / 2) << SCTP_RTT_VAR_SHIFT;
2536179783Srrs		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RTTVAR_LOGGING_ENABLE) {
2537170744Srrs			rto_logging(net, SCTP_LOG_INITIAL_RTT);
2538170744Srrs		}
2539163953Srrs	}
2540219013Stuexen	if (net->lastsv == 0) {
2541219013Stuexen		net->lastsv = SCTP_CLOCK_GRANULARITY;
2542219013Stuexen	}
2543170428Srrs	new_rto = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv;
2544163953Srrs	if ((new_rto > SCTP_SAT_NETWORK_MIN) &&
2545163953Srrs	    (stcb->asoc.sat_network_lockout == 0)) {
2546163953Srrs		stcb->asoc.sat_network = 1;
2547163953Srrs	} else if ((!first_measure) && stcb->asoc.sat_network) {
2548163953Srrs		stcb->asoc.sat_network = 0;
2549163953Srrs		stcb->asoc.sat_network_lockout = 1;
2550163953Srrs	}
2551163953Srrs	/* bound it, per C6/C7 in Section 5.3.1 */
2552163953Srrs	if (new_rto < stcb->asoc.minrto) {
2553163953Srrs		new_rto = stcb->asoc.minrto;
2554163953Srrs	}
2555163953Srrs	if (new_rto > stcb->asoc.maxrto) {
2556163953Srrs		new_rto = stcb->asoc.maxrto;
2557163953Srrs	}
2558168124Srrs	/* we are now returning the RTO */
2559168124Srrs	return (new_rto);
2560163953Srrs}
2561163953Srrs
2562163953Srrs/*
2563163953Srrs * return a pointer to a contiguous piece of data from the given mbuf chain
2564163953Srrs * starting at 'off' for 'len' bytes.  If the desired piece spans more than
2565163953Srrs * one mbuf, a copy is made at 'ptr'. caller must ensure that the buffer size
2566163953Srrs * is >= 'len' returns NULL if there there isn't 'len' bytes in the chain.
2567163953Srrs */
2568170806Srrscaddr_t
2569163953Srrssctp_m_getptr(struct mbuf *m, int off, int len, uint8_t * in_ptr)
2570163953Srrs{
2571163953Srrs	uint32_t count;
2572163953Srrs	uint8_t *ptr;
2573163953Srrs
2574163953Srrs	ptr = in_ptr;
2575163953Srrs	if ((off < 0) || (len <= 0))
2576163953Srrs		return (NULL);
2577163953Srrs
2578163953Srrs	/* find the desired start location */
2579163953Srrs	while ((m != NULL) && (off > 0)) {
2580165647Srrs		if (off < SCTP_BUF_LEN(m))
2581163953Srrs			break;
2582165647Srrs		off -= SCTP_BUF_LEN(m);
2583165647Srrs		m = SCTP_BUF_NEXT(m);
2584163953Srrs	}
2585163953Srrs	if (m == NULL)
2586163953Srrs		return (NULL);
2587163953Srrs
2588163953Srrs	/* is the current mbuf large enough (eg. contiguous)? */
2589165647Srrs	if ((SCTP_BUF_LEN(m) - off) >= len) {
2590163953Srrs		return (mtod(m, caddr_t)+off);
2591163953Srrs	} else {
2592163953Srrs		/* else, it spans more than one mbuf, so save a temp copy... */
2593163953Srrs		while ((m != NULL) && (len > 0)) {
2594165647Srrs			count = min(SCTP_BUF_LEN(m) - off, len);
2595163953Srrs			bcopy(mtod(m, caddr_t)+off, ptr, count);
2596163953Srrs			len -= count;
2597163953Srrs			ptr += count;
2598163953Srrs			off = 0;
2599165647Srrs			m = SCTP_BUF_NEXT(m);
2600163953Srrs		}
2601163953Srrs		if ((m == NULL) && (len > 0))
2602163953Srrs			return (NULL);
2603163953Srrs		else
2604163953Srrs			return ((caddr_t)in_ptr);
2605163953Srrs	}
2606163953Srrs}
2607163953Srrs
2608163953Srrs
2609166023Srrs
2610163953Srrsstruct sctp_paramhdr *
2611163953Srrssctp_get_next_param(struct mbuf *m,
2612163953Srrs    int offset,
2613163953Srrs    struct sctp_paramhdr *pull,
2614163953Srrs    int pull_limit)
2615163953Srrs{
2616163953Srrs	/* This just provides a typed signature to Peter's Pull routine */
2617163953Srrs	return ((struct sctp_paramhdr *)sctp_m_getptr(m, offset, pull_limit,
2618163953Srrs	    (uint8_t *) pull));
2619163953Srrs}
2620163953Srrs
2621163953Srrs
2622270354Stuexenstruct mbuf *
2623163953Srrssctp_add_pad_tombuf(struct mbuf *m, int padlen)
2624163953Srrs{
2625270354Stuexen	struct mbuf *m_last;
2626270354Stuexen	caddr_t dp;
2627163953Srrs
2628163953Srrs	if (padlen > 3) {
2629270354Stuexen		return (NULL);
2630163953Srrs	}
2631174387Srrs	if (padlen <= M_TRAILINGSPACE(m)) {
2632163953Srrs		/*
2633163953Srrs		 * The easy way. We hope the majority of the time we hit
2634163953Srrs		 * here :)
2635163953Srrs		 */
2636270354Stuexen		m_last = m;
2637163953Srrs	} else {
2638270354Stuexen		/* Hard way we must grow the mbuf chain */
2639270354Stuexen		m_last = sctp_get_mbuf_for_msg(padlen, 0, M_NOWAIT, 1, MT_DATA);
2640270354Stuexen		if (m_last == NULL) {
2641270354Stuexen			return (NULL);
2642163953Srrs		}
2643270354Stuexen		SCTP_BUF_LEN(m_last) = 0;
2644270354Stuexen		SCTP_BUF_NEXT(m_last) = NULL;
2645270354Stuexen		SCTP_BUF_NEXT(m) = m_last;
2646163953Srrs	}
2647270354Stuexen	dp = mtod(m_last, caddr_t)+SCTP_BUF_LEN(m_last);
2648270354Stuexen	SCTP_BUF_LEN(m_last) += padlen;
2649270354Stuexen	memset(dp, 0, padlen);
2650270354Stuexen	return (m_last);
2651163953Srrs}
2652163953Srrs
2653270354Stuexenstruct mbuf *
2654163953Srrssctp_pad_lastmbuf(struct mbuf *m, int padval, struct mbuf *last_mbuf)
2655163953Srrs{
2656163953Srrs	/* find the last mbuf in chain and pad it */
2657163953Srrs	struct mbuf *m_at;
2658163953Srrs
2659270354Stuexen	if (last_mbuf != NULL) {
2660163953Srrs		return (sctp_add_pad_tombuf(last_mbuf, padval));
2661163953Srrs	} else {
2662236949Stuexen		for (m_at = m; m_at; m_at = SCTP_BUF_NEXT(m_at)) {
2663165647Srrs			if (SCTP_BUF_NEXT(m_at) == NULL) {
2664163953Srrs				return (sctp_add_pad_tombuf(m_at, padval));
2665163953Srrs			}
2666163953Srrs		}
2667163953Srrs	}
2668270354Stuexen	return (NULL);
2669163953Srrs}
2670163953Srrs
2671163953Srrsstatic void
2672235282Stuexensctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb,
2673235403Stuexen    uint16_t error, struct sctp_abort_chunk *abort, uint8_t from_peer, int so_locked
2674172090Srrs#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
2675172090Srrs    SCTP_UNUSED
2676172090Srrs#endif
2677172090Srrs)
2678163953Srrs{
2679163953Srrs	struct mbuf *m_notify;
2680163953Srrs	struct sctp_assoc_change *sac;
2681163953Srrs	struct sctp_queued_to_read *control;
2682235360Stuexen	size_t notif_len, abort_len;
2683235081Stuexen	unsigned int i;
2684163953Srrs
2685237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
2686172090Srrs	struct socket *so;
2687172090Srrs
2688172090Srrs#endif
2689172090Srrs
2690294153Stuexen	if (stcb == NULL) {
2691294153Stuexen		return;
2692294153Stuexen	}
2693235402Stuexen	if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT)) {
2694235402Stuexen		notif_len = sizeof(struct sctp_assoc_change);
2695235402Stuexen		if (abort != NULL) {
2696258454Stuexen			abort_len = ntohs(abort->ch.chunk_length);
2697235402Stuexen		} else {
2698235402Stuexen			abort_len = 0;
2699235402Stuexen		}
2700235402Stuexen		if ((state == SCTP_COMM_UP) || (state == SCTP_RESTART)) {
2701235402Stuexen			notif_len += SCTP_ASSOC_SUPPORTS_MAX;
2702235402Stuexen		} else if ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC)) {
2703235402Stuexen			notif_len += abort_len;
2704235402Stuexen		}
2705243882Sglebius		m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA);
2706235402Stuexen		if (m_notify == NULL) {
2707235402Stuexen			/* Retry with smaller value. */
2708235402Stuexen			notif_len = sizeof(struct sctp_assoc_change);
2709243882Sglebius			m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA);
2710235402Stuexen			if (m_notify == NULL) {
2711235402Stuexen				goto set_error;
2712235402Stuexen			}
2713235402Stuexen		}
2714235402Stuexen		SCTP_BUF_NEXT(m_notify) = NULL;
2715235402Stuexen		sac = mtod(m_notify, struct sctp_assoc_change *);
2716268432Sdelphij		memset(sac, 0, notif_len);
2717235402Stuexen		sac->sac_type = SCTP_ASSOC_CHANGE;
2718235402Stuexen		sac->sac_flags = 0;
2719235402Stuexen		sac->sac_length = sizeof(struct sctp_assoc_change);
2720235402Stuexen		sac->sac_state = state;
2721235402Stuexen		sac->sac_error = error;
2722235402Stuexen		/* XXX verify these stream counts */
2723235402Stuexen		sac->sac_outbound_streams = stcb->asoc.streamoutcnt;
2724235402Stuexen		sac->sac_inbound_streams = stcb->asoc.streamincnt;
2725235402Stuexen		sac->sac_assoc_id = sctp_get_associd(stcb);
2726235402Stuexen		if (notif_len > sizeof(struct sctp_assoc_change)) {
2727235402Stuexen			if ((state == SCTP_COMM_UP) || (state == SCTP_RESTART)) {
2728235402Stuexen				i = 0;
2729270362Stuexen				if (stcb->asoc.prsctp_supported == 1) {
2730235402Stuexen					sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_PR;
2731235402Stuexen				}
2732270362Stuexen				if (stcb->asoc.auth_supported == 1) {
2733235402Stuexen					sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_AUTH;
2734235402Stuexen				}
2735270362Stuexen				if (stcb->asoc.asconf_supported == 1) {
2736235402Stuexen					sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_ASCONF;
2737235402Stuexen				}
2738235402Stuexen				sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_MULTIBUF;
2739270362Stuexen				if (stcb->asoc.reconfig_supported == 1) {
2740235402Stuexen					sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_RE_CONFIG;
2741235402Stuexen				}
2742235402Stuexen				sac->sac_length += i;
2743235402Stuexen			} else if ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC)) {
2744235402Stuexen				memcpy(sac->sac_info, abort, abort_len);
2745235402Stuexen				sac->sac_length += abort_len;
2746235402Stuexen			}
2747235402Stuexen		}
2748235402Stuexen		SCTP_BUF_LEN(m_notify) = sac->sac_length;
2749235402Stuexen		control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
2750235402Stuexen		    0, 0, stcb->asoc.context, 0, 0, 0,
2751235402Stuexen		    m_notify);
2752235402Stuexen		if (control != NULL) {
2753235402Stuexen			control->length = SCTP_BUF_LEN(m_notify);
2754235402Stuexen			/* not that we need this */
2755235402Stuexen			control->tail_mbuf = m_notify;
2756235402Stuexen			control->spec_flags = M_NOTIFICATION;
2757235402Stuexen			sctp_add_to_readq(stcb->sctp_ep, stcb,
2758235402Stuexen			    control,
2759235402Stuexen			    &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD,
2760235402Stuexen			    so_locked);
2761235402Stuexen		} else {
2762235402Stuexen			sctp_m_freem(m_notify);
2763235402Stuexen		}
2764235402Stuexen	}
2765163953Srrs	/*
2766235402Stuexen	 * For 1-to-1 style sockets, we send up and error when an ABORT
2767235402Stuexen	 * comes in.
2768163953Srrs	 */
2769235402Stuexenset_error:
2770163953Srrs	if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2771163953Srrs	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) &&
2772235282Stuexen	    ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC))) {
2773247412Stuexen		SOCK_LOCK(stcb->sctp_socket);
2774235403Stuexen		if (from_peer) {
2775235403Stuexen			if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_WAIT) {
2776235403Stuexen				SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNREFUSED);
2777235403Stuexen				stcb->sctp_socket->so_error = ECONNREFUSED;
2778235403Stuexen			} else {
2779235403Stuexen				SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET);
2780235403Stuexen				stcb->sctp_socket->so_error = ECONNRESET;
2781235403Stuexen			}
2782171943Srrs		} else {
2783250756Stuexen			if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_WAIT) ||
2784250756Stuexen			    (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED)) {
2785250756Stuexen				SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ETIMEDOUT);
2786250756Stuexen				stcb->sctp_socket->so_error = ETIMEDOUT;
2787250756Stuexen			} else {
2788250756Stuexen				SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNABORTED);
2789250756Stuexen				stcb->sctp_socket->so_error = ECONNABORTED;
2790250756Stuexen			}
2791171943Srrs		}
2792235402Stuexen	}
2793235402Stuexen	/* Wake ANY sleepers */
2794237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
2795235402Stuexen	so = SCTP_INP_SO(stcb->sctp_ep);
2796235402Stuexen	if (!so_locked) {
2797235402Stuexen		atomic_add_int(&stcb->asoc.refcnt, 1);
2798235402Stuexen		SCTP_TCB_UNLOCK(stcb);
2799235402Stuexen		SCTP_SOCKET_LOCK(so, 1);
2800235402Stuexen		SCTP_TCB_LOCK(stcb);
2801235402Stuexen		atomic_subtract_int(&stcb->asoc.refcnt, 1);
2802235402Stuexen		if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
2803172090Srrs			SCTP_SOCKET_UNLOCK(so, 1);
2804235360Stuexen			return;
2805235360Stuexen		}
2806235360Stuexen	}
2807235402Stuexen#endif
2808235402Stuexen	if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2809235402Stuexen	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) &&
2810235402Stuexen	    ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC))) {
2811247412Stuexen		socantrcvmore_locked(stcb->sctp_socket);
2812235081Stuexen	}
2813235402Stuexen	sorwakeup(stcb->sctp_socket);
2814235402Stuexen	sowwakeup(stcb->sctp_socket);
2815237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
2816235402Stuexen	if (!so_locked) {
2817235402Stuexen		SCTP_SOCKET_UNLOCK(so, 1);
2818163953Srrs	}
2819172090Srrs#endif
2820163953Srrs}
2821163953Srrs
2822163953Srrsstatic void
2823163953Srrssctp_notify_peer_addr_change(struct sctp_tcb *stcb, uint32_t state,
2824283726Stuexen    struct sockaddr *sa, uint32_t error, int so_locked
2825283726Stuexen#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
2826283726Stuexen    SCTP_UNUSED
2827283726Stuexen#endif
2828283726Stuexen)
2829163953Srrs{
2830163953Srrs	struct mbuf *m_notify;
2831163953Srrs	struct sctp_paddr_change *spc;
2832163953Srrs	struct sctp_queued_to_read *control;
2833163953Srrs
2834228907Stuexen	if ((stcb == NULL) ||
2835228907Stuexen	    sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT)) {
2836163953Srrs		/* event not enabled */
2837163953Srrs		return;
2838185694Srrs	}
2839243882Sglebius	m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_paddr_change), 0, M_NOWAIT, 1, MT_DATA);
2840163953Srrs	if (m_notify == NULL)
2841163953Srrs		return;
2842165647Srrs	SCTP_BUF_LEN(m_notify) = 0;
2843163953Srrs	spc = mtod(m_notify, struct sctp_paddr_change *);
2844270353Stuexen	memset(spc, 0, sizeof(struct sctp_paddr_change));
2845163953Srrs	spc->spc_type = SCTP_PEER_ADDR_CHANGE;
2846163953Srrs	spc->spc_flags = 0;
2847163953Srrs	spc->spc_length = sizeof(struct sctp_paddr_change);
2848178251Srrs	switch (sa->sa_family) {
2849221328Stuexen#ifdef INET
2850178251Srrs	case AF_INET:
2851283699Stuexen#ifdef INET6
2852283699Stuexen		if (sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
2853283699Stuexen			in6_sin_2_v4mapsin6((struct sockaddr_in *)sa,
2854283699Stuexen			    (struct sockaddr_in6 *)&spc->spc_aaddr);
2855283699Stuexen		} else {
2856283699Stuexen			memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in));
2857283699Stuexen		}
2858283699Stuexen#else
2859163953Srrs		memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in));
2860283699Stuexen#endif
2861178251Srrs		break;
2862221328Stuexen#endif
2863178251Srrs#ifdef INET6
2864178251Srrs	case AF_INET6:
2865178251Srrs		{
2866178251Srrs			struct sockaddr_in6 *sin6;
2867166675Srrs
2868178251Srrs			memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in6));
2869166675Srrs
2870178251Srrs			sin6 = (struct sockaddr_in6 *)&spc->spc_aaddr;
2871178251Srrs			if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) {
2872178251Srrs				if (sin6->sin6_scope_id == 0) {
2873178251Srrs					/* recover scope_id for user */
2874178251Srrs					(void)sa6_recoverscope(sin6);
2875178251Srrs				} else {
2876178251Srrs					/* clear embedded scope_id for user */
2877178251Srrs					in6_clearscope(&sin6->sin6_addr);
2878178251Srrs				}
2879167598Srrs			}
2880178251Srrs			break;
2881166675Srrs		}
2882178251Srrs#endif
2883178251Srrs	default:
2884178251Srrs		/* TSNH */
2885178251Srrs		break;
2886163953Srrs	}
2887163953Srrs	spc->spc_state = state;
2888163953Srrs	spc->spc_error = error;
2889163953Srrs	spc->spc_assoc_id = sctp_get_associd(stcb);
2890163953Srrs
2891165647Srrs	SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_paddr_change);
2892165647Srrs	SCTP_BUF_NEXT(m_notify) = NULL;
2893163953Srrs
2894163953Srrs	/* append to socket */
2895163953Srrs	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
2896228653Stuexen	    0, 0, stcb->asoc.context, 0, 0, 0,
2897163953Srrs	    m_notify);
2898163953Srrs	if (control == NULL) {
2899163953Srrs		/* no memory */
2900163953Srrs		sctp_m_freem(m_notify);
2901163953Srrs		return;
2902163953Srrs	}
2903165647Srrs	control->length = SCTP_BUF_LEN(m_notify);
2904165647Srrs	control->spec_flags = M_NOTIFICATION;
2905163953Srrs	/* not that we need this */
2906163953Srrs	control->tail_mbuf = m_notify;
2907163953Srrs	sctp_add_to_readq(stcb->sctp_ep, stcb,
2908163953Srrs	    control,
2909195918Srrs	    &stcb->sctp_socket->so_rcv, 1,
2910195918Srrs	    SCTP_READ_LOCK_NOT_HELD,
2911283726Stuexen	    so_locked);
2912163953Srrs}
2913163953Srrs
2914163953Srrs
2915163953Srrsstatic void
2916235416Stuexensctp_notify_send_failed(struct sctp_tcb *stcb, uint8_t sent, uint32_t error,
2917172090Srrs    struct sctp_tmit_chunk *chk, int so_locked
2918172090Srrs#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
2919172090Srrs    SCTP_UNUSED
2920172090Srrs#endif
2921172090Srrs)
2922163953Srrs{
2923185694Srrs	struct mbuf *m_notify;
2924163953Srrs	struct sctp_send_failed *ssf;
2925235075Stuexen	struct sctp_send_failed_event *ssfe;
2926163953Srrs	struct sctp_queued_to_read *control;
2927163953Srrs	int length;
2928163953Srrs
2929228907Stuexen	if ((stcb == NULL) ||
2930235075Stuexen	    (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT) &&
2931235075Stuexen	    sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT))) {
2932163953Srrs		/* event not enabled */
2933163953Srrs		return;
2934185694Srrs	}
2935235075Stuexen	if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) {
2936235075Stuexen		length = sizeof(struct sctp_send_failed_event);
2937235075Stuexen	} else {
2938235075Stuexen		length = sizeof(struct sctp_send_failed);
2939235075Stuexen	}
2940243882Sglebius	m_notify = sctp_get_mbuf_for_msg(length, 0, M_NOWAIT, 1, MT_DATA);
2941163953Srrs	if (m_notify == NULL)
2942163953Srrs		/* no space left */
2943163953Srrs		return;
2944165647Srrs	SCTP_BUF_LEN(m_notify) = 0;
2945235075Stuexen	if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) {
2946235075Stuexen		ssfe = mtod(m_notify, struct sctp_send_failed_event *);
2947268432Sdelphij		memset(ssfe, 0, length);
2948235075Stuexen		ssfe->ssfe_type = SCTP_SEND_FAILED_EVENT;
2949235416Stuexen		if (sent) {
2950235416Stuexen			ssfe->ssfe_flags = SCTP_DATA_SENT;
2951235416Stuexen		} else {
2952235075Stuexen			ssfe->ssfe_flags = SCTP_DATA_UNSENT;
2953235416Stuexen		}
2954268432Sdelphij		length += chk->send_size;
2955268432Sdelphij		length -= sizeof(struct sctp_data_chunk);
2956235075Stuexen		ssfe->ssfe_length = length;
2957235075Stuexen		ssfe->ssfe_error = error;
2958235075Stuexen		/* not exactly what the user sent in, but should be close :) */
2959235075Stuexen		ssfe->ssfe_info.snd_sid = chk->rec.data.stream_number;
2960235075Stuexen		ssfe->ssfe_info.snd_flags = chk->rec.data.rcv_flags;
2961235075Stuexen		ssfe->ssfe_info.snd_ppid = chk->rec.data.payloadtype;
2962235075Stuexen		ssfe->ssfe_info.snd_context = chk->rec.data.context;
2963235075Stuexen		ssfe->ssfe_info.snd_assoc_id = sctp_get_associd(stcb);
2964235075Stuexen		ssfe->ssfe_assoc_id = sctp_get_associd(stcb);
2965235075Stuexen		SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed_event);
2966235075Stuexen	} else {
2967235075Stuexen		ssf = mtod(m_notify, struct sctp_send_failed *);
2968268432Sdelphij		memset(ssf, 0, length);
2969235075Stuexen		ssf->ssf_type = SCTP_SEND_FAILED;
2970235416Stuexen		if (sent) {
2971235416Stuexen			ssf->ssf_flags = SCTP_DATA_SENT;
2972235416Stuexen		} else {
2973235075Stuexen			ssf->ssf_flags = SCTP_DATA_UNSENT;
2974235416Stuexen		}
2975268432Sdelphij		length += chk->send_size;
2976268432Sdelphij		length -= sizeof(struct sctp_data_chunk);
2977235075Stuexen		ssf->ssf_length = length;
2978235075Stuexen		ssf->ssf_error = error;
2979235075Stuexen		/* not exactly what the user sent in, but should be close :) */
2980235075Stuexen		bzero(&ssf->ssf_info, sizeof(ssf->ssf_info));
2981235075Stuexen		ssf->ssf_info.sinfo_stream = chk->rec.data.stream_number;
2982235075Stuexen		ssf->ssf_info.sinfo_ssn = chk->rec.data.stream_seq;
2983235075Stuexen		ssf->ssf_info.sinfo_flags = chk->rec.data.rcv_flags;
2984235075Stuexen		ssf->ssf_info.sinfo_ppid = chk->rec.data.payloadtype;
2985235075Stuexen		ssf->ssf_info.sinfo_context = chk->rec.data.context;
2986235075Stuexen		ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb);
2987235075Stuexen		ssf->ssf_assoc_id = sctp_get_associd(stcb);
2988235075Stuexen		SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed);
2989235075Stuexen	}
2990185694Srrs	if (chk->data) {
2991185694Srrs		/*
2992185694Srrs		 * trim off the sctp chunk header(it should be there)
2993185694Srrs		 */
2994185694Srrs		if (chk->send_size >= sizeof(struct sctp_data_chunk)) {
2995185694Srrs			m_adj(chk->data, sizeof(struct sctp_data_chunk));
2996185694Srrs			sctp_mbuf_crush(chk->data);
2997185694Srrs			chk->send_size -= sizeof(struct sctp_data_chunk);
2998185694Srrs		}
2999185694Srrs	}
3000196260Stuexen	SCTP_BUF_NEXT(m_notify) = chk->data;
3001163953Srrs	/* Steal off the mbuf */
3002163953Srrs	chk->data = NULL;
3003163953Srrs	/*
3004163953Srrs	 * For this case, we check the actual socket buffer, since the assoc
3005163953Srrs	 * is going away we don't want to overfill the socket buffer for a
3006163953Srrs	 * non-reader
3007163953Srrs	 */
3008165647Srrs	if (sctp_sbspace_failedmsgs(&stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) {
3009163953Srrs		sctp_m_freem(m_notify);
3010163953Srrs		return;
3011163953Srrs	}
3012163953Srrs	/* append to socket */
3013163953Srrs	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
3014228653Stuexen	    0, 0, stcb->asoc.context, 0, 0, 0,
3015163953Srrs	    m_notify);
3016163953Srrs	if (control == NULL) {
3017163953Srrs		/* no memory */
3018163953Srrs		sctp_m_freem(m_notify);
3019163953Srrs		return;
3020163953Srrs	}
3021165647Srrs	control->spec_flags = M_NOTIFICATION;
3022163953Srrs	sctp_add_to_readq(stcb->sctp_ep, stcb,
3023163953Srrs	    control,
3024195918Srrs	    &stcb->sctp_socket->so_rcv, 1,
3025195918Srrs	    SCTP_READ_LOCK_NOT_HELD,
3026195918Srrs	    so_locked);
3027163953Srrs}
3028163953Srrs
3029163953Srrs
3030163953Srrsstatic void
3031163953Srrssctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error,
3032172090Srrs    struct sctp_stream_queue_pending *sp, int so_locked
3033172090Srrs#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
3034172090Srrs    SCTP_UNUSED
3035172090Srrs#endif
3036172090Srrs)
3037163953Srrs{
3038163953Srrs	struct mbuf *m_notify;
3039163953Srrs	struct sctp_send_failed *ssf;
3040235075Stuexen	struct sctp_send_failed_event *ssfe;
3041163953Srrs	struct sctp_queued_to_read *control;
3042163953Srrs	int length;
3043163953Srrs
3044228907Stuexen	if ((stcb == NULL) ||
3045235075Stuexen	    (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT) &&
3046235075Stuexen	    sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT))) {
3047163953Srrs		/* event not enabled */
3048163953Srrs		return;
3049185694Srrs	}
3050235075Stuexen	if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) {
3051235075Stuexen		length = sizeof(struct sctp_send_failed_event);
3052235075Stuexen	} else {
3053235075Stuexen		length = sizeof(struct sctp_send_failed);
3054235075Stuexen	}
3055243882Sglebius	m_notify = sctp_get_mbuf_for_msg(length, 0, M_NOWAIT, 1, MT_DATA);
3056235075Stuexen	if (m_notify == NULL) {
3057163953Srrs		/* no space left */
3058163953Srrs		return;
3059235075Stuexen	}
3060165647Srrs	SCTP_BUF_LEN(m_notify) = 0;
3061235075Stuexen	if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) {
3062235075Stuexen		ssfe = mtod(m_notify, struct sctp_send_failed_event *);
3063268432Sdelphij		memset(ssfe, 0, length);
3064238458Stuexen		ssfe->ssfe_type = SCTP_SEND_FAILED_EVENT;
3065235416Stuexen		ssfe->ssfe_flags = SCTP_DATA_UNSENT;
3066268432Sdelphij		length += sp->length;
3067235075Stuexen		ssfe->ssfe_length = length;
3068235075Stuexen		ssfe->ssfe_error = error;
3069235075Stuexen		/* not exactly what the user sent in, but should be close :) */
3070235075Stuexen		ssfe->ssfe_info.snd_sid = sp->stream;
3071235075Stuexen		if (sp->some_taken) {
3072235075Stuexen			ssfe->ssfe_info.snd_flags = SCTP_DATA_LAST_FRAG;
3073235075Stuexen		} else {
3074235075Stuexen			ssfe->ssfe_info.snd_flags = SCTP_DATA_NOT_FRAG;
3075235075Stuexen		}
3076235075Stuexen		ssfe->ssfe_info.snd_ppid = sp->ppid;
3077235075Stuexen		ssfe->ssfe_info.snd_context = sp->context;
3078235075Stuexen		ssfe->ssfe_info.snd_assoc_id = sctp_get_associd(stcb);
3079235075Stuexen		ssfe->ssfe_assoc_id = sctp_get_associd(stcb);
3080235075Stuexen		SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed_event);
3081180387Srrs	} else {
3082235075Stuexen		ssf = mtod(m_notify, struct sctp_send_failed *);
3083268432Sdelphij		memset(ssf, 0, length);
3084235075Stuexen		ssf->ssf_type = SCTP_SEND_FAILED;
3085235416Stuexen		ssf->ssf_flags = SCTP_DATA_UNSENT;
3086268432Sdelphij		length += sp->length;
3087235075Stuexen		ssf->ssf_length = length;
3088235075Stuexen		ssf->ssf_error = error;
3089235075Stuexen		/* not exactly what the user sent in, but should be close :) */
3090235075Stuexen		ssf->ssf_info.sinfo_stream = sp->stream;
3091242627Stuexen		ssf->ssf_info.sinfo_ssn = 0;
3092235075Stuexen		if (sp->some_taken) {
3093235075Stuexen			ssf->ssf_info.sinfo_flags = SCTP_DATA_LAST_FRAG;
3094235075Stuexen		} else {
3095235075Stuexen			ssf->ssf_info.sinfo_flags = SCTP_DATA_NOT_FRAG;
3096235075Stuexen		}
3097235075Stuexen		ssf->ssf_info.sinfo_ppid = sp->ppid;
3098235075Stuexen		ssf->ssf_info.sinfo_context = sp->context;
3099235075Stuexen		ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb);
3100235075Stuexen		ssf->ssf_assoc_id = sctp_get_associd(stcb);
3101235075Stuexen		SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed);
3102180387Srrs	}
3103165647Srrs	SCTP_BUF_NEXT(m_notify) = sp->data;
3104163953Srrs
3105163953Srrs	/* Steal off the mbuf */
3106163953Srrs	sp->data = NULL;
3107163953Srrs	/*
3108163953Srrs	 * For this case, we check the actual socket buffer, since the assoc
3109163953Srrs	 * is going away we don't want to overfill the socket buffer for a
3110163953Srrs	 * non-reader
3111163953Srrs	 */
3112165647Srrs	if (sctp_sbspace_failedmsgs(&stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) {
3113163953Srrs		sctp_m_freem(m_notify);
3114163953Srrs		return;
3115163953Srrs	}
3116163953Srrs	/* append to socket */
3117163953Srrs	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
3118228653Stuexen	    0, 0, stcb->asoc.context, 0, 0, 0,
3119163953Srrs	    m_notify);
3120163953Srrs	if (control == NULL) {
3121163953Srrs		/* no memory */
3122163953Srrs		sctp_m_freem(m_notify);
3123163953Srrs		return;
3124163953Srrs	}
3125165647Srrs	control->spec_flags = M_NOTIFICATION;
3126163953Srrs	sctp_add_to_readq(stcb->sctp_ep, stcb,
3127163953Srrs	    control,
3128195918Srrs	    &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, so_locked);
3129163953Srrs}
3130163953Srrs
3131163953Srrs
3132163953Srrs
3133163953Srrsstatic void
3134228653Stuexensctp_notify_adaptation_layer(struct sctp_tcb *stcb)
3135163953Srrs{
3136163953Srrs	struct mbuf *m_notify;
3137163953Srrs	struct sctp_adaptation_event *sai;
3138163953Srrs	struct sctp_queued_to_read *control;
3139163953Srrs
3140228907Stuexen	if ((stcb == NULL) ||
3141228907Stuexen	    sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT)) {
3142163953Srrs		/* event not enabled */
3143163953Srrs		return;
3144185694Srrs	}
3145243882Sglebius	m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_adaption_event), 0, M_NOWAIT, 1, MT_DATA);
3146163953Srrs	if (m_notify == NULL)
3147163953Srrs		/* no space left */
3148163953Srrs		return;
3149165647Srrs	SCTP_BUF_LEN(m_notify) = 0;
3150163953Srrs	sai = mtod(m_notify, struct sctp_adaptation_event *);
3151268432Sdelphij	memset(sai, 0, sizeof(struct sctp_adaptation_event));
3152163953Srrs	sai->sai_type = SCTP_ADAPTATION_INDICATION;
3153163953Srrs	sai->sai_flags = 0;
3154163953Srrs	sai->sai_length = sizeof(struct sctp_adaptation_event);
3155171990Srrs	sai->sai_adaptation_ind = stcb->asoc.peers_adaptation;
3156163953Srrs	sai->sai_assoc_id = sctp_get_associd(stcb);
3157163953Srrs
3158165647Srrs	SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_adaptation_event);
3159165647Srrs	SCTP_BUF_NEXT(m_notify) = NULL;
3160163953Srrs
3161163953Srrs	/* append to socket */
3162163953Srrs	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
3163228653Stuexen	    0, 0, stcb->asoc.context, 0, 0, 0,
3164163953Srrs	    m_notify);
3165163953Srrs	if (control == NULL) {
3166163953Srrs		/* no memory */
3167163953Srrs		sctp_m_freem(m_notify);
3168163953Srrs		return;
3169163953Srrs	}
3170165647Srrs	control->length = SCTP_BUF_LEN(m_notify);
3171165647Srrs	control->spec_flags = M_NOTIFICATION;
3172163953Srrs	/* not that we need this */
3173163953Srrs	control->tail_mbuf = m_notify;
3174163953Srrs	sctp_add_to_readq(stcb->sctp_ep, stcb,
3175163953Srrs	    control,
3176195918Srrs	    &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
3177163953Srrs}
3178163953Srrs
3179164085Srrs/* This always must be called with the read-queue LOCKED in the INP */
3180196260Stuexenstatic void
3181171858Srrssctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, uint32_t error,
3182196260Stuexen    uint32_t val, int so_locked
3183196260Stuexen#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
3184196260Stuexen    SCTP_UNUSED
3185196260Stuexen#endif
3186196260Stuexen)
3187163953Srrs{
3188163953Srrs	struct mbuf *m_notify;
3189163953Srrs	struct sctp_pdapi_event *pdapi;
3190163953Srrs	struct sctp_queued_to_read *control;
3191164085Srrs	struct sockbuf *sb;
3192163953Srrs
3193228907Stuexen	if ((stcb == NULL) ||
3194228907Stuexen	    sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_PDAPIEVNT)) {
3195163953Srrs		/* event not enabled */
3196163953Srrs		return;
3197185694Srrs	}
3198209289Stuexen	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_CANT_READ) {
3199209289Stuexen		return;
3200209289Stuexen	}
3201243882Sglebius	m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_pdapi_event), 0, M_NOWAIT, 1, MT_DATA);
3202163953Srrs	if (m_notify == NULL)
3203163953Srrs		/* no space left */
3204163953Srrs		return;
3205165647Srrs	SCTP_BUF_LEN(m_notify) = 0;
3206163953Srrs	pdapi = mtod(m_notify, struct sctp_pdapi_event *);
3207268432Sdelphij	memset(pdapi, 0, sizeof(struct sctp_pdapi_event));
3208163953Srrs	pdapi->pdapi_type = SCTP_PARTIAL_DELIVERY_EVENT;
3209163953Srrs	pdapi->pdapi_flags = 0;
3210163953Srrs	pdapi->pdapi_length = sizeof(struct sctp_pdapi_event);
3211163953Srrs	pdapi->pdapi_indication = error;
3212168943Srrs	pdapi->pdapi_stream = (val >> 16);
3213168943Srrs	pdapi->pdapi_seq = (val & 0x0000ffff);
3214163953Srrs	pdapi->pdapi_assoc_id = sctp_get_associd(stcb);
3215163953Srrs
3216165647Srrs	SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_pdapi_event);
3217165647Srrs	SCTP_BUF_NEXT(m_notify) = NULL;
3218164085Srrs	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
3219228653Stuexen	    0, 0, stcb->asoc.context, 0, 0, 0,
3220164085Srrs	    m_notify);
3221164085Srrs	if (control == NULL) {
3222164085Srrs		/* no memory */
3223164085Srrs		sctp_m_freem(m_notify);
3224164085Srrs		return;
3225164085Srrs	}
3226165647Srrs	control->spec_flags = M_NOTIFICATION;
3227165647Srrs	control->length = SCTP_BUF_LEN(m_notify);
3228164085Srrs	/* not that we need this */
3229164085Srrs	control->tail_mbuf = m_notify;
3230164085Srrs	control->held_length = 0;
3231164085Srrs	control->length = 0;
3232164085Srrs	sb = &stcb->sctp_socket->so_rcv;
3233179783Srrs	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
3234170744Srrs		sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(m_notify));
3235170744Srrs	}
3236164085Srrs	sctp_sballoc(stcb, sb, m_notify);
3237179783Srrs	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
3238170744Srrs		sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0);
3239170744Srrs	}
3240165647Srrs	atomic_add_int(&control->length, SCTP_BUF_LEN(m_notify));
3241164085Srrs	control->end_added = 1;
3242164085Srrs	if (stcb->asoc.control_pdapi)
3243164085Srrs		TAILQ_INSERT_AFTER(&stcb->sctp_ep->read_queue, stcb->asoc.control_pdapi, control, next);
3244164085Srrs	else {
3245164085Srrs		/* we really should not see this case */
3246164085Srrs		TAILQ_INSERT_TAIL(&stcb->sctp_ep->read_queue, control, next);
3247164085Srrs	}
3248164085Srrs	if (stcb->sctp_ep && stcb->sctp_socket) {
3249164085Srrs		/* This should always be the case */
3250237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
3251196260Stuexen		struct socket *so;
3252196260Stuexen
3253196260Stuexen		so = SCTP_INP_SO(stcb->sctp_ep);
3254196260Stuexen		if (!so_locked) {
3255196260Stuexen			atomic_add_int(&stcb->asoc.refcnt, 1);
3256196260Stuexen			SCTP_TCB_UNLOCK(stcb);
3257196260Stuexen			SCTP_SOCKET_LOCK(so, 1);
3258196260Stuexen			SCTP_TCB_LOCK(stcb);
3259196260Stuexen			atomic_subtract_int(&stcb->asoc.refcnt, 1);
3260196260Stuexen			if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
3261196260Stuexen				SCTP_SOCKET_UNLOCK(so, 1);
3262196260Stuexen				return;
3263196260Stuexen			}
3264196260Stuexen		}
3265196260Stuexen#endif
3266163996Srrs		sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
3267237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
3268196260Stuexen		if (!so_locked) {
3269196260Stuexen			SCTP_SOCKET_UNLOCK(so, 1);
3270196260Stuexen		}
3271196260Stuexen#endif
3272163953Srrs	}
3273163953Srrs}
3274163953Srrs
3275163953Srrsstatic void
3276163953Srrssctp_notify_shutdown_event(struct sctp_tcb *stcb)
3277163953Srrs{
3278163953Srrs	struct mbuf *m_notify;
3279163953Srrs	struct sctp_shutdown_event *sse;
3280163953Srrs	struct sctp_queued_to_read *control;
3281163953Srrs
3282163953Srrs	/*
3283163953Srrs	 * For TCP model AND UDP connected sockets we will send an error up
3284163953Srrs	 * when an SHUTDOWN completes
3285163953Srrs	 */
3286163953Srrs	if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3287163953Srrs	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
3288163953Srrs		/* mark socket closed for read/write and wakeup! */
3289237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
3290172090Srrs		struct socket *so;
3291172090Srrs
3292172090Srrs		so = SCTP_INP_SO(stcb->sctp_ep);
3293172090Srrs		atomic_add_int(&stcb->asoc.refcnt, 1);
3294172090Srrs		SCTP_TCB_UNLOCK(stcb);
3295172090Srrs		SCTP_SOCKET_LOCK(so, 1);
3296172090Srrs		SCTP_TCB_LOCK(stcb);
3297172090Srrs		atomic_subtract_int(&stcb->asoc.refcnt, 1);
3298172090Srrs		if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
3299172090Srrs			SCTP_SOCKET_UNLOCK(so, 1);
3300172090Srrs			return;
3301172090Srrs		}
3302172090Srrs#endif
3303163953Srrs		socantsendmore(stcb->sctp_socket);
3304237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
3305172090Srrs		SCTP_SOCKET_UNLOCK(so, 1);
3306172090Srrs#endif
3307163953Srrs	}
3308223132Stuexen	if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT)) {
3309163953Srrs		/* event not enabled */
3310163953Srrs		return;
3311185694Srrs	}
3312243882Sglebius	m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_shutdown_event), 0, M_NOWAIT, 1, MT_DATA);
3313163953Srrs	if (m_notify == NULL)
3314163953Srrs		/* no space left */
3315163953Srrs		return;
3316163953Srrs	sse = mtod(m_notify, struct sctp_shutdown_event *);
3317268432Sdelphij	memset(sse, 0, sizeof(struct sctp_shutdown_event));
3318163953Srrs	sse->sse_type = SCTP_SHUTDOWN_EVENT;
3319163953Srrs	sse->sse_flags = 0;
3320163953Srrs	sse->sse_length = sizeof(struct sctp_shutdown_event);
3321163953Srrs	sse->sse_assoc_id = sctp_get_associd(stcb);
3322163953Srrs
3323165647Srrs	SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_shutdown_event);
3324165647Srrs	SCTP_BUF_NEXT(m_notify) = NULL;
3325163953Srrs
3326163953Srrs	/* append to socket */
3327163953Srrs	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
3328228653Stuexen	    0, 0, stcb->asoc.context, 0, 0, 0,
3329163953Srrs	    m_notify);
3330163953Srrs	if (control == NULL) {
3331163953Srrs		/* no memory */
3332163953Srrs		sctp_m_freem(m_notify);
3333163953Srrs		return;
3334163953Srrs	}
3335165647Srrs	control->spec_flags = M_NOTIFICATION;
3336165647Srrs	control->length = SCTP_BUF_LEN(m_notify);
3337163953Srrs	/* not that we need this */
3338163953Srrs	control->tail_mbuf = m_notify;
3339163953Srrs	sctp_add_to_readq(stcb->sctp_ep, stcb,
3340163953Srrs	    control,
3341195918Srrs	    &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
3342163953Srrs}
3343163953Srrs
3344163953Srrsstatic void
3345185694Srrssctp_notify_sender_dry_event(struct sctp_tcb *stcb,
3346185694Srrs    int so_locked
3347185694Srrs#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
3348185694Srrs    SCTP_UNUSED
3349185694Srrs#endif
3350185694Srrs)
3351185694Srrs{
3352185694Srrs	struct mbuf *m_notify;
3353185694Srrs	struct sctp_sender_dry_event *event;
3354185694Srrs	struct sctp_queued_to_read *control;
3355185694Srrs
3356228907Stuexen	if ((stcb == NULL) ||
3357228907Stuexen	    sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_DRYEVNT)) {
3358185694Srrs		/* event not enabled */
3359185694Srrs		return;
3360185694Srrs	}
3361243882Sglebius	m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_sender_dry_event), 0, M_NOWAIT, 1, MT_DATA);
3362185694Srrs	if (m_notify == NULL) {
3363185694Srrs		/* no space left */
3364185694Srrs		return;
3365185694Srrs	}
3366185694Srrs	SCTP_BUF_LEN(m_notify) = 0;
3367185694Srrs	event = mtod(m_notify, struct sctp_sender_dry_event *);
3368268432Sdelphij	memset(event, 0, sizeof(struct sctp_sender_dry_event));
3369185694Srrs	event->sender_dry_type = SCTP_SENDER_DRY_EVENT;
3370185694Srrs	event->sender_dry_flags = 0;
3371185694Srrs	event->sender_dry_length = sizeof(struct sctp_sender_dry_event);
3372185694Srrs	event->sender_dry_assoc_id = sctp_get_associd(stcb);
3373185694Srrs
3374185694Srrs	SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_sender_dry_event);
3375185694Srrs	SCTP_BUF_NEXT(m_notify) = NULL;
3376185694Srrs
3377185694Srrs	/* append to socket */
3378185694Srrs	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
3379228653Stuexen	    0, 0, stcb->asoc.context, 0, 0, 0,
3380228653Stuexen	    m_notify);
3381185694Srrs	if (control == NULL) {
3382185694Srrs		/* no memory */
3383185694Srrs		sctp_m_freem(m_notify);
3384185694Srrs		return;
3385185694Srrs	}
3386185694Srrs	control->length = SCTP_BUF_LEN(m_notify);
3387185694Srrs	control->spec_flags = M_NOTIFICATION;
3388185694Srrs	/* not that we need this */
3389185694Srrs	control->tail_mbuf = m_notify;
3390185694Srrs	sctp_add_to_readq(stcb->sctp_ep, stcb, control,
3391195918Srrs	    &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, so_locked);
3392185694Srrs}
3393185694Srrs
3394188854Srrs
3395233660Srrsvoid
3396233660Srrssctp_notify_stream_reset_add(struct sctp_tcb *stcb, uint16_t numberin, uint16_t numberout, int flag)
3397188854Srrs{
3398188854Srrs	struct mbuf *m_notify;
3399188854Srrs	struct sctp_queued_to_read *control;
3400233660Srrs	struct sctp_stream_change_event *stradd;
3401188854Srrs
3402235091Stuexen	if ((stcb == NULL) ||
3403235091Stuexen	    (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_STREAM_CHANGEEVNT))) {
3404188854Srrs		/* event not enabled */
3405188854Srrs		return;
3406188854Srrs	}
3407233660Srrs	if ((stcb->asoc.peer_req_out) && flag) {
3408233660Srrs		/* Peer made the request, don't tell the local user */
3409233660Srrs		stcb->asoc.peer_req_out = 0;
3410233660Srrs		return;
3411233660Srrs	}
3412233660Srrs	stcb->asoc.peer_req_out = 0;
3413268432Sdelphij	m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_stream_change_event), 0, M_NOWAIT, 1, MT_DATA);
3414188854Srrs	if (m_notify == NULL)
3415188854Srrs		/* no space left */
3416188854Srrs		return;
3417188854Srrs	SCTP_BUF_LEN(m_notify) = 0;
3418233660Srrs	stradd = mtod(m_notify, struct sctp_stream_change_event *);
3419268432Sdelphij	memset(stradd, 0, sizeof(struct sctp_stream_change_event));
3420233660Srrs	stradd->strchange_type = SCTP_STREAM_CHANGE_EVENT;
3421233660Srrs	stradd->strchange_flags = flag;
3422268432Sdelphij	stradd->strchange_length = sizeof(struct sctp_stream_change_event);
3423233660Srrs	stradd->strchange_assoc_id = sctp_get_associd(stcb);
3424233660Srrs	stradd->strchange_instrms = numberin;
3425233660Srrs	stradd->strchange_outstrms = numberout;
3426268432Sdelphij	SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_stream_change_event);
3427233660Srrs	SCTP_BUF_NEXT(m_notify) = NULL;
3428233660Srrs	if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) {
3429233660Srrs		/* no space */
3430233660Srrs		sctp_m_freem(m_notify);
3431233660Srrs		return;
3432233660Srrs	}
3433233660Srrs	/* append to socket */
3434233660Srrs	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
3435233660Srrs	    0, 0, stcb->asoc.context, 0, 0, 0,
3436233660Srrs	    m_notify);
3437233660Srrs	if (control == NULL) {
3438233660Srrs		/* no memory */
3439233660Srrs		sctp_m_freem(m_notify);
3440233660Srrs		return;
3441233660Srrs	}
3442233660Srrs	control->spec_flags = M_NOTIFICATION;
3443233660Srrs	control->length = SCTP_BUF_LEN(m_notify);
3444233660Srrs	/* not that we need this */
3445233660Srrs	control->tail_mbuf = m_notify;
3446233660Srrs	sctp_add_to_readq(stcb->sctp_ep, stcb,
3447233660Srrs	    control,
3448233660Srrs	    &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
3449233660Srrs}
3450188854Srrs
3451233660Srrsvoid
3452233660Srrssctp_notify_stream_reset_tsn(struct sctp_tcb *stcb, uint32_t sending_tsn, uint32_t recv_tsn, int flag)
3453233660Srrs{
3454233660Srrs	struct mbuf *m_notify;
3455233660Srrs	struct sctp_queued_to_read *control;
3456233660Srrs	struct sctp_assoc_reset_event *strasoc;
3457233660Srrs
3458235091Stuexen	if ((stcb == NULL) ||
3459235091Stuexen	    (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_ASSOC_RESETEVNT))) {
3460233660Srrs		/* event not enabled */
3461233660Srrs		return;
3462233660Srrs	}
3463268432Sdelphij	m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_assoc_reset_event), 0, M_NOWAIT, 1, MT_DATA);
3464233660Srrs	if (m_notify == NULL)
3465233660Srrs		/* no space left */
3466233660Srrs		return;
3467233660Srrs	SCTP_BUF_LEN(m_notify) = 0;
3468233660Srrs	strasoc = mtod(m_notify, struct sctp_assoc_reset_event *);
3469268432Sdelphij	memset(strasoc, 0, sizeof(struct sctp_assoc_reset_event));
3470233660Srrs	strasoc->assocreset_type = SCTP_ASSOC_RESET_EVENT;
3471233660Srrs	strasoc->assocreset_flags = flag;
3472268432Sdelphij	strasoc->assocreset_length = sizeof(struct sctp_assoc_reset_event);
3473233660Srrs	strasoc->assocreset_assoc_id = sctp_get_associd(stcb);
3474233660Srrs	strasoc->assocreset_local_tsn = sending_tsn;
3475233660Srrs	strasoc->assocreset_remote_tsn = recv_tsn;
3476268432Sdelphij	SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_assoc_reset_event);
3477188854Srrs	SCTP_BUF_NEXT(m_notify) = NULL;
3478188854Srrs	if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) {
3479188854Srrs		/* no space */
3480188854Srrs		sctp_m_freem(m_notify);
3481188854Srrs		return;
3482188854Srrs	}
3483188854Srrs	/* append to socket */
3484188854Srrs	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
3485228653Stuexen	    0, 0, stcb->asoc.context, 0, 0, 0,
3486188854Srrs	    m_notify);
3487188854Srrs	if (control == NULL) {
3488188854Srrs		/* no memory */
3489188854Srrs		sctp_m_freem(m_notify);
3490188854Srrs		return;
3491188854Srrs	}
3492188854Srrs	control->spec_flags = M_NOTIFICATION;
3493188854Srrs	control->length = SCTP_BUF_LEN(m_notify);
3494188854Srrs	/* not that we need this */
3495188854Srrs	control->tail_mbuf = m_notify;
3496188854Srrs	sctp_add_to_readq(stcb->sctp_ep, stcb,
3497188854Srrs	    control,
3498195918Srrs	    &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
3499188854Srrs}
3500188854Srrs
3501188854Srrs
3502233660Srrs
3503188854Srrsstatic void
3504163953Srrssctp_notify_stream_reset(struct sctp_tcb *stcb,
3505163953Srrs    int number_entries, uint16_t * list, int flag)
3506163953Srrs{
3507163953Srrs	struct mbuf *m_notify;
3508163953Srrs	struct sctp_queued_to_read *control;
3509163953Srrs	struct sctp_stream_reset_event *strreset;
3510163953Srrs	int len;
3511163953Srrs
3512235091Stuexen	if ((stcb == NULL) ||
3513235091Stuexen	    (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT))) {
3514185694Srrs		/* event not enabled */
3515169420Srrs		return;
3516169420Srrs	}
3517243882Sglebius	m_notify = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA);
3518163953Srrs	if (m_notify == NULL)
3519163953Srrs		/* no space left */
3520163953Srrs		return;
3521165647Srrs	SCTP_BUF_LEN(m_notify) = 0;
3522163953Srrs	len = sizeof(struct sctp_stream_reset_event) + (number_entries * sizeof(uint16_t));
3523163953Srrs	if (len > M_TRAILINGSPACE(m_notify)) {
3524163953Srrs		/* never enough room */
3525163953Srrs		sctp_m_freem(m_notify);
3526163953Srrs		return;
3527163953Srrs	}
3528163953Srrs	strreset = mtod(m_notify, struct sctp_stream_reset_event *);
3529268432Sdelphij	memset(strreset, 0, len);
3530163953Srrs	strreset->strreset_type = SCTP_STREAM_RESET_EVENT;
3531233660Srrs	strreset->strreset_flags = flag;
3532163953Srrs	strreset->strreset_length = len;
3533163953Srrs	strreset->strreset_assoc_id = sctp_get_associd(stcb);
3534163953Srrs	if (number_entries) {
3535163953Srrs		int i;
3536163953Srrs
3537163953Srrs		for (i = 0; i < number_entries; i++) {
3538233660Srrs			strreset->strreset_stream_list[i] = ntohs(list[i]);
3539163953Srrs		}
3540163953Srrs	}
3541165647Srrs	SCTP_BUF_LEN(m_notify) = len;
3542165647Srrs	SCTP_BUF_NEXT(m_notify) = NULL;
3543165647Srrs	if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) {
3544163953Srrs		/* no space */
3545163953Srrs		sctp_m_freem(m_notify);
3546163953Srrs		return;
3547163953Srrs	}
3548163953Srrs	/* append to socket */
3549163953Srrs	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
3550228653Stuexen	    0, 0, stcb->asoc.context, 0, 0, 0,
3551163953Srrs	    m_notify);
3552163953Srrs	if (control == NULL) {
3553163953Srrs		/* no memory */
3554163953Srrs		sctp_m_freem(m_notify);
3555163953Srrs		return;
3556163953Srrs	}
3557165647Srrs	control->spec_flags = M_NOTIFICATION;
3558165647Srrs	control->length = SCTP_BUF_LEN(m_notify);
3559163953Srrs	/* not that we need this */
3560163953Srrs	control->tail_mbuf = m_notify;
3561163953Srrs	sctp_add_to_readq(stcb->sctp_ep, stcb,
3562163953Srrs	    control,
3563195918Srrs	    &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
3564163953Srrs}
3565163953Srrs
3566163953Srrs
3567235418Stuexenstatic void
3568235418Stuexensctp_notify_remote_error(struct sctp_tcb *stcb, uint16_t error, struct sctp_error_chunk *chunk)
3569235418Stuexen{
3570235418Stuexen	struct mbuf *m_notify;
3571235418Stuexen	struct sctp_remote_error *sre;
3572235418Stuexen	struct sctp_queued_to_read *control;
3573235418Stuexen	size_t notif_len, chunk_len;
3574235418Stuexen
3575235418Stuexen	if ((stcb == NULL) ||
3576235418Stuexen	    sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVPEERERR)) {
3577235418Stuexen		return;
3578235418Stuexen	}
3579235418Stuexen	if (chunk != NULL) {
3580258454Stuexen		chunk_len = ntohs(chunk->ch.chunk_length);
3581235418Stuexen	} else {
3582235418Stuexen		chunk_len = 0;
3583235418Stuexen	}
3584235418Stuexen	notif_len = sizeof(struct sctp_remote_error) + chunk_len;
3585243882Sglebius	m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA);
3586235418Stuexen	if (m_notify == NULL) {
3587235418Stuexen		/* Retry with smaller value. */
3588235418Stuexen		notif_len = sizeof(struct sctp_remote_error);
3589243882Sglebius		m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA);
3590235418Stuexen		if (m_notify == NULL) {
3591235418Stuexen			return;
3592235418Stuexen		}
3593235418Stuexen	}
3594235418Stuexen	SCTP_BUF_NEXT(m_notify) = NULL;
3595235418Stuexen	sre = mtod(m_notify, struct sctp_remote_error *);
3596270353Stuexen	memset(sre, 0, notif_len);
3597235418Stuexen	sre->sre_type = SCTP_REMOTE_ERROR;
3598235418Stuexen	sre->sre_flags = 0;
3599235418Stuexen	sre->sre_length = sizeof(struct sctp_remote_error);
3600235418Stuexen	sre->sre_error = error;
3601235418Stuexen	sre->sre_assoc_id = sctp_get_associd(stcb);
3602235418Stuexen	if (notif_len > sizeof(struct sctp_remote_error)) {
3603235418Stuexen		memcpy(sre->sre_data, chunk, chunk_len);
3604235418Stuexen		sre->sre_length += chunk_len;
3605235418Stuexen	}
3606235418Stuexen	SCTP_BUF_LEN(m_notify) = sre->sre_length;
3607235418Stuexen	control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
3608235418Stuexen	    0, 0, stcb->asoc.context, 0, 0, 0,
3609235418Stuexen	    m_notify);
3610235418Stuexen	if (control != NULL) {
3611235418Stuexen		control->length = SCTP_BUF_LEN(m_notify);
3612235418Stuexen		/* not that we need this */
3613235418Stuexen		control->tail_mbuf = m_notify;
3614235418Stuexen		control->spec_flags = M_NOTIFICATION;
3615235418Stuexen		sctp_add_to_readq(stcb->sctp_ep, stcb,
3616235418Stuexen		    control,
3617235418Stuexen		    &stcb->sctp_socket->so_rcv, 1,
3618235418Stuexen		    SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
3619235418Stuexen	} else {
3620235418Stuexen		sctp_m_freem(m_notify);
3621235418Stuexen	}
3622235418Stuexen}
3623235418Stuexen
3624235418Stuexen
3625163953Srrsvoid
3626163953Srrssctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
3627172090Srrs    uint32_t error, void *data, int so_locked
3628172090Srrs#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
3629172090Srrs    SCTP_UNUSED
3630172090Srrs#endif
3631172090Srrs)
3632163953Srrs{
3633185694Srrs	if ((stcb == NULL) ||
3634185694Srrs	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
3635163953Srrs	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
3636185694Srrs	    (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) {
3637185694Srrs		/* If the socket is gone we are out of here */
3638163953Srrs		return;
3639163953Srrs	}
3640188067Srrs	if (stcb->sctp_socket->so_rcv.sb_state & SBS_CANTRCVMORE) {
3641188067Srrs		return;
3642188067Srrs	}
3643251054Stuexen	if ((stcb->asoc.state & SCTP_STATE_COOKIE_WAIT) ||
3644251054Stuexen	    (stcb->asoc.state & SCTP_STATE_COOKIE_ECHOED)) {
3645169352Srrs		if ((notification == SCTP_NOTIFY_INTERFACE_DOWN) ||
3646169352Srrs		    (notification == SCTP_NOTIFY_INTERFACE_UP) ||
3647169352Srrs		    (notification == SCTP_NOTIFY_INTERFACE_CONFIRMED)) {
3648169352Srrs			/* Don't report these in front states */
3649169352Srrs			return;
3650169352Srrs		}
3651169352Srrs	}
3652163953Srrs	switch (notification) {
3653163953Srrs	case SCTP_NOTIFY_ASSOC_UP:
3654163953Srrs		if (stcb->asoc.assoc_up_sent == 0) {
3655235403Stuexen			sctp_notify_assoc_change(SCTP_COMM_UP, stcb, error, NULL, 0, so_locked);
3656163953Srrs			stcb->asoc.assoc_up_sent = 1;
3657163953Srrs		}
3658171990Srrs		if (stcb->asoc.adaptation_needed && (stcb->asoc.adaptation_sent == 0)) {
3659228653Stuexen			sctp_notify_adaptation_layer(stcb);
3660171990Srrs		}
3661270362Stuexen		if (stcb->asoc.auth_supported == 0) {
3662185694Srrs			sctp_ulp_notify(SCTP_NOTIFY_NO_PEER_AUTH, stcb, 0,
3663185694Srrs			    NULL, so_locked);
3664185694Srrs		}
3665163953Srrs		break;
3666163953Srrs	case SCTP_NOTIFY_ASSOC_DOWN:
3667235403Stuexen		sctp_notify_assoc_change(SCTP_SHUTDOWN_COMP, stcb, error, NULL, 0, so_locked);
3668163953Srrs		break;
3669163953Srrs	case SCTP_NOTIFY_INTERFACE_DOWN:
3670163953Srrs		{
3671163953Srrs			struct sctp_nets *net;
3672163953Srrs
3673163953Srrs			net = (struct sctp_nets *)data;
3674163953Srrs			sctp_notify_peer_addr_change(stcb, SCTP_ADDR_UNREACHABLE,
3675283726Stuexen			    (struct sockaddr *)&net->ro._l_addr, error, so_locked);
3676163953Srrs			break;
3677163953Srrs		}
3678163953Srrs	case SCTP_NOTIFY_INTERFACE_UP:
3679163953Srrs		{
3680163953Srrs			struct sctp_nets *net;
3681163953Srrs
3682163953Srrs			net = (struct sctp_nets *)data;
3683163953Srrs			sctp_notify_peer_addr_change(stcb, SCTP_ADDR_AVAILABLE,
3684283726Stuexen			    (struct sockaddr *)&net->ro._l_addr, error, so_locked);
3685163953Srrs			break;
3686163953Srrs		}
3687163953Srrs	case SCTP_NOTIFY_INTERFACE_CONFIRMED:
3688163953Srrs		{
3689163953Srrs			struct sctp_nets *net;
3690163953Srrs
3691163953Srrs			net = (struct sctp_nets *)data;
3692163953Srrs			sctp_notify_peer_addr_change(stcb, SCTP_ADDR_CONFIRMED,
3693283726Stuexen			    (struct sockaddr *)&net->ro._l_addr, error, so_locked);
3694163953Srrs			break;
3695163953Srrs		}
3696163953Srrs	case SCTP_NOTIFY_SPECIAL_SP_FAIL:
3697163953Srrs		sctp_notify_send_failed2(stcb, error,
3698172090Srrs		    (struct sctp_stream_queue_pending *)data, so_locked);
3699163953Srrs		break;
3700235416Stuexen	case SCTP_NOTIFY_SENT_DG_FAIL:
3701235416Stuexen		sctp_notify_send_failed(stcb, 1, error,
3702172090Srrs		    (struct sctp_tmit_chunk *)data, so_locked);
3703163953Srrs		break;
3704235416Stuexen	case SCTP_NOTIFY_UNSENT_DG_FAIL:
3705235416Stuexen		sctp_notify_send_failed(stcb, 0, error,
3706235416Stuexen		    (struct sctp_tmit_chunk *)data, so_locked);
3707235416Stuexen		break;
3708163953Srrs	case SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION:
3709168943Srrs		{
3710168943Srrs			uint32_t val;
3711168943Srrs
3712168943Srrs			val = *((uint32_t *) data);
3713168943Srrs
3714196260Stuexen			sctp_notify_partial_delivery_indication(stcb, error, val, so_locked);
3715196260Stuexen			break;
3716168943Srrs		}
3717235403Stuexen	case SCTP_NOTIFY_ASSOC_LOC_ABORTED:
3718251054Stuexen		if (((stcb->asoc.state & SCTP_STATE_MASK) == SCTP_STATE_COOKIE_WAIT) ||
3719251054Stuexen		    ((stcb->asoc.state & SCTP_STATE_MASK) == SCTP_STATE_COOKIE_ECHOED)) {
3720235403Stuexen			sctp_notify_assoc_change(SCTP_CANT_STR_ASSOC, stcb, error, data, 0, so_locked);
3721168709Srrs		} else {
3722235403Stuexen			sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error, data, 0, so_locked);
3723168709Srrs		}
3724163953Srrs		break;
3725235403Stuexen	case SCTP_NOTIFY_ASSOC_REM_ABORTED:
3726251054Stuexen		if (((stcb->asoc.state & SCTP_STATE_MASK) == SCTP_STATE_COOKIE_WAIT) ||
3727251054Stuexen		    ((stcb->asoc.state & SCTP_STATE_MASK) == SCTP_STATE_COOKIE_ECHOED)) {
3728235403Stuexen			sctp_notify_assoc_change(SCTP_CANT_STR_ASSOC, stcb, error, data, 1, so_locked);
3729235403Stuexen		} else {
3730235403Stuexen			sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error, data, 1, so_locked);
3731235403Stuexen		}
3732235403Stuexen		break;
3733163953Srrs	case SCTP_NOTIFY_ASSOC_RESTART:
3734235403Stuexen		sctp_notify_assoc_change(SCTP_RESTART, stcb, error, NULL, 0, so_locked);
3735270362Stuexen		if (stcb->asoc.auth_supported == 0) {
3736185694Srrs			sctp_ulp_notify(SCTP_NOTIFY_NO_PEER_AUTH, stcb, 0,
3737185694Srrs			    NULL, so_locked);
3738185694Srrs		}
3739163953Srrs		break;
3740163953Srrs	case SCTP_NOTIFY_STR_RESET_SEND:
3741234614Stuexen		sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), SCTP_STREAM_RESET_OUTGOING_SSN);
3742163953Srrs		break;
3743163953Srrs	case SCTP_NOTIFY_STR_RESET_RECV:
3744234614Stuexen		sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), SCTP_STREAM_RESET_INCOMING);
3745163953Srrs		break;
3746163953Srrs	case SCTP_NOTIFY_STR_RESET_FAILED_OUT:
3747233660Srrs		sctp_notify_stream_reset(stcb, error, ((uint16_t *) data),
3748234614Stuexen		    (SCTP_STREAM_RESET_OUTGOING_SSN | SCTP_STREAM_RESET_FAILED));
3749163953Srrs		break;
3750235066Stuexen	case SCTP_NOTIFY_STR_RESET_DENIED_OUT:
3751235066Stuexen		sctp_notify_stream_reset(stcb, error, ((uint16_t *) data),
3752235066Stuexen		    (SCTP_STREAM_RESET_OUTGOING_SSN | SCTP_STREAM_RESET_DENIED));
3753235066Stuexen		break;
3754163953Srrs	case SCTP_NOTIFY_STR_RESET_FAILED_IN:
3755233660Srrs		sctp_notify_stream_reset(stcb, error, ((uint16_t *) data),
3756234614Stuexen		    (SCTP_STREAM_RESET_INCOMING | SCTP_STREAM_RESET_FAILED));
3757163953Srrs		break;
3758235066Stuexen	case SCTP_NOTIFY_STR_RESET_DENIED_IN:
3759235066Stuexen		sctp_notify_stream_reset(stcb, error, ((uint16_t *) data),
3760235066Stuexen		    (SCTP_STREAM_RESET_INCOMING | SCTP_STREAM_RESET_DENIED));
3761235066Stuexen		break;
3762163953Srrs	case SCTP_NOTIFY_ASCONF_ADD_IP:
3763163953Srrs		sctp_notify_peer_addr_change(stcb, SCTP_ADDR_ADDED, data,
3764283726Stuexen		    error, so_locked);
3765163953Srrs		break;
3766163953Srrs	case SCTP_NOTIFY_ASCONF_DELETE_IP:
3767163953Srrs		sctp_notify_peer_addr_change(stcb, SCTP_ADDR_REMOVED, data,
3768283726Stuexen		    error, so_locked);
3769163953Srrs		break;
3770163953Srrs	case SCTP_NOTIFY_ASCONF_SET_PRIMARY:
3771163953Srrs		sctp_notify_peer_addr_change(stcb, SCTP_ADDR_MADE_PRIM, data,
3772283726Stuexen		    error, so_locked);
3773163953Srrs		break;
3774163953Srrs	case SCTP_NOTIFY_PEER_SHUTDOWN:
3775163953Srrs		sctp_notify_shutdown_event(stcb);
3776163953Srrs		break;
3777163953Srrs	case SCTP_NOTIFY_AUTH_NEW_KEY:
3778234699Stuexen		sctp_notify_authentication(stcb, SCTP_AUTH_NEW_KEY, error,
3779185694Srrs		    (uint16_t) (uintptr_t) data,
3780185694Srrs		    so_locked);
3781163953Srrs		break;
3782185694Srrs	case SCTP_NOTIFY_AUTH_FREE_KEY:
3783185694Srrs		sctp_notify_authentication(stcb, SCTP_AUTH_FREE_KEY, error,
3784185694Srrs		    (uint16_t) (uintptr_t) data,
3785185694Srrs		    so_locked);
3786163953Srrs		break;
3787185694Srrs	case SCTP_NOTIFY_NO_PEER_AUTH:
3788185694Srrs		sctp_notify_authentication(stcb, SCTP_AUTH_NO_AUTH, error,
3789185694Srrs		    (uint16_t) (uintptr_t) data,
3790185694Srrs		    so_locked);
3791185694Srrs		break;
3792185694Srrs	case SCTP_NOTIFY_SENDER_DRY:
3793185694Srrs		sctp_notify_sender_dry_event(stcb, so_locked);
3794185694Srrs		break;
3795235418Stuexen	case SCTP_NOTIFY_REMOTE_ERROR:
3796235418Stuexen		sctp_notify_remote_error(stcb, error, data);
3797235418Stuexen		break;
3798163953Srrs	default:
3799169420Srrs		SCTPDBG(SCTP_DEBUG_UTIL1, "%s: unknown notification %xh (%u)\n",
3800294174Stuexen		    __func__, notification, notification);
3801163953Srrs		break;
3802163953Srrs	}			/* end switch */
3803163953Srrs}
3804163953Srrs
3805163953Srrsvoid
3806235416Stuexensctp_report_all_outbound(struct sctp_tcb *stcb, uint16_t error, int holds_lock, int so_locked
3807172090Srrs#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
3808172090Srrs    SCTP_UNUSED
3809172090Srrs#endif
3810172090Srrs)
3811163953Srrs{
3812163953Srrs	struct sctp_association *asoc;
3813163953Srrs	struct sctp_stream_out *outs;
3814216822Stuexen	struct sctp_tmit_chunk *chk, *nchk;
3815216822Stuexen	struct sctp_stream_queue_pending *sp, *nsp;
3816164205Srrs	int i;
3817163953Srrs
3818169420Srrs	if (stcb == NULL) {
3819169420Srrs		return;
3820169420Srrs	}
3821216822Stuexen	asoc = &stcb->asoc;
3822216822Stuexen	if (asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) {
3823209663Srrs		/* already being freed */
3824209663Srrs		return;
3825209663Srrs	}
3826163953Srrs	if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
3827163953Srrs	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
3828216822Stuexen	    (asoc->state & SCTP_STATE_CLOSED_SOCKET)) {
3829163953Srrs		return;
3830163953Srrs	}
3831163953Srrs	/* now through all the gunk freeing chunks */
3832169420Srrs	if (holds_lock == 0) {
3833164205Srrs		SCTP_TCB_SEND_LOCK(stcb);
3834169420Srrs	}
3835170462Srrs	/* sent queue SHOULD be empty */
3836216822Stuexen	TAILQ_FOREACH_SAFE(chk, &asoc->sent_queue, sctp_next, nchk) {
3837216822Stuexen		TAILQ_REMOVE(&asoc->sent_queue, chk, sctp_next);
3838216822Stuexen		asoc->sent_queue_cnt--;
3839243157Stuexen		if (chk->sent != SCTP_DATAGRAM_NR_ACKED) {
3840242714Stuexen			if (asoc->strmout[chk->rec.data.stream_number].chunks_on_queues > 0) {
3841242714Stuexen				asoc->strmout[chk->rec.data.stream_number].chunks_on_queues--;
3842242714Stuexen#ifdef INVARIANTS
3843242714Stuexen			} else {
3844242714Stuexen				panic("No chunks on the queues for sid %u.", chk->rec.data.stream_number);
3845242714Stuexen#endif
3846242714Stuexen			}
3847242714Stuexen		}
3848216822Stuexen		if (chk->data != NULL) {
3849216822Stuexen			sctp_free_bufspace(stcb, asoc, chk, 1);
3850235416Stuexen			sctp_ulp_notify(SCTP_NOTIFY_SENT_DG_FAIL, stcb,
3851235416Stuexen			    error, chk, so_locked);
3852216822Stuexen			if (chk->data) {
3853216822Stuexen				sctp_m_freem(chk->data);
3854216822Stuexen				chk->data = NULL;
3855163953Srrs			}
3856163953Srrs		}
3857221627Stuexen		sctp_free_a_chunk(stcb, chk, so_locked);
3858216822Stuexen		/* sa_ignore FREED_MEMORY */
3859163953Srrs	}
3860170462Srrs	/* pending send queue SHOULD be empty */
3861216822Stuexen	TAILQ_FOREACH_SAFE(chk, &asoc->send_queue, sctp_next, nchk) {
3862216822Stuexen		TAILQ_REMOVE(&asoc->send_queue, chk, sctp_next);
3863216822Stuexen		asoc->send_queue_cnt--;
3864242714Stuexen		if (asoc->strmout[chk->rec.data.stream_number].chunks_on_queues > 0) {
3865242714Stuexen			asoc->strmout[chk->rec.data.stream_number].chunks_on_queues--;
3866242714Stuexen#ifdef INVARIANTS
3867242714Stuexen		} else {
3868242714Stuexen			panic("No chunks on the queues for sid %u.", chk->rec.data.stream_number);
3869242714Stuexen#endif
3870242714Stuexen		}
3871216822Stuexen		if (chk->data != NULL) {
3872216822Stuexen			sctp_free_bufspace(stcb, asoc, chk, 1);
3873235416Stuexen			sctp_ulp_notify(SCTP_NOTIFY_UNSENT_DG_FAIL, stcb,
3874235416Stuexen			    error, chk, so_locked);
3875216822Stuexen			if (chk->data) {
3876216822Stuexen				sctp_m_freem(chk->data);
3877216822Stuexen				chk->data = NULL;
3878163953Srrs			}
3879163953Srrs		}
3880221627Stuexen		sctp_free_a_chunk(stcb, chk, so_locked);
3881216822Stuexen		/* sa_ignore FREED_MEMORY */
3882163953Srrs	}
3883216822Stuexen	for (i = 0; i < asoc->streamoutcnt; i++) {
3884170462Srrs		/* For each stream */
3885216822Stuexen		outs = &asoc->strmout[i];
3886170462Srrs		/* clean up any sends there */
3887216822Stuexen		asoc->locked_on_sending = NULL;
3888216822Stuexen		TAILQ_FOREACH_SAFE(sp, &outs->outqueue, next, nsp) {
3889216822Stuexen			asoc->stream_queue_cnt--;
3890170462Srrs			TAILQ_REMOVE(&outs->outqueue, sp, next);
3891170462Srrs			sctp_free_spbufspace(stcb, asoc, sp);
3892170462Srrs			if (sp->data) {
3893209663Srrs				sctp_ulp_notify(SCTP_NOTIFY_SPECIAL_SP_FAIL, stcb,
3894235416Stuexen				    error, (void *)sp, so_locked);
3895209663Srrs				if (sp->data) {
3896209663Srrs					sctp_m_freem(sp->data);
3897209663Srrs					sp->data = NULL;
3898238550Stuexen					sp->tail_mbuf = NULL;
3899238550Stuexen					sp->length = 0;
3900209663Srrs				}
3901170462Srrs			}
3902212712Stuexen			if (sp->net) {
3903170462Srrs				sctp_free_remote_addr(sp->net);
3904212712Stuexen				sp->net = NULL;
3905212712Stuexen			}
3906170462Srrs			/* Free the chunk */
3907221627Stuexen			sctp_free_a_strmoq(stcb, sp, so_locked);
3908170462Srrs			/* sa_ignore FREED_MEMORY */
3909170462Srrs		}
3910170462Srrs	}
3911170462Srrs
3912169420Srrs	if (holds_lock == 0) {
3913164205Srrs		SCTP_TCB_SEND_UNLOCK(stcb);
3914169420Srrs	}
3915163953Srrs}
3916163953Srrs
3917163953Srrsvoid
3918235403Stuexensctp_abort_notification(struct sctp_tcb *stcb, uint8_t from_peer, uint16_t error,
3919235360Stuexen    struct sctp_abort_chunk *abort, int so_locked
3920172090Srrs#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
3921172090Srrs    SCTP_UNUSED
3922172090Srrs#endif
3923172090Srrs)
3924163953Srrs{
3925169420Srrs	if (stcb == NULL) {
3926169420Srrs		return;
3927169420Srrs	}
3928225559Stuexen	if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3929225559Stuexen	    ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
3930225559Stuexen	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED))) {
3931225559Stuexen		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_WAS_ABORTED;
3932225559Stuexen	}
3933163953Srrs	if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
3934163953Srrs	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
3935163953Srrs	    (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) {
3936163953Srrs		return;
3937163953Srrs	}
3938163953Srrs	/* Tell them we lost the asoc */
3939235416Stuexen	sctp_report_all_outbound(stcb, error, 1, so_locked);
3940235403Stuexen	if (from_peer) {
3941235403Stuexen		sctp_ulp_notify(SCTP_NOTIFY_ASSOC_REM_ABORTED, stcb, error, abort, so_locked);
3942235403Stuexen	} else {
3943235403Stuexen		sctp_ulp_notify(SCTP_NOTIFY_ASSOC_LOC_ABORTED, stcb, error, abort, so_locked);
3944235403Stuexen	}
3945163953Srrs}
3946163953Srrs
3947163953Srrsvoid
3948163953Srrssctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
3949237715Stuexen    struct mbuf *m, int iphlen,
3950237715Stuexen    struct sockaddr *src, struct sockaddr *dst,
3951237715Stuexen    struct sctphdr *sh, struct mbuf *op_err,
3952281955Shiren    uint8_t mflowtype, uint32_t mflowid,
3953179157Srrs    uint32_t vrf_id, uint16_t port)
3954163953Srrs{
3955163953Srrs	uint32_t vtag;
3956163953Srrs
3957237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
3958172090Srrs	struct socket *so;
3959172090Srrs
3960172090Srrs#endif
3961172090Srrs
3962163953Srrs	vtag = 0;
3963163953Srrs	if (stcb != NULL) {
3964163953Srrs		/* We have a TCB to abort, send notification too */
3965163953Srrs		vtag = stcb->asoc.peer_vtag;
3966235403Stuexen		sctp_abort_notification(stcb, 0, 0, NULL, SCTP_SO_NOT_LOCKED);
3967169352Srrs		/* get the assoc vrf id and table id */
3968169352Srrs		vrf_id = stcb->asoc.vrf_id;
3969171745Srrs		stcb->asoc.state |= SCTP_STATE_WAS_ABORTED;
3970163953Srrs	}
3971237715Stuexen	sctp_send_abort(m, iphlen, src, dst, sh, vtag, op_err,
3972284633Stuexen	    mflowtype, mflowid, inp->fibnum,
3973237049Stuexen	    vrf_id, port);
3974163953Srrs	if (stcb != NULL) {
3975163953Srrs		/* Ok, now lets free it */
3976237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
3977172090Srrs		so = SCTP_INP_SO(inp);
3978172090Srrs		atomic_add_int(&stcb->asoc.refcnt, 1);
3979172090Srrs		SCTP_TCB_UNLOCK(stcb);
3980172090Srrs		SCTP_SOCKET_LOCK(so, 1);
3981172090Srrs		SCTP_TCB_LOCK(stcb);
3982172090Srrs		atomic_subtract_int(&stcb->asoc.refcnt, 1);
3983172090Srrs#endif
3984216397Stuexen		SCTP_STAT_INCR_COUNTER32(sctps_aborted);
3985216397Stuexen		if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
3986216397Stuexen		    (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
3987216397Stuexen			SCTP_STAT_DECR_GAUGE32(sctps_currestab);
3988216397Stuexen		}
3989283823Stuexen		(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
3990283823Stuexen		    SCTP_FROM_SCTPUTIL + SCTP_LOC_4);
3991237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
3992172090Srrs		SCTP_SOCKET_UNLOCK(so, 1);
3993172090Srrs#endif
3994163953Srrs	}
3995163953Srrs}
3996163953Srrs
3997168859Srrs#ifdef SCTP_ASOCLOG_OF_TSNS
3998163953Srrsvoid
3999168859Srrssctp_print_out_track_log(struct sctp_tcb *stcb)
4000168859Srrs{
4001171477Srrs#ifdef NOSIY_PRINTS
4002168859Srrs	int i;
4003168859Srrs
4004169420Srrs	SCTP_PRINTF("Last ep reason:%x\n", stcb->sctp_ep->last_abort_code);
4005169420Srrs	SCTP_PRINTF("IN bound TSN log-aaa\n");
4006168859Srrs	if ((stcb->asoc.tsn_in_at == 0) && (stcb->asoc.tsn_in_wrapped == 0)) {
4007169420Srrs		SCTP_PRINTF("None rcvd\n");
4008168859Srrs		goto none_in;
4009168859Srrs	}
4010168859Srrs	if (stcb->asoc.tsn_in_wrapped) {
4011168859Srrs		for (i = stcb->asoc.tsn_in_at; i < SCTP_TSN_LOG_SIZE; i++) {
4012169420Srrs			SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n",
4013168859Srrs			    stcb->asoc.in_tsnlog[i].tsn,
4014168859Srrs			    stcb->asoc.in_tsnlog[i].strm,
4015168859Srrs			    stcb->asoc.in_tsnlog[i].seq,
4016168859Srrs			    stcb->asoc.in_tsnlog[i].flgs,
4017168859Srrs			    stcb->asoc.in_tsnlog[i].sz);
4018168859Srrs		}
4019168859Srrs	}
4020168859Srrs	if (stcb->asoc.tsn_in_at) {
4021168859Srrs		for (i = 0; i < stcb->asoc.tsn_in_at; i++) {
4022169420Srrs			SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n",
4023168859Srrs			    stcb->asoc.in_tsnlog[i].tsn,
4024168859Srrs			    stcb->asoc.in_tsnlog[i].strm,
4025168859Srrs			    stcb->asoc.in_tsnlog[i].seq,
4026168859Srrs			    stcb->asoc.in_tsnlog[i].flgs,
4027168859Srrs			    stcb->asoc.in_tsnlog[i].sz);
4028168859Srrs		}
4029168859Srrs	}
4030168859Srrsnone_in:
4031169420Srrs	SCTP_PRINTF("OUT bound TSN log-aaa\n");
4032169420Srrs	if ((stcb->asoc.tsn_out_at == 0) &&
4033169420Srrs	    (stcb->asoc.tsn_out_wrapped == 0)) {
4034169420Srrs		SCTP_PRINTF("None sent\n");
4035168859Srrs	}
4036168859Srrs	if (stcb->asoc.tsn_out_wrapped) {
4037168859Srrs		for (i = stcb->asoc.tsn_out_at; i < SCTP_TSN_LOG_SIZE; i++) {
4038169420Srrs			SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n",
4039168859Srrs			    stcb->asoc.out_tsnlog[i].tsn,
4040168859Srrs			    stcb->asoc.out_tsnlog[i].strm,
4041168859Srrs			    stcb->asoc.out_tsnlog[i].seq,
4042168859Srrs			    stcb->asoc.out_tsnlog[i].flgs,
4043168859Srrs			    stcb->asoc.out_tsnlog[i].sz);
4044168859Srrs		}
4045168859Srrs	}
4046168859Srrs	if (stcb->asoc.tsn_out_at) {
4047168859Srrs		for (i = 0; i < stcb->asoc.tsn_out_at; i++) {
4048169420Srrs			SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n",
4049168859Srrs			    stcb->asoc.out_tsnlog[i].tsn,
4050168859Srrs			    stcb->asoc.out_tsnlog[i].strm,
4051168859Srrs			    stcb->asoc.out_tsnlog[i].seq,
4052168859Srrs			    stcb->asoc.out_tsnlog[i].flgs,
4053168859Srrs			    stcb->asoc.out_tsnlog[i].sz);
4054168859Srrs		}
4055168859Srrs	}
4056171477Srrs#endif
4057168859Srrs}
4058168859Srrs
4059168859Srrs#endif
4060168859Srrs
4061168859Srrsvoid
4062163953Srrssctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
4063235360Stuexen    struct mbuf *op_err,
4064172090Srrs    int so_locked
4065172090Srrs#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
4066172090Srrs    SCTP_UNUSED
4067172090Srrs#endif
4068172090Srrs)
4069163953Srrs{
4070237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
4071172090Srrs	struct socket *so;
4072172090Srrs
4073172090Srrs#endif
4074172090Srrs
4075237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
4076172090Srrs	so = SCTP_INP_SO(inp);
4077172090Srrs#endif
4078163953Srrs	if (stcb == NULL) {
4079163953Srrs		/* Got to have a TCB */
4080163953Srrs		if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
4081251248Stuexen			if (LIST_EMPTY(&inp->sctp_asoc_list)) {
4082169380Srrs				sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
4083169380Srrs				    SCTP_CALLED_DIRECTLY_NOCMPSET);
4084163953Srrs			}
4085163953Srrs		}
4086163953Srrs		return;
4087171745Srrs	} else {
4088171745Srrs		stcb->asoc.state |= SCTP_STATE_WAS_ABORTED;
4089163953Srrs	}
4090163953Srrs	/* notify the ulp */
4091235360Stuexen	if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
4092235403Stuexen		sctp_abort_notification(stcb, 0, 0, NULL, so_locked);
4093235360Stuexen	}
4094163953Srrs	/* notify the peer */
4095172090Srrs	sctp_send_abort_tcb(stcb, op_err, so_locked);
4096163953Srrs	SCTP_STAT_INCR_COUNTER32(sctps_aborted);
4097163953Srrs	if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
4098163953Srrs	    (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
4099163953Srrs		SCTP_STAT_DECR_GAUGE32(sctps_currestab);
4100163953Srrs	}
4101163953Srrs	/* now free the asoc */
4102168859Srrs#ifdef SCTP_ASOCLOG_OF_TSNS
4103168859Srrs	sctp_print_out_track_log(stcb);
4104168859Srrs#endif
4105237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
4106172090Srrs	if (!so_locked) {
4107172090Srrs		atomic_add_int(&stcb->asoc.refcnt, 1);
4108172090Srrs		SCTP_TCB_UNLOCK(stcb);
4109172090Srrs		SCTP_SOCKET_LOCK(so, 1);
4110172090Srrs		SCTP_TCB_LOCK(stcb);
4111172090Srrs		atomic_subtract_int(&stcb->asoc.refcnt, 1);
4112172090Srrs	}
4113172090Srrs#endif
4114283823Stuexen	(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
4115283823Stuexen	    SCTP_FROM_SCTPUTIL + SCTP_LOC_5);
4116237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
4117172090Srrs	if (!so_locked) {
4118172090Srrs		SCTP_SOCKET_UNLOCK(so, 1);
4119172090Srrs	}
4120172090Srrs#endif
4121163953Srrs}
4122163953Srrs
4123163953Srrsvoid
4124237715Stuexensctp_handle_ootb(struct mbuf *m, int iphlen, int offset,
4125237715Stuexen    struct sockaddr *src, struct sockaddr *dst,
4126237715Stuexen    struct sctphdr *sh, struct sctp_inpcb *inp,
4127267723Stuexen    struct mbuf *cause,
4128284633Stuexen    uint8_t mflowtype, uint32_t mflowid, uint16_t fibnum,
4129237049Stuexen    uint32_t vrf_id, uint16_t port)
4130163953Srrs{
4131163953Srrs	struct sctp_chunkhdr *ch, chunk_buf;
4132163953Srrs	unsigned int chk_length;
4133229805Stuexen	int contains_init_chunk;
4134163953Srrs
4135163953Srrs	SCTP_STAT_INCR_COUNTER32(sctps_outoftheblue);
4136163953Srrs	/* Generate a TO address for future reference */
4137163953Srrs	if (inp && (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
4138251248Stuexen		if (LIST_EMPTY(&inp->sctp_asoc_list)) {
4139169380Srrs			sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
4140169380Srrs			    SCTP_CALLED_DIRECTLY_NOCMPSET);
4141163953Srrs		}
4142163953Srrs	}
4143229805Stuexen	contains_init_chunk = 0;
4144163953Srrs	ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset,
4145163953Srrs	    sizeof(*ch), (uint8_t *) & chunk_buf);
4146163953Srrs	while (ch != NULL) {
4147163953Srrs		chk_length = ntohs(ch->chunk_length);
4148163953Srrs		if (chk_length < sizeof(*ch)) {
4149163953Srrs			/* break to abort land */
4150163953Srrs			break;
4151163953Srrs		}
4152163953Srrs		switch (ch->chunk_type) {
4153229805Stuexen		case SCTP_INIT:
4154229805Stuexen			contains_init_chunk = 1;
4155229805Stuexen			break;
4156163953Srrs		case SCTP_PACKET_DROPPED:
4157163953Srrs			/* we don't respond to pkt-dropped */
4158163953Srrs			return;
4159163953Srrs		case SCTP_ABORT_ASSOCIATION:
4160163953Srrs			/* we don't respond with an ABORT to an ABORT */
4161163953Srrs			return;
4162163953Srrs		case SCTP_SHUTDOWN_COMPLETE:
4163163953Srrs			/*
4164163953Srrs			 * we ignore it since we are not waiting for it and
4165163953Srrs			 * peer is gone
4166163953Srrs			 */
4167163953Srrs			return;
4168163953Srrs		case SCTP_SHUTDOWN_ACK:
4169237715Stuexen			sctp_send_shutdown_complete2(src, dst, sh,
4170284633Stuexen			    mflowtype, mflowid, fibnum,
4171237049Stuexen			    vrf_id, port);
4172163953Srrs			return;
4173163953Srrs		default:
4174163953Srrs			break;
4175163953Srrs		}
4176163953Srrs		offset += SCTP_SIZE32(chk_length);
4177163953Srrs		ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset,
4178163953Srrs		    sizeof(*ch), (uint8_t *) & chunk_buf);
4179163953Srrs	}
4180229805Stuexen	if ((SCTP_BASE_SYSCTL(sctp_blackhole) == 0) ||
4181229805Stuexen	    ((SCTP_BASE_SYSCTL(sctp_blackhole) == 1) &&
4182229805Stuexen	    (contains_init_chunk == 0))) {
4183267723Stuexen		sctp_send_abort(m, iphlen, src, dst, sh, 0, cause,
4184284633Stuexen		    mflowtype, mflowid, fibnum,
4185237049Stuexen		    vrf_id, port);
4186229805Stuexen	}
4187163953Srrs}
4188163953Srrs
4189163953Srrs/*
4190163953Srrs * check the inbound datagram to make sure there is not an abort inside it,
4191163953Srrs * if there is return 1, else return 0.
4192163953Srrs */
4193163953Srrsint
4194163953Srrssctp_is_there_an_abort_here(struct mbuf *m, int iphlen, uint32_t * vtagfill)
4195163953Srrs{
4196163953Srrs	struct sctp_chunkhdr *ch;
4197163953Srrs	struct sctp_init_chunk *init_chk, chunk_buf;
4198163953Srrs	int offset;
4199163953Srrs	unsigned int chk_length;
4200163953Srrs
4201163953Srrs	offset = iphlen + sizeof(struct sctphdr);
4202163953Srrs	ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, sizeof(*ch),
4203163953Srrs	    (uint8_t *) & chunk_buf);
4204163953Srrs	while (ch != NULL) {
4205163953Srrs		chk_length = ntohs(ch->chunk_length);
4206163953Srrs		if (chk_length < sizeof(*ch)) {
4207163953Srrs			/* packet is probably corrupt */
4208163953Srrs			break;
4209163953Srrs		}
4210163953Srrs		/* we seem to be ok, is it an abort? */
4211163953Srrs		if (ch->chunk_type == SCTP_ABORT_ASSOCIATION) {
4212163953Srrs			/* yep, tell them */
4213163953Srrs			return (1);
4214163953Srrs		}
4215163953Srrs		if (ch->chunk_type == SCTP_INITIATION) {
4216163953Srrs			/* need to update the Vtag */
4217163953Srrs			init_chk = (struct sctp_init_chunk *)sctp_m_getptr(m,
4218163953Srrs			    offset, sizeof(*init_chk), (uint8_t *) & chunk_buf);
4219163953Srrs			if (init_chk != NULL) {
4220163953Srrs				*vtagfill = ntohl(init_chk->init.initiate_tag);
4221163953Srrs			}
4222163953Srrs		}
4223163953Srrs		/* Nope, move to the next chunk */
4224163953Srrs		offset += SCTP_SIZE32(chk_length);
4225163953Srrs		ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset,
4226163953Srrs		    sizeof(*ch), (uint8_t *) & chunk_buf);
4227163953Srrs	}
4228163953Srrs	return (0);
4229163953Srrs}
4230163953Srrs
4231163953Srrs/*
4232163953Srrs * currently (2/02), ifa_addr embeds scope_id's and don't have sin6_scope_id
4233163953Srrs * set (i.e. it's 0) so, create this function to compare link local scopes
4234163953Srrs */
4235178251Srrs#ifdef INET6
4236163953Srrsuint32_t
4237163953Srrssctp_is_same_scope(struct sockaddr_in6 *addr1, struct sockaddr_in6 *addr2)
4238163953Srrs{
4239163953Srrs	struct sockaddr_in6 a, b;
4240163953Srrs
4241163953Srrs	/* save copies */
4242163953Srrs	a = *addr1;
4243163953Srrs	b = *addr2;
4244163953Srrs
4245163953Srrs	if (a.sin6_scope_id == 0)
4246163953Srrs		if (sa6_recoverscope(&a)) {
4247163953Srrs			/* can't get scope, so can't match */
4248163953Srrs			return (0);
4249163953Srrs		}
4250163953Srrs	if (b.sin6_scope_id == 0)
4251163953Srrs		if (sa6_recoverscope(&b)) {
4252163953Srrs			/* can't get scope, so can't match */
4253163953Srrs			return (0);
4254163953Srrs		}
4255163953Srrs	if (a.sin6_scope_id != b.sin6_scope_id)
4256163953Srrs		return (0);
4257163953Srrs
4258163953Srrs	return (1);
4259163953Srrs}
4260163953Srrs
4261163953Srrs/*
4262163953Srrs * returns a sockaddr_in6 with embedded scope recovered and removed
4263163953Srrs */
4264163953Srrsstruct sockaddr_in6 *
4265163953Srrssctp_recover_scope(struct sockaddr_in6 *addr, struct sockaddr_in6 *store)
4266163953Srrs{
4267163953Srrs	/* check and strip embedded scope junk */
4268163953Srrs	if (addr->sin6_family == AF_INET6) {
4269163953Srrs		if (IN6_IS_SCOPE_LINKLOCAL(&addr->sin6_addr)) {
4270163953Srrs			if (addr->sin6_scope_id == 0) {
4271163953Srrs				*store = *addr;
4272163953Srrs				if (!sa6_recoverscope(store)) {
4273163953Srrs					/* use the recovered scope */
4274163953Srrs					addr = store;
4275163953Srrs				}
4276166675Srrs			} else {
4277163953Srrs				/* else, return the original "to" addr */
4278166675Srrs				in6_clearscope(&addr->sin6_addr);
4279163953Srrs			}
4280163953Srrs		}
4281163953Srrs	}
4282163953Srrs	return (addr);
4283163953Srrs}
4284163953Srrs
4285178251Srrs#endif
4286178251Srrs
4287163953Srrs/*
4288163953Srrs * are the two addresses the same?  currently a "scopeless" check returns: 1
4289163953Srrs * if same, 0 if not
4290163953Srrs */
4291170806Srrsint
4292163953Srrssctp_cmpaddr(struct sockaddr *sa1, struct sockaddr *sa2)
4293163953Srrs{
4294163953Srrs
4295163953Srrs	/* must be valid */
4296163953Srrs	if (sa1 == NULL || sa2 == NULL)
4297163953Srrs		return (0);
4298163953Srrs
4299163953Srrs	/* must be the same family */
4300163953Srrs	if (sa1->sa_family != sa2->sa_family)
4301163953Srrs		return (0);
4302163953Srrs
4303178251Srrs	switch (sa1->sa_family) {
4304178251Srrs#ifdef INET6
4305178251Srrs	case AF_INET6:
4306178251Srrs		{
4307178251Srrs			/* IPv6 addresses */
4308178251Srrs			struct sockaddr_in6 *sin6_1, *sin6_2;
4309163953Srrs
4310178251Srrs			sin6_1 = (struct sockaddr_in6 *)sa1;
4311178251Srrs			sin6_2 = (struct sockaddr_in6 *)sa2;
4312179157Srrs			return (SCTP6_ARE_ADDR_EQUAL(sin6_1,
4313179157Srrs			    sin6_2));
4314178251Srrs		}
4315178251Srrs#endif
4316221328Stuexen#ifdef INET
4317178251Srrs	case AF_INET:
4318178251Srrs		{
4319178251Srrs			/* IPv4 addresses */
4320178251Srrs			struct sockaddr_in *sin_1, *sin_2;
4321163953Srrs
4322178251Srrs			sin_1 = (struct sockaddr_in *)sa1;
4323178251Srrs			sin_2 = (struct sockaddr_in *)sa2;
4324178251Srrs			return (sin_1->sin_addr.s_addr == sin_2->sin_addr.s_addr);
4325178251Srrs		}
4326221328Stuexen#endif
4327178251Srrs	default:
4328163953Srrs		/* we don't do these... */
4329163953Srrs		return (0);
4330163953Srrs	}
4331163953Srrs}
4332163953Srrs
4333163953Srrsvoid
4334163953Srrssctp_print_address(struct sockaddr *sa)
4335163953Srrs{
4336178251Srrs#ifdef INET6
4337169420Srrs	char ip6buf[INET6_ADDRSTRLEN];
4338163953Srrs
4339178251Srrs#endif
4340163953Srrs
4341178251Srrs	switch (sa->sa_family) {
4342178251Srrs#ifdef INET6
4343178251Srrs	case AF_INET6:
4344178251Srrs		{
4345178251Srrs			struct sockaddr_in6 *sin6;
4346163953Srrs
4347178251Srrs			sin6 = (struct sockaddr_in6 *)sa;
4348178251Srrs			SCTP_PRINTF("IPv6 address: %s:port:%d scope:%u\n",
4349178251Srrs			    ip6_sprintf(ip6buf, &sin6->sin6_addr),
4350178251Srrs			    ntohs(sin6->sin6_port),
4351178251Srrs			    sin6->sin6_scope_id);
4352178251Srrs			break;
4353178251Srrs		}
4354178251Srrs#endif
4355221328Stuexen#ifdef INET
4356178251Srrs	case AF_INET:
4357178251Srrs		{
4358178251Srrs			struct sockaddr_in *sin;
4359178251Srrs			unsigned char *p;
4360178251Srrs
4361178251Srrs			sin = (struct sockaddr_in *)sa;
4362178251Srrs			p = (unsigned char *)&sin->sin_addr;
4363178251Srrs			SCTP_PRINTF("IPv4 address: %u.%u.%u.%u:%d\n",
4364178251Srrs			    p[0], p[1], p[2], p[3], ntohs(sin->sin_port));
4365178251Srrs			break;
4366178251Srrs		}
4367221328Stuexen#endif
4368178251Srrs	default:
4369169420Srrs		SCTP_PRINTF("?\n");
4370178251Srrs		break;
4371163953Srrs	}
4372163953Srrs}
4373163953Srrs
4374163953Srrsvoid
4375163953Srrssctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp,
4376163953Srrs    struct sctp_inpcb *new_inp,
4377169208Srrs    struct sctp_tcb *stcb,
4378169208Srrs    int waitflags)
4379163953Srrs{
4380163953Srrs	/*
4381163953Srrs	 * go through our old INP and pull off any control structures that
4382163953Srrs	 * belong to stcb and move then to the new inp.
4383163953Srrs	 */
4384163953Srrs	struct socket *old_so, *new_so;
4385163953Srrs	struct sctp_queued_to_read *control, *nctl;
4386163953Srrs	struct sctp_readhead tmp_queue;
4387163953Srrs	struct mbuf *m;
4388168299Srrs	int error = 0;
4389163953Srrs
4390163953Srrs	old_so = old_inp->sctp_socket;
4391163953Srrs	new_so = new_inp->sctp_socket;
4392163953Srrs	TAILQ_INIT(&tmp_queue);
4393169208Srrs	error = sblock(&old_so->so_rcv, waitflags);
4394163953Srrs	if (error) {
4395163953Srrs		/*
4396163953Srrs		 * Gak, can't get sblock, we have a problem. data will be
4397163953Srrs		 * left stranded.. and we don't dare look at it since the
4398163953Srrs		 * other thread may be reading something. Oh well, its a
4399163953Srrs		 * screwed up app that does a peeloff OR a accept while
4400163953Srrs		 * reading from the main socket... actually its only the
4401163953Srrs		 * peeloff() case, since I think read will fail on a
4402163953Srrs		 * listening socket..
4403163953Srrs		 */
4404163953Srrs		return;
4405163953Srrs	}
4406163953Srrs	/* lock the socket buffers */
4407163953Srrs	SCTP_INP_READ_LOCK(old_inp);
4408216822Stuexen	TAILQ_FOREACH_SAFE(control, &old_inp->read_queue, next, nctl) {
4409216822Stuexen		/* Pull off all for out target stcb */
4410163953Srrs		if (control->stcb == stcb) {
4411163953Srrs			/* remove it we want it */
4412163953Srrs			TAILQ_REMOVE(&old_inp->read_queue, control, next);
4413163953Srrs			TAILQ_INSERT_TAIL(&tmp_queue, control, next);
4414163953Srrs			m = control->data;
4415163953Srrs			while (m) {
4416179783Srrs				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
4417170744Srrs					sctp_sblog(&old_so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m));
4418170744Srrs				}
4419163953Srrs				sctp_sbfree(control, stcb, &old_so->so_rcv, m);
4420179783Srrs				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
4421170744Srrs					sctp_sblog(&old_so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0);
4422170744Srrs				}
4423165647Srrs				m = SCTP_BUF_NEXT(m);
4424163953Srrs			}
4425163953Srrs		}
4426163953Srrs	}
4427163953Srrs	SCTP_INP_READ_UNLOCK(old_inp);
4428163953Srrs	/* Remove the sb-lock on the old socket */
4429163953Srrs
4430163953Srrs	sbunlock(&old_so->so_rcv);
4431163953Srrs	/* Now we move them over to the new socket buffer */
4432163953Srrs	SCTP_INP_READ_LOCK(new_inp);
4433216822Stuexen	TAILQ_FOREACH_SAFE(control, &tmp_queue, next, nctl) {
4434163953Srrs		TAILQ_INSERT_TAIL(&new_inp->read_queue, control, next);
4435163953Srrs		m = control->data;
4436163953Srrs		while (m) {
4437179783Srrs			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
4438170744Srrs				sctp_sblog(&new_so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(m));
4439170744Srrs			}
4440163953Srrs			sctp_sballoc(stcb, &new_so->so_rcv, m);
4441179783Srrs			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
4442170744Srrs				sctp_sblog(&new_so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0);
4443170744Srrs			}
4444165647Srrs			m = SCTP_BUF_NEXT(m);
4445163953Srrs		}
4446163953Srrs	}
4447163953Srrs	SCTP_INP_READ_UNLOCK(new_inp);
4448163953Srrs}
4449163953Srrs
4450163953Srrsvoid
4451163953Srrssctp_add_to_readq(struct sctp_inpcb *inp,
4452163953Srrs    struct sctp_tcb *stcb,
4453163953Srrs    struct sctp_queued_to_read *control,
4454163953Srrs    struct sockbuf *sb,
4455172090Srrs    int end,
4456195918Srrs    int inp_read_lock_held,
4457172090Srrs    int so_locked
4458172090Srrs#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
4459172090Srrs    SCTP_UNUSED
4460172090Srrs#endif
4461172090Srrs)
4462163953Srrs{
4463163953Srrs	/*
4464163953Srrs	 * Here we must place the control on the end of the socket read
4465163953Srrs	 * queue AND increment sb_cc so that select will work properly on
4466163953Srrs	 * read.
4467163953Srrs	 */
4468163953Srrs	struct mbuf *m, *prev = NULL;
4469163953Srrs
4470164085Srrs	if (inp == NULL) {
4471164085Srrs		/* Gak, TSNH!! */
4472165220Srrs#ifdef INVARIANTS
4473164085Srrs		panic("Gak, inp NULL on add_to_readq");
4474164085Srrs#endif
4475164085Srrs		return;
4476164085Srrs	}
4477195918Srrs	if (inp_read_lock_held == 0)
4478195918Srrs		SCTP_INP_READ_LOCK(inp);
4479209289Stuexen	if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_CANT_READ) {
4480209289Stuexen		sctp_free_remote_addr(control->whoFrom);
4481209289Stuexen		if (control->data) {
4482209289Stuexen			sctp_m_freem(control->data);
4483209289Stuexen			control->data = NULL;
4484209289Stuexen		}
4485209289Stuexen		SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), control);
4486209289Stuexen		if (inp_read_lock_held == 0)
4487209289Stuexen			SCTP_INP_READ_UNLOCK(inp);
4488209289Stuexen		return;
4489209289Stuexen	}
4490167598Srrs	if (!(control->spec_flags & M_NOTIFICATION)) {
4491167598Srrs		atomic_add_int(&inp->total_recvs, 1);
4492167598Srrs		if (!control->do_not_ref_stcb) {
4493167598Srrs			atomic_add_int(&stcb->total_recvs, 1);
4494167598Srrs		}
4495167598Srrs	}
4496163953Srrs	m = control->data;
4497163953Srrs	control->held_length = 0;
4498163953Srrs	control->length = 0;
4499163953Srrs	while (m) {
4500165647Srrs		if (SCTP_BUF_LEN(m) == 0) {
4501163953Srrs			/* Skip mbufs with NO length */
4502163953Srrs			if (prev == NULL) {
4503163953Srrs				/* First one */
4504163953Srrs				control->data = sctp_m_free(m);
4505163953Srrs				m = control->data;
4506163953Srrs			} else {
4507165647Srrs				SCTP_BUF_NEXT(prev) = sctp_m_free(m);
4508165647Srrs				m = SCTP_BUF_NEXT(prev);
4509163953Srrs			}
4510163953Srrs			if (m == NULL) {
4511201758Smbr				control->tail_mbuf = prev;
4512163953Srrs			}
4513163953Srrs			continue;
4514163953Srrs		}
4515163953Srrs		prev = m;
4516179783Srrs		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
4517170744Srrs			sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(m));
4518170744Srrs		}
4519163953Srrs		sctp_sballoc(stcb, sb, m);
4520179783Srrs		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
4521170744Srrs			sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0);
4522170744Srrs		}
4523165647Srrs		atomic_add_int(&control->length, SCTP_BUF_LEN(m));
4524165647Srrs		m = SCTP_BUF_NEXT(m);
4525163953Srrs	}
4526163953Srrs	if (prev != NULL) {
4527163953Srrs		control->tail_mbuf = prev;
4528163953Srrs	} else {
4529165647Srrs		/* Everything got collapsed out?? */
4530209289Stuexen		sctp_free_remote_addr(control->whoFrom);
4531209289Stuexen		SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), control);
4532195918Srrs		if (inp_read_lock_held == 0)
4533195918Srrs			SCTP_INP_READ_UNLOCK(inp);
4534163953Srrs		return;
4535163953Srrs	}
4536163953Srrs	if (end) {
4537163953Srrs		control->end_added = 1;
4538163953Srrs	}
4539163953Srrs	TAILQ_INSERT_TAIL(&inp->read_queue, control, next);
4540195918Srrs	if (inp_read_lock_held == 0)
4541195918Srrs		SCTP_INP_READ_UNLOCK(inp);
4542163953Srrs	if (inp && inp->sctp_socket) {
4543169352Srrs		if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) {
4544169352Srrs			SCTP_ZERO_COPY_EVENT(inp, inp->sctp_socket);
4545172090Srrs		} else {
4546237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
4547172090Srrs			struct socket *so;
4548172090Srrs
4549172090Srrs			so = SCTP_INP_SO(inp);
4550172090Srrs			if (!so_locked) {
4551228907Stuexen				if (stcb) {
4552228907Stuexen					atomic_add_int(&stcb->asoc.refcnt, 1);
4553228907Stuexen					SCTP_TCB_UNLOCK(stcb);
4554228907Stuexen				}
4555172090Srrs				SCTP_SOCKET_LOCK(so, 1);
4556228907Stuexen				if (stcb) {
4557228907Stuexen					SCTP_TCB_LOCK(stcb);
4558228907Stuexen					atomic_subtract_int(&stcb->asoc.refcnt, 1);
4559228907Stuexen				}
4560172090Srrs				if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
4561172090Srrs					SCTP_SOCKET_UNLOCK(so, 1);
4562172090Srrs					return;
4563172090Srrs				}
4564172090Srrs			}
4565172090Srrs#endif
4566169352Srrs			sctp_sorwakeup(inp, inp->sctp_socket);
4567237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
4568172090Srrs			if (!so_locked) {
4569172090Srrs				SCTP_SOCKET_UNLOCK(so, 1);
4570172090Srrs			}
4571172090Srrs#endif
4572172090Srrs		}
4573163953Srrs	}
4574163953Srrs}
4575163953Srrs
4576163953Srrs
4577163953Srrsint
4578163953Srrssctp_append_to_readq(struct sctp_inpcb *inp,
4579163953Srrs    struct sctp_tcb *stcb,
4580163953Srrs    struct sctp_queued_to_read *control,
4581163953Srrs    struct mbuf *m,
4582163953Srrs    int end,
4583163953Srrs    int ctls_cumack,
4584163953Srrs    struct sockbuf *sb)
4585163953Srrs{
4586163953Srrs	/*
4587163953Srrs	 * A partial delivery API event is underway. OR we are appending on
4588163953Srrs	 * the reassembly queue.
4589163953Srrs	 *
4590163953Srrs	 * If PDAPI this means we need to add m to the end of the data.
4591163953Srrs	 * Increase the length in the control AND increment the sb_cc.
4592163953Srrs	 * Otherwise sb is NULL and all we need to do is put it at the end
4593163953Srrs	 * of the mbuf chain.
4594163953Srrs	 */
4595163953Srrs	int len = 0;
4596163953Srrs	struct mbuf *mm, *tail = NULL, *prev = NULL;
4597163953Srrs
4598163953Srrs	if (inp) {
4599163953Srrs		SCTP_INP_READ_LOCK(inp);
4600163953Srrs	}
4601163953Srrs	if (control == NULL) {
4602163953Srrsget_out:
4603163953Srrs		if (inp) {
4604163953Srrs			SCTP_INP_READ_UNLOCK(inp);
4605163953Srrs		}
4606163953Srrs		return (-1);
4607163953Srrs	}
4608209289Stuexen	if (inp && (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_CANT_READ)) {
4609209289Stuexen		SCTP_INP_READ_UNLOCK(inp);
4610228907Stuexen		return (0);
4611209289Stuexen	}
4612165647Srrs	if (control->end_added) {
4613163953Srrs		/* huh this one is complete? */
4614163953Srrs		goto get_out;
4615163953Srrs	}
4616163953Srrs	mm = m;
4617163953Srrs	if (mm == NULL) {
4618163953Srrs		goto get_out;
4619163953Srrs	}
4620163953Srrs	while (mm) {
4621165647Srrs		if (SCTP_BUF_LEN(mm) == 0) {
4622163953Srrs			/* Skip mbufs with NO lenght */
4623163953Srrs			if (prev == NULL) {
4624163953Srrs				/* First one */
4625163953Srrs				m = sctp_m_free(mm);
4626163953Srrs				mm = m;
4627163953Srrs			} else {
4628165647Srrs				SCTP_BUF_NEXT(prev) = sctp_m_free(mm);
4629165647Srrs				mm = SCTP_BUF_NEXT(prev);
4630163953Srrs			}
4631163953Srrs			continue;
4632163953Srrs		}
4633163953Srrs		prev = mm;
4634165647Srrs		len += SCTP_BUF_LEN(mm);
4635163953Srrs		if (sb) {
4636179783Srrs			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
4637170744Srrs				sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(mm));
4638170744Srrs			}
4639163953Srrs			sctp_sballoc(stcb, sb, mm);
4640179783Srrs			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
4641170744Srrs				sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0);
4642170744Srrs			}
4643163953Srrs		}
4644165647Srrs		mm = SCTP_BUF_NEXT(mm);
4645163953Srrs	}
4646163953Srrs	if (prev) {
4647163953Srrs		tail = prev;
4648163953Srrs	} else {
4649163953Srrs		/* Really there should always be a prev */
4650163953Srrs		if (m == NULL) {
4651163953Srrs			/* Huh nothing left? */
4652165220Srrs#ifdef INVARIANTS
4653163953Srrs			panic("Nothing left to add?");
4654163953Srrs#else
4655163953Srrs			goto get_out;
4656163953Srrs#endif
4657163953Srrs		}
4658163953Srrs		tail = m;
4659163953Srrs	}
4660163953Srrs	if (control->tail_mbuf) {
4661163953Srrs		/* append */
4662165647Srrs		SCTP_BUF_NEXT(control->tail_mbuf) = m;
4663163953Srrs		control->tail_mbuf = tail;
4664163953Srrs	} else {
4665163953Srrs		/* nothing there */
4666165220Srrs#ifdef INVARIANTS
4667163953Srrs		if (control->data != NULL) {
4668163953Srrs			panic("This should NOT happen");
4669163953Srrs		}
4670163953Srrs#endif
4671163953Srrs		control->data = m;
4672163953Srrs		control->tail_mbuf = tail;
4673163953Srrs	}
4674171477Srrs	atomic_add_int(&control->length, len);
4675171477Srrs	if (end) {
4676171477Srrs		/* message is complete */
4677171477Srrs		if (stcb && (control == stcb->asoc.control_pdapi)) {
4678171477Srrs			stcb->asoc.control_pdapi = NULL;
4679171477Srrs		}
4680171477Srrs		control->held_length = 0;
4681171477Srrs		control->end_added = 1;
4682171477Srrs	}
4683169420Srrs	if (stcb == NULL) {
4684169420Srrs		control->do_not_ref_stcb = 1;
4685169420Srrs	}
4686163953Srrs	/*
4687163953Srrs	 * When we are appending in partial delivery, the cum-ack is used
4688163953Srrs	 * for the actual pd-api highest tsn on this mbuf. The true cum-ack
4689163953Srrs	 * is populated in the outbound sinfo structure from the true cumack
4690163953Srrs	 * if the association exists...
4691163953Srrs	 */
4692163953Srrs	control->sinfo_tsn = control->sinfo_cumtsn = ctls_cumack;
4693163953Srrs	if (inp) {
4694163953Srrs		SCTP_INP_READ_UNLOCK(inp);
4695163953Srrs	}
4696163953Srrs	if (inp && inp->sctp_socket) {
4697169352Srrs		if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) {
4698169352Srrs			SCTP_ZERO_COPY_EVENT(inp, inp->sctp_socket);
4699172090Srrs		} else {
4700237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
4701172090Srrs			struct socket *so;
4702172090Srrs
4703172090Srrs			so = SCTP_INP_SO(inp);
4704228907Stuexen			if (stcb) {
4705228907Stuexen				atomic_add_int(&stcb->asoc.refcnt, 1);
4706228907Stuexen				SCTP_TCB_UNLOCK(stcb);
4707228907Stuexen			}
4708172090Srrs			SCTP_SOCKET_LOCK(so, 1);
4709228907Stuexen			if (stcb) {
4710228907Stuexen				SCTP_TCB_LOCK(stcb);
4711228907Stuexen				atomic_subtract_int(&stcb->asoc.refcnt, 1);
4712228907Stuexen			}
4713172090Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
4714172090Srrs				SCTP_SOCKET_UNLOCK(so, 1);
4715172090Srrs				return (0);
4716172090Srrs			}
4717172090Srrs#endif
4718169352Srrs			sctp_sorwakeup(inp, inp->sctp_socket);
4719237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
4720172090Srrs			SCTP_SOCKET_UNLOCK(so, 1);
4721172090Srrs#endif
4722172090Srrs		}
4723163953Srrs	}
4724163953Srrs	return (0);
4725163953Srrs}
4726163953Srrs
4727163953Srrs
4728163953Srrs
4729163953Srrs/*************HOLD THIS COMMENT FOR PATCH FILE OF
4730163953Srrs *************ALTERNATE ROUTING CODE
4731163953Srrs */
4732163953Srrs
4733163953Srrs/*************HOLD THIS COMMENT FOR END OF PATCH FILE OF
4734163953Srrs *************ALTERNATE ROUTING CODE
4735163953Srrs */
4736163953Srrs
4737163953Srrsstruct mbuf *
4738267723Stuexensctp_generate_cause(uint16_t code, char *info)
4739163953Srrs{
4740163953Srrs	struct mbuf *m;
4741267723Stuexen	struct sctp_gen_error_cause *cause;
4742267723Stuexen	size_t info_len, len;
4743163953Srrs
4744267723Stuexen	if ((code == 0) || (info == NULL)) {
4745267723Stuexen		return (NULL);
4746163953Srrs	}
4747267723Stuexen	info_len = strlen(info);
4748267723Stuexen	len = sizeof(struct sctp_paramhdr) + info_len;
4749267723Stuexen	m = sctp_get_mbuf_for_msg(len, 0, M_NOWAIT, 1, MT_DATA);
4750267723Stuexen	if (m != NULL) {
4751267723Stuexen		SCTP_BUF_LEN(m) = len;
4752267723Stuexen		cause = mtod(m, struct sctp_gen_error_cause *);
4753267723Stuexen		cause->code = htons(code);
4754267723Stuexen		cause->length = htons((uint16_t) len);
4755267723Stuexen		memcpy(cause->info, info, info_len);
4756267723Stuexen	}
4757163953Srrs	return (m);
4758163953Srrs}
4759163953Srrs
4760267729Stuexenstruct mbuf *
4761267729Stuexensctp_generate_no_user_data_cause(uint32_t tsn)
4762267729Stuexen{
4763267729Stuexen	struct mbuf *m;
4764267729Stuexen	struct sctp_error_no_user_data *no_user_data_cause;
4765267729Stuexen	size_t len;
4766267729Stuexen
4767267729Stuexen	len = sizeof(struct sctp_error_no_user_data);
4768267729Stuexen	m = sctp_get_mbuf_for_msg(len, 0, M_NOWAIT, 1, MT_DATA);
4769267729Stuexen	if (m != NULL) {
4770267729Stuexen		SCTP_BUF_LEN(m) = len;
4771267729Stuexen		no_user_data_cause = mtod(m, struct sctp_error_no_user_data *);
4772267729Stuexen		no_user_data_cause->cause.code = htons(SCTP_CAUSE_NO_USER_DATA);
4773267729Stuexen		no_user_data_cause->cause.length = htons((uint16_t) len);
4774267729Stuexen		no_user_data_cause->tsn = tsn;	/* tsn is passed in as NBO */
4775267729Stuexen	}
4776267729Stuexen	return (m);
4777267729Stuexen}
4778267729Stuexen
4779163953Srrs#ifdef SCTP_MBCNT_LOGGING
4780163953Srrsvoid
4781163953Srrssctp_free_bufspace(struct sctp_tcb *stcb, struct sctp_association *asoc,
4782163953Srrs    struct sctp_tmit_chunk *tp1, int chk_cnt)
4783163953Srrs{
4784163953Srrs	if (tp1->data == NULL) {
4785163953Srrs		return;
4786163953Srrs	}
4787163953Srrs	asoc->chunks_on_out_queue -= chk_cnt;
4788179783Srrs	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBCNT_LOGGING_ENABLE) {
4789170744Srrs		sctp_log_mbcnt(SCTP_LOG_MBCNT_DECREASE,
4790170744Srrs		    asoc->total_output_queue_size,
4791170744Srrs		    tp1->book_size,
4792170744Srrs		    0,
4793170744Srrs		    tp1->mbcnt);
4794170744Srrs	}
4795163953Srrs	if (asoc->total_output_queue_size >= tp1->book_size) {
4796166023Srrs		atomic_add_int(&asoc->total_output_queue_size, -tp1->book_size);
4797163953Srrs	} else {
4798163953Srrs		asoc->total_output_queue_size = 0;
4799163953Srrs	}
4800163953Srrs
4801163953Srrs	if (stcb->sctp_socket && (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) ||
4802163953Srrs	    ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE)))) {
4803163953Srrs		if (stcb->sctp_socket->so_snd.sb_cc >= tp1->book_size) {
4804163953Srrs			stcb->sctp_socket->so_snd.sb_cc -= tp1->book_size;
4805163953Srrs		} else {
4806163953Srrs			stcb->sctp_socket->so_snd.sb_cc = 0;
4807163953Srrs
4808163953Srrs		}
4809163953Srrs	}
4810163953Srrs}
4811163953Srrs
4812163953Srrs#endif
4813163953Srrs
4814163953Srrsint
4815163953Srrssctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1,
4816235416Stuexen    uint8_t sent, int so_locked
4817172090Srrs#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
4818172090Srrs    SCTP_UNUSED
4819172090Srrs#endif
4820172090Srrs)
4821163953Srrs{
4822189790Srrs	struct sctp_stream_out *strq;
4823216822Stuexen	struct sctp_tmit_chunk *chk = NULL, *tp2;
4824189790Srrs	struct sctp_stream_queue_pending *sp;
4825189790Srrs	uint16_t stream = 0, seq = 0;
4826189790Srrs	uint8_t foundeom = 0;
4827163953Srrs	int ret_sz = 0;
4828163953Srrs	int notdone;
4829189790Srrs	int do_wakeup_routine = 0;
4830163953Srrs
4831189790Srrs	stream = tp1->rec.data.stream_number;
4832189790Srrs	seq = tp1->rec.data.stream_seq;
4833270363Stuexen	if (sent || !(tp1->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG)) {
4834270363Stuexen		stcb->asoc.abandoned_sent[0]++;
4835270363Stuexen		stcb->asoc.abandoned_sent[PR_SCTP_POLICY(tp1->flags)]++;
4836270363Stuexen		stcb->asoc.strmout[stream].abandoned_sent[0]++;
4837270363Stuexen#if defined(SCTP_DETAILED_STR_STATS)
4838270363Stuexen		stcb->asoc.strmout[stream].abandoned_sent[PR_SCTP_POLICY(tp1->flags)]++;
4839270363Stuexen#endif
4840270363Stuexen	} else {
4841270363Stuexen		stcb->asoc.abandoned_unsent[0]++;
4842270363Stuexen		stcb->asoc.abandoned_unsent[PR_SCTP_POLICY(tp1->flags)]++;
4843270363Stuexen		stcb->asoc.strmout[stream].abandoned_unsent[0]++;
4844270363Stuexen#if defined(SCTP_DETAILED_STR_STATS)
4845270363Stuexen		stcb->asoc.strmout[stream].abandoned_unsent[PR_SCTP_POLICY(tp1->flags)]++;
4846270363Stuexen#endif
4847270363Stuexen	}
4848163953Srrs	do {
4849163953Srrs		ret_sz += tp1->book_size;
4850189790Srrs		if (tp1->data != NULL) {
4851190689Srrs			if (tp1->sent < SCTP_DATAGRAM_RESEND) {
4852190689Srrs				sctp_flight_size_decrease(tp1);
4853190689Srrs				sctp_total_flight_decrease(stcb, tp1);
4854190689Srrs			}
4855163953Srrs			sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1);
4856189790Srrs			stcb->asoc.peers_rwnd += tp1->send_size;
4857189790Srrs			stcb->asoc.peers_rwnd += SCTP_BASE_SYSCTL(sctp_peer_chunk_oh);
4858235416Stuexen			if (sent) {
4859235416Stuexen				sctp_ulp_notify(SCTP_NOTIFY_SENT_DG_FAIL, stcb, 0, tp1, so_locked);
4860235416Stuexen			} else {
4861235416Stuexen				sctp_ulp_notify(SCTP_NOTIFY_UNSENT_DG_FAIL, stcb, 0, tp1, so_locked);
4862235416Stuexen			}
4863196376Stuexen			if (tp1->data) {
4864196376Stuexen				sctp_m_freem(tp1->data);
4865196376Stuexen				tp1->data = NULL;
4866196376Stuexen			}
4867189790Srrs			do_wakeup_routine = 1;
4868189790Srrs			if (PR_SCTP_BUF_ENABLED(tp1->flags)) {
4869189790Srrs				stcb->asoc.sent_queue_cnt_removeable--;
4870172090Srrs			}
4871163953Srrs		}
4872190689Srrs		tp1->sent = SCTP_FORWARD_TSN_SKIP;
4873163953Srrs		if ((tp1->rec.data.rcv_flags & SCTP_DATA_NOT_FRAG) ==
4874163953Srrs		    SCTP_DATA_NOT_FRAG) {
4875163953Srrs			/* not frag'ed we ae done   */
4876163953Srrs			notdone = 0;
4877163953Srrs			foundeom = 1;
4878163953Srrs		} else if (tp1->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) {
4879163953Srrs			/* end of frag, we are done */
4880163953Srrs			notdone = 0;
4881163953Srrs			foundeom = 1;
4882163953Srrs		} else {
4883163953Srrs			/*
4884163953Srrs			 * Its a begin or middle piece, we must mark all of
4885163953Srrs			 * it
4886163953Srrs			 */
4887163953Srrs			notdone = 1;
4888163953Srrs			tp1 = TAILQ_NEXT(tp1, sctp_next);
4889163953Srrs		}
4890163953Srrs	} while (tp1 && notdone);
4891189790Srrs	if (foundeom == 0) {
4892163953Srrs		/*
4893163953Srrs		 * The multi-part message was scattered across the send and
4894163953Srrs		 * sent queue.
4895163953Srrs		 */
4896216822Stuexen		TAILQ_FOREACH_SAFE(tp1, &stcb->asoc.send_queue, sctp_next, tp2) {
4897216822Stuexen			if ((tp1->rec.data.stream_number != stream) ||
4898216822Stuexen			    (tp1->rec.data.stream_seq != seq)) {
4899216822Stuexen				break;
4900216822Stuexen			}
4901189790Srrs			/*
4902189790Srrs			 * save to chk in case we have some on stream out
4903189790Srrs			 * queue. If so and we have an un-transmitted one we
4904189790Srrs			 * don't have to fudge the TSN.
4905189790Srrs			 */
4906189790Srrs			chk = tp1;
4907189790Srrs			ret_sz += tp1->book_size;
4908196376Stuexen			sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1);
4909235416Stuexen			if (sent) {
4910235416Stuexen				sctp_ulp_notify(SCTP_NOTIFY_SENT_DG_FAIL, stcb, 0, tp1, so_locked);
4911235416Stuexen			} else {
4912235416Stuexen				sctp_ulp_notify(SCTP_NOTIFY_UNSENT_DG_FAIL, stcb, 0, tp1, so_locked);
4913235416Stuexen			}
4914196376Stuexen			if (tp1->data) {
4915196376Stuexen				sctp_m_freem(tp1->data);
4916196376Stuexen				tp1->data = NULL;
4917196376Stuexen			}
4918190689Srrs			/* No flight involved here book the size to 0 */
4919190689Srrs			tp1->book_size = 0;
4920189790Srrs			if (tp1->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) {
4921189790Srrs				foundeom = 1;
4922189790Srrs			}
4923189790Srrs			do_wakeup_routine = 1;
4924189790Srrs			tp1->sent = SCTP_FORWARD_TSN_SKIP;
4925189790Srrs			TAILQ_REMOVE(&stcb->asoc.send_queue, tp1, sctp_next);
4926189790Srrs			/*
4927189790Srrs			 * on to the sent queue so we can wait for it to be
4928189790Srrs			 * passed by.
4929189790Srrs			 */
4930189790Srrs			TAILQ_INSERT_TAIL(&stcb->asoc.sent_queue, tp1,
4931189790Srrs			    sctp_next);
4932189790Srrs			stcb->asoc.send_queue_cnt--;
4933189790Srrs			stcb->asoc.sent_queue_cnt++;
4934163953Srrs		}
4935163953Srrs	}
4936189790Srrs	if (foundeom == 0) {
4937189790Srrs		/*
4938189790Srrs		 * Still no eom found. That means there is stuff left on the
4939189790Srrs		 * stream out queue.. yuck.
4940189790Srrs		 */
4941242627Stuexen		SCTP_TCB_SEND_LOCK(stcb);
4942189790Srrs		strq = &stcb->asoc.strmout[stream];
4943242627Stuexen		sp = TAILQ_FIRST(&strq->outqueue);
4944242627Stuexen		if (sp != NULL) {
4945242627Stuexen			sp->discard_rest = 1;
4946242627Stuexen			/*
4947242627Stuexen			 * We may need to put a chunk on the queue that
4948242627Stuexen			 * holds the TSN that would have been sent with the
4949242627Stuexen			 * LAST bit.
4950242627Stuexen			 */
4951242627Stuexen			if (chk == NULL) {
4952242627Stuexen				/* Yep, we have to */
4953242627Stuexen				sctp_alloc_a_chunk(stcb, chk);
4954189790Srrs				if (chk == NULL) {
4955189790Srrs					/*
4956242627Stuexen					 * we are hosed. All we can do is
4957242627Stuexen					 * nothing.. which will cause an
4958242627Stuexen					 * abort if the peer is paying
4959242627Stuexen					 * attention.
4960189790Srrs					 */
4961242627Stuexen					goto oh_well;
4962189790Srrs				}
4963242627Stuexen				memset(chk, 0, sizeof(*chk));
4964242627Stuexen				chk->rec.data.rcv_flags = SCTP_DATA_LAST_FRAG;
4965242627Stuexen				chk->sent = SCTP_FORWARD_TSN_SKIP;
4966242627Stuexen				chk->asoc = &stcb->asoc;
4967242627Stuexen				chk->rec.data.stream_seq = strq->next_sequence_send;
4968242627Stuexen				chk->rec.data.stream_number = sp->stream;
4969242627Stuexen				chk->rec.data.payloadtype = sp->ppid;
4970242627Stuexen				chk->rec.data.context = sp->context;
4971242627Stuexen				chk->flags = sp->act_flags;
4972283730Stuexen				chk->whoTo = NULL;
4973242627Stuexen				chk->rec.data.TSN_seq = atomic_fetchadd_int(&stcb->asoc.sending_seq, 1);
4974283730Stuexen				strq->chunks_on_queues++;
4975242627Stuexen				TAILQ_INSERT_TAIL(&stcb->asoc.sent_queue, chk, sctp_next);
4976242627Stuexen				stcb->asoc.sent_queue_cnt++;
4977242627Stuexen				stcb->asoc.pr_sctp_cnt++;
4978242627Stuexen			} else {
4979242627Stuexen				chk->rec.data.rcv_flags |= SCTP_DATA_LAST_FRAG;
4980189790Srrs			}
4981242627Stuexen			strq->next_sequence_send++;
4982242627Stuexen	oh_well:
4983242627Stuexen			if (sp->data) {
4984242627Stuexen				/*
4985242627Stuexen				 * Pull any data to free up the SB and allow
4986242627Stuexen				 * sender to "add more" while we will throw
4987242627Stuexen				 * away :-)
4988242627Stuexen				 */
4989242627Stuexen				sctp_free_spbufspace(stcb, &stcb->asoc, sp);
4990242627Stuexen				ret_sz += sp->length;
4991242627Stuexen				do_wakeup_routine = 1;
4992242627Stuexen				sp->some_taken = 1;
4993242627Stuexen				sctp_m_freem(sp->data);
4994242627Stuexen				sp->data = NULL;
4995242627Stuexen				sp->tail_mbuf = NULL;
4996242627Stuexen				sp->length = 0;
4997242627Stuexen			}
4998242627Stuexen		}
4999189790Srrs		SCTP_TCB_SEND_UNLOCK(stcb);
5000189790Srrs	}
5001189790Srrs	if (do_wakeup_routine) {
5002237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
5003190689Srrs		struct socket *so;
5004190689Srrs
5005189790Srrs		so = SCTP_INP_SO(stcb->sctp_ep);
5006189790Srrs		if (!so_locked) {
5007189790Srrs			atomic_add_int(&stcb->asoc.refcnt, 1);
5008189790Srrs			SCTP_TCB_UNLOCK(stcb);
5009189790Srrs			SCTP_SOCKET_LOCK(so, 1);
5010189790Srrs			SCTP_TCB_LOCK(stcb);
5011189790Srrs			atomic_subtract_int(&stcb->asoc.refcnt, 1);
5012189790Srrs			if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
5013189790Srrs				/* assoc was freed while we were unlocked */
5014189790Srrs				SCTP_SOCKET_UNLOCK(so, 1);
5015189790Srrs				return (ret_sz);
5016189790Srrs			}
5017189790Srrs		}
5018189790Srrs#endif
5019189790Srrs		sctp_sowwakeup(stcb->sctp_ep, stcb->sctp_socket);
5020237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
5021189790Srrs		if (!so_locked) {
5022189790Srrs			SCTP_SOCKET_UNLOCK(so, 1);
5023189790Srrs		}
5024189790Srrs#endif
5025189790Srrs	}
5026163953Srrs	return (ret_sz);
5027163953Srrs}
5028163953Srrs
5029163953Srrs/*
5030163953Srrs * checks to see if the given address, sa, is one that is currently known by
5031163953Srrs * the kernel note: can't distinguish the same address on multiple interfaces
5032163953Srrs * and doesn't handle multiple addresses with different zone/scope id's note:
5033163953Srrs * ifa_ifwithaddr() compares the entire sockaddr struct
5034163953Srrs */
5035167598Srrsstruct sctp_ifa *
5036170744Srrssctp_find_ifa_in_ep(struct sctp_inpcb *inp, struct sockaddr *addr,
5037170744Srrs    int holds_lock)
5038163953Srrs{
5039167598Srrs	struct sctp_laddr *laddr;
5040163953Srrs
5041169420Srrs	if (holds_lock == 0) {
5042167598Srrs		SCTP_INP_RLOCK(inp);
5043169420Srrs	}
5044167598Srrs	LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
5045167598Srrs		if (laddr->ifa == NULL)
5046167598Srrs			continue;
5047167598Srrs		if (addr->sa_family != laddr->ifa->address.sa.sa_family)
5048167598Srrs			continue;
5049221249Stuexen#ifdef INET
5050167598Srrs		if (addr->sa_family == AF_INET) {
5051167598Srrs			if (((struct sockaddr_in *)addr)->sin_addr.s_addr ==
5052167598Srrs			    laddr->ifa->address.sin.sin_addr.s_addr) {
5053167598Srrs				/* found him. */
5054169420Srrs				if (holds_lock == 0) {
5055167598Srrs					SCTP_INP_RUNLOCK(inp);
5056169420Srrs				}
5057167598Srrs				return (laddr->ifa);
5058167598Srrs				break;
5059167598Srrs			}
5060178251Srrs		}
5061221249Stuexen#endif
5062178251Srrs#ifdef INET6
5063178251Srrs		if (addr->sa_family == AF_INET6) {
5064179157Srrs			if (SCTP6_ARE_ADDR_EQUAL((struct sockaddr_in6 *)addr,
5065179157Srrs			    &laddr->ifa->address.sin6)) {
5066167598Srrs				/* found him. */
5067169420Srrs				if (holds_lock == 0) {
5068167598Srrs					SCTP_INP_RUNLOCK(inp);
5069169420Srrs				}
5070167598Srrs				return (laddr->ifa);
5071167598Srrs				break;
5072167598Srrs			}
5073167598Srrs		}
5074178251Srrs#endif
5075167598Srrs	}
5076169420Srrs	if (holds_lock == 0) {
5077167598Srrs		SCTP_INP_RUNLOCK(inp);
5078169420Srrs	}
5079167598Srrs	return (NULL);
5080167598Srrs}
5081163953Srrs
5082167698Srrsuint32_t
5083167698Srrssctp_get_ifa_hash_val(struct sockaddr *addr)
5084167698Srrs{
5085221328Stuexen	switch (addr->sa_family) {
5086221328Stuexen#ifdef INET
5087221328Stuexen	case AF_INET:
5088221328Stuexen		{
5089221328Stuexen			struct sockaddr_in *sin;
5090167698Srrs
5091221328Stuexen			sin = (struct sockaddr_in *)addr;
5092221328Stuexen			return (sin->sin_addr.s_addr ^ (sin->sin_addr.s_addr >> 16));
5093221328Stuexen		}
5094221328Stuexen#endif
5095221328Stuexen#ifdef INET6
5096244728Stuexen	case AF_INET6:
5097221328Stuexen		{
5098221328Stuexen			struct sockaddr_in6 *sin6;
5099221328Stuexen			uint32_t hash_of_addr;
5100167698Srrs
5101221328Stuexen			sin6 = (struct sockaddr_in6 *)addr;
5102221328Stuexen			hash_of_addr = (sin6->sin6_addr.s6_addr32[0] +
5103221328Stuexen			    sin6->sin6_addr.s6_addr32[1] +
5104221328Stuexen			    sin6->sin6_addr.s6_addr32[2] +
5105221328Stuexen			    sin6->sin6_addr.s6_addr32[3]);
5106221328Stuexen			hash_of_addr = (hash_of_addr ^ (hash_of_addr >> 16));
5107221328Stuexen			return (hash_of_addr);
5108221328Stuexen		}
5109221328Stuexen#endif
5110221328Stuexen	default:
5111221328Stuexen		break;
5112167698Srrs	}
5113167698Srrs	return (0);
5114167698Srrs}
5115167698Srrs
5116167598Srrsstruct sctp_ifa *
5117167598Srrssctp_find_ifa_by_addr(struct sockaddr *addr, uint32_t vrf_id, int holds_lock)
5118167598Srrs{
5119167598Srrs	struct sctp_ifa *sctp_ifap;
5120167598Srrs	struct sctp_vrf *vrf;
5121167698Srrs	struct sctp_ifalist *hash_head;
5122167698Srrs	uint32_t hash_of_addr;
5123167598Srrs
5124168299Srrs	if (holds_lock == 0)
5125172218Srrs		SCTP_IPI_ADDR_RLOCK();
5126168299Srrs
5127167598Srrs	vrf = sctp_find_vrf(vrf_id);
5128168299Srrs	if (vrf == NULL) {
5129168299Srrs		if (holds_lock == 0)
5130172218Srrs			SCTP_IPI_ADDR_RUNLOCK();
5131167598Srrs		return (NULL);
5132168299Srrs	}
5133167698Srrs	hash_of_addr = sctp_get_ifa_hash_val(addr);
5134167598Srrs
5135169352Srrs	hash_head = &vrf->vrf_addr_hash[(hash_of_addr & vrf->vrf_addr_hashmark)];
5136168299Srrs	if (hash_head == NULL) {
5137169420Srrs		SCTP_PRINTF("hash_of_addr:%x mask:%x table:%x - ",
5138172218Srrs		    hash_of_addr, (uint32_t) vrf->vrf_addr_hashmark,
5139172218Srrs		    (uint32_t) (hash_of_addr & vrf->vrf_addr_hashmark));
5140168299Srrs		sctp_print_address(addr);
5141169420Srrs		SCTP_PRINTF("No such bucket for address\n");
5142168299Srrs		if (holds_lock == 0)
5143172218Srrs			SCTP_IPI_ADDR_RUNLOCK();
5144168299Srrs
5145168299Srrs		return (NULL);
5146168299Srrs	}
5147167698Srrs	LIST_FOREACH(sctp_ifap, hash_head, next_bucket) {
5148167698Srrs		if (addr->sa_family != sctp_ifap->address.sa.sa_family)
5149167698Srrs			continue;
5150221249Stuexen#ifdef INET
5151167698Srrs		if (addr->sa_family == AF_INET) {
5152167698Srrs			if (((struct sockaddr_in *)addr)->sin_addr.s_addr ==
5153167698Srrs			    sctp_ifap->address.sin.sin_addr.s_addr) {
5154167698Srrs				/* found him. */
5155167698Srrs				if (holds_lock == 0)
5156172218Srrs					SCTP_IPI_ADDR_RUNLOCK();
5157167698Srrs				return (sctp_ifap);
5158167698Srrs				break;
5159167698Srrs			}
5160178251Srrs		}
5161221249Stuexen#endif
5162178251Srrs#ifdef INET6
5163178251Srrs		if (addr->sa_family == AF_INET6) {
5164179157Srrs			if (SCTP6_ARE_ADDR_EQUAL((struct sockaddr_in6 *)addr,
5165179157Srrs			    &sctp_ifap->address.sin6)) {
5166167698Srrs				/* found him. */
5167167698Srrs				if (holds_lock == 0)
5168172218Srrs					SCTP_IPI_ADDR_RUNLOCK();
5169167698Srrs				return (sctp_ifap);
5170167698Srrs				break;
5171167698Srrs			}
5172167598Srrs		}
5173178251Srrs#endif
5174167598Srrs	}
5175167598Srrs	if (holds_lock == 0)
5176172218Srrs		SCTP_IPI_ADDR_RUNLOCK();
5177167598Srrs	return (NULL);
5178167598Srrs}
5179167598Srrs
5180163953Srrsstatic void
5181170140Srrssctp_user_rcvd(struct sctp_tcb *stcb, uint32_t * freed_so_far, int hold_rlock,
5182163953Srrs    uint32_t rwnd_req)
5183163953Srrs{
5184163953Srrs	/* User pulled some data, do we need a rwnd update? */
5185163953Srrs	int r_unlocked = 0;
5186163953Srrs	uint32_t dif, rwnd;
5187163953Srrs	struct socket *so = NULL;
5188163953Srrs
5189163953Srrs	if (stcb == NULL)
5190163953Srrs		return;
5191163953Srrs
5192163996Srrs	atomic_add_int(&stcb->asoc.refcnt, 1);
5193163953Srrs
5194167736Srrs	if (stcb->asoc.state & (SCTP_STATE_ABOUT_TO_BE_FREED |
5195167736Srrs	    SCTP_STATE_SHUTDOWN_RECEIVED |
5196170140Srrs	    SCTP_STATE_SHUTDOWN_ACK_SENT)) {
5197163953Srrs		/* Pre-check If we are freeing no update */
5198163953Srrs		goto no_lock;
5199163953Srrs	}
5200163953Srrs	SCTP_INP_INCR_REF(stcb->sctp_ep);
5201163953Srrs	if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
5202163953Srrs	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE)) {
5203163953Srrs		goto out;
5204163953Srrs	}
5205163953Srrs	so = stcb->sctp_socket;
5206163953Srrs	if (so == NULL) {
5207163953Srrs		goto out;
5208163953Srrs	}
5209163953Srrs	atomic_add_int(&stcb->freed_by_sorcv_sincelast, *freed_so_far);
5210163953Srrs	/* Have you have freed enough to look */
5211163953Srrs	*freed_so_far = 0;
5212163953Srrs	/* Yep, its worth a look and the lock overhead */
5213163953Srrs
5214163953Srrs	/* Figure out what the rwnd would be */
5215163953Srrs	rwnd = sctp_calc_rwnd(stcb, &stcb->asoc);
5216163953Srrs	if (rwnd >= stcb->asoc.my_last_reported_rwnd) {
5217163953Srrs		dif = rwnd - stcb->asoc.my_last_reported_rwnd;
5218163953Srrs	} else {
5219163953Srrs		dif = 0;
5220163953Srrs	}
5221163953Srrs	if (dif >= rwnd_req) {
5222163953Srrs		if (hold_rlock) {
5223163953Srrs			SCTP_INP_READ_UNLOCK(stcb->sctp_ep);
5224163953Srrs			r_unlocked = 1;
5225163953Srrs		}
5226163953Srrs		if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
5227163953Srrs			/*
5228163953Srrs			 * One last check before we allow the guy possibly
5229163953Srrs			 * to get in. There is a race, where the guy has not
5230163953Srrs			 * reached the gate. In that case
5231163953Srrs			 */
5232163953Srrs			goto out;
5233163953Srrs		}
5234163953Srrs		SCTP_TCB_LOCK(stcb);
5235163953Srrs		if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
5236163953Srrs			/* No reports here */
5237163953Srrs			SCTP_TCB_UNLOCK(stcb);
5238163953Srrs			goto out;
5239163953Srrs		}
5240163953Srrs		SCTP_STAT_INCR(sctps_wu_sacks_sent);
5241221627Stuexen		sctp_send_sack(stcb, SCTP_SO_LOCKED);
5242185694Srrs
5243163953Srrs		sctp_chunk_output(stcb->sctp_ep, stcb,
5244172090Srrs		    SCTP_OUTPUT_FROM_USR_RCVD, SCTP_SO_LOCKED);
5245163953Srrs		/* make sure no timer is running */
5246283823Stuexen		sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL,
5247283823Stuexen		    SCTP_FROM_SCTPUTIL + SCTP_LOC_6);
5248163953Srrs		SCTP_TCB_UNLOCK(stcb);
5249163953Srrs	} else {
5250163953Srrs		/* Update how much we have pending */
5251163953Srrs		stcb->freed_by_sorcv_sincelast = dif;
5252163953Srrs	}
5253163953Srrsout:
5254163953Srrs	if (so && r_unlocked && hold_rlock) {
5255163953Srrs		SCTP_INP_READ_LOCK(stcb->sctp_ep);
5256163953Srrs	}
5257163953Srrs	SCTP_INP_DECR_REF(stcb->sctp_ep);
5258163953Srrsno_lock:
5259163996Srrs	atomic_add_int(&stcb->asoc.refcnt, -1);
5260163953Srrs	return;
5261163953Srrs}
5262163953Srrs
5263163953Srrsint
5264163953Srrssctp_sorecvmsg(struct socket *so,
5265163953Srrs    struct uio *uio,
5266163953Srrs    struct mbuf **mp,
5267163953Srrs    struct sockaddr *from,
5268163953Srrs    int fromlen,
5269163953Srrs    int *msg_flags,
5270163953Srrs    struct sctp_sndrcvinfo *sinfo,
5271163953Srrs    int filling_sinfo)
5272163953Srrs{
5273163953Srrs	/*
5274163953Srrs	 * MSG flags we will look at MSG_DONTWAIT - non-blocking IO.
5275163953Srrs	 * MSG_PEEK - Look don't touch :-D (only valid with OUT mbuf copy
5276163953Srrs	 * mp=NULL thus uio is the copy method to userland) MSG_WAITALL - ??
5277163953Srrs	 * On the way out we may send out any combination of:
5278163953Srrs	 * MSG_NOTIFICATION MSG_EOR
5279163953Srrs	 *
5280163953Srrs	 */
5281163953Srrs	struct sctp_inpcb *inp = NULL;
5282163953Srrs	int my_len = 0;
5283163953Srrs	int cp_len = 0, error = 0;
5284163953Srrs	struct sctp_queued_to_read *control = NULL, *ctl = NULL, *nxt = NULL;
5285212713Stuexen	struct mbuf *m = NULL;
5286163953Srrs	struct sctp_tcb *stcb = NULL;
5287163953Srrs	int wakeup_read_socket = 0;
5288163953Srrs	int freecnt_applied = 0;
5289163953Srrs	int out_flags = 0, in_flags = 0;
5290163953Srrs	int block_allowed = 1;
5291170140Srrs	uint32_t freed_so_far = 0;
5292173509Srrs	uint32_t copied_so_far = 0;
5293166086Srrs	int in_eeor_mode = 0;
5294163953Srrs	int no_rcv_needed = 0;
5295163953Srrs	uint32_t rwnd_req = 0;
5296163953Srrs	int hold_sblock = 0;
5297163953Srrs	int hold_rlock = 0;
5298167598Srrs	int slen = 0;
5299170140Srrs	uint32_t held_length = 0;
5300169236Srwatson	int sockbuf_lock = 0;
5301163953Srrs
5302169352Srrs	if (uio == NULL) {
5303171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
5304169352Srrs		return (EINVAL);
5305169352Srrs	}
5306163953Srrs	if (msg_flags) {
5307163953Srrs		in_flags = *msg_flags;
5308168709Srrs		if (in_flags & MSG_PEEK)
5309168709Srrs			SCTP_STAT_INCR(sctps_read_peeks);
5310163953Srrs	} else {
5311163953Srrs		in_flags = 0;
5312163953Srrs	}
5313169352Srrs	slen = uio->uio_resid;
5314169352Srrs
5315163953Srrs	/* Pull in and set up our int flags */
5316163953Srrs	if (in_flags & MSG_OOB) {
5317163953Srrs		/* Out of band's NOT supported */
5318163953Srrs		return (EOPNOTSUPP);
5319163953Srrs	}
5320163953Srrs	if ((in_flags & MSG_PEEK) && (mp != NULL)) {
5321171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
5322163953Srrs		return (EINVAL);
5323163953Srrs	}
5324163953Srrs	if ((in_flags & (MSG_DONTWAIT
5325163953Srrs	    | MSG_NBIO
5326163953Srrs	    )) ||
5327167598Srrs	    SCTP_SO_IS_NBIO(so)) {
5328163953Srrs		block_allowed = 0;
5329163953Srrs	}
5330163953Srrs	/* setup the endpoint */
5331163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
5332163953Srrs	if (inp == NULL) {
5333171943Srrs		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EFAULT);
5334163953Srrs		return (EFAULT);
5335163953Srrs	}
5336167736Srrs	rwnd_req = (SCTP_SB_LIMIT_RCV(so) >> SCTP_RWND_HIWAT_SHIFT);
5337163953Srrs	/* Must be at least a MTU's worth */
5338163953Srrs	if (rwnd_req < SCTP_MIN_RWND)
5339163953Srrs		rwnd_req = SCTP_MIN_RWND;
5340163953Srrs	in_eeor_mode = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR);
5341179783Srrs	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RECV_RWND_LOGGING_ENABLE) {
5342170744Srrs		sctp_misc_ints(SCTP_SORECV_ENTER,
5343170744Srrs		    rwnd_req, in_eeor_mode, so->so_rcv.sb_cc, uio->uio_resid);
5344170744Srrs	}
5345179783Srrs	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RECV_RWND_LOGGING_ENABLE) {
5346170744Srrs		sctp_misc_ints(SCTP_SORECV_ENTERPL,
5347170744Srrs		    rwnd_req, block_allowed, so->so_rcv.sb_cc, uio->uio_resid);
5348170744Srrs	}
5349175845Srwatson	error = sblock(&so->so_rcv, (block_allowed ? SBL_WAIT : 0));
5350163953Srrs	if (error) {
5351163953Srrs		goto release_unlocked;
5352163953Srrs	}
5353242680Smjg	sockbuf_lock = 1;
5354163953Srrsrestart:
5355163953Srrs
5356169236Srwatson
5357163953Srrsrestart_nosblocks:
5358163953Srrs	if (hold_sblock == 0) {
5359163953Srrs		SOCKBUF_LOCK(&so->so_rcv);
5360163953Srrs		hold_sblock = 1;
5361163953Srrs	}
5362163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
5363163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE)) {
5364163953Srrs		goto out;
5365163953Srrs	}
5366235402Stuexen	if ((so->so_rcv.sb_state & SBS_CANTRCVMORE) && (so->so_rcv.sb_cc == 0)) {
5367163953Srrs		if (so->so_error) {
5368163953Srrs			error = so->so_error;
5369166023Srrs			if ((in_flags & MSG_PEEK) == 0)
5370166023Srrs				so->so_error = 0;
5371174257Srrs			goto out;
5372163953Srrs		} else {
5373174257Srrs			if (so->so_rcv.sb_cc == 0) {
5374174257Srrs				/* indicate EOF */
5375174257Srrs				error = 0;
5376174257Srrs				goto out;
5377174257Srrs			}
5378163953Srrs		}
5379163953Srrs	}
5380163953Srrs	if ((so->so_rcv.sb_cc <= held_length) && block_allowed) {
5381163953Srrs		/* we need to wait for data */
5382163953Srrs		if ((so->so_rcv.sb_cc == 0) &&
5383163953Srrs		    ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5384163953Srrs		    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) {
5385163953Srrs			if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0) {
5386163953Srrs				/*
5387163953Srrs				 * For active open side clear flags for
5388163953Srrs				 * re-use passive open is blocked by
5389163953Srrs				 * connect.
5390163953Srrs				 */
5391163953Srrs				if (inp->sctp_flags & SCTP_PCB_FLAGS_WAS_ABORTED) {
5392163953Srrs					/*
5393163953Srrs					 * You were aborted, passive side
5394163953Srrs					 * always hits here
5395163953Srrs					 */
5396171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET);
5397163953Srrs					error = ECONNRESET;
5398163953Srrs				}
5399163953Srrs				so->so_state &= ~(SS_ISCONNECTING |
5400163953Srrs				    SS_ISDISCONNECTING |
5401163953Srrs				    SS_ISCONFIRMING |
5402163953Srrs				    SS_ISCONNECTED);
5403163953Srrs				if (error == 0) {
5404163953Srrs					if ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) == 0) {
5405171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOTCONN);
5406163953Srrs						error = ENOTCONN;
5407163953Srrs					}
5408163953Srrs				}
5409163953Srrs				goto out;
5410163953Srrs			}
5411163953Srrs		}
5412163953Srrs		error = sbwait(&so->so_rcv);
5413163953Srrs		if (error) {
5414163953Srrs			goto out;
5415163953Srrs		}
5416163953Srrs		held_length = 0;
5417163953Srrs		goto restart_nosblocks;
5418163953Srrs	} else if (so->so_rcv.sb_cc == 0) {
5419166023Srrs		if (so->so_error) {
5420166023Srrs			error = so->so_error;
5421166023Srrs			if ((in_flags & MSG_PEEK) == 0)
5422166023Srrs				so->so_error = 0;
5423166023Srrs		} else {
5424166023Srrs			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5425166023Srrs			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
5426166023Srrs				if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0) {
5427166023Srrs					/*
5428166023Srrs					 * For active open side clear flags
5429166023Srrs					 * for re-use passive open is
5430166023Srrs					 * blocked by connect.
5431166023Srrs					 */
5432166023Srrs					if (inp->sctp_flags & SCTP_PCB_FLAGS_WAS_ABORTED) {
5433166023Srrs						/*
5434166023Srrs						 * You were aborted, passive
5435166023Srrs						 * side always hits here
5436166023Srrs						 */
5437171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET);
5438166023Srrs						error = ECONNRESET;
5439166023Srrs					}
5440166023Srrs					so->so_state &= ~(SS_ISCONNECTING |
5441166023Srrs					    SS_ISDISCONNECTING |
5442166023Srrs					    SS_ISCONFIRMING |
5443166023Srrs					    SS_ISCONNECTED);
5444166023Srrs					if (error == 0) {
5445166023Srrs						if ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) == 0) {
5446171943Srrs							SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOTCONN);
5447166023Srrs							error = ENOTCONN;
5448166023Srrs						}
5449166023Srrs					}
5450166023Srrs					goto out;
5451166023Srrs				}
5452166023Srrs			}
5453171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EWOULDBLOCK);
5454166023Srrs			error = EWOULDBLOCK;
5455166023Srrs		}
5456163953Srrs		goto out;
5457163953Srrs	}
5458169208Srrs	if (hold_sblock == 1) {
5459169208Srrs		SOCKBUF_UNLOCK(&so->so_rcv);
5460169208Srrs		hold_sblock = 0;
5461169208Srrs	}
5462163953Srrs	/* we possibly have data we can read */
5463169655Srrs	/* sa_ignore FREED_MEMORY */
5464163953Srrs	control = TAILQ_FIRST(&inp->read_queue);
5465163953Srrs	if (control == NULL) {
5466163953Srrs		/*
5467163953Srrs		 * This could be happening since the appender did the
5468163953Srrs		 * increment but as not yet did the tailq insert onto the
5469163953Srrs		 * read_queue
5470163953Srrs		 */
5471163953Srrs		if (hold_rlock == 0) {
5472163953Srrs			SCTP_INP_READ_LOCK(inp);
5473163953Srrs		}
5474163953Srrs		control = TAILQ_FIRST(&inp->read_queue);
5475163953Srrs		if ((control == NULL) && (so->so_rcv.sb_cc != 0)) {
5476165220Srrs#ifdef INVARIANTS
5477163953Srrs			panic("Huh, its non zero and nothing on control?");
5478163953Srrs#endif
5479163953Srrs			so->so_rcv.sb_cc = 0;
5480163953Srrs		}
5481163953Srrs		SCTP_INP_READ_UNLOCK(inp);
5482163953Srrs		hold_rlock = 0;
5483163953Srrs		goto restart;
5484163953Srrs	}
5485163953Srrs	if ((control->length == 0) &&
5486163953Srrs	    (control->do_not_ref_stcb)) {
5487163953Srrs		/*
5488163953Srrs		 * Clean up code for freeing assoc that left behind a
5489163953Srrs		 * pdapi.. maybe a peer in EEOR that just closed after
5490163953Srrs		 * sending and never indicated a EOR.
5491163953Srrs		 */
5492163953Srrs		if (hold_rlock == 0) {
5493163953Srrs			hold_rlock = 1;
5494163953Srrs			SCTP_INP_READ_LOCK(inp);
5495163953Srrs		}
5496163953Srrs		control->held_length = 0;
5497163953Srrs		if (control->data) {
5498163953Srrs			/* Hmm there is data here .. fix */
5499170140Srrs			struct mbuf *m_tmp;
5500163953Srrs			int cnt = 0;
5501163953Srrs
5502170140Srrs			m_tmp = control->data;
5503170140Srrs			while (m_tmp) {
5504170140Srrs				cnt += SCTP_BUF_LEN(m_tmp);
5505170140Srrs				if (SCTP_BUF_NEXT(m_tmp) == NULL) {
5506170140Srrs					control->tail_mbuf = m_tmp;
5507163953Srrs					control->end_added = 1;
5508163953Srrs				}
5509170140Srrs				m_tmp = SCTP_BUF_NEXT(m_tmp);
5510163953Srrs			}
5511163953Srrs			control->length = cnt;
5512163953Srrs		} else {
5513163953Srrs			/* remove it */
5514163953Srrs			TAILQ_REMOVE(&inp->read_queue, control, next);
5515163953Srrs			/* Add back any hiddend data */
5516163953Srrs			sctp_free_remote_addr(control->whoFrom);
5517163953Srrs			sctp_free_a_readq(stcb, control);
5518163953Srrs		}
5519163953Srrs		if (hold_rlock) {
5520163953Srrs			hold_rlock = 0;
5521163953Srrs			SCTP_INP_READ_UNLOCK(inp);
5522163953Srrs		}
5523163953Srrs		goto restart;
5524163953Srrs	}
5525196260Stuexen	if ((control->length == 0) &&
5526196260Stuexen	    (control->end_added == 1)) {
5527196260Stuexen		/*
5528196260Stuexen		 * Do we also need to check for (control->pdapi_aborted ==
5529196260Stuexen		 * 1)?
5530196260Stuexen		 */
5531196260Stuexen		if (hold_rlock == 0) {
5532196260Stuexen			hold_rlock = 1;
5533196260Stuexen			SCTP_INP_READ_LOCK(inp);
5534196260Stuexen		}
5535196260Stuexen		TAILQ_REMOVE(&inp->read_queue, control, next);
5536196260Stuexen		if (control->data) {
5537196260Stuexen#ifdef INVARIANTS
5538196260Stuexen			panic("control->data not null but control->length == 0");
5539196260Stuexen#else
5540196260Stuexen			SCTP_PRINTF("Strange, data left in the control buffer. Cleaning up.\n");
5541196260Stuexen			sctp_m_freem(control->data);
5542196260Stuexen			control->data = NULL;
5543196260Stuexen#endif
5544196260Stuexen		}
5545196260Stuexen		if (control->aux_data) {
5546196260Stuexen			sctp_m_free(control->aux_data);
5547196260Stuexen			control->aux_data = NULL;
5548196260Stuexen		}
5549196260Stuexen		sctp_free_remote_addr(control->whoFrom);
5550196260Stuexen		sctp_free_a_readq(stcb, control);
5551196260Stuexen		if (hold_rlock) {
5552196260Stuexen			hold_rlock = 0;
5553196260Stuexen			SCTP_INP_READ_UNLOCK(inp);
5554196260Stuexen		}
5555196260Stuexen		goto restart;
5556196260Stuexen	}
5557163953Srrs	if (control->length == 0) {
5558163953Srrs		if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) &&
5559163953Srrs		    (filling_sinfo)) {
5560163953Srrs			/* find a more suitable one then this */
5561163953Srrs			ctl = TAILQ_NEXT(control, next);
5562163953Srrs			while (ctl) {
5563168943Srrs				if ((ctl->stcb != control->stcb) && (ctl->length) &&
5564168943Srrs				    (ctl->some_taken ||
5565169352Srrs				    (ctl->spec_flags & M_NOTIFICATION) ||
5566168943Srrs				    ((ctl->do_not_ref_stcb == 0) &&
5567168943Srrs				    (ctl->stcb->asoc.strmin[ctl->sinfo_stream].delivery_started == 0)))
5568168943Srrs				    ) {
5569168943Srrs					/*-
5570168943Srrs					 * If we have a different TCB next, and there is data
5571168943Srrs					 * present. If we have already taken some (pdapi), OR we can
5572168943Srrs					 * ref the tcb and no delivery as started on this stream, we
5573169352Srrs					 * take it. Note we allow a notification on a different
5574169352Srrs					 * assoc to be delivered..
5575168943Srrs					 */
5576163953Srrs					control = ctl;
5577163953Srrs					goto found_one;
5578168943Srrs				} else if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS)) &&
5579168943Srrs					    (ctl->length) &&
5580168943Srrs					    ((ctl->some_taken) ||
5581168943Srrs					    ((ctl->do_not_ref_stcb == 0) &&
5582169352Srrs					    ((ctl->spec_flags & M_NOTIFICATION) == 0) &&
5583206137Stuexen				    (ctl->stcb->asoc.strmin[ctl->sinfo_stream].delivery_started == 0)))) {
5584168943Srrs					/*-
5585168943Srrs					 * If we have the same tcb, and there is data present, and we
5586168943Srrs					 * have the strm interleave feature present. Then if we have
5587168943Srrs					 * taken some (pdapi) or we can refer to tht tcb AND we have
5588168943Srrs					 * not started a delivery for this stream, we can take it.
5589169352Srrs					 * Note we do NOT allow a notificaiton on the same assoc to
5590169352Srrs					 * be delivered.
5591168943Srrs					 */
5592168943Srrs					control = ctl;
5593168943Srrs					goto found_one;
5594163953Srrs				}
5595163953Srrs				ctl = TAILQ_NEXT(ctl, next);
5596163953Srrs			}
5597163953Srrs		}
5598163953Srrs		/*
5599163953Srrs		 * if we reach here, not suitable replacement is available
5600163953Srrs		 * <or> fragment interleave is NOT on. So stuff the sb_cc
5601163953Srrs		 * into the our held count, and its time to sleep again.
5602163953Srrs		 */
5603163953Srrs		held_length = so->so_rcv.sb_cc;
5604163953Srrs		control->held_length = so->so_rcv.sb_cc;
5605163953Srrs		goto restart;
5606163953Srrs	}
5607163953Srrs	/* Clear the held length since there is something to read */
5608163953Srrs	control->held_length = 0;
5609163953Srrs	if (hold_rlock) {
5610163953Srrs		SCTP_INP_READ_UNLOCK(inp);
5611163953Srrs		hold_rlock = 0;
5612163953Srrs	}
5613163953Srrsfound_one:
5614163953Srrs	/*
5615163953Srrs	 * If we reach here, control has a some data for us to read off.
5616163953Srrs	 * Note that stcb COULD be NULL.
5617163953Srrs	 */
5618174323Srrs	control->some_taken++;
5619163953Srrs	if (hold_sblock) {
5620163953Srrs		SOCKBUF_UNLOCK(&so->so_rcv);
5621163953Srrs		hold_sblock = 0;
5622163953Srrs	}
5623163953Srrs	stcb = control->stcb;
5624163953Srrs	if (stcb) {
5625170138Srrs		if ((control->do_not_ref_stcb == 0) &&
5626170138Srrs		    (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED)) {
5627163996Srrs			if (freecnt_applied == 0)
5628163996Srrs				stcb = NULL;
5629163953Srrs		} else if (control->do_not_ref_stcb == 0) {
5630163953Srrs			/* you can't free it on me please */
5631163953Srrs			/*
5632163953Srrs			 * The lock on the socket buffer protects us so the
5633163953Srrs			 * free code will stop. But since we used the
5634163953Srrs			 * socketbuf lock and the sender uses the tcb_lock
5635163953Srrs			 * to increment, we need to use the atomic add to
5636163953Srrs			 * the refcnt
5637163953Srrs			 */
5638172396Srrs			if (freecnt_applied) {
5639172396Srrs#ifdef INVARIANTS
5640170091Srrs				panic("refcnt already incremented");
5641172396Srrs#else
5642234995Stuexen				SCTP_PRINTF("refcnt already incremented?\n");
5643172396Srrs#endif
5644172396Srrs			} else {
5645172396Srrs				atomic_add_int(&stcb->asoc.refcnt, 1);
5646172396Srrs				freecnt_applied = 1;
5647172396Srrs			}
5648163953Srrs			/*
5649163953Srrs			 * Setup to remember how much we have not yet told
5650163953Srrs			 * the peer our rwnd has opened up. Note we grab the
5651163953Srrs			 * value from the tcb from last time. Note too that
5652170138Srrs			 * sack sending clears this when a sack is sent,
5653163953Srrs			 * which is fine. Once we hit the rwnd_req, we then
5654163953Srrs			 * will go to the sctp_user_rcvd() that will not
5655163953Srrs			 * lock until it KNOWs it MUST send a WUP-SACK.
5656163953Srrs			 */
5657163953Srrs			freed_so_far = stcb->freed_by_sorcv_sincelast;
5658163953Srrs			stcb->freed_by_sorcv_sincelast = 0;
5659163953Srrs		}
5660163953Srrs	}
5661169352Srrs	if (stcb &&
5662169352Srrs	    ((control->spec_flags & M_NOTIFICATION) == 0) &&
5663169295Srrs	    control->do_not_ref_stcb == 0) {
5664169208Srrs		stcb->asoc.strmin[control->sinfo_stream].delivery_started = 1;
5665169208Srrs	}
5666163953Srrs	/* First lets get off the sinfo and sockaddr info */
5667163953Srrs	if ((sinfo) && filling_sinfo) {
5668163953Srrs		memcpy(sinfo, control, sizeof(struct sctp_nonpad_sndrcvinfo));
5669163953Srrs		nxt = TAILQ_NEXT(control, next);
5670223132Stuexen		if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO) ||
5671223132Stuexen		    sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO)) {
5672163953Srrs			struct sctp_extrcvinfo *s_extra;
5673163953Srrs
5674163953Srrs			s_extra = (struct sctp_extrcvinfo *)sinfo;
5675168943Srrs			if ((nxt) &&
5676168943Srrs			    (nxt->length)) {
5677294178Stuexen				s_extra->serinfo_next_flags = SCTP_NEXT_MSG_AVAIL;
5678163953Srrs				if (nxt->sinfo_flags & SCTP_UNORDERED) {
5679294178Stuexen					s_extra->serinfo_next_flags |= SCTP_NEXT_MSG_IS_UNORDERED;
5680163953Srrs				}
5681166675Srrs				if (nxt->spec_flags & M_NOTIFICATION) {
5682294178Stuexen					s_extra->serinfo_next_flags |= SCTP_NEXT_MSG_IS_NOTIFICATION;
5683166675Srrs				}
5684294178Stuexen				s_extra->serinfo_next_aid = nxt->sinfo_assoc_id;
5685294178Stuexen				s_extra->serinfo_next_length = nxt->length;
5686294178Stuexen				s_extra->serinfo_next_ppid = nxt->sinfo_ppid;
5687294178Stuexen				s_extra->serinfo_next_stream = nxt->sinfo_stream;
5688163953Srrs				if (nxt->tail_mbuf != NULL) {
5689165647Srrs					if (nxt->end_added) {
5690294178Stuexen						s_extra->serinfo_next_flags |= SCTP_NEXT_MSG_ISCOMPLETE;
5691163953Srrs					}
5692163953Srrs				}
5693163953Srrs			} else {
5694163953Srrs				/*
5695163953Srrs				 * we explicitly 0 this, since the memcpy
5696163953Srrs				 * got some other things beyond the older
5697163953Srrs				 * sinfo_ that is on the control's structure
5698163953Srrs				 * :-D
5699163953Srrs				 */
5700168943Srrs				nxt = NULL;
5701294178Stuexen				s_extra->serinfo_next_flags = SCTP_NO_NEXT_MSG;
5702294178Stuexen				s_extra->serinfo_next_aid = 0;
5703294178Stuexen				s_extra->serinfo_next_length = 0;
5704294178Stuexen				s_extra->serinfo_next_ppid = 0;
5705294178Stuexen				s_extra->serinfo_next_stream = 0;
5706163953Srrs			}
5707163953Srrs		}
5708163953Srrs		/*
5709163953Srrs		 * update off the real current cum-ack, if we have an stcb.
5710163953Srrs		 */
5711170138Srrs		if ((control->do_not_ref_stcb == 0) && stcb)
5712163953Srrs			sinfo->sinfo_cumtsn = stcb->asoc.cumulative_tsn;
5713163953Srrs		/*
5714163953Srrs		 * mask off the high bits, we keep the actual chunk bits in
5715163953Srrs		 * there.
5716163953Srrs		 */
5717163953Srrs		sinfo->sinfo_flags &= 0x00ff;
5718170354Srrs		if ((control->sinfo_flags >> 8) & SCTP_DATA_UNORDERED) {
5719170354Srrs			sinfo->sinfo_flags |= SCTP_UNORDERED;
5720170354Srrs		}
5721163953Srrs	}
5722171477Srrs#ifdef SCTP_ASOCLOG_OF_TSNS
5723171477Srrs	{
5724171477Srrs		int index, newindex;
5725171477Srrs		struct sctp_pcbtsn_rlog *entry;
5726171477Srrs
5727171477Srrs		do {
5728171477Srrs			index = inp->readlog_index;
5729171477Srrs			newindex = index + 1;
5730171477Srrs			if (newindex >= SCTP_READ_LOG_SIZE) {
5731171477Srrs				newindex = 0;
5732171477Srrs			}
5733171477Srrs		} while (atomic_cmpset_int(&inp->readlog_index, index, newindex) == 0);
5734171477Srrs		entry = &inp->readlog[index];
5735171477Srrs		entry->vtag = control->sinfo_assoc_id;
5736171477Srrs		entry->strm = control->sinfo_stream;
5737171477Srrs		entry->seq = control->sinfo_ssn;
5738171477Srrs		entry->sz = control->length;
5739171477Srrs		entry->flgs = control->sinfo_flags;
5740171477Srrs	}
5741171477Srrs#endif
5742283699Stuexen	if ((fromlen > 0) && (from != NULL)) {
5743283699Stuexen		union sctp_sockstore store;
5744283699Stuexen		size_t len;
5745283699Stuexen
5746233311Stuexen		switch (control->whoFrom->ro._l_addr.sa.sa_family) {
5747233311Stuexen#ifdef INET6
5748233311Stuexen		case AF_INET6:
5749283699Stuexen			len = sizeof(struct sockaddr_in6);
5750283699Stuexen			store.sin6 = control->whoFrom->ro._l_addr.sin6;
5751283699Stuexen			store.sin6.sin6_port = control->port_from;
5752233311Stuexen			break;
5753233311Stuexen#endif
5754167598Srrs#ifdef INET
5755233311Stuexen		case AF_INET:
5756283699Stuexen#ifdef INET6
5757283699Stuexen			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
5758283699Stuexen				len = sizeof(struct sockaddr_in6);
5759283699Stuexen				in6_sin_2_v4mapsin6(&control->whoFrom->ro._l_addr.sin,
5760283699Stuexen				    &store.sin6);
5761283699Stuexen				store.sin6.sin6_port = control->port_from;
5762283699Stuexen			} else {
5763283699Stuexen				len = sizeof(struct sockaddr_in);
5764283699Stuexen				store.sin = control->whoFrom->ro._l_addr.sin;
5765283699Stuexen				store.sin.sin_port = control->port_from;
5766283699Stuexen			}
5767283699Stuexen#else
5768283699Stuexen			len = sizeof(struct sockaddr_in);
5769283699Stuexen			store.sin = control->whoFrom->ro._l_addr.sin;
5770283699Stuexen			store.sin.sin_port = control->port_from;
5771283699Stuexen#endif
5772233311Stuexen			break;
5773233311Stuexen#endif
5774233311Stuexen		default:
5775283699Stuexen			len = 0;
5776233311Stuexen			break;
5777233311Stuexen		}
5778283699Stuexen		memcpy(from, &store, min((size_t)fromlen, len));
5779238475Stuexen#ifdef INET6
5780163953Srrs		{
5781233311Stuexen			struct sockaddr_in6 lsa6, *from6;
5782163953Srrs
5783233311Stuexen			from6 = (struct sockaddr_in6 *)from;
5784233311Stuexen			sctp_recover_scope_mac(from6, (&lsa6));
5785163953Srrs		}
5786163953Srrs#endif
5787163953Srrs	}
5788163953Srrs	/* now copy out what data we can */
5789163953Srrs	if (mp == NULL) {
5790163953Srrs		/* copy out each mbuf in the chain up to length */
5791163953Srrsget_more_data:
5792163953Srrs		m = control->data;
5793163953Srrs		while (m) {
5794163953Srrs			/* Move out all we can */
5795163953Srrs			cp_len = (int)uio->uio_resid;
5796165647Srrs			my_len = (int)SCTP_BUF_LEN(m);
5797163953Srrs			if (cp_len > my_len) {
5798163953Srrs				/* not enough in this buf */
5799163953Srrs				cp_len = my_len;
5800163953Srrs			}
5801163953Srrs			if (hold_rlock) {
5802163953Srrs				SCTP_INP_READ_UNLOCK(inp);
5803163953Srrs				hold_rlock = 0;
5804163953Srrs			}
5805163953Srrs			if (cp_len > 0)
5806163953Srrs				error = uiomove(mtod(m, char *), cp_len, uio);
5807163953Srrs			/* re-read */
5808163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
5809163953Srrs				goto release;
5810163953Srrs			}
5811170138Srrs			if ((control->do_not_ref_stcb == 0) && stcb &&
5812163953Srrs			    stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
5813163953Srrs				no_rcv_needed = 1;
5814163953Srrs			}
5815163953Srrs			if (error) {
5816163953Srrs				/* error we are out of here */
5817163953Srrs				goto release;
5818163953Srrs			}
5819165647Srrs			if ((SCTP_BUF_NEXT(m) == NULL) &&
5820165647Srrs			    (cp_len >= SCTP_BUF_LEN(m)) &&
5821163953Srrs			    ((control->end_added == 0) ||
5822170138Srrs			    (control->end_added &&
5823170138Srrs			    (TAILQ_NEXT(control, next) == NULL)))
5824163953Srrs			    ) {
5825163953Srrs				SCTP_INP_READ_LOCK(inp);
5826163953Srrs				hold_rlock = 1;
5827163953Srrs			}
5828165647Srrs			if (cp_len == SCTP_BUF_LEN(m)) {
5829165647Srrs				if ((SCTP_BUF_NEXT(m) == NULL) &&
5830165647Srrs				    (control->end_added)) {
5831163953Srrs					out_flags |= MSG_EOR;
5832212225Srrs					if ((control->do_not_ref_stcb == 0) &&
5833212225Srrs					    (control->stcb != NULL) &&
5834212225Srrs					    ((control->spec_flags & M_NOTIFICATION) == 0))
5835168961Srrs						control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0;
5836163953Srrs				}
5837165647Srrs				if (control->spec_flags & M_NOTIFICATION) {
5838163953Srrs					out_flags |= MSG_NOTIFICATION;
5839163953Srrs				}
5840163953Srrs				/* we ate up the mbuf */
5841163953Srrs				if (in_flags & MSG_PEEK) {
5842163953Srrs					/* just looking */
5843165647Srrs					m = SCTP_BUF_NEXT(m);
5844163953Srrs					copied_so_far += cp_len;
5845163953Srrs				} else {
5846163953Srrs					/* dispose of the mbuf */
5847179783Srrs					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
5848170744Srrs						sctp_sblog(&so->so_rcv,
5849170744Srrs						    control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m));
5850170744Srrs					}
5851163953Srrs					sctp_sbfree(control, stcb, &so->so_rcv, m);
5852179783Srrs					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
5853170744Srrs						sctp_sblog(&so->so_rcv,
5854170744Srrs						    control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0);
5855170744Srrs					}
5856163953Srrs					copied_so_far += cp_len;
5857163953Srrs					freed_so_far += cp_len;
5858171943Srrs					freed_so_far += MSIZE;
5859171477Srrs					atomic_subtract_int(&control->length, cp_len);
5860163953Srrs					control->data = sctp_m_free(m);
5861163953Srrs					m = control->data;
5862163953Srrs					/*
5863163953Srrs					 * been through it all, must hold sb
5864163953Srrs					 * lock ok to null tail
5865163953Srrs					 */
5866163953Srrs					if (control->data == NULL) {
5867165220Srrs#ifdef INVARIANTS
5868163953Srrs						if ((control->end_added == 0) ||
5869163953Srrs						    (TAILQ_NEXT(control, next) == NULL)) {
5870163953Srrs							/*
5871163953Srrs							 * If the end is not
5872163953Srrs							 * added, OR the
5873163953Srrs							 * next is NOT null
5874163953Srrs							 * we MUST have the
5875163953Srrs							 * lock.
5876163953Srrs							 */
5877163953Srrs							if (mtx_owned(&inp->inp_rdata_mtx) == 0) {
5878163953Srrs								panic("Hmm we don't own the lock?");
5879163953Srrs							}
5880163953Srrs						}
5881163953Srrs#endif
5882163953Srrs						control->tail_mbuf = NULL;
5883165220Srrs#ifdef INVARIANTS
5884163953Srrs						if ((control->end_added) && ((out_flags & MSG_EOR) == 0)) {
5885163953Srrs							panic("end_added, nothing left and no MSG_EOR");
5886163953Srrs						}
5887163953Srrs#endif
5888163953Srrs					}
5889163953Srrs				}
5890163953Srrs			} else {
5891163953Srrs				/* Do we need to trim the mbuf? */
5892165647Srrs				if (control->spec_flags & M_NOTIFICATION) {
5893163953Srrs					out_flags |= MSG_NOTIFICATION;
5894163953Srrs				}
5895163953Srrs				if ((in_flags & MSG_PEEK) == 0) {
5896165647Srrs					SCTP_BUF_RESV_UF(m, cp_len);
5897165647Srrs					SCTP_BUF_LEN(m) -= cp_len;
5898179783Srrs					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
5899170744Srrs						sctp_sblog(&so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, cp_len);
5900170744Srrs					}
5901163953Srrs					atomic_subtract_int(&so->so_rcv.sb_cc, cp_len);
5902170138Srrs					if ((control->do_not_ref_stcb == 0) &&
5903170138Srrs					    stcb) {
5904163953Srrs						atomic_subtract_int(&stcb->asoc.sb_cc, cp_len);
5905163953Srrs					}
5906163953Srrs					copied_so_far += cp_len;
5907163953Srrs					freed_so_far += cp_len;
5908171943Srrs					freed_so_far += MSIZE;
5909179783Srrs					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
5910170744Srrs						sctp_sblog(&so->so_rcv, control->do_not_ref_stcb ? NULL : stcb,
5911170744Srrs						    SCTP_LOG_SBRESULT, 0);
5912170744Srrs					}
5913171477Srrs					atomic_subtract_int(&control->length, cp_len);
5914163953Srrs				} else {
5915163953Srrs					copied_so_far += cp_len;
5916163953Srrs				}
5917163953Srrs			}
5918170056Srrs			if ((out_flags & MSG_EOR) || (uio->uio_resid == 0)) {
5919163953Srrs				break;
5920163953Srrs			}
5921163953Srrs			if (((stcb) && (in_flags & MSG_PEEK) == 0) &&
5922163953Srrs			    (control->do_not_ref_stcb == 0) &&
5923163953Srrs			    (freed_so_far >= rwnd_req)) {
5924163953Srrs				sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req);
5925163953Srrs			}
5926163953Srrs		}		/* end while(m) */
5927163953Srrs		/*
5928163953Srrs		 * At this point we have looked at it all and we either have
5929163953Srrs		 * a MSG_EOR/or read all the user wants... <OR>
5930163953Srrs		 * control->length == 0.
5931163953Srrs		 */
5932170056Srrs		if ((out_flags & MSG_EOR) && ((in_flags & MSG_PEEK) == 0)) {
5933163953Srrs			/* we are done with this control */
5934163953Srrs			if (control->length == 0) {
5935163953Srrs				if (control->data) {
5936165220Srrs#ifdef INVARIANTS
5937163953Srrs					panic("control->data not null at read eor?");
5938163953Srrs#else
5939169420Srrs					SCTP_PRINTF("Strange, data left in the control buffer .. invarients would panic?\n");
5940163953Srrs					sctp_m_freem(control->data);
5941163953Srrs					control->data = NULL;
5942163953Srrs#endif
5943163953Srrs				}
5944163953Srrs		done_with_control:
5945163953Srrs				if (TAILQ_NEXT(control, next) == NULL) {
5946163953Srrs					/*
5947163953Srrs					 * If we don't have a next we need a
5948172703Srrs					 * lock, if there is a next
5949172703Srrs					 * interrupt is filling ahead of us
5950172703Srrs					 * and we don't need a lock to
5951172703Srrs					 * remove this guy (which is the
5952172703Srrs					 * head of the queue).
5953163953Srrs					 */
5954163953Srrs					if (hold_rlock == 0) {
5955163953Srrs						SCTP_INP_READ_LOCK(inp);
5956163953Srrs						hold_rlock = 1;
5957163953Srrs					}
5958163953Srrs				}
5959163953Srrs				TAILQ_REMOVE(&inp->read_queue, control, next);
5960163953Srrs				/* Add back any hiddend data */
5961163953Srrs				if (control->held_length) {
5962163953Srrs					held_length = 0;
5963163953Srrs					control->held_length = 0;
5964163953Srrs					wakeup_read_socket = 1;
5965163953Srrs				}
5966169352Srrs				if (control->aux_data) {
5967169352Srrs					sctp_m_free(control->aux_data);
5968169352Srrs					control->aux_data = NULL;
5969169352Srrs				}
5970163953Srrs				no_rcv_needed = control->do_not_ref_stcb;
5971163953Srrs				sctp_free_remote_addr(control->whoFrom);
5972163953Srrs				control->data = NULL;
5973163953Srrs				sctp_free_a_readq(stcb, control);
5974163953Srrs				control = NULL;
5975170138Srrs				if ((freed_so_far >= rwnd_req) &&
5976170138Srrs				    (no_rcv_needed == 0))
5977163953Srrs					sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req);
5978163953Srrs
5979163953Srrs			} else {
5980163953Srrs				/*
5981163953Srrs				 * The user did not read all of this
5982163953Srrs				 * message, turn off the returned MSG_EOR
5983163953Srrs				 * since we are leaving more behind on the
5984163953Srrs				 * control to read.
5985163953Srrs				 */
5986165220Srrs#ifdef INVARIANTS
5987170138Srrs				if (control->end_added &&
5988170138Srrs				    (control->data == NULL) &&
5989163953Srrs				    (control->tail_mbuf == NULL)) {
5990163953Srrs					panic("Gak, control->length is corrupt?");
5991163953Srrs				}
5992163953Srrs#endif
5993163953Srrs				no_rcv_needed = control->do_not_ref_stcb;
5994163953Srrs				out_flags &= ~MSG_EOR;
5995163953Srrs			}
5996163953Srrs		}
5997163953Srrs		if (out_flags & MSG_EOR) {
5998163953Srrs			goto release;
5999163953Srrs		}
6000163953Srrs		if ((uio->uio_resid == 0) ||
6001260426Stuexen		    ((in_eeor_mode) &&
6002260426Stuexen		    (copied_so_far >= (uint32_t) max(so->so_rcv.sb_lowat, 1)))) {
6003163953Srrs			goto release;
6004163953Srrs		}
6005163953Srrs		/*
6006163953Srrs		 * If I hit here the receiver wants more and this message is
6007163953Srrs		 * NOT done (pd-api). So two questions. Can we block? if not
6008163953Srrs		 * we are done. Did the user NOT set MSG_WAITALL?
6009163953Srrs		 */
6010163953Srrs		if (block_allowed == 0) {
6011163953Srrs			goto release;
6012163953Srrs		}
6013163953Srrs		/*
6014163953Srrs		 * We need to wait for more data a few things: - We don't
6015163953Srrs		 * sbunlock() so we don't get someone else reading. - We
6016163953Srrs		 * must be sure to account for the case where what is added
6017163953Srrs		 * is NOT to our control when we wakeup.
6018163953Srrs		 */
6019163953Srrs
6020163953Srrs		/*
6021163953Srrs		 * Do we need to tell the transport a rwnd update might be
6022163953Srrs		 * needed before we go to sleep?
6023163953Srrs		 */
6024163953Srrs		if (((stcb) && (in_flags & MSG_PEEK) == 0) &&
6025163953Srrs		    ((freed_so_far >= rwnd_req) &&
6026163953Srrs		    (control->do_not_ref_stcb == 0) &&
6027163953Srrs		    (no_rcv_needed == 0))) {
6028163953Srrs			sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req);
6029163953Srrs		}
6030163953Srrswait_some_more:
6031166023Srrs		if (so->so_rcv.sb_state & SBS_CANTRCVMORE) {
6032163953Srrs			goto release;
6033163953Srrs		}
6034163953Srrs		if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)
6035163953Srrs			goto release;
6036163953Srrs
6037163953Srrs		if (hold_rlock == 1) {
6038163953Srrs			SCTP_INP_READ_UNLOCK(inp);
6039163953Srrs			hold_rlock = 0;
6040163953Srrs		}
6041163953Srrs		if (hold_sblock == 0) {
6042163953Srrs			SOCKBUF_LOCK(&so->so_rcv);
6043163953Srrs			hold_sblock = 1;
6044163953Srrs		}
6045172091Srrs		if ((copied_so_far) && (control->length == 0) &&
6046206137Stuexen		    (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE))) {
6047172091Srrs			goto release;
6048172091Srrs		}
6049163953Srrs		if (so->so_rcv.sb_cc <= control->held_length) {
6050163953Srrs			error = sbwait(&so->so_rcv);
6051163953Srrs			if (error) {
6052163953Srrs				goto release;
6053163953Srrs			}
6054163953Srrs			control->held_length = 0;
6055163953Srrs		}
6056163953Srrs		if (hold_sblock) {
6057163953Srrs			SOCKBUF_UNLOCK(&so->so_rcv);
6058163953Srrs			hold_sblock = 0;
6059163953Srrs		}
6060163953Srrs		if (control->length == 0) {
6061163953Srrs			/* still nothing here */
6062163953Srrs			if (control->end_added == 1) {
6063163953Srrs				/* he aborted, or is done i.e.did a shutdown */
6064163953Srrs				out_flags |= MSG_EOR;
6065168943Srrs				if (control->pdapi_aborted) {
6066169295Srrs					if ((control->do_not_ref_stcb == 0) && ((control->spec_flags & M_NOTIFICATION) == 0))
6067168961Srrs						control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0;
6068168943Srrs
6069164085Srrs					out_flags |= MSG_TRUNC;
6070168943Srrs				} else {
6071169295Srrs					if ((control->do_not_ref_stcb == 0) && ((control->spec_flags & M_NOTIFICATION) == 0))
6072168961Srrs						control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0;
6073168943Srrs				}
6074163953Srrs				goto done_with_control;
6075163953Srrs			}
6076163953Srrs			if (so->so_rcv.sb_cc > held_length) {
6077163953Srrs				control->held_length = so->so_rcv.sb_cc;
6078163953Srrs				held_length = 0;
6079163953Srrs			}
6080163953Srrs			goto wait_some_more;
6081163953Srrs		} else if (control->data == NULL) {
6082163996Srrs			/*
6083163996Srrs			 * we must re-sync since data is probably being
6084163996Srrs			 * added
6085163996Srrs			 */
6086163996Srrs			SCTP_INP_READ_LOCK(inp);
6087163996Srrs			if ((control->length > 0) && (control->data == NULL)) {
6088163996Srrs				/*
6089163996Srrs				 * big trouble.. we have the lock and its
6090163996Srrs				 * corrupt?
6091163996Srrs				 */
6092174323Srrs#ifdef INVARIANTS
6093163996Srrs				panic("Impossible data==NULL length !=0");
6094174323Srrs#endif
6095174323Srrs				out_flags |= MSG_EOR;
6096174323Srrs				out_flags |= MSG_TRUNC;
6097174323Srrs				control->length = 0;
6098174323Srrs				SCTP_INP_READ_UNLOCK(inp);
6099174323Srrs				goto done_with_control;
6100163996Srrs			}
6101163996Srrs			SCTP_INP_READ_UNLOCK(inp);
6102163996Srrs			/* We will fall around to get more data */
6103163953Srrs		}
6104163953Srrs		goto get_more_data;
6105163953Srrs	} else {
6106169352Srrs		/*-
6107169352Srrs		 * Give caller back the mbuf chain,
6108169352Srrs		 * store in uio_resid the length
6109163953Srrs		 */
6110169352Srrs		wakeup_read_socket = 0;
6111169352Srrs		if ((control->end_added == 0) ||
6112169352Srrs		    (TAILQ_NEXT(control, next) == NULL)) {
6113169352Srrs			/* Need to get rlock */
6114169352Srrs			if (hold_rlock == 0) {
6115169352Srrs				SCTP_INP_READ_LOCK(inp);
6116169352Srrs				hold_rlock = 1;
6117163953Srrs			}
6118169352Srrs		}
6119169352Srrs		if (control->end_added) {
6120169352Srrs			out_flags |= MSG_EOR;
6121228907Stuexen			if ((control->do_not_ref_stcb == 0) &&
6122228907Stuexen			    (control->stcb != NULL) &&
6123228907Stuexen			    ((control->spec_flags & M_NOTIFICATION) == 0))
6124169352Srrs				control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0;
6125169352Srrs		}
6126169352Srrs		if (control->spec_flags & M_NOTIFICATION) {
6127169352Srrs			out_flags |= MSG_NOTIFICATION;
6128169352Srrs		}
6129169352Srrs		uio->uio_resid = control->length;
6130169352Srrs		*mp = control->data;
6131169352Srrs		m = control->data;
6132169352Srrs		while (m) {
6133179783Srrs			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
6134170744Srrs				sctp_sblog(&so->so_rcv,
6135170744Srrs				    control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m));
6136170744Srrs			}
6137169352Srrs			sctp_sbfree(control, stcb, &so->so_rcv, m);
6138169352Srrs			freed_so_far += SCTP_BUF_LEN(m);
6139171943Srrs			freed_so_far += MSIZE;
6140179783Srrs			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
6141170744Srrs				sctp_sblog(&so->so_rcv,
6142170744Srrs				    control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0);
6143170744Srrs			}
6144169352Srrs			m = SCTP_BUF_NEXT(m);
6145163953Srrs		}
6146169352Srrs		control->data = control->tail_mbuf = NULL;
6147169352Srrs		control->length = 0;
6148169352Srrs		if (out_flags & MSG_EOR) {
6149169352Srrs			/* Done with this control */
6150169352Srrs			goto done_with_control;
6151169352Srrs		}
6152163953Srrs	}
6153163953Srrsrelease:
6154163953Srrs	if (hold_rlock == 1) {
6155163953Srrs		SCTP_INP_READ_UNLOCK(inp);
6156163953Srrs		hold_rlock = 0;
6157163953Srrs	}
6158169236Srwatson	if (hold_sblock == 1) {
6159169236Srwatson		SOCKBUF_UNLOCK(&so->so_rcv);
6160169236Srwatson		hold_sblock = 0;
6161163953Srrs	}
6162163953Srrs	sbunlock(&so->so_rcv);
6163169236Srwatson	sockbuf_lock = 0;
6164163953Srrs
6165163953Srrsrelease_unlocked:
6166163953Srrs	if (hold_sblock) {
6167163953Srrs		SOCKBUF_UNLOCK(&so->so_rcv);
6168163953Srrs		hold_sblock = 0;
6169163953Srrs	}
6170163953Srrs	if ((stcb) && (in_flags & MSG_PEEK) == 0) {
6171163953Srrs		if ((freed_so_far >= rwnd_req) &&
6172163953Srrs		    (control && (control->do_not_ref_stcb == 0)) &&
6173163953Srrs		    (no_rcv_needed == 0))
6174163953Srrs			sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req);
6175163953Srrs	}
6176184031Srrsout:
6177184031Srrs	if (msg_flags) {
6178174323Srrs		*msg_flags = out_flags;
6179184031Srrs	}
6180168943Srrs	if (((out_flags & MSG_EOR) == 0) &&
6181168943Srrs	    ((in_flags & MSG_PEEK) == 0) &&
6182168943Srrs	    (sinfo) &&
6183223132Stuexen	    (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO) ||
6184223132Stuexen	    sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO))) {
6185168943Srrs		struct sctp_extrcvinfo *s_extra;
6186168943Srrs
6187168943Srrs		s_extra = (struct sctp_extrcvinfo *)sinfo;
6188294178Stuexen		s_extra->serinfo_next_flags = SCTP_NO_NEXT_MSG;
6189168943Srrs	}
6190163953Srrs	if (hold_rlock == 1) {
6191163953Srrs		SCTP_INP_READ_UNLOCK(inp);
6192163953Srrs	}
6193163953Srrs	if (hold_sblock) {
6194163953Srrs		SOCKBUF_UNLOCK(&so->so_rcv);
6195163953Srrs	}
6196169236Srwatson	if (sockbuf_lock) {
6197169236Srwatson		sbunlock(&so->so_rcv);
6198169236Srwatson	}
6199163996Srrs	if (freecnt_applied) {
6200163953Srrs		/*
6201163953Srrs		 * The lock on the socket buffer protects us so the free
6202163953Srrs		 * code will stop. But since we used the socketbuf lock and
6203163953Srrs		 * the sender uses the tcb_lock to increment, we need to use
6204163953Srrs		 * the atomic add to the refcnt.
6205163953Srrs		 */
6206163996Srrs		if (stcb == NULL) {
6207182367Srrs#ifdef INVARIANTS
6208163996Srrs			panic("stcb for refcnt has gone NULL?");
6209182367Srrs			goto stage_left;
6210182367Srrs#else
6211182367Srrs			goto stage_left;
6212182367Srrs#endif
6213163996Srrs		}
6214163996Srrs		atomic_add_int(&stcb->asoc.refcnt, -1);
6215163953Srrs		/* Save the value back for next time */
6216163953Srrs		stcb->freed_by_sorcv_sincelast = freed_so_far;
6217163953Srrs	}
6218179783Srrs	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RECV_RWND_LOGGING_ENABLE) {
6219170744Srrs		if (stcb) {
6220170744Srrs			sctp_misc_ints(SCTP_SORECV_DONE,
6221170744Srrs			    freed_so_far,
6222170744Srrs			    ((uio) ? (slen - uio->uio_resid) : slen),
6223170744Srrs			    stcb->asoc.my_rwnd,
6224170744Srrs			    so->so_rcv.sb_cc);
6225170744Srrs		} else {
6226170744Srrs			sctp_misc_ints(SCTP_SORECV_DONE,
6227170744Srrs			    freed_so_far,
6228170744Srrs			    ((uio) ? (slen - uio->uio_resid) : slen),
6229170744Srrs			    0,
6230170744Srrs			    so->so_rcv.sb_cc);
6231170744Srrs		}
6232163953Srrs	}
6233182367Srrsstage_left:
6234163953Srrs	if (wakeup_read_socket) {
6235163953Srrs		sctp_sorwakeup(inp, so);
6236163953Srrs	}
6237163953Srrs	return (error);
6238163953Srrs}
6239163953Srrs
6240163953Srrs
6241163953Srrs#ifdef SCTP_MBUF_LOGGING
6242163953Srrsstruct mbuf *
6243163953Srrssctp_m_free(struct mbuf *m)
6244163953Srrs{
6245179783Srrs	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
6246283708Stuexen		sctp_log_mb(m, SCTP_MBUF_IFREE);
6247163953Srrs	}
6248163953Srrs	return (m_free(m));
6249163953Srrs}
6250163953Srrs
6251163953Srrsvoid
6252163953Srrssctp_m_freem(struct mbuf *mb)
6253163953Srrs{
6254163953Srrs	while (mb != NULL)
6255163953Srrs		mb = sctp_m_free(mb);
6256163953Srrs}
6257163953Srrs
6258163953Srrs#endif
6259163953Srrs
6260167598Srrsint
6261167598Srrssctp_dynamic_set_primary(struct sockaddr *sa, uint32_t vrf_id)
6262167598Srrs{
6263167598Srrs	/*
6264167598Srrs	 * Given a local address. For all associations that holds the
6265167598Srrs	 * address, request a peer-set-primary.
6266167598Srrs	 */
6267167598Srrs	struct sctp_ifa *ifa;
6268167598Srrs	struct sctp_laddr *wi;
6269163953Srrs
6270167598Srrs	ifa = sctp_find_ifa_by_addr(sa, vrf_id, 0);
6271167598Srrs	if (ifa == NULL) {
6272171943Srrs		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EADDRNOTAVAIL);
6273167598Srrs		return (EADDRNOTAVAIL);
6274167598Srrs	}
6275167598Srrs	/*
6276167598Srrs	 * Now that we have the ifa we must awaken the iterator with this
6277167598Srrs	 * message.
6278167598Srrs	 */
6279179783Srrs	wi = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_laddr), struct sctp_laddr);
6280167598Srrs	if (wi == NULL) {
6281171943Srrs		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOMEM);
6282167598Srrs		return (ENOMEM);
6283167598Srrs	}
6284167598Srrs	/* Now incr the count and int wi structure */
6285167598Srrs	SCTP_INCR_LADDR_COUNT();
6286167598Srrs	bzero(wi, sizeof(*wi));
6287170056Srrs	(void)SCTP_GETTIME_TIMEVAL(&wi->start_time);
6288167598Srrs	wi->ifa = ifa;
6289167598Srrs	wi->action = SCTP_SET_PRIM_ADDR;
6290167598Srrs	atomic_add_int(&ifa->refcount, 1);
6291167598Srrs
6292167598Srrs	/* Now add it to the work queue */
6293208160Srrs	SCTP_WQ_ADDR_LOCK();
6294167598Srrs	/*
6295167598Srrs	 * Should this really be a tailq? As it is we will process the
6296167598Srrs	 * newest first :-0
6297167598Srrs	 */
6298179783Srrs	LIST_INSERT_HEAD(&SCTP_BASE_INFO(addr_wq), wi, sctp_nxt_addr);
6299208160Srrs	SCTP_WQ_ADDR_UNLOCK();
6300167598Srrs	sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ,
6301167598Srrs	    (struct sctp_inpcb *)NULL,
6302167598Srrs	    (struct sctp_tcb *)NULL,
6303167598Srrs	    (struct sctp_nets *)NULL);
6304167598Srrs	return (0);
6305167598Srrs}
6306167598Srrs
6307167598Srrs
6308163953Srrsint
6309169352Srrssctp_soreceive(struct socket *so,
6310169352Srrs    struct sockaddr **psa,
6311169352Srrs    struct uio *uio,
6312169352Srrs    struct mbuf **mp0,
6313169352Srrs    struct mbuf **controlp,
6314169352Srrs    int *flagsp)
6315163953Srrs{
6316163953Srrs	int error, fromlen;
6317163953Srrs	uint8_t sockbuf[256];
6318163953Srrs	struct sockaddr *from;
6319163953Srrs	struct sctp_extrcvinfo sinfo;
6320163953Srrs	int filling_sinfo = 1;
6321163953Srrs	struct sctp_inpcb *inp;
6322163953Srrs
6323163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
6324163953Srrs	/* pickup the assoc we are reading from */
6325163953Srrs	if (inp == NULL) {
6326171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6327163953Srrs		return (EINVAL);
6328163953Srrs	}
6329223132Stuexen	if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT) &&
6330223132Stuexen	    sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVRCVINFO) &&
6331223132Stuexen	    sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVNXTINFO)) ||
6332163953Srrs	    (controlp == NULL)) {
6333163953Srrs		/* user does not want the sndrcv ctl */
6334163953Srrs		filling_sinfo = 0;
6335163953Srrs	}
6336163953Srrs	if (psa) {
6337163953Srrs		from = (struct sockaddr *)sockbuf;
6338163953Srrs		fromlen = sizeof(sockbuf);
6339163953Srrs		from->sa_len = 0;
6340163953Srrs	} else {
6341163953Srrs		from = NULL;
6342163953Srrs		fromlen = 0;
6343163953Srrs	}
6344163953Srrs
6345268432Sdelphij	if (filling_sinfo) {
6346268432Sdelphij		memset(&sinfo, 0, sizeof(struct sctp_extrcvinfo));
6347268432Sdelphij	}
6348163953Srrs	error = sctp_sorecvmsg(so, uio, mp0, from, fromlen, flagsp,
6349163953Srrs	    (struct sctp_sndrcvinfo *)&sinfo, filling_sinfo);
6350268432Sdelphij	if (controlp != NULL) {
6351163953Srrs		/* copy back the sinfo in a CMSG format */
6352163953Srrs		if (filling_sinfo)
6353163953Srrs			*controlp = sctp_build_ctl_nchunk(inp,
6354163953Srrs			    (struct sctp_sndrcvinfo *)&sinfo);
6355163953Srrs		else
6356163953Srrs			*controlp = NULL;
6357163953Srrs	}
6358163953Srrs	if (psa) {
6359163953Srrs		/* copy back the address info */
6360163953Srrs		if (from && from->sa_len) {
6361163953Srrs			*psa = sodupsockaddr(from, M_NOWAIT);
6362163953Srrs		} else {
6363163953Srrs			*psa = NULL;
6364163953Srrs		}
6365163953Srrs	}
6366163953Srrs	return (error);
6367163953Srrs}
6368169352Srrs
6369169352Srrs
6370169352Srrs
6371169352Srrs
6372169352Srrs
6373169352Srrsint
6374170056Srrssctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr,
6375170056Srrs    int totaddr, int *error)
6376169352Srrs{
6377169352Srrs	int added = 0;
6378169352Srrs	int i;
6379169352Srrs	struct sctp_inpcb *inp;
6380169352Srrs	struct sockaddr *sa;
6381169352Srrs	size_t incr = 0;
6382169352Srrs
6383225571Stuexen#ifdef INET
6384225571Stuexen	struct sockaddr_in *sin;
6385225571Stuexen
6386225571Stuexen#endif
6387225571Stuexen#ifdef INET6
6388225571Stuexen	struct sockaddr_in6 *sin6;
6389225571Stuexen
6390225571Stuexen#endif
6391225571Stuexen
6392169352Srrs	sa = addr;
6393169352Srrs	inp = stcb->sctp_ep;
6394169352Srrs	*error = 0;
6395169352Srrs	for (i = 0; i < totaddr; i++) {
6396221328Stuexen		switch (sa->sa_family) {
6397221328Stuexen#ifdef INET
6398221328Stuexen		case AF_INET:
6399169352Srrs			incr = sizeof(struct sockaddr_in);
6400225571Stuexen			sin = (struct sockaddr_in *)sa;
6401225571Stuexen			if ((sin->sin_addr.s_addr == INADDR_ANY) ||
6402225571Stuexen			    (sin->sin_addr.s_addr == INADDR_BROADCAST) ||
6403225571Stuexen			    IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
6404225571Stuexen				SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6405283823Stuexen				(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
6406283823Stuexen				    SCTP_FROM_SCTPUTIL + SCTP_LOC_7);
6407225571Stuexen				*error = EINVAL;
6408225571Stuexen				goto out_now;
6409225571Stuexen			}
6410224641Stuexen			if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
6411169352Srrs				/* assoc gone no un-lock */
6412171943Srrs				SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS);
6413283823Stuexen				(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
6414283823Stuexen				    SCTP_FROM_SCTPUTIL + SCTP_LOC_8);
6415169352Srrs				*error = ENOBUFS;
6416169352Srrs				goto out_now;
6417169352Srrs			}
6418169352Srrs			added++;
6419221328Stuexen			break;
6420221328Stuexen#endif
6421221328Stuexen#ifdef INET6
6422221328Stuexen		case AF_INET6:
6423169352Srrs			incr = sizeof(struct sockaddr_in6);
6424225571Stuexen			sin6 = (struct sockaddr_in6 *)sa;
6425225571Stuexen			if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) ||
6426225571Stuexen			    IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
6427225571Stuexen				SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6428283823Stuexen				(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
6429283823Stuexen				    SCTP_FROM_SCTPUTIL + SCTP_LOC_9);
6430225571Stuexen				*error = EINVAL;
6431225571Stuexen				goto out_now;
6432225571Stuexen			}
6433224641Stuexen			if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
6434169352Srrs				/* assoc gone no un-lock */
6435171943Srrs				SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS);
6436283823Stuexen				(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
6437283823Stuexen				    SCTP_FROM_SCTPUTIL + SCTP_LOC_10);
6438169352Srrs				*error = ENOBUFS;
6439169352Srrs				goto out_now;
6440169352Srrs			}
6441169352Srrs			added++;
6442221328Stuexen			break;
6443221328Stuexen#endif
6444221328Stuexen		default:
6445221328Stuexen			break;
6446169352Srrs		}
6447169352Srrs		sa = (struct sockaddr *)((caddr_t)sa + incr);
6448169352Srrs	}
6449169352Srrsout_now:
6450169352Srrs	return (added);
6451169352Srrs}
6452169352Srrs
6453169352Srrsstruct sctp_tcb *
6454170056Srrssctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr,
6455170056Srrs    int *totaddr, int *num_v4, int *num_v6, int *error,
6456170056Srrs    int limit, int *bad_addr)
6457169352Srrs{
6458169352Srrs	struct sockaddr *sa;
6459169352Srrs	struct sctp_tcb *stcb = NULL;
6460169352Srrs	size_t incr, at, i;
6461169352Srrs
6462169352Srrs	at = incr = 0;
6463169352Srrs	sa = addr;
6464221328Stuexen
6465169352Srrs	*error = *num_v6 = *num_v4 = 0;
6466169352Srrs	/* account and validate addresses */
6467170140Srrs	for (i = 0; i < (size_t)*totaddr; i++) {
6468221328Stuexen		switch (sa->sa_family) {
6469221328Stuexen#ifdef INET
6470221328Stuexen		case AF_INET:
6471169352Srrs			(*num_v4) += 1;
6472169352Srrs			incr = sizeof(struct sockaddr_in);
6473170056Srrs			if (sa->sa_len != incr) {
6474171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6475170056Srrs				*error = EINVAL;
6476170056Srrs				*bad_addr = 1;
6477170056Srrs				return (NULL);
6478170056Srrs			}
6479221328Stuexen			break;
6480221328Stuexen#endif
6481221328Stuexen#ifdef INET6
6482221328Stuexen		case AF_INET6:
6483221328Stuexen			{
6484221328Stuexen				struct sockaddr_in6 *sin6;
6485169352Srrs
6486221328Stuexen				sin6 = (struct sockaddr_in6 *)sa;
6487221328Stuexen				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
6488221328Stuexen					/* Must be non-mapped for connectx */
6489221328Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6490221328Stuexen					*error = EINVAL;
6491221328Stuexen					*bad_addr = 1;
6492221328Stuexen					return (NULL);
6493221328Stuexen				}
6494221328Stuexen				(*num_v6) += 1;
6495221328Stuexen				incr = sizeof(struct sockaddr_in6);
6496221328Stuexen				if (sa->sa_len != incr) {
6497221328Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6498221328Stuexen					*error = EINVAL;
6499221328Stuexen					*bad_addr = 1;
6500221328Stuexen					return (NULL);
6501221328Stuexen				}
6502221328Stuexen				break;
6503169352Srrs			}
6504221328Stuexen#endif
6505221328Stuexen		default:
6506169352Srrs			*totaddr = i;
6507169352Srrs			/* we are done */
6508169352Srrs			break;
6509169352Srrs		}
6510221328Stuexen		if (i == (size_t)*totaddr) {
6511221328Stuexen			break;
6512221328Stuexen		}
6513170056Srrs		SCTP_INP_INCR_REF(inp);
6514169352Srrs		stcb = sctp_findassociation_ep_addr(&inp, sa, NULL, NULL, NULL);
6515169352Srrs		if (stcb != NULL) {
6516169352Srrs			/* Already have or am bring up an association */
6517169352Srrs			return (stcb);
6518170056Srrs		} else {
6519170056Srrs			SCTP_INP_DECR_REF(inp);
6520169352Srrs		}
6521170140Srrs		if ((at + incr) > (size_t)limit) {
6522169352Srrs			*totaddr = i;
6523169352Srrs			break;
6524169352Srrs		}
6525169352Srrs		sa = (struct sockaddr *)((caddr_t)sa + incr);
6526169352Srrs	}
6527169352Srrs	return ((struct sctp_tcb *)NULL);
6528169352Srrs}
6529170606Srrs
6530170606Srrs/*
6531170606Srrs * sctp_bindx(ADD) for one address.
6532170606Srrs * assumes all arguments are valid/checked by caller.
6533170606Srrs */
6534170606Srrsvoid
6535170606Srrssctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp,
6536170606Srrs    struct sockaddr *sa, sctp_assoc_t assoc_id,
6537170606Srrs    uint32_t vrf_id, int *error, void *p)
6538170606Srrs{
6539170606Srrs	struct sockaddr *addr_touse;
6540178251Srrs
6541283699Stuexen#if defined(INET) && defined(INET6)
6542170606Srrs	struct sockaddr_in sin;
6543170606Srrs
6544178251Srrs#endif
6545178251Srrs
6546170606Srrs	/* see if we're bound all already! */
6547170606Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
6548171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6549170606Srrs		*error = EINVAL;
6550170606Srrs		return;
6551170606Srrs	}
6552170606Srrs	addr_touse = sa;
6553221328Stuexen#ifdef INET6
6554170606Srrs	if (sa->sa_family == AF_INET6) {
6555283699Stuexen#ifdef INET
6556170606Srrs		struct sockaddr_in6 *sin6;
6557170606Srrs
6558283699Stuexen#endif
6559170606Srrs		if (sa->sa_len != sizeof(struct sockaddr_in6)) {
6560171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6561170606Srrs			*error = EINVAL;
6562170606Srrs			return;
6563170606Srrs		}
6564170665Srrs		if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
6565170665Srrs			/* can only bind v6 on PF_INET6 sockets */
6566171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6567170665Srrs			*error = EINVAL;
6568170665Srrs			return;
6569170665Srrs		}
6570283699Stuexen#ifdef INET
6571170606Srrs		sin6 = (struct sockaddr_in6 *)addr_touse;
6572170606Srrs		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
6573170665Srrs			if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
6574170665Srrs			    SCTP_IPV6_V6ONLY(inp)) {
6575170665Srrs				/* can't bind v4-mapped on PF_INET sockets */
6576171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6577170665Srrs				*error = EINVAL;
6578170665Srrs				return;
6579170665Srrs			}
6580170606Srrs			in6_sin6_2_sin(&sin, sin6);
6581170606Srrs			addr_touse = (struct sockaddr *)&sin;
6582170606Srrs		}
6583283699Stuexen#endif
6584170606Srrs	}
6585170606Srrs#endif
6586221328Stuexen#ifdef INET
6587170606Srrs	if (sa->sa_family == AF_INET) {
6588170606Srrs		if (sa->sa_len != sizeof(struct sockaddr_in)) {
6589171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6590170606Srrs			*error = EINVAL;
6591170606Srrs			return;
6592170606Srrs		}
6593170665Srrs		if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
6594170665Srrs		    SCTP_IPV6_V6ONLY(inp)) {
6595170665Srrs			/* can't bind v4 on PF_INET sockets */
6596171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6597170665Srrs			*error = EINVAL;
6598170665Srrs			return;
6599170665Srrs		}
6600170606Srrs	}
6601221328Stuexen#endif
6602170606Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) {
6603170606Srrs		if (p == NULL) {
6604170606Srrs			/* Can't get proc for Net/Open BSD */
6605171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6606170606Srrs			*error = EINVAL;
6607170606Srrs			return;
6608170606Srrs		}
6609171572Srrs		*error = sctp_inpcb_bind(so, addr_touse, NULL, p);
6610170606Srrs		return;
6611170606Srrs	}
6612170606Srrs	/*
6613170606Srrs	 * No locks required here since bind and mgmt_ep_sa all do their own
6614170606Srrs	 * locking. If we do something for the FIX: below we may need to
6615170606Srrs	 * lock in that case.
6616170606Srrs	 */
6617170606Srrs	if (assoc_id == 0) {
6618170606Srrs		/* add the address */
6619170606Srrs		struct sctp_inpcb *lep;
6620171032Srrs		struct sockaddr_in *lsin = (struct sockaddr_in *)addr_touse;
6621170606Srrs
6622171032Srrs		/* validate the incoming port */
6623171032Srrs		if ((lsin->sin_port != 0) &&
6624171032Srrs		    (lsin->sin_port != inp->sctp_lport)) {
6625171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6626171032Srrs			*error = EINVAL;
6627171032Srrs			return;
6628171032Srrs		} else {
6629171032Srrs			/* user specified 0 port, set it to existing port */
6630171032Srrs			lsin->sin_port = inp->sctp_lport;
6631171032Srrs		}
6632171032Srrs
6633170606Srrs		lep = sctp_pcb_findep(addr_touse, 1, 0, vrf_id);
6634170606Srrs		if (lep != NULL) {
6635170606Srrs			/*
6636170606Srrs			 * We must decrement the refcount since we have the
6637170606Srrs			 * ep already and are binding. No remove going on
6638170606Srrs			 * here.
6639170606Srrs			 */
6640181054Srrs			SCTP_INP_DECR_REF(lep);
6641170606Srrs		}
6642170606Srrs		if (lep == inp) {
6643170606Srrs			/* already bound to it.. ok */
6644170606Srrs			return;
6645170606Srrs		} else if (lep == NULL) {
6646170606Srrs			((struct sockaddr_in *)addr_touse)->sin_port = 0;
6647170606Srrs			*error = sctp_addr_mgmt_ep_sa(inp, addr_touse,
6648170606Srrs			    SCTP_ADD_IP_ADDRESS,
6649170744Srrs			    vrf_id, NULL);
6650170606Srrs		} else {
6651170606Srrs			*error = EADDRINUSE;
6652170606Srrs		}
6653170606Srrs		if (*error)
6654170606Srrs			return;
6655170606Srrs	} else {
6656170606Srrs		/*
6657170606Srrs		 * FIX: decide whether we allow assoc based bindx
6658170606Srrs		 */
6659170606Srrs	}
6660170606Srrs}
6661170606Srrs
6662170606Srrs/*
6663170606Srrs * sctp_bindx(DELETE) for one address.
6664170606Srrs * assumes all arguments are valid/checked by caller.
6665170606Srrs */
6666170606Srrsvoid
6667228653Stuexensctp_bindx_delete_address(struct sctp_inpcb *inp,
6668170606Srrs    struct sockaddr *sa, sctp_assoc_t assoc_id,
6669170606Srrs    uint32_t vrf_id, int *error)
6670170606Srrs{
6671170606Srrs	struct sockaddr *addr_touse;
6672178251Srrs
6673283699Stuexen#if defined(INET) && defined(INET6)
6674170606Srrs	struct sockaddr_in sin;
6675170606Srrs
6676178251Srrs#endif
6677178251Srrs
6678170606Srrs	/* see if we're bound all already! */
6679170606Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
6680171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6681170606Srrs		*error = EINVAL;
6682170606Srrs		return;
6683170606Srrs	}
6684170606Srrs	addr_touse = sa;
6685238475Stuexen#ifdef INET6
6686170606Srrs	if (sa->sa_family == AF_INET6) {
6687283699Stuexen#ifdef INET
6688170606Srrs		struct sockaddr_in6 *sin6;
6689170606Srrs
6690283699Stuexen#endif
6691283699Stuexen
6692170606Srrs		if (sa->sa_len != sizeof(struct sockaddr_in6)) {
6693171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6694170606Srrs			*error = EINVAL;
6695170606Srrs			return;
6696170606Srrs		}
6697170665Srrs		if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
6698170665Srrs			/* can only bind v6 on PF_INET6 sockets */
6699171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6700170665Srrs			*error = EINVAL;
6701170665Srrs			return;
6702170665Srrs		}
6703283699Stuexen#ifdef INET
6704170606Srrs		sin6 = (struct sockaddr_in6 *)addr_touse;
6705170606Srrs		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
6706170665Srrs			if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
6707170665Srrs			    SCTP_IPV6_V6ONLY(inp)) {
6708170665Srrs				/* can't bind mapped-v4 on PF_INET sockets */
6709171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6710170665Srrs				*error = EINVAL;
6711170665Srrs				return;
6712170665Srrs			}
6713170606Srrs			in6_sin6_2_sin(&sin, sin6);
6714170606Srrs			addr_touse = (struct sockaddr *)&sin;
6715170606Srrs		}
6716283699Stuexen#endif
6717170606Srrs	}
6718170606Srrs#endif
6719221328Stuexen#ifdef INET
6720170606Srrs	if (sa->sa_family == AF_INET) {
6721170606Srrs		if (sa->sa_len != sizeof(struct sockaddr_in)) {
6722171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6723170606Srrs			*error = EINVAL;
6724170606Srrs			return;
6725170606Srrs		}
6726170665Srrs		if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
6727170665Srrs		    SCTP_IPV6_V6ONLY(inp)) {
6728170665Srrs			/* can't bind v4 on PF_INET sockets */
6729171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
6730170665Srrs			*error = EINVAL;
6731170665Srrs			return;
6732170665Srrs		}
6733170606Srrs	}
6734221328Stuexen#endif
6735170606Srrs	/*
6736170606Srrs	 * No lock required mgmt_ep_sa does its own locking. If the FIX:
6737170606Srrs	 * below is ever changed we may need to lock before calling
6738170606Srrs	 * association level binding.
6739170606Srrs	 */
6740170606Srrs	if (assoc_id == 0) {
6741170606Srrs		/* delete the address */
6742170606Srrs		*error = sctp_addr_mgmt_ep_sa(inp, addr_touse,
6743170606Srrs		    SCTP_DEL_IP_ADDRESS,
6744170744Srrs		    vrf_id, NULL);
6745170606Srrs	} else {
6746170606Srrs		/*
6747170606Srrs		 * FIX: decide whether we allow assoc based bindx
6748170606Srrs		 */
6749170606Srrs	}
6750170606Srrs}
6751171572Srrs
6752171572Srrs/*
6753171572Srrs * returns the valid local address count for an assoc, taking into account
6754171572Srrs * all scoping rules
6755171572Srrs */
6756171572Srrsint
6757171572Srrssctp_local_addr_count(struct sctp_tcb *stcb)
6758171572Srrs{
6759258454Stuexen	int loopback_scope;
6760258454Stuexen
6761258454Stuexen#if defined(INET)
6762258454Stuexen	int ipv4_local_scope, ipv4_addr_legal;
6763258454Stuexen
6764258454Stuexen#endif
6765258454Stuexen#if defined (INET6)
6766258454Stuexen	int local_scope, site_scope, ipv6_addr_legal;
6767258454Stuexen
6768258454Stuexen#endif
6769171572Srrs	struct sctp_vrf *vrf;
6770171572Srrs	struct sctp_ifn *sctp_ifn;
6771171572Srrs	struct sctp_ifa *sctp_ifa;
6772171572Srrs	int count = 0;
6773171572Srrs
6774171572Srrs	/* Turn on all the appropriate scopes */
6775246595Stuexen	loopback_scope = stcb->asoc.scope.loopback_scope;
6776258454Stuexen#if defined(INET)
6777246595Stuexen	ipv4_local_scope = stcb->asoc.scope.ipv4_local_scope;
6778258454Stuexen	ipv4_addr_legal = stcb->asoc.scope.ipv4_addr_legal;
6779258454Stuexen#endif
6780258454Stuexen#if defined(INET6)
6781246595Stuexen	local_scope = stcb->asoc.scope.local_scope;
6782246595Stuexen	site_scope = stcb->asoc.scope.site_scope;
6783246595Stuexen	ipv6_addr_legal = stcb->asoc.scope.ipv6_addr_legal;
6784258454Stuexen#endif
6785172218Srrs	SCTP_IPI_ADDR_RLOCK();
6786171572Srrs	vrf = sctp_find_vrf(stcb->asoc.vrf_id);
6787171572Srrs	if (vrf == NULL) {
6788171572Srrs		/* no vrf, no addresses */
6789172218Srrs		SCTP_IPI_ADDR_RUNLOCK();
6790171572Srrs		return (0);
6791171572Srrs	}
6792171572Srrs	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
6793171572Srrs		/*
6794171572Srrs		 * bound all case: go through all ifns on the vrf
6795171572Srrs		 */
6796171572Srrs		LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
6797171572Srrs			if ((loopback_scope == 0) &&
6798171572Srrs			    SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
6799171572Srrs				continue;
6800171572Srrs			}
6801171572Srrs			LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
6802171572Srrs				if (sctp_is_addr_restricted(stcb, sctp_ifa))
6803171572Srrs					continue;
6804178251Srrs				switch (sctp_ifa->address.sa.sa_family) {
6805221328Stuexen#ifdef INET
6806178251Srrs				case AF_INET:
6807178251Srrs					if (ipv4_addr_legal) {
6808178251Srrs						struct sockaddr_in *sin;
6809171572Srrs
6810271746Stuexen						sin = &sctp_ifa->address.sin;
6811178251Srrs						if (sin->sin_addr.s_addr == 0) {
6812178251Srrs							/*
6813178251Srrs							 * skip unspecified
6814178251Srrs							 * addrs
6815178251Srrs							 */
6816178251Srrs							continue;
6817178251Srrs						}
6818267769Stuexen						if (prison_check_ip4(stcb->sctp_ep->ip_inp.inp.inp_cred,
6819267769Stuexen						    &sin->sin_addr) != 0) {
6820267769Stuexen							continue;
6821267769Stuexen						}
6822178251Srrs						if ((ipv4_local_scope == 0) &&
6823178251Srrs						    (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) {
6824178251Srrs							continue;
6825178251Srrs						}
6826178251Srrs						/* count this one */
6827178251Srrs						count++;
6828178251Srrs					} else {
6829171572Srrs						continue;
6830171572Srrs					}
6831178251Srrs					break;
6832221328Stuexen#endif
6833178251Srrs#ifdef INET6
6834178251Srrs				case AF_INET6:
6835178251Srrs					if (ipv6_addr_legal) {
6836178251Srrs						struct sockaddr_in6 *sin6;
6837171572Srrs
6838271746Stuexen						sin6 = &sctp_ifa->address.sin6;
6839178251Srrs						if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
6840171572Srrs							continue;
6841178251Srrs						}
6842267769Stuexen						if (prison_check_ip6(stcb->sctp_ep->ip_inp.inp.inp_cred,
6843267769Stuexen						    &sin6->sin6_addr) != 0) {
6844267769Stuexen							continue;
6845267769Stuexen						}
6846178251Srrs						if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
6847178251Srrs							if (local_scope == 0)
6848171572Srrs								continue;
6849178251Srrs							if (sin6->sin6_scope_id == 0) {
6850178251Srrs								if (sa6_recoverscope(sin6) != 0)
6851178251Srrs									/*
6852178251Srrs									 *
6853178251Srrs									 * bad
6854178251Srrs									 *
6855178251Srrs									 * li
6856178251Srrs									 * nk
6857178251Srrs									 *
6858178251Srrs									 * loc
6859178251Srrs									 * al
6860178251Srrs									 *
6861178251Srrs									 * add
6862178251Srrs									 * re
6863178251Srrs									 * ss
6864178251Srrs									 * */
6865178251Srrs									continue;
6866178251Srrs							}
6867171572Srrs						}
6868178251Srrs						if ((site_scope == 0) &&
6869178251Srrs						    (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) {
6870178251Srrs							continue;
6871178251Srrs						}
6872178251Srrs						/* count this one */
6873178251Srrs						count++;
6874171572Srrs					}
6875178251Srrs					break;
6876178251Srrs#endif
6877178251Srrs				default:
6878178251Srrs					/* TSNH */
6879178251Srrs					break;
6880171572Srrs				}
6881171572Srrs			}
6882171572Srrs		}
6883171572Srrs	} else {
6884171572Srrs		/*
6885171572Srrs		 * subset bound case
6886171572Srrs		 */
6887171572Srrs		struct sctp_laddr *laddr;
6888171572Srrs
6889171572Srrs		LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list,
6890171572Srrs		    sctp_nxt_addr) {
6891171572Srrs			if (sctp_is_addr_restricted(stcb, laddr->ifa)) {
6892171572Srrs				continue;
6893171572Srrs			}
6894171572Srrs			/* count this one */
6895171572Srrs			count++;
6896171572Srrs		}
6897171572Srrs	}
6898172218Srrs	SCTP_IPI_ADDR_RUNLOCK();
6899171572Srrs	return (count);
6900171572Srrs}
6901171943Srrs
6902171943Srrs#if defined(SCTP_LOCAL_TRACE_BUF)
6903171943Srrs
6904171943Srrsvoid
6905172157Srrssctp_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)
6906171943Srrs{
6907172157Srrs	uint32_t saveindex, newindex;
6908171943Srrs
6909171943Srrs	do {
6910179783Srrs		saveindex = SCTP_BASE_SYSCTL(sctp_log).index;
6911171943Srrs		if (saveindex >= SCTP_MAX_LOGGING_SIZE) {
6912171943Srrs			newindex = 1;
6913171943Srrs		} else {
6914171943Srrs			newindex = saveindex + 1;
6915171943Srrs		}
6916179783Srrs	} while (atomic_cmpset_int(&SCTP_BASE_SYSCTL(sctp_log).index, saveindex, newindex) == 0);
6917171943Srrs	if (saveindex >= SCTP_MAX_LOGGING_SIZE) {
6918171943Srrs		saveindex = 0;
6919171943Srrs	}
6920179783Srrs	SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].timestamp = SCTP_GET_CYCLECOUNT;
6921179783Srrs	SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].subsys = subsys;
6922179783Srrs	SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[0] = a;
6923179783Srrs	SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[1] = b;
6924179783Srrs	SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[2] = c;
6925179783Srrs	SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[3] = d;
6926179783Srrs	SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[4] = e;
6927179783Srrs	SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[5] = f;
6928171943Srrs}
6929171943Srrs
6930171943Srrs#endif
6931188067Srrsstatic void
6932294140Stuexensctp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *inp,
6933277789Sbryanv    const struct sockaddr *sa SCTP_UNUSED, void *ctx SCTP_UNUSED)
6934188067Srrs{
6935188067Srrs	struct ip *iph;
6936243186Stuexen
6937243186Stuexen#ifdef INET6
6938243186Stuexen	struct ip6_hdr *ip6;
6939243186Stuexen
6940243186Stuexen#endif
6941188067Srrs	struct mbuf *sp, *last;
6942188067Srrs	struct udphdr *uhdr;
6943237229Stuexen	uint16_t port;
6944188067Srrs
6945188067Srrs	if ((m->m_flags & M_PKTHDR) == 0) {
6946188067Srrs		/* Can't handle one that is not a pkt hdr */
6947188067Srrs		goto out;
6948188067Srrs	}
6949237229Stuexen	/* Pull the src port */
6950188067Srrs	iph = mtod(m, struct ip *);
6951188067Srrs	uhdr = (struct udphdr *)((caddr_t)iph + off);
6952188067Srrs	port = uhdr->uh_sport;
6953237229Stuexen	/*
6954237229Stuexen	 * Split out the mbuf chain. Leave the IP header in m, place the
6955237229Stuexen	 * rest in the sp.
6956237229Stuexen	 */
6957243882Sglebius	sp = m_split(m, off, M_NOWAIT);
6958188067Srrs	if (sp == NULL) {
6959188067Srrs		/* Gak, drop packet, we can't do a split */
6960188067Srrs		goto out;
6961188067Srrs	}
6962237229Stuexen	if (sp->m_pkthdr.len < sizeof(struct udphdr) + sizeof(struct sctphdr)) {
6963237229Stuexen		/* Gak, packet can't have an SCTP header in it - too small */
6964188067Srrs		m_freem(sp);
6965188067Srrs		goto out;
6966188067Srrs	}
6967237229Stuexen	/* Now pull up the UDP header and SCTP header together */
6968237229Stuexen	sp = m_pullup(sp, sizeof(struct udphdr) + sizeof(struct sctphdr));
6969188067Srrs	if (sp == NULL) {
6970188067Srrs		/* Gak pullup failed */
6971188067Srrs		goto out;
6972188067Srrs	}
6973237229Stuexen	/* Trim out the UDP header */
6974188067Srrs	m_adj(sp, sizeof(struct udphdr));
6975188067Srrs
6976188067Srrs	/* Now reconstruct the mbuf chain */
6977237229Stuexen	for (last = m; last->m_next; last = last->m_next);
6978188067Srrs	last->m_next = sp;
6979188067Srrs	m->m_pkthdr.len += sp->m_pkthdr.len;
6980294189Stuexen	/*
6981294189Stuexen	 * The CSUM_DATA_VALID flags indicates that the HW checked the UDP
6982294189Stuexen	 * checksum and it was valid. Since CSUM_DATA_VALID ==
6983294189Stuexen	 * CSUM_SCTP_VALID this would imply that the HW also verified the
6984294189Stuexen	 * SCTP checksum. Therefore, clear the bit.
6985294189Stuexen	 */
6986294189Stuexen	SCTPDBG(SCTP_DEBUG_CRCOFFLOAD,
6987294189Stuexen	    "sctp_recv_udp_tunneled_packet(): Packet of length %d received on %s with csum_flags 0x%b.\n",
6988294189Stuexen	    m->m_pkthdr.len,
6989294189Stuexen	    if_name(m->m_pkthdr.rcvif),
6990294189Stuexen	    (int)m->m_pkthdr.csum_flags, CSUM_BITS);
6991294189Stuexen	m->m_pkthdr.csum_flags &= ~CSUM_DATA_VALID;
6992188067Srrs	iph = mtod(m, struct ip *);
6993188067Srrs	switch (iph->ip_v) {
6994221249Stuexen#ifdef INET
6995188067Srrs	case IPVERSION:
6996242325Stuexen		iph->ip_len = htons(ntohs(iph->ip_len) - sizeof(struct udphdr));
6997237229Stuexen		sctp_input_with_port(m, off, port);
6998237229Stuexen		break;
6999221249Stuexen#endif
7000188067Srrs#ifdef INET6
7001188067Srrs	case IPV6_VERSION >> 4:
7002243186Stuexen		ip6 = mtod(m, struct ip6_hdr *);
7003243186Stuexen		ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - sizeof(struct udphdr));
7004243186Stuexen		sctp6_input_with_port(&m, &off, port);
7005237229Stuexen		break;
7006188067Srrs#endif
7007188067Srrs	default:
7008237229Stuexen		goto out;
7009237229Stuexen		break;
7010188067Srrs	}
7011188067Srrs	return;
7012188067Srrsout:
7013188067Srrs	m_freem(m);
7014188067Srrs}
7015188067Srrs
7016221328Stuexenvoid
7017179157Srrssctp_over_udp_stop(void)
7018179157Srrs{
7019188067Srrs	/*
7020188067Srrs	 * This function assumes sysctl caller holds sctp_sysctl_info_lock()
7021188067Srrs	 * for writting!
7022188067Srrs	 */
7023243186Stuexen#ifdef INET
7024243186Stuexen	if (SCTP_BASE_INFO(udp4_tun_socket) != NULL) {
7025243186Stuexen		soclose(SCTP_BASE_INFO(udp4_tun_socket));
7026243186Stuexen		SCTP_BASE_INFO(udp4_tun_socket) = NULL;
7027188067Srrs	}
7028243186Stuexen#endif
7029243186Stuexen#ifdef INET6
7030243186Stuexen	if (SCTP_BASE_INFO(udp6_tun_socket) != NULL) {
7031243186Stuexen		soclose(SCTP_BASE_INFO(udp6_tun_socket));
7032243186Stuexen		SCTP_BASE_INFO(udp6_tun_socket) = NULL;
7033243186Stuexen	}
7034243186Stuexen#endif
7035179157Srrs}
7036221328Stuexen
7037221328Stuexenint
7038179157Srrssctp_over_udp_start(void)
7039179157Srrs{
7040188067Srrs	uint16_t port;
7041188067Srrs	int ret;
7042243186Stuexen
7043243186Stuexen#ifdef INET
7044188067Srrs	struct sockaddr_in sin;
7045188067Srrs
7046243186Stuexen#endif
7047243186Stuexen#ifdef INET6
7048243186Stuexen	struct sockaddr_in6 sin6;
7049243186Stuexen
7050243186Stuexen#endif
7051188067Srrs	/*
7052188067Srrs	 * This function assumes sysctl caller holds sctp_sysctl_info_lock()
7053188067Srrs	 * for writting!
7054188067Srrs	 */
7055188067Srrs	port = SCTP_BASE_SYSCTL(sctp_udp_tunneling_port);
7056243186Stuexen	if (ntohs(port) == 0) {
7057188067Srrs		/* Must have a port set */
7058188067Srrs		return (EINVAL);
7059188067Srrs	}
7060243186Stuexen#ifdef INET
7061243186Stuexen	if (SCTP_BASE_INFO(udp4_tun_socket) != NULL) {
7062188067Srrs		/* Already running -- must stop first */
7063188067Srrs		return (EALREADY);
7064188067Srrs	}
7065243186Stuexen#endif
7066243186Stuexen#ifdef INET6
7067243186Stuexen	if (SCTP_BASE_INFO(udp6_tun_socket) != NULL) {
7068243186Stuexen		/* Already running -- must stop first */
7069243186Stuexen		return (EALREADY);
7070243186Stuexen	}
7071243186Stuexen#endif
7072243186Stuexen#ifdef INET
7073243186Stuexen	if ((ret = socreate(PF_INET, &SCTP_BASE_INFO(udp4_tun_socket),
7074243186Stuexen	    SOCK_DGRAM, IPPROTO_UDP,
7075243186Stuexen	    curthread->td_ucred, curthread))) {
7076243186Stuexen		sctp_over_udp_stop();
7077188067Srrs		return (ret);
7078188067Srrs	}
7079243186Stuexen	/* Call the special UDP hook. */
7080243186Stuexen	if ((ret = udp_set_kernel_tunneling(SCTP_BASE_INFO(udp4_tun_socket),
7081277789Sbryanv	    sctp_recv_udp_tunneled_packet, NULL))) {
7082243186Stuexen		sctp_over_udp_stop();
7083243186Stuexen		return (ret);
7084188067Srrs	}
7085243186Stuexen	/* Ok, we have a socket, bind it to the port. */
7086243186Stuexen	memset(&sin, 0, sizeof(struct sockaddr_in));
7087243186Stuexen	sin.sin_len = sizeof(struct sockaddr_in);
7088188067Srrs	sin.sin_family = AF_INET;
7089188067Srrs	sin.sin_port = htons(port);
7090243186Stuexen	if ((ret = sobind(SCTP_BASE_INFO(udp4_tun_socket),
7091243186Stuexen	    (struct sockaddr *)&sin, curthread))) {
7092188067Srrs		sctp_over_udp_stop();
7093188067Srrs		return (ret);
7094188067Srrs	}
7095243186Stuexen#endif
7096243186Stuexen#ifdef INET6
7097243186Stuexen	if ((ret = socreate(PF_INET6, &SCTP_BASE_INFO(udp6_tun_socket),
7098243186Stuexen	    SOCK_DGRAM, IPPROTO_UDP,
7099243186Stuexen	    curthread->td_ucred, curthread))) {
7100243186Stuexen		sctp_over_udp_stop();
7101243186Stuexen		return (ret);
7102243186Stuexen	}
7103243186Stuexen	/* Call the special UDP hook. */
7104243186Stuexen	if ((ret = udp_set_kernel_tunneling(SCTP_BASE_INFO(udp6_tun_socket),
7105277789Sbryanv	    sctp_recv_udp_tunneled_packet, NULL))) {
7106243186Stuexen		sctp_over_udp_stop();
7107243186Stuexen		return (ret);
7108243186Stuexen	}
7109243186Stuexen	/* Ok, we have a socket, bind it to the port. */
7110243186Stuexen	memset(&sin6, 0, sizeof(struct sockaddr_in6));
7111243186Stuexen	sin6.sin6_len = sizeof(struct sockaddr_in6);
7112243186Stuexen	sin6.sin6_family = AF_INET6;
7113243186Stuexen	sin6.sin6_port = htons(port);
7114243186Stuexen	if ((ret = sobind(SCTP_BASE_INFO(udp6_tun_socket),
7115243186Stuexen	    (struct sockaddr *)&sin6, curthread))) {
7116243186Stuexen		sctp_over_udp_stop();
7117243186Stuexen		return (ret);
7118243186Stuexen	}
7119243186Stuexen#endif
7120188067Srrs	return (0);
7121179157Srrs}
7122