xref: /netbsd-src/sys/netinet/sctputil.c (revision 481d3881954fd794ca5f2d880b68c53a5db8620e)
18c2654abSrjs /*	$KAME: sctputil.c,v 1.39 2005/06/16 20:54:06 jinmei Exp $	*/
2*481d3881Srin /*	$NetBSD: sctputil.c,v 1.20 2024/07/05 04:31:54 rin Exp $	*/
38c2654abSrjs 
48c2654abSrjs /*
58c2654abSrjs  * Copyright (c) 2001, 2002, 2003, 2004 Cisco Systems, Inc.
68c2654abSrjs  * All rights reserved.
78c2654abSrjs  *
88c2654abSrjs  * Redistribution and use in source and binary forms, with or without
98c2654abSrjs  * modification, are permitted provided that the following conditions
108c2654abSrjs  * are met:
118c2654abSrjs  * 1. Redistributions of source code must retain the above copyright
128c2654abSrjs  *    notice, this list of conditions and the following disclaimer.
138c2654abSrjs  * 2. Redistributions in binary form must reproduce the above copyright
148c2654abSrjs  *    notice, this list of conditions and the following disclaimer in the
158c2654abSrjs  *    documentation and/or other materials provided with the distribution.
168c2654abSrjs  * 3. All advertising materials mentioning features or use of this software
178c2654abSrjs  *    must display the following acknowledgement:
188c2654abSrjs  *      This product includes software developed by Cisco Systems, Inc.
198c2654abSrjs  * 4. Neither the name of the project nor the names of its contributors
208c2654abSrjs  *    may be used to endorse or promote products derived from this software
218c2654abSrjs  *    without specific prior written permission.
228c2654abSrjs  *
238c2654abSrjs  * THIS SOFTWARE IS PROVIDED BY CISCO SYSTEMS AND CONTRIBUTORS ``AS IS'' AND
248c2654abSrjs  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
258c2654abSrjs  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
268c2654abSrjs  * ARE DISCLAIMED.  IN NO EVENT SHALL CISCO SYSTEMS OR CONTRIBUTORS BE LIABLE
278c2654abSrjs  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
288c2654abSrjs  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
298c2654abSrjs  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
308c2654abSrjs  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
318c2654abSrjs  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
328c2654abSrjs  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
338c2654abSrjs  * SUCH DAMAGE.
348c2654abSrjs  */
358c2654abSrjs 
368c2654abSrjs #include <sys/cdefs.h>
37*481d3881Srin __KERNEL_RCSID(0, "$NetBSD: sctputil.c,v 1.20 2024/07/05 04:31:54 rin Exp $");
388c2654abSrjs 
398c2654abSrjs #ifdef _KERNEL_OPT
408c2654abSrjs #include "opt_inet.h"
418c2654abSrjs #include "opt_ipsec.h"
428c2654abSrjs #include "opt_sctp.h"
438c2654abSrjs #endif /* _KERNEL_OPT */
448c2654abSrjs 
458c2654abSrjs #include <sys/param.h>
468c2654abSrjs #include <sys/systm.h>
478c2654abSrjs #include <sys/malloc.h>
488c2654abSrjs #include <sys/mbuf.h>
498c2654abSrjs #include <sys/domain.h>
508c2654abSrjs #include <sys/protosw.h>
518c2654abSrjs #include <sys/socket.h>
528c2654abSrjs #include <sys/socketvar.h>
538c2654abSrjs #include <sys/mutex.h>
548c2654abSrjs #include <sys/proc.h>
558c2654abSrjs #include <sys/kernel.h>
568c2654abSrjs #include <sys/sysctl.h>
57a2f9ec55Sriastradh #include <sys/cprng.h>
588c2654abSrjs 
598c2654abSrjs #include <sys/callout.h>
608c2654abSrjs 
618c2654abSrjs #include <net/route.h>
628c2654abSrjs 
638c2654abSrjs #ifdef INET6
648c2654abSrjs #include <sys/domain.h>
658c2654abSrjs #endif
668c2654abSrjs 
678c2654abSrjs #include <machine/limits.h>
688c2654abSrjs 
698c2654abSrjs #include <net/if.h>
708c2654abSrjs #include <net/if_types.h>
718c2654abSrjs #include <net/route.h>
728c2654abSrjs 
738c2654abSrjs #include <netinet/in.h>
748c2654abSrjs #include <netinet/in_systm.h>
758c2654abSrjs #include <netinet/ip.h>
768c2654abSrjs #include <netinet/in_pcb.h>
778c2654abSrjs #include <netinet/in_var.h>
788c2654abSrjs #include <netinet/ip_var.h>
798c2654abSrjs 
808c2654abSrjs #ifdef INET6
818c2654abSrjs #include <netinet/ip6.h>
828c2654abSrjs #include <netinet6/ip6_var.h>
838c2654abSrjs #include <netinet6/scope6_var.h>
848c2654abSrjs #include <netinet6/in6_pcb.h>
858c2654abSrjs 
868c2654abSrjs #endif /* INET6 */
878c2654abSrjs 
888c2654abSrjs #include <netinet/sctp_pcb.h>
898c2654abSrjs 
908c2654abSrjs #ifdef IPSEC
91991b8746Srjs #include <netipsec/ipsec.h>
92991b8746Srjs #include <netipsec/key.h>
938c2654abSrjs #endif /* IPSEC */
948c2654abSrjs 
958c2654abSrjs #include <netinet/sctputil.h>
968c2654abSrjs #include <netinet/sctp_var.h>
978c2654abSrjs #ifdef INET6
988c2654abSrjs #include <netinet6/sctp6_var.h>
998c2654abSrjs #endif
1008c2654abSrjs #include <netinet/sctp_header.h>
1018c2654abSrjs #include <netinet/sctp_output.h>
1028c2654abSrjs #include <netinet/sctp_hashdriver.h>
1038c2654abSrjs #include <netinet/sctp_uio.h>
1048c2654abSrjs #include <netinet/sctp_timer.h>
1058c2654abSrjs #include <netinet/sctp_crc32.h>
1068c2654abSrjs #include <netinet/sctp_indata.h>	/* for sctp_deliver_data() */
1078c2654abSrjs #define NUMBER_OF_MTU_SIZES 18
1088c2654abSrjs 
1098c2654abSrjs #ifdef SCTP_DEBUG
1108c2654abSrjs extern u_int32_t sctp_debug_on;
1118c2654abSrjs #endif
1128c2654abSrjs 
1138c2654abSrjs #ifdef SCTP_STAT_LOGGING
1148c2654abSrjs int sctp_cwnd_log_at=0;
1158c2654abSrjs int sctp_cwnd_log_rolled=0;
1168c2654abSrjs struct sctp_cwnd_log sctp_clog[SCTP_STAT_LOG_SIZE];
1178c2654abSrjs 
sctp_clr_stat_log(void)1188c2654abSrjs void sctp_clr_stat_log(void)
1198c2654abSrjs {
1208c2654abSrjs 	sctp_cwnd_log_at=0;
1218c2654abSrjs 	sctp_cwnd_log_rolled=0;
1228c2654abSrjs }
1238c2654abSrjs 
1248c2654abSrjs void
sctp_log_strm_del_alt(u_int32_t tsn,u_int16_t sseq,int from)1258c2654abSrjs sctp_log_strm_del_alt(u_int32_t tsn, u_int16_t sseq, int from)
1268c2654abSrjs {
1278c2654abSrjs 
1288c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].from = (u_int8_t)from;
1298c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].event_type = (u_int8_t)SCTP_LOG_EVENT_STRM;
1308c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.strlog.n_tsn = tsn;
1318c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.strlog.n_sseq = sseq;
1328c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.strlog.e_tsn = 0;
1338c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.strlog.e_sseq = 0;
1348c2654abSrjs 	sctp_cwnd_log_at++;
1358c2654abSrjs 	if (sctp_cwnd_log_at >= SCTP_STAT_LOG_SIZE) {
1368c2654abSrjs 		sctp_cwnd_log_at = 0;
1378c2654abSrjs 		sctp_cwnd_log_rolled = 1;
1388c2654abSrjs 	}
1398c2654abSrjs 
1408c2654abSrjs }
1418c2654abSrjs 
1428c2654abSrjs void
sctp_log_map(uint32_t map,uint32_t cum,uint32_t high,int from)1438c2654abSrjs sctp_log_map(uint32_t map, uint32_t cum, uint32_t high, int from)
1448c2654abSrjs {
1458c2654abSrjs 
1468c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].from = (u_int8_t)from;
1478c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].event_type = (u_int8_t)SCTP_LOG_EVENT_MAP;
1488c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.map.base = map;
1498c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.map.cum = cum;
1508c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.map.high = high;
1518c2654abSrjs 	sctp_cwnd_log_at++;
1528c2654abSrjs 	if (sctp_cwnd_log_at >= SCTP_STAT_LOG_SIZE) {
1538c2654abSrjs 		sctp_cwnd_log_at = 0;
1548c2654abSrjs 		sctp_cwnd_log_rolled = 1;
1558c2654abSrjs 	}
1568c2654abSrjs }
1578c2654abSrjs 
1588c2654abSrjs void
sctp_log_fr(uint32_t biggest_tsn,uint32_t biggest_new_tsn,uint32_t tsn,int from)1598c2654abSrjs sctp_log_fr(uint32_t biggest_tsn, uint32_t biggest_new_tsn, uint32_t tsn,
1608c2654abSrjs     int from)
1618c2654abSrjs {
1628c2654abSrjs 
1638c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].from = (u_int8_t)from;
1648c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].event_type = (u_int8_t)SCTP_LOG_EVENT_FR;
1658c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.fr.largest_tsn = biggest_tsn;
1668c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.fr.largest_new_tsn = biggest_new_tsn;
1678c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.fr.tsn = tsn;
1688c2654abSrjs 	sctp_cwnd_log_at++;
1698c2654abSrjs 	if (sctp_cwnd_log_at >= SCTP_STAT_LOG_SIZE) {
1708c2654abSrjs 		sctp_cwnd_log_at = 0;
1718c2654abSrjs 		sctp_cwnd_log_rolled = 1;
1728c2654abSrjs 	}
1738c2654abSrjs }
1748c2654abSrjs 
1758c2654abSrjs void
sctp_log_strm_del(struct sctp_tmit_chunk * chk,struct sctp_tmit_chunk * poschk,int from)1768c2654abSrjs sctp_log_strm_del(struct sctp_tmit_chunk *chk, struct sctp_tmit_chunk *poschk,
1778c2654abSrjs     int from)
1788c2654abSrjs {
1798c2654abSrjs 
1808c2654abSrjs 	if (chk == NULL) {
1818c2654abSrjs 		printf("Gak log of NULL?\n");
1828c2654abSrjs 		return;
1838c2654abSrjs 	}
1848c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].from = (u_int8_t)from;
1858c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].event_type = (u_int8_t)SCTP_LOG_EVENT_STRM;
1868c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.strlog.n_tsn = chk->rec.data.TSN_seq;
1878c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.strlog.n_sseq = chk->rec.data.stream_seq;
1888c2654abSrjs 	if (poschk != NULL) {
1898c2654abSrjs 		sctp_clog[sctp_cwnd_log_at].x.strlog.e_tsn =
1908c2654abSrjs 		    poschk->rec.data.TSN_seq;
1918c2654abSrjs 		sctp_clog[sctp_cwnd_log_at].x.strlog.e_sseq =
1928c2654abSrjs 		    poschk->rec.data.stream_seq;
1938c2654abSrjs 	} else {
1948c2654abSrjs 		sctp_clog[sctp_cwnd_log_at].x.strlog.e_tsn = 0;
1958c2654abSrjs 		sctp_clog[sctp_cwnd_log_at].x.strlog.e_sseq = 0;
1968c2654abSrjs 	}
1978c2654abSrjs 	sctp_cwnd_log_at++;
1988c2654abSrjs 	if (sctp_cwnd_log_at >= SCTP_STAT_LOG_SIZE) {
1998c2654abSrjs 		sctp_cwnd_log_at = 0;
2008c2654abSrjs 		sctp_cwnd_log_rolled = 1;
2018c2654abSrjs 	}
2028c2654abSrjs }
2038c2654abSrjs 
2048c2654abSrjs void
sctp_log_cwnd(struct sctp_nets * net,int augment,uint8_t from)2058c2654abSrjs sctp_log_cwnd(struct sctp_nets *net, int augment, uint8_t from)
2068c2654abSrjs {
2078c2654abSrjs 
2088c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].from = (u_int8_t)from;
2098c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].event_type = (u_int8_t)SCTP_LOG_EVENT_CWND;
2108c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.cwnd.net = net;
2118c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.cwnd.cwnd_new_value = net->cwnd;
2128c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.cwnd.inflight = net->flight_size;
2138c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.cwnd.cwnd_augment = augment;
2148c2654abSrjs 	sctp_cwnd_log_at++;
2158c2654abSrjs 	if (sctp_cwnd_log_at >= SCTP_STAT_LOG_SIZE) {
2168c2654abSrjs 		sctp_cwnd_log_at = 0;
2178c2654abSrjs 		sctp_cwnd_log_rolled = 1;
2188c2654abSrjs 	}
2198c2654abSrjs }
2208c2654abSrjs 
2218c2654abSrjs void
sctp_log_maxburst(struct sctp_nets * net,int error,int burst,uint8_t from)2228c2654abSrjs sctp_log_maxburst(struct sctp_nets *net, int error, int burst, uint8_t from)
2238c2654abSrjs {
2248c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].from = (u_int8_t)from;
2258c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].event_type = (u_int8_t)SCTP_LOG_EVENT_MAXBURST;
2268c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.cwnd.net = net;
2278c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.cwnd.cwnd_new_value = error;
2288c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.cwnd.inflight = net->flight_size;
2298c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.cwnd.cwnd_augment = burst;
2308c2654abSrjs 	sctp_cwnd_log_at++;
2318c2654abSrjs 	if (sctp_cwnd_log_at >= SCTP_STAT_LOG_SIZE) {
2328c2654abSrjs 		sctp_cwnd_log_at = 0;
2338c2654abSrjs 		sctp_cwnd_log_rolled = 1;
2348c2654abSrjs 	}
2358c2654abSrjs }
2368c2654abSrjs 
2378c2654abSrjs void
sctp_log_rwnd(uint8_t from,u_int32_t peers_rwnd,u_int32_t snd_size,u_int32_t overhead)2388c2654abSrjs sctp_log_rwnd(uint8_t from, u_int32_t peers_rwnd , u_int32_t snd_size, u_int32_t overhead)
2398c2654abSrjs {
2408c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].from = (u_int8_t)from;
2418c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].event_type = (u_int8_t)SCTP_LOG_EVENT_RWND;
2428c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.rwnd.rwnd = peers_rwnd;
2438c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.rwnd.send_size = snd_size;
2448c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.rwnd.overhead = overhead;
2458c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.rwnd.new_rwnd = 0;
2468c2654abSrjs 	sctp_cwnd_log_at++;
2478c2654abSrjs 	if (sctp_cwnd_log_at >= SCTP_STAT_LOG_SIZE) {
2488c2654abSrjs 		sctp_cwnd_log_at = 0;
2498c2654abSrjs 		sctp_cwnd_log_rolled = 1;
2508c2654abSrjs 	}
2518c2654abSrjs }
2528c2654abSrjs 
2538c2654abSrjs void
sctp_log_rwnd_set(uint8_t from,u_int32_t peers_rwnd,u_int32_t flight_size,u_int32_t overhead,u_int32_t a_rwndval)2548c2654abSrjs sctp_log_rwnd_set(uint8_t from, u_int32_t peers_rwnd , u_int32_t flight_size, u_int32_t overhead, u_int32_t a_rwndval)
2558c2654abSrjs {
2568c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].from = (u_int8_t)from;
2578c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].event_type = (u_int8_t)SCTP_LOG_EVENT_RWND;
2588c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.rwnd.rwnd = peers_rwnd;
2598c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.rwnd.send_size = flight_size;
2608c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.rwnd.overhead = overhead;
2618c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.rwnd.new_rwnd = a_rwndval;
2628c2654abSrjs 	sctp_cwnd_log_at++;
2638c2654abSrjs 	if (sctp_cwnd_log_at >= SCTP_STAT_LOG_SIZE) {
2648c2654abSrjs 		sctp_cwnd_log_at = 0;
2658c2654abSrjs 		sctp_cwnd_log_rolled = 1;
2668c2654abSrjs 	}
2678c2654abSrjs }
2688c2654abSrjs 
2698c2654abSrjs void
sctp_log_mbcnt(uint8_t from,u_int32_t total_oq,u_int32_t book,u_int32_t total_mbcnt_q,u_int32_t mbcnt)2708c2654abSrjs sctp_log_mbcnt(uint8_t from, u_int32_t total_oq , u_int32_t book, u_int32_t total_mbcnt_q, u_int32_t mbcnt)
2718c2654abSrjs {
2728c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].from = (u_int8_t)from;
2738c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].event_type = (u_int8_t)SCTP_LOG_EVENT_MBCNT;
2748c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.mbcnt.total_queue_size = total_oq;
2758c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.mbcnt.size_change  = book;
2768c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.mbcnt.total_queue_mb_size = total_mbcnt_q;
2778c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.mbcnt.mbcnt_change = mbcnt;
2788c2654abSrjs 	sctp_cwnd_log_at++;
2798c2654abSrjs 	if (sctp_cwnd_log_at >= SCTP_STAT_LOG_SIZE) {
2808c2654abSrjs 		sctp_cwnd_log_at = 0;
2818c2654abSrjs 		sctp_cwnd_log_rolled = 1;
2828c2654abSrjs 	}
2838c2654abSrjs }
2848c2654abSrjs 
2858c2654abSrjs void
sctp_log_block(uint8_t from,struct socket * so,struct sctp_association * asoc)2868c2654abSrjs sctp_log_block(uint8_t from, struct socket *so, struct sctp_association *asoc)
2878c2654abSrjs {
2888c2654abSrjs 
2898c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].from = (u_int8_t)from;
2908c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].event_type = (u_int8_t)SCTP_LOG_EVENT_BLOCK;
2918c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.blk.maxmb = (u_int16_t)(so->so_snd.sb_mbmax/1024);
2928c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.blk.onmb = asoc->total_output_mbuf_queue_size;
2938c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.blk.maxsb = (u_int16_t)(so->so_snd.sb_hiwat/1024);
2948c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.blk.onsb = asoc->total_output_queue_size;
2958c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.blk.send_sent_qcnt = (u_int16_t)(asoc->send_queue_cnt + asoc->sent_queue_cnt);
2968c2654abSrjs 	sctp_clog[sctp_cwnd_log_at].x.blk.stream_qcnt = (u_int16_t)asoc->stream_queue_cnt;
2978c2654abSrjs 	sctp_cwnd_log_at++;
2988c2654abSrjs 	if (sctp_cwnd_log_at >= SCTP_STAT_LOG_SIZE) {
2998c2654abSrjs 		sctp_cwnd_log_at = 0;
3008c2654abSrjs 		sctp_cwnd_log_rolled = 1;
3018c2654abSrjs 	}
3028c2654abSrjs }
3038c2654abSrjs 
3048c2654abSrjs int
sctp_fill_stat_log(struct mbuf * m)3058c2654abSrjs sctp_fill_stat_log(struct mbuf *m)
3068c2654abSrjs {
3078c2654abSrjs 	struct sctp_cwnd_log_req *req;
3088c2654abSrjs 	int size_limit, num, i, at, cnt_out=0;
3098c2654abSrjs 
3108c2654abSrjs 	if (m == NULL)
3118c2654abSrjs 		return (EINVAL);
3128c2654abSrjs 
3138c2654abSrjs 	size_limit = (m->m_len - sizeof(struct sctp_cwnd_log_req));
3148c2654abSrjs 	if (size_limit < sizeof(struct sctp_cwnd_log)) {
3158c2654abSrjs 		return (EINVAL);
3168c2654abSrjs 	}
3178c2654abSrjs 	req = mtod(m, struct sctp_cwnd_log_req *);
3188c2654abSrjs 	num = size_limit/sizeof(struct sctp_cwnd_log);
3198c2654abSrjs 	if (sctp_cwnd_log_rolled) {
3208c2654abSrjs 		req->num_in_log = SCTP_STAT_LOG_SIZE;
3218c2654abSrjs 	} else {
3228c2654abSrjs 		req->num_in_log = sctp_cwnd_log_at;
3238c2654abSrjs 		/* if the log has not rolled, we don't
3248c2654abSrjs 		 * let you have old data.
3258c2654abSrjs 		 */
3268c2654abSrjs  		if (req->end_at > sctp_cwnd_log_at) {
3278c2654abSrjs 			req->end_at = sctp_cwnd_log_at;
3288c2654abSrjs 		}
3298c2654abSrjs 	}
3308c2654abSrjs 	if ((num < SCTP_STAT_LOG_SIZE) &&
3318c2654abSrjs 	    ((sctp_cwnd_log_rolled) || (sctp_cwnd_log_at > num))) {
3328c2654abSrjs 		/* we can't return all of it */
3338c2654abSrjs 		if (((req->start_at == 0) && (req->end_at == 0)) ||
3348c2654abSrjs 		    (req->start_at >= SCTP_STAT_LOG_SIZE) ||
3358c2654abSrjs 		    (req->end_at >= SCTP_STAT_LOG_SIZE)) {
3368c2654abSrjs 			/* No user request or user is wacked. */
3378c2654abSrjs 			req->num_ret = num;
3388c2654abSrjs 			req->end_at = sctp_cwnd_log_at - 1;
3398c2654abSrjs 			if ((sctp_cwnd_log_at - num) < 0) {
3408c2654abSrjs 				int cc;
3418c2654abSrjs 				cc = num - sctp_cwnd_log_at;
3428c2654abSrjs 				req->start_at = SCTP_STAT_LOG_SIZE - cc;
3438c2654abSrjs 			} else {
3448c2654abSrjs 				req->start_at = sctp_cwnd_log_at - num;
3458c2654abSrjs 			}
3468c2654abSrjs 		} else {
3478c2654abSrjs 			/* a user request */
3488c2654abSrjs 			int cc;
3498c2654abSrjs 			if (req->start_at > req->end_at) {
3508c2654abSrjs 				cc = (SCTP_STAT_LOG_SIZE - req->start_at) +
3518c2654abSrjs 				    (req->end_at + 1);
3528c2654abSrjs 			} else {
3538c2654abSrjs 
3548c2654abSrjs 				cc = req->end_at - req->start_at;
3558c2654abSrjs 			}
3568c2654abSrjs 			if (cc < num) {
3578c2654abSrjs 				num = cc;
3588c2654abSrjs 			}
3598c2654abSrjs 			req->num_ret = num;
3608c2654abSrjs 		}
3618c2654abSrjs 	} else {
3628c2654abSrjs 		/* We can return all  of it */
3638c2654abSrjs 		req->start_at = 0;
3648c2654abSrjs 		req->end_at = sctp_cwnd_log_at - 1;
3658c2654abSrjs 		req->num_ret = sctp_cwnd_log_at;
3668c2654abSrjs 	}
3678c2654abSrjs 	for (i = 0, at = req->start_at; i < req->num_ret; i++) {
3688c2654abSrjs 		req->log[i] = sctp_clog[at];
3698c2654abSrjs 		cnt_out++;
3708c2654abSrjs 		at++;
3718c2654abSrjs 		if (at >= SCTP_STAT_LOG_SIZE)
3728c2654abSrjs 			at = 0;
3738c2654abSrjs 	}
3748c2654abSrjs 	m->m_len = (cnt_out * sizeof(struct sctp_cwnd_log_req)) + sizeof(struct sctp_cwnd_log_req);
3758c2654abSrjs 	return (0);
3768c2654abSrjs }
3778c2654abSrjs 
3788c2654abSrjs #endif
3798c2654abSrjs 
3808c2654abSrjs #ifdef SCTP_AUDITING_ENABLED
3818c2654abSrjs u_int8_t sctp_audit_data[SCTP_AUDIT_SIZE][2];
3828c2654abSrjs static int sctp_audit_indx = 0;
3838c2654abSrjs 
3848c2654abSrjs static
sctp_print_audit_report(void)3858c2654abSrjs void sctp_print_audit_report(void)
3868c2654abSrjs {
3878c2654abSrjs 	int i;
3888c2654abSrjs 	int cnt;
3898c2654abSrjs 	cnt = 0;
3908c2654abSrjs 	for (i=sctp_audit_indx;i<SCTP_AUDIT_SIZE;i++) {
3918c2654abSrjs 		if ((sctp_audit_data[i][0] == 0xe0) &&
3928c2654abSrjs 		    (sctp_audit_data[i][1] == 0x01)) {
3938c2654abSrjs 			cnt = 0;
3948c2654abSrjs 			printf("\n");
3958c2654abSrjs 		} else if (sctp_audit_data[i][0] == 0xf0) {
3968c2654abSrjs 			cnt = 0;
3978c2654abSrjs 			printf("\n");
3988c2654abSrjs 		} else if ((sctp_audit_data[i][0] == 0xc0) &&
3998c2654abSrjs 		    (sctp_audit_data[i][1] == 0x01)) {
4008c2654abSrjs 			printf("\n");
4018c2654abSrjs 			cnt = 0;
4028c2654abSrjs 		}
4038c2654abSrjs 		printf("%2.2x%2.2x ", (uint32_t)sctp_audit_data[i][0],
4048c2654abSrjs 		    (uint32_t)sctp_audit_data[i][1]);
4058c2654abSrjs 		cnt++;
4068c2654abSrjs 		if ((cnt % 14) == 0)
4078c2654abSrjs 			printf("\n");
4088c2654abSrjs 	}
4098c2654abSrjs 	for (i=0;i<sctp_audit_indx;i++) {
4108c2654abSrjs 		if ((sctp_audit_data[i][0] == 0xe0) &&
4118c2654abSrjs 		    (sctp_audit_data[i][1] == 0x01)) {
4128c2654abSrjs 			cnt = 0;
4138c2654abSrjs 			printf("\n");
4148c2654abSrjs 		} else if (sctp_audit_data[i][0] == 0xf0) {
4158c2654abSrjs 			cnt = 0;
4168c2654abSrjs 			printf("\n");
4178c2654abSrjs 		} else if ((sctp_audit_data[i][0] == 0xc0) &&
4188c2654abSrjs 			 (sctp_audit_data[i][1] == 0x01)) {
4198c2654abSrjs 			printf("\n");
4208c2654abSrjs 			cnt = 0;
4218c2654abSrjs 		}
4228c2654abSrjs 		printf("%2.2x%2.2x ", (uint32_t)sctp_audit_data[i][0],
4238c2654abSrjs 		    (uint32_t)sctp_audit_data[i][1]);
4248c2654abSrjs 		cnt++;
4258c2654abSrjs 		if ((cnt % 14) == 0)
4268c2654abSrjs 			printf("\n");
4278c2654abSrjs 	}
4288c2654abSrjs 	printf("\n");
4298c2654abSrjs }
4308c2654abSrjs 
sctp_auditing(int from,struct sctp_inpcb * inp,struct sctp_tcb * stcb,struct sctp_nets * net)4318c2654abSrjs void sctp_auditing(int from, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
4328c2654abSrjs     struct sctp_nets *net)
4338c2654abSrjs {
4348c2654abSrjs 	int resend_cnt, tot_out, rep, tot_book_cnt;
4358c2654abSrjs 	struct sctp_nets *lnet;
4368c2654abSrjs 	struct sctp_tmit_chunk *chk;
4378c2654abSrjs 
4388c2654abSrjs 	sctp_audit_data[sctp_audit_indx][0] = 0xAA;
4398c2654abSrjs 	sctp_audit_data[sctp_audit_indx][1] = 0x000000ff & from;
4408c2654abSrjs 	sctp_audit_indx++;
4418c2654abSrjs 	if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
4428c2654abSrjs 		sctp_audit_indx = 0;
4438c2654abSrjs 	}
4448c2654abSrjs 	if (inp == NULL) {
4458c2654abSrjs 		sctp_audit_data[sctp_audit_indx][0] = 0xAF;
4468c2654abSrjs 		sctp_audit_data[sctp_audit_indx][1] = 0x01;
4478c2654abSrjs 		sctp_audit_indx++;
4488c2654abSrjs 		if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
4498c2654abSrjs 			sctp_audit_indx = 0;
4508c2654abSrjs 		}
4518c2654abSrjs 		return;
4528c2654abSrjs 	}
4538c2654abSrjs 	if (stcb == NULL) {
4548c2654abSrjs 		sctp_audit_data[sctp_audit_indx][0] = 0xAF;
4558c2654abSrjs 		sctp_audit_data[sctp_audit_indx][1] = 0x02;
4568c2654abSrjs 		sctp_audit_indx++;
4578c2654abSrjs 		if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
4588c2654abSrjs 			sctp_audit_indx = 0;
4598c2654abSrjs 		}
4608c2654abSrjs 		return;
4618c2654abSrjs 	}
4628c2654abSrjs 	sctp_audit_data[sctp_audit_indx][0] = 0xA1;
4638c2654abSrjs 	sctp_audit_data[sctp_audit_indx][1] =
4648c2654abSrjs 	    (0x000000ff & stcb->asoc.sent_queue_retran_cnt);
4658c2654abSrjs 	sctp_audit_indx++;
4668c2654abSrjs 	if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
4678c2654abSrjs 		sctp_audit_indx = 0;
4688c2654abSrjs 	}
4698c2654abSrjs 	rep = 0;
4708c2654abSrjs 	tot_book_cnt = 0;
4718c2654abSrjs 	resend_cnt = tot_out = 0;
4728c2654abSrjs 	TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
4738c2654abSrjs 		if (chk->sent == SCTP_DATAGRAM_RESEND) {
4748c2654abSrjs 			resend_cnt++;
4758c2654abSrjs 		} else if (chk->sent < SCTP_DATAGRAM_RESEND) {
4768c2654abSrjs 			tot_out += chk->book_size;
4778c2654abSrjs 			tot_book_cnt++;
4788c2654abSrjs 		}
4798c2654abSrjs 	}
4808c2654abSrjs 	if (resend_cnt != stcb->asoc.sent_queue_retran_cnt) {
4818c2654abSrjs 		sctp_audit_data[sctp_audit_indx][0] = 0xAF;
4828c2654abSrjs 		sctp_audit_data[sctp_audit_indx][1] = 0xA1;
4838c2654abSrjs 		sctp_audit_indx++;
4848c2654abSrjs 		if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
4858c2654abSrjs 			sctp_audit_indx = 0;
4868c2654abSrjs 		}
4878c2654abSrjs 		printf("resend_cnt:%d asoc-tot:%d\n",
4888c2654abSrjs 		    resend_cnt, stcb->asoc.sent_queue_retran_cnt);
4898c2654abSrjs 		rep = 1;
4908c2654abSrjs 		stcb->asoc.sent_queue_retran_cnt = resend_cnt;
4918c2654abSrjs 		sctp_audit_data[sctp_audit_indx][0] = 0xA2;
4928c2654abSrjs 		sctp_audit_data[sctp_audit_indx][1] =
4938c2654abSrjs 		    (0x000000ff & stcb->asoc.sent_queue_retran_cnt);
4948c2654abSrjs 		sctp_audit_indx++;
4958c2654abSrjs 		if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
4968c2654abSrjs 			sctp_audit_indx = 0;
4978c2654abSrjs 		}
4988c2654abSrjs 	}
4998c2654abSrjs 	if (tot_out != stcb->asoc.total_flight) {
5008c2654abSrjs 		sctp_audit_data[sctp_audit_indx][0] = 0xAF;
5018c2654abSrjs 		sctp_audit_data[sctp_audit_indx][1] = 0xA2;
5028c2654abSrjs 		sctp_audit_indx++;
5038c2654abSrjs 		if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
5048c2654abSrjs 			sctp_audit_indx = 0;
5058c2654abSrjs 		}
5068c2654abSrjs 		rep = 1;
5078c2654abSrjs 		printf("tot_flt:%d asoc_tot:%d\n", tot_out,
5088c2654abSrjs 		    (int)stcb->asoc.total_flight);
5098c2654abSrjs 		stcb->asoc.total_flight = tot_out;
5108c2654abSrjs 	}
5118c2654abSrjs 	if (tot_book_cnt != stcb->asoc.total_flight_count) {
5128c2654abSrjs 		sctp_audit_data[sctp_audit_indx][0] = 0xAF;
5138c2654abSrjs 		sctp_audit_data[sctp_audit_indx][1] = 0xA5;
5148c2654abSrjs 		sctp_audit_indx++;
5158c2654abSrjs 		if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
5168c2654abSrjs 			sctp_audit_indx = 0;
5178c2654abSrjs 		}
5188c2654abSrjs 		rep = 1;
5198c2654abSrjs 		printf("tot_flt_book:%d\n", tot_book);
5208c2654abSrjs 
5218c2654abSrjs 		stcb->asoc.total_flight_count = tot_book_cnt;
5228c2654abSrjs 	}
5238c2654abSrjs 	tot_out = 0;
5248c2654abSrjs 	TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
5258c2654abSrjs 		tot_out += lnet->flight_size;
5268c2654abSrjs 	}
5278c2654abSrjs 	if (tot_out != stcb->asoc.total_flight) {
5288c2654abSrjs 		sctp_audit_data[sctp_audit_indx][0] = 0xAF;
5298c2654abSrjs 		sctp_audit_data[sctp_audit_indx][1] = 0xA3;
5308c2654abSrjs 		sctp_audit_indx++;
5318c2654abSrjs 		if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
5328c2654abSrjs 			sctp_audit_indx = 0;
5338c2654abSrjs 		}
5348c2654abSrjs 		rep = 1;
5358c2654abSrjs 		printf("real flight:%d net total was %d\n",
5368c2654abSrjs 		    stcb->asoc.total_flight, tot_out);
5378c2654abSrjs 		/* now corrective action */
5388c2654abSrjs 		TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
5398c2654abSrjs 			tot_out = 0;
5408c2654abSrjs 			TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
5418c2654abSrjs 				if ((chk->whoTo == lnet) &&
5428c2654abSrjs 				    (chk->sent < SCTP_DATAGRAM_RESEND)) {
5438c2654abSrjs 					tot_out += chk->book_size;
5448c2654abSrjs 				}
5458c2654abSrjs 			}
5468c2654abSrjs 			if (lnet->flight_size != tot_out) {
5478c2654abSrjs 				printf("net:%x flight was %d corrected to %d\n",
5488c2654abSrjs 				    (uint32_t)lnet, lnet->flight_size, tot_out);
5498c2654abSrjs 				lnet->flight_size = tot_out;
5508c2654abSrjs 			}
5518c2654abSrjs 
5528c2654abSrjs 		}
5538c2654abSrjs 	}
5548c2654abSrjs 
5558c2654abSrjs 	if (rep) {
5568c2654abSrjs 		sctp_print_audit_report();
5578c2654abSrjs 	}
5588c2654abSrjs }
5598c2654abSrjs 
5608c2654abSrjs void
sctp_audit_log(u_int8_t ev,u_int8_t fd)5618c2654abSrjs sctp_audit_log(u_int8_t ev, u_int8_t fd)
5628c2654abSrjs {
5638c2654abSrjs 	sctp_audit_data[sctp_audit_indx][0] = ev;
5648c2654abSrjs 	sctp_audit_data[sctp_audit_indx][1] = fd;
5658c2654abSrjs 	sctp_audit_indx++;
5668c2654abSrjs 	if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
5678c2654abSrjs 		sctp_audit_indx = 0;
5688c2654abSrjs 	}
5698c2654abSrjs }
5708c2654abSrjs 
5718c2654abSrjs #endif
5728c2654abSrjs 
5738c2654abSrjs /*
5748c2654abSrjs  * a list of sizes based on typical mtu's, used only if next hop
5758c2654abSrjs  * size not returned.
5768c2654abSrjs  */
5778c2654abSrjs static int sctp_mtu_sizes[] = {
5788c2654abSrjs 	68,
5798c2654abSrjs 	296,
5808c2654abSrjs 	508,
5818c2654abSrjs 	512,
5828c2654abSrjs 	544,
5838c2654abSrjs 	576,
5848c2654abSrjs 	1006,
5858c2654abSrjs 	1492,
5868c2654abSrjs 	1500,
5878c2654abSrjs 	1536,
5888c2654abSrjs 	2002,
5898c2654abSrjs 	2048,
5908c2654abSrjs 	4352,
5918c2654abSrjs 	4464,
5928c2654abSrjs 	8166,
5938c2654abSrjs 	17914,
5948c2654abSrjs 	32000,
5958c2654abSrjs 	65535
5968c2654abSrjs };
5978c2654abSrjs 
5988c2654abSrjs int
find_next_best_mtu(int totsz)5998c2654abSrjs find_next_best_mtu(int totsz)
6008c2654abSrjs {
6018c2654abSrjs 	int i, perfer;
6028c2654abSrjs 	/*
6038c2654abSrjs 	 * if we are in here we must find the next best fit based on the
6048c2654abSrjs 	 * size of the dg that failed to be sent.
6058c2654abSrjs 	 */
6068c2654abSrjs 	perfer = 0;
6078c2654abSrjs 	for (i = 0; i < NUMBER_OF_MTU_SIZES; i++) {
6088c2654abSrjs 		if (totsz < sctp_mtu_sizes[i]) {
6098c2654abSrjs 			perfer = i - 1;
6108c2654abSrjs 			if (perfer < 0)
6118c2654abSrjs 				perfer = 0;
6128c2654abSrjs 			break;
6138c2654abSrjs 		}
6148c2654abSrjs 	}
6158c2654abSrjs 	return (sctp_mtu_sizes[perfer]);
6168c2654abSrjs }
6178c2654abSrjs 
6188c2654abSrjs uint32_t
sctp_select_initial_TSN(struct sctp_pcb * m)6198c2654abSrjs sctp_select_initial_TSN(struct sctp_pcb *m)
6208c2654abSrjs {
621a2f9ec55Sriastradh 	return cprng_strong32();
6228c2654abSrjs }
6238c2654abSrjs 
sctp_select_a_tag(struct sctp_inpcb * m)6248c2654abSrjs u_int32_t sctp_select_a_tag(struct sctp_inpcb *m)
6258c2654abSrjs {
6268c2654abSrjs 	u_long x, not_done;
6278c2654abSrjs 	struct timeval now;
6288c2654abSrjs 
6298c2654abSrjs 	SCTP_GETTIME_TIMEVAL(&now);
6308c2654abSrjs 	not_done = 1;
6318c2654abSrjs 	while (not_done) {
6328c2654abSrjs 		x = sctp_select_initial_TSN(&m->sctp_ep);
6338c2654abSrjs 		if (x == 0) {
6348c2654abSrjs 			/* we never use 0 */
6358c2654abSrjs 			continue;
6368c2654abSrjs 		}
6378c2654abSrjs 		if (sctp_is_vtag_good(m, x, &now)) {
6388c2654abSrjs 			not_done = 0;
6398c2654abSrjs 		}
6408c2654abSrjs 	}
6418c2654abSrjs 	return (x);
6428c2654abSrjs }
6438c2654abSrjs 
6448c2654abSrjs 
6458c2654abSrjs int
sctp_init_asoc(struct sctp_inpcb * m,struct sctp_association * asoc,int for_a_init,uint32_t override_tag)6468c2654abSrjs sctp_init_asoc(struct sctp_inpcb *m, struct sctp_association *asoc,
6478c2654abSrjs 	       int for_a_init, uint32_t override_tag )
6488c2654abSrjs {
6498c2654abSrjs 	/*
6508c2654abSrjs 	 * Anything set to zero is taken care of by the allocation
6518c2654abSrjs 	 * routine's bzero
6528c2654abSrjs 	 */
6538c2654abSrjs 
6548c2654abSrjs 	/*
6558c2654abSrjs 	 * Up front select what scoping to apply on addresses I tell my peer
6568c2654abSrjs 	 * Not sure what to do with these right now, we will need to come up
6578c2654abSrjs 	 * with a way to set them. We may need to pass them through from the
6588c2654abSrjs 	 * caller in the sctp_aloc_assoc() function.
6598c2654abSrjs 	 */
6608c2654abSrjs 	int i;
6618c2654abSrjs 	/* init all variables to a known value.*/
6628c2654abSrjs 	asoc->state = SCTP_STATE_INUSE;
6638c2654abSrjs 	asoc->max_burst = m->sctp_ep.max_burst;
6648c2654abSrjs 	asoc->heart_beat_delay = m->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT];
6658c2654abSrjs 	asoc->cookie_life = m->sctp_ep.def_cookie_life;
6668c2654abSrjs 
6678c2654abSrjs 	if (override_tag) {
6688c2654abSrjs 		asoc->my_vtag = override_tag;
6698c2654abSrjs 	} else {
6708c2654abSrjs 		asoc->my_vtag = sctp_select_a_tag(m);
6718c2654abSrjs 	}
6728c2654abSrjs 	asoc->asconf_seq_out = asoc->str_reset_seq_out = asoc->init_seq_number = asoc->sending_seq =
6738c2654abSrjs 		sctp_select_initial_TSN(&m->sctp_ep);
6748c2654abSrjs 	asoc->t3timeout_highest_marked = asoc->asconf_seq_out;
6758c2654abSrjs 	/* we are opptimisitic here */
6768c2654abSrjs 	asoc->peer_supports_asconf = 1;
6778c2654abSrjs 	asoc->peer_supports_asconf_setprim = 1;
6788c2654abSrjs 	asoc->peer_supports_pktdrop = 1;
6798c2654abSrjs 
6808c2654abSrjs 	asoc->sent_queue_retran_cnt = 0;
6818c2654abSrjs 	/* This will need to be adjusted */
6828c2654abSrjs 	asoc->last_cwr_tsn = asoc->init_seq_number - 1;
6838c2654abSrjs 	asoc->last_acked_seq = asoc->init_seq_number - 1;
6848c2654abSrjs 	asoc->advanced_peer_ack_point = asoc->last_acked_seq;
6858c2654abSrjs 	asoc->asconf_seq_in = asoc->last_acked_seq;
6868c2654abSrjs 
6878c2654abSrjs 	/* here we are different, we hold the next one we expect */
6888c2654abSrjs 	asoc->str_reset_seq_in = asoc->last_acked_seq + 1;
6898c2654abSrjs 
6908c2654abSrjs 	asoc->initial_init_rto_max = m->sctp_ep.initial_init_rto_max;
6918c2654abSrjs 	asoc->initial_rto = m->sctp_ep.initial_rto;
6928c2654abSrjs 
6938c2654abSrjs 	asoc->max_init_times = m->sctp_ep.max_init_times;
6948c2654abSrjs 	asoc->max_send_times = m->sctp_ep.max_send_times;
6958c2654abSrjs 	asoc->def_net_failure = m->sctp_ep.def_net_failure;
6968c2654abSrjs 
6978c2654abSrjs 	/* ECN Nonce initialization */
6988c2654abSrjs 	asoc->ecn_nonce_allowed = 0;
6998c2654abSrjs 	asoc->receiver_nonce_sum = 1;
7008c2654abSrjs 	asoc->nonce_sum_expect_base = 1;
7018c2654abSrjs 	asoc->nonce_sum_check = 1;
7028c2654abSrjs 	asoc->nonce_resync_tsn = 0;
7038c2654abSrjs 	asoc->nonce_wait_for_ecne = 0;
7048c2654abSrjs 	asoc->nonce_wait_tsn = 0;
7058c2654abSrjs 
7068c2654abSrjs 	if (m->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
7078c2654abSrjs 		struct in6pcb *inp6;
7088c2654abSrjs 
7098c2654abSrjs 
7108c2654abSrjs 		/* Its a V6 socket */
7118c2654abSrjs 		inp6 = (struct in6pcb *)m;
7128c2654abSrjs 		asoc->ipv6_addr_legal = 1;
7138c2654abSrjs 		/* Now look at the binding flag to see if V4 will be legal */
7148c2654abSrjs 	if (
7158c2654abSrjs #if defined(__OpenBSD__)
7168c2654abSrjs 		(0) /* we always do dual bind */
7178c2654abSrjs #elif defined (__NetBSD__)
7188c2654abSrjs 		(inp6->in6p_flags & IN6P_IPV6_V6ONLY)
7198c2654abSrjs #else
7208c2654abSrjs 		(inp6->inp_flags & IN6P_IPV6_V6ONLY)
7218c2654abSrjs #endif
7228c2654abSrjs 	     == 0) {
7238c2654abSrjs 			asoc->ipv4_addr_legal = 1;
7248c2654abSrjs 		} else {
7258c2654abSrjs 			/* V4 addresses are NOT legal on the association */
7268c2654abSrjs 			asoc->ipv4_addr_legal = 0;
7278c2654abSrjs 		}
7288c2654abSrjs 	} else {
7298c2654abSrjs 		/* Its a V4 socket, no - V6 */
7308c2654abSrjs 		asoc->ipv4_addr_legal = 1;
7318c2654abSrjs 		asoc->ipv6_addr_legal = 0;
7328c2654abSrjs 	}
7338c2654abSrjs 
7348c2654abSrjs 
735d1579b2dSriastradh 	asoc->my_rwnd = uimax(m->sctp_socket->so_rcv.sb_hiwat, SCTP_MINIMAL_RWND);
7368c2654abSrjs 	asoc->peers_rwnd = m->sctp_socket->so_rcv.sb_hiwat;
7378c2654abSrjs 
7388c2654abSrjs 	asoc->smallest_mtu = m->sctp_frag_point;
7398c2654abSrjs 	asoc->minrto = m->sctp_ep.sctp_minrto;
7408c2654abSrjs 	asoc->maxrto = m->sctp_ep.sctp_maxrto;
7418c2654abSrjs 
7428c2654abSrjs 	LIST_INIT(&asoc->sctp_local_addr_list);
7438c2654abSrjs 	TAILQ_INIT(&asoc->nets);
7448c2654abSrjs 	TAILQ_INIT(&asoc->pending_reply_queue);
7458c2654abSrjs 	asoc->last_asconf_ack_sent = NULL;
7468c2654abSrjs 	/* Setup to fill the hb random cache at first HB */
7478c2654abSrjs 	asoc->hb_random_idx = 4;
7488c2654abSrjs 
7498c2654abSrjs 	asoc->sctp_autoclose_ticks = m->sctp_ep.auto_close_time;
7508c2654abSrjs 
7518c2654abSrjs 	/*
7528c2654abSrjs 	 * Now the stream parameters, here we allocate space for all
7538c2654abSrjs 	 * streams that we request by default.
7548c2654abSrjs 	 */
7558c2654abSrjs 	asoc->streamoutcnt = asoc->pre_open_streams =
7568c2654abSrjs 	    m->sctp_ep.pre_open_stream_count;
7578c2654abSrjs 	asoc->strmout = malloc(asoc->streamoutcnt *
7588c2654abSrjs 	    sizeof(struct sctp_stream_out), M_PCB, M_NOWAIT);
7598c2654abSrjs 	if (asoc->strmout == NULL) {
7608c2654abSrjs 		/* big trouble no memory */
7618c2654abSrjs 		return (ENOMEM);
7628c2654abSrjs 	}
7638c2654abSrjs 	for (i = 0; i < asoc->streamoutcnt; i++) {
7648c2654abSrjs 		/*
7658c2654abSrjs 		 * inbound side must be set to 0xffff,
7668c2654abSrjs 		 * also NOTE when we get the INIT-ACK back (for INIT sender)
7678c2654abSrjs 		 * we MUST reduce the count (streamoutcnt) but first check
7688c2654abSrjs 		 * if we sent to any of the upper streams that were dropped
7698c2654abSrjs 		 * (if some were). Those that were dropped must be notified
7708c2654abSrjs 		 * to the upper layer as failed to send.
7718c2654abSrjs 		 */
7728c2654abSrjs 		asoc->strmout[i].next_sequence_sent = 0x0;
7738c2654abSrjs 		TAILQ_INIT(&asoc->strmout[i].outqueue);
7748c2654abSrjs 		asoc->strmout[i].stream_no = i;
7758c2654abSrjs 		asoc->strmout[i].next_spoke.tqe_next = 0;
7768c2654abSrjs 		asoc->strmout[i].next_spoke.tqe_prev = 0;
7778c2654abSrjs 	}
7788c2654abSrjs 	/* Now the mapping array */
7798c2654abSrjs 	asoc->mapping_array_size = SCTP_INITIAL_MAPPING_ARRAY;
7808c2654abSrjs 	asoc->mapping_array = malloc(asoc->mapping_array_size,
7818c2654abSrjs 	       M_PCB, M_NOWAIT);
7828c2654abSrjs 	if (asoc->mapping_array == NULL) {
7838c2654abSrjs 		free(asoc->strmout, M_PCB);
7848c2654abSrjs 		return (ENOMEM);
7858c2654abSrjs 	}
7868c2654abSrjs 	memset(asoc->mapping_array, 0, asoc->mapping_array_size);
7878c2654abSrjs 	/* Now the init of the other outqueues */
7888c2654abSrjs 	TAILQ_INIT(&asoc->out_wheel);
7898c2654abSrjs 	TAILQ_INIT(&asoc->control_send_queue);
7908c2654abSrjs 	TAILQ_INIT(&asoc->send_queue);
7918c2654abSrjs 	TAILQ_INIT(&asoc->sent_queue);
7928c2654abSrjs 	TAILQ_INIT(&asoc->reasmqueue);
7938c2654abSrjs 	TAILQ_INIT(&asoc->delivery_queue);
7948c2654abSrjs 	asoc->max_inbound_streams = m->sctp_ep.max_open_streams_intome;
7958c2654abSrjs 
7968c2654abSrjs 	TAILQ_INIT(&asoc->asconf_queue);
7978c2654abSrjs 	return (0);
7988c2654abSrjs }
7998c2654abSrjs 
8008c2654abSrjs int
sctp_expand_mapping_array(struct sctp_association * asoc)8018c2654abSrjs sctp_expand_mapping_array(struct sctp_association *asoc)
8028c2654abSrjs {
8038c2654abSrjs 	/* mapping array needs to grow */
8048c2654abSrjs 	u_int8_t *new_array;
8056228dc51Schristos 	uint16_t new_size, old_size;
8068c2654abSrjs 
8076228dc51Schristos 	old_size = asoc->mapping_array_size;
8086228dc51Schristos 	new_size = old_size + SCTP_MAPPING_ARRAY_INCR;
8098c2654abSrjs 	new_array = malloc(new_size, M_PCB, M_NOWAIT);
8108c2654abSrjs 	if (new_array == NULL) {
8118c2654abSrjs 		/* can't get more, forget it */
8128c2654abSrjs 		printf("No memory for expansion of SCTP mapping array %d\n",
8138c2654abSrjs 		       new_size);
8148c2654abSrjs 		return (-1);
8158c2654abSrjs 	}
8166228dc51Schristos 	memcpy(new_array, asoc->mapping_array, old_size);
8176228dc51Schristos 	memset(new_array + old_size, 0, SCTP_MAPPING_ARRAY_INCR);
8188c2654abSrjs 	free(asoc->mapping_array, M_PCB);
8198c2654abSrjs 	asoc->mapping_array = new_array;
8208c2654abSrjs 	asoc->mapping_array_size = new_size;
8218c2654abSrjs 	return (0);
8228c2654abSrjs }
8238c2654abSrjs 
8248c2654abSrjs static void
sctp_timeout_handler(void * t)8258c2654abSrjs sctp_timeout_handler(void *t)
8268c2654abSrjs {
8278c2654abSrjs 	struct sctp_inpcb *inp;
8288c2654abSrjs 	struct sctp_tcb *stcb;
8298c2654abSrjs 	struct sctp_nets *net;
8308c2654abSrjs 	struct sctp_timer *tmr;
8318c2654abSrjs 	int did_output;
8328c2654abSrjs 
8338c2654abSrjs 	mutex_enter(softnet_lock);
8348c2654abSrjs 	tmr = (struct sctp_timer *)t;
8358c2654abSrjs 	inp = (struct sctp_inpcb *)tmr->ep;
8368c2654abSrjs 	stcb = (struct sctp_tcb *)tmr->tcb;
8378c2654abSrjs 	net = (struct sctp_nets *)tmr->net;
8388c2654abSrjs 	did_output = 1;
8398c2654abSrjs 
8408c2654abSrjs #ifdef SCTP_AUDITING_ENABLED
8418c2654abSrjs 	sctp_audit_log(0xF0, (u_int8_t)tmr->type);
8428c2654abSrjs 	sctp_auditing(3, inp, stcb, net);
8438c2654abSrjs #endif
8448c2654abSrjs 	sctp_pegs[SCTP_TIMERS_EXP]++;
8458c2654abSrjs 
8468c2654abSrjs 	if (inp == NULL) {
8478c2654abSrjs 		return;
8488c2654abSrjs 	}
8498c2654abSrjs 
8508c2654abSrjs 	SCTP_INP_WLOCK(inp);
8518c2654abSrjs 	if (inp->sctp_socket == 0) {
8528c2654abSrjs 		mutex_exit(softnet_lock);
8538c2654abSrjs 		SCTP_INP_WUNLOCK(inp);
8548c2654abSrjs 		return;
8558c2654abSrjs 	}
8568c2654abSrjs 	if (stcb) {
8578c2654abSrjs 		if (stcb->asoc.state == 0) {
8588c2654abSrjs 			mutex_exit(softnet_lock);
8598c2654abSrjs 			SCTP_INP_WUNLOCK(inp);
8608c2654abSrjs 			return;
8618c2654abSrjs 		}
8628c2654abSrjs 	}
8638c2654abSrjs #ifdef SCTP_DEBUG
8648c2654abSrjs 	if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
8658c2654abSrjs 		printf("Timer type %d goes off\n", tmr->type);
8668c2654abSrjs 	}
8678c2654abSrjs #endif /* SCTP_DEBUG */
8688c2654abSrjs #ifndef __NetBSD__
8698c2654abSrjs 	if (!callout_active(&tmr->timer)) {
8708c2654abSrjs 		SCTP_INP_WUNLOCK(inp);
8718c2654abSrjs 		return;
8728c2654abSrjs 	}
8738c2654abSrjs #endif
8748c2654abSrjs 	if (stcb) {
8758c2654abSrjs 		SCTP_TCB_LOCK(stcb);
8768c2654abSrjs 	}
8778c2654abSrjs 	SCTP_INP_INCR_REF(inp);
8788c2654abSrjs 	SCTP_INP_WUNLOCK(inp);
8798c2654abSrjs 
8808c2654abSrjs 	switch (tmr->type) {
8818c2654abSrjs 	case SCTP_TIMER_TYPE_ITERATOR:
8828c2654abSrjs 	{
8838c2654abSrjs 		struct sctp_iterator *it;
8848c2654abSrjs 		it = (struct sctp_iterator *)inp;
8858c2654abSrjs 		sctp_iterator_timer(it);
8868c2654abSrjs 	}
8878c2654abSrjs 	break;
8888c2654abSrjs 	/* call the handler for the appropriate timer type */
8898c2654abSrjs 	case SCTP_TIMER_TYPE_SEND:
8908c2654abSrjs 		sctp_pegs[SCTP_TMIT_TIMER]++;
8918c2654abSrjs 		stcb->asoc.num_send_timers_up--;
8928c2654abSrjs 		if (stcb->asoc.num_send_timers_up < 0) {
8938c2654abSrjs 			stcb->asoc.num_send_timers_up = 0;
8948c2654abSrjs 		}
8958c2654abSrjs 		if (sctp_t3rxt_timer(inp, stcb, net)) {
8968c2654abSrjs 			/* no need to unlock on tcb its gone */
8978c2654abSrjs 
8988c2654abSrjs 			goto out_decr;
8998c2654abSrjs 		}
9008c2654abSrjs #ifdef SCTP_AUDITING_ENABLED
9018c2654abSrjs 		sctp_auditing(4, inp, stcb, net);
9028c2654abSrjs #endif
9038c2654abSrjs 		sctp_chunk_output(inp, stcb, 1);
9048c2654abSrjs 		if ((stcb->asoc.num_send_timers_up == 0) &&
9058c2654abSrjs 		    (stcb->asoc.sent_queue_cnt > 0)
9068c2654abSrjs 			) {
9078c2654abSrjs 			struct sctp_tmit_chunk *chk;
9088c2654abSrjs 			/*
9098c2654abSrjs 			 * safeguard. If there on some on the sent queue
9108c2654abSrjs 			 * somewhere but no timers running something is
9118c2654abSrjs 			 * wrong... so we start a timer on the first chunk
9128c2654abSrjs 			 * on the send queue on whatever net it is sent to.
9138c2654abSrjs 			 */
9148c2654abSrjs 			sctp_pegs[SCTP_T3_SAFEGRD]++;
9158c2654abSrjs 			chk = TAILQ_FIRST(&stcb->asoc.sent_queue);
9168c2654abSrjs 			sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb,
9178c2654abSrjs 					 chk->whoTo);
9188c2654abSrjs 		}
9198c2654abSrjs 		break;
9208c2654abSrjs 	case SCTP_TIMER_TYPE_INIT:
9218c2654abSrjs 		if (sctp_t1init_timer(inp, stcb, net)) {
9228c2654abSrjs 			/* no need to unlock on tcb its gone */
9238c2654abSrjs 			goto out_decr;
9248c2654abSrjs 		}
9258c2654abSrjs 		/* We do output but not here */
9268c2654abSrjs 		did_output = 0;
9278c2654abSrjs 		break;
9288c2654abSrjs 	case SCTP_TIMER_TYPE_RECV:
9298c2654abSrjs 		sctp_pegs[SCTP_RECV_TIMER]++;
9308c2654abSrjs 		sctp_send_sack(stcb);
9318c2654abSrjs #ifdef SCTP_AUDITING_ENABLED
9328c2654abSrjs 		sctp_auditing(4, inp, stcb, net);
9338c2654abSrjs #endif
9348c2654abSrjs 		sctp_chunk_output(inp, stcb, 4);
9358c2654abSrjs 		break;
9368c2654abSrjs 	case SCTP_TIMER_TYPE_SHUTDOWN:
9378c2654abSrjs 		if (sctp_shutdown_timer(inp, stcb, net) ) {
9388c2654abSrjs 			/* no need to unlock on tcb its gone */
9398c2654abSrjs 			goto out_decr;
9408c2654abSrjs 		}
9418c2654abSrjs #ifdef SCTP_AUDITING_ENABLED
9428c2654abSrjs 		sctp_auditing(4, inp, stcb, net);
9438c2654abSrjs #endif
9448c2654abSrjs 		sctp_chunk_output(inp, stcb, 5);
9458c2654abSrjs 		break;
9468c2654abSrjs 	case SCTP_TIMER_TYPE_HEARTBEAT:
9478c2654abSrjs 		if (sctp_heartbeat_timer(inp, stcb, net)) {
9488c2654abSrjs 			/* no need to unlock on tcb its gone */
9498c2654abSrjs 			goto out_decr;
9508c2654abSrjs 		}
9518c2654abSrjs #ifdef SCTP_AUDITING_ENABLED
9528c2654abSrjs 		sctp_auditing(4, inp, stcb, net);
9538c2654abSrjs #endif
9548c2654abSrjs 		sctp_chunk_output(inp, stcb, 6);
9558c2654abSrjs 		break;
9568c2654abSrjs 	case SCTP_TIMER_TYPE_COOKIE:
9578c2654abSrjs 		if (sctp_cookie_timer(inp, stcb, net)) {
9588c2654abSrjs 			/* no need to unlock on tcb its gone */
9598c2654abSrjs 			goto out_decr;
9608c2654abSrjs 		}
9618c2654abSrjs #ifdef SCTP_AUDITING_ENABLED
9628c2654abSrjs 		sctp_auditing(4, inp, stcb, net);
9638c2654abSrjs #endif
9648c2654abSrjs 		sctp_chunk_output(inp, stcb, 1);
9658c2654abSrjs 		break;
9668c2654abSrjs 	case SCTP_TIMER_TYPE_NEWCOOKIE:
9678c2654abSrjs 	{
9688c2654abSrjs 		struct timeval tv;
9698c2654abSrjs 		int i, secret;
9708c2654abSrjs 		SCTP_GETTIME_TIMEVAL(&tv);
9718c2654abSrjs 		SCTP_INP_WLOCK(inp);
9728c2654abSrjs 		inp->sctp_ep.time_of_secret_change = tv.tv_sec;
9738c2654abSrjs 		inp->sctp_ep.last_secret_number =
9748c2654abSrjs 			inp->sctp_ep.current_secret_number;
9758c2654abSrjs 		inp->sctp_ep.current_secret_number++;
9768c2654abSrjs 		if (inp->sctp_ep.current_secret_number >=
9778c2654abSrjs 		    SCTP_HOW_MANY_SECRETS) {
9788c2654abSrjs 			inp->sctp_ep.current_secret_number = 0;
9798c2654abSrjs 		}
9808c2654abSrjs 		secret = (int)inp->sctp_ep.current_secret_number;
9818c2654abSrjs 		for (i = 0; i < SCTP_NUMBER_OF_SECRETS; i++) {
9828c2654abSrjs 			inp->sctp_ep.secret_key[secret][i] =
9838c2654abSrjs 				sctp_select_initial_TSN(&inp->sctp_ep);
9848c2654abSrjs 		}
9858c2654abSrjs 		SCTP_INP_WUNLOCK(inp);
9868c2654abSrjs 		sctp_timer_start(SCTP_TIMER_TYPE_NEWCOOKIE, inp, stcb, net);
9878c2654abSrjs 	}
9888c2654abSrjs 	did_output = 0;
9898c2654abSrjs 	break;
9908c2654abSrjs 	case SCTP_TIMER_TYPE_PATHMTURAISE:
9918c2654abSrjs 		sctp_pathmtu_timer(inp, stcb, net);
9928c2654abSrjs 		did_output = 0;
9938c2654abSrjs 		break;
9948c2654abSrjs 	case SCTP_TIMER_TYPE_SHUTDOWNACK:
9958c2654abSrjs 		if (sctp_shutdownack_timer(inp, stcb, net)) {
9968c2654abSrjs 			/* no need to unlock on tcb its gone */
9978c2654abSrjs 			goto out_decr;
9988c2654abSrjs 		}
9998c2654abSrjs #ifdef SCTP_AUDITING_ENABLED
10008c2654abSrjs 		sctp_auditing(4, inp, stcb, net);
10018c2654abSrjs #endif
10028c2654abSrjs 		sctp_chunk_output(inp, stcb, 7);
10038c2654abSrjs 		break;
10048c2654abSrjs 	case SCTP_TIMER_TYPE_SHUTDOWNGUARD:
10058c2654abSrjs 		sctp_abort_an_association(inp, stcb,
10068c2654abSrjs 					  SCTP_SHUTDOWN_GUARD_EXPIRES, NULL);
10078c2654abSrjs 		/* no need to unlock on tcb its gone */
10088c2654abSrjs 		goto out_decr;
10098c2654abSrjs 		break;
10108c2654abSrjs 
10118c2654abSrjs 	case SCTP_TIMER_TYPE_STRRESET:
10128c2654abSrjs 		if (sctp_strreset_timer(inp, stcb, net)) {
10138c2654abSrjs 			/* no need to unlock on tcb its gone */
10148c2654abSrjs 			goto out_decr;
10158c2654abSrjs 		}
10168c2654abSrjs 		sctp_chunk_output(inp, stcb, 9);
10178c2654abSrjs 		break;
10188c2654abSrjs 
10198c2654abSrjs 	case SCTP_TIMER_TYPE_ASCONF:
10208c2654abSrjs 		if (sctp_asconf_timer(inp, stcb, net)) {
10218c2654abSrjs 			/* no need to unlock on tcb its gone */
10228c2654abSrjs 			goto out_decr;
10238c2654abSrjs 		}
10248c2654abSrjs #ifdef SCTP_AUDITING_ENABLED
10258c2654abSrjs 		sctp_auditing(4, inp, stcb, net);
10268c2654abSrjs #endif
10278c2654abSrjs 		sctp_chunk_output(inp, stcb, 8);
10288c2654abSrjs 		break;
10298c2654abSrjs 
10308c2654abSrjs 	case SCTP_TIMER_TYPE_AUTOCLOSE:
10318c2654abSrjs 		sctp_autoclose_timer(inp, stcb, net);
10328c2654abSrjs 		sctp_chunk_output(inp, stcb, 10);
10338c2654abSrjs 		did_output = 0;
10348c2654abSrjs 		break;
10358c2654abSrjs 	case SCTP_TIMER_TYPE_INPKILL:
10368c2654abSrjs 		/* special case, take away our
10378c2654abSrjs 		 * increment since WE are the killer
10388c2654abSrjs 		 */
10398c2654abSrjs 		SCTP_INP_WLOCK(inp);
10408c2654abSrjs 		SCTP_INP_DECR_REF(inp);
10418c2654abSrjs 		SCTP_INP_WUNLOCK(inp);
10428c2654abSrjs 		sctp_timer_stop(SCTP_TIMER_TYPE_INPKILL, inp, NULL, NULL);
10438c2654abSrjs 		sctp_inpcb_free(inp, 1);
10448c2654abSrjs 		goto out_no_decr;
10458c2654abSrjs 		break;
10468c2654abSrjs 	default:
10478c2654abSrjs #ifdef SCTP_DEBUG
10488c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
10498c2654abSrjs 			printf("sctp_timeout_handler:unknown timer %d\n",
10508c2654abSrjs 			       tmr->type);
10518c2654abSrjs 		}
10528c2654abSrjs #endif /* SCTP_DEBUG */
10538c2654abSrjs 		break;
10548c2654abSrjs 	};
10558c2654abSrjs #ifdef SCTP_AUDITING_ENABLED
10568c2654abSrjs 	sctp_audit_log(0xF1, (u_int8_t)tmr->type);
10578c2654abSrjs 	sctp_auditing(5, inp, stcb, net);
10588c2654abSrjs #endif
10598c2654abSrjs 	if (did_output) {
10608c2654abSrjs 		/*
10618c2654abSrjs 		 * Now we need to clean up the control chunk chain if an
10628c2654abSrjs 		 * ECNE is on it. It must be marked as UNSENT again so next
10638c2654abSrjs 		 * call will continue to send it until such time that we get
10648c2654abSrjs 		 * a CWR, to remove it. It is, however, less likely that we
10658c2654abSrjs 		 * will find a ecn echo on the chain though.
10668c2654abSrjs 		 */
10678c2654abSrjs 		sctp_fix_ecn_echo(&stcb->asoc);
10688c2654abSrjs 	}
10698c2654abSrjs 	if (stcb) {
10708c2654abSrjs 		SCTP_TCB_UNLOCK(stcb);
10718c2654abSrjs 	}
10728c2654abSrjs  out_decr:
10738c2654abSrjs 	SCTP_INP_WLOCK(inp);
10748c2654abSrjs 	SCTP_INP_DECR_REF(inp);
10758c2654abSrjs 	SCTP_INP_WUNLOCK(inp);
10768c2654abSrjs 
10778c2654abSrjs  out_no_decr:
10788c2654abSrjs 
10798c2654abSrjs 	mutex_exit(softnet_lock);
10808c2654abSrjs }
10818c2654abSrjs 
10828c2654abSrjs int
sctp_timer_start(int t_type,struct sctp_inpcb * inp,struct sctp_tcb * stcb,struct sctp_nets * net)10838c2654abSrjs sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
10848c2654abSrjs     struct sctp_nets *net)
10858c2654abSrjs {
10868c2654abSrjs 	int to_ticks;
10878c2654abSrjs 	struct sctp_timer *tmr;
10888c2654abSrjs 
10898c2654abSrjs 	if (inp == NULL)
10908c2654abSrjs 		return (EFAULT);
10918c2654abSrjs 
10928c2654abSrjs 	to_ticks = 0;
10938c2654abSrjs 
10948c2654abSrjs 	tmr = NULL;
10958c2654abSrjs 	switch (t_type) {
10968c2654abSrjs 	case SCTP_TIMER_TYPE_ITERATOR:
10978c2654abSrjs 	{
10988c2654abSrjs 		struct sctp_iterator *it;
10998c2654abSrjs 		it = (struct sctp_iterator *)inp;
11008c2654abSrjs 		tmr = &it->tmr;
11018c2654abSrjs 		to_ticks = SCTP_ITERATOR_TICKS;
11028c2654abSrjs 	}
11038c2654abSrjs 	break;
11048c2654abSrjs 	case SCTP_TIMER_TYPE_SEND:
11058c2654abSrjs 		/* Here we use the RTO timer */
11068c2654abSrjs 	{
11078c2654abSrjs 		int rto_val;
11088c2654abSrjs 		if ((stcb == NULL) || (net == NULL)) {
11098c2654abSrjs 			return (EFAULT);
11108c2654abSrjs 		}
11118c2654abSrjs 		tmr = &net->rxt_timer;
11128c2654abSrjs 		if (net->RTO == 0) {
11138c2654abSrjs 			rto_val = stcb->asoc.initial_rto;
11148c2654abSrjs 		} else {
11158c2654abSrjs 			rto_val = net->RTO;
11168c2654abSrjs 		}
11178c2654abSrjs 		to_ticks = MSEC_TO_TICKS(rto_val);
11188c2654abSrjs 	}
11198c2654abSrjs 	break;
11208c2654abSrjs 	case SCTP_TIMER_TYPE_INIT:
11218c2654abSrjs 		/*
11228c2654abSrjs 		 * Here we use the INIT timer default
11238c2654abSrjs 		 * usually about 1 minute.
11248c2654abSrjs 		 */
11258c2654abSrjs 		if ((stcb == NULL) || (net == NULL)) {
11268c2654abSrjs 			return (EFAULT);
11278c2654abSrjs 		}
11288c2654abSrjs 		tmr = &net->rxt_timer;
11298c2654abSrjs 		if (net->RTO == 0) {
11308c2654abSrjs 			to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
11318c2654abSrjs 		} else {
11328c2654abSrjs 			to_ticks = MSEC_TO_TICKS(net->RTO);
11338c2654abSrjs 		}
11348c2654abSrjs 		break;
11358c2654abSrjs 	case SCTP_TIMER_TYPE_RECV:
11368c2654abSrjs 		/*
11378c2654abSrjs 		 * Here we use the Delayed-Ack timer value from the inp
11388c2654abSrjs 		 * ususually about 200ms.
11398c2654abSrjs 		 */
11408c2654abSrjs 		if (stcb == NULL) {
11418c2654abSrjs 			return (EFAULT);
11428c2654abSrjs 		}
11438c2654abSrjs 		tmr = &stcb->asoc.dack_timer;
11448c2654abSrjs 		to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV];
11458c2654abSrjs 		break;
11468c2654abSrjs 	case SCTP_TIMER_TYPE_SHUTDOWN:
11478c2654abSrjs 		/* Here we use the RTO of the destination. */
11488c2654abSrjs 		if ((stcb == NULL) || (net == NULL)) {
11498c2654abSrjs 			return (EFAULT);
11508c2654abSrjs 		}
11518c2654abSrjs 
11528c2654abSrjs 		if (net->RTO == 0) {
11538c2654abSrjs 			to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
11548c2654abSrjs 		} else {
11558c2654abSrjs 			to_ticks = MSEC_TO_TICKS(net->RTO);
11568c2654abSrjs 		}
11578c2654abSrjs 		tmr = &net->rxt_timer;
11588c2654abSrjs 		break;
11598c2654abSrjs 	case SCTP_TIMER_TYPE_HEARTBEAT:
11608c2654abSrjs 		/*
11618c2654abSrjs 		 * the net is used here so that we can add in the RTO.
11628c2654abSrjs 		 * Even though we use a different timer. We also add the
11638c2654abSrjs 		 * HB timer PLUS a random jitter.
11648c2654abSrjs 		 */
11658c2654abSrjs 		if (stcb == NULL) {
11668c2654abSrjs 			return (EFAULT);
11678c2654abSrjs 		}
11688c2654abSrjs 		{
11698c2654abSrjs 			uint32_t rndval;
11708c2654abSrjs 			uint8_t this_random;
11718c2654abSrjs 			int cnt_of_unconf=0;
11728c2654abSrjs 			struct sctp_nets *lnet;
11738c2654abSrjs 
11748c2654abSrjs 			TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
11758c2654abSrjs 				if (lnet->dest_state & SCTP_ADDR_UNCONFIRMED) {
11768c2654abSrjs 					cnt_of_unconf++;
11778c2654abSrjs 				}
11788c2654abSrjs 			}
11798c2654abSrjs #ifdef SCTP_DEBUG
11808c2654abSrjs 			if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
11818c2654abSrjs 				printf("HB timer to start unconfirmed:%d hb_delay:%d\n",
11828c2654abSrjs 				       cnt_of_unconf, stcb->asoc.heart_beat_delay);
11838c2654abSrjs 			}
11848c2654abSrjs #endif
11858c2654abSrjs 			if (stcb->asoc.hb_random_idx > 3) {
11868c2654abSrjs 				rndval = sctp_select_initial_TSN(&inp->sctp_ep);
11878c2654abSrjs 				memcpy(stcb->asoc.hb_random_values, &rndval,
11888c2654abSrjs 				       sizeof(stcb->asoc.hb_random_values));
11898c2654abSrjs 				this_random = stcb->asoc.hb_random_values[0];
11908c2654abSrjs 				stcb->asoc.hb_random_idx = 0;
11918c2654abSrjs 				stcb->asoc.hb_ect_randombit = 0;
11928c2654abSrjs 			} else {
11938c2654abSrjs 				this_random = stcb->asoc.hb_random_values[stcb->asoc.hb_random_idx];
11948c2654abSrjs 				stcb->asoc.hb_random_idx++;
11958c2654abSrjs 				stcb->asoc.hb_ect_randombit = 0;
11968c2654abSrjs 			}
11978c2654abSrjs 			/*
11988c2654abSrjs 			 * this_random will be 0 - 256 ms
11998c2654abSrjs 			 * RTO is in ms.
12008c2654abSrjs 			 */
12018c2654abSrjs 			if ((stcb->asoc.heart_beat_delay == 0) &&
12028c2654abSrjs 			    (cnt_of_unconf == 0)) {
12038c2654abSrjs 				/* no HB on this inp after confirmations */
12048c2654abSrjs 				return (0);
12058c2654abSrjs 			}
12068c2654abSrjs 			if (net) {
12078c2654abSrjs 				int delay;
12088c2654abSrjs 				delay = stcb->asoc.heart_beat_delay;
12098c2654abSrjs 				TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
12108c2654abSrjs 					if ((lnet->dest_state & SCTP_ADDR_UNCONFIRMED) &&
12118c2654abSrjs 					    ((lnet->dest_state & SCTP_ADDR_OUT_OF_SCOPE) == 0) &&
12128c2654abSrjs 					    (lnet->dest_state & SCTP_ADDR_REACHABLE)) {
12138c2654abSrjs 					    delay = 0;
12148c2654abSrjs 					}
12158c2654abSrjs 				}
12168c2654abSrjs 				if (net->RTO == 0) {
12178c2654abSrjs 					/* Never been checked */
12188c2654abSrjs 					to_ticks = this_random + stcb->asoc.initial_rto + delay;
12198c2654abSrjs 				} else {
12208c2654abSrjs 					/* set rto_val to the ms */
12218c2654abSrjs 					to_ticks = delay + net->RTO + this_random;
12228c2654abSrjs 				}
12238c2654abSrjs 			} else {
12248c2654abSrjs 				if (cnt_of_unconf) {
12258c2654abSrjs 					to_ticks = this_random + stcb->asoc.initial_rto;
12268c2654abSrjs 				} else {
12278c2654abSrjs 					to_ticks = stcb->asoc.heart_beat_delay + this_random + stcb->asoc.initial_rto;
12288c2654abSrjs 				}
12298c2654abSrjs 			}
12308c2654abSrjs 			/*
12318c2654abSrjs 			 * Now we must convert the to_ticks that are now in
12328c2654abSrjs 			 * ms to ticks.
12338c2654abSrjs 			 */
12348c2654abSrjs 			to_ticks *= hz;
12358c2654abSrjs 			to_ticks /= 1000;
12368c2654abSrjs #ifdef SCTP_DEBUG
12378c2654abSrjs 			if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
12388c2654abSrjs 				printf("Timer to expire in %d ticks\n", to_ticks);
12398c2654abSrjs 			}
12408c2654abSrjs #endif
12418c2654abSrjs 			tmr = &stcb->asoc.hb_timer;
12428c2654abSrjs 		}
12438c2654abSrjs 		break;
12448c2654abSrjs 	case SCTP_TIMER_TYPE_COOKIE:
12458c2654abSrjs 		/*
12468c2654abSrjs 		 * Here we can use the RTO timer from the network since
12478c2654abSrjs 		 * one RTT was compelete. If a retran happened then we will
12488c2654abSrjs 		 * be using the RTO initial value.
12498c2654abSrjs 		 */
12508c2654abSrjs 		if ((stcb == NULL) || (net == NULL)) {
12518c2654abSrjs 			return (EFAULT);
12528c2654abSrjs 		}
12538c2654abSrjs 		if (net->RTO == 0) {
12548c2654abSrjs 			to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
12558c2654abSrjs 		} else {
12568c2654abSrjs 			to_ticks = MSEC_TO_TICKS(net->RTO);
12578c2654abSrjs 		}
12588c2654abSrjs 		tmr = &net->rxt_timer;
12598c2654abSrjs 		break;
12608c2654abSrjs 	case SCTP_TIMER_TYPE_NEWCOOKIE:
12618c2654abSrjs 		/*
12628c2654abSrjs 		 * nothing needed but the endpoint here
12638c2654abSrjs 		 * ususually about 60 minutes.
12648c2654abSrjs 		 */
12658c2654abSrjs 		tmr = &inp->sctp_ep.signature_change;
12668c2654abSrjs 		to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_SIGNATURE];
12678c2654abSrjs 		break;
12688c2654abSrjs 	case SCTP_TIMER_TYPE_INPKILL:
12698c2654abSrjs 		/*
12708c2654abSrjs 		 * The inp is setup to die. We re-use the
12717991f5a7Sandvar 		 * signature_change timer since that has
12728c2654abSrjs 		 * stopped and we are in the GONE state.
12738c2654abSrjs 		 */
12748c2654abSrjs 		tmr = &inp->sctp_ep.signature_change;
12758c2654abSrjs 		to_ticks = (SCTP_INP_KILL_TIMEOUT * hz) / 1000;
12768c2654abSrjs 		break;
12778c2654abSrjs 	case SCTP_TIMER_TYPE_PATHMTURAISE:
12788c2654abSrjs 		/*
12798c2654abSrjs 		 * Here we use the value found in the EP for PMTU
12808c2654abSrjs 		 * ususually about 10 minutes.
12818c2654abSrjs 		 */
12828c2654abSrjs 		if (stcb == NULL) {
12838c2654abSrjs 			return (EFAULT);
12848c2654abSrjs 		}
12858c2654abSrjs 		if (net == NULL) {
12868c2654abSrjs 			return (EFAULT);
12878c2654abSrjs 		}
12888c2654abSrjs 		to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_PMTU];
12898c2654abSrjs 		tmr = &net->pmtu_timer;
12908c2654abSrjs 		break;
12918c2654abSrjs 	case SCTP_TIMER_TYPE_SHUTDOWNACK:
12928c2654abSrjs 		/* Here we use the RTO of the destination */
12938c2654abSrjs 		if ((stcb == NULL) || (net == NULL)) {
12948c2654abSrjs 			return (EFAULT);
12958c2654abSrjs 		}
12968c2654abSrjs 		if (net->RTO == 0) {
12978c2654abSrjs 			to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
12988c2654abSrjs 		} else {
12998c2654abSrjs 			to_ticks = MSEC_TO_TICKS(net->RTO);
13008c2654abSrjs 		}
13018c2654abSrjs 		tmr = &net->rxt_timer;
13028c2654abSrjs 		break;
13038c2654abSrjs 	case SCTP_TIMER_TYPE_SHUTDOWNGUARD:
13048c2654abSrjs 		/*
13058c2654abSrjs 		 * Here we use the endpoints shutdown guard timer
13068c2654abSrjs 		 * usually about 3 minutes.
13078c2654abSrjs 		 */
13088c2654abSrjs 		if (stcb == NULL) {
13098c2654abSrjs 			return (EFAULT);
13108c2654abSrjs 		}
13118c2654abSrjs 		to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_MAXSHUTDOWN];
13128c2654abSrjs 		tmr = &stcb->asoc.shut_guard_timer;
13138c2654abSrjs 		break;
13148c2654abSrjs 	case SCTP_TIMER_TYPE_STRRESET:
13158c2654abSrjs 		/*
13168c2654abSrjs 		 * Here the timer comes from the inp
13178c2654abSrjs 		 * but its value is from the RTO.
13188c2654abSrjs 		 */
13198c2654abSrjs 		if ((stcb == NULL) || (net == NULL)) {
13208c2654abSrjs 			return (EFAULT);
13218c2654abSrjs 		}
13228c2654abSrjs 		if (net->RTO == 0) {
13238c2654abSrjs 			to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
13248c2654abSrjs 		} else {
13258c2654abSrjs 			to_ticks = MSEC_TO_TICKS(net->RTO);
13268c2654abSrjs 		}
13278c2654abSrjs 		tmr = &stcb->asoc.strreset_timer;
13288c2654abSrjs 		break;
13298c2654abSrjs 
13308c2654abSrjs 	case SCTP_TIMER_TYPE_ASCONF:
13318c2654abSrjs 		/*
13328c2654abSrjs 		 * Here the timer comes from the inp
13338c2654abSrjs 		 * but its value is from the RTO.
13348c2654abSrjs 		 */
13358c2654abSrjs 		if ((stcb == NULL) || (net == NULL)) {
13368c2654abSrjs 			return (EFAULT);
13378c2654abSrjs 		}
13388c2654abSrjs 		if (net->RTO == 0) {
13398c2654abSrjs 			to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
13408c2654abSrjs 		} else {
13418c2654abSrjs 			to_ticks = MSEC_TO_TICKS(net->RTO);
13428c2654abSrjs 		}
13438c2654abSrjs 		tmr = &stcb->asoc.asconf_timer;
13448c2654abSrjs 		break;
13458c2654abSrjs 	case SCTP_TIMER_TYPE_AUTOCLOSE:
13468c2654abSrjs 		if (stcb == NULL) {
13478c2654abSrjs 			return (EFAULT);
13488c2654abSrjs 		}
13498c2654abSrjs 		if (stcb->asoc.sctp_autoclose_ticks == 0) {
13508c2654abSrjs 			/* Really an error since stcb is NOT set to autoclose */
13518c2654abSrjs 			return (0);
13528c2654abSrjs 		}
13538c2654abSrjs 		to_ticks = stcb->asoc.sctp_autoclose_ticks;
13548c2654abSrjs 		tmr = &stcb->asoc.autoclose_timer;
13558c2654abSrjs 		break;
13568c2654abSrjs 	default:
13578c2654abSrjs #ifdef SCTP_DEBUG
13588c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
13598c2654abSrjs 			printf("sctp_timer_start:Unknown timer type %d\n",
13608c2654abSrjs 			       t_type);
13618c2654abSrjs 		}
13628c2654abSrjs #endif /* SCTP_DEBUG */
13638c2654abSrjs 		return (EFAULT);
13648c2654abSrjs 		break;
13658c2654abSrjs 	};
13668c2654abSrjs 	if ((to_ticks <= 0) || (tmr == NULL)) {
13678c2654abSrjs #ifdef SCTP_DEBUG
13688c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
13698c2654abSrjs 			printf("sctp_timer_start:%d:software error to_ticks:%d tmr:%p not set ??\n",
13708c2654abSrjs 			       t_type, to_ticks, tmr);
13718c2654abSrjs 		}
13728c2654abSrjs #endif /* SCTP_DEBUG */
13738c2654abSrjs 		return (EFAULT);
13748c2654abSrjs 	}
13758c2654abSrjs 	if (callout_pending(&tmr->timer)) {
13768c2654abSrjs 		/*
13778c2654abSrjs 		 * we do NOT allow you to have it already running.
13788c2654abSrjs 		 * if it is we leave the current one up unchanged
13798c2654abSrjs 		 */
13808c2654abSrjs 		return (EALREADY);
13818c2654abSrjs 	}
13828c2654abSrjs 	/* At this point we can proceed */
13838c2654abSrjs 	if (t_type == SCTP_TIMER_TYPE_SEND) {
13848c2654abSrjs 		stcb->asoc.num_send_timers_up++;
13858c2654abSrjs 	}
13868c2654abSrjs 	tmr->type = t_type;
13878c2654abSrjs 	tmr->ep = (void *)inp;
13888c2654abSrjs 	tmr->tcb = (void *)stcb;
13898c2654abSrjs 	tmr->net = (void *)net;
13908c2654abSrjs 	callout_reset(&tmr->timer, to_ticks, sctp_timeout_handler, tmr);
13918c2654abSrjs 	return (0);
13928c2654abSrjs }
13938c2654abSrjs 
13948c2654abSrjs int
sctp_timer_stop(int t_type,struct sctp_inpcb * inp,struct sctp_tcb * stcb,struct sctp_nets * net)13958c2654abSrjs sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
13968c2654abSrjs 		struct sctp_nets *net)
13978c2654abSrjs {
13988c2654abSrjs 	struct sctp_timer *tmr;
13998c2654abSrjs 
14008c2654abSrjs 	if (inp == NULL)
14018c2654abSrjs 		return (EFAULT);
14028c2654abSrjs 
14038c2654abSrjs 	tmr = NULL;
14048c2654abSrjs 	switch (t_type) {
14058c2654abSrjs 	case SCTP_TIMER_TYPE_ITERATOR:
14068c2654abSrjs 	{
14078c2654abSrjs 		struct sctp_iterator *it;
14088c2654abSrjs 		it = (struct sctp_iterator *)inp;
14098c2654abSrjs 		tmr = &it->tmr;
14108c2654abSrjs 	}
14118c2654abSrjs 	break;
14128c2654abSrjs 	case SCTP_TIMER_TYPE_SEND:
14138c2654abSrjs 		if ((stcb == NULL) || (net == NULL)) {
14148c2654abSrjs 			return (EFAULT);
14158c2654abSrjs 		}
14168c2654abSrjs 		tmr = &net->rxt_timer;
14178c2654abSrjs 		break;
14188c2654abSrjs 	case SCTP_TIMER_TYPE_INIT:
14198c2654abSrjs 		if ((stcb == NULL) || (net == NULL)) {
14208c2654abSrjs 			return (EFAULT);
14218c2654abSrjs 		}
14228c2654abSrjs 		tmr = &net->rxt_timer;
14238c2654abSrjs 		break;
14248c2654abSrjs 	case SCTP_TIMER_TYPE_RECV:
14258c2654abSrjs 		if (stcb == NULL) {
14268c2654abSrjs 			return (EFAULT);
14278c2654abSrjs 		}
14288c2654abSrjs 		tmr = &stcb->asoc.dack_timer;
14298c2654abSrjs 		break;
14308c2654abSrjs 	case SCTP_TIMER_TYPE_SHUTDOWN:
14318c2654abSrjs 		if ((stcb == NULL) || (net == NULL)) {
14328c2654abSrjs 			return (EFAULT);
14338c2654abSrjs 		}
14348c2654abSrjs 		tmr = &net->rxt_timer;
14358c2654abSrjs 		break;
14368c2654abSrjs 	case SCTP_TIMER_TYPE_HEARTBEAT:
14378c2654abSrjs 		if (stcb == NULL) {
14388c2654abSrjs 			return (EFAULT);
14398c2654abSrjs 		}
14408c2654abSrjs 		tmr = &stcb->asoc.hb_timer;
14418c2654abSrjs 		break;
14428c2654abSrjs 	case SCTP_TIMER_TYPE_COOKIE:
14438c2654abSrjs 		if ((stcb == NULL) || (net == NULL)) {
14448c2654abSrjs 			return (EFAULT);
14458c2654abSrjs 		}
14468c2654abSrjs 		tmr = &net->rxt_timer;
14478c2654abSrjs 		break;
14488c2654abSrjs 	case SCTP_TIMER_TYPE_NEWCOOKIE:
14498c2654abSrjs 		/* nothing needed but the endpoint here */
14508c2654abSrjs 		tmr = &inp->sctp_ep.signature_change;
14518c2654abSrjs 		/* We re-use the newcookie timer for
14528c2654abSrjs 		 * the INP kill timer. We must assure
14538c2654abSrjs 		 * that we do not kill it by accident.
14548c2654abSrjs 		 */
14558c2654abSrjs 		break;
14568c2654abSrjs 	case SCTP_TIMER_TYPE_INPKILL:
14578c2654abSrjs 		/*
14588c2654abSrjs 		 * The inp is setup to die. We re-use the
14597991f5a7Sandvar 		 * signature_change timer since that has
14608c2654abSrjs 		 * stopped and we are in the GONE state.
14618c2654abSrjs 		 */
14628c2654abSrjs 		tmr = &inp->sctp_ep.signature_change;
14638c2654abSrjs 		break;
14648c2654abSrjs 	case SCTP_TIMER_TYPE_PATHMTURAISE:
14658c2654abSrjs 		if (stcb == NULL) {
14668c2654abSrjs 			return (EFAULT);
14678c2654abSrjs 		}
14688c2654abSrjs 		if (net == NULL) {
14698c2654abSrjs 			return (EFAULT);
14708c2654abSrjs 		}
14718c2654abSrjs 		tmr = &net->pmtu_timer;
14728c2654abSrjs 		break;
14738c2654abSrjs 	case SCTP_TIMER_TYPE_SHUTDOWNACK:
14748c2654abSrjs 		if ((stcb == NULL) || (net == NULL)) {
14758c2654abSrjs 			return (EFAULT);
14768c2654abSrjs 		}
14778c2654abSrjs 		tmr = &net->rxt_timer;
14788c2654abSrjs 		break;
14798c2654abSrjs 	case SCTP_TIMER_TYPE_SHUTDOWNGUARD:
14808c2654abSrjs 		if (stcb == NULL) {
14818c2654abSrjs 			return (EFAULT);
14828c2654abSrjs 		}
14838c2654abSrjs 		tmr = &stcb->asoc.shut_guard_timer;
14848c2654abSrjs 		break;
14858c2654abSrjs 	case SCTP_TIMER_TYPE_STRRESET:
14868c2654abSrjs 		if (stcb == NULL) {
14878c2654abSrjs 			return (EFAULT);
14888c2654abSrjs 		}
14898c2654abSrjs 		tmr = &stcb->asoc.strreset_timer;
14908c2654abSrjs 		break;
14918c2654abSrjs 	case SCTP_TIMER_TYPE_ASCONF:
14928c2654abSrjs 		if (stcb == NULL) {
14938c2654abSrjs 			return (EFAULT);
14948c2654abSrjs 		}
14958c2654abSrjs 		tmr = &stcb->asoc.asconf_timer;
14968c2654abSrjs 		break;
14978c2654abSrjs 	case SCTP_TIMER_TYPE_AUTOCLOSE:
14988c2654abSrjs 		if (stcb == NULL) {
14998c2654abSrjs 			return (EFAULT);
15008c2654abSrjs 		}
15018c2654abSrjs 		tmr = &stcb->asoc.autoclose_timer;
15028c2654abSrjs 		break;
15038c2654abSrjs 	default:
15048c2654abSrjs #ifdef SCTP_DEBUG
15058c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
15068c2654abSrjs 			printf("sctp_timer_stop:Unknown timer type %d\n",
15078c2654abSrjs 			       t_type);
15088c2654abSrjs 		}
15098c2654abSrjs #endif /* SCTP_DEBUG */
15108c2654abSrjs 		break;
15118c2654abSrjs 	};
15128c2654abSrjs 	if (tmr == NULL)
15138c2654abSrjs 		return (EFAULT);
15148c2654abSrjs 
15158c2654abSrjs 	if ((tmr->type != t_type) && tmr->type) {
15168c2654abSrjs 		/*
15178c2654abSrjs 		 * Ok we have a timer that is under joint use. Cookie timer
15188c2654abSrjs 		 * per chance with the SEND timer. We therefore are NOT
15198c2654abSrjs 		 * running the timer that the caller wants stopped.  So just
15208c2654abSrjs 		 * return.
15218c2654abSrjs 		 */
15228c2654abSrjs 		return (0);
15238c2654abSrjs 	}
15248c2654abSrjs 	if (t_type == SCTP_TIMER_TYPE_SEND) {
15258c2654abSrjs 		stcb->asoc.num_send_timers_up--;
15268c2654abSrjs 		if (stcb->asoc.num_send_timers_up < 0) {
15278c2654abSrjs 			stcb->asoc.num_send_timers_up = 0;
15288c2654abSrjs 		}
15298c2654abSrjs 	}
15308c2654abSrjs 	callout_stop(&tmr->timer);
15318c2654abSrjs 	return (0);
15328c2654abSrjs }
15338c2654abSrjs 
15348c2654abSrjs u_int32_t
sctp_calculate_len(struct mbuf * m)15358c2654abSrjs sctp_calculate_len(struct mbuf *m)
15368c2654abSrjs {
15378c2654abSrjs 	u_int32_t tlen=0;
15388c2654abSrjs 	struct mbuf *at;
15398c2654abSrjs 	at = m;
15408c2654abSrjs 	while (at) {
15418c2654abSrjs 		tlen += at->m_len;
15428c2654abSrjs 		at = at->m_next;
15438c2654abSrjs 	}
15448c2654abSrjs 	return (tlen);
15458c2654abSrjs }
15468c2654abSrjs 
15478c2654abSrjs uint32_t
sctp_calculate_sum(struct mbuf * m,int32_t * pktlen,uint32_t offset)15488c2654abSrjs sctp_calculate_sum(struct mbuf *m, int32_t *pktlen, uint32_t offset)
15498c2654abSrjs {
15508c2654abSrjs 	/*
15518c2654abSrjs 	 * given a mbuf chain with a packetheader offset by 'offset'
15528c2654abSrjs 	 * pointing at a sctphdr (with csum set to 0) go through
15538c2654abSrjs 	 * the chain of m_next's and calculate the SCTP checksum.
155412b0ad45Srjs 	 * This is CRC32c.
155512b0ad45Srjs 	 * Also has a side bonus calculate the total length
15568c2654abSrjs 	 * of the mbuf chain.
15578c2654abSrjs 	 * Note: if offset is greater than the total mbuf length,
15588c2654abSrjs 	 * checksum=1, pktlen=0 is returned (ie. no real error code)
15598c2654abSrjs 	 */
15608c2654abSrjs 	int32_t tlen=0;
15618c2654abSrjs 	uint32_t base = 0xffffffff;
15628c2654abSrjs 	struct mbuf *at;
15638c2654abSrjs 	at = m;
15648c2654abSrjs 	/* find the correct mbuf and offset into mbuf */
15658c2654abSrjs 	while ((at != NULL) && (offset > (uint32_t)at->m_len)) {
15668c2654abSrjs 		offset -= at->m_len;	/* update remaining offset left */
15678c2654abSrjs 		at = at->m_next;
15688c2654abSrjs 	}
15698c2654abSrjs 
15708c2654abSrjs 	while (at != NULL) {
15718c2654abSrjs 		base = update_crc32(base, at->m_data + offset,
15728c2654abSrjs 		    at->m_len - offset);
15738c2654abSrjs 		tlen += at->m_len - offset;
15748c2654abSrjs 		/* we only offset once into the first mbuf */
15758c2654abSrjs 		if (offset) {
15768c2654abSrjs 			offset = 0;
15778c2654abSrjs 		}
15788c2654abSrjs 		at = at->m_next;
15798c2654abSrjs 	}
15808c2654abSrjs 	if (pktlen != NULL) {
15818c2654abSrjs 		*pktlen = tlen;
15828c2654abSrjs 	}
15838c2654abSrjs 	/* CRC-32c */
15848c2654abSrjs 	base = sctp_csum_finalize(base);
15858c2654abSrjs 	return (base);
15868c2654abSrjs }
15878c2654abSrjs 
15888c2654abSrjs void
sctp_mtu_size_reset(struct sctp_inpcb * inp,struct sctp_association * asoc,u_long mtu)15898c2654abSrjs sctp_mtu_size_reset(struct sctp_inpcb *inp,
15908c2654abSrjs 		    struct sctp_association *asoc, u_long mtu)
15918c2654abSrjs {
15928c2654abSrjs 	/*
15938c2654abSrjs 	 * Reset the P-MTU size on this association, this involves changing
15948c2654abSrjs 	 * the asoc MTU, going through ANY chunk+overhead larger than mtu
15958c2654abSrjs 	 * to allow the DF flag to be cleared.
15968c2654abSrjs 	 */
15978c2654abSrjs 	struct sctp_tmit_chunk *chk;
15988c2654abSrjs 	struct sctp_stream_out *strm;
15998c2654abSrjs 	unsigned int eff_mtu, ovh;
16008c2654abSrjs 	asoc->smallest_mtu = mtu;
16018c2654abSrjs 	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
16028c2654abSrjs 		ovh = SCTP_MIN_OVERHEAD;
16038c2654abSrjs 	} else {
16048c2654abSrjs 		ovh = SCTP_MIN_V4_OVERHEAD;
16058c2654abSrjs 	}
16068c2654abSrjs 	eff_mtu = mtu - ovh;
16078c2654abSrjs 	/* Now mark any chunks that need to let IP fragment */
16088c2654abSrjs 	TAILQ_FOREACH(strm, &asoc->out_wheel, next_spoke) {
16098c2654abSrjs 		TAILQ_FOREACH(chk, &strm->outqueue, sctp_next) {
16108c2654abSrjs 			if (chk->send_size > eff_mtu) {
16118c2654abSrjs 				chk->flags &= SCTP_DONT_FRAGMENT;
16128c2654abSrjs 				chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
16138c2654abSrjs 			}
16148c2654abSrjs 		}
16158c2654abSrjs 	}
16168c2654abSrjs 	TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) {
16178c2654abSrjs 		if (chk->send_size > eff_mtu) {
16188c2654abSrjs 			chk->flags &= SCTP_DONT_FRAGMENT;
16198c2654abSrjs 			chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
16208c2654abSrjs 		}
16218c2654abSrjs 	}
16228c2654abSrjs 	TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) {
16238c2654abSrjs 		if (chk->send_size > eff_mtu) {
16248c2654abSrjs 			chk->flags &= SCTP_DONT_FRAGMENT;
16258c2654abSrjs 			chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
16268c2654abSrjs 		}
16278c2654abSrjs 	}
16288c2654abSrjs }
16298c2654abSrjs 
16308c2654abSrjs 
16318c2654abSrjs /*
16328c2654abSrjs  * given an association and starting time of the current RTT period
16338c2654abSrjs  * return RTO in number of usecs
16348c2654abSrjs  * net should point to the current network
16358c2654abSrjs  */
16368c2654abSrjs u_int32_t
sctp_calculate_rto(struct sctp_tcb * stcb,struct sctp_association * asoc,struct sctp_nets * net,struct timeval * old)16378c2654abSrjs sctp_calculate_rto(struct sctp_tcb *stcb,
16388c2654abSrjs 		   struct sctp_association *asoc,
16398c2654abSrjs 		   struct sctp_nets *net,
16408c2654abSrjs 		   struct timeval *old)
16418c2654abSrjs {
16428c2654abSrjs 	/*
16438c2654abSrjs 	 * given an association and the starting time of the current RTT
16448c2654abSrjs 	 * period (in value1/value2) return RTO in number of usecs.
16458c2654abSrjs 	 */
16468c2654abSrjs 	int calc_time = 0;
16478c2654abSrjs 	unsigned int new_rto = 0;
16488c2654abSrjs 	int first_measure = 0;
16498c2654abSrjs 	struct timeval now;
16508c2654abSrjs 
16518c2654abSrjs 	/************************/
16528c2654abSrjs 	/* 1. calculate new RTT */
16538c2654abSrjs 	/************************/
16548c2654abSrjs 	/* get the current time */
16558c2654abSrjs 	SCTP_GETTIME_TIMEVAL(&now);
16568c2654abSrjs 	/* compute the RTT value */
16578c2654abSrjs 	if ((u_long)now.tv_sec > (u_long)old->tv_sec) {
16588c2654abSrjs 		calc_time = ((u_long)now.tv_sec - (u_long)old->tv_sec) * 1000;
16598c2654abSrjs 		if ((u_long)now.tv_usec > (u_long)old->tv_usec) {
16608c2654abSrjs 			calc_time += (((u_long)now.tv_usec -
16618c2654abSrjs 				       (u_long)old->tv_usec)/1000);
16628c2654abSrjs 		} else if ((u_long)now.tv_usec < (u_long)old->tv_usec) {
16638c2654abSrjs 			/* Borrow 1,000ms from current calculation */
16648c2654abSrjs 			calc_time -= 1000;
16658c2654abSrjs 			/* Add in the slop over */
16668c2654abSrjs 			calc_time += ((int)now.tv_usec/1000);
16678c2654abSrjs 			/* Add in the pre-second ms's */
16688c2654abSrjs 			calc_time += (((int)1000000 - (int)old->tv_usec)/1000);
16698c2654abSrjs 		}
16708c2654abSrjs 	} else if ((u_long)now.tv_sec == (u_long)old->tv_sec) {
16718c2654abSrjs 		if ((u_long)now.tv_usec > (u_long)old->tv_usec) {
16728c2654abSrjs 			calc_time = ((u_long)now.tv_usec -
16738c2654abSrjs 				     (u_long)old->tv_usec)/1000;
16748c2654abSrjs 		} else if ((u_long)now.tv_usec < (u_long)old->tv_usec) {
16758c2654abSrjs 			/* impossible .. garbage in nothing out */
16768c2654abSrjs 			return (((net->lastsa >> 2) + net->lastsv) >> 1);
16778c2654abSrjs 		} else {
16788c2654abSrjs 			/* impossible .. garbage in nothing out */
16798c2654abSrjs 			return (((net->lastsa >> 2) + net->lastsv) >> 1);
16808c2654abSrjs 		}
16818c2654abSrjs 	} else {
16828c2654abSrjs 		/* Clock wrapped? */
16838c2654abSrjs 		return (((net->lastsa >> 2) + net->lastsv) >> 1);
16848c2654abSrjs 	}
16858c2654abSrjs 	/***************************/
16868c2654abSrjs 	/* 2. update RTTVAR & SRTT */
16878c2654abSrjs 	/***************************/
16888c2654abSrjs #if 0
16898c2654abSrjs 	/*	if (net->lastsv || net->lastsa) {*/
16908c2654abSrjs 	/* per Section 5.3.1 C3 in SCTP */
16918c2654abSrjs 	/*		net->lastsv = (int) 	*//* RTTVAR */
16928c2654abSrjs 	/*			(((double)(1.0 - 0.25) * (double)net->lastsv) +
16938c2654abSrjs 				(double)(0.25 * (double)abs(net->lastsa - calc_time)));
16948c2654abSrjs 				net->lastsa = (int) */	/* SRTT */
16958c2654abSrjs 	/*(((double)(1.0 - 0.125) * (double)net->lastsa) +
16968c2654abSrjs 	  (double)(0.125 * (double)calc_time));
16978c2654abSrjs 	  } else {
16988c2654abSrjs 	*//* the first RTT calculation, per C2 Section 5.3.1 */
16998c2654abSrjs 	/*		net->lastsa = calc_time;	*//* SRTT */
17008c2654abSrjs 	/*		net->lastsv = calc_time / 2;	*//* RTTVAR */
17018c2654abSrjs 	/*	}*/
17028c2654abSrjs 	/* if RTTVAR goes to 0 you set to clock grainularity */
17038c2654abSrjs 	/*	if (net->lastsv == 0) {
17048c2654abSrjs 		net->lastsv = SCTP_CLOCK_GRANULARITY;
17058c2654abSrjs 		}
17068c2654abSrjs 		new_rto = net->lastsa + 4 * net->lastsv;
17078c2654abSrjs 	*/
17088c2654abSrjs #endif
17098c2654abSrjs 	/* this is Van Jacobson's integer version */
17108c2654abSrjs 	if (net->RTO) {
17118c2654abSrjs 		calc_time -= (net->lastsa >> 3);
17128c2654abSrjs 		net->lastsa += calc_time;
17138c2654abSrjs 		if (calc_time < 0) {
17148c2654abSrjs 			calc_time = -calc_time;
17158c2654abSrjs 		}
17168c2654abSrjs 		calc_time -= (net->lastsv >> 2);
17178c2654abSrjs 		net->lastsv += calc_time;
17188c2654abSrjs 		if (net->lastsv == 0) {
17198c2654abSrjs 			net->lastsv = SCTP_CLOCK_GRANULARITY;
17208c2654abSrjs 		}
17218c2654abSrjs 	} else {
1722213f8d89Smsaitoh 		/* First RTO measurement */
17238c2654abSrjs 		net->lastsa = calc_time;
17248c2654abSrjs 		net->lastsv = calc_time >> 1;
17258c2654abSrjs 		first_measure = 1;
17268c2654abSrjs 	}
17278c2654abSrjs 	new_rto = ((net->lastsa >> 2) + net->lastsv) >> 1;
17288c2654abSrjs 	if ((new_rto > SCTP_SAT_NETWORK_MIN) &&
17298c2654abSrjs 	    (stcb->asoc.sat_network_lockout == 0)) {
17308c2654abSrjs 		stcb->asoc.sat_network = 1;
17318c2654abSrjs 	} else 	if ((!first_measure) && stcb->asoc.sat_network) {
17328c2654abSrjs 		stcb->asoc.sat_network = 0;
17338c2654abSrjs 		stcb->asoc.sat_network_lockout = 1;
17348c2654abSrjs 	}
17358c2654abSrjs 	/* bound it, per C6/C7 in Section 5.3.1 */
17368c2654abSrjs 	if (new_rto < stcb->asoc.minrto) {
17378c2654abSrjs 		new_rto = stcb->asoc.minrto;
17388c2654abSrjs 	}
17398c2654abSrjs 	if (new_rto > stcb->asoc.maxrto) {
17408c2654abSrjs 		new_rto = stcb->asoc.maxrto;
17418c2654abSrjs 	}
17428c2654abSrjs 	/* we are now returning the RTT Smoothed */
17438c2654abSrjs 	return ((u_int32_t)new_rto);
17448c2654abSrjs }
17458c2654abSrjs 
17468c2654abSrjs 
17478c2654abSrjs /*
17488c2654abSrjs  * return a pointer to a contiguous piece of data from the given
17498c2654abSrjs  * mbuf chain starting at 'off' for 'len' bytes.  If the desired
17508c2654abSrjs  * piece spans more than one mbuf, a copy is made at 'ptr'.
17518c2654abSrjs  * caller must ensure that the buffer size is >= 'len'
17528c2654abSrjs  * returns NULL if there there isn't 'len' bytes in the chain.
17538c2654abSrjs  */
17548c2654abSrjs void *
sctp_m_getptr(struct mbuf * m,int off,int len,u_int8_t * in_ptr)17558c2654abSrjs sctp_m_getptr(struct mbuf *m, int off, int len, u_int8_t *in_ptr)
17568c2654abSrjs {
17578c2654abSrjs 	uint32_t count;
17588c2654abSrjs 	uint8_t *ptr;
17598c2654abSrjs 	ptr = in_ptr;
17608c2654abSrjs 	if ((off < 0) || (len <= 0))
17618c2654abSrjs 		return (NULL);
17628c2654abSrjs 
17638c2654abSrjs 	/* find the desired start location */
17648c2654abSrjs 	while ((m != NULL) && (off > 0)) {
17658c2654abSrjs 		if (off < m->m_len)
17668c2654abSrjs 			break;
17678c2654abSrjs 		off -= m->m_len;
17688c2654abSrjs 		m = m->m_next;
17698c2654abSrjs 	}
17708c2654abSrjs 	if (m == NULL)
17718c2654abSrjs 		return (NULL);
17728c2654abSrjs 
17738c2654abSrjs 	/* is the current mbuf large enough (eg. contiguous)? */
17748c2654abSrjs 	if ((m->m_len - off) >= len) {
17758c2654abSrjs 		return ((void *)(mtod(m, vaddr_t) + off));
17768c2654abSrjs 	} else {
17778c2654abSrjs 		/* else, it spans more than one mbuf, so save a temp copy... */
17788c2654abSrjs 		while ((m != NULL) && (len > 0)) {
1779d1579b2dSriastradh 			count = uimin(m->m_len - off, len);
17808c2654abSrjs 			memcpy(ptr, (void *)(mtod(m, vaddr_t) + off), count);
17818c2654abSrjs 			len -= count;
17828c2654abSrjs 			ptr += count;
17838c2654abSrjs 			off = 0;
17848c2654abSrjs 			m = m->m_next;
17858c2654abSrjs 		}
17868c2654abSrjs 		if ((m == NULL) && (len > 0))
17878c2654abSrjs 			return (NULL);
17888c2654abSrjs 		else
17898c2654abSrjs 			return ((void *)in_ptr);
17908c2654abSrjs 	}
17918c2654abSrjs }
17928c2654abSrjs 
17938c2654abSrjs 
17948c2654abSrjs struct sctp_paramhdr *
sctp_get_next_param(struct mbuf * m,int offset,struct sctp_paramhdr * pull,int pull_limit)17958c2654abSrjs sctp_get_next_param(struct mbuf *m,
17968c2654abSrjs 		    int offset,
17978c2654abSrjs 		    struct sctp_paramhdr *pull,
17988c2654abSrjs 		    int pull_limit)
17998c2654abSrjs {
18008c2654abSrjs 	/* This just provides a typed signature to Peter's Pull routine */
18018c2654abSrjs 	return ((struct sctp_paramhdr *)sctp_m_getptr(m, offset, pull_limit,
18028c2654abSrjs     	    (u_int8_t *)pull));
18038c2654abSrjs }
18048c2654abSrjs 
18058c2654abSrjs 
18068c2654abSrjs int
sctp_add_pad_tombuf(struct mbuf * m,int padlen)18078c2654abSrjs sctp_add_pad_tombuf(struct mbuf *m, int padlen)
18088c2654abSrjs {
18098c2654abSrjs 	/*
18108c2654abSrjs 	 * add padlen bytes of 0 filled padding to the end of the mbuf.
18118c2654abSrjs 	 * If padlen is > 3 this routine will fail.
18128c2654abSrjs 	 */
18138c2654abSrjs 	u_int8_t *dp;
18148c2654abSrjs 	int i;
18158c2654abSrjs 	if (padlen > 3) {
18168c2654abSrjs 		return (ENOBUFS);
18178c2654abSrjs 	}
18188c2654abSrjs 	if (M_TRAILINGSPACE(m)) {
18198c2654abSrjs 		/*
18208c2654abSrjs 		 * The easy way.
18218c2654abSrjs 		 * We hope the majority of the time we hit here :)
18228c2654abSrjs 		 */
18238c2654abSrjs 		dp = (u_int8_t *)(mtod(m, vaddr_t) + m->m_len);
18248c2654abSrjs 		m->m_len += padlen;
18258c2654abSrjs 	} else {
18268c2654abSrjs 		/* Hard way we must grow the mbuf */
18278c2654abSrjs 		struct mbuf *tmp;
18288c2654abSrjs 		MGET(tmp, M_DONTWAIT, MT_DATA);
18298c2654abSrjs 		if (tmp == NULL) {
18308c2654abSrjs 			/* Out of space GAK! we are in big trouble. */
18318c2654abSrjs 			return (ENOSPC);
18328c2654abSrjs 		}
18338c2654abSrjs 		/* setup and insert in middle */
18348c2654abSrjs 		tmp->m_next = m->m_next;
18358c2654abSrjs 		tmp->m_len = padlen;
18368c2654abSrjs 		m->m_next = tmp;
18378c2654abSrjs 		dp = mtod(tmp, u_int8_t *);
18388c2654abSrjs 	}
18398c2654abSrjs 	/* zero out the pad */
18408c2654abSrjs 	for (i=  0; i < padlen; i++) {
18418c2654abSrjs 		*dp = 0;
18428c2654abSrjs 		dp++;
18438c2654abSrjs 	}
18448c2654abSrjs 	return (0);
18458c2654abSrjs }
18468c2654abSrjs 
18478c2654abSrjs int
sctp_pad_lastmbuf(struct mbuf * m,int padval)18488c2654abSrjs sctp_pad_lastmbuf(struct mbuf *m, int padval)
18498c2654abSrjs {
18508c2654abSrjs 	/* find the last mbuf in chain and pad it */
18518c2654abSrjs 	struct mbuf *m_at;
18528c2654abSrjs 	m_at = m;
18538c2654abSrjs 	while (m_at) {
18548c2654abSrjs 		if (m_at->m_next == NULL) {
18558c2654abSrjs 			return (sctp_add_pad_tombuf(m_at, padval));
18568c2654abSrjs 		}
18578c2654abSrjs 		m_at = m_at->m_next;
18588c2654abSrjs 	}
18598c2654abSrjs 	return (EFAULT);
18608c2654abSrjs }
18618c2654abSrjs 
18628c2654abSrjs static void
sctp_notify_assoc_change(u_int32_t event,struct sctp_tcb * stcb,u_int32_t error)18638c2654abSrjs sctp_notify_assoc_change(u_int32_t event, struct sctp_tcb *stcb,
18648c2654abSrjs     u_int32_t error)
18658c2654abSrjs {
18668c2654abSrjs 	struct mbuf *m_notify;
18678c2654abSrjs 	struct sctp_assoc_change *sac;
18688c2654abSrjs 	const struct sockaddr *to;
18698c2654abSrjs 	struct sockaddr_in6 sin6, lsa6;
18708c2654abSrjs 
18718c2654abSrjs #ifdef SCTP_DEBUG
18728c2654abSrjs 	printf("notify: %d\n", event);
18738c2654abSrjs #endif
18748c2654abSrjs 	/*
187554c9821eSmsaitoh 	 * First if we are going down dump everything we
18768c2654abSrjs 	 * can to the socket rcv queue.
18778c2654abSrjs 	 */
18788c2654abSrjs 	if ((event == SCTP_SHUTDOWN_COMP) || (event == SCTP_COMM_LOST)) {
18798c2654abSrjs 		sctp_deliver_data(stcb, &stcb->asoc, NULL, 0);
18808c2654abSrjs 	}
18818c2654abSrjs 
18828c2654abSrjs 	/*
18838c2654abSrjs 	 * For TCP model AND UDP connected sockets we will send
18848c2654abSrjs 	 * an error up when an ABORT comes in.
18858c2654abSrjs 	 */
18868c2654abSrjs 	if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
18878c2654abSrjs 	     (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) &&
18888c2654abSrjs 	    (event == SCTP_COMM_LOST)) {
18898c2654abSrjs 		stcb->sctp_socket->so_error = ECONNRESET;
18908c2654abSrjs 		/* Wake ANY sleepers */
18918c2654abSrjs 		sowwakeup(stcb->sctp_socket);
18928c2654abSrjs 		sorwakeup(stcb->sctp_socket);
18938c2654abSrjs 	}
18948c2654abSrjs #if 0
18958c2654abSrjs 	if ((event == SCTP_COMM_UP) &&
18968c2654abSrjs 	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
18978c2654abSrjs  	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
18988c2654abSrjs 		 soisconnected(stcb->sctp_socket);
18998c2654abSrjs 	}
19008c2654abSrjs #endif
19018c2654abSrjs 	if (!(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_RECVASSOCEVNT)) {
19028c2654abSrjs 		/* event not enabled */
19038c2654abSrjs 		return;
19048c2654abSrjs 	}
19058c2654abSrjs 	MGETHDR(m_notify, M_DONTWAIT, MT_DATA);
19068c2654abSrjs 	if (m_notify == NULL)
19078c2654abSrjs 		/* no space left */
19088c2654abSrjs 		return;
19098c2654abSrjs 	m_notify->m_len = 0;
19108c2654abSrjs 
19118c2654abSrjs 	sac = mtod(m_notify, struct sctp_assoc_change *);
19128c2654abSrjs 	sac->sac_type = SCTP_ASSOC_CHANGE;
19138c2654abSrjs 	sac->sac_flags = 0;
19148c2654abSrjs 	sac->sac_length = sizeof(struct sctp_assoc_change);
19158c2654abSrjs 	sac->sac_state = event;
19168c2654abSrjs 	sac->sac_error = error;
19178c2654abSrjs 	/* XXX verify these stream counts */
19188c2654abSrjs 	sac->sac_outbound_streams = stcb->asoc.streamoutcnt;
19198c2654abSrjs 	sac->sac_inbound_streams = stcb->asoc.streamincnt;
19208c2654abSrjs 	sac->sac_assoc_id = sctp_get_associd(stcb);
19218c2654abSrjs 
19228c2654abSrjs 	m_notify->m_flags |= M_EOR | M_NOTIFICATION;
19238c2654abSrjs 	m_notify->m_pkthdr.len = sizeof(struct sctp_assoc_change);
1924d938d837Sozaki-r 	m_reset_rcvif(m_notify);
19258c2654abSrjs 	m_notify->m_len = sizeof(struct sctp_assoc_change);
19268c2654abSrjs 	m_notify->m_next = NULL;
19278c2654abSrjs 
19288c2654abSrjs 	/* append to socket */
19298c2654abSrjs 	to = rtcache_getdst(&stcb->asoc.primary_destination->ro);
19308c2654abSrjs 	if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) &&
19318c2654abSrjs 	    to->sa_family == AF_INET) {
19328c2654abSrjs 		const struct sockaddr_in *sin;
19338c2654abSrjs 
19348c2654abSrjs 		sin = (const struct sockaddr_in *)to;
19350a0528fdSrtr 		in6_sin_2_v4mapsin6(sin, &sin6);
19368c2654abSrjs 		to = (struct sockaddr *)&sin6;
19378c2654abSrjs 	}
19388c2654abSrjs 	/* check and strip embedded scope junk */
19398c2654abSrjs 	to = (const struct sockaddr *)sctp_recover_scope((const struct sockaddr_in6 *)to,
19408c2654abSrjs 						   &lsa6);
19418c2654abSrjs 	/*
19428c2654abSrjs 	 * We need to always notify comm changes.
19438c2654abSrjs 	 * if (sctp_sbspace(&stcb->sctp_socket->so_rcv) < m_notify->m_len) {
19448c2654abSrjs 	 * 	sctp_m_freem(m_notify);
19458c2654abSrjs 	 *	return;
19468c2654abSrjs 	 * }
19478c2654abSrjs 	*/
19488c2654abSrjs 	SCTP_TCB_UNLOCK(stcb);
19498c2654abSrjs 	SCTP_INP_WLOCK(stcb->sctp_ep);
19508c2654abSrjs 	SCTP_TCB_LOCK(stcb);
19518c2654abSrjs 	if (!sbappendaddr_nocheck(&stcb->sctp_socket->so_rcv,
19528c2654abSrjs 	    to, m_notify, NULL, stcb->asoc.my_vtag, stcb->sctp_ep)) {
19538c2654abSrjs 		/* not enough room */
19548c2654abSrjs 		sctp_m_freem(m_notify);
19558c2654abSrjs 		SCTP_INP_WUNLOCK(stcb->sctp_ep);
19568c2654abSrjs 		return;
19578c2654abSrjs 	}
19588c2654abSrjs 	if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) &&
19598c2654abSrjs 	   ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)){
19608c2654abSrjs 		if (sctp_add_to_socket_q(stcb->sctp_ep, stcb)) {
19618c2654abSrjs 			stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
19628c2654abSrjs 		}
19638c2654abSrjs 	} else {
19648c2654abSrjs 		stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
19658c2654abSrjs 	}
19668c2654abSrjs 	SCTP_INP_WUNLOCK(stcb->sctp_ep);
19678c2654abSrjs 	/* Wake up any sleeper */
19688c2654abSrjs 	sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
19698c2654abSrjs 	sctp_sowwakeup(stcb->sctp_ep, stcb->sctp_socket);
19708c2654abSrjs }
19718c2654abSrjs 
19728c2654abSrjs static void
sctp_notify_peer_addr_change(struct sctp_tcb * stcb,uint32_t state,const struct sockaddr * sa,uint32_t error)19738c2654abSrjs sctp_notify_peer_addr_change(struct sctp_tcb *stcb, uint32_t state,
19748c2654abSrjs     const struct sockaddr *sa, uint32_t error)
19758c2654abSrjs {
19768c2654abSrjs 	struct mbuf *m_notify;
19778c2654abSrjs 	struct sctp_paddr_change *spc;
19788c2654abSrjs 	const struct sockaddr *to;
19798c2654abSrjs 	struct sockaddr_in6 sin6, lsa6;
19808c2654abSrjs 
19818c2654abSrjs 	if (!(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_RECVPADDREVNT))
19828c2654abSrjs 		/* event not enabled */
19838c2654abSrjs 		return;
19848c2654abSrjs 
19858c2654abSrjs 	MGETHDR(m_notify, M_DONTWAIT, MT_DATA);
19868c2654abSrjs 	if (m_notify == NULL)
19878c2654abSrjs 		return;
19888c2654abSrjs 	m_notify->m_len = 0;
19898c2654abSrjs 
19908c2654abSrjs 	MCLGET(m_notify, M_DONTWAIT);
19918c2654abSrjs 	if ((m_notify->m_flags & M_EXT) != M_EXT) {
19928c2654abSrjs 		sctp_m_freem(m_notify);
19938c2654abSrjs 		return;
19948c2654abSrjs 	}
19958c2654abSrjs 
19968c2654abSrjs 	spc = mtod(m_notify, struct sctp_paddr_change *);
19978c2654abSrjs 	spc->spc_type = SCTP_PEER_ADDR_CHANGE;
19988c2654abSrjs 	spc->spc_flags = 0;
19998c2654abSrjs 	spc->spc_length = sizeof(struct sctp_paddr_change);
20008c2654abSrjs 	if (sa->sa_family == AF_INET) {
20018c2654abSrjs 		memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in));
20028c2654abSrjs 	} else {
20038c2654abSrjs 		memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in6));
20048c2654abSrjs 	}
20058c2654abSrjs 	spc->spc_state = state;
20068c2654abSrjs 	spc->spc_error = error;
20078c2654abSrjs 	spc->spc_assoc_id = sctp_get_associd(stcb);
20088c2654abSrjs 
20098c2654abSrjs 	m_notify->m_flags |= M_EOR | M_NOTIFICATION;
20108c2654abSrjs 	m_notify->m_pkthdr.len = sizeof(struct sctp_paddr_change);
2011d938d837Sozaki-r 	m_reset_rcvif(m_notify);
20128c2654abSrjs 	m_notify->m_len = sizeof(struct sctp_paddr_change);
20138c2654abSrjs 	m_notify->m_next = NULL;
20148c2654abSrjs 
20158c2654abSrjs 	to = rtcache_getdst(&stcb->asoc.primary_destination->ro);
20168c2654abSrjs 	if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) &&
20178c2654abSrjs 	    to->sa_family == AF_INET) {
20188c2654abSrjs 		const struct sockaddr_in *sin;
20198c2654abSrjs 
20208c2654abSrjs 		sin = (const struct sockaddr_in *)to;
20210a0528fdSrtr 		in6_sin_2_v4mapsin6(sin, &sin6);
20228c2654abSrjs 		to = (struct sockaddr *)&sin6;
20238c2654abSrjs 	}
20248c2654abSrjs 	/* check and strip embedded scope junk */
20258c2654abSrjs 	to = (const struct sockaddr *)sctp_recover_scope((const struct sockaddr_in6 *)to,
20268c2654abSrjs 	    &lsa6);
20278c2654abSrjs 
20288c2654abSrjs 	if (sctp_sbspace(&stcb->sctp_socket->so_rcv) < m_notify->m_len) {
20298c2654abSrjs 		sctp_m_freem(m_notify);
20308c2654abSrjs 		return;
20318c2654abSrjs 	}
20328c2654abSrjs 	/* append to socket */
20338c2654abSrjs 	SCTP_TCB_UNLOCK(stcb);
20348c2654abSrjs 	SCTP_INP_WLOCK(stcb->sctp_ep);
20358c2654abSrjs 	SCTP_TCB_LOCK(stcb);
20368c2654abSrjs 	if (!sbappendaddr_nocheck(&stcb->sctp_socket->so_rcv, to,
20378c2654abSrjs 	    m_notify, NULL, stcb->asoc.my_vtag, stcb->sctp_ep)) {
20388c2654abSrjs 		/* not enough room */
20398c2654abSrjs 		sctp_m_freem(m_notify);
20408c2654abSrjs 		SCTP_INP_WUNLOCK(stcb->sctp_ep);
20418c2654abSrjs 		return;
20428c2654abSrjs 	}
20438c2654abSrjs 	if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) &&
20448c2654abSrjs 	   ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)){
20458c2654abSrjs 		if (sctp_add_to_socket_q(stcb->sctp_ep, stcb)) {
20468c2654abSrjs 			stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
20478c2654abSrjs 		}
20488c2654abSrjs 	} else {
20498c2654abSrjs 		stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
20508c2654abSrjs 	}
20518c2654abSrjs 	SCTP_INP_WUNLOCK(stcb->sctp_ep);
20528c2654abSrjs 	sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
20538c2654abSrjs }
20548c2654abSrjs 
20558c2654abSrjs 
20568c2654abSrjs static void
sctp_notify_send_failed(struct sctp_tcb * stcb,u_int32_t error,struct sctp_tmit_chunk * chk)20578c2654abSrjs sctp_notify_send_failed(struct sctp_tcb *stcb, u_int32_t error,
20588c2654abSrjs 			struct sctp_tmit_chunk *chk)
20598c2654abSrjs {
20608c2654abSrjs 	struct mbuf *m_notify;
20618c2654abSrjs 	struct sctp_send_failed *ssf;
20628c2654abSrjs 	struct sockaddr_in6 sin6, lsa6;
20638c2654abSrjs 	const struct sockaddr *to;
20648c2654abSrjs 	int length;
20658c2654abSrjs 
20668c2654abSrjs 	if (!(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_RECVSENDFAILEVNT))
20678c2654abSrjs 		/* event not enabled */
20688c2654abSrjs 		return;
20698c2654abSrjs 
20708c2654abSrjs 	length = sizeof(struct sctp_send_failed) + chk->send_size;
20718c2654abSrjs 	MGETHDR(m_notify, M_DONTWAIT, MT_DATA);
20728c2654abSrjs 	if (m_notify == NULL)
20738c2654abSrjs 		/* no space left */
20748c2654abSrjs 		return;
20758c2654abSrjs 	m_notify->m_len = 0;
20768c2654abSrjs 	ssf = mtod(m_notify, struct sctp_send_failed *);
20778c2654abSrjs 	ssf->ssf_type = SCTP_SEND_FAILED;
20788c2654abSrjs 	if (error == SCTP_NOTIFY_DATAGRAM_UNSENT)
20798c2654abSrjs 		ssf->ssf_flags = SCTP_DATA_UNSENT;
20808c2654abSrjs 	else
20818c2654abSrjs 		ssf->ssf_flags = SCTP_DATA_SENT;
20828c2654abSrjs 	ssf->ssf_length = length;
20838c2654abSrjs 	ssf->ssf_error = error;
20848c2654abSrjs 	/* not exactly what the user sent in, but should be close :) */
20858c2654abSrjs 	ssf->ssf_info.sinfo_stream = chk->rec.data.stream_number;
20868c2654abSrjs 	ssf->ssf_info.sinfo_ssn = chk->rec.data.stream_seq;
20878c2654abSrjs 	ssf->ssf_info.sinfo_flags = chk->rec.data.rcv_flags;
20888c2654abSrjs 	ssf->ssf_info.sinfo_ppid = chk->rec.data.payloadtype;
20898c2654abSrjs 	ssf->ssf_info.sinfo_context = chk->rec.data.context;
20908c2654abSrjs 	ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb);
20918c2654abSrjs 	ssf->ssf_assoc_id = sctp_get_associd(stcb);
20928c2654abSrjs 	m_notify->m_next = chk->data;
20938c2654abSrjs 	if (m_notify->m_next == NULL)
20948c2654abSrjs 		m_notify->m_flags |= M_EOR | M_NOTIFICATION;
20958c2654abSrjs 	else {
20968c2654abSrjs 		struct mbuf *m;
20978c2654abSrjs 		m_notify->m_flags |= M_NOTIFICATION;
20988c2654abSrjs 		m = m_notify;
20998c2654abSrjs 		while (m->m_next != NULL)
21008c2654abSrjs 			m = m->m_next;
21018c2654abSrjs 		m->m_flags |= M_EOR;
21028c2654abSrjs 	}
21038c2654abSrjs 	m_notify->m_pkthdr.len = length;
2104d938d837Sozaki-r 	m_reset_rcvif(m_notify);
21058c2654abSrjs 	m_notify->m_len = sizeof(struct sctp_send_failed);
21068c2654abSrjs 
21078c2654abSrjs 	/* Steal off the mbuf */
21088c2654abSrjs 	chk->data = NULL;
21098c2654abSrjs 	to = rtcache_getdst(&stcb->asoc.primary_destination->ro);
21108c2654abSrjs 	if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) &&
21118c2654abSrjs 	    to->sa_family == AF_INET) {
21128c2654abSrjs 		const struct sockaddr_in *sin;
21138c2654abSrjs 
21148c2654abSrjs 		sin = satocsin(to);
21150a0528fdSrtr 		in6_sin_2_v4mapsin6(sin, &sin6);
21168c2654abSrjs 		to = (struct sockaddr *)&sin6;
21178c2654abSrjs 	}
21188c2654abSrjs 	/* check and strip embedded scope junk */
21198c2654abSrjs 	to = (const struct sockaddr *)sctp_recover_scope((const struct sockaddr_in6 *)to,
21208c2654abSrjs 						   &lsa6);
21218c2654abSrjs 
21228c2654abSrjs 	if (sctp_sbspace(&stcb->sctp_socket->so_rcv) < m_notify->m_len) {
21238c2654abSrjs 		sctp_m_freem(m_notify);
21248c2654abSrjs 		return;
21258c2654abSrjs 	}
21268c2654abSrjs 
21278c2654abSrjs 	/* append to socket */
21288c2654abSrjs 	SCTP_TCB_UNLOCK(stcb);
21298c2654abSrjs 	SCTP_INP_WLOCK(stcb->sctp_ep);
21308c2654abSrjs 	SCTP_TCB_LOCK(stcb);
21318c2654abSrjs 	if (!sbappendaddr_nocheck(&stcb->sctp_socket->so_rcv, to,
21328c2654abSrjs 	    m_notify, NULL, stcb->asoc.my_vtag, stcb->sctp_ep)) {
21338c2654abSrjs 		/* not enough room */
21348c2654abSrjs 		sctp_m_freem(m_notify);
21358c2654abSrjs 		SCTP_INP_WUNLOCK(stcb->sctp_ep);
21368c2654abSrjs 		return;
21378c2654abSrjs 	}
21388c2654abSrjs 	if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) &&
21398c2654abSrjs 	   ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)){
21408c2654abSrjs 		if (sctp_add_to_socket_q(stcb->sctp_ep, stcb)) {
21418c2654abSrjs 			stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
21428c2654abSrjs 		}
21438c2654abSrjs 	} else {
21448c2654abSrjs 		stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
21458c2654abSrjs 	}
21468c2654abSrjs 	SCTP_INP_WUNLOCK(stcb->sctp_ep);
21478c2654abSrjs 	sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
21488c2654abSrjs }
21498c2654abSrjs 
21508c2654abSrjs static void
sctp_notify_adaption_layer(struct sctp_tcb * stcb,u_int32_t error)21518c2654abSrjs sctp_notify_adaption_layer(struct sctp_tcb *stcb,
21528c2654abSrjs 			   u_int32_t error)
21538c2654abSrjs {
21548c2654abSrjs 	struct mbuf *m_notify;
21558c2654abSrjs 	struct sctp_adaption_event *sai;
21568c2654abSrjs 	struct sockaddr_in6 sin6, lsa6;
21578c2654abSrjs 	const struct sockaddr *to;
21588c2654abSrjs 
21598c2654abSrjs 	if (!(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_ADAPTIONEVNT))
21608c2654abSrjs 		/* event not enabled */
21618c2654abSrjs 		return;
21628c2654abSrjs 
21638c2654abSrjs 	MGETHDR(m_notify, M_DONTWAIT, MT_DATA);
21648c2654abSrjs 	if (m_notify == NULL)
21658c2654abSrjs 		/* no space left */
21668c2654abSrjs 		return;
21678c2654abSrjs 	m_notify->m_len = 0;
21688c2654abSrjs 	sai = mtod(m_notify, struct sctp_adaption_event *);
21698c2654abSrjs 	sai->sai_type = SCTP_ADAPTION_INDICATION;
21708c2654abSrjs 	sai->sai_flags = 0;
21718c2654abSrjs 	sai->sai_length = sizeof(struct sctp_adaption_event);
21728c2654abSrjs 	sai->sai_adaption_ind = error;
21738c2654abSrjs 	sai->sai_assoc_id = sctp_get_associd(stcb);
21748c2654abSrjs 
21758c2654abSrjs 	m_notify->m_flags |= M_EOR | M_NOTIFICATION;
21768c2654abSrjs 	m_notify->m_pkthdr.len = sizeof(struct sctp_adaption_event);
2177d938d837Sozaki-r 	m_reset_rcvif(m_notify);
21788c2654abSrjs 	m_notify->m_len = sizeof(struct sctp_adaption_event);
21798c2654abSrjs 	m_notify->m_next = NULL;
21808c2654abSrjs 
21818c2654abSrjs 	to = rtcache_getdst(&stcb->asoc.primary_destination->ro);
21828c2654abSrjs 	if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) &&
21838c2654abSrjs 	    (to->sa_family == AF_INET)) {
21848c2654abSrjs 		const struct sockaddr_in *sin;
21858c2654abSrjs 
21868c2654abSrjs 		sin = satocsin(to);
21870a0528fdSrtr 		in6_sin_2_v4mapsin6(sin, &sin6);
21888c2654abSrjs 		to = (struct sockaddr *)&sin6;
21898c2654abSrjs 	}
21908c2654abSrjs 	/* check and strip embedded scope junk */
21918c2654abSrjs 	to = (const struct sockaddr *)sctp_recover_scope((const struct sockaddr_in6 *)to,
21928c2654abSrjs 						   &lsa6);
21938c2654abSrjs 	if (sctp_sbspace(&stcb->sctp_socket->so_rcv) < m_notify->m_len) {
21948c2654abSrjs 		sctp_m_freem(m_notify);
21958c2654abSrjs 		return;
21968c2654abSrjs 	}
21978c2654abSrjs 	/* append to socket */
21988c2654abSrjs 	SCTP_TCB_UNLOCK(stcb);
21998c2654abSrjs 	SCTP_INP_WLOCK(stcb->sctp_ep);
22008c2654abSrjs 	SCTP_TCB_LOCK(stcb);
22018c2654abSrjs 	if (!sbappendaddr_nocheck(&stcb->sctp_socket->so_rcv, to,
22028c2654abSrjs 	    m_notify, NULL, stcb->asoc.my_vtag, stcb->sctp_ep)) {
22038c2654abSrjs 		/* not enough room */
22048c2654abSrjs 		sctp_m_freem(m_notify);
22058c2654abSrjs 		SCTP_INP_WUNLOCK(stcb->sctp_ep);
22068c2654abSrjs 		return;
22078c2654abSrjs 	}
22088c2654abSrjs 	if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) &&
22098c2654abSrjs 	   ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)){
22108c2654abSrjs 		if (sctp_add_to_socket_q(stcb->sctp_ep, stcb)) {
22118c2654abSrjs 			stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
22128c2654abSrjs 		}
22138c2654abSrjs 	} else {
22148c2654abSrjs 		stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
22158c2654abSrjs 	}
22168c2654abSrjs 	SCTP_INP_WUNLOCK(stcb->sctp_ep);
22178c2654abSrjs 	sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
22188c2654abSrjs }
22198c2654abSrjs 
22208c2654abSrjs static void
sctp_notify_partial_delivery_indication(struct sctp_tcb * stcb,u_int32_t error)22218c2654abSrjs sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb,
22228c2654abSrjs 					u_int32_t error)
22238c2654abSrjs {
22248c2654abSrjs 	struct mbuf *m_notify;
22258c2654abSrjs 	struct sctp_pdapi_event *pdapi;
22268c2654abSrjs 	struct sockaddr_in6 sin6, lsa6;
22278c2654abSrjs 	const struct sockaddr *to;
22288c2654abSrjs 
22298c2654abSrjs 	if (!(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_PDAPIEVNT))
22308c2654abSrjs 		/* event not enabled */
22318c2654abSrjs 		return;
22328c2654abSrjs 
22338c2654abSrjs 	MGETHDR(m_notify, M_DONTWAIT, MT_DATA);
22348c2654abSrjs 	if (m_notify == NULL)
22358c2654abSrjs 		/* no space left */
22368c2654abSrjs 		return;
22378c2654abSrjs 	m_notify->m_len = 0;
22388c2654abSrjs 	pdapi = mtod(m_notify, struct sctp_pdapi_event *);
22398c2654abSrjs 	pdapi->pdapi_type = SCTP_PARTIAL_DELIVERY_EVENT;
22408c2654abSrjs 	pdapi->pdapi_flags = 0;
22418c2654abSrjs 	pdapi->pdapi_length = sizeof(struct sctp_pdapi_event);
22428c2654abSrjs 	pdapi->pdapi_indication = error;
22438c2654abSrjs 	pdapi->pdapi_assoc_id = sctp_get_associd(stcb);
22448c2654abSrjs 
22458c2654abSrjs 	m_notify->m_flags |= M_EOR | M_NOTIFICATION;
22468c2654abSrjs 	m_notify->m_pkthdr.len = sizeof(struct sctp_pdapi_event);
2247d938d837Sozaki-r 	m_reset_rcvif(m_notify);
22488c2654abSrjs 	m_notify->m_len = sizeof(struct sctp_pdapi_event);
22498c2654abSrjs 	m_notify->m_next = NULL;
22508c2654abSrjs 
22518c2654abSrjs 	to = rtcache_getdst(&stcb->asoc.primary_destination->ro);
22528c2654abSrjs 	if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) &&
22538c2654abSrjs 	    (to->sa_family == AF_INET)) {
22548c2654abSrjs 		const struct sockaddr_in *sin;
22558c2654abSrjs 
22568c2654abSrjs 		sin = satocsin(to);
22570a0528fdSrtr 		in6_sin_2_v4mapsin6(sin, &sin6);
22588c2654abSrjs 		to = (struct sockaddr *)&sin6;
22598c2654abSrjs 	}
22608c2654abSrjs 	/* check and strip embedded scope junk */
22618c2654abSrjs 	to = (const struct sockaddr *)sctp_recover_scope((const struct sockaddr_in6 *)to,
22628c2654abSrjs 						   &lsa6);
22638c2654abSrjs 	if (sctp_sbspace(&stcb->sctp_socket->so_rcv) < m_notify->m_len) {
22648c2654abSrjs 		sctp_m_freem(m_notify);
22658c2654abSrjs 		return;
22668c2654abSrjs 	}
22678c2654abSrjs 	/* append to socket */
22688c2654abSrjs 	SCTP_TCB_UNLOCK(stcb);
22698c2654abSrjs 	SCTP_INP_WLOCK(stcb->sctp_ep);
22708c2654abSrjs 	SCTP_TCB_LOCK(stcb);
22718c2654abSrjs 	if (!sbappendaddr_nocheck(&stcb->sctp_socket->so_rcv, to,
22728c2654abSrjs 	    m_notify, NULL, stcb->asoc.my_vtag, stcb->sctp_ep)) {
22738c2654abSrjs 		/* not enough room */
22748c2654abSrjs 		sctp_m_freem(m_notify);
22758c2654abSrjs 		SCTP_INP_WUNLOCK(stcb->sctp_ep);
22768c2654abSrjs 		return;
22778c2654abSrjs 	}
22788c2654abSrjs 	if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) &&
22798c2654abSrjs 	   ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)){
22808c2654abSrjs 		if (sctp_add_to_socket_q(stcb->sctp_ep, stcb)) {
22818c2654abSrjs 			stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
22828c2654abSrjs 		}
22838c2654abSrjs 	} else {
22848c2654abSrjs 		stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
22858c2654abSrjs 	}
22868c2654abSrjs 	SCTP_INP_WUNLOCK(stcb->sctp_ep);
22878c2654abSrjs 	sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
22888c2654abSrjs }
22898c2654abSrjs 
22908c2654abSrjs static void
sctp_notify_shutdown_event(struct sctp_tcb * stcb)22918c2654abSrjs sctp_notify_shutdown_event(struct sctp_tcb *stcb)
22928c2654abSrjs {
22938c2654abSrjs 	struct mbuf *m_notify;
22948c2654abSrjs 	struct sctp_shutdown_event *sse;
22958c2654abSrjs 	struct sockaddr_in6 sin6, lsa6;
22968c2654abSrjs 	const struct sockaddr *to;
22978c2654abSrjs 
22988c2654abSrjs 	/*
22998c2654abSrjs 	 * For TCP model AND UDP connected sockets we will send
23008c2654abSrjs 	 * an error up when an SHUTDOWN completes
23018c2654abSrjs 	 */
23028c2654abSrjs 	if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
23038c2654abSrjs 	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
23048c2654abSrjs 		/* mark socket closed for read/write and wakeup! */
23058c2654abSrjs 		socantrcvmore(stcb->sctp_socket);
23068c2654abSrjs 		socantsendmore(stcb->sctp_socket);
23078c2654abSrjs 	}
23088c2654abSrjs 
23098c2654abSrjs 	if (!(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT))
23108c2654abSrjs 		/* event not enabled */
23118c2654abSrjs 		return;
23128c2654abSrjs 
23138c2654abSrjs 	MGETHDR(m_notify, M_DONTWAIT, MT_DATA);
23148c2654abSrjs 	if (m_notify == NULL)
23158c2654abSrjs 		/* no space left */
23168c2654abSrjs 		return;
23178c2654abSrjs 	m_notify->m_len = 0;
23188c2654abSrjs 	sse = mtod(m_notify, struct sctp_shutdown_event *);
23198c2654abSrjs 	sse->sse_type = SCTP_SHUTDOWN_EVENT;
23208c2654abSrjs 	sse->sse_flags = 0;
23218c2654abSrjs 	sse->sse_length = sizeof(struct sctp_shutdown_event);
23228c2654abSrjs 	sse->sse_assoc_id = sctp_get_associd(stcb);
23238c2654abSrjs 
23248c2654abSrjs 	m_notify->m_flags |= M_EOR | M_NOTIFICATION;
23258c2654abSrjs 	m_notify->m_pkthdr.len = sizeof(struct sctp_shutdown_event);
2326d938d837Sozaki-r 	m_reset_rcvif(m_notify);
23278c2654abSrjs 	m_notify->m_len = sizeof(struct sctp_shutdown_event);
23288c2654abSrjs 	m_notify->m_next = NULL;
23298c2654abSrjs 
23308c2654abSrjs 	to = rtcache_getdst(&stcb->asoc.primary_destination->ro);
23318c2654abSrjs 	if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) &&
23328c2654abSrjs 	    to->sa_family == AF_INET) {
23338c2654abSrjs 		const struct sockaddr_in *sin;
23348c2654abSrjs 
23358c2654abSrjs 		sin = satocsin(to);
23360a0528fdSrtr 		in6_sin_2_v4mapsin6(sin, &sin6);
23378c2654abSrjs 		to = (struct sockaddr *)&sin6;
23388c2654abSrjs 	}
23398c2654abSrjs 	/* check and strip embedded scope junk */
23408c2654abSrjs 	to = (const struct sockaddr *)sctp_recover_scope((const struct sockaddr_in6 *)to,
23418c2654abSrjs 	    &lsa6);
23428c2654abSrjs 	if (sctp_sbspace(&stcb->sctp_socket->so_rcv) < m_notify->m_len) {
23438c2654abSrjs 		sctp_m_freem(m_notify);
23448c2654abSrjs 		return;
23458c2654abSrjs 	}
23468c2654abSrjs 	/* append to socket */
23478c2654abSrjs 	SCTP_TCB_UNLOCK(stcb);
23488c2654abSrjs 	SCTP_INP_WLOCK(stcb->sctp_ep);
23498c2654abSrjs 	SCTP_TCB_LOCK(stcb);
23508c2654abSrjs 	if (!sbappendaddr_nocheck(&stcb->sctp_socket->so_rcv, to,
23518c2654abSrjs 	    m_notify, NULL, stcb->asoc.my_vtag, stcb->sctp_ep)) {
23528c2654abSrjs 		/* not enough room */
23538c2654abSrjs 		sctp_m_freem(m_notify);
23548c2654abSrjs 		SCTP_INP_WUNLOCK(stcb->sctp_ep);
23558c2654abSrjs 		return;
23568c2654abSrjs 	}
23578c2654abSrjs 	if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) &&
23588c2654abSrjs 	   ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)){
23598c2654abSrjs 		if (sctp_add_to_socket_q(stcb->sctp_ep, stcb)) {
23608c2654abSrjs 			stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
23618c2654abSrjs 		}
23628c2654abSrjs 	} else {
23638c2654abSrjs 		stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
23648c2654abSrjs 	}
23658c2654abSrjs 	SCTP_INP_WUNLOCK(stcb->sctp_ep);
23668c2654abSrjs 	sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
23678c2654abSrjs }
23688c2654abSrjs 
23698c2654abSrjs static void
sctp_notify_stream_reset(struct sctp_tcb * stcb,int number_entries,uint16_t * list,int flag)23708c2654abSrjs sctp_notify_stream_reset(struct sctp_tcb *stcb,
23718c2654abSrjs     int number_entries, uint16_t *list, int flag)
23728c2654abSrjs {
23738c2654abSrjs 	struct mbuf *m_notify;
23748c2654abSrjs 	struct sctp_stream_reset_event *strreset;
23758c2654abSrjs 	struct sockaddr_in6 sin6, lsa6;
23768c2654abSrjs 	const struct sockaddr *to;
23778c2654abSrjs 	int len;
23788c2654abSrjs 
23798c2654abSrjs 	if (!(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_STREAM_RESETEVNT))
23808c2654abSrjs 		/* event not enabled */
23818c2654abSrjs 		return;
23828c2654abSrjs 
23838c2654abSrjs 	MGETHDR(m_notify, M_DONTWAIT, MT_DATA);
23848c2654abSrjs 	if (m_notify == NULL)
23858c2654abSrjs 		/* no space left */
23868c2654abSrjs 		return;
23878c2654abSrjs 	m_notify->m_len = 0;
23888c2654abSrjs 	len = sizeof(struct sctp_stream_reset_event) + (number_entries * sizeof(uint16_t));
23898c2654abSrjs 	if (len > M_TRAILINGSPACE(m_notify)) {
23908c2654abSrjs 		MCLGET(m_notify, M_WAIT);
23918c2654abSrjs 	}
23928c2654abSrjs 	if (m_notify == NULL)
23938c2654abSrjs 		/* no clusters */
23948c2654abSrjs 		return;
23958c2654abSrjs 
23968c2654abSrjs 	if (len > M_TRAILINGSPACE(m_notify)) {
23978c2654abSrjs 		/* never enough room */
23988c2654abSrjs 		m_freem(m_notify);
23998c2654abSrjs 		return;
24008c2654abSrjs 	}
24018c2654abSrjs 	strreset = mtod(m_notify, struct sctp_stream_reset_event *);
24028c2654abSrjs 	strreset->strreset_type = SCTP_STREAM_RESET_EVENT;
24038c2654abSrjs 	if (number_entries == 0) {
24048c2654abSrjs 		strreset->strreset_flags = flag | SCTP_STRRESET_ALL_STREAMS;
24058c2654abSrjs 	} else {
24068c2654abSrjs 		strreset->strreset_flags = flag | SCTP_STRRESET_STREAM_LIST;
24078c2654abSrjs 	}
24088c2654abSrjs 	strreset->strreset_length = len;
24098c2654abSrjs 	strreset->strreset_assoc_id = sctp_get_associd(stcb);
24108c2654abSrjs 	if (number_entries) {
24118c2654abSrjs 		int i;
24128c2654abSrjs 		for (i=0; i<number_entries; i++) {
24138c2654abSrjs 			strreset->strreset_list[i] = list[i];
24148c2654abSrjs 		}
24158c2654abSrjs 	}
24168c2654abSrjs 	m_notify->m_flags |= M_EOR | M_NOTIFICATION;
24178c2654abSrjs 	m_notify->m_pkthdr.len = len;
2418d938d837Sozaki-r 	m_reset_rcvif(m_notify);
24198c2654abSrjs 	m_notify->m_len = len;
24208c2654abSrjs 	m_notify->m_next = NULL;
24218c2654abSrjs 	if (sctp_sbspace(&stcb->sctp_socket->so_rcv) < m_notify->m_len) {
24228c2654abSrjs 		/* no space */
24238c2654abSrjs 		sctp_m_freem(m_notify);
24248c2654abSrjs 		return;
24258c2654abSrjs 	}
24268c2654abSrjs 	to = rtcache_getdst(&stcb->asoc.primary_destination->ro);
24278c2654abSrjs 	if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) &&
24288c2654abSrjs 	    to->sa_family == AF_INET) {
24298c2654abSrjs 		const struct sockaddr_in *sin;
24308c2654abSrjs 
24318c2654abSrjs 		sin = satocsin(to);
24320a0528fdSrtr 		in6_sin_2_v4mapsin6(sin, &sin6);
24338c2654abSrjs 		to = (struct sockaddr *)&sin6;
24348c2654abSrjs 	}
24358c2654abSrjs 	/* check and strip embedded scope junk */
24368c2654abSrjs 	to = (const struct sockaddr *) sctp_recover_scope((const struct sockaddr_in6 *)to,
24378c2654abSrjs 	    &lsa6);
24388c2654abSrjs 	/* append to socket */
24398c2654abSrjs 	SCTP_TCB_UNLOCK(stcb);
24408c2654abSrjs 	SCTP_INP_WLOCK(stcb->sctp_ep);
24418c2654abSrjs 	SCTP_TCB_LOCK(stcb);
24428c2654abSrjs 	if (!sbappendaddr_nocheck(&stcb->sctp_socket->so_rcv, to,
24438c2654abSrjs 	    m_notify, NULL, stcb->asoc.my_vtag, stcb->sctp_ep)) {
24448c2654abSrjs 		/* not enough room */
24458c2654abSrjs 		sctp_m_freem(m_notify);
24468c2654abSrjs 		SCTP_INP_WUNLOCK(stcb->sctp_ep);
24478c2654abSrjs 		return;
24488c2654abSrjs 	}
24498c2654abSrjs 	if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) &&
24508c2654abSrjs 	   ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)){
24518c2654abSrjs 		if (sctp_add_to_socket_q(stcb->sctp_ep, stcb)) {
24528c2654abSrjs 			stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
24538c2654abSrjs 		}
24548c2654abSrjs 	} else {
24558c2654abSrjs 		stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
24568c2654abSrjs 	}
24578c2654abSrjs 	SCTP_INP_WUNLOCK(stcb->sctp_ep);
24588c2654abSrjs 	sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
24598c2654abSrjs }
24608c2654abSrjs 
24618c2654abSrjs 
24628c2654abSrjs void
sctp_ulp_notify(u_int32_t notification,struct sctp_tcb * stcb,u_int32_t error,void * data)24638c2654abSrjs sctp_ulp_notify(u_int32_t notification, struct sctp_tcb *stcb,
24648c2654abSrjs 		u_int32_t error, void *data)
24658c2654abSrjs {
24668c2654abSrjs 	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
24678c2654abSrjs 		/* No notifications up when we are in a no socket state */
24688c2654abSrjs 		return;
24698c2654abSrjs 	}
24708c2654abSrjs 	if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
24718c2654abSrjs 		/* Can't send up to a closed socket any notifications */
24728c2654abSrjs 		return;
24738c2654abSrjs 	}
24748c2654abSrjs 	switch (notification) {
24758c2654abSrjs 	case SCTP_NOTIFY_ASSOC_UP:
24768c2654abSrjs 		sctp_notify_assoc_change(SCTP_COMM_UP, stcb, error);
24778c2654abSrjs 		break;
24788c2654abSrjs 	case SCTP_NOTIFY_ASSOC_DOWN:
24798c2654abSrjs 		sctp_notify_assoc_change(SCTP_SHUTDOWN_COMP, stcb, error);
24808c2654abSrjs 		break;
24818c2654abSrjs 	case SCTP_NOTIFY_INTERFACE_DOWN:
24828c2654abSrjs 	{
24838c2654abSrjs 		struct sctp_nets *net;
24848c2654abSrjs 		net = (struct sctp_nets *)data;
24858c2654abSrjs 		sctp_notify_peer_addr_change(stcb, SCTP_ADDR_UNREACHABLE,
24868c2654abSrjs 		    rtcache_getdst(&net->ro), error);
24878c2654abSrjs 		break;
24888c2654abSrjs 	}
24898c2654abSrjs 	case SCTP_NOTIFY_INTERFACE_UP:
24908c2654abSrjs 	{
24918c2654abSrjs 		struct sctp_nets *net;
24928c2654abSrjs 		net = (struct sctp_nets *)data;
24938c2654abSrjs 		sctp_notify_peer_addr_change(stcb, SCTP_ADDR_AVAILABLE,
24948c2654abSrjs 		    rtcache_getdst(&net->ro), error);
24958c2654abSrjs 		break;
24968c2654abSrjs 	}
24978c2654abSrjs 	case SCTP_NOTIFY_INTERFACE_CONFIRMED:
24988c2654abSrjs 	{
24998c2654abSrjs 		struct sctp_nets *net;
25008c2654abSrjs 		net = (struct sctp_nets *)data;
25018c2654abSrjs 		sctp_notify_peer_addr_change(stcb, SCTP_ADDR_CONFIRMED,
25028c2654abSrjs 		    rtcache_getdst(&net->ro), error);
25038c2654abSrjs 		break;
25048c2654abSrjs 	}
25058c2654abSrjs 	case SCTP_NOTIFY_DG_FAIL:
25068c2654abSrjs 		sctp_notify_send_failed(stcb, error,
25078c2654abSrjs 		    (struct sctp_tmit_chunk *)data);
25088c2654abSrjs 		break;
25098c2654abSrjs 	case SCTP_NOTIFY_ADAPTION_INDICATION:
25108c2654abSrjs 		/* Here the error is the adaption indication */
25118c2654abSrjs 		sctp_notify_adaption_layer(stcb, error);
25128c2654abSrjs 		break;
25138c2654abSrjs 	case SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION:
25148c2654abSrjs 		sctp_notify_partial_delivery_indication(stcb, error);
25158c2654abSrjs 		break;
25168c2654abSrjs 	case SCTP_NOTIFY_STRDATA_ERR:
25178c2654abSrjs 		break;
25188c2654abSrjs 	case SCTP_NOTIFY_ASSOC_ABORTED:
25198c2654abSrjs 		sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error);
25208c2654abSrjs 		break;
25218c2654abSrjs 	case SCTP_NOTIFY_PEER_OPENED_STREAM:
25228c2654abSrjs 		break;
25238c2654abSrjs 	case SCTP_NOTIFY_STREAM_OPENED_OK:
25248c2654abSrjs 		break;
25258c2654abSrjs 	case SCTP_NOTIFY_ASSOC_RESTART:
25268c2654abSrjs 		sctp_notify_assoc_change(SCTP_RESTART, stcb, error);
25278c2654abSrjs 		break;
25288c2654abSrjs 	case SCTP_NOTIFY_HB_RESP:
25298c2654abSrjs 		break;
25308c2654abSrjs 	case SCTP_NOTIFY_STR_RESET_SEND:
25318c2654abSrjs 		sctp_notify_stream_reset(stcb, error, ((uint16_t *)data), SCTP_STRRESET_OUTBOUND_STR);
25328c2654abSrjs 		break;
25338c2654abSrjs 	case SCTP_NOTIFY_STR_RESET_RECV:
25348c2654abSrjs 		sctp_notify_stream_reset(stcb, error, ((uint16_t *)data), SCTP_STRRESET_INBOUND_STR);
25358c2654abSrjs 		break;
25368c2654abSrjs 	case SCTP_NOTIFY_ASCONF_ADD_IP:
25378c2654abSrjs 		sctp_notify_peer_addr_change(stcb, SCTP_ADDR_ADDED, data,
25388c2654abSrjs 		    error);
25398c2654abSrjs 		break;
25408c2654abSrjs 	case SCTP_NOTIFY_ASCONF_DELETE_IP:
25418c2654abSrjs 		sctp_notify_peer_addr_change(stcb, SCTP_ADDR_REMOVED, data,
25428c2654abSrjs 		    error);
25438c2654abSrjs 		break;
25448c2654abSrjs 	case SCTP_NOTIFY_ASCONF_SET_PRIMARY:
25458c2654abSrjs 		sctp_notify_peer_addr_change(stcb, SCTP_ADDR_MADE_PRIM, data,
25468c2654abSrjs 		    error);
25478c2654abSrjs 		break;
25488c2654abSrjs 	case SCTP_NOTIFY_ASCONF_SUCCESS:
25498c2654abSrjs 		break;
25508c2654abSrjs 	case SCTP_NOTIFY_ASCONF_FAILED:
25518c2654abSrjs 		break;
25528c2654abSrjs 	case SCTP_NOTIFY_PEER_SHUTDOWN:
25538c2654abSrjs 		sctp_notify_shutdown_event(stcb);
25548c2654abSrjs 		break;
25558c2654abSrjs 	default:
25568c2654abSrjs #ifdef SCTP_DEBUG
25578c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_UTIL1) {
25588c2654abSrjs 			printf("NOTIFY: unknown notification %xh (%u)\n",
25598c2654abSrjs 			    notification, notification);
25608c2654abSrjs 		}
25618c2654abSrjs #endif /* SCTP_DEBUG */
25628c2654abSrjs 		break;
25638c2654abSrjs 	} /* end switch */
25648c2654abSrjs }
25658c2654abSrjs 
25668c2654abSrjs void
sctp_report_all_outbound(struct sctp_tcb * stcb)25678c2654abSrjs sctp_report_all_outbound(struct sctp_tcb *stcb)
25688c2654abSrjs {
25698c2654abSrjs 	struct sctp_association *asoc;
25708c2654abSrjs 	struct sctp_stream_out *outs;
25718c2654abSrjs 	struct sctp_tmit_chunk *chk;
25728c2654abSrjs 
25738c2654abSrjs 	asoc = &stcb->asoc;
25748c2654abSrjs 
25758c2654abSrjs 	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
25768c2654abSrjs 		return;
25778c2654abSrjs 	}
25788c2654abSrjs 	/* now through all the gunk freeing chunks */
25798c2654abSrjs 	TAILQ_FOREACH(outs, &asoc->out_wheel, next_spoke) {
25808c2654abSrjs 		/* now clean up any chunks here */
25818c2654abSrjs 		chk = TAILQ_FIRST(&outs->outqueue);
25828c2654abSrjs 		while (chk) {
25838c2654abSrjs 			stcb->asoc.stream_queue_cnt--;
25848c2654abSrjs 			TAILQ_REMOVE(&outs->outqueue, chk, sctp_next);
25858c2654abSrjs 			sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb,
25868c2654abSrjs 			    SCTP_NOTIFY_DATAGRAM_UNSENT, chk);
25878c2654abSrjs 			sctp_m_freem(chk->data);
25888c2654abSrjs 			chk->data = NULL;
25898c2654abSrjs 			if (chk->whoTo)
25908c2654abSrjs 				sctp_free_remote_addr(chk->whoTo);
25918c2654abSrjs 			chk->whoTo = NULL;
25928c2654abSrjs 			chk->asoc = NULL;
25938c2654abSrjs 			/* Free the chunk */
25948c2654abSrjs 			SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk);
25958c2654abSrjs 			sctppcbinfo.ipi_count_chunk--;
25968c2654abSrjs 			if ((int)sctppcbinfo.ipi_count_chunk < 0) {
25978c2654abSrjs 				panic("Chunk count is negative");
25988c2654abSrjs 			}
25998c2654abSrjs 			sctppcbinfo.ipi_gencnt_chunk++;
26008c2654abSrjs 			chk = TAILQ_FIRST(&outs->outqueue);
26018c2654abSrjs 		}
26028c2654abSrjs 	}
26038c2654abSrjs 	/* pending send queue SHOULD be empty */
26048c2654abSrjs 	if (!TAILQ_EMPTY(&asoc->send_queue)) {
26058c2654abSrjs 		chk = TAILQ_FIRST(&asoc->send_queue);
26068c2654abSrjs 		while (chk) {
26078c2654abSrjs 			TAILQ_REMOVE(&asoc->send_queue, chk, sctp_next);
26088c2654abSrjs 			sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, SCTP_NOTIFY_DATAGRAM_UNSENT, chk);
26098c2654abSrjs 			sctp_m_freem(chk->data);
26108c2654abSrjs 			chk->data = NULL;
26118c2654abSrjs 			if (chk->whoTo)
26128c2654abSrjs 				sctp_free_remote_addr(chk->whoTo);
26138c2654abSrjs 			chk->whoTo = NULL;
26148c2654abSrjs 			SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk);
26158c2654abSrjs 			sctppcbinfo.ipi_count_chunk--;
26168c2654abSrjs 			if ((int)sctppcbinfo.ipi_count_chunk < 0) {
26178c2654abSrjs 				panic("Chunk count is negative");
26188c2654abSrjs 			}
26198c2654abSrjs 			sctppcbinfo.ipi_gencnt_chunk++;
26208c2654abSrjs 			chk = TAILQ_FIRST(&asoc->send_queue);
26218c2654abSrjs 		}
26228c2654abSrjs 	}
26238c2654abSrjs 	/* sent queue SHOULD be empty */
26248c2654abSrjs 	if (!TAILQ_EMPTY(&asoc->sent_queue)) {
26258c2654abSrjs 		chk = TAILQ_FIRST(&asoc->sent_queue);
26268c2654abSrjs 		while (chk) {
26278c2654abSrjs 			TAILQ_REMOVE(&asoc->sent_queue, chk, sctp_next);
26288c2654abSrjs 			sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb,
26298c2654abSrjs 			    SCTP_NOTIFY_DATAGRAM_SENT, chk);
26308c2654abSrjs 			sctp_m_freem(chk->data);
26318c2654abSrjs 			chk->data = NULL;
26328c2654abSrjs 			if (chk->whoTo)
26338c2654abSrjs 				sctp_free_remote_addr(chk->whoTo);
26348c2654abSrjs 			chk->whoTo = NULL;
26358c2654abSrjs 			SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk);
26368c2654abSrjs 			sctppcbinfo.ipi_count_chunk--;
26378c2654abSrjs 			if ((int)sctppcbinfo.ipi_count_chunk < 0) {
26388c2654abSrjs 				panic("Chunk count is negative");
26398c2654abSrjs 			}
26408c2654abSrjs 			sctppcbinfo.ipi_gencnt_chunk++;
26418c2654abSrjs 			chk = TAILQ_FIRST(&asoc->sent_queue);
26428c2654abSrjs 		}
26438c2654abSrjs 	}
26448c2654abSrjs }
26458c2654abSrjs 
26468c2654abSrjs void
sctp_abort_notification(struct sctp_tcb * stcb,int error)26478c2654abSrjs sctp_abort_notification(struct sctp_tcb *stcb, int error)
26488c2654abSrjs {
26498c2654abSrjs 
26508c2654abSrjs 	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
26518c2654abSrjs 		return;
26528c2654abSrjs 	}
26538c2654abSrjs 	/* Tell them we lost the asoc */
26548c2654abSrjs 	sctp_report_all_outbound(stcb);
26558c2654abSrjs 	sctp_ulp_notify(SCTP_NOTIFY_ASSOC_ABORTED, stcb, error, NULL);
26568c2654abSrjs }
26578c2654abSrjs 
26588c2654abSrjs void
sctp_abort_association(struct sctp_inpcb * inp,struct sctp_tcb * stcb,struct mbuf * m,int iphlen,struct sctphdr * sh,struct mbuf * op_err)26598c2654abSrjs sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
26608c2654abSrjs     struct mbuf *m, int iphlen, struct sctphdr *sh, struct mbuf *op_err)
26618c2654abSrjs {
26628c2654abSrjs 	u_int32_t vtag;
26638c2654abSrjs 
26648c2654abSrjs 	vtag = 0;
26658c2654abSrjs 	if (stcb != NULL) {
26668c2654abSrjs 		/* We have a TCB to abort, send notification too */
26678c2654abSrjs 		vtag = stcb->asoc.peer_vtag;
26688c2654abSrjs 		sctp_abort_notification(stcb, 0);
26698c2654abSrjs 	}
26708c2654abSrjs 	sctp_send_abort(m, iphlen, sh, vtag, op_err);
26718c2654abSrjs 	if (stcb != NULL) {
26728c2654abSrjs 		/* Ok, now lets free it */
26738c2654abSrjs 		sctp_free_assoc(inp, stcb);
26748c2654abSrjs 	} else {
26758c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
26768c2654abSrjs 			if (LIST_FIRST(&inp->sctp_asoc_list) == NULL) {
26778c2654abSrjs 				sctp_inpcb_free(inp, 1);
26788c2654abSrjs 			}
26798c2654abSrjs 		}
26808c2654abSrjs 	}
26818c2654abSrjs }
26828c2654abSrjs 
26838c2654abSrjs void
sctp_abort_an_association(struct sctp_inpcb * inp,struct sctp_tcb * stcb,int error,struct mbuf * op_err)26848c2654abSrjs sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
26858c2654abSrjs     int error, struct mbuf *op_err)
26868c2654abSrjs {
26878c2654abSrjs 
26888c2654abSrjs 	if (stcb == NULL) {
26898c2654abSrjs 		/* Got to have a TCB */
26908c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
26918c2654abSrjs 			if (LIST_FIRST(&inp->sctp_asoc_list) == NULL) {
26928c2654abSrjs 				sctp_inpcb_free(inp, 1);
26938c2654abSrjs 			}
26948c2654abSrjs 		}
26958c2654abSrjs 		return;
26968c2654abSrjs 	}
26978c2654abSrjs 	/* notify the ulp */
26988c2654abSrjs 	if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0)
26998c2654abSrjs 		sctp_abort_notification(stcb, error);
27008c2654abSrjs 	/* notify the peer */
27018c2654abSrjs 	sctp_send_abort_tcb(stcb, op_err);
27028c2654abSrjs 	/* now free the asoc */
27038c2654abSrjs 	sctp_free_assoc(inp, stcb);
27048c2654abSrjs }
27058c2654abSrjs 
27068c2654abSrjs void
sctp_handle_ootb(struct mbuf * m,int iphlen,int offset,struct sctphdr * sh,struct sctp_inpcb * inp,struct mbuf * op_err)27078c2654abSrjs sctp_handle_ootb(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
27088c2654abSrjs     struct sctp_inpcb *inp, struct mbuf *op_err)
27098c2654abSrjs {
27108c2654abSrjs 	struct sctp_chunkhdr *ch, chunk_buf;
27118c2654abSrjs 	unsigned int chk_length;
27128c2654abSrjs 
27138c2654abSrjs 	/* Generate a TO address for future reference */
27148c2654abSrjs 	if (inp && (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
27158c2654abSrjs 		if (LIST_FIRST(&inp->sctp_asoc_list) == NULL) {
27168c2654abSrjs 			sctp_inpcb_free(inp, 1);
27178c2654abSrjs 		}
27188c2654abSrjs 	}
27198c2654abSrjs 	ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset,
27208c2654abSrjs 	    sizeof(*ch), (u_int8_t *)&chunk_buf);
27218c2654abSrjs 	while (ch != NULL) {
27228c2654abSrjs 		chk_length = ntohs(ch->chunk_length);
27238c2654abSrjs 		if (chk_length < sizeof(*ch)) {
27248c2654abSrjs 			/* break to abort land */
27258c2654abSrjs 			break;
27268c2654abSrjs 		}
27278c2654abSrjs 		switch (ch->chunk_type) {
27288c2654abSrjs 		case SCTP_PACKET_DROPPED:
27298c2654abSrjs 			/* we don't respond to pkt-dropped */
27308c2654abSrjs 			return;
27318c2654abSrjs 		case SCTP_ABORT_ASSOCIATION:
27328c2654abSrjs 			/* we don't respond with an ABORT to an ABORT */
27338c2654abSrjs 			return;
27348c2654abSrjs 		case SCTP_SHUTDOWN_COMPLETE:
27358c2654abSrjs 			/*
27368c2654abSrjs 			 * we ignore it since we are not waiting for it
27378c2654abSrjs 			 * and peer is gone
27388c2654abSrjs 			 */
27398c2654abSrjs 			return;
27408c2654abSrjs 		case SCTP_SHUTDOWN_ACK:
27418c2654abSrjs 			sctp_send_shutdown_complete2(m, iphlen, sh);
27428c2654abSrjs 			return;
27438c2654abSrjs 		default:
27448c2654abSrjs 			break;
27458c2654abSrjs 		}
27468c2654abSrjs 		offset += SCTP_SIZE32(chk_length);
27478c2654abSrjs 		ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset,
27488c2654abSrjs 		    sizeof(*ch), (u_int8_t *)&chunk_buf);
27498c2654abSrjs 	}
27508c2654abSrjs 	sctp_send_abort(m, iphlen, sh, 0, op_err);
27518c2654abSrjs }
27528c2654abSrjs 
27538c2654abSrjs /*
27548c2654abSrjs  * check the inbound datagram to make sure there is not an abort
27558c2654abSrjs  * inside it, if there is return 1, else return 0.
27568c2654abSrjs  */
27578c2654abSrjs int
sctp_is_there_an_abort_here(struct mbuf * m,int iphlen,int * vtagfill)27588c2654abSrjs sctp_is_there_an_abort_here(struct mbuf *m, int iphlen, int *vtagfill)
27598c2654abSrjs {
27608c2654abSrjs 	struct sctp_chunkhdr *ch;
27618c2654abSrjs 	struct sctp_init_chunk *init_chk, chunk_buf;
27628c2654abSrjs 	int offset;
27638c2654abSrjs 	unsigned int chk_length;
27648c2654abSrjs 
27658c2654abSrjs 	offset = iphlen + sizeof(struct sctphdr);
27668c2654abSrjs 	ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, sizeof(*ch),
27678c2654abSrjs 	    (u_int8_t *)&chunk_buf);
27688c2654abSrjs 	while (ch != NULL) {
27698c2654abSrjs 		chk_length = ntohs(ch->chunk_length);
27708c2654abSrjs 		if (chk_length < sizeof(*ch)) {
27718c2654abSrjs 			/* packet is probably corrupt */
27728c2654abSrjs 			break;
27738c2654abSrjs 		}
27748c2654abSrjs 		/* we seem to be ok, is it an abort? */
27758c2654abSrjs 		if (ch->chunk_type == SCTP_ABORT_ASSOCIATION) {
27768c2654abSrjs 			/* yep, tell them */
27778c2654abSrjs 			return (1);
27788c2654abSrjs 		}
27798c2654abSrjs 		if (ch->chunk_type == SCTP_INITIATION) {
27808c2654abSrjs 			/* need to update the Vtag */
27818c2654abSrjs 			init_chk = (struct sctp_init_chunk *)sctp_m_getptr(m,
27828c2654abSrjs 			    offset, sizeof(*init_chk), (u_int8_t *)&chunk_buf);
27838c2654abSrjs 			if (init_chk != NULL) {
27848c2654abSrjs 				*vtagfill = ntohl(init_chk->init.initiate_tag);
27858c2654abSrjs 			}
27868c2654abSrjs 		}
27878c2654abSrjs 		/* Nope, move to the next chunk */
27888c2654abSrjs 		offset += SCTP_SIZE32(chk_length);
27898c2654abSrjs 		ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset,
27908c2654abSrjs 		    sizeof(*ch), (u_int8_t *)&chunk_buf);
27918c2654abSrjs 	}
27928c2654abSrjs 	return (0);
27938c2654abSrjs }
27948c2654abSrjs 
27958c2654abSrjs /*
27968c2654abSrjs  * currently (2/02), ifa_addr embeds scope_id's and don't
27978c2654abSrjs  * have sin6_scope_id set (i.e. it's 0)
27988c2654abSrjs  * so, create this function to compare link local scopes
27998c2654abSrjs  */
28008c2654abSrjs uint32_t
sctp_is_same_scope(const struct sockaddr_in6 * addr1,const struct sockaddr_in6 * addr2)2801afd52931Srjs sctp_is_same_scope(const struct sockaddr_in6 *addr1, const struct sockaddr_in6 *addr2)
28028c2654abSrjs {
28038c2654abSrjs 	struct sockaddr_in6 a, b;
28048c2654abSrjs 
28058c2654abSrjs 	/* save copies */
28068c2654abSrjs 	a = *addr1;
28078c2654abSrjs 	b = *addr2;
28088c2654abSrjs 
28098c2654abSrjs 	if (a.sin6_scope_id == 0)
28108c2654abSrjs 		if (sa6_recoverscope(&a)) {
28118c2654abSrjs 			/* can't get scope, so can't match */
28128c2654abSrjs 			return (0);
28138c2654abSrjs 		}
28148c2654abSrjs 	if (b.sin6_scope_id == 0)
28158c2654abSrjs 		if (sa6_recoverscope(&b)) {
28168c2654abSrjs 			/* can't get scope, so can't match */
28178c2654abSrjs 			return (0);
28188c2654abSrjs 		}
28198c2654abSrjs 	if (a.sin6_scope_id != b.sin6_scope_id)
28208c2654abSrjs 		return (0);
28218c2654abSrjs 
28228c2654abSrjs 	return (1);
28238c2654abSrjs }
28248c2654abSrjs 
28258c2654abSrjs /*
28268c2654abSrjs  * returns a sockaddr_in6 with embedded scope recovered and removed
28278c2654abSrjs  */
28288c2654abSrjs const struct sockaddr_in6 *
sctp_recover_scope(const struct sockaddr_in6 * addr,struct sockaddr_in6 * store)28298c2654abSrjs sctp_recover_scope(const struct sockaddr_in6 *addr, struct sockaddr_in6 *store)
28308c2654abSrjs {
28318c2654abSrjs 	const struct sockaddr_in6 *newaddr;
28328c2654abSrjs 
28338c2654abSrjs 	newaddr = addr;
28348c2654abSrjs 	/* check and strip embedded scope junk */
28358c2654abSrjs 	if (addr->sin6_family == AF_INET6) {
28368c2654abSrjs 		if (IN6_IS_SCOPE_LINKLOCAL(&addr->sin6_addr)) {
28378c2654abSrjs 			if (addr->sin6_scope_id == 0) {
28388c2654abSrjs 				*store = *addr;
28398c2654abSrjs 				if (sa6_recoverscope(store) == 0) {
28408c2654abSrjs 					/* use the recovered scope */
28418c2654abSrjs 					newaddr = store;
28428c2654abSrjs 				}
28438c2654abSrjs 				/* else, return the original "to" addr */
28448c2654abSrjs 			}
28458c2654abSrjs 		}
28468c2654abSrjs 	}
28478c2654abSrjs 	return (newaddr);
28488c2654abSrjs }
28498c2654abSrjs 
28508c2654abSrjs /*
28518c2654abSrjs  * are the two addresses the same?  currently a "scopeless" check
28528c2654abSrjs  * returns: 1 if same, 0 if not
28538c2654abSrjs  */
28548c2654abSrjs int
sctp_cmpaddr(const struct sockaddr * sa1,const struct sockaddr * sa2)28558c2654abSrjs sctp_cmpaddr(const struct sockaddr *sa1, const struct sockaddr *sa2)
28568c2654abSrjs {
28578c2654abSrjs 
28588c2654abSrjs 	/* must be valid */
28598c2654abSrjs 	if (sa1 == NULL || sa2 == NULL)
28608c2654abSrjs 		return (0);
28618c2654abSrjs 
28628c2654abSrjs 	/* must be the same family */
28638c2654abSrjs 	if (sa1->sa_family != sa2->sa_family)
28648c2654abSrjs 		return (0);
28658c2654abSrjs 
28668c2654abSrjs 	if (sa1->sa_family == AF_INET6) {
28678c2654abSrjs 		/* IPv6 addresses */
28688c2654abSrjs 		const struct sockaddr_in6 *sin6_1, *sin6_2;
28698c2654abSrjs 
28708c2654abSrjs 		sin6_1 = (const struct sockaddr_in6 *)sa1;
28718c2654abSrjs 		sin6_2 = (const struct sockaddr_in6 *)sa2;
28728c2654abSrjs 		return (SCTP6_ARE_ADDR_EQUAL(&sin6_1->sin6_addr,
28738c2654abSrjs 		    &sin6_2->sin6_addr));
28748c2654abSrjs 	} else if (sa1->sa_family == AF_INET) {
28758c2654abSrjs 		/* IPv4 addresses */
28768c2654abSrjs 		const struct sockaddr_in *sin_1, *sin_2;
28778c2654abSrjs 
28788c2654abSrjs 		sin_1 = (const struct sockaddr_in *)sa1;
28798c2654abSrjs 		sin_2 = (const struct sockaddr_in *)sa2;
28808c2654abSrjs 		return (sin_1->sin_addr.s_addr == sin_2->sin_addr.s_addr);
28818c2654abSrjs 	} else {
28828c2654abSrjs 		/* we don't do these... */
28838c2654abSrjs 		return (0);
28848c2654abSrjs 	}
28858c2654abSrjs }
28868c2654abSrjs 
28878c2654abSrjs void
sctp_print_address(const struct sockaddr * sa)28888c2654abSrjs sctp_print_address(const struct sockaddr *sa)
28898c2654abSrjs {
289028f4c24cSryo 	char ip6buf[INET6_ADDRSTRLEN];
28918c2654abSrjs 
28928c2654abSrjs 	if (sa->sa_family == AF_INET6) {
28938c2654abSrjs 		const struct sockaddr_in6 *sin6;
28948c2654abSrjs 		sin6 = (const struct sockaddr_in6 *)sa;
28958c2654abSrjs 		printf("IPv6 address: %s:%d scope:%u\n",
289635561f6bSchristos 		    IN6_PRINT(ip6buf, &sin6->sin6_addr), ntohs(sin6->sin6_port),
28978c2654abSrjs 		    sin6->sin6_scope_id);
28988c2654abSrjs 	} else if (sa->sa_family == AF_INET) {
28998c2654abSrjs 		const struct sockaddr_in *sin;
29008c2654abSrjs 		sin = (const struct sockaddr_in *)sa;
29018c2654abSrjs 		printf("IPv4 address: %s:%d\n", inet_ntoa(sin->sin_addr),
29028c2654abSrjs 		    ntohs(sin->sin_port));
29038c2654abSrjs 	} else {
29048c2654abSrjs 		printf("?\n");
29058c2654abSrjs 	}
29068c2654abSrjs }
29078c2654abSrjs 
29088c2654abSrjs void
sctp_print_address_pkt(struct ip * iph,struct sctphdr * sh)29098c2654abSrjs sctp_print_address_pkt(struct ip *iph, struct sctphdr *sh)
29108c2654abSrjs {
29118c2654abSrjs 	if (iph->ip_v == IPVERSION) {
29128c2654abSrjs 		struct sockaddr_in lsa, fsa;
29138c2654abSrjs 
29148c2654abSrjs 		memset(&lsa, 0, sizeof(lsa));
29158c2654abSrjs 		lsa.sin_len = sizeof(lsa);
29168c2654abSrjs 		lsa.sin_family = AF_INET;
29178c2654abSrjs 		lsa.sin_addr = iph->ip_src;
29188c2654abSrjs 		lsa.sin_port = sh->src_port;
29198c2654abSrjs 		memset(&fsa, 0, sizeof(fsa));
29208c2654abSrjs 		fsa.sin_len = sizeof(fsa);
29218c2654abSrjs 		fsa.sin_family = AF_INET;
29228c2654abSrjs 		fsa.sin_addr = iph->ip_dst;
29238c2654abSrjs 		fsa.sin_port = sh->dest_port;
29248c2654abSrjs 		printf("src: ");
29258c2654abSrjs 		sctp_print_address((struct sockaddr *)&lsa);
29268c2654abSrjs 		printf("dest: ");
29278c2654abSrjs 		sctp_print_address((struct sockaddr *)&fsa);
29288c2654abSrjs 	} else if (iph->ip_v == (IPV6_VERSION >> 4)) {
29298c2654abSrjs 		struct ip6_hdr *ip6;
29308c2654abSrjs 		struct sockaddr_in6 lsa6, fsa6;
29318c2654abSrjs 
29328c2654abSrjs 		ip6 = (struct ip6_hdr *)iph;
29338c2654abSrjs 		memset(&lsa6, 0, sizeof(lsa6));
29348c2654abSrjs 		lsa6.sin6_len = sizeof(lsa6);
29358c2654abSrjs 		lsa6.sin6_family = AF_INET6;
29368c2654abSrjs 		lsa6.sin6_addr = ip6->ip6_src;
29378c2654abSrjs 		lsa6.sin6_port = sh->src_port;
29388c2654abSrjs 		memset(&fsa6, 0, sizeof(fsa6));
29398c2654abSrjs 		fsa6.sin6_len = sizeof(fsa6);
29408c2654abSrjs 		fsa6.sin6_family = AF_INET6;
29418c2654abSrjs 		fsa6.sin6_addr = ip6->ip6_dst;
29428c2654abSrjs 		fsa6.sin6_port = sh->dest_port;
29438c2654abSrjs 		printf("src: ");
29448c2654abSrjs 		sctp_print_address((struct sockaddr *)&lsa6);
29458c2654abSrjs 		printf("dest: ");
29468c2654abSrjs 		sctp_print_address((struct sockaddr *)&fsa6);
29478c2654abSrjs 	}
29488c2654abSrjs }
29498c2654abSrjs 
29508c2654abSrjs #if defined(__FreeBSD__) || defined(__APPLE__)
29518c2654abSrjs 
29528c2654abSrjs /* cloned from uipc_socket.c */
29538c2654abSrjs 
29548c2654abSrjs #define SCTP_SBLINKRECORD(sb, m0) do {					\
29558c2654abSrjs 	if ((sb)->sb_lastrecord != NULL)				\
29568c2654abSrjs 		(sb)->sb_lastrecord->m_nextpkt = (m0);			\
29578c2654abSrjs 	else								\
29588c2654abSrjs 		(sb)->sb_mb = (m0);					\
29598c2654abSrjs 	(sb)->sb_lastrecord = (m0);					\
29608c2654abSrjs } while (/*CONSTCOND*/0)
29618c2654abSrjs #endif
29628c2654abSrjs 
29638c2654abSrjs 
29648c2654abSrjs int
sbappendaddr_nocheck(struct sockbuf * sb,const struct sockaddr * asa,struct mbuf * m0,struct mbuf * control,u_int32_t tag,struct sctp_inpcb * inp)29658c2654abSrjs sbappendaddr_nocheck(struct sockbuf *sb, const struct sockaddr *asa,
29668c2654abSrjs 	struct mbuf *m0, struct mbuf *control,
29678c2654abSrjs 	u_int32_t tag, struct sctp_inpcb *inp)
29688c2654abSrjs {
29698c2654abSrjs #ifdef __NetBSD__
29708c2654abSrjs 	struct mbuf *m, *n;
29718c2654abSrjs 
29728c2654abSrjs 	if (m0 && (m0->m_flags & M_PKTHDR) == 0)
29738c2654abSrjs 		panic("sbappendaddr_nocheck");
29748c2654abSrjs 
29758c2654abSrjs 	m0->m_pkthdr.csum_data = (int)tag;
29768c2654abSrjs 
29778c2654abSrjs 	for (n = control; n; n = n->m_next) {
29788c2654abSrjs 		if (n->m_next == 0)	/* keep pointer to last control buf */
29798c2654abSrjs 			break;
29808c2654abSrjs 	}
29818c2654abSrjs 	if (((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) == 0) ||
29828c2654abSrjs 	    ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)== 0)) {
29838c2654abSrjs 		MGETHDR(m, M_DONTWAIT, MT_SONAME);
29848c2654abSrjs 		if (m == 0)
29858c2654abSrjs 			return (0);
29868c2654abSrjs 
29878c2654abSrjs 		m->m_len = asa->sa_len;
29888c2654abSrjs 		memcpy(mtod(m, void *), (const void *)asa, asa->sa_len);
29898c2654abSrjs 	} else {
29908c2654abSrjs 		m = NULL;
29918c2654abSrjs 	}
29928c2654abSrjs 	if (n) {
29938c2654abSrjs 		n->m_next = m0;		/* concatenate data to control */
29948c2654abSrjs 	}else {
29958c2654abSrjs 		control = m0;
29968c2654abSrjs 	}
29978c2654abSrjs 	if (m)
29988c2654abSrjs 		m->m_next = control;
29998c2654abSrjs 	else
30008c2654abSrjs 		m = control;
30018c2654abSrjs 	m->m_pkthdr.csum_data = tag;
30028c2654abSrjs 
30038c2654abSrjs 	for (n = m; n; n = n->m_next)
30048c2654abSrjs 		sballoc(sb, n);
30058c2654abSrjs 	if ((n = sb->sb_mb) != NULL) {
30068c2654abSrjs 		if ((n->m_nextpkt != inp->sb_last_mpkt) && (n->m_nextpkt == NULL)) {
30078c2654abSrjs 			inp->sb_last_mpkt = NULL;
30088c2654abSrjs 		}
30098c2654abSrjs 		if (inp->sb_last_mpkt)
30108c2654abSrjs 			inp->sb_last_mpkt->m_nextpkt = m;
30118c2654abSrjs  		else {
30128c2654abSrjs 			while (n->m_nextpkt) {
30138c2654abSrjs 				n = n->m_nextpkt;
30148c2654abSrjs 			}
30158c2654abSrjs 			n->m_nextpkt = m;
30168c2654abSrjs 		}
30178c2654abSrjs 		inp->sb_last_mpkt = m;
30188c2654abSrjs 	} else {
30198c2654abSrjs 		inp->sb_last_mpkt = sb->sb_mb = m;
30208c2654abSrjs 		inp->sctp_vtag_first = tag;
30218c2654abSrjs 	}
30228c2654abSrjs 	return (1);
30238c2654abSrjs #endif
30248c2654abSrjs #if defined(__FreeBSD__) || defined(__APPLE__)
30258c2654abSrjs 	struct mbuf *m, *n, *nlast;
30268c2654abSrjs 	int cnt=0;
30278c2654abSrjs 
30288c2654abSrjs 	if (m0 && (m0->m_flags & M_PKTHDR) == 0)
30298c2654abSrjs 		panic("sbappendaddr_nocheck");
30308c2654abSrjs 
30318c2654abSrjs 	for (n = control; n; n = n->m_next) {
30328c2654abSrjs 		if (n->m_next == 0)	/* get pointer to last control buf */
30338c2654abSrjs 			break;
30348c2654abSrjs 	}
30358c2654abSrjs 	if (((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) == 0) ||
30368c2654abSrjs 	    ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)== 0)) {
30378c2654abSrjs 		if (asa->sa_len > MHLEN)
30388c2654abSrjs 			return (0);
30398c2654abSrjs  try_again:
30408c2654abSrjs 		MGETHDR(m, M_DONTWAIT, MT_SONAME);
30418c2654abSrjs 		if (m == 0)
30428c2654abSrjs 			return (0);
30438c2654abSrjs 		m->m_len = 0;
30448c2654abSrjs 		/* safety */
30458c2654abSrjs 		if (m == m0) {
30468c2654abSrjs 			printf("Duplicate mbuf allocated %p in and mget returned %p?\n",
30478c2654abSrjs 			       m0, m);
30488c2654abSrjs 			if (cnt) {
30498c2654abSrjs 				panic("more than once");
30508c2654abSrjs 			}
30518c2654abSrjs 			cnt++;
30528c2654abSrjs 			goto try_again;
30538c2654abSrjs 		}
30548c2654abSrjs 		m->m_len = asa->sa_len;
30558c2654abSrjs 		bcopy((void *)asa, mtod(m, void *), asa->sa_len);
30568c2654abSrjs 	}
30578c2654abSrjs 	else {
30588c2654abSrjs 		m = NULL;
30598c2654abSrjs 	}
30608c2654abSrjs 	if (n)
30618c2654abSrjs 		n->m_next = m0;		/* concatenate data to control */
30628c2654abSrjs 	else
30638c2654abSrjs 		control = m0;
30648c2654abSrjs 	if (m)
30658c2654abSrjs 		m->m_next = control;
30668c2654abSrjs 	else
30678c2654abSrjs 		m = control;
30688c2654abSrjs 	m->m_pkthdr.csum_data = (int)tag;
30698c2654abSrjs 
30708c2654abSrjs 	for (n = m; n; n = n->m_next)
30718c2654abSrjs 		sballoc(sb, n);
30728c2654abSrjs 	nlast = n;
30738c2654abSrjs 	if (sb->sb_mb == NULL) {
30748c2654abSrjs 		inp->sctp_vtag_first = tag;
30758c2654abSrjs 	}
30768c2654abSrjs 
30778c2654abSrjs #ifdef __FREEBSD__
30788c2654abSrjs 	if (sb->sb_mb == NULL)
30798c2654abSrjs 		inp->sctp_vtag_first = tag;
30808c2654abSrjs 	SCTP_SBLINKRECORD(sb, m);
30818c2654abSrjs 	sb->sb_mbtail = nlast;
30828c2654abSrjs #else
30838c2654abSrjs 	if ((n = sb->sb_mb) != NULL) {
30848c2654abSrjs 		if ((n->m_nextpkt != inp->sb_last_mpkt) && (n->m_nextpkt == NULL)) {
30858c2654abSrjs 			inp->sb_last_mpkt = NULL;
30868c2654abSrjs 		}
30878c2654abSrjs 		if (inp->sb_last_mpkt)
30888c2654abSrjs 			inp->sb_last_mpkt->m_nextpkt = m;
30898c2654abSrjs  		else {
30908c2654abSrjs 			while (n->m_nextpkt) {
30918c2654abSrjs 				n = n->m_nextpkt;
30928c2654abSrjs 			}
30938c2654abSrjs 			n->m_nextpkt = m;
30948c2654abSrjs 		}
30958c2654abSrjs 		inp->sb_last_mpkt = m;
30968c2654abSrjs 	} else {
30978c2654abSrjs 		inp->sb_last_mpkt = sb->sb_mb = m;
30988c2654abSrjs 		inp->sctp_vtag_first = tag;
30998c2654abSrjs 	}
31008c2654abSrjs #endif
31018c2654abSrjs 	return (1);
31028c2654abSrjs #endif
31038c2654abSrjs #ifdef __OpenBSD__
31048c2654abSrjs 	struct mbuf *m, *n;
31058c2654abSrjs 
31068c2654abSrjs 	if (m0 && (m0->m_flags & M_PKTHDR) == 0)
31078c2654abSrjs 		panic("sbappendaddr_nocheck");
31088c2654abSrjs 	m0->m_pkthdr.csum = (int)tag;
31098c2654abSrjs 	for (n = control; n; n = n->m_next) {
31108c2654abSrjs 		if (n->m_next == 0)	/* keep pointer to last control buf */
31118c2654abSrjs 			break;
31128c2654abSrjs 	}
31138c2654abSrjs 	if (((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) == 0) ||
31148c2654abSrjs 	    ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)== 0)) {
31158c2654abSrjs 		if (asa->sa_len > MHLEN)
31168c2654abSrjs 			return (0);
31178c2654abSrjs 		MGETHDR(m, M_DONTWAIT, MT_SONAME);
31188c2654abSrjs 		if (m == 0)
31198c2654abSrjs 			return (0);
31208c2654abSrjs 		m->m_len = asa->sa_len;
31218c2654abSrjs 		bcopy((void *)asa, mtod(m, void *), asa->sa_len);
31228c2654abSrjs 	} else {
31238c2654abSrjs 		m = NULL;
31248c2654abSrjs 	}
31258c2654abSrjs 	if (n)
31268c2654abSrjs 		n->m_next = m0;		/* concatenate data to control */
31278c2654abSrjs 	else
31288c2654abSrjs 		control = m0;
31298c2654abSrjs 
31308c2654abSrjs 	m->m_pkthdr.csum = (int)tag;
31318c2654abSrjs 	m->m_next = control;
31328c2654abSrjs 	for (n = m; n; n = n->m_next)
31338c2654abSrjs 		sballoc(sb, n);
31348c2654abSrjs 	if ((n = sb->sb_mb) != NULL) {
31358c2654abSrjs 		if ((n->m_nextpkt != inp->sb_last_mpkt) && (n->m_nextpkt == NULL)) {
31368c2654abSrjs 			inp->sb_last_mpkt = NULL;
31378c2654abSrjs 		}
31388c2654abSrjs 		if (inp->sb_last_mpkt)
31398c2654abSrjs 			inp->sb_last_mpkt->m_nextpkt = m;
31408c2654abSrjs  		else {
31418c2654abSrjs 			while (n->m_nextpkt) {
31428c2654abSrjs 				n = n->m_nextpkt;
31438c2654abSrjs 			}
31448c2654abSrjs 			n->m_nextpkt = m;
31458c2654abSrjs 		}
31468c2654abSrjs 		inp->sb_last_mpkt = m;
31478c2654abSrjs 	} else {
31488c2654abSrjs 		inp->sb_last_mpkt = sb->sb_mb = m;
31498c2654abSrjs 		inp->sctp_vtag_first = tag;
31508c2654abSrjs 	}
31518c2654abSrjs 	return (1);
31528c2654abSrjs #endif
31538c2654abSrjs }
31548c2654abSrjs 
31558c2654abSrjs /*************HOLD THIS COMMENT FOR PATCH FILE OF
31568c2654abSrjs  *************ALTERNATE ROUTING CODE
31578c2654abSrjs  */
31588c2654abSrjs 
31598c2654abSrjs /*************HOLD THIS COMMENT FOR END OF PATCH FILE OF
31608c2654abSrjs  *************ALTERNATE ROUTING CODE
31618c2654abSrjs  */
31628c2654abSrjs 
31638c2654abSrjs struct mbuf *
sctp_generate_invmanparam(int err)31648c2654abSrjs sctp_generate_invmanparam(int err)
31658c2654abSrjs {
31668c2654abSrjs 	/* Return a MBUF with a invalid mandatory parameter */
31678c2654abSrjs 	struct mbuf *m;
31688c2654abSrjs 
31698c2654abSrjs 	MGET(m, M_DONTWAIT, MT_DATA);
31708c2654abSrjs 	if (m) {
31718c2654abSrjs 		struct sctp_paramhdr *ph;
31728c2654abSrjs 		m->m_len = sizeof(struct sctp_paramhdr);
31738c2654abSrjs 		ph = mtod(m, struct sctp_paramhdr *);
31748c2654abSrjs 		ph->param_length = htons(sizeof(struct sctp_paramhdr));
31758c2654abSrjs 		ph->param_type = htons(err);
31768c2654abSrjs 	}
31778c2654abSrjs 	return (m);
31788c2654abSrjs }
31798c2654abSrjs 
31808c2654abSrjs static int
sctp_should_be_moved(struct mbuf * this,struct sctp_association * asoc)31818c2654abSrjs sctp_should_be_moved(struct mbuf *this, struct sctp_association *asoc)
31828c2654abSrjs {
31838c2654abSrjs 	struct mbuf *m;
31848c2654abSrjs 	/*
31858c2654abSrjs 	 * given a mbuf chain, look through it finding
31868c2654abSrjs 	 * the M_PKTHDR and return 1 if it belongs to
31878c2654abSrjs 	 * the association given. We tell this by
31888c2654abSrjs 	 * a kludge where we stuff the my_vtag of the asoc
31898c2654abSrjs 	 * into the m->m_pkthdr.csum_data/csum field.
31908c2654abSrjs 	 */
31918c2654abSrjs 	m = this;
31928c2654abSrjs 	while (m) {
31938c2654abSrjs 		if (m->m_flags & M_PKTHDR) {
31948c2654abSrjs 			/* check it */
31958c2654abSrjs #if defined(__OpenBSD__)
31968c2654abSrjs 			if ((u_int32_t)m->m_pkthdr.csum == asoc->my_vtag)
31978c2654abSrjs #else
31988c2654abSrjs 			if ((u_int32_t)m->m_pkthdr.csum_data == asoc->my_vtag)
31998c2654abSrjs #endif
32008c2654abSrjs 			{
32018c2654abSrjs 				/* Yep */
32028c2654abSrjs 				return (1);
32038c2654abSrjs 			}
32048c2654abSrjs 		}
32058c2654abSrjs 		m = m->m_next;
32068c2654abSrjs 	}
32078c2654abSrjs 	return (0);
32088c2654abSrjs }
32098c2654abSrjs 
32108c2654abSrjs u_int32_t
sctp_get_first_vtag_from_sb(struct socket * so)32118c2654abSrjs sctp_get_first_vtag_from_sb(struct socket *so)
32128c2654abSrjs {
32138c2654abSrjs 	struct mbuf *this, *at;
32148c2654abSrjs 	u_int32_t retval;
32158c2654abSrjs 
32168c2654abSrjs 	retval = 0;
32178c2654abSrjs 	if (so->so_rcv.sb_mb) {
32188c2654abSrjs 		/* grubbing time */
32198c2654abSrjs 		this = so->so_rcv.sb_mb;
32208c2654abSrjs 		while (this) {
32218c2654abSrjs 			at = this;
32228c2654abSrjs 			/* get to the m_pkthdr */
32238c2654abSrjs 			while (at) {
32248c2654abSrjs 				if (at->m_flags & M_PKTHDR)
32258c2654abSrjs 					break;
32268c2654abSrjs 				else {
32278c2654abSrjs 					at = at->m_next;
32288c2654abSrjs 				}
32298c2654abSrjs 			}
32308c2654abSrjs 			/* now do we have a m_pkthdr */
32318c2654abSrjs 			if (at && (at->m_flags & M_PKTHDR)) {
32328c2654abSrjs 				/* check it */
32338c2654abSrjs #if defined(__OpenBSD__)
32348c2654abSrjs 				if ((u_int32_t)at->m_pkthdr.csum != 0)
32358c2654abSrjs #else
32368c2654abSrjs 				if ((u_int32_t)at->m_pkthdr.csum_data != 0)
32378c2654abSrjs #endif
32388c2654abSrjs 				{
32398c2654abSrjs 					/* its the one */
32408c2654abSrjs #if defined(__OpenBSD__)
32418c2654abSrjs 					retval = (u_int32_t)at->m_pkthdr.csum;
32428c2654abSrjs #else
32438c2654abSrjs 					retval =
32448c2654abSrjs 					    (u_int32_t)at->m_pkthdr.csum_data;
32458c2654abSrjs #endif
32468c2654abSrjs 					break;
32478c2654abSrjs 				}
32488c2654abSrjs 			}
32498c2654abSrjs 			this = this->m_nextpkt;
32508c2654abSrjs 		}
32518c2654abSrjs 
32528c2654abSrjs 	}
32538c2654abSrjs 	return (retval);
32548c2654abSrjs 
32558c2654abSrjs }
32568c2654abSrjs void
sctp_grub_through_socket_buffer(struct sctp_inpcb * inp,struct socket * old,struct socket * new,struct sctp_tcb * stcb)32578c2654abSrjs sctp_grub_through_socket_buffer(struct sctp_inpcb *inp, struct socket *old,
32588c2654abSrjs     struct socket *new, struct sctp_tcb *stcb)
32598c2654abSrjs {
32608c2654abSrjs 	struct mbuf **put, **take, *next, *this;
32618c2654abSrjs 	struct sockbuf *old_sb, *new_sb;
32628c2654abSrjs 	struct sctp_association *asoc;
32638c2654abSrjs 	int moved_top = 0;
32648c2654abSrjs 
32658c2654abSrjs 	asoc = &stcb->asoc;
32668c2654abSrjs 	old_sb = &old->so_rcv;
32678c2654abSrjs 	new_sb = &new->so_rcv;
32688c2654abSrjs 	if (old_sb->sb_mb == NULL) {
32698c2654abSrjs 		/* Nothing to move */
32708c2654abSrjs 		return;
32718c2654abSrjs 	}
32728c2654abSrjs 
32738c2654abSrjs 	if (inp->sctp_vtag_first == asoc->my_vtag) {
32748c2654abSrjs 		/* First one must be moved */
32758c2654abSrjs 		struct mbuf *mm;
32768c2654abSrjs 		for (mm = old_sb->sb_mb; mm; mm = mm->m_next) {
32778c2654abSrjs 			/*
32788c2654abSrjs 			 * Go down the chain and fix
32798c2654abSrjs 			 * the space allocation of the
32808c2654abSrjs 			 * two sockets.
32818c2654abSrjs 			 */
32828c2654abSrjs 			sbfree(old_sb, mm);
32838c2654abSrjs 			sballoc(new_sb, mm);
32848c2654abSrjs 		}
32858c2654abSrjs 		new_sb->sb_mb = old_sb->sb_mb;
32868c2654abSrjs 		old_sb->sb_mb = new_sb->sb_mb->m_nextpkt;
32878c2654abSrjs 		new_sb->sb_mb->m_nextpkt = NULL;
32888c2654abSrjs 		put = &new_sb->sb_mb->m_nextpkt;
32898c2654abSrjs 		moved_top = 1;
32908c2654abSrjs 	} else {
32918c2654abSrjs 		put = &new_sb->sb_mb;
32928c2654abSrjs 	}
32938c2654abSrjs 
32948c2654abSrjs 	take = &old_sb->sb_mb;
32958c2654abSrjs 	next = old_sb->sb_mb;
32968c2654abSrjs 	while (next) {
32978c2654abSrjs 		this = next;
3298146d03e6Sandvar 		/* position for next one */
32998c2654abSrjs 		next = this->m_nextpkt;
33008c2654abSrjs 		/* check the tag of this packet */
33018c2654abSrjs 		if (sctp_should_be_moved(this, asoc)) {
33028c2654abSrjs 			/* yes this needs to be moved */
33038c2654abSrjs 			struct mbuf *mm;
33048c2654abSrjs 			*take = this->m_nextpkt;
33058c2654abSrjs 			this->m_nextpkt = NULL;
33068c2654abSrjs 			*put = this;
33078c2654abSrjs 			for (mm = this; mm; mm = mm->m_next) {
33088c2654abSrjs 				/*
33098c2654abSrjs 				 * Go down the chain and fix
33108c2654abSrjs 				 * the space allocation of the
33118c2654abSrjs 				 * two sockets.
33128c2654abSrjs 				 */
33138c2654abSrjs 				sbfree(old_sb, mm);
33148c2654abSrjs 				sballoc(new_sb, mm);
33158c2654abSrjs 			}
33168c2654abSrjs 			put = &this->m_nextpkt;
33178c2654abSrjs 
33188c2654abSrjs 		} else {
33198c2654abSrjs 			/* no advance our take point. */
33208c2654abSrjs 			take = &this->m_nextpkt;
33218c2654abSrjs 		}
33228c2654abSrjs 	}
33238c2654abSrjs 	if (moved_top) {
33248c2654abSrjs 		/*
3325146d03e6Sandvar 		 * Ok so now we must re-position vtag_first to
33268c2654abSrjs 		 * match the new first one since we moved the
33278c2654abSrjs 		 * mbuf at the top.
33288c2654abSrjs 		 */
33298c2654abSrjs 		inp->sctp_vtag_first = sctp_get_first_vtag_from_sb(old);
33308c2654abSrjs 	}
33318c2654abSrjs }
33328c2654abSrjs 
33338c2654abSrjs void
sctp_free_bufspace(struct sctp_tcb * stcb,struct sctp_association * asoc,struct sctp_tmit_chunk * tp1)33348c2654abSrjs sctp_free_bufspace(struct sctp_tcb *stcb, struct sctp_association *asoc,
33358c2654abSrjs     struct sctp_tmit_chunk *tp1)
33368c2654abSrjs {
33378c2654abSrjs 	if (tp1->data == NULL) {
33388c2654abSrjs 		return;
33398c2654abSrjs 	}
33408c2654abSrjs #ifdef SCTP_MBCNT_LOGGING
33418c2654abSrjs 	sctp_log_mbcnt(SCTP_LOG_MBCNT_DECREASE,
33428c2654abSrjs 		       asoc->total_output_queue_size,
33438c2654abSrjs 		       tp1->book_size,
33448c2654abSrjs 		       asoc->total_output_mbuf_queue_size,
33458c2654abSrjs 		       tp1->mbcnt);
33468c2654abSrjs #endif
33478c2654abSrjs 	if (asoc->total_output_queue_size >= tp1->book_size) {
33488c2654abSrjs 		asoc->total_output_queue_size -= tp1->book_size;
33498c2654abSrjs 	} else {
33508c2654abSrjs 		asoc->total_output_queue_size = 0;
33518c2654abSrjs 	}
33528c2654abSrjs 
33538c2654abSrjs 	/* Now free the mbuf */
33548c2654abSrjs 	if (asoc->total_output_mbuf_queue_size >= tp1->mbcnt) {
33558c2654abSrjs 		asoc->total_output_mbuf_queue_size -= tp1->mbcnt;
33568c2654abSrjs 	} else {
33578c2654abSrjs 		asoc->total_output_mbuf_queue_size = 0;
33588c2654abSrjs 	}
33598c2654abSrjs 	if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
33608c2654abSrjs 	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
33618c2654abSrjs 		if (stcb->sctp_socket->so_snd.sb_cc >= tp1->book_size) {
33628c2654abSrjs 			stcb->sctp_socket->so_snd.sb_cc -= tp1->book_size;
33638c2654abSrjs 		} else {
33648c2654abSrjs 			stcb->sctp_socket->so_snd.sb_cc = 0;
33658c2654abSrjs 
33668c2654abSrjs 		}
33678c2654abSrjs 		if (stcb->sctp_socket->so_snd.sb_mbcnt >= tp1->mbcnt) {
33688c2654abSrjs 			stcb->sctp_socket->so_snd.sb_mbcnt -= tp1->mbcnt;
33698c2654abSrjs 		} else {
33708c2654abSrjs 			stcb->sctp_socket->so_snd.sb_mbcnt = 0;
33718c2654abSrjs 		}
33728c2654abSrjs 	}
33738c2654abSrjs }
33748c2654abSrjs 
33758c2654abSrjs int
sctp_release_pr_sctp_chunk(struct sctp_tcb * stcb,struct sctp_tmit_chunk * tp1,int reason,struct sctpchunk_listhead * queue)33768c2654abSrjs sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1,
33778c2654abSrjs     int reason, struct sctpchunk_listhead *queue)
33788c2654abSrjs {
33798c2654abSrjs 	int ret_sz = 0;
33808c2654abSrjs 	int notdone;
33818c2654abSrjs 	uint8_t foundeom = 0;
33828c2654abSrjs 
33838c2654abSrjs 	do {
33848c2654abSrjs 		ret_sz += tp1->book_size;
33858c2654abSrjs 		tp1->sent = SCTP_FORWARD_TSN_SKIP;
33868c2654abSrjs 		if (tp1->data) {
33878c2654abSrjs 			sctp_free_bufspace(stcb, &stcb->asoc, tp1);
33888c2654abSrjs 			sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, reason, tp1);
33898c2654abSrjs 			sctp_m_freem(tp1->data);
33908c2654abSrjs 			tp1->data = NULL;
33918c2654abSrjs 			sctp_sowwakeup(stcb->sctp_ep, stcb->sctp_socket);
33928c2654abSrjs 		}
33938c2654abSrjs 		if (tp1->flags & SCTP_PR_SCTP_BUFFER) {
33948c2654abSrjs 			stcb->asoc.sent_queue_cnt_removeable--;
33958c2654abSrjs 		}
33968c2654abSrjs 		if (queue == &stcb->asoc.send_queue) {
33978c2654abSrjs 			TAILQ_REMOVE(&stcb->asoc.send_queue, tp1, sctp_next);
33988c2654abSrjs 			/* on to the sent queue */
33998c2654abSrjs 			TAILQ_INSERT_TAIL(&stcb->asoc.sent_queue, tp1,
34008c2654abSrjs 			    sctp_next);
34018c2654abSrjs 			stcb->asoc.sent_queue_cnt++;
34028c2654abSrjs 		}
34038c2654abSrjs 		if ((tp1->rec.data.rcv_flags & SCTP_DATA_NOT_FRAG) ==
34048c2654abSrjs 		    SCTP_DATA_NOT_FRAG) {
34058c2654abSrjs 			/* not frag'ed we ae done   */
34068c2654abSrjs 			notdone = 0;
34078c2654abSrjs 			foundeom = 1;
34088c2654abSrjs 		} else if (tp1->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) {
34098c2654abSrjs 			/* end of frag, we are done */
34108c2654abSrjs 			notdone = 0;
34118c2654abSrjs 			foundeom = 1;
34128c2654abSrjs 		} else {
34138c2654abSrjs 			/* Its a begin or middle piece, we must mark all of it */
34148c2654abSrjs 			notdone = 1;
34158c2654abSrjs 			tp1 = TAILQ_NEXT(tp1, sctp_next);
34168c2654abSrjs 		}
34178c2654abSrjs 	} while (tp1 && notdone);
34188c2654abSrjs 	if ((foundeom == 0) && (queue == &stcb->asoc.sent_queue)) {
34198c2654abSrjs 		/*
34208c2654abSrjs 		 * The multi-part message was scattered
34218c2654abSrjs 		 * across the send and sent queue.
34228c2654abSrjs 		 */
34238c2654abSrjs 		tp1 = TAILQ_FIRST(&stcb->asoc.send_queue);
34248c2654abSrjs 		/*
34258c2654abSrjs 		 * recurse throught the send_queue too, starting at the
34268c2654abSrjs 		 * beginning.
34278c2654abSrjs 		 */
34288c2654abSrjs 		if (tp1) {
34298c2654abSrjs 			ret_sz += sctp_release_pr_sctp_chunk(stcb, tp1, reason,
34308c2654abSrjs 			    &stcb->asoc.send_queue);
34318c2654abSrjs 		} else {
34328c2654abSrjs 			printf("hmm, nothing on the send queue and no EOM?\n");
34338c2654abSrjs 		}
34348c2654abSrjs 	}
34358c2654abSrjs 	return (ret_sz);
34368c2654abSrjs }
34378c2654abSrjs 
34388c2654abSrjs /*
34398c2654abSrjs  * checks to see if the given address, sa, is one that is currently
34408c2654abSrjs  * known by the kernel
34418c2654abSrjs  * note: can't distinguish the same address on multiple interfaces and
34428c2654abSrjs  *       doesn't handle multiple addresses with different zone/scope id's
34438c2654abSrjs  * note: ifa_ifwithaddr() compares the entire sockaddr struct
34448c2654abSrjs  */
34458c2654abSrjs struct ifaddr *
sctp_find_ifa_by_addr(struct sockaddr * sa)34468c2654abSrjs sctp_find_ifa_by_addr(struct sockaddr *sa)
34478c2654abSrjs {
34488c2654abSrjs 	struct ifnet *ifn;
34498c2654abSrjs 	struct ifaddr *ifa;
3450040205aeSozaki-r 	int s;
34518c2654abSrjs 
34528c2654abSrjs 	/* go through all our known interfaces */
3453040205aeSozaki-r 	s = pserialize_read_enter();
3454040205aeSozaki-r 	IFNET_READER_FOREACH(ifn) {
34558c2654abSrjs 		/* go through each interface addresses */
34569e4c2bdaSozaki-r 		IFADDR_READER_FOREACH(ifa, ifn) {
34578c2654abSrjs 			/* correct family? */
34588c2654abSrjs 			if (ifa->ifa_addr->sa_family != sa->sa_family)
34598c2654abSrjs 				continue;
34608c2654abSrjs 
34618c2654abSrjs #ifdef INET6
34628c2654abSrjs 			if (ifa->ifa_addr->sa_family == AF_INET6) {
34638c2654abSrjs 				/* IPv6 address */
34648c2654abSrjs 				struct sockaddr_in6 *sin1, *sin2, sin6_tmp;
34658c2654abSrjs 				sin1 = (struct sockaddr_in6 *)ifa->ifa_addr;
34668c2654abSrjs 				if (IN6_IS_SCOPE_LINKLOCAL(&sin1->sin6_addr)) {
34678c2654abSrjs 					/* create a copy and clear scope */
34688c2654abSrjs 					memcpy(&sin6_tmp, sin1,
34698c2654abSrjs 					    sizeof(struct sockaddr_in6));
34708c2654abSrjs 					sin1 = &sin6_tmp;
34718c2654abSrjs 					in6_clearscope(&sin1->sin6_addr);
34728c2654abSrjs 				}
34738c2654abSrjs 				sin2 = (struct sockaddr_in6 *)sa;
34748c2654abSrjs 				if (memcmp(&sin1->sin6_addr, &sin2->sin6_addr,
34758c2654abSrjs 					   sizeof(struct in6_addr)) == 0) {
34768c2654abSrjs 					/* found it */
3477040205aeSozaki-r 					pserialize_read_exit(s);
34788c2654abSrjs 					return (ifa);
34798c2654abSrjs 				}
34808c2654abSrjs 			} else
34818c2654abSrjs #endif
34828c2654abSrjs 			if (ifa->ifa_addr->sa_family == AF_INET) {
34838c2654abSrjs 				/* IPv4 address */
34848c2654abSrjs 				struct sockaddr_in *sin1, *sin2;
34858c2654abSrjs 				sin1 = (struct sockaddr_in *)ifa->ifa_addr;
34868c2654abSrjs 				sin2 = (struct sockaddr_in *)sa;
34878c2654abSrjs 				if (sin1->sin_addr.s_addr ==
34888c2654abSrjs 				    sin2->sin_addr.s_addr) {
34898c2654abSrjs 					/* found it */
3490040205aeSozaki-r 					pserialize_read_exit(s);
34918c2654abSrjs 					return (ifa);
34928c2654abSrjs 				}
34938c2654abSrjs 			}
34948c2654abSrjs 			/* else, not AF_INET or AF_INET6, so skip */
34958c2654abSrjs 		} /* end foreach ifa */
34968c2654abSrjs 	} /* end foreach ifn */
3497040205aeSozaki-r 	pserialize_read_exit(s);
3498040205aeSozaki-r 
34998c2654abSrjs 	/* not found! */
35008c2654abSrjs 	return (NULL);
35018c2654abSrjs }
35028c2654abSrjs 
35038c2654abSrjs 
35048c2654abSrjs #ifdef __APPLE__
35058c2654abSrjs /*
35068c2654abSrjs  * here we hack in a fix for Apple's m_copym for the case where the first mbuf
35078c2654abSrjs  * in the chain is a M_PKTHDR and the length is zero
35088c2654abSrjs  */
35098c2654abSrjs static void
sctp_pkthdr_fix(struct mbuf * m)35108c2654abSrjs sctp_pkthdr_fix(struct mbuf *m)
35118c2654abSrjs {
35128c2654abSrjs 	struct mbuf *m_nxt;
35138c2654abSrjs 
35148c2654abSrjs 	if ((m->m_flags & M_PKTHDR) == 0) {
35158c2654abSrjs 		/* not a PKTHDR */
35168c2654abSrjs 		return;
35178c2654abSrjs 	}
35188c2654abSrjs 
35198c2654abSrjs 	if (m->m_len != 0) {
35208c2654abSrjs 		/* not a zero length PKTHDR mbuf */
35218c2654abSrjs 		return;
35228c2654abSrjs 	}
35238c2654abSrjs 
35248c2654abSrjs 	/* let's move in a word into the first mbuf... yes, ugly! */
35258c2654abSrjs 	m_nxt = m->m_next;
35268c2654abSrjs 	if (m_nxt == NULL) {
35278c2654abSrjs 		/* umm... not a very useful mbuf chain... */
35288c2654abSrjs 		return;
35298c2654abSrjs 	}
35308c2654abSrjs 	if ((size_t)m_nxt->m_len > sizeof(long)) {
35318c2654abSrjs 		/* move over a long */
35328c2654abSrjs 		bcopy(mtod(m_nxt, void *), mtod(m, void *), sizeof(long));
35338c2654abSrjs 		/* update mbuf data pointers and lengths */
35348c2654abSrjs 		m->m_len += sizeof(long);
35358c2654abSrjs 		m_nxt->m_data += sizeof(long);
35368c2654abSrjs 		m_nxt->m_len -= sizeof(long);
35378c2654abSrjs 	}
35388c2654abSrjs }
35398c2654abSrjs 
35408c2654abSrjs inline struct mbuf *
sctp_m_copym(struct mbuf * m,int off,int len,int wait)35418c2654abSrjs sctp_m_copym(struct mbuf *m, int off, int len, int wait)
35428c2654abSrjs {
35438c2654abSrjs 	sctp_pkthdr_fix(m);
35448c2654abSrjs 	return (m_copym(m, off, len, wait));
35458c2654abSrjs }
35468c2654abSrjs #endif /* __APPLE__ */
3547