xref: /netbsd-src/sys/netinet/sctp_usrreq.c (revision 76748ca41481dcbc1f6e51bd5c3316613ca32cb8)
18c2654abSrjs /*	$KAME: sctp_usrreq.c,v 1.50 2005/06/16 20:45:29 jinmei Exp $	*/
2*76748ca4Srillig /*	$NetBSD: sctp_usrreq.c,v 1.27 2024/09/08 17:28:37 rillig 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 #include <sys/cdefs.h>
36*76748ca4Srillig __KERNEL_RCSID(0, "$NetBSD: sctp_usrreq.c,v 1.27 2024/09/08 17:28:37 rillig Exp $");
378c2654abSrjs 
388c2654abSrjs #ifdef _KERNEL_OPT
398c2654abSrjs #include "opt_inet.h"
408c2654abSrjs #include "opt_sctp.h"
418c2654abSrjs #endif /* _KERNEL_OPT */
428c2654abSrjs 
438c2654abSrjs #include <sys/param.h>
448c2654abSrjs #include <sys/systm.h>
458c2654abSrjs #include <sys/kernel.h>
468c2654abSrjs #include <sys/malloc.h>
478c2654abSrjs #include <sys/mbuf.h>
488c2654abSrjs #include <sys/domain.h>
498c2654abSrjs #include <sys/proc.h>
508c2654abSrjs #include <sys/protosw.h>
518c2654abSrjs #include <sys/socket.h>
528c2654abSrjs #include <sys/socketvar.h>
538c2654abSrjs #include <sys/sysctl.h>
548c2654abSrjs #include <sys/syslog.h>
558c2654abSrjs #include <net/if.h>
568c2654abSrjs #include <net/if_types.h>
578c2654abSrjs #include <net/route.h>
588c2654abSrjs #include <netinet/in.h>
598c2654abSrjs #include <netinet/in_systm.h>
608c2654abSrjs #include <netinet/ip.h>
618c2654abSrjs #include <netinet/ip6.h>
628c2654abSrjs #include <netinet/in_pcb.h>
638c2654abSrjs #include <netinet/in_var.h>
648c2654abSrjs #include <netinet/ip_var.h>
658c2654abSrjs #include <netinet6/ip6_var.h>
668c2654abSrjs #include <netinet6/in6_var.h>
678c2654abSrjs #include <netinet6/scope6_var.h>
688c2654abSrjs 
698c2654abSrjs #include <netinet/ip_icmp.h>
708c2654abSrjs #include <netinet/icmp_var.h>
718c2654abSrjs #include <netinet/sctp_pcb.h>
728c2654abSrjs #include <netinet/sctp_header.h>
738c2654abSrjs #include <netinet/sctp_var.h>
748c2654abSrjs #include <netinet/sctp_output.h>
758c2654abSrjs #include <netinet/sctp_uio.h>
768c2654abSrjs #include <netinet/sctp_asconf.h>
778e337251Srjs #include <netinet/sctp_route.h>
788c2654abSrjs #include <netinet/sctputil.h>
798c2654abSrjs #include <netinet/sctp_indata.h>
808c2654abSrjs #include <netinet/sctp_asconf.h>
818c2654abSrjs #ifdef IPSEC
82505ea976Srjs #include <netipsec/ipsec.h>
83505ea976Srjs #include <netipsec/key.h>
848c2654abSrjs #endif /* IPSEC */
858c2654abSrjs 
868c2654abSrjs #if defined(HAVE_NRL_INPCB) || defined(__FreeBSD__)
878c2654abSrjs #ifndef in6pcb
888c2654abSrjs #define in6pcb		inpcb
898c2654abSrjs #endif
908c2654abSrjs #ifndef sotoin6pcb
918c2654abSrjs #define sotoin6pcb      sotoinpcb
928c2654abSrjs #endif
938c2654abSrjs #endif
948c2654abSrjs 
958c2654abSrjs #ifdef SCTP_DEBUG
968c2654abSrjs extern u_int32_t sctp_debug_on;
978c2654abSrjs #endif /* SCTP_DEBUG */
988c2654abSrjs 
998c2654abSrjs /*
1008c2654abSrjs  * sysctl tunable variables
1018c2654abSrjs  */
1028c2654abSrjs int sctp_auto_asconf = SCTP_DEFAULT_AUTO_ASCONF;
1038c2654abSrjs int sctp_max_burst_default = SCTP_DEF_MAX_BURST;
1048c2654abSrjs int sctp_peer_chunk_oh = sizeof(struct mbuf);
1058c2654abSrjs int sctp_strict_init = 1;
1068c2654abSrjs int sctp_no_csum_on_loopback = 1;
1078c2654abSrjs unsigned int sctp_max_chunks_on_queue = SCTP_ASOC_MAX_CHUNKS_ON_QUEUE;
1088c2654abSrjs int sctp_sendspace = (128 * 1024);
1098c2654abSrjs int sctp_recvspace = 128 * (1024 +
1108c2654abSrjs #ifdef INET6
1118c2654abSrjs 				sizeof(struct sockaddr_in6)
1128c2654abSrjs #else
1138c2654abSrjs 				sizeof(struct sockaddr_in)
1148c2654abSrjs #endif
1158c2654abSrjs 	);
1168c2654abSrjs int sctp_strict_sacks = 0;
1178c2654abSrjs int sctp_ecn = 1;
1188c2654abSrjs int sctp_ecn_nonce = 0;
1198c2654abSrjs 
1208c2654abSrjs unsigned int sctp_delayed_sack_time_default = SCTP_RECV_MSEC;
1218c2654abSrjs unsigned int sctp_heartbeat_interval_default = SCTP_HB_DEFAULT_MSEC;
1228c2654abSrjs unsigned int sctp_pmtu_raise_time_default = SCTP_DEF_PMTU_RAISE_SEC;
1238c2654abSrjs unsigned int sctp_shutdown_guard_time_default = SCTP_DEF_MAX_SHUTDOWN_SEC;
1248c2654abSrjs unsigned int sctp_secret_lifetime_default = SCTP_DEFAULT_SECRET_LIFE_SEC;
1258c2654abSrjs unsigned int sctp_rto_max_default = SCTP_RTO_UPPER_BOUND;
1268c2654abSrjs unsigned int sctp_rto_min_default = SCTP_RTO_LOWER_BOUND;
1278c2654abSrjs unsigned int sctp_rto_initial_default = SCTP_RTO_INITIAL;
1288c2654abSrjs unsigned int sctp_init_rto_max_default = SCTP_RTO_UPPER_BOUND;
1298c2654abSrjs unsigned int sctp_valid_cookie_life_default = SCTP_DEFAULT_COOKIE_LIFE;
1308c2654abSrjs unsigned int sctp_init_rtx_max_default = SCTP_DEF_MAX_INIT;
1318c2654abSrjs unsigned int sctp_assoc_rtx_max_default = SCTP_DEF_MAX_SEND;
1328c2654abSrjs unsigned int sctp_path_rtx_max_default = SCTP_DEF_MAX_SEND/2;
1338c2654abSrjs unsigned int sctp_nr_outgoing_streams_default = SCTP_OSTREAM_INITIAL;
1348c2654abSrjs 
135ad7c6453Srjs static void sysctl_net_inet_sctp_setup(struct sysctllog **);
136ad7c6453Srjs 
1378c2654abSrjs void
1388c2654abSrjs sctp_init(void)
1398c2654abSrjs {
1408c2654abSrjs 	/* Init the SCTP pcb in sctp_pcb.c */
1418c2654abSrjs 	u_long sb_max_adj;
1428c2654abSrjs 
143ad7c6453Srjs 	sysctl_net_inet_sctp_setup(NULL);
144ad7c6453Srjs 
1458c2654abSrjs 	sctp_pcb_init();
1468c2654abSrjs 
1478c2654abSrjs 	if (nmbclusters > SCTP_ASOC_MAX_CHUNKS_ON_QUEUE)
1488c2654abSrjs 		sctp_max_chunks_on_queue = nmbclusters;
1498c2654abSrjs 	/*
1508c2654abSrjs 	 * Allow a user to take no more than 1/2 the number of clusters
1518c2654abSrjs 	 * or the SB_MAX whichever is smaller for the send window.
1528c2654abSrjs 	 */
1538c2654abSrjs 	sb_max_adj = (u_long)((u_quad_t)(SB_MAX) * MCLBYTES / (MSIZE + MCLBYTES));
154d1579b2dSriastradh 	sctp_sendspace = uimin((uimin(SB_MAX, sb_max_adj)),
1558c2654abSrjs 			     ((nmbclusters/2) * SCTP_DEFAULT_MAXSEGMENT));
1568c2654abSrjs 	/*
1578c2654abSrjs 	 * Now for the recv window, should we take the same amount?
1588c2654abSrjs 	 * or should I do 1/2 the SB_MAX instead in the SB_MAX min above.
1598c2654abSrjs 	 * For now I will just copy.
1608c2654abSrjs 	 */
1618c2654abSrjs 	sctp_recvspace = sctp_sendspace;
1628c2654abSrjs }
1638c2654abSrjs 
1648c2654abSrjs #ifdef INET6
1658c2654abSrjs void
1668c2654abSrjs ip_2_ip6_hdr(struct ip6_hdr *ip6, struct ip *ip)
1678c2654abSrjs {
1688c2654abSrjs 	memset(ip6, 0, sizeof(*ip6));
1698c2654abSrjs 
1708c2654abSrjs 	ip6->ip6_vfc = IPV6_VERSION;
1718c2654abSrjs 	ip6->ip6_plen = ip->ip_len;
1728c2654abSrjs 	ip6->ip6_nxt = ip->ip_p;
1738c2654abSrjs 	ip6->ip6_hlim = ip->ip_ttl;
1748c2654abSrjs 	ip6->ip6_src.s6_addr32[2] = ip6->ip6_dst.s6_addr32[2] =
1758c2654abSrjs 		IPV6_ADDR_INT32_SMP;
1768c2654abSrjs 	ip6->ip6_src.s6_addr32[3] = ip->ip_src.s_addr;
1778c2654abSrjs 	ip6->ip6_dst.s6_addr32[3] = ip->ip_dst.s_addr;
1788c2654abSrjs }
1798c2654abSrjs #endif /* INET6 */
1808c2654abSrjs 
1818c2654abSrjs static void
1828c2654abSrjs sctp_split_chunks(struct sctp_association *asoc,
1838c2654abSrjs 		  struct sctp_stream_out *strm,
1848c2654abSrjs 		  struct sctp_tmit_chunk *chk)
1858c2654abSrjs {
1868c2654abSrjs 	struct sctp_tmit_chunk *new_chk;
1878c2654abSrjs 
1888c2654abSrjs 	/* First we need a chunk */
1898c2654abSrjs 	new_chk = (struct sctp_tmit_chunk *)SCTP_ZONE_GET(sctppcbinfo.ipi_zone_chunk);
1908c2654abSrjs 	if (new_chk == NULL) {
1918c2654abSrjs 		chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
1928c2654abSrjs 		return;
1938c2654abSrjs 	}
1948c2654abSrjs 	sctppcbinfo.ipi_count_chunk++;
1958c2654abSrjs 	sctppcbinfo.ipi_gencnt_chunk++;
1968c2654abSrjs 	/* Copy it all */
1978c2654abSrjs 	*new_chk = *chk;
1988c2654abSrjs 	/*  split the data */
1998c2654abSrjs 	new_chk->data = m_split(chk->data, (chk->send_size>>1), M_DONTWAIT);
2008c2654abSrjs 	if (new_chk->data == NULL) {
2018c2654abSrjs 		/* Can't split */
2028c2654abSrjs 		chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
2038c2654abSrjs 		SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, new_chk);
2048c2654abSrjs 		sctppcbinfo.ipi_count_chunk--;
2058c2654abSrjs 		if ((int)sctppcbinfo.ipi_count_chunk < 0) {
2068c2654abSrjs 			panic("Chunk count is negative");
2078c2654abSrjs 		}
2088c2654abSrjs 		sctppcbinfo.ipi_gencnt_chunk++;
2098c2654abSrjs 		return;
2108c2654abSrjs 
2118c2654abSrjs 	}
2128c2654abSrjs 	/* Data is now split adjust sizes */
2138c2654abSrjs 	chk->send_size >>= 1;
2148c2654abSrjs 	new_chk->send_size >>= 1;
2158c2654abSrjs 
2168c2654abSrjs 	chk->book_size >>= 1;
2178c2654abSrjs 	new_chk->book_size >>= 1;
2188c2654abSrjs 
2198c2654abSrjs 	/* now adjust the marks */
2208c2654abSrjs 	chk->rec.data.rcv_flags |= SCTP_DATA_FIRST_FRAG;
2218c2654abSrjs 	chk->rec.data.rcv_flags &= ~SCTP_DATA_LAST_FRAG;
2228c2654abSrjs 
2238c2654abSrjs 	new_chk->rec.data.rcv_flags &= ~SCTP_DATA_FIRST_FRAG;
2248c2654abSrjs 	new_chk->rec.data.rcv_flags |= SCTP_DATA_LAST_FRAG;
2258c2654abSrjs 
2268c2654abSrjs 	/* Increase ref count if dest is set */
2278c2654abSrjs 	if (chk->whoTo) {
2288c2654abSrjs 		new_chk->whoTo->ref_count++;
2298c2654abSrjs 	}
2308c2654abSrjs 	/* now drop it on the end of the list*/
2318c2654abSrjs 	asoc->stream_queue_cnt++;
2328c2654abSrjs 	TAILQ_INSERT_AFTER(&strm->outqueue, chk, new_chk, sctp_next);
2338c2654abSrjs }
2348c2654abSrjs 
2358c2654abSrjs static void
2368c2654abSrjs sctp_notify_mbuf(struct sctp_inpcb *inp,
2378c2654abSrjs 		 struct sctp_tcb *stcb,
2388c2654abSrjs 		 struct sctp_nets *net,
2398c2654abSrjs 		 struct ip *ip,
2408c2654abSrjs 		 struct sctphdr *sh)
2418c2654abSrjs 
2428c2654abSrjs {
2438c2654abSrjs 	struct icmp *icmph;
2448c2654abSrjs 	int totsz;
2458c2654abSrjs 	uint16_t nxtsz;
2468c2654abSrjs 
2478c2654abSrjs 	/* protection */
2488c2654abSrjs 	if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
2498c2654abSrjs 	    (ip == NULL) || (sh == NULL)) {
2508c2654abSrjs 		if (stcb != NULL) {
2518c2654abSrjs 			SCTP_TCB_UNLOCK(stcb);
2528c2654abSrjs 		}
2538c2654abSrjs 		return;
2548c2654abSrjs 	}
2558c2654abSrjs 	/* First job is to verify the vtag matches what I would send */
2568c2654abSrjs 	if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) {
2578c2654abSrjs 		SCTP_TCB_UNLOCK(stcb);
2588c2654abSrjs 		return;
2598c2654abSrjs 	}
2608c2654abSrjs 	icmph = (struct icmp *)((vaddr_t)ip - (sizeof(struct icmp) -
2618c2654abSrjs 					       sizeof(struct ip)));
2628c2654abSrjs 	if (icmph->icmp_type != ICMP_UNREACH) {
2638c2654abSrjs 		/* We only care about unreachable */
2648c2654abSrjs 		SCTP_TCB_UNLOCK(stcb);
2658c2654abSrjs 		return;
2668c2654abSrjs 	}
2678c2654abSrjs 	if (icmph->icmp_code != ICMP_UNREACH_NEEDFRAG) {
2688c2654abSrjs 		/* not a unreachable message due to frag. */
2698c2654abSrjs 		SCTP_TCB_UNLOCK(stcb);
2708c2654abSrjs 		return;
2718c2654abSrjs 	}
2728c2654abSrjs 	totsz = ip->ip_len;
2738c2654abSrjs 	nxtsz = ntohs(icmph->icmp_seq);
2748c2654abSrjs 	if (nxtsz == 0) {
2758c2654abSrjs 		/*
2768c2654abSrjs 		 * old type router that does not tell us what the next size
2778c2654abSrjs 		 * mtu is. Rats we will have to guess (in a educated fashion
2788c2654abSrjs 		 * of course)
2798c2654abSrjs 		 */
2808c2654abSrjs 		nxtsz = find_next_best_mtu(totsz);
2818c2654abSrjs 	}
2828c2654abSrjs 
2838c2654abSrjs 	/* Stop any PMTU timer */
2848c2654abSrjs 	sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL);
2858c2654abSrjs 
2868c2654abSrjs 	/* Adjust destination size limit */
2878c2654abSrjs 	if (net->mtu > nxtsz) {
2888c2654abSrjs 		net->mtu = nxtsz;
2898c2654abSrjs 	}
2908c2654abSrjs 	/* now what about the ep? */
2918c2654abSrjs 	if (stcb->asoc.smallest_mtu > nxtsz) {
2928c2654abSrjs 		struct sctp_tmit_chunk *chk, *nchk;
2938c2654abSrjs 		struct sctp_stream_out *strm;
2948c2654abSrjs 		/* Adjust that too */
2958c2654abSrjs 		stcb->asoc.smallest_mtu = nxtsz;
2968c2654abSrjs 		/* now off to subtract IP_DF flag if needed */
2978c2654abSrjs 
2988c2654abSrjs 		TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) {
2998c2654abSrjs 			if ((chk->send_size+IP_HDR_SIZE) > nxtsz) {
3008c2654abSrjs 				chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
3018c2654abSrjs 			}
3028c2654abSrjs 		}
3038c2654abSrjs 		TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
3048c2654abSrjs 			if ((chk->send_size+IP_HDR_SIZE) > nxtsz) {
3058c2654abSrjs 				/*
3068c2654abSrjs 				 * For this guy we also mark for immediate
3078c2654abSrjs 				 * resend since we sent to big of chunk
3088c2654abSrjs 				 */
3098c2654abSrjs 				chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
3108c2654abSrjs 				if (chk->sent != SCTP_DATAGRAM_RESEND) {
3118c2654abSrjs 					stcb->asoc.sent_queue_retran_cnt++;
3128c2654abSrjs 				}
3138c2654abSrjs 				chk->sent = SCTP_DATAGRAM_RESEND;
3148c2654abSrjs 				chk->rec.data.doing_fast_retransmit = 0;
3158c2654abSrjs 
3168c2654abSrjs 				/* Clear any time so NO RTT is being done */
3178c2654abSrjs 				chk->do_rtt = 0;
3188c2654abSrjs 				sctp_total_flight_decrease(stcb, chk);
3198c2654abSrjs 				if (net->flight_size >= chk->book_size) {
3208c2654abSrjs 					net->flight_size -= chk->book_size;
3218c2654abSrjs 				} else {
3228c2654abSrjs 					net->flight_size = 0;
3238c2654abSrjs 				}
3248c2654abSrjs 			}
3258c2654abSrjs 		}
3268c2654abSrjs 		TAILQ_FOREACH(strm, &stcb->asoc.out_wheel, next_spoke) {
3278c2654abSrjs 			chk = TAILQ_FIRST(&strm->outqueue);
3288c2654abSrjs 			while (chk) {
3298c2654abSrjs 				nchk = TAILQ_NEXT(chk, sctp_next);
3308c2654abSrjs 				if ((chk->send_size+SCTP_MED_OVERHEAD) > nxtsz) {
3318c2654abSrjs 					sctp_split_chunks(&stcb->asoc, strm, chk);
3328c2654abSrjs 				}
3338c2654abSrjs 				chk = nchk;
3348c2654abSrjs 			}
3358c2654abSrjs 		}
3368c2654abSrjs 	}
3378c2654abSrjs 	sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL);
3388c2654abSrjs 	SCTP_TCB_UNLOCK(stcb);
3398c2654abSrjs }
3408c2654abSrjs 
3418c2654abSrjs 
3428c2654abSrjs void
3438c2654abSrjs sctp_notify(struct sctp_inpcb *inp,
3448c2654abSrjs 	    int errno,
3458c2654abSrjs 	    struct sctphdr *sh,
3468c2654abSrjs 	    struct sockaddr *to,
3478c2654abSrjs 	    struct sctp_tcb *stcb,
3488c2654abSrjs 	    struct sctp_nets *net)
3498c2654abSrjs {
3508c2654abSrjs 	/* protection */
3518c2654abSrjs 	if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
3528c2654abSrjs 	    (sh == NULL) || (to == NULL)) {
3538c2654abSrjs #ifdef SCTP_DEBUG
3548c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_USRREQ1) {
3558c2654abSrjs 			printf("sctp-notify, bad call\n");
3568c2654abSrjs 		}
3578c2654abSrjs #endif /* SCTP_DEBUG */
3588c2654abSrjs 		return;
3598c2654abSrjs 	}
3608c2654abSrjs 	/* First job is to verify the vtag matches what I would send */
3618c2654abSrjs 	if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) {
3628c2654abSrjs 		return;
3638c2654abSrjs 	}
3648c2654abSrjs 
3658c2654abSrjs /* FIX ME FIX ME PROTOPT i.e. no SCTP should ALWAYS be an ABORT */
3668c2654abSrjs 
3678c2654abSrjs 	if ((errno == EHOSTUNREACH) ||  /* Host is not reachable */
3688c2654abSrjs 	    (errno == EHOSTDOWN) ||	/* Host is down */
3698c2654abSrjs 	    (errno == ECONNREFUSED) ||	/* Host refused the connection, (not an abort?) */
3708c2654abSrjs 	    (errno == ENOPROTOOPT)	/* SCTP is not present on host */
3718c2654abSrjs 		) {
3728c2654abSrjs 		/*
3736478b405Sandvar 		 * Hmm reachability problems we must examine closely.
3748c2654abSrjs 		 * If its not reachable, we may have lost a network.
3758c2654abSrjs 		 * Or if there is NO protocol at the other end named SCTP.
3768c2654abSrjs 		 * well we consider it a OOTB abort.
3778c2654abSrjs 		 */
3788c2654abSrjs 		if ((errno == EHOSTUNREACH) || (errno == EHOSTDOWN)) {
3798c2654abSrjs 			if (net->dest_state & SCTP_ADDR_REACHABLE) {
3808c2654abSrjs 				/* Ok that destination is NOT reachable */
3818c2654abSrjs 				net->dest_state &= ~SCTP_ADDR_REACHABLE;
3828c2654abSrjs 				net->dest_state |= SCTP_ADDR_NOT_REACHABLE;
3838c2654abSrjs 				net->error_count = net->failure_threshold + 1;
3848c2654abSrjs 				sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
3858c2654abSrjs 						stcb, SCTP_FAILED_THRESHOLD,
3868c2654abSrjs 						(void *)net);
3878c2654abSrjs 			}
3888c2654abSrjs 			if (stcb) {
3898c2654abSrjs 				SCTP_TCB_UNLOCK(stcb);
3908c2654abSrjs 			}
3918c2654abSrjs 		} else {
3928c2654abSrjs 			/*
3938c2654abSrjs 			 * Here the peer is either playing tricks on us,
3948c2654abSrjs 			 * including an address that belongs to someone who
3958c2654abSrjs 			 * does not support SCTP OR was a userland
3968c2654abSrjs 			 * implementation that shutdown and now is dead. In
3978c2654abSrjs 			 * either case treat it like a OOTB abort with no TCB
3988c2654abSrjs 			 */
3998c2654abSrjs 			sctp_abort_notification(stcb, SCTP_PEER_FAULTY);
4008c2654abSrjs 			sctp_free_assoc(inp, stcb);
4018c2654abSrjs 			/* no need to unlock here, since the TCB is gone */
4028c2654abSrjs 		}
4038c2654abSrjs 	} else {
4048c2654abSrjs 		/* Send all others to the app */
4058c2654abSrjs 		if (inp->sctp_socket) {
4068c2654abSrjs 			inp->sctp_socket->so_error = errno;
4078c2654abSrjs 			sctp_sowwakeup(inp, inp->sctp_socket);
4088c2654abSrjs 		}
4098c2654abSrjs 	        if (stcb) {
4108c2654abSrjs 			SCTP_TCB_UNLOCK(stcb);
4118c2654abSrjs 		}
4128c2654abSrjs 	}
4138c2654abSrjs }
4148c2654abSrjs 
4158c2654abSrjs void *
4168c2654abSrjs sctp_ctlinput(int cmd, const struct sockaddr *sa, void *vip)
4178c2654abSrjs {
4188c2654abSrjs 	struct ip *ip = vip;
4198c2654abSrjs 	struct sctphdr *sh;
4208c2654abSrjs 	int s;
4218c2654abSrjs 
4228c2654abSrjs 	if (sa->sa_family != AF_INET ||
4238c2654abSrjs 	    ((const struct sockaddr_in *)sa)->sin_addr.s_addr == INADDR_ANY) {
4248c2654abSrjs 		return (NULL);
4258c2654abSrjs 	}
4268c2654abSrjs 
4278c2654abSrjs 	if (PRC_IS_REDIRECT(cmd)) {
4288c2654abSrjs 		ip = 0;
4298c2654abSrjs 	} else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) {
4308c2654abSrjs 		return (NULL);
4318c2654abSrjs 	}
4328c2654abSrjs 	if (ip) {
4338c2654abSrjs 		struct sctp_inpcb *inp;
4348c2654abSrjs 		struct sctp_tcb *stcb;
4358c2654abSrjs 		struct sctp_nets *net;
4368c2654abSrjs 		struct sockaddr_in to, from;
4378c2654abSrjs 
4388c2654abSrjs 		sh = (struct sctphdr *)((vaddr_t)ip + (ip->ip_hl << 2));
4398c2654abSrjs 		memset(&to, 0, sizeof(to));
4408c2654abSrjs 		memset(&from, 0, sizeof(from));
4418c2654abSrjs 		from.sin_family = to.sin_family = AF_INET;
4428c2654abSrjs 		from.sin_len = to.sin_len = sizeof(to);
4438c2654abSrjs 		from.sin_port = sh->src_port;
4448c2654abSrjs 		from.sin_addr = ip->ip_src;
4458c2654abSrjs 		to.sin_port = sh->dest_port;
4468c2654abSrjs 		to.sin_addr = ip->ip_dst;
4478c2654abSrjs 
4488c2654abSrjs 		/*
4498c2654abSrjs 		 * 'to' holds the dest of the packet that failed to be sent.
4508c2654abSrjs 		 * 'from' holds our local endpoint address.
4518c2654abSrjs 		 * Thus we reverse the to and the from in the lookup.
4528c2654abSrjs 		 */
4538c2654abSrjs 		s = splsoftnet();
4548c2654abSrjs 		stcb = sctp_findassociation_addr_sa((struct sockaddr *)&from,
4558c2654abSrjs 						    (struct sockaddr *)&to,
4568c2654abSrjs 						    &inp, &net, 1);
4578c2654abSrjs 		if (stcb != NULL && inp && (inp->sctp_socket != NULL)) {
4588c2654abSrjs 			if (cmd != PRC_MSGSIZE) {
4598c2654abSrjs 				int cm;
4608c2654abSrjs 				if (cmd == PRC_HOSTDEAD) {
4618c2654abSrjs 					cm = EHOSTUNREACH;
4628c2654abSrjs 				} else {
4638c2654abSrjs 					cm = inetctlerrmap[cmd];
4648c2654abSrjs 				}
4658c2654abSrjs 				sctp_notify(inp, cm, sh,
4668c2654abSrjs 					    (struct sockaddr *)&to, stcb,
4678c2654abSrjs 					    net);
4688c2654abSrjs 			} else {
4698c2654abSrjs 				/* handle possible ICMP size messages */
4708c2654abSrjs 				sctp_notify_mbuf(inp, stcb, net, ip, sh);
4718c2654abSrjs 			}
4728c2654abSrjs 		} else {
4738c2654abSrjs #if defined(__FreeBSD__) && __FreeBSD_version < 500000
4748c2654abSrjs                         /* XXX must be fixed for 5.x and higher, leave for 4.x */
4758c2654abSrjs 			if (PRC_IS_REDIRECT(cmd) && inp) {
4762ba9f052Sozaki-r 				inpcb_rtchange((struct inpcb *)inp,
4778c2654abSrjs 					    inetctlerrmap[cmd]);
4788c2654abSrjs 			}
4798c2654abSrjs #endif
4808c2654abSrjs 			if ((stcb == NULL) && (inp != NULL)) {
4818c2654abSrjs 				/* reduce ref-count */
4828c2654abSrjs 				SCTP_INP_WLOCK(inp);
4838c2654abSrjs 				SCTP_INP_DECR_REF(inp);
4848c2654abSrjs 				SCTP_INP_WUNLOCK(inp);
4858c2654abSrjs 			}
4868c2654abSrjs 
4878c2654abSrjs 		}
4888c2654abSrjs 		splx(s);
4898c2654abSrjs 	}
4908c2654abSrjs 	return (NULL);
4918c2654abSrjs }
4928c2654abSrjs 
4938c2654abSrjs static int
4948c2654abSrjs sctp_abort(struct socket *so)
4958c2654abSrjs {
4968c2654abSrjs 	struct sctp_inpcb *inp;
4978c2654abSrjs 
4988c2654abSrjs 	inp = (struct sctp_inpcb *)so->so_pcb;
4998c2654abSrjs 	if (inp == 0)
5008c2654abSrjs 		return EINVAL;	/* ??? possible? panic instead? */
5018c2654abSrjs 
5028c2654abSrjs 	sctp_inpcb_free(inp, 1);
5038c2654abSrjs 	return 0;
5048c2654abSrjs }
5058c2654abSrjs 
5068c2654abSrjs static int
5078c2654abSrjs sctp_attach(struct socket *so, int proto)
5088c2654abSrjs {
5098c2654abSrjs 	struct sctp_inpcb *inp;
5108c2654abSrjs #ifdef IPSEC
5118c2654abSrjs 	struct inpcb *ip_inp;
5128c2654abSrjs #endif
5138c2654abSrjs 	int error;
5148c2654abSrjs 
5158c2654abSrjs 	sosetlock(so);
5168c2654abSrjs 	inp = (struct sctp_inpcb *)so->so_pcb;
5178c2654abSrjs 	if (inp != 0) {
5188c2654abSrjs 		return EINVAL;
5198c2654abSrjs 	}
5208c2654abSrjs 	error = soreserve(so, sctp_sendspace, sctp_recvspace);
5218c2654abSrjs 	if (error) {
5228c2654abSrjs 		return error;
5238c2654abSrjs 	}
5248c2654abSrjs 	error = sctp_inpcb_alloc(so);
5258c2654abSrjs 	if (error) {
5268c2654abSrjs 		return error;
5278c2654abSrjs 	}
5288c2654abSrjs 	inp = (struct sctp_inpcb *)so->so_pcb;
5298c2654abSrjs 	SCTP_INP_WLOCK(inp);
5308c2654abSrjs 
5318c2654abSrjs 	inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUND_V6;	/* I'm not v6! */
5328c2654abSrjs #ifdef IPSEC
5338c2654abSrjs 	ip_inp = &inp->ip_inp.inp;
53401b82b52Srjs 	ip_inp->inp_af = proto;
5358c2654abSrjs #endif
5368c2654abSrjs 	inp->inp_vflag |= INP_IPV4;
5378c2654abSrjs 	inp->inp_ip_ttl = ip_defttl;
5388c2654abSrjs 
5398c2654abSrjs #ifdef IPSEC
5408c2654abSrjs 	error = ipsec_init_pcbpolicy(so, &ip_inp->inp_sp);
5418c2654abSrjs 	if (error != 0) {
5428c2654abSrjs 		sctp_inpcb_free(inp, 1);
5438c2654abSrjs 		return error;
5448c2654abSrjs 	}
5458c2654abSrjs #endif /*IPSEC*/
5468c2654abSrjs 	SCTP_INP_WUNLOCK(inp);
5478c2654abSrjs 	so->so_send = sctp_sosend;
5488c2654abSrjs 	return 0;
5498c2654abSrjs }
5508c2654abSrjs 
5518c2654abSrjs static int
5528c2654abSrjs sctp_bind(struct socket *so, struct sockaddr *nam, struct lwp *l)
5538c2654abSrjs {
5548c2654abSrjs 	struct sctp_inpcb *inp;
5558c2654abSrjs 	int error;
5568c2654abSrjs 
5578c2654abSrjs 	KASSERT(solocked(so));
5588c2654abSrjs 
5598c2654abSrjs #ifdef INET6
5608c2654abSrjs 	if (nam && nam->sa_family != AF_INET)
5618c2654abSrjs 		/* must be a v4 address! */
5628c2654abSrjs 		return EINVAL;
5638c2654abSrjs #endif /* INET6 */
5648c2654abSrjs 
5658c2654abSrjs 	inp = (struct sctp_inpcb *)so->so_pcb;
5668c2654abSrjs 	if (inp == 0)
5678c2654abSrjs 		return EINVAL;
5688c2654abSrjs 
5698c2654abSrjs 	error = sctp_inpcb_bind(so, nam, l);
5708c2654abSrjs 	return error;
5718c2654abSrjs }
5728c2654abSrjs 
5738c2654abSrjs 
5748c2654abSrjs static int
5758c2654abSrjs sctp_detach(struct socket *so)
5768c2654abSrjs {
5778c2654abSrjs 	struct sctp_inpcb *inp;
578ff49eadeSrjs 
5798c2654abSrjs 	inp = (struct sctp_inpcb *)so->so_pcb;
5808c2654abSrjs 	if (inp == 0)
5818c2654abSrjs 		return EINVAL;
5828c2654abSrjs 
5838c2654abSrjs 	if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) ||
5848c2654abSrjs 	    (so->so_rcv.sb_cc > 0)) {
5858c2654abSrjs 		sctp_inpcb_free(inp, 1);
5868c2654abSrjs 	} else {
5878c2654abSrjs 		sctp_inpcb_free(inp, 0);
5888c2654abSrjs 	}
5898c2654abSrjs 	return 0;
5908c2654abSrjs }
5918c2654abSrjs 
5928c2654abSrjs static int
5938c2654abSrjs sctp_recvoob(struct socket *so, struct mbuf *m, int flags)
5948c2654abSrjs {
5958c2654abSrjs 	KASSERT(solocked(so));
5968c2654abSrjs 
5978c2654abSrjs 	return EOPNOTSUPP;
5988c2654abSrjs }
5998c2654abSrjs 
6008c2654abSrjs int
6018c2654abSrjs sctp_send(struct socket *so, struct mbuf *m, struct sockaddr *addr,
6028c2654abSrjs 	  struct mbuf *control, struct lwp *l)
6038c2654abSrjs {
6048c2654abSrjs 	struct sctp_inpcb *inp;
6058c2654abSrjs 	int error;
6068c2654abSrjs 	inp = (struct sctp_inpcb *)so->so_pcb;
6078c2654abSrjs 	if (inp == 0) {
6088c2654abSrjs 		sctp_m_freem(control);
6098c2654abSrjs 		control = NULL;
6108c2654abSrjs 		sctp_m_freem(m);
6118c2654abSrjs 		return EINVAL;
6128c2654abSrjs 	}
6135b28f239Srillig 	/* Got to have a to address if we are NOT a connected socket */
6148c2654abSrjs 	if ((addr == NULL) &&
6158c2654abSrjs 	    ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) ||
6168c2654abSrjs 	     (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE))
6178c2654abSrjs 		) {
6188c2654abSrjs 		goto connected_type;
6198c2654abSrjs 	} else if (addr == NULL) {
6208c2654abSrjs 		error = EDESTADDRREQ;
6218c2654abSrjs 		sctp_m_freem(m);
6228c2654abSrjs 		sctp_m_freem(control);
6238c2654abSrjs 		control = NULL;
6248c2654abSrjs 		return (error);
6258c2654abSrjs 	}
6268c2654abSrjs #ifdef INET6
6278c2654abSrjs 	if (addr->sa_family != AF_INET) {
6288c2654abSrjs 		/* must be a v4 address! */
6298c2654abSrjs 		sctp_m_freem(m);
6308c2654abSrjs 		sctp_m_freem(control);
6318c2654abSrjs 		control = NULL;
6328c2654abSrjs 		error = EDESTADDRREQ;
6338c2654abSrjs 		return EINVAL;
6348c2654abSrjs 	}
6358c2654abSrjs #endif /* INET6 */
636d020c71cSmaxv 
637d020c71cSmaxv 	/*
638d020c71cSmaxv 	 * XXX XXX XXX Check addr->sa_len?
639d020c71cSmaxv 	 */
640d020c71cSmaxv 
6418c2654abSrjs  connected_type:
6428c2654abSrjs 	/* now what about control */
6438c2654abSrjs 	if (control) {
6448c2654abSrjs 		if (inp->control) {
6458c2654abSrjs 			printf("huh? control set?\n");
6468c2654abSrjs 			sctp_m_freem(inp->control);
6478c2654abSrjs 			inp->control = NULL;
6488c2654abSrjs 		}
6498c2654abSrjs 		inp->control = control;
6508c2654abSrjs 	}
6518c2654abSrjs 	/* add it in possibly */
6528c2654abSrjs 	if ((inp->pkt) && (inp->pkt->m_flags & M_PKTHDR)) {
6538c2654abSrjs 		struct mbuf *x;
6548c2654abSrjs 		int c_len;
6558c2654abSrjs 
6568c2654abSrjs 		c_len = 0;
6578c2654abSrjs 		/* How big is it */
6588c2654abSrjs 		for (x=m;x;x = x->m_next) {
6598c2654abSrjs 			c_len += x->m_len;
6608c2654abSrjs 		}
6618c2654abSrjs 		inp->pkt->m_pkthdr.len += c_len;
6628c2654abSrjs 	}
6638c2654abSrjs 	/* Place the data */
6648c2654abSrjs 	if (inp->pkt) {
6658c2654abSrjs 		inp->pkt_last->m_next = m;
6668c2654abSrjs 		inp->pkt_last = m;
6678c2654abSrjs 	} else {
6688c2654abSrjs 		inp->pkt_last = inp->pkt = m;
6698c2654abSrjs 	}
6708c2654abSrjs 	if ((so->so_state & SS_MORETOCOME) == 0) {
6718c2654abSrjs 		/*
6728c2654abSrjs 		 * note with the current version this code will only be used
6738c2654abSrjs 		 * by OpenBSD-- NetBSD, FreeBSD, and MacOS have methods for
6748c2654abSrjs 		 * re-defining sosend to use the sctp_sosend. One can
6758c2654abSrjs 		 * optionally switch back to this code (by changing back the
6768c2654abSrjs 		 * definitions) but this is not advisable.
6778c2654abSrjs 	     */
6788c2654abSrjs 		int ret;
6798c2654abSrjs 		ret = sctp_output(inp, inp->pkt, addr, inp->control, l, 0);
6808c2654abSrjs 		inp->pkt = NULL;
6818c2654abSrjs 		inp->control = NULL;
6828c2654abSrjs 		return (ret);
6838c2654abSrjs 	} else {
6848c2654abSrjs 		return (0);
6858c2654abSrjs 	}
6868c2654abSrjs }
6878c2654abSrjs 
6888c2654abSrjs static int
6898c2654abSrjs sctp_disconnect(struct socket *so)
6908c2654abSrjs {
6918c2654abSrjs 	struct sctp_inpcb *inp;
692ff49eadeSrjs 	int s;
6938c2654abSrjs 
6948c2654abSrjs 	inp = (struct sctp_inpcb *)so->so_pcb;
6958c2654abSrjs 	if (inp == NULL) {
6968c2654abSrjs 		return (ENOTCONN);
6978c2654abSrjs 	}
698ff49eadeSrjs 	s = splsoftnet();
6998c2654abSrjs 	SCTP_INP_RLOCK(inp);
7008c2654abSrjs 	if (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
7018c2654abSrjs 		if (LIST_EMPTY(&inp->sctp_asoc_list)) {
7028c2654abSrjs 			/* No connection */
7038c2654abSrjs 			SCTP_INP_RUNLOCK(inp);
704ff49eadeSrjs 			splx(s);
7058c2654abSrjs 			return (0);
7068c2654abSrjs 		} else {
7078c2654abSrjs 			int some_on_streamwheel = 0;
7088c2654abSrjs 			struct sctp_association *asoc;
7098c2654abSrjs 			struct sctp_tcb *stcb;
7108c2654abSrjs 
7118c2654abSrjs 			stcb = LIST_FIRST(&inp->sctp_asoc_list);
7128c2654abSrjs 			if (stcb == NULL) {
7138c2654abSrjs 				SCTP_INP_RUNLOCK(inp);
714ff49eadeSrjs 				splx(s);
7158c2654abSrjs 				return (EINVAL);
7168c2654abSrjs 			}
7178c2654abSrjs 			asoc = &stcb->asoc;
7188c2654abSrjs 			SCTP_TCB_LOCK(stcb);
7198c2654abSrjs 			if (((so->so_options & SO_LINGER) &&
7208c2654abSrjs 			     (so->so_linger == 0)) ||
7218c2654abSrjs 			    (so->so_rcv.sb_cc > 0)) {
7228c2654abSrjs 				if (SCTP_GET_STATE(asoc) !=
7238c2654abSrjs 				    SCTP_STATE_COOKIE_WAIT) {
7248c2654abSrjs 					/* Left with Data unread */
7258c2654abSrjs 					struct mbuf *err;
7268c2654abSrjs 					err = NULL;
7278c2654abSrjs 					MGET(err, M_DONTWAIT, MT_DATA);
7288c2654abSrjs 					if (err) {
7298c2654abSrjs 						/* Fill in the user initiated abort */
7308c2654abSrjs 						struct sctp_paramhdr *ph;
7318c2654abSrjs 						ph = mtod(err, struct sctp_paramhdr *);
7328c2654abSrjs 						err->m_len = sizeof(struct sctp_paramhdr);
7338c2654abSrjs 						ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT);
7348c2654abSrjs 						ph->param_length = htons(err->m_len);
7358c2654abSrjs 					}
7368c2654abSrjs 					sctp_send_abort_tcb(stcb, err);
7378c2654abSrjs 				}
7388c2654abSrjs 				SCTP_INP_RUNLOCK(inp);
7398c2654abSrjs 				sctp_free_assoc(inp, stcb);
7408c2654abSrjs 				/* No unlock tcb assoc is gone */
741ff49eadeSrjs 				splx(s);
7428c2654abSrjs 				return (0);
7438c2654abSrjs 			}
7448c2654abSrjs 			if (!TAILQ_EMPTY(&asoc->out_wheel)) {
7458c2654abSrjs 				/* Check to see if some data queued */
7468c2654abSrjs 				struct sctp_stream_out *outs;
7478c2654abSrjs 				TAILQ_FOREACH(outs, &asoc->out_wheel,
7488c2654abSrjs 					      next_spoke) {
7498c2654abSrjs 					if (!TAILQ_EMPTY(&outs->outqueue)) {
7508c2654abSrjs 						some_on_streamwheel = 1;
7518c2654abSrjs 						break;
7528c2654abSrjs 					}
7538c2654abSrjs 				}
7548c2654abSrjs 			}
7558c2654abSrjs 
7568c2654abSrjs 			if (TAILQ_EMPTY(&asoc->send_queue) &&
7578c2654abSrjs 			    TAILQ_EMPTY(&asoc->sent_queue) &&
7588c2654abSrjs 			    (some_on_streamwheel == 0)) {
7598c2654abSrjs 				/* there is nothing queued to send, so done */
7608c2654abSrjs 				if ((SCTP_GET_STATE(asoc) !=
7618c2654abSrjs 				     SCTP_STATE_SHUTDOWN_SENT) &&
7628c2654abSrjs 				    (SCTP_GET_STATE(asoc) !=
7638c2654abSrjs 				     SCTP_STATE_SHUTDOWN_ACK_SENT)) {
7648c2654abSrjs 					/* only send SHUTDOWN 1st time thru */
7658c2654abSrjs #ifdef SCTP_DEBUG
7668c2654abSrjs 					if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) {
7678c2654abSrjs 						printf("%s:%d sends a shutdown\n",
7688c2654abSrjs 						       __FILE__,
7698c2654abSrjs 						       __LINE__
7708c2654abSrjs 							);
7718c2654abSrjs 					}
7728c2654abSrjs #endif
7738c2654abSrjs 					sctp_send_shutdown(stcb,
7748c2654abSrjs 							   stcb->asoc.primary_destination);
7758c2654abSrjs 					sctp_chunk_output(stcb->sctp_ep, stcb, 1);
7768c2654abSrjs 					asoc->state = SCTP_STATE_SHUTDOWN_SENT;
7778c2654abSrjs 					sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
7788c2654abSrjs 							 stcb->sctp_ep, stcb,
7798c2654abSrjs 							 asoc->primary_destination);
7808c2654abSrjs 					sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
7818c2654abSrjs 							 stcb->sctp_ep, stcb,
7828c2654abSrjs 							 asoc->primary_destination);
7838c2654abSrjs 				}
7848c2654abSrjs 			} else {
7858c2654abSrjs 				/*
7868c2654abSrjs 				 * we still got (or just got) data to send,
7878c2654abSrjs 				 * so set SHUTDOWN_PENDING
7888c2654abSrjs 				 */
7898c2654abSrjs 				asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
7908c2654abSrjs 			}
7918c2654abSrjs 			SCTP_TCB_UNLOCK(stcb);
7928c2654abSrjs 			SCTP_INP_RUNLOCK(inp);
793ff49eadeSrjs 			splx(s);
7948c2654abSrjs 			return (0);
7958c2654abSrjs 		}
7968c2654abSrjs 		/* not reached */
7978c2654abSrjs 	} else {
7988c2654abSrjs 		/* UDP model does not support this */
7998c2654abSrjs 		SCTP_INP_RUNLOCK(inp);
800ff49eadeSrjs 		splx(s);
8018c2654abSrjs 		return EOPNOTSUPP;
8028c2654abSrjs 	}
8038c2654abSrjs }
8048c2654abSrjs 
8058c2654abSrjs int
8068c2654abSrjs sctp_shutdown(struct socket *so)
8078c2654abSrjs {
8088c2654abSrjs 	struct sctp_inpcb *inp;
8098c2654abSrjs 
8108c2654abSrjs 	inp = (struct sctp_inpcb *)so->so_pcb;
8118c2654abSrjs 	if (inp == 0) {
8128c2654abSrjs 		return EINVAL;
8138c2654abSrjs 	}
8148c2654abSrjs 	SCTP_INP_RLOCK(inp);
8158c2654abSrjs 	/* For UDP model this is a invalid call */
8168c2654abSrjs 	if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
8178c2654abSrjs 		/* Restore the flags that the soshutdown took away. */
8188c2654abSrjs 		so->so_state &= ~SS_CANTRCVMORE;
8198c2654abSrjs 		/* This proc will wakeup for read and do nothing (I hope) */
8208c2654abSrjs 		SCTP_INP_RUNLOCK(inp);
8218c2654abSrjs 		return (EOPNOTSUPP);
8228c2654abSrjs 	}
8238c2654abSrjs 	/*
8248c2654abSrjs 	 * Ok if we reach here its the TCP model and it is either a SHUT_WR
8258c2654abSrjs 	 * or SHUT_RDWR. This means we put the shutdown flag against it.
8268c2654abSrjs 	 */
8278c2654abSrjs 	{
8288c2654abSrjs 		int some_on_streamwheel = 0;
8298c2654abSrjs 		struct sctp_tcb *stcb;
8308c2654abSrjs 		struct sctp_association *asoc;
8318c2654abSrjs 		socantsendmore(so);
8328c2654abSrjs 
8338c2654abSrjs 		stcb = LIST_FIRST(&inp->sctp_asoc_list);
8348c2654abSrjs 		if (stcb == NULL) {
8358c2654abSrjs 			/*
8368c2654abSrjs 			 * Ok we hit the case that the shutdown call was made
8378c2654abSrjs 			 * after an abort or something. Nothing to do now.
8388c2654abSrjs 			 */
8398c2654abSrjs 			return (0);
8408c2654abSrjs 		}
8418c2654abSrjs 		SCTP_TCB_LOCK(stcb);
8428c2654abSrjs 		asoc = &stcb->asoc;
8438c2654abSrjs 
8448c2654abSrjs 		if (!TAILQ_EMPTY(&asoc->out_wheel)) {
8458c2654abSrjs 			/* Check to see if some data queued */
8468c2654abSrjs 			struct sctp_stream_out *outs;
8478c2654abSrjs 			TAILQ_FOREACH(outs, &asoc->out_wheel, next_spoke) {
8488c2654abSrjs 				if (!TAILQ_EMPTY(&outs->outqueue)) {
8498c2654abSrjs 					some_on_streamwheel = 1;
8508c2654abSrjs 					break;
8518c2654abSrjs 				}
8528c2654abSrjs 			}
8538c2654abSrjs 		}
8548c2654abSrjs 		if (TAILQ_EMPTY(&asoc->send_queue) &&
8558c2654abSrjs 		    TAILQ_EMPTY(&asoc->sent_queue) &&
8568c2654abSrjs 		    (some_on_streamwheel == 0)) {
8578c2654abSrjs 			/* there is nothing queued to send, so I'm done... */
8588c2654abSrjs 			if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) {
8598c2654abSrjs 				/* only send SHUTDOWN the first time through */
8608c2654abSrjs #ifdef SCTP_DEBUG
8618c2654abSrjs 				if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) {
8628c2654abSrjs 					printf("%s:%d sends a shutdown\n",
8638c2654abSrjs 					       __FILE__,
8648c2654abSrjs 					       __LINE__
8658c2654abSrjs 						);
8668c2654abSrjs 				}
8678c2654abSrjs #endif
8688c2654abSrjs 				sctp_send_shutdown(stcb,
8698c2654abSrjs 						   stcb->asoc.primary_destination);
8708c2654abSrjs 				sctp_chunk_output(stcb->sctp_ep, stcb, 1);
8718c2654abSrjs 				asoc->state = SCTP_STATE_SHUTDOWN_SENT;
8728c2654abSrjs 				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
8738c2654abSrjs 						 stcb->sctp_ep, stcb,
8748c2654abSrjs 						 asoc->primary_destination);
8758c2654abSrjs 				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
8768c2654abSrjs 						 stcb->sctp_ep, stcb,
8778c2654abSrjs 						 asoc->primary_destination);
8788c2654abSrjs 			}
8798c2654abSrjs 		} else {
8808c2654abSrjs 			/*
8818c2654abSrjs 			 * we still got (or just got) data to send, so
8828c2654abSrjs 			 * set SHUTDOWN_PENDING
8838c2654abSrjs 			 */
8848c2654abSrjs 			asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
8858c2654abSrjs 		}
8868c2654abSrjs 		SCTP_TCB_UNLOCK(stcb);
8878c2654abSrjs 	}
8888c2654abSrjs 	SCTP_INP_RUNLOCK(inp);
8898c2654abSrjs 	return 0;
8908c2654abSrjs }
8918c2654abSrjs 
8928c2654abSrjs /*
8938c2654abSrjs  * copies a "user" presentable address and removes embedded scope, etc.
8948c2654abSrjs  * returns 0 on success, 1 on error
8958c2654abSrjs  */
8968c2654abSrjs static uint32_t
8978c2654abSrjs sctp_fill_user_address(struct sockaddr_storage *ss, struct sockaddr *sa)
8988c2654abSrjs {
8998c2654abSrjs 	struct sockaddr_in6 lsa6;
9008c2654abSrjs 
9018c2654abSrjs 	sctp_recover_scope((struct sockaddr_in6 *)sa, &lsa6);
9028c2654abSrjs 	memcpy(ss, sa, sa->sa_len);
9038c2654abSrjs 	return (0);
9048c2654abSrjs }
9058c2654abSrjs 
9068c2654abSrjs 
9078c2654abSrjs static int
9088c2654abSrjs sctp_fill_up_addresses(struct sctp_inpcb *inp,
9098c2654abSrjs 		       struct sctp_tcb *stcb,
9108c2654abSrjs 		       int limit,
9118c2654abSrjs 		       struct sockaddr_storage *sas)
9128c2654abSrjs {
9138c2654abSrjs 	struct ifnet *ifn;
9148c2654abSrjs 	struct ifaddr *ifa;
9158c2654abSrjs 	int loopback_scope, ipv4_local_scope, local_scope, site_scope, actual;
9168c2654abSrjs 	int ipv4_addr_legal, ipv6_addr_legal;
9178c2654abSrjs 	actual = 0;
9188c2654abSrjs 	if (limit <= 0)
9198c2654abSrjs 		return (actual);
9208c2654abSrjs 
9218c2654abSrjs 	if (stcb) {
9228c2654abSrjs 		/* Turn on all the appropriate scope */
9238c2654abSrjs 		loopback_scope = stcb->asoc.loopback_scope;
9248c2654abSrjs 		ipv4_local_scope = stcb->asoc.ipv4_local_scope;
9258c2654abSrjs 		local_scope = stcb->asoc.local_scope;
9268c2654abSrjs 		site_scope = stcb->asoc.site_scope;
9278c2654abSrjs 	} else {
9288c2654abSrjs 		/* Turn on ALL scope, since we look at the EP */
9298c2654abSrjs 		loopback_scope = ipv4_local_scope = local_scope =
9308c2654abSrjs 			site_scope = 1;
9318c2654abSrjs 	}
9328c2654abSrjs 	ipv4_addr_legal = ipv6_addr_legal = 0;
9338c2654abSrjs 	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
9348c2654abSrjs 		ipv6_addr_legal = 1;
9358c2654abSrjs 		if (
9368c2654abSrjs #if defined(__OpenBSD__)
9378c2654abSrjs 		(0) /* we always do dual bind */
9388c2654abSrjs #elif defined (__NetBSD__)
9398c2654abSrjs 		(((struct in6pcb *)inp)->in6p_flags & IN6P_IPV6_V6ONLY)
9408c2654abSrjs #else
9418c2654abSrjs 		(((struct in6pcb *)inp)->inp_flags & IN6P_IPV6_V6ONLY)
9428c2654abSrjs #endif
9438c2654abSrjs 		== 0) {
9448c2654abSrjs 			ipv4_addr_legal = 1;
9458c2654abSrjs 		}
9468c2654abSrjs 	} else {
9478c2654abSrjs 		ipv4_addr_legal = 1;
9488c2654abSrjs 	}
9498c2654abSrjs 
9508c2654abSrjs 	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
951040205aeSozaki-r 		int s = pserialize_read_enter();
952040205aeSozaki-r 		IFNET_READER_FOREACH(ifn) {
9538c2654abSrjs 			if ((loopback_scope == 0) &&
9548c2654abSrjs 			    (ifn->if_type == IFT_LOOP)) {
9558c2654abSrjs 				/* Skip loopback if loopback_scope not set */
9568c2654abSrjs 				continue;
9578c2654abSrjs 			}
9589e4c2bdaSozaki-r 			IFADDR_READER_FOREACH(ifa, ifn) {
9598c2654abSrjs 				if (stcb) {
9608c2654abSrjs 				/*
9618c2654abSrjs 				 * For the BOUND-ALL case, the list
9628c2654abSrjs 				 * associated with a TCB is Always
9638c2654abSrjs 				 * considered a reverse list.. i.e.
9648c2654abSrjs 				 * it lists addresses that are NOT
9658c2654abSrjs 				 * part of the association. If this
9668c2654abSrjs 				 * is one of those we must skip it.
9678c2654abSrjs 				 */
9688c2654abSrjs 					if (sctp_is_addr_restricted(stcb,
9698c2654abSrjs 								    ifa->ifa_addr)) {
9708c2654abSrjs 						continue;
9718c2654abSrjs 					}
9728c2654abSrjs 				}
9738c2654abSrjs 				if ((ifa->ifa_addr->sa_family == AF_INET) &&
9748c2654abSrjs 				    (ipv4_addr_legal)) {
9758c2654abSrjs 					struct sockaddr_in *sin;
9768c2654abSrjs 					sin = (struct sockaddr_in *)ifa->ifa_addr;
9778c2654abSrjs 					if (sin->sin_addr.s_addr == 0) {
978100a3398Sandvar 						/* we skip unspecified addresses */
9798c2654abSrjs 						continue;
9808c2654abSrjs 					}
9818c2654abSrjs 					if ((ipv4_local_scope == 0) &&
9828c2654abSrjs 					    (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) {
9838c2654abSrjs 						continue;
9848c2654abSrjs 					}
9858c2654abSrjs 					if (inp->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) {
9868c2654abSrjs 						in6_sin_2_v4mapsin6(sin, (struct sockaddr_in6 *)sas);
9878c2654abSrjs 						((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
9888c2654abSrjs 						sas = (struct sockaddr_storage *)((vaddr_t)sas + sizeof(struct sockaddr_in6));
9897273e27bSchristos 						actual += sizeof(struct sockaddr_in6);
9908c2654abSrjs 					} else {
9918c2654abSrjs 						memcpy(sas, sin, sizeof(*sin));
9928c2654abSrjs 						((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport;
9938c2654abSrjs 						sas = (struct sockaddr_storage *)((vaddr_t)sas + sizeof(*sin));
9948c2654abSrjs 						actual += sizeof(*sin);
9958c2654abSrjs 					}
9968c2654abSrjs 					if (actual >= limit) {
997040205aeSozaki-r 						pserialize_read_exit(s);
9988c2654abSrjs 						return (actual);
9998c2654abSrjs 					}
10008c2654abSrjs 				} else if ((ifa->ifa_addr->sa_family == AF_INET6) &&
10018c2654abSrjs 					   (ipv6_addr_legal)) {
10028c2654abSrjs 					struct sockaddr_in6 *sin6;
10038c2654abSrjs 					sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
10048c2654abSrjs 					if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
10058c2654abSrjs 						/*
10068c2654abSrjs 						 * we skip unspecified
10078c2654abSrjs 						 * addresses
10088c2654abSrjs 						 */
10098c2654abSrjs 						continue;
10108c2654abSrjs 					}
10118c2654abSrjs 					if ((site_scope == 0) &&
10128c2654abSrjs 					    (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) {
10138c2654abSrjs 						continue;
10148c2654abSrjs 					}
10158c2654abSrjs 					memcpy(sas, sin6, sizeof(*sin6));
10168c2654abSrjs 					((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
10178c2654abSrjs 					sas = (struct sockaddr_storage *)((vaddr_t)sas + sizeof(*sin6));
10188c2654abSrjs 					actual += sizeof(*sin6);
10198c2654abSrjs 					if (actual >= limit) {
1020040205aeSozaki-r 						pserialize_read_exit(s);
10218c2654abSrjs 						return (actual);
10228c2654abSrjs 					}
10238c2654abSrjs 				}
10248c2654abSrjs 			}
10258c2654abSrjs 		}
1026040205aeSozaki-r 		pserialize_read_exit(s);
10278c2654abSrjs 	} else {
10288c2654abSrjs 		struct sctp_laddr *laddr;
10298c2654abSrjs 		/*
10308c2654abSrjs 		 * If we have a TCB and we do NOT support ASCONF (it's
10318c2654abSrjs 		 * turned off or otherwise) then the list is always the
10328c2654abSrjs 		 * true list of addresses (the else case below).  Otherwise
10338c2654abSrjs 		 * the list on the association is a list of addresses that
10348c2654abSrjs 		 * are NOT part of the association.
10358c2654abSrjs 		 */
10368c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_DO_ASCONF) {
10378c2654abSrjs 			/* The list is a NEGATIVE list */
10388c2654abSrjs 			LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
10398c2654abSrjs 				if (stcb) {
10408c2654abSrjs 					if (sctp_is_addr_restricted(stcb, laddr->ifa->ifa_addr)) {
10418c2654abSrjs 						continue;
10428c2654abSrjs 					}
10438c2654abSrjs 				}
10448c2654abSrjs 				if (sctp_fill_user_address(sas, laddr->ifa->ifa_addr))
10458c2654abSrjs 					continue;
10468c2654abSrjs 
10478c2654abSrjs 				((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
10488c2654abSrjs 				sas = (struct sockaddr_storage *)((vaddr_t)sas +
10498c2654abSrjs 								  laddr->ifa->ifa_addr->sa_len);
10508c2654abSrjs 				actual += laddr->ifa->ifa_addr->sa_len;
10518c2654abSrjs 				if (actual >= limit) {
10528c2654abSrjs 					return (actual);
10538c2654abSrjs 				}
10548c2654abSrjs 			}
10558c2654abSrjs 		} else {
10568c2654abSrjs 			/* The list is a positive list if present */
10578c2654abSrjs 			if (stcb) {
10588c2654abSrjs 				/* Must use the specific association list */
10598c2654abSrjs 				LIST_FOREACH(laddr, &stcb->asoc.sctp_local_addr_list,
10608c2654abSrjs 					     sctp_nxt_addr) {
10618c2654abSrjs 					if (sctp_fill_user_address(sas,
10628c2654abSrjs 								   laddr->ifa->ifa_addr))
10638c2654abSrjs 						continue;
10648c2654abSrjs 					((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
10658c2654abSrjs 					sas = (struct sockaddr_storage *)((vaddr_t)sas +
10668c2654abSrjs 									  laddr->ifa->ifa_addr->sa_len);
10678c2654abSrjs 					actual += laddr->ifa->ifa_addr->sa_len;
10688c2654abSrjs 					if (actual >= limit) {
10698c2654abSrjs 						return (actual);
10708c2654abSrjs 					}
10718c2654abSrjs 				}
10728c2654abSrjs 			} else {
10738c2654abSrjs 				/* No endpoint so use the endpoints individual list */
10748c2654abSrjs 				LIST_FOREACH(laddr, &inp->sctp_addr_list,
10758c2654abSrjs 					     sctp_nxt_addr) {
10768c2654abSrjs 					if (sctp_fill_user_address(sas,
10778c2654abSrjs 								   laddr->ifa->ifa_addr))
10788c2654abSrjs 						continue;
10798c2654abSrjs 					((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
10808c2654abSrjs 					sas = (struct sockaddr_storage *)((vaddr_t)sas +
10818c2654abSrjs 									  laddr->ifa->ifa_addr->sa_len);
10828c2654abSrjs 					actual += laddr->ifa->ifa_addr->sa_len;
10838c2654abSrjs 					if (actual >= limit) {
10848c2654abSrjs 						return (actual);
10858c2654abSrjs 					}
10868c2654abSrjs 				}
10878c2654abSrjs 			}
10888c2654abSrjs 		}
10898c2654abSrjs 	}
10908c2654abSrjs 	return (actual);
10918c2654abSrjs }
10928c2654abSrjs 
10938c2654abSrjs static int
10948c2654abSrjs sctp_count_max_addresses(struct sctp_inpcb *inp)
10958c2654abSrjs {
10968c2654abSrjs 	int cnt = 0;
10978c2654abSrjs 	/*
10985b28f239Srillig 	 * In both sub-set bound and bound_all cases we return the MAXIMUM
10998c2654abSrjs 	 * number of addresses that you COULD get. In reality the sub-set
11008c2654abSrjs 	 * bound may have an exclusion list for a given TCB OR in the
11018c2654abSrjs 	 * bound-all case a TCB may NOT include the loopback or other
11028c2654abSrjs 	 * addresses as well.
11038c2654abSrjs 	 */
11048c2654abSrjs 	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
11058c2654abSrjs 		struct ifnet *ifn;
11068c2654abSrjs 		struct ifaddr *ifa;
1107040205aeSozaki-r 		int s;
11088c2654abSrjs 
1109040205aeSozaki-r 		s = pserialize_read_enter();
1110040205aeSozaki-r 		IFNET_READER_FOREACH(ifn) {
11119e4c2bdaSozaki-r 			IFADDR_READER_FOREACH(ifa, ifn) {
11128c2654abSrjs 				/* Count them if they are the right type */
11138c2654abSrjs 				if (ifa->ifa_addr->sa_family == AF_INET) {
11148c2654abSrjs 					if (inp->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)
11158c2654abSrjs 						cnt += sizeof(struct sockaddr_in6);
11168c2654abSrjs 					else
11178c2654abSrjs 						cnt += sizeof(struct sockaddr_in);
11188c2654abSrjs 
11198c2654abSrjs 				} else if (ifa->ifa_addr->sa_family == AF_INET6)
11208c2654abSrjs 					cnt += sizeof(struct sockaddr_in6);
11218c2654abSrjs 			}
11228c2654abSrjs 		}
1123040205aeSozaki-r 		pserialize_read_exit(s);
11248c2654abSrjs 	} else {
11258c2654abSrjs 		struct sctp_laddr *laddr;
11268c2654abSrjs 		LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
11278c2654abSrjs 			if (laddr->ifa->ifa_addr->sa_family == AF_INET) {
11288c2654abSrjs 				if (inp->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)
11298c2654abSrjs 					cnt += sizeof(struct sockaddr_in6);
11308c2654abSrjs 				else
11318c2654abSrjs 					cnt += sizeof(struct sockaddr_in);
11328c2654abSrjs 
11338c2654abSrjs 			} else if (laddr->ifa->ifa_addr->sa_family == AF_INET6)
11348c2654abSrjs 				cnt += sizeof(struct sockaddr_in6);
11358c2654abSrjs 		}
11368c2654abSrjs 	}
11378c2654abSrjs 	return (cnt);
11388c2654abSrjs }
11398c2654abSrjs 
11407cd04cafSrjs int
11413917a6f0Srjs sctp_do_connect_x(struct socket *so, struct sctp_connectx_addrs *sca,
11428c2654abSrjs     struct lwp *l, int delay)
11438c2654abSrjs {
11448c2654abSrjs         int error = 0;
11453917a6f0Srjs 	struct sctp_inpcb *inp;
11468c2654abSrjs 	struct sctp_tcb *stcb = NULL;
11478c2654abSrjs 	struct sockaddr *sa;
11483917a6f0Srjs 	int num_v6=0, num_v4=0, totaddr, i, incr, at;
11493917a6f0Srjs 	char buf[2048];
11503917a6f0Srjs 	size_t len;
11513917a6f0Srjs 	sctp_assoc_t id;
11528c2654abSrjs #ifdef SCTP_DEBUG
11538c2654abSrjs 	if (sctp_debug_on & SCTP_DEBUG_PCB1) {
11548c2654abSrjs 		printf("Connectx called\n");
11558c2654abSrjs 	}
11568c2654abSrjs #endif /* SCTP_DEBUG */
11578c2654abSrjs 
11583917a6f0Srjs 	inp = (struct sctp_inpcb *)so->so_pcb;
11593917a6f0Srjs 	if (inp == 0)
11603917a6f0Srjs 		return EINVAL;
11613917a6f0Srjs 
11628c2654abSrjs 	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
11638c2654abSrjs 	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
11648c2654abSrjs 		/* We are already connected AND the TCP model */
11658c2654abSrjs 		return (EADDRINUSE);
11668c2654abSrjs 	}
11678c2654abSrjs 	if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
11688c2654abSrjs 		SCTP_INP_RLOCK(inp);
11698c2654abSrjs 		stcb = LIST_FIRST(&inp->sctp_asoc_list);
11708c2654abSrjs 		SCTP_INP_RUNLOCK(inp);
11718c2654abSrjs 	}
11728c2654abSrjs 	if (stcb) {
11738c2654abSrjs 		return (EALREADY);
11748c2654abSrjs 
11758c2654abSrjs 	}
11768c2654abSrjs 	SCTP_ASOC_CREATE_LOCK(inp);
11778c2654abSrjs 	if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
11788c2654abSrjs 	    (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
11798c2654abSrjs 		SCTP_ASOC_CREATE_UNLOCK(inp);
11808c2654abSrjs 		return (EFAULT);
11818c2654abSrjs 	}
11828c2654abSrjs 
11833917a6f0Srjs 	len = sca->cx_len;
11843917a6f0Srjs 	totaddr = sca->cx_num;
11853917a6f0Srjs 	if (len > sizeof(buf)) {
11863917a6f0Srjs 		return E2BIG;
11873917a6f0Srjs 	}
11883917a6f0Srjs 	error = copyin(sca->cx_addrs, buf, len);
11893917a6f0Srjs 	if (error) {
11903917a6f0Srjs 		return error;
11913917a6f0Srjs 	}
11923917a6f0Srjs 	sa = (struct sockaddr *)buf;
11938c2654abSrjs 	at = incr = 0;
11948c2654abSrjs 	/* account and validate addresses */
11958c2654abSrjs 	SCTP_INP_WLOCK(inp);
11968c2654abSrjs 	SCTP_INP_INCR_REF(inp);
11978c2654abSrjs 	SCTP_INP_WUNLOCK(inp);
11988c2654abSrjs 	for (i = 0; i < totaddr; i++) {
11998c2654abSrjs 		if (sa->sa_family == AF_INET) {
12008c2654abSrjs 			num_v4++;
12018c2654abSrjs 			incr = sizeof(struct sockaddr_in);
12028c2654abSrjs 		} else if (sa->sa_family == AF_INET6) {
12038c2654abSrjs 			struct sockaddr_in6 *sin6;
12048c2654abSrjs 			sin6 = (struct sockaddr_in6 *)sa;
12058c2654abSrjs 			if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
12068c2654abSrjs 				/* Must be non-mapped for connectx */
12078c2654abSrjs 				SCTP_ASOC_CREATE_UNLOCK(inp);
12088c2654abSrjs 				return EINVAL;
12098c2654abSrjs 			}
12108c2654abSrjs 			num_v6++;
12118c2654abSrjs 			incr = sizeof(struct sockaddr_in6);
12128c2654abSrjs 		} else {
12138c2654abSrjs 			totaddr = i;
12148c2654abSrjs 			break;
12158c2654abSrjs 		}
12168c2654abSrjs 		stcb = sctp_findassociation_ep_addr(&inp, sa, NULL, NULL, NULL);
12178c2654abSrjs 		if (stcb != NULL) {
12188c2654abSrjs 			/* Already have or am bring up an association */
12198c2654abSrjs 			SCTP_ASOC_CREATE_UNLOCK(inp);
12208c2654abSrjs 			SCTP_TCB_UNLOCK(stcb);
12218c2654abSrjs 			return (EALREADY);
12228c2654abSrjs 		}
12233917a6f0Srjs 		if ((at + incr) > len) {
12248c2654abSrjs 			totaddr = i;
12258c2654abSrjs 			break;
12268c2654abSrjs 		}
12278c2654abSrjs 		sa = (struct sockaddr *)((vaddr_t)sa + incr);
12288c2654abSrjs 	}
12293917a6f0Srjs 	sa = (struct sockaddr *)buf;
12308c2654abSrjs 	SCTP_INP_WLOCK(inp);
12318c2654abSrjs 	SCTP_INP_DECR_REF(inp);
12328c2654abSrjs 	SCTP_INP_WUNLOCK(inp);
12338c2654abSrjs #ifdef INET6
12348c2654abSrjs 	if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) &&
12358c2654abSrjs 	    (num_v6 > 0)) {
12368c2654abSrjs 		SCTP_INP_WUNLOCK(inp);
12378c2654abSrjs 		SCTP_ASOC_CREATE_UNLOCK(inp);
12388c2654abSrjs 		return (EINVAL);
12398c2654abSrjs 	}
12408c2654abSrjs 	if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
12418c2654abSrjs 	    (num_v4 > 0)) {
12428c2654abSrjs 		struct in6pcb *inp6;
12438c2654abSrjs 		inp6 = (struct in6pcb *)inp;
12448c2654abSrjs 		if (inp6->in6p_flags & IN6P_IPV6_V6ONLY) {
12458c2654abSrjs 			/*
12468c2654abSrjs 			 * if IPV6_V6ONLY flag, ignore connections
12478c2654abSrjs 			 * destined to a v4 addr or v4-mapped addr
12488c2654abSrjs 			 */
12498c2654abSrjs 			SCTP_INP_WUNLOCK(inp);
12508c2654abSrjs 			SCTP_ASOC_CREATE_UNLOCK(inp);
12518c2654abSrjs 			return EINVAL;
12528c2654abSrjs 		}
12538c2654abSrjs 	}
12548c2654abSrjs #endif /* INET6 */
12558c2654abSrjs 	if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
12568c2654abSrjs 	    SCTP_PCB_FLAGS_UNBOUND) {
12578c2654abSrjs 		/* Bind a ephemeral port */
12588c2654abSrjs 		SCTP_INP_WUNLOCK(inp);
12598c2654abSrjs 		error = sctp_inpcb_bind(so, NULL, l);
12608c2654abSrjs 		if (error) {
12618c2654abSrjs 			SCTP_ASOC_CREATE_UNLOCK(inp);
12628c2654abSrjs 			return (error);
12638c2654abSrjs 		}
12648c2654abSrjs 	} else {
12658c2654abSrjs 		SCTP_INP_WUNLOCK(inp);
12668c2654abSrjs 	}
12678c2654abSrjs         /* We are GOOD to go */
12688c2654abSrjs 	stcb = sctp_aloc_assoc(inp, sa, 1, &error, 0);
12698c2654abSrjs 	if (stcb == NULL) {
12708c2654abSrjs 		/* Gak! no memory */
12718c2654abSrjs 		SCTP_ASOC_CREATE_UNLOCK(inp);
12728c2654abSrjs 		return (error);
12738c2654abSrjs 	}
12743917a6f0Srjs 
12758c2654abSrjs 	/* move to second address */
12768c2654abSrjs 	if (sa->sa_family == AF_INET)
12778c2654abSrjs 		sa = (struct sockaddr *)((vaddr_t)sa + sizeof(struct sockaddr_in));
12788c2654abSrjs 	else
12798c2654abSrjs 		sa = (struct sockaddr *)((vaddr_t)sa + sizeof(struct sockaddr_in6));
12808c2654abSrjs 
12818c2654abSrjs 	for (i = 1; i < totaddr; i++) {
12828c2654abSrjs 		if (sa->sa_family == AF_INET) {
12838c2654abSrjs 			incr = sizeof(struct sockaddr_in);
12848c2654abSrjs 			if (sctp_add_remote_addr(stcb, sa, 0, 8)) {
12858c2654abSrjs 				/* assoc gone no un-lock */
12868c2654abSrjs 				sctp_free_assoc(inp, stcb);
12878c2654abSrjs 				SCTP_ASOC_CREATE_UNLOCK(inp);
12888c2654abSrjs 				return (ENOBUFS);
12898c2654abSrjs 			}
12908c2654abSrjs 
12918c2654abSrjs 		} else if (sa->sa_family == AF_INET6) {
12928c2654abSrjs 			incr = sizeof(struct sockaddr_in6);
12938c2654abSrjs 			if (sctp_add_remote_addr(stcb, sa, 0, 8)) {
12948c2654abSrjs 				/* assoc gone no un-lock */
12958c2654abSrjs 				sctp_free_assoc(inp, stcb);
12968c2654abSrjs 				SCTP_ASOC_CREATE_UNLOCK(inp);
12978c2654abSrjs 				return (ENOBUFS);
12988c2654abSrjs 			}
12998c2654abSrjs 		}
13008c2654abSrjs 		sa = (struct sockaddr *)((vaddr_t)sa + incr);
13018c2654abSrjs 	}
13028c2654abSrjs 	stcb->asoc.state = SCTP_STATE_COOKIE_WAIT;
13033917a6f0Srjs 
13043917a6f0Srjs 	id = sctp_get_associd(stcb);
13053917a6f0Srjs 	memcpy(&sca->cx_num, &id, sizeof(sctp_assoc_t));
13063917a6f0Srjs 
13078c2654abSrjs 	if (delay) {
13088c2654abSrjs 		/* doing delayed connection */
13098c2654abSrjs 		stcb->asoc.delayed_connection = 1;
13108c2654abSrjs 		sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, stcb->asoc.primary_destination);
13118c2654abSrjs 	} else {
13128c2654abSrjs 		SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
13138c2654abSrjs 		sctp_send_initiate(inp, stcb);
13148c2654abSrjs 	}
13158c2654abSrjs 	SCTP_TCB_UNLOCK(stcb);
13168c2654abSrjs 	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
13178c2654abSrjs 		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
13188c2654abSrjs 		/* Set the connected flag so we can queue data */
13198c2654abSrjs 		soisconnecting(so);
13208c2654abSrjs 	}
13218c2654abSrjs 	SCTP_ASOC_CREATE_UNLOCK(inp);
13228c2654abSrjs 	return error;
13238c2654abSrjs }
13248c2654abSrjs 
13258c2654abSrjs 
13268c2654abSrjs static int
13278c2654abSrjs sctp_optsget(struct socket *so, struct sockopt *sopt)
13288c2654abSrjs {
13298c2654abSrjs 	struct sctp_inpcb *inp;
13308c2654abSrjs 	int error, optval=0;
13318c2654abSrjs 	int *ovp;
13328c2654abSrjs 	struct sctp_tcb *stcb = NULL;
13338c2654abSrjs 
13348c2654abSrjs         inp = (struct sctp_inpcb *)so->so_pcb;
13358c2654abSrjs 	if (inp == 0)
13368c2654abSrjs 		return EINVAL;
13378c2654abSrjs 	error = 0;
13388c2654abSrjs 
13398c2654abSrjs #ifdef SCTP_DEBUG
13408c2654abSrjs 	if (sctp_debug_on & SCTP_DEBUG_USRREQ2) {
13418c2654abSrjs 		printf("optsget opt:%x sz:%zu\n", sopt->sopt_name,
13428c2654abSrjs 		       sopt->sopt_size);
13438c2654abSrjs 	}
13448c2654abSrjs #endif /* SCTP_DEBUG */
13458c2654abSrjs 
13468c2654abSrjs 	switch (sopt->sopt_name) {
13478c2654abSrjs 	case SCTP_NODELAY:
13488c2654abSrjs 	case SCTP_AUTOCLOSE:
13498c2654abSrjs 	case SCTP_AUTO_ASCONF:
13508c2654abSrjs 	case SCTP_DISABLE_FRAGMENTS:
13518c2654abSrjs 	case SCTP_I_WANT_MAPPED_V4_ADDR:
13528c2654abSrjs #ifdef SCTP_DEBUG
13538c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_USRREQ2) {
13548c2654abSrjs 			printf("other stuff\n");
13558c2654abSrjs 		}
13568c2654abSrjs #endif /* SCTP_DEBUG */
13578c2654abSrjs 		SCTP_INP_RLOCK(inp);
13588c2654abSrjs 		switch (sopt->sopt_name) {
13598c2654abSrjs 		case SCTP_DISABLE_FRAGMENTS:
13608c2654abSrjs 			optval = inp->sctp_flags & SCTP_PCB_FLAGS_NO_FRAGMENT;
13618c2654abSrjs 			break;
13628c2654abSrjs 		case SCTP_I_WANT_MAPPED_V4_ADDR:
13638c2654abSrjs 			optval = inp->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4;
13648c2654abSrjs 			break;
13658c2654abSrjs 		case SCTP_AUTO_ASCONF:
13668c2654abSrjs 			optval = inp->sctp_flags & SCTP_PCB_FLAGS_AUTO_ASCONF;
13678c2654abSrjs 			break;
13688c2654abSrjs 		case SCTP_NODELAY:
13698c2654abSrjs 			optval = inp->sctp_flags & SCTP_PCB_FLAGS_NODELAY;
13708c2654abSrjs 			break;
13718c2654abSrjs 		case SCTP_AUTOCLOSE:
13728c2654abSrjs 			if ((inp->sctp_flags & SCTP_PCB_FLAGS_AUTOCLOSE) ==
13738c2654abSrjs 			    SCTP_PCB_FLAGS_AUTOCLOSE)
13748c2654abSrjs 				optval = inp->sctp_ep.auto_close_time;
13758c2654abSrjs 			else
13768c2654abSrjs 				optval = 0;
13778c2654abSrjs 			break;
13788c2654abSrjs 
13798c2654abSrjs 		default:
13808c2654abSrjs 			error = ENOPROTOOPT;
13818c2654abSrjs 		} /* end switch (sopt->sopt_name) */
13828c2654abSrjs 		if (sopt->sopt_name != SCTP_AUTOCLOSE) {
13838c2654abSrjs 			/* make it an "on/off" value */
13848c2654abSrjs 			optval = (optval != 0);
13858c2654abSrjs 		}
13868c2654abSrjs 		if (sopt->sopt_size < sizeof(int)) {
13878c2654abSrjs 			error = EINVAL;
13888c2654abSrjs 		}
13898c2654abSrjs 		SCTP_INP_RUNLOCK(inp);
13908c2654abSrjs 		if (error == 0) {
13918c2654abSrjs 			/* return the option value */
13928c2654abSrjs 			ovp = sopt->sopt_data;
13938c2654abSrjs 			*ovp = optval;
13948c2654abSrjs 			sopt->sopt_size = sizeof(optval);
13958c2654abSrjs 		}
13968c2654abSrjs 		break;
13978c2654abSrjs 	case SCTP_GET_ASOC_ID_LIST:
13988c2654abSrjs 	{
13998c2654abSrjs 		struct sctp_assoc_ids *ids;
14008c2654abSrjs 		int cnt, at;
14018c2654abSrjs 		u_int16_t orig;
14028c2654abSrjs 
14038c2654abSrjs 		if (sopt->sopt_size < sizeof(struct sctp_assoc_ids)) {
14048c2654abSrjs 			error = EINVAL;
14058c2654abSrjs 			break;
14068c2654abSrjs 		}
14078c2654abSrjs 		ids = sopt->sopt_data;
14088c2654abSrjs 		cnt = 0;
14098c2654abSrjs 		SCTP_INP_RLOCK(inp);
14108c2654abSrjs 		stcb = LIST_FIRST(&inp->sctp_asoc_list);
14118c2654abSrjs 		if (stcb == NULL) {
14128c2654abSrjs 		none_out_now:
14138c2654abSrjs 			ids->asls_numb_present = 0;
14148c2654abSrjs 			ids->asls_more_to_get = 0;
14158c2654abSrjs 			SCTP_INP_RUNLOCK(inp);
14168c2654abSrjs 			break;
14178c2654abSrjs 		}
14188c2654abSrjs 		orig = ids->asls_assoc_start;
14198c2654abSrjs 		stcb = LIST_FIRST(&inp->sctp_asoc_list);
14208c2654abSrjs 		while( orig ) {
14218c2654abSrjs 			stcb = LIST_NEXT(stcb , sctp_tcblist);
14228c2654abSrjs 			orig--;
14238c2654abSrjs 			cnt--;
14248c2654abSrjs 		}
14258c2654abSrjs 		if ( stcb == NULL)
14268c2654abSrjs 			goto none_out_now;
14278c2654abSrjs 
14288c2654abSrjs 		at = 0;
14298c2654abSrjs 		ids->asls_numb_present = 0;
14308c2654abSrjs 		ids->asls_more_to_get = 1;
14318c2654abSrjs 		while(at < MAX_ASOC_IDS_RET) {
14328c2654abSrjs 			ids->asls_assoc_id[at] = sctp_get_associd(stcb);
14338c2654abSrjs 			at++;
14348c2654abSrjs 			ids->asls_numb_present++;
14358c2654abSrjs 			stcb = LIST_NEXT(stcb , sctp_tcblist);
14368c2654abSrjs 			if (stcb == NULL) {
14378c2654abSrjs 				ids->asls_more_to_get = 0;
14388c2654abSrjs 				break;
14398c2654abSrjs 			}
14408c2654abSrjs 		}
14418c2654abSrjs 		SCTP_INP_RUNLOCK(inp);
14428c2654abSrjs 	}
14438c2654abSrjs 	break;
14448c2654abSrjs 	case SCTP_GET_NONCE_VALUES:
14458c2654abSrjs 	{
14468c2654abSrjs 		struct sctp_get_nonce_values *gnv;
14478c2654abSrjs 		if (sopt->sopt_size < sizeof(struct sctp_get_nonce_values)) {
14488c2654abSrjs 			error = EINVAL;
14498c2654abSrjs 			break;
14508c2654abSrjs 		}
14518c2654abSrjs 		gnv = sopt->sopt_data;
14528c2654abSrjs 		stcb = sctp_findassociation_ep_asocid(inp, gnv->gn_assoc_id);
14538c2654abSrjs 		if (stcb == NULL) {
14548c2654abSrjs 			error = ENOTCONN;
14558c2654abSrjs 		} else {
14568c2654abSrjs 			gnv->gn_peers_tag = stcb->asoc.peer_vtag;
14578c2654abSrjs 			gnv->gn_local_tag = stcb->asoc.my_vtag;
14588c2654abSrjs 			SCTP_TCB_UNLOCK(stcb);
14598c2654abSrjs 		}
14608c2654abSrjs 
14618c2654abSrjs 	}
14628c2654abSrjs 	break;
14638c2654abSrjs 	case SCTP_PEER_PUBLIC_KEY:
14648c2654abSrjs 	case SCTP_MY_PUBLIC_KEY:
14658c2654abSrjs 	case SCTP_SET_AUTH_CHUNKS:
14668c2654abSrjs 	case SCTP_SET_AUTH_SECRET:
14678c2654abSrjs 		/* not supported yet and until we refine the draft */
14688c2654abSrjs 		error = EOPNOTSUPP;
14698c2654abSrjs 		break;
14708c2654abSrjs 
14718c2654abSrjs 	case SCTP_DELAYED_ACK_TIME:
14728c2654abSrjs 	{
14738c2654abSrjs 		int32_t *tm;
14748c2654abSrjs 		if (sopt->sopt_size < sizeof(int32_t)) {
14758c2654abSrjs 			error = EINVAL;
14768c2654abSrjs 			break;
14778c2654abSrjs 		}
14788c2654abSrjs 		tm = sopt->sopt_data;
14798c2654abSrjs 
14808c2654abSrjs 		*tm = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]);
14818c2654abSrjs 	}
14828c2654abSrjs 	break;
14838c2654abSrjs 
14848c2654abSrjs 	case SCTP_GET_SNDBUF_USE:
14858c2654abSrjs 		if (sopt->sopt_size < sizeof(struct sctp_sockstat)) {
14868c2654abSrjs 			error = EINVAL;
14878c2654abSrjs 		} else {
14888c2654abSrjs 			struct sctp_sockstat *ss;
14898c2654abSrjs 			struct sctp_association *asoc;
14908c2654abSrjs 			ss = sopt->sopt_data;
14918c2654abSrjs    		        stcb = sctp_findassociation_ep_asocid(inp, ss->ss_assoc_id);
14928c2654abSrjs 			if (stcb == NULL) {
14938c2654abSrjs 				error = ENOTCONN;
14948c2654abSrjs 			} else {
14958c2654abSrjs 				asoc = &stcb->asoc;
14968c2654abSrjs 				ss->ss_total_sndbuf = (u_int32_t)asoc->total_output_queue_size;
14978c2654abSrjs 				ss->ss_total_mbuf_sndbuf = (u_int32_t)asoc->total_output_mbuf_queue_size;
14988c2654abSrjs 				ss->ss_total_recv_buf = (u_int32_t)(asoc->size_on_delivery_queue +
14998c2654abSrjs 								    asoc->size_on_reasm_queue +
15008c2654abSrjs 								    asoc->size_on_all_streams);
15018c2654abSrjs 				SCTP_TCB_UNLOCK(stcb);
15028c2654abSrjs 				error = 0;
15038c2654abSrjs 				sopt->sopt_size = sizeof(struct sctp_sockstat);
15048c2654abSrjs 			}
15058c2654abSrjs 		}
15068c2654abSrjs 		break;
15078c2654abSrjs 	case SCTP_MAXBURST:
15088c2654abSrjs 	{
15098c2654abSrjs 		u_int8_t *burst;
15108c2654abSrjs 		burst = sopt->sopt_data;
15118c2654abSrjs 		SCTP_INP_RLOCK(inp);
15128c2654abSrjs 		*burst = inp->sctp_ep.max_burst;
15138c2654abSrjs 		SCTP_INP_RUNLOCK(inp);
15148c2654abSrjs 		sopt->sopt_size = sizeof(u_int8_t);
15158c2654abSrjs 	}
15168c2654abSrjs 	break;
15178c2654abSrjs 	case SCTP_MAXSEG:
15188c2654abSrjs 	{
15198c2654abSrjs 		u_int32_t *segsize;
15208c2654abSrjs 		sctp_assoc_t *assoc_id;
15218c2654abSrjs 		int ovh;
15228c2654abSrjs 
15238c2654abSrjs 		if (sopt->sopt_size < sizeof(u_int32_t)) {
15248c2654abSrjs 			error = EINVAL;
15258c2654abSrjs 			break;
15268c2654abSrjs 		}
15278c2654abSrjs 		if (sopt->sopt_size < sizeof(sctp_assoc_t)) {
15288c2654abSrjs 			error = EINVAL;
15298c2654abSrjs 			break;
15308c2654abSrjs 		}
15318c2654abSrjs 		assoc_id = sopt->sopt_data;
15328c2654abSrjs 		segsize = sopt->sopt_data;
15338c2654abSrjs 		sopt->sopt_size = sizeof(u_int32_t);
15348c2654abSrjs 
15358c2654abSrjs 		if (((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
15368c2654abSrjs 		     (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) ||
15378c2654abSrjs 		    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
15388c2654abSrjs 			SCTP_INP_RLOCK(inp);
15398c2654abSrjs 			stcb = LIST_FIRST(&inp->sctp_asoc_list);
15408c2654abSrjs 			if (stcb) {
15418c2654abSrjs 				SCTP_TCB_LOCK(stcb);
15428c2654abSrjs 				SCTP_INP_RUNLOCK(inp);
15438c2654abSrjs 				*segsize = sctp_get_frag_point(stcb, &stcb->asoc);
15448c2654abSrjs 				SCTP_TCB_UNLOCK(stcb);
15458c2654abSrjs 			} else {
15468c2654abSrjs 				SCTP_INP_RUNLOCK(inp);
15478c2654abSrjs 				goto skipit;
15488c2654abSrjs 			}
15498c2654abSrjs 		} else {
15508c2654abSrjs 			stcb = sctp_findassociation_ep_asocid(inp, *assoc_id);
15518c2654abSrjs 			if (stcb) {
15528c2654abSrjs 				*segsize = sctp_get_frag_point(stcb, &stcb->asoc);
15538c2654abSrjs 				SCTP_TCB_UNLOCK(stcb);
15548c2654abSrjs 				break;
15558c2654abSrjs 			}
15568c2654abSrjs 		skipit:
15578c2654abSrjs 			/* default is to get the max, if I
15588c2654abSrjs 			 * can't calculate from an existing association.
15598c2654abSrjs 			 */
15608c2654abSrjs 			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
15618c2654abSrjs 				ovh = SCTP_MED_OVERHEAD;
15628c2654abSrjs 			} else {
15638c2654abSrjs 				ovh = SCTP_MED_V4_OVERHEAD;
15648c2654abSrjs 			}
15658c2654abSrjs 			*segsize = inp->sctp_frag_point - ovh;
15668c2654abSrjs 		}
15678c2654abSrjs 	}
15688c2654abSrjs 	break;
15698c2654abSrjs 
15708c2654abSrjs 	case SCTP_SET_DEBUG_LEVEL:
15718c2654abSrjs #ifdef SCTP_DEBUG
15728c2654abSrjs 	{
15738c2654abSrjs 		u_int32_t *level;
15748c2654abSrjs 		if (sopt->sopt_size < sizeof(u_int32_t)) {
15758c2654abSrjs 			error = EINVAL;
15768c2654abSrjs 			break;
15778c2654abSrjs 		}
15788c2654abSrjs 		level = sopt->sopt_data;
15798c2654abSrjs 		error = 0;
15808c2654abSrjs 		*level = sctp_debug_on;
15818c2654abSrjs 		sopt->sopt_size = sizeof(u_int32_t);
15828c2654abSrjs 		printf("Returning DEBUG LEVEL %x is set\n",
15838c2654abSrjs 		       (u_int)sctp_debug_on);
15848c2654abSrjs 	}
15858c2654abSrjs #else /* SCTP_DEBUG */
15868c2654abSrjs 	error = EOPNOTSUPP;
15878c2654abSrjs #endif
15888c2654abSrjs 	break;
15898c2654abSrjs 	case SCTP_GET_STAT_LOG:
15908c2654abSrjs #ifdef SCTP_STAT_LOGGING
15918c2654abSrjs 		error = sctp_fill_stat_log(m);
15928c2654abSrjs #else /* SCTP_DEBUG */
15938c2654abSrjs 		error = EOPNOTSUPP;
15948c2654abSrjs #endif
15958c2654abSrjs 		break;
15968c2654abSrjs 	case SCTP_GET_PEGS:
15978c2654abSrjs 	{
15988c2654abSrjs 		u_int32_t *pt;
15998c2654abSrjs 		if (sopt->sopt_size < sizeof(sctp_pegs)) {
16008c2654abSrjs 			error = EINVAL;
16018c2654abSrjs 			break;
16028c2654abSrjs 		}
16038c2654abSrjs 		pt = sopt->sopt_data;
16048c2654abSrjs 		memcpy(pt, sctp_pegs, sizeof(sctp_pegs));
16058c2654abSrjs 		sopt->sopt_size = sizeof(sctp_pegs);
16068c2654abSrjs 	}
16078c2654abSrjs 	break;
16088c2654abSrjs 	case SCTP_EVENTS:
16098c2654abSrjs 	{
16108c2654abSrjs 		struct sctp_event_subscribe *events;
16118c2654abSrjs #ifdef SCTP_DEBUG
16128c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_USRREQ2) {
16138c2654abSrjs 			printf("get events\n");
16148c2654abSrjs 		}
16158c2654abSrjs #endif /* SCTP_DEBUG */
16168c2654abSrjs 		if (sopt->sopt_size < sizeof(struct sctp_event_subscribe)) {
16178c2654abSrjs #ifdef SCTP_DEBUG
16188c2654abSrjs 			if (sctp_debug_on & SCTP_DEBUG_USRREQ2) {
16198c2654abSrjs 				printf("sopt->sopt_size is %d not %d\n",
16208c2654abSrjs 				       (int)sopt->sopt_size,
16218c2654abSrjs 				       (int)sizeof(struct sctp_event_subscribe));
16228c2654abSrjs 			}
16238c2654abSrjs #endif /* SCTP_DEBUG */
16248c2654abSrjs 			error = EINVAL;
16258c2654abSrjs 			break;
16268c2654abSrjs 		}
16278c2654abSrjs 		events = sopt->sopt_data;
16288c2654abSrjs 		memset(events, 0, sopt->sopt_size);
16298c2654abSrjs 		SCTP_INP_RLOCK(inp);
16308c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_RECVDATAIOEVNT)
16318c2654abSrjs 			events->sctp_data_io_event = 1;
16328c2654abSrjs 
16338c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_RECVASSOCEVNT)
16348c2654abSrjs 			events->sctp_association_event = 1;
16358c2654abSrjs 
16368c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_RECVPADDREVNT)
16378c2654abSrjs 			events->sctp_address_event = 1;
16388c2654abSrjs 
16398c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_RECVSENDFAILEVNT)
16408c2654abSrjs 			events->sctp_send_failure_event = 1;
16418c2654abSrjs 
16428c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_RECVPEERERR)
16438c2654abSrjs 			events->sctp_peer_error_event = 1;
16448c2654abSrjs 
16458c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT)
16468c2654abSrjs 			events->sctp_shutdown_event = 1;
16478c2654abSrjs 
16488c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_PDAPIEVNT)
16498c2654abSrjs 			events->sctp_partial_delivery_event = 1;
16508c2654abSrjs 
16518c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_ADAPTIONEVNT)
16528c2654abSrjs 			events->sctp_adaption_layer_event = 1;
16538c2654abSrjs 
16548c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_STREAM_RESETEVNT)
16558c2654abSrjs 			events->sctp_stream_reset_events = 1;
16568c2654abSrjs 		SCTP_INP_RUNLOCK(inp);
16578c2654abSrjs 		sopt->sopt_size = sizeof(struct sctp_event_subscribe);
16588c2654abSrjs 
16598c2654abSrjs 	}
16608c2654abSrjs 	break;
16618c2654abSrjs 
16628c2654abSrjs 	case SCTP_ADAPTION_LAYER:
16638c2654abSrjs 		if (sopt->sopt_size < sizeof(int)) {
16648c2654abSrjs 			error = EINVAL;
16658c2654abSrjs 			break;
16668c2654abSrjs 		}
16678c2654abSrjs #ifdef SCTP_DEBUG
16688c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_USRREQ1) {
16698c2654abSrjs 			printf("getadaption ind\n");
16708c2654abSrjs 		}
16718c2654abSrjs #endif /* SCTP_DEBUG */
16728c2654abSrjs 		SCTP_INP_RLOCK(inp);
16738c2654abSrjs 		ovp = sopt->sopt_data;
16748c2654abSrjs 		*ovp = inp->sctp_ep.adaption_layer_indicator;
16758c2654abSrjs 		SCTP_INP_RUNLOCK(inp);
16768c2654abSrjs 		sopt->sopt_size = sizeof(int);
16778c2654abSrjs 		break;
16788c2654abSrjs 	case SCTP_SET_INITIAL_DBG_SEQ:
16798c2654abSrjs 		if (sopt->sopt_size < sizeof(int)) {
16808c2654abSrjs 			error = EINVAL;
16818c2654abSrjs 			break;
16828c2654abSrjs 		}
16838c2654abSrjs #ifdef SCTP_DEBUG
16848c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_USRREQ1) {
16858c2654abSrjs 			printf("get initial dbg seq\n");
16868c2654abSrjs 		}
16878c2654abSrjs #endif /* SCTP_DEBUG */
16888c2654abSrjs 		SCTP_INP_RLOCK(inp);
16898c2654abSrjs 		ovp = sopt->sopt_data;
16908c2654abSrjs 		*ovp = inp->sctp_ep.initial_sequence_debug;
16918c2654abSrjs 		SCTP_INP_RUNLOCK(inp);
16928c2654abSrjs 		sopt->sopt_size = sizeof(int);
16938c2654abSrjs 		break;
16948c2654abSrjs 	case SCTP_GET_LOCAL_ADDR_SIZE:
16958c2654abSrjs 		if (sopt->sopt_size < sizeof(int)) {
16968c2654abSrjs 			error = EINVAL;
16978c2654abSrjs 			break;
16988c2654abSrjs 		}
16998c2654abSrjs #ifdef SCTP_DEBUG
17008c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_USRREQ1) {
17018c2654abSrjs 			printf("get local sizes\n");
17028c2654abSrjs 		}
17038c2654abSrjs #endif /* SCTP_DEBUG */
17048c2654abSrjs 		SCTP_INP_RLOCK(inp);
17058c2654abSrjs 		ovp = sopt->sopt_data;
17068c2654abSrjs 		*ovp = sctp_count_max_addresses(inp);
17078c2654abSrjs 		SCTP_INP_RUNLOCK(inp);
17088c2654abSrjs 		sopt->sopt_size = sizeof(int);
17098c2654abSrjs 		break;
17108c2654abSrjs 	case SCTP_GET_REMOTE_ADDR_SIZE:
17118c2654abSrjs 	{
17128c2654abSrjs 		sctp_assoc_t *assoc_id;
17138c2654abSrjs 		u_int32_t *val, sz;
17148c2654abSrjs 		struct sctp_nets *net;
17158c2654abSrjs #ifdef SCTP_DEBUG
17168c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_USRREQ1) {
17178c2654abSrjs 			printf("get remote size\n");
17188c2654abSrjs 		}
17198c2654abSrjs #endif /* SCTP_DEBUG */
17208c2654abSrjs 		if (sopt->sopt_size < sizeof(sctp_assoc_t)) {
17218c2654abSrjs #ifdef SCTP_DEBUG
17228c2654abSrjs 			printf("sopt->sopt_size:%zu not %zu\n",
17238c2654abSrjs 			       sopt->sopt_size, sizeof(sctp_assoc_t));
17248c2654abSrjs #endif /* SCTP_DEBUG */
17258c2654abSrjs 			error = EINVAL;
17268c2654abSrjs 			break;
17278c2654abSrjs 		}
17288c2654abSrjs 		stcb = NULL;
17298c2654abSrjs 		val = sopt->sopt_data;
17308c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
17318c2654abSrjs 			SCTP_INP_RLOCK(inp);
17328c2654abSrjs 			stcb = LIST_FIRST(&inp->sctp_asoc_list);
17338c2654abSrjs 			if (stcb) {
17348c2654abSrjs 				SCTP_TCB_LOCK(stcb);
17358c2654abSrjs 			}
17368c2654abSrjs 			SCTP_INP_RUNLOCK(inp);
17378c2654abSrjs 		}
17388c2654abSrjs 		if (stcb == NULL) {
17398c2654abSrjs 			assoc_id = sopt->sopt_data;
17408c2654abSrjs 			stcb = sctp_findassociation_ep_asocid(inp, *assoc_id);
17418c2654abSrjs 		}
17428c2654abSrjs 
17438c2654abSrjs 		if (stcb == NULL) {
17448c2654abSrjs 			error = EINVAL;
17458c2654abSrjs 			break;
17468c2654abSrjs 		}
17478c2654abSrjs 		*val = 0;
17488c2654abSrjs 		sz = 0;
17498c2654abSrjs 		/* Count the sizes */
17508c2654abSrjs 		TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
17518c2654abSrjs 			if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) ||
17528c2654abSrjs 			    (rtcache_getdst(&net->ro)->sa_family == AF_INET6)) {
17538c2654abSrjs 				sz += sizeof(struct sockaddr_in6);
17548c2654abSrjs 			} else if (rtcache_getdst(&net->ro)->sa_family == AF_INET) {
17558c2654abSrjs 				sz += sizeof(struct sockaddr_in);
17568c2654abSrjs 			} else {
17578c2654abSrjs 				/* huh */
17588c2654abSrjs 				break;
17598c2654abSrjs 			}
17608c2654abSrjs 		}
17618c2654abSrjs 		SCTP_TCB_UNLOCK(stcb);
17628c2654abSrjs 		*val = sz;
17638c2654abSrjs 		sopt->sopt_size = sizeof(u_int32_t);
17648c2654abSrjs 	}
17658c2654abSrjs 	break;
17668c2654abSrjs 	case SCTP_GET_PEER_ADDRESSES:
17678c2654abSrjs 		/*
17688c2654abSrjs 		 * Get the address information, an array
17698c2654abSrjs 		 * is passed in to fill up we pack it.
17708c2654abSrjs 		 */
17718c2654abSrjs 	{
17728c2654abSrjs 		int cpsz, left;
17738c2654abSrjs 		struct sockaddr_storage *sas;
17748c2654abSrjs 		struct sctp_nets *net;
17758c2654abSrjs 		struct sctp_getaddresses *saddr;
17768c2654abSrjs #ifdef SCTP_DEBUG
17778c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_USRREQ1) {
17788c2654abSrjs 			printf("get peer addresses\n");
17798c2654abSrjs 		}
17808c2654abSrjs #endif /* SCTP_DEBUG */
17818c2654abSrjs 		if (sopt->sopt_size < sizeof(struct sctp_getaddresses)) {
17828c2654abSrjs 			error = EINVAL;
17838c2654abSrjs 			break;
17848c2654abSrjs 		}
17858c2654abSrjs 		left = sopt->sopt_size - sizeof(struct sctp_getaddresses);
17868c2654abSrjs 		saddr = sopt->sopt_data;
17878c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
17888c2654abSrjs 			SCTP_INP_RLOCK(inp);
17898c2654abSrjs 			stcb = LIST_FIRST(&inp->sctp_asoc_list);
17908c2654abSrjs 			if (stcb) {
17918c2654abSrjs 				SCTP_TCB_LOCK(stcb);
17928c2654abSrjs 			}
17938c2654abSrjs 			SCTP_INP_RUNLOCK(inp);
17948c2654abSrjs 		} else
17958c2654abSrjs 			stcb = sctp_findassociation_ep_asocid(inp,
17968c2654abSrjs 							      saddr->sget_assoc_id);
17978c2654abSrjs 		if (stcb == NULL) {
17988c2654abSrjs 			error = ENOENT;
17998c2654abSrjs 			break;
18008c2654abSrjs 		}
18018c2654abSrjs 		sopt->sopt_size = sizeof(struct sctp_getaddresses);
18028c2654abSrjs 		sas = (struct sockaddr_storage *)&saddr->addr[0];
18038c2654abSrjs 
18048c2654abSrjs 		TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
18058c2654abSrjs 			sa_family_t family;
18068c2654abSrjs 
18078c2654abSrjs 			family = rtcache_getdst(&net->ro)->sa_family;
18088c2654abSrjs 			if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) ||
18098c2654abSrjs 			    (family == AF_INET6)) {
18108c2654abSrjs 				cpsz = sizeof(struct sockaddr_in6);
18118c2654abSrjs 			} else if (family == AF_INET) {
18128c2654abSrjs 				cpsz = sizeof(struct sockaddr_in);
18138c2654abSrjs 			} else {
18148c2654abSrjs 				/* huh */
18158c2654abSrjs 				break;
18168c2654abSrjs 			}
18178c2654abSrjs 			if (left < cpsz) {
18188c2654abSrjs 				/* not enough room. */
18198c2654abSrjs #ifdef SCTP_DEBUG
18208c2654abSrjs 				if (sctp_debug_on & SCTP_DEBUG_USRREQ1) {
18218c2654abSrjs 					printf("Out of room\n");
18228c2654abSrjs 				}
18238c2654abSrjs #endif /* SCTP_DEBUG */
18248c2654abSrjs 				break;
18258c2654abSrjs 			}
18268c2654abSrjs 			if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) &&
18278c2654abSrjs 			    (family == AF_INET)) {
18288c2654abSrjs 				/* Must map the address */
18298c2654abSrjs 				in6_sin_2_v4mapsin6((const struct sockaddr_in *) rtcache_getdst(&net->ro),
18308c2654abSrjs 						    (struct sockaddr_in6 *)sas);
18318c2654abSrjs 			} else {
18328c2654abSrjs 				memcpy(sas, rtcache_getdst(&net->ro), cpsz);
18338c2654abSrjs 			}
18348c2654abSrjs 			((struct sockaddr_in *)sas)->sin_port = stcb->rport;
18358c2654abSrjs 
18368c2654abSrjs 			sas = (struct sockaddr_storage *)((vaddr_t)sas + cpsz);
18378c2654abSrjs 			left -= cpsz;
18388c2654abSrjs 			sopt->sopt_size += cpsz;
18398c2654abSrjs #ifdef SCTP_DEBUG
18408c2654abSrjs 			if (sctp_debug_on & SCTP_DEBUG_USRREQ2) {
18418c2654abSrjs 				printf("left now:%d mlen:%zu\n",
18428c2654abSrjs 				       left, sopt->sopt_size);
18438c2654abSrjs 			}
18448c2654abSrjs #endif /* SCTP_DEBUG */
18458c2654abSrjs 		}
18468c2654abSrjs 		SCTP_TCB_UNLOCK(stcb);
18478c2654abSrjs 	}
18488c2654abSrjs #ifdef SCTP_DEBUG
18498c2654abSrjs 	if (sctp_debug_on & SCTP_DEBUG_USRREQ1) {
18508c2654abSrjs 		printf("All done\n");
18518c2654abSrjs 	}
18528c2654abSrjs #endif /* SCTP_DEBUG */
18538c2654abSrjs 	break;
18548c2654abSrjs 	case SCTP_GET_LOCAL_ADDRESSES:
18558c2654abSrjs 	{
18568c2654abSrjs 		int limit, actual;
18578c2654abSrjs 		struct sockaddr_storage *sas;
18588c2654abSrjs 		struct sctp_getaddresses *saddr;
18598c2654abSrjs #ifdef SCTP_DEBUG
18608c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_USRREQ1) {
18618c2654abSrjs 			printf("get local addresses\n");
18628c2654abSrjs 		}
18638c2654abSrjs #endif /* SCTP_DEBUG */
18648c2654abSrjs 		if (sopt->sopt_size < sizeof(struct sctp_getaddresses)) {
18658c2654abSrjs 			error = EINVAL;
18668c2654abSrjs 			break;
18678c2654abSrjs 		}
18688c2654abSrjs 		saddr = sopt->sopt_data;
18698c2654abSrjs 
18708c2654abSrjs 		if (saddr->sget_assoc_id) {
18718c2654abSrjs 			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
18728c2654abSrjs 				SCTP_INP_RLOCK(inp);
18738c2654abSrjs 				stcb = LIST_FIRST(&inp->sctp_asoc_list);
18748c2654abSrjs 				if (stcb) {
18758c2654abSrjs 					SCTP_TCB_LOCK(stcb);
18768c2654abSrjs 				}
18778c2654abSrjs 				SCTP_INP_RUNLOCK(inp);
18788c2654abSrjs 			} else
18798c2654abSrjs 				stcb = sctp_findassociation_ep_asocid(inp, saddr->sget_assoc_id);
18808c2654abSrjs 
18818c2654abSrjs 		} else {
18828c2654abSrjs 			stcb = NULL;
18838c2654abSrjs 		}
18848c2654abSrjs 		/*
18858c2654abSrjs 		 * assure that the TCP model does not need a assoc id
18868c2654abSrjs 		 * once connected.
18878c2654abSrjs 		 */
18888c2654abSrjs 		if ( (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) &&
18898c2654abSrjs 		     (stcb == NULL) ) {
18908c2654abSrjs 			SCTP_INP_RLOCK(inp);
18918c2654abSrjs 			stcb = LIST_FIRST(&inp->sctp_asoc_list);
18928c2654abSrjs 			if (stcb) {
18938c2654abSrjs 				SCTP_TCB_LOCK(stcb);
18948c2654abSrjs 			}
18958c2654abSrjs 			SCTP_INP_RUNLOCK(inp);
18968c2654abSrjs 		}
18978c2654abSrjs 		sas = (struct sockaddr_storage *)&saddr->addr[0];
18988c2654abSrjs 		limit = sopt->sopt_size - sizeof(sctp_assoc_t);
18998c2654abSrjs 		actual = sctp_fill_up_addresses(inp, stcb, limit, sas);
19008c2654abSrjs 		SCTP_TCB_UNLOCK(stcb);
19018c2654abSrjs 		sopt->sopt_size = sizeof(struct sockaddr_storage) + actual;
19028c2654abSrjs 	}
19038c2654abSrjs 	break;
19048c2654abSrjs 	case SCTP_PEER_ADDR_PARAMS:
19058c2654abSrjs 	{
19068c2654abSrjs 		struct sctp_paddrparams *paddrp;
19078c2654abSrjs 		struct sctp_nets *net;
19088c2654abSrjs 
19098c2654abSrjs #ifdef SCTP_DEBUG
19108c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_USRREQ1) {
19118c2654abSrjs 			printf("Getting peer_addr_params\n");
19128c2654abSrjs 		}
19138c2654abSrjs #endif /* SCTP_DEBUG */
19148c2654abSrjs 		if (sopt->sopt_size < sizeof(struct sctp_paddrparams)) {
19158c2654abSrjs #ifdef SCTP_DEBUG
19168c2654abSrjs 			if (sctp_debug_on & SCTP_DEBUG_USRREQ2) {
19178c2654abSrjs 				printf("Hmm m->m_len:%zu is to small\n",
19188c2654abSrjs 				       sopt->sopt_size);
19198c2654abSrjs 			}
19208c2654abSrjs #endif /* SCTP_DEBUG */
19218c2654abSrjs 			error = EINVAL;
19228c2654abSrjs 			break;
19238c2654abSrjs 		}
19248c2654abSrjs 		paddrp = sopt->sopt_data;
19258c2654abSrjs 
19268c2654abSrjs 		net = NULL;
19278c2654abSrjs 		if (paddrp->spp_assoc_id) {
19288c2654abSrjs #ifdef SCTP_DEBUG
19298c2654abSrjs 			if (sctp_debug_on & SCTP_DEBUG_USRREQ1) {
19308c2654abSrjs 				printf("In spp_assoc_id find type\n");
19318c2654abSrjs 			}
19328c2654abSrjs #endif /* SCTP_DEBUG */
19338c2654abSrjs 			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
19348c2654abSrjs 				SCTP_INP_RLOCK(inp);
19358c2654abSrjs 				stcb = LIST_FIRST(&inp->sctp_asoc_list);
19368c2654abSrjs 				if (stcb) {
19378c2654abSrjs 					SCTP_TCB_LOCK(stcb);
19388c2654abSrjs 					net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address);
19398c2654abSrjs 				}
19408c2654abSrjs 				SCTP_INP_RLOCK(inp);
19418c2654abSrjs 			} else {
19428c2654abSrjs 				stcb = sctp_findassociation_ep_asocid(inp, paddrp->spp_assoc_id);
19438c2654abSrjs 			}
19448c2654abSrjs 			if (stcb == NULL) {
19458c2654abSrjs 				error = ENOENT;
19468c2654abSrjs 				break;
19478c2654abSrjs 			}
19488c2654abSrjs 		}
19498c2654abSrjs 		if ((stcb == NULL) &&
19508c2654abSrjs 			((((struct sockaddr *)&paddrp->spp_address)->sa_family == AF_INET) ||
19518c2654abSrjs 			 (((struct sockaddr *)&paddrp->spp_address)->sa_family == AF_INET6))) {
19528c2654abSrjs 			/* Lookup via address */
19538c2654abSrjs #ifdef SCTP_DEBUG
19548c2654abSrjs 			if (sctp_debug_on & SCTP_DEBUG_USRREQ1) {
19558c2654abSrjs 				printf("Ok we need to lookup a param\n");
19568c2654abSrjs 			}
19578c2654abSrjs #endif /* SCTP_DEBUG */
19588c2654abSrjs 			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
19598c2654abSrjs 				SCTP_INP_RLOCK(inp);
19608c2654abSrjs 				stcb = LIST_FIRST(&inp->sctp_asoc_list);
19618c2654abSrjs 				if (stcb) {
19628c2654abSrjs 					SCTP_TCB_LOCK(stcb);
19638c2654abSrjs 					net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address);
19648c2654abSrjs 				}
19658c2654abSrjs 				SCTP_INP_RUNLOCK(inp);
19668c2654abSrjs 			} else {
19678c2654abSrjs 				SCTP_INP_WLOCK(inp);
19688c2654abSrjs 				SCTP_INP_INCR_REF(inp);
19698c2654abSrjs 				SCTP_INP_WUNLOCK(inp);
19708c2654abSrjs 				stcb = sctp_findassociation_ep_addr(&inp,
19718c2654abSrjs 								    (struct sockaddr *)&paddrp->spp_address,
19728c2654abSrjs 								    &net, NULL, NULL);
19738c2654abSrjs 				if (stcb == NULL) {
19748c2654abSrjs 					SCTP_INP_WLOCK(inp);
19758c2654abSrjs 					SCTP_INP_DECR_REF(inp);
19768c2654abSrjs 					SCTP_INP_WUNLOCK(inp);
19778c2654abSrjs 				}
19788c2654abSrjs 			}
19798c2654abSrjs 
19808c2654abSrjs 			if (stcb == NULL) {
19818c2654abSrjs 				error = ENOENT;
19828c2654abSrjs 				break;
19838c2654abSrjs 			}
19848c2654abSrjs 		} else {
19858c2654abSrjs 			/* Effects the Endpoint */
19868c2654abSrjs #ifdef SCTP_DEBUG
19878c2654abSrjs 			if (sctp_debug_on & SCTP_DEBUG_USRREQ1) {
19888c2654abSrjs 				printf("User wants EP level info\n");
19898c2654abSrjs 			}
19908c2654abSrjs #endif /* SCTP_DEBUG */
19918c2654abSrjs 			stcb = NULL;
19928c2654abSrjs 		}
19938c2654abSrjs 		if (stcb) {
19948c2654abSrjs 			/* Applys to the specific association */
19958c2654abSrjs #ifdef SCTP_DEBUG
19968c2654abSrjs 			if (sctp_debug_on & SCTP_DEBUG_USRREQ1) {
19978c2654abSrjs 				printf("In TCB side\n");
19988c2654abSrjs 			}
19998c2654abSrjs #endif /* SCTP_DEBUG */
20008c2654abSrjs 			if (net) {
20018c2654abSrjs 				paddrp->spp_pathmaxrxt = net->failure_threshold;
20028c2654abSrjs 			} else {
20038c2654abSrjs 				/* No destination so return default value */
20048c2654abSrjs 				paddrp->spp_pathmaxrxt = stcb->asoc.def_net_failure;
20058c2654abSrjs 			}
20068c2654abSrjs 			paddrp->spp_hbinterval = stcb->asoc.heart_beat_delay;
20078c2654abSrjs 			paddrp->spp_assoc_id = sctp_get_associd(stcb);
20088c2654abSrjs 			SCTP_TCB_UNLOCK(stcb);
20098c2654abSrjs 		} else {
20108c2654abSrjs 			/* Use endpoint defaults */
20118c2654abSrjs 			SCTP_INP_RLOCK(inp);
20128c2654abSrjs #ifdef SCTP_DEBUG
20138c2654abSrjs 			if (sctp_debug_on & SCTP_DEBUG_USRREQ1) {
20145fb5f516Sandvar 				printf("In EP level info\n");
20158c2654abSrjs 			}
20168c2654abSrjs #endif /* SCTP_DEBUG */
20178c2654abSrjs 			paddrp->spp_pathmaxrxt = inp->sctp_ep.def_net_failure;
20188c2654abSrjs 			paddrp->spp_hbinterval = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT];
20198c2654abSrjs 			paddrp->spp_assoc_id = (sctp_assoc_t)0;
20208c2654abSrjs 			SCTP_INP_RUNLOCK(inp);
20218c2654abSrjs 		}
20228c2654abSrjs 		sopt->sopt_size = sizeof(struct sctp_paddrparams);
20238c2654abSrjs 	}
20248c2654abSrjs 	break;
20258c2654abSrjs 	case SCTP_GET_PEER_ADDR_INFO:
20268c2654abSrjs 	{
20278c2654abSrjs 		struct sctp_paddrinfo *paddri;
20288c2654abSrjs 		struct sctp_nets *net;
20298c2654abSrjs #ifdef SCTP_DEBUG
20308c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_USRREQ1) {
20318c2654abSrjs 			printf("GetPEER ADDR_INFO\n");
20328c2654abSrjs 		}
20338c2654abSrjs #endif /* SCTP_DEBUG */
20348c2654abSrjs 		if (sopt->sopt_size < sizeof(struct sctp_paddrinfo)) {
20358c2654abSrjs 			error = EINVAL;
20368c2654abSrjs 			break;
20378c2654abSrjs 		}
20388c2654abSrjs 		paddri = sopt->sopt_data;
20398c2654abSrjs 		net = NULL;
20408c2654abSrjs 		if ((((struct sockaddr *)&paddri->spinfo_address)->sa_family == AF_INET) ||
20418c2654abSrjs 		    (((struct sockaddr *)&paddri->spinfo_address)->sa_family == AF_INET6)) {
20428c2654abSrjs 			/* Lookup via address */
20438c2654abSrjs 			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
20448c2654abSrjs 				SCTP_INP_RLOCK(inp);
20458c2654abSrjs 				stcb = LIST_FIRST(&inp->sctp_asoc_list);
20468c2654abSrjs 				if (stcb) {
20478c2654abSrjs 					SCTP_TCB_LOCK(stcb);
20488c2654abSrjs 					net = sctp_findnet(stcb,
20498c2654abSrjs 							    (struct sockaddr *)&paddri->spinfo_address);
20508c2654abSrjs 				}
20518c2654abSrjs 				SCTP_INP_RUNLOCK(inp);
20528c2654abSrjs 			} else {
20538c2654abSrjs 				SCTP_INP_WLOCK(inp);
20548c2654abSrjs 				SCTP_INP_INCR_REF(inp);
20558c2654abSrjs 				SCTP_INP_WUNLOCK(inp);
20568c2654abSrjs 				stcb = sctp_findassociation_ep_addr(&inp,
20578c2654abSrjs 				    (struct sockaddr *)&paddri->spinfo_address,
20588c2654abSrjs 				    &net, NULL, NULL);
20598c2654abSrjs 				if (stcb == NULL) {
20608c2654abSrjs 					SCTP_INP_WLOCK(inp);
20618c2654abSrjs 					SCTP_INP_DECR_REF(inp);
20628c2654abSrjs 					SCTP_INP_WUNLOCK(inp);
20638c2654abSrjs 				}
20648c2654abSrjs 			}
20658c2654abSrjs 
20668c2654abSrjs 		} else {
20678c2654abSrjs 			stcb = NULL;
20688c2654abSrjs 		}
20698c2654abSrjs 		if ((stcb == NULL) || (net == NULL)) {
20708c2654abSrjs 			error = ENOENT;
20718c2654abSrjs 			break;
20728c2654abSrjs 		}
20738c2654abSrjs 		sopt->sopt_size = sizeof(struct sctp_paddrinfo);
20748c2654abSrjs 		paddri->spinfo_state = net->dest_state & (SCTP_REACHABLE_MASK|SCTP_ADDR_NOHB);
20758c2654abSrjs 		paddri->spinfo_cwnd = net->cwnd;
20768c2654abSrjs 		paddri->spinfo_srtt = ((net->lastsa >> 2) + net->lastsv) >> 1;
20778c2654abSrjs 		paddri->spinfo_rto = net->RTO;
20788c2654abSrjs 		paddri->spinfo_assoc_id = sctp_get_associd(stcb);
20798c2654abSrjs 		SCTP_TCB_UNLOCK(stcb);
20808c2654abSrjs 	}
20818c2654abSrjs 	break;
20828c2654abSrjs 	case SCTP_PCB_STATUS:
20838c2654abSrjs 	{
20848c2654abSrjs 		struct sctp_pcbinfo *spcb;
20858c2654abSrjs #ifdef SCTP_DEBUG
20868c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_USRREQ1) {
20878c2654abSrjs 			printf("PCB status\n");
20888c2654abSrjs 		}
20898c2654abSrjs #endif /* SCTP_DEBUG */
20908c2654abSrjs 		if (sopt->sopt_size < sizeof(struct sctp_pcbinfo)) {
20918c2654abSrjs 			error = EINVAL;
20928c2654abSrjs 			break;
20938c2654abSrjs 		}
20948c2654abSrjs 		spcb = sopt->sopt_data;
20958c2654abSrjs 		sctp_fill_pcbinfo(spcb);
20968c2654abSrjs 		sopt->sopt_size = sizeof(struct sctp_pcbinfo);
20978c2654abSrjs 	}
20988c2654abSrjs 	break;
20998c2654abSrjs 	case SCTP_STATUS:
21008c2654abSrjs 	{
21018c2654abSrjs 		struct sctp_nets *net;
21028c2654abSrjs 		struct sctp_status *sstat;
21038c2654abSrjs #ifdef SCTP_DEBUG
21048c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_USRREQ1) {
21058c2654abSrjs 			printf("SCTP status\n");
21068c2654abSrjs 		}
21078c2654abSrjs #endif /* SCTP_DEBUG */
21088c2654abSrjs 
21098c2654abSrjs 		if (sopt->sopt_size < sizeof(struct sctp_status)) {
21108c2654abSrjs 			error = EINVAL;
21118c2654abSrjs 			break;
21128c2654abSrjs 		}
21138c2654abSrjs 		sstat = sopt->sopt_data;
21148c2654abSrjs 
21158c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
21168c2654abSrjs 			SCTP_INP_RLOCK(inp);
21178c2654abSrjs 			stcb = LIST_FIRST(&inp->sctp_asoc_list);
21188c2654abSrjs 			if (stcb) {
21198c2654abSrjs 				SCTP_TCB_LOCK(stcb);
21208c2654abSrjs 			}
21218c2654abSrjs 			SCTP_INP_RUNLOCK(inp);
21228c2654abSrjs 		} else
21238c2654abSrjs 			stcb = sctp_findassociation_ep_asocid(inp, sstat->sstat_assoc_id);
21248c2654abSrjs 
21258c2654abSrjs 		if (stcb == NULL) {
21263917a6f0Srjs 			printf("SCTP status, no stcb\n");
21278c2654abSrjs 			error = EINVAL;
21288c2654abSrjs 			break;
21298c2654abSrjs 		}
21308c2654abSrjs 		/*
21318c2654abSrjs 		 * I think passing the state is fine since
21328c2654abSrjs 		 * sctp_constants.h will be available to the user
21338c2654abSrjs 		 * land.
21348c2654abSrjs 		 */
21358c2654abSrjs 		sstat->sstat_state = stcb->asoc.state;
21368c2654abSrjs 		sstat->sstat_rwnd = stcb->asoc.peers_rwnd;
21378c2654abSrjs 		sstat->sstat_unackdata = stcb->asoc.sent_queue_cnt;
21388c2654abSrjs 		/*
21398c2654abSrjs 		 * We can't include chunks that have been passed
21408c2654abSrjs 		 * to the socket layer. Only things in queue.
21418c2654abSrjs 		 */
21428c2654abSrjs 		sstat->sstat_penddata = (stcb->asoc.cnt_on_delivery_queue +
21438c2654abSrjs 					 stcb->asoc.cnt_on_reasm_queue +
21448c2654abSrjs 					 stcb->asoc.cnt_on_all_streams);
21458c2654abSrjs 
21468c2654abSrjs 
21478c2654abSrjs 		sstat->sstat_instrms = stcb->asoc.streamincnt;
21488c2654abSrjs 		sstat->sstat_outstrms = stcb->asoc.streamoutcnt;
21498c2654abSrjs 		sstat->sstat_fragmentation_point = sctp_get_frag_point(stcb, &stcb->asoc);
21508c2654abSrjs 		memcpy(&sstat->sstat_primary.spinfo_address,
21518c2654abSrjs 		       rtcache_getdst(&stcb->asoc.primary_destination->ro),
21528c2654abSrjs 		       (rtcache_getdst(&stcb->asoc.primary_destination->ro))->sa_len);
21538c2654abSrjs 		net = stcb->asoc.primary_destination;
21548c2654abSrjs 		((struct sockaddr_in *)&sstat->sstat_primary.spinfo_address)->sin_port = stcb->rport;
21558c2654abSrjs 		/*
21568c2654abSrjs 		 * Again the user can get info from sctp_constants.h
21578c2654abSrjs 		 * for what the state of the network is.
21588c2654abSrjs 		 */
21598c2654abSrjs 		sstat->sstat_primary.spinfo_state = net->dest_state & SCTP_REACHABLE_MASK;
21608c2654abSrjs 		sstat->sstat_primary.spinfo_cwnd = net->cwnd;
21618c2654abSrjs 		sstat->sstat_primary.spinfo_srtt = net->lastsa;
21628c2654abSrjs 		sstat->sstat_primary.spinfo_rto = net->RTO;
21638c2654abSrjs 		sstat->sstat_primary.spinfo_mtu = net->mtu;
21648c2654abSrjs 		sstat->sstat_primary.spinfo_assoc_id = sctp_get_associd(stcb);
21658c2654abSrjs 		SCTP_TCB_UNLOCK(stcb);
21668c2654abSrjs 		sopt->sopt_size = sizeof(*sstat);
21678c2654abSrjs 	}
21688c2654abSrjs 	break;
21698c2654abSrjs 	case SCTP_RTOINFO:
21708c2654abSrjs 	{
21718c2654abSrjs 		struct sctp_rtoinfo *srto;
21728c2654abSrjs #ifdef SCTP_DEBUG
21738c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_USRREQ1) {
21748c2654abSrjs 			printf("RTO Info\n");
21758c2654abSrjs 		}
21768c2654abSrjs #endif /* SCTP_DEBUG */
21778c2654abSrjs 		if (sopt->sopt_size < sizeof(struct sctp_rtoinfo)) {
21788c2654abSrjs 			error = EINVAL;
21798c2654abSrjs 			break;
21808c2654abSrjs 		}
21818c2654abSrjs 		srto = sopt->sopt_data;
21828c2654abSrjs 		if (srto->srto_assoc_id == 0) {
21838c2654abSrjs 			/* Endpoint only please */
21848c2654abSrjs 			SCTP_INP_RLOCK(inp);
21858c2654abSrjs 			srto->srto_initial = inp->sctp_ep.initial_rto;
21868c2654abSrjs 			srto->srto_max = inp->sctp_ep.sctp_maxrto;
21878c2654abSrjs 			srto->srto_min = inp->sctp_ep.sctp_minrto;
21888c2654abSrjs 			SCTP_INP_RUNLOCK(inp);
21898c2654abSrjs 			break;
21908c2654abSrjs 		}
21918c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
21928c2654abSrjs 			SCTP_INP_RLOCK(inp);
21938c2654abSrjs 			stcb = LIST_FIRST(&inp->sctp_asoc_list);
21948c2654abSrjs 			if (stcb) {
21958c2654abSrjs 				SCTP_TCB_LOCK(stcb);
21968c2654abSrjs 			}
21978c2654abSrjs 			SCTP_INP_RUNLOCK(inp);
21988c2654abSrjs 		} else
21998c2654abSrjs 			stcb = sctp_findassociation_ep_asocid(inp, srto->srto_assoc_id);
22008c2654abSrjs 
22018c2654abSrjs 		if (stcb == NULL) {
22028c2654abSrjs 			error = EINVAL;
22038c2654abSrjs 			break;
22048c2654abSrjs 		}
22058c2654abSrjs 		srto->srto_initial = stcb->asoc.initial_rto;
22068c2654abSrjs 		srto->srto_max = stcb->asoc.maxrto;
22078c2654abSrjs 		srto->srto_min = stcb->asoc.minrto;
22088c2654abSrjs 		SCTP_TCB_UNLOCK(stcb);
22098c2654abSrjs 		sopt->sopt_size = sizeof(*srto);
22108c2654abSrjs 	}
22118c2654abSrjs 	break;
22128c2654abSrjs 	case SCTP_ASSOCINFO:
22138c2654abSrjs 	{
22148c2654abSrjs 		struct sctp_assocparams *sasoc;
22158c2654abSrjs #ifdef SCTP_DEBUG
22168c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_USRREQ1) {
22178c2654abSrjs 			printf("Associnfo\n");
22188c2654abSrjs 		}
22198c2654abSrjs #endif /* SCTP_DEBUG */
22208c2654abSrjs 		if (sopt->sopt_size < sizeof(struct sctp_assocparams)) {
22218c2654abSrjs 			error = EINVAL;
22228c2654abSrjs 			break;
22238c2654abSrjs 		}
22248c2654abSrjs 		sasoc = sopt->sopt_data;
22258c2654abSrjs 		stcb = NULL;
22268c2654abSrjs 
22278c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
22288c2654abSrjs 			SCTP_INP_RLOCK(inp);
22298c2654abSrjs 			stcb = LIST_FIRST(&inp->sctp_asoc_list);
22308c2654abSrjs 			if (stcb) {
22318c2654abSrjs 				SCTP_TCB_LOCK(stcb);
22328c2654abSrjs 			}
22338c2654abSrjs 			SCTP_INP_RUNLOCK(inp);
22348c2654abSrjs 		}
22358c2654abSrjs 		if ((sasoc->sasoc_assoc_id) && (stcb == NULL)) {
22368c2654abSrjs 			stcb = sctp_findassociation_ep_asocid(inp,
22378c2654abSrjs 							     sasoc->sasoc_assoc_id);
22388c2654abSrjs 			if (stcb == NULL) {
22398c2654abSrjs 				error = ENOENT;
22408c2654abSrjs 				break;
22418c2654abSrjs 			}
22428c2654abSrjs 		} else {
22438c2654abSrjs 			stcb = NULL;
22448c2654abSrjs 		}
22458c2654abSrjs 
22468c2654abSrjs 		if (stcb) {
22478c2654abSrjs 			sasoc->sasoc_asocmaxrxt = stcb->asoc.max_send_times;
22488c2654abSrjs 			sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets;
22498c2654abSrjs 			sasoc->sasoc_peer_rwnd = stcb->asoc.peers_rwnd;
22508c2654abSrjs 			sasoc->sasoc_local_rwnd = stcb->asoc.my_rwnd;
22518c2654abSrjs 			sasoc->sasoc_cookie_life = stcb->asoc.cookie_life;
22528c2654abSrjs 			SCTP_TCB_UNLOCK(stcb);
22538c2654abSrjs 		} else {
22548c2654abSrjs 			SCTP_INP_RLOCK(inp);
22558c2654abSrjs 			sasoc->sasoc_asocmaxrxt = inp->sctp_ep.max_send_times;
22568c2654abSrjs 			sasoc->sasoc_number_peer_destinations = 0;
22578c2654abSrjs 			sasoc->sasoc_peer_rwnd = 0;
22588c2654abSrjs 			sasoc->sasoc_local_rwnd = sbspace(&inp->sctp_socket->so_rcv);
22598c2654abSrjs 			sasoc->sasoc_cookie_life = inp->sctp_ep.def_cookie_life;
22608c2654abSrjs 			SCTP_INP_RUNLOCK(inp);
22618c2654abSrjs 		}
22628c2654abSrjs 		sopt->sopt_size = sizeof(*sasoc);
22638c2654abSrjs 	}
22648c2654abSrjs 	break;
22658c2654abSrjs 	case SCTP_DEFAULT_SEND_PARAM:
22668c2654abSrjs 	{
22678c2654abSrjs 		struct sctp_sndrcvinfo *s_info;
22688c2654abSrjs 
22698c2654abSrjs 		if (sopt->sopt_size != sizeof(struct sctp_sndrcvinfo)) {
22708c2654abSrjs 			error = EINVAL;
22718c2654abSrjs 			break;
22728c2654abSrjs 		}
22738c2654abSrjs 		s_info = sopt->sopt_data;
22748c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
22758c2654abSrjs 			SCTP_INP_RLOCK(inp);
22768c2654abSrjs 			stcb = LIST_FIRST(&inp->sctp_asoc_list);
22778c2654abSrjs 			if (stcb) {
22788c2654abSrjs 				SCTP_TCB_LOCK(stcb);
22798c2654abSrjs 			}
22808c2654abSrjs 			SCTP_INP_RUNLOCK(inp);
22818c2654abSrjs 		} else
22828c2654abSrjs 			stcb = sctp_findassociation_ep_asocid(inp, s_info->sinfo_assoc_id);
22838c2654abSrjs 
22848c2654abSrjs 		if (stcb == NULL) {
22858c2654abSrjs 			error = ENOENT;
22868c2654abSrjs 			break;
22878c2654abSrjs 		}
22888c2654abSrjs 		/* Copy it out */
22898c2654abSrjs 		*s_info = stcb->asoc.def_send;
22908c2654abSrjs 		SCTP_TCB_UNLOCK(stcb);
22918c2654abSrjs 		sopt->sopt_size = sizeof(*s_info);
2292786ba994Srjs 	}
2293786ba994Srjs 	break;
22948c2654abSrjs 	case SCTP_INITMSG:
22958c2654abSrjs 	{
22968c2654abSrjs 		struct sctp_initmsg *sinit;
22978c2654abSrjs #ifdef SCTP_DEBUG
22988c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_USRREQ1) {
22998c2654abSrjs 			printf("initmsg\n");
23008c2654abSrjs 		}
23018c2654abSrjs #endif /* SCTP_DEBUG */
23028c2654abSrjs 		if (sopt->sopt_size < sizeof(struct sctp_initmsg)) {
23038c2654abSrjs 			error = EINVAL;
23048c2654abSrjs 			break;
23058c2654abSrjs 		}
23068c2654abSrjs 		sinit = sopt->sopt_data;
23078c2654abSrjs 		SCTP_INP_RLOCK(inp);
23088c2654abSrjs 		sinit->sinit_num_ostreams = inp->sctp_ep.pre_open_stream_count;
23098c2654abSrjs 		sinit->sinit_max_instreams = inp->sctp_ep.max_open_streams_intome;
23108c2654abSrjs 		sinit->sinit_max_attempts = inp->sctp_ep.max_init_times;
23118c2654abSrjs 		sinit->sinit_max_init_timeo = inp->sctp_ep.initial_init_rto_max;
23128c2654abSrjs 		SCTP_INP_RUNLOCK(inp);
23138c2654abSrjs 		sopt->sopt_size = sizeof(*sinit);
23148c2654abSrjs 	}
23158c2654abSrjs 	break;
23168c2654abSrjs 	case SCTP_PRIMARY_ADDR:
23178c2654abSrjs 		/* we allow a "get" operation on this */
23188c2654abSrjs 	{
23198c2654abSrjs 		struct sctp_setprim *ssp;
23208c2654abSrjs 
23218c2654abSrjs #ifdef SCTP_DEBUG
23228c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_USRREQ1) {
23238c2654abSrjs 			printf("setprimary\n");
23248c2654abSrjs 		}
23258c2654abSrjs #endif /* SCTP_DEBUG */
23268c2654abSrjs 		if (sopt->sopt_size < sizeof(struct sctp_setprim)) {
23278c2654abSrjs 			error = EINVAL;
23288c2654abSrjs 			break;
23298c2654abSrjs 		}
23308c2654abSrjs 		ssp = sopt->sopt_data;
23318c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
23328c2654abSrjs 			SCTP_INP_RLOCK(inp);
23338c2654abSrjs 			stcb = LIST_FIRST(&inp->sctp_asoc_list);
23348c2654abSrjs 			if (stcb) {
23358c2654abSrjs 				SCTP_TCB_LOCK(stcb);
23368c2654abSrjs 			}
23378c2654abSrjs 			SCTP_INP_RUNLOCK(inp);
23388c2654abSrjs 		} else {
23398c2654abSrjs 			stcb = sctp_findassociation_ep_asocid(inp, ssp->ssp_assoc_id);
23408c2654abSrjs 			if (stcb == NULL) {
23418c2654abSrjs 				/* one last shot, try it by the address in */
23428c2654abSrjs 				struct sctp_nets *net;
23438c2654abSrjs 
23448c2654abSrjs 				SCTP_INP_WLOCK(inp);
23458c2654abSrjs 				SCTP_INP_INCR_REF(inp);
23468c2654abSrjs 				SCTP_INP_WUNLOCK(inp);
23478c2654abSrjs 				stcb = sctp_findassociation_ep_addr(&inp,
23488c2654abSrjs 							    (struct sockaddr *)&ssp->ssp_addr,
23498c2654abSrjs 							    &net, NULL, NULL);
23508c2654abSrjs 				if (stcb == NULL) {
23518c2654abSrjs 					SCTP_INP_WLOCK(inp);
23528c2654abSrjs 					SCTP_INP_DECR_REF(inp);
23538c2654abSrjs 					SCTP_INP_WUNLOCK(inp);
23548c2654abSrjs 				}
23558c2654abSrjs 			}
23568c2654abSrjs 			if (stcb == NULL) {
23578c2654abSrjs 				error = EINVAL;
23588c2654abSrjs 				break;
23598c2654abSrjs 			}
23608c2654abSrjs 		}
23618c2654abSrjs 		/* simply copy out the sockaddr_storage... */
23628c2654abSrjs 		memcpy(&ssp->ssp_addr,
23638c2654abSrjs 		       rtcache_getdst(&stcb->asoc.primary_destination->ro),
23648c2654abSrjs 		       (rtcache_getdst(&stcb->asoc.primary_destination->ro))->sa_len);
23658c2654abSrjs 		SCTP_TCB_UNLOCK(stcb);
23668c2654abSrjs 		sopt->sopt_size = sizeof(*ssp);
23678c2654abSrjs 	}
23688c2654abSrjs 	break;
23698c2654abSrjs 	default:
23708c2654abSrjs 		error = ENOPROTOOPT;
23718c2654abSrjs 		sopt->sopt_size = 0;
23728c2654abSrjs 		break;
23738c2654abSrjs 	} /* end switch (sopt->sopt_name) */
23748c2654abSrjs         return (error);
23758c2654abSrjs }
23768c2654abSrjs 
23778c2654abSrjs static int
23788c2654abSrjs sctp_optsset(struct socket *so, struct sockopt *sopt)
23798c2654abSrjs {
23808c2654abSrjs 	int error, *mopt, set_opt;
23818c2654abSrjs 	struct sctp_tcb *stcb = NULL;
23828c2654abSrjs         struct sctp_inpcb *inp;
23838c2654abSrjs 
23848c2654abSrjs 	if (sopt->sopt_data == NULL) {
23858c2654abSrjs #ifdef SCTP_DEBUG
23868c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_USRREQ1) {
23878c2654abSrjs 			printf("optsset:MP is NULL EINVAL\n");
23888c2654abSrjs 		}
23898c2654abSrjs #endif /* SCTP_DEBUG */
23908c2654abSrjs 		return (EINVAL);
23918c2654abSrjs 	}
23928c2654abSrjs 	inp = (struct sctp_inpcb *)so->so_pcb;
23938c2654abSrjs 	if (inp == 0)
23948c2654abSrjs 		return EINVAL;
23958c2654abSrjs 
23968c2654abSrjs 	error = 0;
23978c2654abSrjs 	switch (sopt->sopt_name) {
23988c2654abSrjs 	case SCTP_NODELAY:
23998c2654abSrjs 	case SCTP_AUTOCLOSE:
24008c2654abSrjs 	case SCTP_AUTO_ASCONF:
24018c2654abSrjs 	case SCTP_DISABLE_FRAGMENTS:
24028c2654abSrjs 	case SCTP_I_WANT_MAPPED_V4_ADDR:
24038c2654abSrjs 		/* copy in the option value */
24048c2654abSrjs 		if (sopt->sopt_size < sizeof(int)) {
24058c2654abSrjs 			error = EINVAL;
24068c2654abSrjs 			break;
24078c2654abSrjs 		}
24088c2654abSrjs 		mopt = sopt->sopt_data;
24098c2654abSrjs 		set_opt = 0;
24108c2654abSrjs 		if (error)
24118c2654abSrjs 			break;
24128c2654abSrjs 		switch (sopt->sopt_name) {
24138c2654abSrjs 		case SCTP_DISABLE_FRAGMENTS:
24148c2654abSrjs 			set_opt = SCTP_PCB_FLAGS_NO_FRAGMENT;
24158c2654abSrjs 			break;
24168c2654abSrjs 		case SCTP_AUTO_ASCONF:
24178c2654abSrjs 			set_opt = SCTP_PCB_FLAGS_AUTO_ASCONF;
24188c2654abSrjs 			break;
24198c2654abSrjs 
24208c2654abSrjs 		case SCTP_I_WANT_MAPPED_V4_ADDR:
24218c2654abSrjs 			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
24228c2654abSrjs 				set_opt = SCTP_PCB_FLAGS_NEEDS_MAPPED_V4;
24238c2654abSrjs 			} else {
24248c2654abSrjs 				return (EINVAL);
24258c2654abSrjs 			}
24268c2654abSrjs 			break;
24278c2654abSrjs 		case SCTP_NODELAY:
24288c2654abSrjs 			set_opt = SCTP_PCB_FLAGS_NODELAY;
24298c2654abSrjs 			break;
24308c2654abSrjs 		case SCTP_AUTOCLOSE:
24318c2654abSrjs 			set_opt = SCTP_PCB_FLAGS_AUTOCLOSE;
24328c2654abSrjs 			/*
24338c2654abSrjs 			 * The value is in ticks.
2434*76748ca4Srillig 			 * Note this does not affect old associations, only
24358c2654abSrjs 			 * new ones.
24368c2654abSrjs 			 */
24378c2654abSrjs 			inp->sctp_ep.auto_close_time = (*mopt * hz);
24388c2654abSrjs 			break;
24398c2654abSrjs 		}
24408c2654abSrjs 		SCTP_INP_WLOCK(inp);
24418c2654abSrjs 		if (*mopt != 0) {
24428c2654abSrjs 			inp->sctp_flags |= set_opt;
24438c2654abSrjs 		} else {
24448c2654abSrjs 			inp->sctp_flags &= ~set_opt;
24458c2654abSrjs 		}
24468c2654abSrjs 		SCTP_INP_WUNLOCK(inp);
24478c2654abSrjs 		break;
24488c2654abSrjs 	case SCTP_MY_PUBLIC_KEY:    /* set my public key */
24498c2654abSrjs 	case SCTP_SET_AUTH_CHUNKS:  /* set the authenticated chunks required */
24508c2654abSrjs 	case SCTP_SET_AUTH_SECRET:  /* set the actual secret for the endpoint */
24518c2654abSrjs 		/* not supported yet and until we refine the draft */
24528c2654abSrjs 		error = EOPNOTSUPP;
24538c2654abSrjs 		break;
24548c2654abSrjs 
24558c2654abSrjs 	case SCTP_CLR_STAT_LOG:
24568c2654abSrjs #ifdef SCTP_STAT_LOGGING
24578c2654abSrjs 		sctp_clr_stat_log();
24588c2654abSrjs #else
24598c2654abSrjs 		error = EOPNOTSUPP;
24608c2654abSrjs #endif
24618c2654abSrjs 		break;
24628c2654abSrjs 	case SCTP_DELAYED_ACK_TIME:
24638c2654abSrjs 	{
24648c2654abSrjs 		int32_t *tm;
24658c2654abSrjs 		if (sopt->sopt_size < sizeof(int32_t)) {
24668c2654abSrjs 			error = EINVAL;
24678c2654abSrjs 			break;
24688c2654abSrjs 		}
24698c2654abSrjs 		tm = sopt->sopt_data;
24708c2654abSrjs 
24718c2654abSrjs 		if ((*tm < 10) || (*tm > 500)) {
24728c2654abSrjs 			/* can't be smaller than 10ms */
24738c2654abSrjs 			/* MUST NOT be larger than 500ms */
24748c2654abSrjs 			error = EINVAL;
24758c2654abSrjs 			break;
24768c2654abSrjs 		}
24778c2654abSrjs 		inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(*tm);
24788c2654abSrjs 	}
24798c2654abSrjs 		break;
24808c2654abSrjs 	case SCTP_RESET_STREAMS:
24818c2654abSrjs 	{
24828c2654abSrjs 		struct sctp_stream_reset *strrst;
24838c2654abSrjs 		uint8_t two_way, not_peer;
24848c2654abSrjs 
24858c2654abSrjs 		if (sopt->sopt_size < sizeof(struct sctp_stream_reset)) {
24868c2654abSrjs 			error = EINVAL;
24878c2654abSrjs 			break;
24888c2654abSrjs 		}
24898c2654abSrjs 		strrst = sopt->sopt_data;
24908c2654abSrjs 
24918c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
24928c2654abSrjs 			SCTP_INP_RLOCK(inp);
24938c2654abSrjs 			stcb = LIST_FIRST(&inp->sctp_asoc_list);
24948c2654abSrjs 			if (stcb) {
24958c2654abSrjs 				SCTP_TCB_LOCK(stcb);
24968c2654abSrjs 			}
24978c2654abSrjs 			SCTP_INP_RUNLOCK(inp);
24988c2654abSrjs 		} else
24998c2654abSrjs 			stcb = sctp_findassociation_ep_asocid(inp, strrst->strrst_assoc_id);
25008c2654abSrjs 		if (stcb == NULL) {
25018c2654abSrjs 			error = ENOENT;
25028c2654abSrjs 			break;
25038c2654abSrjs 		}
25048c2654abSrjs 		if (stcb->asoc.peer_supports_strreset == 0) {
25058c2654abSrjs 			/* Peer does not support it,
25068c2654abSrjs 			 * we return protocol not supported since
25078c2654abSrjs 			 * this is true for this feature and this
25088c2654abSrjs 			 * peer, not the socket request in general.
25098c2654abSrjs 			 */
25108c2654abSrjs 			error = EPROTONOSUPPORT;
25118c2654abSrjs 			SCTP_TCB_UNLOCK(stcb);
25128c2654abSrjs 			break;
25138c2654abSrjs 		}
25148c2654abSrjs 
25158c2654abSrjs /* Having re-thought this code I added as I write the I-D there
25168c2654abSrjs  * is NO need for it. The peer, if we are requesting a stream-reset
25178c2654abSrjs  * will send a request to us but will itself do what we do, take
25188c2654abSrjs  * and copy off the "reset information" we send and queue TSN's
25198c2654abSrjs  * larger than the send-next in our response message. Thus they
25208c2654abSrjs  * will handle it.
25218c2654abSrjs  */
25228c2654abSrjs /*		if (stcb->asoc.sending_seq != (stcb->asoc.last_acked_seq + 1)) {*/
25238c2654abSrjs 		/* Must have all sending data ack'd before we
25248c2654abSrjs 		 * start this procedure. This is a bit restrictive
25258c2654abSrjs 		 * and we SHOULD work on changing this so ONLY the
25268c2654abSrjs 		 * streams being RESET get held up. So, a reset-all
25278c2654abSrjs 		 * would require this.. but a reset specific just
25288c2654abSrjs 		 * needs to be sure that the ones being reset have
25298c2654abSrjs 		 * nothing on the send_queue. For now we will
25308c2654abSrjs 		 * skip this more detailed method and do a course
25318c2654abSrjs 		 * way.. i.e. nothing pending ... for future FIX ME!
25328c2654abSrjs 		 */
25338c2654abSrjs /*			error = EBUSY;*/
25348c2654abSrjs /*			break;*/
25358c2654abSrjs /*		}*/
25368c2654abSrjs 
25378c2654abSrjs 		if (stcb->asoc.stream_reset_outstanding) {
25388c2654abSrjs 			error = EALREADY;
25398c2654abSrjs 			SCTP_TCB_UNLOCK(stcb);
25408c2654abSrjs 			break;
25418c2654abSrjs 		}
25428c2654abSrjs 		if (strrst->strrst_flags == SCTP_RESET_LOCAL_RECV) {
25438c2654abSrjs 			two_way = 0;
25448c2654abSrjs 			not_peer = 0;
25458c2654abSrjs 		} else if (strrst->strrst_flags == SCTP_RESET_LOCAL_SEND) {
25468c2654abSrjs 			two_way = 1;
25478c2654abSrjs 			not_peer = 1;
25488c2654abSrjs 		} else if (strrst->strrst_flags == SCTP_RESET_BOTH) {
25498c2654abSrjs 			two_way = 1;
25508c2654abSrjs 			not_peer = 0;
25518c2654abSrjs 		} else {
25528c2654abSrjs 			error = EINVAL;
25538c2654abSrjs 			SCTP_TCB_UNLOCK(stcb);
25548c2654abSrjs 			break;
25558c2654abSrjs 		}
25568c2654abSrjs 		sctp_send_str_reset_req(stcb, strrst->strrst_num_streams,
25578c2654abSrjs 					strrst->strrst_list, two_way, not_peer);
25588c2654abSrjs 		sctp_chunk_output(inp, stcb, 12);
25598c2654abSrjs 		SCTP_TCB_UNLOCK(stcb);
25608c2654abSrjs 
25618c2654abSrjs 	}
25628c2654abSrjs 	break;
25638c2654abSrjs 	case SCTP_RESET_PEGS:
25648c2654abSrjs 		memset(sctp_pegs, 0, sizeof(sctp_pegs));
25658c2654abSrjs 		error = 0;
25668c2654abSrjs 		break;
25678c2654abSrjs 	case SCTP_CONNECT_X_COMPLETE:
25688c2654abSrjs 	{
25698c2654abSrjs 		struct sockaddr *sa;
25708c2654abSrjs 		struct sctp_nets *net;
25718c2654abSrjs 		if (sopt->sopt_size < sizeof(struct sockaddr_in)) {
25728c2654abSrjs 			error = EINVAL;
25738c2654abSrjs 			break;
25748c2654abSrjs 		}
25758c2654abSrjs 		sa = sopt->sopt_data;
25768c2654abSrjs 		/* find tcb */
25778c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
25788c2654abSrjs 			SCTP_INP_RLOCK(inp);
25798c2654abSrjs 			stcb = LIST_FIRST(&inp->sctp_asoc_list);
25808c2654abSrjs 			if (stcb) {
25818c2654abSrjs 				SCTP_TCB_LOCK(stcb);
25828c2654abSrjs 				net = sctp_findnet(stcb, sa);
25838c2654abSrjs 			}
25848c2654abSrjs 			SCTP_INP_RUNLOCK(inp);
25858c2654abSrjs 		} else {
25868c2654abSrjs 			SCTP_INP_WLOCK(inp);
25878c2654abSrjs 			SCTP_INP_INCR_REF(inp);
25888c2654abSrjs 			SCTP_INP_WUNLOCK(inp);
25898c2654abSrjs 			stcb = sctp_findassociation_ep_addr(&inp, sa, &net, NULL, NULL);
25908c2654abSrjs 			if (stcb == NULL) {
25918c2654abSrjs 				SCTP_INP_WLOCK(inp);
25928c2654abSrjs 				SCTP_INP_DECR_REF(inp);
25938c2654abSrjs 				SCTP_INP_WUNLOCK(inp);
25948c2654abSrjs 			}
25958c2654abSrjs 		}
25968c2654abSrjs 
25978c2654abSrjs 		if (stcb == NULL) {
25988c2654abSrjs 			error = ENOENT;
25998c2654abSrjs 			break;
26008c2654abSrjs 		}
26018c2654abSrjs 		if (stcb->asoc.delayed_connection == 1) {
26028c2654abSrjs 			stcb->asoc.delayed_connection = 0;
26038c2654abSrjs 			SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
26048c2654abSrjs 			sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, stcb->asoc.primary_destination);
26058c2654abSrjs 			sctp_send_initiate(inp, stcb);
26068c2654abSrjs 		} else {
26078c2654abSrjs 			/* already expired or did not use delayed connectx */
26088c2654abSrjs 			error = EALREADY;
26098c2654abSrjs 		}
26108c2654abSrjs 		SCTP_TCB_UNLOCK(stcb);
26118c2654abSrjs 	}
26128c2654abSrjs 	break;
26138c2654abSrjs 	case SCTP_MAXBURST:
26148c2654abSrjs 	{
26158c2654abSrjs 		u_int8_t *burst;
26168c2654abSrjs 		SCTP_INP_WLOCK(inp);
26178c2654abSrjs 		burst = sopt->sopt_data;
26188c2654abSrjs 		if (*burst) {
26198c2654abSrjs 			inp->sctp_ep.max_burst = *burst;
26208c2654abSrjs 		}
26218c2654abSrjs 		SCTP_INP_WUNLOCK(inp);
26228c2654abSrjs 	}
26238c2654abSrjs 	break;
26248c2654abSrjs 	case SCTP_MAXSEG:
26258c2654abSrjs 	{
26268c2654abSrjs 		u_int32_t *segsize;
26278c2654abSrjs 		int ovh;
26288c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
26298c2654abSrjs 			ovh = SCTP_MED_OVERHEAD;
26308c2654abSrjs 		} else {
26318c2654abSrjs 			ovh = SCTP_MED_V4_OVERHEAD;
26328c2654abSrjs 		}
26338c2654abSrjs 		segsize = sopt->sopt_data;
26348c2654abSrjs 		if (*segsize < 1) {
26358c2654abSrjs 			error = EINVAL;
26368c2654abSrjs 			break;
26378c2654abSrjs 		}
26388c2654abSrjs 		SCTP_INP_WLOCK(inp);
26398c2654abSrjs 		inp->sctp_frag_point = (*segsize+ovh);
26408c2654abSrjs 		if (inp->sctp_frag_point < MHLEN) {
26418c2654abSrjs 			inp->sctp_frag_point = MHLEN;
26428c2654abSrjs 		}
26438c2654abSrjs 		SCTP_INP_WUNLOCK(inp);
26448c2654abSrjs 	}
26458c2654abSrjs 	break;
26468c2654abSrjs 	case SCTP_SET_DEBUG_LEVEL:
26478c2654abSrjs #ifdef SCTP_DEBUG
26488c2654abSrjs 	{
26498c2654abSrjs 		u_int32_t *level;
26508c2654abSrjs 		if (sopt->sopt_size < sizeof(u_int32_t)) {
26518c2654abSrjs 			error = EINVAL;
26528c2654abSrjs 			break;
26538c2654abSrjs 		}
26548c2654abSrjs 		level = sopt->sopt_data;
26558c2654abSrjs 		error = 0;
26568c2654abSrjs 		sctp_debug_on = (*level & (SCTP_DEBUG_ALL |
26578c2654abSrjs 					   SCTP_DEBUG_NOISY));
26588c2654abSrjs 		printf("SETTING DEBUG LEVEL to %x\n",
26598c2654abSrjs 		       (u_int)sctp_debug_on);
26608c2654abSrjs 
26618c2654abSrjs 	}
26628c2654abSrjs #else
26638c2654abSrjs 	error = EOPNOTSUPP;
26648c2654abSrjs #endif /* SCTP_DEBUG */
26658c2654abSrjs 	break;
26668c2654abSrjs 	case SCTP_EVENTS:
26678c2654abSrjs 	{
26688c2654abSrjs 		struct sctp_event_subscribe *events;
26698c2654abSrjs 		if (sopt->sopt_size < sizeof(struct sctp_event_subscribe)) {
26708c2654abSrjs 			error = EINVAL;
26718c2654abSrjs 			break;
26728c2654abSrjs 		}
26738c2654abSrjs 		SCTP_INP_WLOCK(inp);
26748c2654abSrjs 		events = sopt->sopt_data;
26758c2654abSrjs 		if (events->sctp_data_io_event) {
26768c2654abSrjs 			inp->sctp_flags |= SCTP_PCB_FLAGS_RECVDATAIOEVNT;
26778c2654abSrjs 		} else {
26788c2654abSrjs 			inp->sctp_flags &= ~SCTP_PCB_FLAGS_RECVDATAIOEVNT;
26798c2654abSrjs 		}
26808c2654abSrjs 
26818c2654abSrjs 		if (events->sctp_association_event) {
26828c2654abSrjs 			inp->sctp_flags |= SCTP_PCB_FLAGS_RECVASSOCEVNT;
26838c2654abSrjs 		} else {
26848c2654abSrjs 			inp->sctp_flags &= ~SCTP_PCB_FLAGS_RECVASSOCEVNT;
26858c2654abSrjs 		}
26868c2654abSrjs 
26878c2654abSrjs 		if (events->sctp_address_event) {
26888c2654abSrjs 			inp->sctp_flags |= SCTP_PCB_FLAGS_RECVPADDREVNT;
26898c2654abSrjs 		} else {
26908c2654abSrjs 			inp->sctp_flags &= ~SCTP_PCB_FLAGS_RECVPADDREVNT;
26918c2654abSrjs 		}
26928c2654abSrjs 
26938c2654abSrjs 		if (events->sctp_send_failure_event) {
26948c2654abSrjs 			inp->sctp_flags |= SCTP_PCB_FLAGS_RECVSENDFAILEVNT;
26958c2654abSrjs 		} else {
26968c2654abSrjs 			inp->sctp_flags &= ~SCTP_PCB_FLAGS_RECVSENDFAILEVNT;
26978c2654abSrjs 		}
26988c2654abSrjs 
26998c2654abSrjs 		if (events->sctp_peer_error_event) {
27008c2654abSrjs 			inp->sctp_flags |= SCTP_PCB_FLAGS_RECVPEERERR;
27018c2654abSrjs 		} else {
27028c2654abSrjs 			inp->sctp_flags &= ~SCTP_PCB_FLAGS_RECVPEERERR;
27038c2654abSrjs 		}
27048c2654abSrjs 
27058c2654abSrjs 		if (events->sctp_shutdown_event) {
27068c2654abSrjs 			inp->sctp_flags |= SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT;
27078c2654abSrjs 		} else {
27088c2654abSrjs 			inp->sctp_flags &= ~SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT;
27098c2654abSrjs 		}
27108c2654abSrjs 
27118c2654abSrjs 		if (events->sctp_partial_delivery_event) {
27128c2654abSrjs 			inp->sctp_flags |= SCTP_PCB_FLAGS_PDAPIEVNT;
27138c2654abSrjs 		} else {
27148c2654abSrjs 			inp->sctp_flags &= ~SCTP_PCB_FLAGS_PDAPIEVNT;
27158c2654abSrjs 		}
27168c2654abSrjs 
27178c2654abSrjs 		if (events->sctp_adaption_layer_event) {
27188c2654abSrjs 			inp->sctp_flags |= SCTP_PCB_FLAGS_ADAPTIONEVNT;
27198c2654abSrjs 		} else {
27208c2654abSrjs 			inp->sctp_flags &= ~SCTP_PCB_FLAGS_ADAPTIONEVNT;
27218c2654abSrjs 		}
27228c2654abSrjs 
27238c2654abSrjs 		if (events->sctp_stream_reset_events) {
27248c2654abSrjs 			inp->sctp_flags |= SCTP_PCB_FLAGS_STREAM_RESETEVNT;
27258c2654abSrjs 		} else {
27268c2654abSrjs 			inp->sctp_flags &= ~SCTP_PCB_FLAGS_STREAM_RESETEVNT;
27278c2654abSrjs 		}
27288c2654abSrjs 		SCTP_INP_WUNLOCK(inp);
27298c2654abSrjs 	}
27308c2654abSrjs 	break;
27318c2654abSrjs 
27328c2654abSrjs 	case SCTP_ADAPTION_LAYER:
27338c2654abSrjs 	{
27348c2654abSrjs 		struct sctp_setadaption *adap_bits;
27358c2654abSrjs 		if (sopt->sopt_size < sizeof(struct sctp_setadaption)) {
27368c2654abSrjs 			error = EINVAL;
27378c2654abSrjs 			break;
27388c2654abSrjs 		}
27398c2654abSrjs 		SCTP_INP_WLOCK(inp);
27408c2654abSrjs 		adap_bits = sopt->sopt_data;
27418c2654abSrjs 		inp->sctp_ep.adaption_layer_indicator = adap_bits->ssb_adaption_ind;
27428c2654abSrjs 		SCTP_INP_WUNLOCK(inp);
27438c2654abSrjs 	}
27448c2654abSrjs 	break;
27458c2654abSrjs 	case SCTP_SET_INITIAL_DBG_SEQ:
27468c2654abSrjs 	{
27478c2654abSrjs 		u_int32_t *vvv;
27488c2654abSrjs 		if (sopt->sopt_size < sizeof(u_int32_t)) {
27498c2654abSrjs 			error = EINVAL;
27508c2654abSrjs 			break;
27518c2654abSrjs 		}
27528c2654abSrjs 		SCTP_INP_WLOCK(inp);
27538c2654abSrjs 		vvv = sopt->sopt_data;
27548c2654abSrjs 		inp->sctp_ep.initial_sequence_debug = *vvv;
27558c2654abSrjs 		SCTP_INP_WUNLOCK(inp);
27568c2654abSrjs 	}
27578c2654abSrjs 	break;
27588c2654abSrjs 	case SCTP_DEFAULT_SEND_PARAM:
27598c2654abSrjs 	{
27608c2654abSrjs 		struct sctp_sndrcvinfo *s_info;
27618c2654abSrjs 
27628c2654abSrjs 		if (sopt->sopt_size != sizeof(struct sctp_sndrcvinfo)) {
27638c2654abSrjs 			error = EINVAL;
27648c2654abSrjs 			break;
27658c2654abSrjs 		}
27668c2654abSrjs 		s_info = sopt->sopt_data;
27678c2654abSrjs 
27688c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
27698c2654abSrjs 			SCTP_INP_RLOCK(inp);
27708c2654abSrjs 			stcb = LIST_FIRST(&inp->sctp_asoc_list);
27718c2654abSrjs 			if (stcb) {
27728c2654abSrjs 				SCTP_TCB_LOCK(stcb);
27738c2654abSrjs 			}
27748c2654abSrjs 			SCTP_INP_RUNLOCK(inp);
27758c2654abSrjs 		} else
27768c2654abSrjs 			stcb = sctp_findassociation_ep_asocid(inp, s_info->sinfo_assoc_id);
27778c2654abSrjs 
27788c2654abSrjs 		if (stcb == NULL) {
27798c2654abSrjs 			error = ENOENT;
27808c2654abSrjs 			break;
27818c2654abSrjs 		}
27828c2654abSrjs 		/* Validate things */
27838c2654abSrjs 		if (s_info->sinfo_stream > stcb->asoc.streamoutcnt) {
27848c2654abSrjs 			SCTP_TCB_UNLOCK(stcb);
27858c2654abSrjs 			error = EINVAL;
27868c2654abSrjs 			break;
27878c2654abSrjs 		}
27888c2654abSrjs 		/* Mask off the flags that are allowed */
27898c2654abSrjs 		s_info->sinfo_flags = (s_info->sinfo_flags &
279020ba2d4fSrjs 				       (SCTP_UNORDERED | SCTP_ADDR_OVER |
279120ba2d4fSrjs 					SCTP_PR_SCTP_TTL | SCTP_PR_SCTP_BUF));
27928c2654abSrjs 		/* Copy it in */
27938c2654abSrjs 		stcb->asoc.def_send = *s_info;
27948c2654abSrjs 		SCTP_TCB_UNLOCK(stcb);
27958c2654abSrjs 	}
27968c2654abSrjs 	break;
27978c2654abSrjs 	case SCTP_PEER_ADDR_PARAMS:
27988c2654abSrjs 	{
27998c2654abSrjs 		struct sctp_paddrparams *paddrp;
28008c2654abSrjs 		struct sctp_nets *net;
28018c2654abSrjs 		if (sopt->sopt_size < sizeof(struct sctp_paddrparams)) {
28028c2654abSrjs 			error = EINVAL;
28038c2654abSrjs 			break;
28048c2654abSrjs 		}
28058c2654abSrjs 		paddrp = sopt->sopt_data;
28068c2654abSrjs 		net = NULL;
28078c2654abSrjs 		if (paddrp->spp_assoc_id) {
28088c2654abSrjs 			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
28098c2654abSrjs 				SCTP_INP_RLOCK(inp);
28108c2654abSrjs 				stcb = LIST_FIRST(&inp->sctp_asoc_list);
28118c2654abSrjs 				if (stcb) {
28128c2654abSrjs 					SCTP_TCB_LOCK(stcb);
28138c2654abSrjs 					net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address);
28148c2654abSrjs 				}
28158c2654abSrjs 				SCTP_INP_RUNLOCK(inp);
28168c2654abSrjs 			} else
28178c2654abSrjs 				stcb = sctp_findassociation_ep_asocid(inp, paddrp->spp_assoc_id);
28188c2654abSrjs 			if (stcb == NULL) {
28198c2654abSrjs 				error = ENOENT;
28208c2654abSrjs 				break;
28218c2654abSrjs 			}
28228c2654abSrjs 
28238c2654abSrjs 		}
28248c2654abSrjs 		if ((stcb == NULL) &&
28258c2654abSrjs 		    ((((struct sockaddr *)&paddrp->spp_address)->sa_family == AF_INET) ||
28268c2654abSrjs 		     (((struct sockaddr *)&paddrp->spp_address)->sa_family == AF_INET6))) {
28278c2654abSrjs 			/* Lookup via address */
28288c2654abSrjs 			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
28298c2654abSrjs 				SCTP_INP_RLOCK(inp);
28308c2654abSrjs 				stcb = LIST_FIRST(&inp->sctp_asoc_list);
28318c2654abSrjs 				if (stcb) {
28328c2654abSrjs 					SCTP_TCB_LOCK(stcb);
28338c2654abSrjs 					net = sctp_findnet(stcb,
28348c2654abSrjs 							   (struct sockaddr *)&paddrp->spp_address);
28358c2654abSrjs 				}
28368c2654abSrjs 				SCTP_INP_RUNLOCK(inp);
28378c2654abSrjs 			} else {
28388c2654abSrjs 				SCTP_INP_WLOCK(inp);
28398c2654abSrjs 				SCTP_INP_INCR_REF(inp);
28408c2654abSrjs 				SCTP_INP_WUNLOCK(inp);
28418c2654abSrjs 				stcb = sctp_findassociation_ep_addr(&inp,
28428c2654abSrjs 								    (struct sockaddr *)&paddrp->spp_address,
28438c2654abSrjs 								    &net, NULL, NULL);
28448c2654abSrjs 				if (stcb == NULL) {
28458c2654abSrjs 					SCTP_INP_WLOCK(inp);
28468c2654abSrjs 					SCTP_INP_DECR_REF(inp);
28478c2654abSrjs 					SCTP_INP_WUNLOCK(inp);
28488c2654abSrjs 				}
28498c2654abSrjs 			}
28508c2654abSrjs 		} else {
28518c2654abSrjs 			/* Effects the Endpoint */
28528c2654abSrjs 			stcb = NULL;
28538c2654abSrjs 		}
28548c2654abSrjs 		if (stcb) {
28558c2654abSrjs 			/* Applies to the specific association */
28568c2654abSrjs 			if (paddrp->spp_pathmaxrxt) {
28578c2654abSrjs 				if (net) {
28588c2654abSrjs 					if (paddrp->spp_pathmaxrxt)
28598c2654abSrjs 						net->failure_threshold = paddrp->spp_pathmaxrxt;
28608c2654abSrjs 				} else {
28618c2654abSrjs 					if (paddrp->spp_pathmaxrxt)
28628c2654abSrjs 						stcb->asoc.def_net_failure = paddrp->spp_pathmaxrxt;
28638c2654abSrjs 				}
28648c2654abSrjs 			}
28658c2654abSrjs 			if ((paddrp->spp_hbinterval != 0) && (paddrp->spp_hbinterval != 0xffffffff)) {
28668c2654abSrjs 				/* Just a set */
28678c2654abSrjs 				int old;
28688c2654abSrjs 				if (net) {
28698c2654abSrjs 					net->dest_state &= ~SCTP_ADDR_NOHB;
28708c2654abSrjs 				} else {
28718c2654abSrjs 					old = stcb->asoc.heart_beat_delay;
28728c2654abSrjs 					stcb->asoc.heart_beat_delay = paddrp->spp_hbinterval;
28738c2654abSrjs 					if (old == 0) {
28748c2654abSrjs 						/* Turn back on the timer */
28758c2654abSrjs 						sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
28768c2654abSrjs 					}
28778c2654abSrjs 				}
28788c2654abSrjs 			} else if (paddrp->spp_hbinterval == 0xffffffff) {
28798c2654abSrjs 				/* on demand HB */
28808c2654abSrjs 				sctp_send_hb(stcb, 1, net);
28818c2654abSrjs 			} else {
28828c2654abSrjs 				if (net == NULL) {
28838c2654abSrjs 					/* off on association */
28848c2654abSrjs 					if (stcb->asoc.heart_beat_delay) {
28858c2654abSrjs 						int cnt_of_unconf = 0;
28868c2654abSrjs 						struct sctp_nets *lnet;
28878c2654abSrjs 						TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
28888c2654abSrjs 							if (lnet->dest_state & SCTP_ADDR_UNCONFIRMED) {
28898c2654abSrjs 								cnt_of_unconf++;
28908c2654abSrjs 							}
28918c2654abSrjs 						}
28928c2654abSrjs 						/* stop the timer ONLY if we have no unconfirmed addresses
28938c2654abSrjs 						 */
28948c2654abSrjs 						if (cnt_of_unconf == 0)
28958c2654abSrjs 							sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
28968c2654abSrjs 					}
28978c2654abSrjs 					stcb->asoc.heart_beat_delay = 0;
28988c2654abSrjs 				} else {
28998c2654abSrjs 					net->dest_state |= SCTP_ADDR_NOHB;
29008c2654abSrjs 				}
29018c2654abSrjs 			}
29028c2654abSrjs 			SCTP_TCB_UNLOCK(stcb);
29038c2654abSrjs 		} else {
29048c2654abSrjs 			/* Use endpoint defaults */
29058c2654abSrjs 			SCTP_INP_WLOCK(inp);
29068c2654abSrjs 			if (paddrp->spp_pathmaxrxt)
29078c2654abSrjs 				inp->sctp_ep.def_net_failure = paddrp->spp_pathmaxrxt;
29088c2654abSrjs 			if (paddrp->spp_hbinterval != SCTP_ISSUE_HB)
29098c2654abSrjs 				inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = paddrp->spp_hbinterval;
29108c2654abSrjs 			SCTP_INP_WUNLOCK(inp);
29118c2654abSrjs 		}
29128c2654abSrjs 	}
29138c2654abSrjs 	break;
29148c2654abSrjs 	case SCTP_RTOINFO:
29158c2654abSrjs 	{
29168c2654abSrjs 		struct sctp_rtoinfo *srto;
29178c2654abSrjs 		if (sopt->sopt_size < sizeof(struct sctp_rtoinfo)) {
29188c2654abSrjs 			error = EINVAL;
29198c2654abSrjs 			break;
29208c2654abSrjs 		}
29218c2654abSrjs 		srto = sopt->sopt_data;
29228c2654abSrjs 		if (srto->srto_assoc_id == 0) {
29238c2654abSrjs 			SCTP_INP_WLOCK(inp);
29248c2654abSrjs 			/* If we have a null asoc, its default for the endpoint */
29258c2654abSrjs 			if (srto->srto_initial > 10)
29268c2654abSrjs 				inp->sctp_ep.initial_rto = srto->srto_initial;
29278c2654abSrjs 			if (srto->srto_max > 10)
29288c2654abSrjs 				inp->sctp_ep.sctp_maxrto = srto->srto_max;
29298c2654abSrjs 			if (srto->srto_min > 10)
29308c2654abSrjs 				inp->sctp_ep.sctp_minrto = srto->srto_min;
29318c2654abSrjs 			SCTP_INP_WUNLOCK(inp);
29328c2654abSrjs 			break;
29338c2654abSrjs 		}
29348c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
29358c2654abSrjs 			SCTP_INP_RLOCK(inp);
29368c2654abSrjs 			stcb = LIST_FIRST(&inp->sctp_asoc_list);
29378c2654abSrjs 			if (stcb) {
29388c2654abSrjs 				SCTP_TCB_LOCK(stcb);
29398c2654abSrjs 			}
29408c2654abSrjs 			SCTP_INP_RUNLOCK(inp);
29418c2654abSrjs 		} else
29428c2654abSrjs 			stcb = sctp_findassociation_ep_asocid(inp, srto->srto_assoc_id);
29438c2654abSrjs 		if (stcb == NULL) {
29448c2654abSrjs 			error = EINVAL;
29458c2654abSrjs 			break;
29468c2654abSrjs 		}
29478c2654abSrjs 		/* Set in ms we hope :-) */
29488c2654abSrjs 		if (srto->srto_initial > 10)
29498c2654abSrjs 			stcb->asoc.initial_rto = srto->srto_initial;
29508c2654abSrjs 		if (srto->srto_max > 10)
29518c2654abSrjs 			stcb->asoc.maxrto = srto->srto_max;
29528c2654abSrjs 		if (srto->srto_min > 10)
29538c2654abSrjs 			stcb->asoc.minrto = srto->srto_min;
29548c2654abSrjs 		SCTP_TCB_UNLOCK(stcb);
29558c2654abSrjs 	}
29568c2654abSrjs 	break;
29578c2654abSrjs 	case SCTP_ASSOCINFO:
29588c2654abSrjs 	{
29598c2654abSrjs 		struct sctp_assocparams *sasoc;
29608c2654abSrjs 
29618c2654abSrjs 		if (sopt->sopt_size < sizeof(struct sctp_assocparams)) {
29628c2654abSrjs 			error = EINVAL;
29638c2654abSrjs 			break;
29648c2654abSrjs 		}
29658c2654abSrjs 		sasoc = sopt->sopt_data;
29668c2654abSrjs 		if (sasoc->sasoc_assoc_id) {
29678c2654abSrjs 			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
29688c2654abSrjs 				SCTP_INP_RLOCK(inp);
29698c2654abSrjs 				stcb = LIST_FIRST(&inp->sctp_asoc_list);
29708c2654abSrjs 				if (stcb) {
29718c2654abSrjs 					SCTP_TCB_LOCK(stcb);
29728c2654abSrjs 				}
29738c2654abSrjs 				SCTP_INP_RUNLOCK(inp);
29748c2654abSrjs 			} else
29758c2654abSrjs 				stcb = sctp_findassociation_ep_asocid(inp,
29768c2654abSrjs 								      sasoc->sasoc_assoc_id);
29778c2654abSrjs 			if (stcb == NULL) {
29788c2654abSrjs 				error = ENOENT;
29798c2654abSrjs 				break;
29808c2654abSrjs 			}
29818c2654abSrjs 
29828c2654abSrjs 		} else {
29838c2654abSrjs 			stcb = NULL;
29848c2654abSrjs 		}
29858c2654abSrjs 		if (stcb) {
29868c2654abSrjs 			if (sasoc->sasoc_asocmaxrxt)
29878c2654abSrjs 				stcb->asoc.max_send_times = sasoc->sasoc_asocmaxrxt;
29888c2654abSrjs 			sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets;
29898c2654abSrjs 			sasoc->sasoc_peer_rwnd = 0;
29908c2654abSrjs 			sasoc->sasoc_local_rwnd = 0;
29918c2654abSrjs 			if (stcb->asoc.cookie_life)
29928c2654abSrjs 				stcb->asoc.cookie_life = sasoc->sasoc_cookie_life;
29938c2654abSrjs 			SCTP_TCB_UNLOCK(stcb);
29948c2654abSrjs 		} else {
29958c2654abSrjs 			SCTP_INP_WLOCK(inp);
29968c2654abSrjs                         if (sasoc->sasoc_asocmaxrxt)
29978c2654abSrjs 				inp->sctp_ep.max_send_times = sasoc->sasoc_asocmaxrxt;
29988c2654abSrjs 			sasoc->sasoc_number_peer_destinations = 0;
29998c2654abSrjs 			sasoc->sasoc_peer_rwnd = 0;
30008c2654abSrjs 			sasoc->sasoc_local_rwnd = 0;
30018c2654abSrjs 			if (sasoc->sasoc_cookie_life)
30028c2654abSrjs 				inp->sctp_ep.def_cookie_life = sasoc->sasoc_cookie_life;
30038c2654abSrjs 			SCTP_INP_WUNLOCK(inp);
30048c2654abSrjs 		}
30058c2654abSrjs 	}
30068c2654abSrjs 	break;
30078c2654abSrjs 	case SCTP_INITMSG:
30088c2654abSrjs 	{
30098c2654abSrjs                 struct sctp_initmsg *sinit;
30108c2654abSrjs 
30118c2654abSrjs 		if (sopt->sopt_size < sizeof(struct sctp_initmsg)) {
30128c2654abSrjs 			error = EINVAL;
30138c2654abSrjs 			break;
30148c2654abSrjs 		}
30158c2654abSrjs 		sinit = sopt->sopt_data;
30168c2654abSrjs 		SCTP_INP_WLOCK(inp);
30178c2654abSrjs 		if (sinit->sinit_num_ostreams)
30188c2654abSrjs 			inp->sctp_ep.pre_open_stream_count = sinit->sinit_num_ostreams;
30198c2654abSrjs 
30208c2654abSrjs 		if (sinit->sinit_max_instreams)
30218c2654abSrjs 			inp->sctp_ep.max_open_streams_intome = sinit->sinit_max_instreams;
30228c2654abSrjs 
30238c2654abSrjs 		if (sinit->sinit_max_attempts)
30248c2654abSrjs 			inp->sctp_ep.max_init_times = sinit->sinit_max_attempts;
30258c2654abSrjs 
30268c2654abSrjs 		if (sinit->sinit_max_init_timeo > 10)
30278c2654abSrjs 			/* We must be at least a 100ms (we set in ticks) */
30288c2654abSrjs 			inp->sctp_ep.initial_init_rto_max = sinit->sinit_max_init_timeo;
30298c2654abSrjs 		SCTP_INP_WUNLOCK(inp);
30308c2654abSrjs 	}
30318c2654abSrjs 	break;
30328c2654abSrjs 	case SCTP_PRIMARY_ADDR:
30338c2654abSrjs 	{
30348c2654abSrjs 		struct sctp_setprim *spa;
30358c2654abSrjs 		struct sctp_nets *net, *lnet;
30368c2654abSrjs 		if (sopt->sopt_size < sizeof(struct sctp_setprim)) {
30378c2654abSrjs 			error = EINVAL;
30388c2654abSrjs 			break;
30398c2654abSrjs 		}
30408c2654abSrjs 		spa = sopt->sopt_data;
30418c2654abSrjs 
30428c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
30438c2654abSrjs  			SCTP_INP_RLOCK(inp);
30448c2654abSrjs 			stcb = LIST_FIRST(&inp->sctp_asoc_list);
30458c2654abSrjs 			if (stcb) {
30468c2654abSrjs 				SCTP_TCB_LOCK(stcb);
30478c2654abSrjs 			} else {
30488c2654abSrjs 				error = EINVAL;
30498c2654abSrjs 				break;
30508c2654abSrjs 			}
30518c2654abSrjs  			SCTP_INP_RUNLOCK(inp);
30528c2654abSrjs 		} else
30538c2654abSrjs 			stcb = sctp_findassociation_ep_asocid(inp, spa->ssp_assoc_id);
30548c2654abSrjs 		if (stcb == NULL) {
30558c2654abSrjs 			/* One last shot */
30568c2654abSrjs 			SCTP_INP_WLOCK(inp);
30578c2654abSrjs 			SCTP_INP_INCR_REF(inp);
30588c2654abSrjs 			SCTP_INP_WUNLOCK(inp);
30598c2654abSrjs 			stcb = sctp_findassociation_ep_addr(&inp,
30608c2654abSrjs 							    (struct sockaddr *)&spa->ssp_addr,
30618c2654abSrjs 							    &net, NULL, NULL);
30628c2654abSrjs 			if (stcb == NULL) {
30638c2654abSrjs 				SCTP_INP_WLOCK(inp);
30648c2654abSrjs 				SCTP_INP_DECR_REF(inp);
30658c2654abSrjs 				SCTP_INP_WUNLOCK(inp);
30668c2654abSrjs 				error = EINVAL;
30678c2654abSrjs 				break;
30688c2654abSrjs 			}
30698c2654abSrjs 		} else {
30708c2654abSrjs 			/* find the net, associd or connected lookup type */
30718c2654abSrjs 			net = sctp_findnet(stcb, (struct sockaddr *)&spa->ssp_addr);
30728c2654abSrjs 			if (net == NULL) {
30738c2654abSrjs 				SCTP_TCB_UNLOCK(stcb);
30748c2654abSrjs 				error = EINVAL;
30758c2654abSrjs 				break;
30768c2654abSrjs 			}
30778c2654abSrjs                 }
30788c2654abSrjs                 if ((net != stcb->asoc.primary_destination) &&
30798c2654abSrjs   		    (!(net->dest_state & SCTP_ADDR_UNCONFIRMED))) {
30808c2654abSrjs 			/* Ok we need to set it */
30818c2654abSrjs 			lnet = stcb->asoc.primary_destination;
30828c2654abSrjs                         lnet->next_tsn_at_change = net->next_tsn_at_change = stcb->asoc.sending_seq;
30838c2654abSrjs 		        if (sctp_set_primary_addr(stcb,
30848c2654abSrjs 						  (struct sockaddr *)NULL,
30858c2654abSrjs 						  net) == 0) {
30868c2654abSrjs 			        if (net->dest_state & SCTP_ADDR_SWITCH_PRIMARY) {
30878c2654abSrjs    				        net->dest_state |= SCTP_ADDR_DOUBLE_SWITCH;
30888c2654abSrjs                                 }
30898c2654abSrjs                                 net->dest_state |= SCTP_ADDR_SWITCH_PRIMARY;
30908c2654abSrjs                         }
30918c2654abSrjs 		}
30928c2654abSrjs 		SCTP_TCB_UNLOCK(stcb);
30938c2654abSrjs         }
30948c2654abSrjs 	break;
30958c2654abSrjs 
30968c2654abSrjs 	case SCTP_SET_PEER_PRIMARY_ADDR:
30978c2654abSrjs 	{
30988c2654abSrjs 		struct sctp_setpeerprim *sspp;
30998c2654abSrjs 		if (sopt->sopt_size < sizeof(struct sctp_setpeerprim)) {
31008c2654abSrjs 			error = EINVAL;
31018c2654abSrjs 			break;
31028c2654abSrjs 		}
31038c2654abSrjs 		sspp = sopt->sopt_data;
31048c2654abSrjs 
31058c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
31068c2654abSrjs 			SCTP_INP_RLOCK(inp);
31078c2654abSrjs 			stcb = LIST_FIRST(&inp->sctp_asoc_list);
31088c2654abSrjs 			if (stcb) {
31098c2654abSrjs 				SCTP_TCB_UNLOCK(stcb);
31108c2654abSrjs 			}
31118c2654abSrjs 			SCTP_INP_RUNLOCK(inp);
31128c2654abSrjs 		} else
31138c2654abSrjs 			stcb = sctp_findassociation_ep_asocid(inp, sspp->sspp_assoc_id);
31148c2654abSrjs 		if (stcb == NULL) {
31158c2654abSrjs 			error = EINVAL;
31168c2654abSrjs 			break;
31178c2654abSrjs 		}
31188c2654abSrjs 		if (sctp_set_primary_ip_address_sa(stcb, (struct sockaddr *)&sspp->sspp_addr) != 0) {
31198c2654abSrjs 			error = EINVAL;
31208c2654abSrjs 		}
31218c2654abSrjs 		SCTP_TCB_UNLOCK(stcb);
31228c2654abSrjs 	}
31238c2654abSrjs 	break;
31248c2654abSrjs 	case SCTP_BINDX_ADD_ADDR:
31258c2654abSrjs 	{
31268c2654abSrjs 		struct sctp_getaddresses *addrs;
31278c2654abSrjs 		struct sockaddr *addr_touse;
31288c2654abSrjs 		struct sockaddr_in sin;
31298c2654abSrjs 		/* see if we're bound all already! */
31308c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
31318c2654abSrjs 			error = EINVAL;
31328c2654abSrjs 			break;
31338c2654abSrjs 		}
31348c2654abSrjs 		if (sopt->sopt_size < sizeof(struct sctp_getaddresses)) {
31358c2654abSrjs 			error = EINVAL;
31368c2654abSrjs 			break;
31378c2654abSrjs 		}
31388c2654abSrjs 		addrs = sopt->sopt_data;
31398c2654abSrjs 		addr_touse = addrs->addr;
31408c2654abSrjs 		if (addrs->addr->sa_family == AF_INET6) {
31418c2654abSrjs 			struct sockaddr_in6 *sin6;
31428c2654abSrjs 			sin6 = (struct sockaddr_in6 *)addr_touse;
31438c2654abSrjs 			if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
31448c2654abSrjs 				in6_sin6_2_sin(&sin, sin6);
31458c2654abSrjs 				addr_touse = (struct sockaddr *)&sin;
31468c2654abSrjs 			}
31478c2654abSrjs 		}
31488c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) {
31498c2654abSrjs 			error = sctp_inpcb_bind(so, addr_touse, curlwp);
31508c2654abSrjs 			break;
31518c2654abSrjs 		}
31528c2654abSrjs 		/* No locks required here since bind and mgmt_ep_sa all
31538c2654abSrjs 		 * do their own locking. If we do something for the FIX:
31548c2654abSrjs 		 * below we may need to lock in that case.
31558c2654abSrjs 		 */
31568c2654abSrjs 		if (addrs->sget_assoc_id == 0) {
31578c2654abSrjs 			/* add the address */
31588c2654abSrjs 			struct sctp_inpcb  *lep;
31598c2654abSrjs 			((struct sockaddr_in *)addr_touse)->sin_port = inp->sctp_lport;
31608c2654abSrjs 			lep = sctp_pcb_findep(addr_touse, 1, 0);
31618c2654abSrjs 			if (lep != NULL) {
31628c2654abSrjs 				/* We must decrement the refcount
31638c2654abSrjs 				 * since we have the ep already and
31648c2654abSrjs 				 * are binding. No remove going on
31658c2654abSrjs 				 * here.
31668c2654abSrjs 				 */
31678c2654abSrjs 				SCTP_INP_WLOCK(inp);
31688c2654abSrjs 				SCTP_INP_DECR_REF(inp);
31698c2654abSrjs 				SCTP_INP_WUNLOCK(inp);
31708c2654abSrjs 			}
31718c2654abSrjs 			if (lep == inp) {
31728c2654abSrjs 				/* already bound to it.. ok */
31738c2654abSrjs 				break;
31748c2654abSrjs 			} else if (lep == NULL) {
31758c2654abSrjs 				((struct sockaddr_in *)addr_touse)->sin_port = 0;
31768c2654abSrjs 				error = sctp_addr_mgmt_ep_sa(inp, addr_touse,
31778c2654abSrjs 							     SCTP_ADD_IP_ADDRESS);
31788c2654abSrjs 			} else {
31798c2654abSrjs 				error = EADDRNOTAVAIL;
31808c2654abSrjs 			}
31818c2654abSrjs 			if (error)
31828c2654abSrjs 				break;
31838c2654abSrjs 
31848c2654abSrjs 		} else {
31858c2654abSrjs 			/* FIX: decide whether we allow assoc based bindx */
31868c2654abSrjs 		}
31878c2654abSrjs 	}
31888c2654abSrjs 	break;
31898c2654abSrjs 	case SCTP_BINDX_REM_ADDR:
31908c2654abSrjs 	{
31918c2654abSrjs 		struct sctp_getaddresses *addrs;
31928c2654abSrjs 		struct sockaddr *addr_touse;
31938c2654abSrjs 		struct sockaddr_in sin;
31948c2654abSrjs 		/* see if we're bound all already! */
31958c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
31968c2654abSrjs 			error = EINVAL;
31978c2654abSrjs 			break;
31988c2654abSrjs 		}
31998c2654abSrjs 		if (sopt->sopt_size < sizeof(struct sctp_getaddresses)) {
32008c2654abSrjs 			error = EINVAL;
32018c2654abSrjs 			break;
32028c2654abSrjs 		}
32038c2654abSrjs 		addrs = sopt->sopt_data;
32048c2654abSrjs 		addr_touse = addrs->addr;
32058c2654abSrjs 		if (addrs->addr->sa_family == AF_INET6) {
32068c2654abSrjs 			struct sockaddr_in6 *sin6;
32078c2654abSrjs 			sin6 = (struct sockaddr_in6 *)addr_touse;
32088c2654abSrjs 			if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
32098c2654abSrjs 				in6_sin6_2_sin(&sin, sin6);
32108c2654abSrjs 				addr_touse = (struct sockaddr *)&sin;
32118c2654abSrjs 			}
32128c2654abSrjs 		}
32138c2654abSrjs                 /* No lock required mgmt_ep_sa does its own locking. If
32148c2654abSrjs 		 * the FIX: below is ever changed we may need to
32158c2654abSrjs 		 * lock before calling association level binding.
32168c2654abSrjs 		 */
32178c2654abSrjs 		if (addrs->sget_assoc_id == 0) {
32188c2654abSrjs 			/* delete the address */
32198c2654abSrjs 			sctp_addr_mgmt_ep_sa(inp, addr_touse,
32208c2654abSrjs 					     SCTP_DEL_IP_ADDRESS);
32218c2654abSrjs 		} else {
32228c2654abSrjs 			/* FIX: decide whether we allow assoc based bindx */
32238c2654abSrjs 		}
32248c2654abSrjs 	}
32258c2654abSrjs 	break;
32268c2654abSrjs 	default:
32278c2654abSrjs 		error = ENOPROTOOPT;
32288c2654abSrjs 		break;
32298c2654abSrjs 	} /* end switch (opt) */
32308c2654abSrjs 	return (error);
32318c2654abSrjs }
32328c2654abSrjs 
32338c2654abSrjs int
32348c2654abSrjs sctp_ctloutput(int op, struct socket *so, struct sockopt *sopt)
32358c2654abSrjs {
32368c2654abSrjs 	int s, error = 0;
32378c2654abSrjs 	struct inpcb *inp;
32388c2654abSrjs #ifdef INET6
32398c2654abSrjs 	struct in6pcb *in6p;
32408c2654abSrjs #endif
32418c2654abSrjs 	int family;	/* family of the socket */
32428c2654abSrjs 
32438c2654abSrjs 	family = so->so_proto->pr_domain->dom_family;
32448c2654abSrjs 
32458c2654abSrjs 	s = splsoftnet();
32468c2654abSrjs 	switch (family) {
32478c2654abSrjs 	case PF_INET:
32488c2654abSrjs 		inp = sotoinpcb(so);
32498c2654abSrjs #ifdef INET6
32508c2654abSrjs 		in6p = NULL;
32518c2654abSrjs #endif
32528c2654abSrjs 		break;
32538c2654abSrjs #ifdef INET6
32548c2654abSrjs 	case PF_INET6:
32558c2654abSrjs 		inp = NULL;
32568c2654abSrjs 		in6p = sotoin6pcb(so);
32578c2654abSrjs 		break;
32588c2654abSrjs #endif
32598c2654abSrjs 	default:
32608c2654abSrjs 		splx(s);
32618c2654abSrjs 		return EAFNOSUPPORT;
32628c2654abSrjs 	}
32638c2654abSrjs #ifndef INET6
32648c2654abSrjs 	if (inp == NULL)
32658c2654abSrjs #else
32668c2654abSrjs 	if (inp == NULL && in6p == NULL)
32678c2654abSrjs #endif
32688c2654abSrjs 	{
32698c2654abSrjs 		splx(s);
32708c2654abSrjs 		return (ECONNRESET);
32718c2654abSrjs 	}
32728c2654abSrjs 	if (sopt->sopt_level != IPPROTO_SCTP) {
32738c2654abSrjs 		switch (family) {
32748c2654abSrjs 		case PF_INET:
32758c2654abSrjs 			error = ip_ctloutput(op, so, sopt);
32768c2654abSrjs 			break;
32778c2654abSrjs #ifdef INET6
32788c2654abSrjs 		case PF_INET6:
32798c2654abSrjs 			error = ip6_ctloutput(op, so, sopt);
32808c2654abSrjs 			break;
32818c2654abSrjs #endif
32828c2654abSrjs 		}
32838c2654abSrjs 		splx(s);
32848c2654abSrjs 		return (error);
32858c2654abSrjs 	}
32868c2654abSrjs 	/* Ok if we reach here it is a SCTP option we hope */
32878c2654abSrjs 	if (op == PRCO_SETOPT) {
32888c2654abSrjs 		error = sctp_optsset(so, sopt);
32898c2654abSrjs 	} else if (op ==  PRCO_GETOPT) {
32908c2654abSrjs 		error = sctp_optsget(so, sopt);
32918c2654abSrjs 	} else {
32928c2654abSrjs 		error = EINVAL;
32938c2654abSrjs 	}
32948c2654abSrjs 	splx(s);
32958c2654abSrjs 	return (error);
32968c2654abSrjs }
32978c2654abSrjs 
32988c2654abSrjs static int
32998c2654abSrjs sctp_connect(struct socket *so, struct sockaddr *nam, struct lwp *l)
33008c2654abSrjs {
33018c2654abSrjs 	int error = 0;
33028c2654abSrjs 	struct sctp_inpcb *inp;
33038c2654abSrjs 	struct sctp_tcb *stcb;
33048c2654abSrjs 
33058c2654abSrjs 	KASSERT(solocked(so));
33068c2654abSrjs #ifdef SCTP_DEBUG
33078c2654abSrjs 	if (sctp_debug_on & SCTP_DEBUG_PCB1) {
33088c2654abSrjs 		printf("Connect called in SCTP to ");
33098c2654abSrjs 		sctp_print_address(nam);
33108c2654abSrjs 		printf("Port %d\n", ntohs(((struct sockaddr_in *)nam)->sin_port));
33118c2654abSrjs 	}
33128c2654abSrjs #endif /* SCTP_DEBUG */
33138c2654abSrjs 	inp = (struct sctp_inpcb *)so->so_pcb;
33148c2654abSrjs 	if (inp == 0) {
33158c2654abSrjs 		/* I made the same as TCP since we are not setup? */
33168c2654abSrjs 		return (ECONNRESET);
33178c2654abSrjs 	}
33188c2654abSrjs 	SCTP_ASOC_CREATE_LOCK(inp);
33198c2654abSrjs #ifdef SCTP_DEBUG
33208c2654abSrjs 	if (sctp_debug_on & SCTP_DEBUG_PCB1) {
33218c2654abSrjs 		printf("After ASOC lock\n");
33228c2654abSrjs 	}
33238c2654abSrjs #endif /* SCTP_DEBUG */
33248c2654abSrjs 	SCTP_INP_WLOCK(inp);
33258c2654abSrjs #ifdef SCTP_DEBUG
33268c2654abSrjs 	if (sctp_debug_on & SCTP_DEBUG_PCB1) {
33278c2654abSrjs 		printf("After INP_WLOCK lock\n");
33288c2654abSrjs 	}
33298c2654abSrjs #endif /* SCTP_DEBUG */
33308c2654abSrjs 	if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
33318c2654abSrjs 	    (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
33328c2654abSrjs 		/* Should I really unlock ? */
33338c2654abSrjs 		SCTP_INP_WUNLOCK(inp);
33348c2654abSrjs 		SCTP_ASOC_CREATE_UNLOCK(inp);
33358c2654abSrjs 		return (EFAULT);
33368c2654abSrjs 	}
33378c2654abSrjs #ifdef INET6
33388c2654abSrjs 	if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) &&
33398c2654abSrjs 	    (nam->sa_family == AF_INET6)) {
33408c2654abSrjs 		SCTP_INP_WUNLOCK(inp);
33418c2654abSrjs 		SCTP_ASOC_CREATE_UNLOCK(inp);
33428c2654abSrjs 		return (EINVAL);
33438c2654abSrjs 	}
33448c2654abSrjs #endif /* INET6 */
3345d26f60daSmaxv 
3346d26f60daSmaxv 	/*
3347d26f60daSmaxv 	 * XXX XXX XXX Check nam->sa_len?
3348d26f60daSmaxv 	 */
3349d26f60daSmaxv 
33508c2654abSrjs 	if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
33518c2654abSrjs 	    SCTP_PCB_FLAGS_UNBOUND) {
33528c2654abSrjs 		/* Bind a ephemeral port */
33538c2654abSrjs 		SCTP_INP_WUNLOCK(inp);
33548c2654abSrjs 		error = sctp_inpcb_bind(so, NULL, l);
33558c2654abSrjs 		if (error) {
33568c2654abSrjs 			SCTP_ASOC_CREATE_UNLOCK(inp);
33578c2654abSrjs 			return (error);
33588c2654abSrjs 		}
33598c2654abSrjs 		SCTP_INP_WLOCK(inp);
33608c2654abSrjs 	}
33618c2654abSrjs #ifdef SCTP_DEBUG
33628c2654abSrjs 	if (sctp_debug_on & SCTP_DEBUG_PCB1) {
33638c2654abSrjs 		printf("After bind\n");
33648c2654abSrjs 	}
33658c2654abSrjs #endif /* SCTP_DEBUG */
33668c2654abSrjs 	/* Now do we connect? */
33678c2654abSrjs 	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
33688c2654abSrjs 	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
33698c2654abSrjs 		/* We are already connected AND the TCP model */
33708c2654abSrjs 		SCTP_INP_WUNLOCK(inp);
33718c2654abSrjs 		SCTP_ASOC_CREATE_UNLOCK(inp);
33728c2654abSrjs 		return (EADDRINUSE);
33738c2654abSrjs 	}
33748c2654abSrjs 	if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
33758c2654abSrjs 		stcb = LIST_FIRST(&inp->sctp_asoc_list);
33768c2654abSrjs 		if (stcb) {
33778c2654abSrjs 			SCTP_TCB_UNLOCK(stcb);
33788c2654abSrjs 		}
33798c2654abSrjs 		SCTP_INP_WUNLOCK(inp);
33808c2654abSrjs 	} else {
33818c2654abSrjs 		SCTP_INP_INCR_REF(inp);
33828c2654abSrjs 		SCTP_INP_WUNLOCK(inp);
33838c2654abSrjs 		stcb = sctp_findassociation_ep_addr(&inp, nam, NULL, NULL, NULL);
33848c2654abSrjs 		if (stcb == NULL) {
33858c2654abSrjs 			SCTP_INP_WLOCK(inp);
33868c2654abSrjs 			SCTP_INP_DECR_REF(inp);
33878c2654abSrjs 			SCTP_INP_WUNLOCK(inp);
33888c2654abSrjs 		}
33898c2654abSrjs 	}
33908c2654abSrjs 	if (stcb != NULL) {
33918c2654abSrjs 		/* Already have or am bring up an association */
33928c2654abSrjs 		SCTP_ASOC_CREATE_UNLOCK(inp);
33938c2654abSrjs 		SCTP_TCB_UNLOCK(stcb);
33948c2654abSrjs 		return (EALREADY);
33958c2654abSrjs 	}
33968c2654abSrjs 	/* We are GOOD to go */
33978c2654abSrjs 	stcb = sctp_aloc_assoc(inp, nam, 1, &error, 0);
33988c2654abSrjs 	if (stcb == NULL) {
33998c2654abSrjs 		/* Gak! no memory */
34008c2654abSrjs 		return (error);
34018c2654abSrjs 	}
34028c2654abSrjs 	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
34038c2654abSrjs 		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
34048c2654abSrjs 		/* Set the connected flag so we can queue data */
34058c2654abSrjs 		soisconnecting(so);
34068c2654abSrjs 	}
34078c2654abSrjs 	stcb->asoc.state = SCTP_STATE_COOKIE_WAIT;
34088c2654abSrjs 	SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
34098c2654abSrjs 	sctp_send_initiate(inp, stcb);
34108c2654abSrjs 	SCTP_ASOC_CREATE_UNLOCK(inp);
34118c2654abSrjs 	SCTP_TCB_UNLOCK(stcb);
34128c2654abSrjs 	return error;
34138c2654abSrjs }
34148c2654abSrjs 
34158c2654abSrjs static int
34168c2654abSrjs sctp_connect2(struct socket *so, struct socket *so2)
34178c2654abSrjs {
34188c2654abSrjs 	KASSERT(solocked(so));
34198c2654abSrjs 
34208c2654abSrjs 	return EOPNOTSUPP;
34218c2654abSrjs }
34228c2654abSrjs 
34238c2654abSrjs int
34248c2654abSrjs sctp_rcvd(struct socket *so, int flags, struct lwp *l)
34258c2654abSrjs {
34268c2654abSrjs 	struct sctp_socket_q_list *sq=NULL;
34278c2654abSrjs 	/*
34288c2654abSrjs 	 * The user has received some data, we may be able to stuff more
34298c2654abSrjs 	 * up the socket. And we need to possibly update the rwnd.
34308c2654abSrjs 	 */
34318c2654abSrjs 	struct sctp_inpcb *inp;
34328c2654abSrjs 	struct sctp_tcb *stcb=NULL;
34338c2654abSrjs 
34348c2654abSrjs 	inp = (struct sctp_inpcb *)so->so_pcb;
34358c2654abSrjs #ifdef SCTP_DEBUG
34368c2654abSrjs 	if (sctp_debug_on & SCTP_DEBUG_USRREQ2)
34378c2654abSrjs 		printf("Read for so:%p inp:%p Flags:%x\n",
34388c2654abSrjs 		       so, inp, flags);
34398c2654abSrjs #endif
34408c2654abSrjs 
34418c2654abSrjs 	if (inp == 0) {
34428c2654abSrjs 		/* I made the same as TCP since we are not setup? */
34438c2654abSrjs #ifdef SCTP_DEBUG
34448c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_USRREQ2)
34458c2654abSrjs 			printf("Nope, connection reset\n");
34468c2654abSrjs #endif
34478c2654abSrjs 		return (ECONNRESET);
34488c2654abSrjs 	}
34498c2654abSrjs 	/*
34508c2654abSrjs 	 * Grab the first one on the list. It will re-insert itself if
34518c2654abSrjs 	 * it runs out of room
34528c2654abSrjs 	 */
34538c2654abSrjs 	SCTP_INP_WLOCK(inp);
34548c2654abSrjs 	if ((flags & MSG_EOR) && ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0)
34558c2654abSrjs 	    && ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) {
34568c2654abSrjs 		/* Ok the other part of our grubby tracking
34578c2654abSrjs 		 * stuff for our horrible layer violation that
34588c2654abSrjs 		 * the tsvwg thinks is ok for sctp_peeloff.. gak!
34598c2654abSrjs 		 * We must update the next vtag pending on the
34608c2654abSrjs 		 * socket buffer (if any).
34618c2654abSrjs 		 */
34628c2654abSrjs 		inp->sctp_vtag_first = sctp_get_first_vtag_from_sb(so);
34638c2654abSrjs 		sq = TAILQ_FIRST(&inp->sctp_queue_list);
34648c2654abSrjs 		if (sq) {
34658c2654abSrjs 			stcb = sq->tcb;
34668c2654abSrjs 		} else {
34678c2654abSrjs 			stcb = NULL;
34688c2654abSrjs 		}
34698c2654abSrjs 	} else {
34708c2654abSrjs 		stcb = LIST_FIRST(&inp->sctp_asoc_list);
34718c2654abSrjs 	}
34728c2654abSrjs 	if (stcb) {
34738c2654abSrjs 		SCTP_TCB_LOCK(stcb);
34748c2654abSrjs 	}
34758c2654abSrjs 	if (stcb) {
34768c2654abSrjs 		long incr;
34778c2654abSrjs 		/* all code in normal stcb path assumes
34788c2654abSrjs 		 * that you have a tcb_lock only. Thus
34798c2654abSrjs 		 * we must release the inp write lock.
34808c2654abSrjs 		 */
34818c2654abSrjs 		if (flags & MSG_EOR) {
34828c2654abSrjs 			if (((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0)
34838c2654abSrjs 			   && ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) {
34848c2654abSrjs 				stcb = sctp_remove_from_socket_q(inp);
34858c2654abSrjs 			}
34868c2654abSrjs #ifdef SCTP_DEBUG
34878c2654abSrjs 			if (sctp_debug_on & SCTP_DEBUG_USRREQ2)
34888c2654abSrjs 				printf("remove from socket queue for inp:%p tcbret:%p\n",
34898c2654abSrjs 				       inp, stcb);
34908c2654abSrjs #endif
34918c2654abSrjs 
34928c2654abSrjs  			stcb->asoc.my_rwnd_control_len = sctp_sbspace_sub(stcb->asoc.my_rwnd_control_len,
34938c2654abSrjs  									  sizeof(struct mbuf));
34948c2654abSrjs 			if (inp->sctp_flags & SCTP_PCB_FLAGS_RECVDATAIOEVNT) {
34958c2654abSrjs  				stcb->asoc.my_rwnd_control_len = sctp_sbspace_sub(stcb->asoc.my_rwnd_control_len,
34968c2654abSrjs  										  CMSG_LEN(sizeof(struct sctp_sndrcvinfo)));
34978c2654abSrjs 			}
34988c2654abSrjs 		}
34998c2654abSrjs 		if ((TAILQ_EMPTY(&stcb->asoc.delivery_queue) == 0) ||
35008c2654abSrjs 		    (TAILQ_EMPTY(&stcb->asoc.reasmqueue) == 0)) {
35018c2654abSrjs 			/* Deliver if there is something to be delivered */
35028c2654abSrjs 			sctp_service_queues(stcb, &stcb->asoc, 1);
35038c2654abSrjs 		}
35048c2654abSrjs 		sctp_set_rwnd(stcb, &stcb->asoc);
35058c2654abSrjs 		/* if we increase by 1 or more MTU's (smallest MTUs of all
35068c2654abSrjs 		 * nets) we send a window update sack
35078c2654abSrjs 		 */
35088c2654abSrjs 		incr = stcb->asoc.my_rwnd - stcb->asoc.my_last_reported_rwnd;
35098c2654abSrjs 		if (incr < 0) {
35108c2654abSrjs 			incr = 0;
35118c2654abSrjs 		}
35128c2654abSrjs 		if (((uint32_t)incr >= (stcb->asoc.smallest_mtu * SCTP_SEG_TO_RWND_UPD)) ||
35138c2654abSrjs 		    ((((uint32_t)incr)*SCTP_SCALE_OF_RWND_TO_UPD) >= so->so_rcv.sb_hiwat)) {
35148c2654abSrjs 			if (callout_pending(&stcb->asoc.dack_timer.timer)) {
35158c2654abSrjs 				/* If the timer is up, stop it */
35168c2654abSrjs 				sctp_timer_stop(SCTP_TIMER_TYPE_RECV,
35178c2654abSrjs 						stcb->sctp_ep, stcb, NULL);
35188c2654abSrjs 			}
35198c2654abSrjs 			/* Send the sack, with the new rwnd */
35208c2654abSrjs 			sctp_send_sack(stcb);
35218c2654abSrjs 			/* Now do the output */
35228c2654abSrjs 			sctp_chunk_output(inp, stcb, 10);
35238c2654abSrjs 		}
35248c2654abSrjs 	} else {
35258c2654abSrjs 		if ((( sq ) && (flags & MSG_EOR) && ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0))
35268c2654abSrjs 		    && ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) {
35278c2654abSrjs 			stcb = sctp_remove_from_socket_q(inp);
35288c2654abSrjs 		}
35298c2654abSrjs 	}
35308c2654abSrjs 	if ((so->so_rcv.sb_mb == NULL) &&
35318c2654abSrjs 	    (TAILQ_EMPTY(&inp->sctp_queue_list) == 0)) {
35328c2654abSrjs 		int sq_cnt=0;
35338c2654abSrjs #ifdef SCTP_DEBUG
35348c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_USRREQ2)
35358c2654abSrjs 			printf("Something off, inp:%p so->so_rcv->sb_mb is empty and sockq is not.. cleaning\n",
35368c2654abSrjs 			       inp);
35378c2654abSrjs #endif
35388c2654abSrjs 		if (((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0)
35398c2654abSrjs 		   && ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) {
35408c2654abSrjs 			int done_yet;
35418c2654abSrjs 			done_yet = TAILQ_EMPTY(&inp->sctp_queue_list);
35428c2654abSrjs 			while (!done_yet) {
35438c2654abSrjs 				sq_cnt++;
35448c2654abSrjs 				(void)sctp_remove_from_socket_q(inp);
35458c2654abSrjs 				done_yet = TAILQ_EMPTY(&inp->sctp_queue_list);
35468c2654abSrjs 			}
35478c2654abSrjs 		}
35488c2654abSrjs #ifdef SCTP_DEBUG
35498c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_USRREQ2)
35508c2654abSrjs 			printf("Cleaned up %d sockq's\n", sq_cnt);
35518c2654abSrjs #endif
35528c2654abSrjs 	}
35538c2654abSrjs 	if (stcb) {
35548c2654abSrjs 		SCTP_TCB_UNLOCK(stcb);
35558c2654abSrjs 	}
35568c2654abSrjs 	SCTP_INP_WUNLOCK(inp);
35578c2654abSrjs 	return (0);
35588c2654abSrjs }
35598c2654abSrjs 
35608c2654abSrjs int
35618c2654abSrjs sctp_listen(struct socket *so, struct lwp *l)
35628c2654abSrjs {
35638c2654abSrjs 	/*
35648c2654abSrjs 	 * Note this module depends on the protocol processing being
35658c2654abSrjs 	 * called AFTER any socket level flags and backlog are applied
35668c2654abSrjs 	 * to the socket. The traditional way that the socket flags are
35678c2654abSrjs 	 * applied is AFTER protocol processing. We have made a change
35688c2654abSrjs 	 * to the sys/kern/uipc_socket.c module to reverse this but this
35698c2654abSrjs 	 * MUST be in place if the socket API for SCTP is to work properly.
35708c2654abSrjs 	 */
35718c2654abSrjs 	int error = 0;
35728c2654abSrjs 	struct sctp_inpcb *inp;
35738c2654abSrjs 
35748c2654abSrjs 	inp = (struct sctp_inpcb *)so->so_pcb;
35758c2654abSrjs 	if (inp == 0) {
35768c2654abSrjs 		/* I made the same as TCP since we are not setup? */
35778c2654abSrjs 		return (ECONNRESET);
35788c2654abSrjs 	}
35798c2654abSrjs 	SCTP_INP_RLOCK(inp);
35808c2654abSrjs 	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
35818c2654abSrjs 	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
35828c2654abSrjs 		/* We are already connected AND the TCP model */
35838c2654abSrjs 		SCTP_INP_RUNLOCK(inp);
35848c2654abSrjs 		return (EADDRINUSE);
35858c2654abSrjs 	}
35868c2654abSrjs 	if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) {
35878c2654abSrjs 		/* We must do a bind. */
35888c2654abSrjs 		SCTP_INP_RUNLOCK(inp);
35898c2654abSrjs 		if ((error = sctp_inpcb_bind(so, NULL, l))) {
35908c2654abSrjs 			/* bind error, probably perm */
35918c2654abSrjs 			return (error);
35928c2654abSrjs 		}
35938c2654abSrjs 	} else {
35948c2654abSrjs 		SCTP_INP_RUNLOCK(inp);
35958c2654abSrjs 	}
35968c2654abSrjs 	SCTP_INP_WLOCK(inp);
35978c2654abSrjs 	if (inp->sctp_socket->so_qlimit) {
35988c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
35998c2654abSrjs 			/*
36008c2654abSrjs 			 * For the UDP model we must TURN OFF the ACCEPT
36018c2654abSrjs 			 * flags since we do NOT allow the accept() call.
36028c2654abSrjs 			 * The TCP model (when present) will do accept which
36038c2654abSrjs 			 * then prohibits connect().
36048c2654abSrjs 			 */
36058c2654abSrjs 			inp->sctp_socket->so_options &= ~SO_ACCEPTCONN;
36068c2654abSrjs 		}
36078c2654abSrjs 		inp->sctp_flags |= SCTP_PCB_FLAGS_ACCEPTING;
36088c2654abSrjs 	} else {
36098c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_ACCEPTING) {
36108c2654abSrjs 			/*
36118c2654abSrjs 			 * Turning off the listen flags if the backlog is
36128c2654abSrjs 			 * set to 0 (i.e. qlimit is 0).
36138c2654abSrjs 			 */
36148c2654abSrjs 			inp->sctp_flags &= ~SCTP_PCB_FLAGS_ACCEPTING;
36158c2654abSrjs 		}
36168c2654abSrjs 		inp->sctp_socket->so_options &= ~SO_ACCEPTCONN;
36178c2654abSrjs 	}
36188c2654abSrjs 	SCTP_INP_WUNLOCK(inp);
36198c2654abSrjs 	return (error);
36208c2654abSrjs }
36218c2654abSrjs 
36228c2654abSrjs int
36238c2654abSrjs sctp_accept(struct socket *so, struct sockaddr *nam)
36248c2654abSrjs {
36258c2654abSrjs 	struct sctp_tcb *stcb;
36268c2654abSrjs 	const struct sockaddr *prim;
36278c2654abSrjs 	struct sctp_inpcb *inp;
36288c2654abSrjs 	int error;
36298c2654abSrjs 
36308c2654abSrjs 	if (nam == NULL) {
36318c2654abSrjs 		return EINVAL;
36328c2654abSrjs 	}
36338c2654abSrjs 	inp = (struct sctp_inpcb *)so->so_pcb;
36348c2654abSrjs 
36358c2654abSrjs 	if (inp == 0) {
36368c2654abSrjs 		return ECONNRESET;
36378c2654abSrjs 	}
36388c2654abSrjs 	SCTP_INP_RLOCK(inp);
36398c2654abSrjs 	if (so->so_state & SS_ISDISCONNECTED) {
36408c2654abSrjs 		SCTP_INP_RUNLOCK(inp);
36418c2654abSrjs 		return ECONNABORTED;
36428c2654abSrjs 	}
36438c2654abSrjs 	stcb = LIST_FIRST(&inp->sctp_asoc_list);
36448c2654abSrjs 	if (stcb == NULL) {
36458c2654abSrjs 		SCTP_INP_RUNLOCK(inp);
36468c2654abSrjs 		return ECONNRESET;
36478c2654abSrjs 	}
36488c2654abSrjs 	SCTP_TCB_LOCK(stcb);
36498c2654abSrjs 	SCTP_INP_RUNLOCK(inp);
36508c2654abSrjs 	prim = (const struct sockaddr *)rtcache_getdst(&stcb->asoc.primary_destination->ro);
36518c2654abSrjs 	if (prim->sa_family == AF_INET) {
36528c2654abSrjs 		struct sockaddr_in *sin;
36538c2654abSrjs 
36548c2654abSrjs 		sin = (struct sockaddr_in *)nam;
36558c2654abSrjs 		memset((void *)sin, 0, sizeof (*sin));
36568c2654abSrjs 
36578c2654abSrjs 		sin->sin_family = AF_INET;
36588c2654abSrjs 		sin->sin_len = sizeof(*sin);
36598c2654abSrjs 		sin->sin_port = ((const struct sockaddr_in *)prim)->sin_port;
36608c2654abSrjs 		sin->sin_addr = ((const struct sockaddr_in *)prim)->sin_addr;
36618c2654abSrjs 	} else {
36628c2654abSrjs 		struct sockaddr_in6 *sin6;
36638c2654abSrjs 
36648c2654abSrjs 		sin6 = (struct sockaddr_in6 *)nam;
36658c2654abSrjs 		memset((void *)sin6, 0, sizeof (*sin6));
36668c2654abSrjs 		sin6->sin6_family = AF_INET6;
36678c2654abSrjs 		sin6->sin6_len = sizeof(*sin6);
36688c2654abSrjs 		sin6->sin6_port = ((const struct sockaddr_in6 *)prim)->sin6_port;
36698c2654abSrjs 
36708c2654abSrjs 		sin6->sin6_addr = ((const struct sockaddr_in6 *)prim)->sin6_addr;
36718c2654abSrjs 		if ((error = sa6_recoverscope(sin6)) != 0)
36728c2654abSrjs 			return error;
36738c2654abSrjs 
36748c2654abSrjs 	}
36758c2654abSrjs 	/* Wake any delayed sleep action */
36768c2654abSrjs 	SCTP_TCB_UNLOCK(stcb);
36778c2654abSrjs 	SCTP_INP_WLOCK(inp);
36788c2654abSrjs 	if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) {
36798c2654abSrjs 		inp->sctp_flags &= ~SCTP_PCB_FLAGS_DONT_WAKE;
36808c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT) {
36818c2654abSrjs 			inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEOUTPUT;
36828c2654abSrjs 			if (sowritable(inp->sctp_socket))
36838c2654abSrjs 				sowwakeup(inp->sctp_socket);
36848c2654abSrjs 		}
36858c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT) {
36868c2654abSrjs 			inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEINPUT;
36878c2654abSrjs 			if (soreadable(inp->sctp_socket))
36888c2654abSrjs 				sorwakeup(inp->sctp_socket);
36898c2654abSrjs 		}
36908c2654abSrjs 
36918c2654abSrjs 	}
36928c2654abSrjs 	SCTP_INP_WUNLOCK(inp);
36938c2654abSrjs 	return 0;
36948c2654abSrjs }
36958c2654abSrjs 
36968c2654abSrjs static int
36978c2654abSrjs sctp_stat(struct socket *so, struct stat *ub)
36988c2654abSrjs {
36998c2654abSrjs 	return 0;
37008c2654abSrjs }
37018c2654abSrjs 
37028c2654abSrjs int
37038c2654abSrjs sctp_sockaddr(struct socket *so, struct sockaddr *nam)
37048c2654abSrjs {
37058c2654abSrjs 	struct sockaddr_in *sin = (struct sockaddr_in *)nam;
37068c2654abSrjs 	struct sctp_inpcb *inp;
37078c2654abSrjs 
37088c2654abSrjs 	memset(sin, 0, sizeof(*sin));
37098c2654abSrjs 	sin->sin_family = AF_INET;
37108c2654abSrjs 	sin->sin_len = sizeof(*sin);
37118c2654abSrjs 	inp = (struct sctp_inpcb *)so->so_pcb;
37128c2654abSrjs 	if (!inp) {
37138c2654abSrjs 		return ECONNRESET;
37148c2654abSrjs 	}
37158c2654abSrjs 	SCTP_INP_RLOCK(inp);
37168c2654abSrjs 	sin->sin_port = inp->sctp_lport;
37178c2654abSrjs 	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
37188c2654abSrjs 		if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
37198c2654abSrjs 			struct sctp_tcb *stcb;
37208c2654abSrjs 			const struct sockaddr_in *sin_a;
37218c2654abSrjs 			struct sctp_nets *net;
37228c2654abSrjs 			int fnd;
37238c2654abSrjs 
37248c2654abSrjs 			stcb = LIST_FIRST(&inp->sctp_asoc_list);
37258c2654abSrjs 			if (stcb == NULL) {
37268c2654abSrjs 				goto notConn;
37278c2654abSrjs 			}
37288c2654abSrjs 			fnd = 0;
37298c2654abSrjs 			sin_a = NULL;
37308c2654abSrjs 			SCTP_TCB_LOCK(stcb);
37318c2654abSrjs 			TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
37328c2654abSrjs 				sin_a = (const struct sockaddr_in *)rtcache_getdst(&net->ro);
37338c2654abSrjs 				if (sin_a->sin_family == AF_INET) {
37348c2654abSrjs 					fnd = 1;
37358c2654abSrjs 					break;
37368c2654abSrjs 				}
37378c2654abSrjs 			}
37388c2654abSrjs 			if ((!fnd) || (sin_a == NULL)) {
37398c2654abSrjs 				/* punt */
37408c2654abSrjs 				SCTP_TCB_UNLOCK(stcb);
37418c2654abSrjs 				goto notConn;
37428c2654abSrjs 			}
37438c2654abSrjs 			sin->sin_addr = sctp_ipv4_source_address_selection(inp,
37448c2654abSrjs 			    stcb, (struct route *)&net->ro, net, 0);
37458c2654abSrjs 			SCTP_TCB_UNLOCK(stcb);
37468c2654abSrjs 		} else {
37478c2654abSrjs 			/* For the bound all case you get back 0 */
37488c2654abSrjs 		notConn:
37498c2654abSrjs 			sin->sin_addr.s_addr = 0;
37508c2654abSrjs 		}
37518c2654abSrjs 
37528c2654abSrjs 	} else {
37538c2654abSrjs 		/* Take the first IPv4 address in the list */
37548c2654abSrjs 		struct sctp_laddr *laddr;
37558c2654abSrjs 		int fnd = 0;
37568c2654abSrjs 		LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
37578c2654abSrjs 			if (laddr->ifa->ifa_addr->sa_family == AF_INET) {
37588c2654abSrjs 				struct sockaddr_in *sin_a;
37598c2654abSrjs 				sin_a = (struct sockaddr_in *)laddr->ifa->ifa_addr;
37608c2654abSrjs 				sin->sin_addr = sin_a->sin_addr;
37618c2654abSrjs 				fnd = 1;
37628c2654abSrjs 				break;
37638c2654abSrjs 			}
37648c2654abSrjs 		}
37658c2654abSrjs 		if (!fnd) {
37668c2654abSrjs 			SCTP_INP_RUNLOCK(inp);
37678c2654abSrjs 			return ENOENT;
37688c2654abSrjs 		}
37698c2654abSrjs 	}
37708c2654abSrjs 	SCTP_INP_RUNLOCK(inp);
37718c2654abSrjs 	return (0);
37728c2654abSrjs }
37738c2654abSrjs 
37748c2654abSrjs int
37758c2654abSrjs sctp_peeraddr(struct socket *so, struct sockaddr *nam)
37768c2654abSrjs {
37778c2654abSrjs 	struct sockaddr_in *sin = (struct sockaddr_in *)nam;
37788c2654abSrjs 	int fnd;
37798c2654abSrjs 	const struct sockaddr_in *sin_a;
37808c2654abSrjs 	struct sctp_inpcb *inp;
37818c2654abSrjs 	struct sctp_tcb *stcb;
37828c2654abSrjs 	struct sctp_nets *net;
37838c2654abSrjs 
37848c2654abSrjs 	/* Do the malloc first in case it blocks. */
37858c2654abSrjs 	inp = (struct sctp_inpcb *)so->so_pcb;
37868c2654abSrjs 	if ((inp == NULL) ||
37878c2654abSrjs 	    ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) {
37888c2654abSrjs 		/* UDP type and listeners will drop out here */
37898c2654abSrjs 		return (ENOTCONN);
37908c2654abSrjs 	}
37918c2654abSrjs 
37928c2654abSrjs 	memset(sin, 0, sizeof(*sin));
37938c2654abSrjs 	sin->sin_family = AF_INET;
37948c2654abSrjs 	sin->sin_len = sizeof(*sin);
37958c2654abSrjs 
37968c2654abSrjs 	/* We must recapture incase we blocked */
37978c2654abSrjs 	inp = (struct sctp_inpcb *)so->so_pcb;
37988c2654abSrjs 	if (!inp) {
37998c2654abSrjs 		return ECONNRESET;
38008c2654abSrjs 	}
38018c2654abSrjs 	SCTP_INP_RLOCK(inp);
38028c2654abSrjs 	stcb = LIST_FIRST(&inp->sctp_asoc_list);
38038c2654abSrjs 	if (stcb) {
38048c2654abSrjs 		SCTP_TCB_LOCK(stcb);
38058c2654abSrjs 	}
38068c2654abSrjs 	SCTP_INP_RUNLOCK(inp);
38078c2654abSrjs 	if (stcb == NULL) {
38088c2654abSrjs 		return ECONNRESET;
38098c2654abSrjs 	}
38108c2654abSrjs 	fnd = 0;
38118c2654abSrjs 	TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
38128c2654abSrjs 		sin_a = (const struct sockaddr_in *)rtcache_getdst(&net->ro);
38138c2654abSrjs 		if (sin_a->sin_family == AF_INET) {
38148c2654abSrjs 			fnd = 1;
38158c2654abSrjs 			sin->sin_port = stcb->rport;
38168c2654abSrjs 			sin->sin_addr = sin_a->sin_addr;
38178c2654abSrjs 			break;
38188c2654abSrjs 		}
38198c2654abSrjs 	}
38208c2654abSrjs 	SCTP_TCB_UNLOCK(stcb);
38218c2654abSrjs 	if (!fnd) {
38228c2654abSrjs 		/* No IPv4 address */
38238c2654abSrjs 		return ENOENT;
38248c2654abSrjs 	}
38258c2654abSrjs 	return (0);
38268c2654abSrjs }
38278c2654abSrjs 
38288c2654abSrjs static int
38298c2654abSrjs sctp_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control)
38308c2654abSrjs {
38318c2654abSrjs 	KASSERT(solocked(so));
38328c2654abSrjs 
38338c2654abSrjs 	m_freem(m);
38348c2654abSrjs 	m_freem(control);
38358c2654abSrjs 
38368c2654abSrjs 	return EOPNOTSUPP;
38378c2654abSrjs }
38388c2654abSrjs 
38398c2654abSrjs static int
38408c2654abSrjs sctp_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp)
38418c2654abSrjs {
38428c2654abSrjs 	int error = 0;
38438c2654abSrjs 	int family;
38448c2654abSrjs 
38453917a6f0Srjs 	if (cmd == SIOCCONNECTX) {
38463917a6f0Srjs 		solock(so);
38473917a6f0Srjs 		error = sctp_do_connect_x(so, nam, curlwp, 0);
38483917a6f0Srjs 		sounlock(so);
38493917a6f0Srjs 	} else if (cmd == SIOCCONNECTXDEL) {
38503917a6f0Srjs 		solock(so);
38513917a6f0Srjs 		error = sctp_do_connect_x(so, nam, curlwp, 1);
38523917a6f0Srjs 		sounlock(so);
38533917a6f0Srjs 	} else {
38548c2654abSrjs 		family = so->so_proto->pr_domain->dom_family;
38558c2654abSrjs 		switch (family) {
38568c2654abSrjs #ifdef INET
38578c2654abSrjs 		case PF_INET:
38588c2654abSrjs 			error = in_control(so, cmd, nam, ifp);
38598c2654abSrjs 			break;
38608c2654abSrjs #endif
38618c2654abSrjs #ifdef INET6
38628c2654abSrjs 		case PF_INET6:
38638c2654abSrjs 			error = in6_control(so, cmd, nam, ifp);
38648c2654abSrjs 			break;
38658c2654abSrjs #endif
38668c2654abSrjs 		default:
38678c2654abSrjs 			error =  EAFNOSUPPORT;
38688c2654abSrjs 		}
38693917a6f0Srjs 	}
38708c2654abSrjs 	return (error);
38718c2654abSrjs }
38728c2654abSrjs 
38738c2654abSrjs static int
38748c2654abSrjs sctp_purgeif(struct socket *so, struct ifnet *ifp)
38758c2654abSrjs {
38768c2654abSrjs 	struct ifaddr *ifa;
38779e4c2bdaSozaki-r 	IFADDR_READER_FOREACH(ifa, ifp) {
38788c2654abSrjs 		if (ifa->ifa_addr->sa_family == PF_INET) {
38798c2654abSrjs 			sctp_delete_ip_address(ifa);
38808c2654abSrjs 		}
38818c2654abSrjs 	}
38828c2654abSrjs 
38838c2654abSrjs 	mutex_enter(softnet_lock);
38848c2654abSrjs 	in_purgeif(ifp);
38858c2654abSrjs 	mutex_exit(softnet_lock);
38868c2654abSrjs 
38878c2654abSrjs 	return 0;
38888c2654abSrjs }
38898c2654abSrjs 
38908c2654abSrjs /*
38918c2654abSrjs  * Sysctl for sctp variables.
38928c2654abSrjs  */
3893ad7c6453Srjs static void
3894ad7c6453Srjs sysctl_net_inet_sctp_setup(struct sysctllog **clog)
38958c2654abSrjs {
38968c2654abSrjs 
38978c2654abSrjs 	sysctl_createv(clog, 0, NULL, NULL,
38988c2654abSrjs 		       CTLFLAG_PERMANENT,
38998c2654abSrjs 	               CTLTYPE_NODE, "net", NULL,
39008c2654abSrjs                        NULL, 0, NULL, 0,
39018c2654abSrjs                        CTL_NET, CTL_EOL);
39028c2654abSrjs         sysctl_createv(clog, 0, NULL, NULL,
39038c2654abSrjs                        CTLFLAG_PERMANENT,
39048c2654abSrjs                        CTLTYPE_NODE, "inet", NULL,
39058c2654abSrjs                        NULL, 0, NULL, 0,
39068c2654abSrjs                        CTL_NET, PF_INET, CTL_EOL);
39078c2654abSrjs         sysctl_createv(clog, 0, NULL, NULL,
39088c2654abSrjs                        CTLFLAG_PERMANENT,
39098c2654abSrjs                        CTLTYPE_NODE, "sctp",
39108c2654abSrjs                        SYSCTL_DESCR("sctp related settings"),
39118c2654abSrjs                        NULL, 0, NULL, 0,
39128c2654abSrjs                        CTL_NET, PF_INET, IPPROTO_SCTP, CTL_EOL);
39138c2654abSrjs 
39148c2654abSrjs        sysctl_createv(clog, 0, NULL, NULL,
39158c2654abSrjs                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
39168c2654abSrjs                        CTLTYPE_INT, "maxdgram",
39178c2654abSrjs                        SYSCTL_DESCR("Maximum outgoing SCTP buffer size"),
39188c2654abSrjs                        NULL, 0, &sctp_sendspace, 0,
39198c2654abSrjs                        CTL_NET, PF_INET, IPPROTO_SCTP, SCTPCTL_MAXDGRAM,
39208c2654abSrjs                        CTL_EOL);
39218c2654abSrjs 
39228c2654abSrjs        sysctl_createv(clog, 0, NULL, NULL,
39238c2654abSrjs                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
39248c2654abSrjs                        CTLTYPE_INT, "recvspace",
39258c2654abSrjs                        SYSCTL_DESCR("Maximum incoming SCTP buffer size"),
39268c2654abSrjs                        NULL, 0, &sctp_recvspace, 0,
39278c2654abSrjs                        CTL_NET, PF_INET, IPPROTO_SCTP, SCTPCTL_RECVSPACE,
39288c2654abSrjs                        CTL_EOL);
39298c2654abSrjs 
39308c2654abSrjs        sysctl_createv(clog, 0, NULL, NULL,
39318c2654abSrjs                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
3932ad7c6453Srjs                        CTLTYPE_INT, "auto_asconf",
39338c2654abSrjs                        SYSCTL_DESCR("Enable SCTP Auto-ASCONF"),
39348c2654abSrjs                        NULL, 0, &sctp_auto_asconf, 0,
39358c2654abSrjs                        CTL_NET, PF_INET, IPPROTO_SCTP, SCTPCTL_AUTOASCONF,
39368c2654abSrjs                        CTL_EOL);
39378c2654abSrjs 
39388c2654abSrjs        sysctl_createv(clog, 0, NULL, NULL,
39398c2654abSrjs                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
39408c2654abSrjs                        CTLTYPE_INT, "ecn_enable",
39418c2654abSrjs                        SYSCTL_DESCR("Enable SCTP ECN"),
39428c2654abSrjs                        NULL, 0, &sctp_ecn, 0,
39438c2654abSrjs                        CTL_NET, PF_INET, IPPROTO_SCTP, SCTPCTL_ECN_ENABLE,
39448c2654abSrjs                        CTL_EOL);
39458c2654abSrjs 
39468c2654abSrjs        sysctl_createv(clog, 0, NULL, NULL,
39478c2654abSrjs                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
39488c2654abSrjs                        CTLTYPE_INT, "ecn_nonce",
39498c2654abSrjs                        SYSCTL_DESCR("Enable SCTP ECN Nonce"),
39508c2654abSrjs                        NULL, 0, &sctp_ecn_nonce, 0,
39518c2654abSrjs                        CTL_NET, PF_INET, IPPROTO_SCTP, SCTPCTL_ECN_NONCE,
39528c2654abSrjs                        CTL_EOL);
39538c2654abSrjs 
39548c2654abSrjs        sysctl_createv(clog, 0, NULL, NULL,
39558c2654abSrjs                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
39568c2654abSrjs                        CTLTYPE_INT, "strict_sack",
39578c2654abSrjs                        SYSCTL_DESCR("Enable SCTP Strict SACK checking"),
39588c2654abSrjs                        NULL, 0, &sctp_strict_sacks, 0,
39598c2654abSrjs                        CTL_NET, PF_INET, IPPROTO_SCTP, SCTPCTL_STRICT_SACK,
39608c2654abSrjs                        CTL_EOL);
39618c2654abSrjs 
39628c2654abSrjs        sysctl_createv(clog, 0, NULL, NULL,
39638c2654abSrjs                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
39648c2654abSrjs                        CTLTYPE_INT, "loopback_nocsum",
39658c2654abSrjs                        SYSCTL_DESCR("Enable NO Csum on packets sent on loopback"),
39668c2654abSrjs                        NULL, 0, &sctp_no_csum_on_loopback, 0,
39678c2654abSrjs                        CTL_NET, PF_INET, IPPROTO_SCTP, SCTPCTL_NOCSUM_LO,
39688c2654abSrjs                        CTL_EOL);
39698c2654abSrjs 
39708c2654abSrjs        sysctl_createv(clog, 0, NULL, NULL,
39718c2654abSrjs                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
39728c2654abSrjs                        CTLTYPE_INT, "strict_init",
39738c2654abSrjs                        SYSCTL_DESCR("Enable strict INIT/INIT-ACK singleton enforcement"),
39748c2654abSrjs                        NULL, 0, &sctp_strict_init, 0,
39758c2654abSrjs                        CTL_NET, PF_INET, IPPROTO_SCTP, SCTPCTL_STRICT_INIT,
39768c2654abSrjs                        CTL_EOL);
39778c2654abSrjs 
39788c2654abSrjs        sysctl_createv(clog, 0, NULL, NULL,
39798c2654abSrjs                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
39808c2654abSrjs                        CTLTYPE_INT, "peer_chkoh",
39818c2654abSrjs                        SYSCTL_DESCR("Amount to debit peers rwnd per chunk sent"),
39828c2654abSrjs                        NULL, 0, &sctp_peer_chunk_oh, 0,
39838c2654abSrjs                        CTL_NET, PF_INET, IPPROTO_SCTP, SCTPCTL_PEER_CHK_OH,
39848c2654abSrjs                        CTL_EOL);
39858c2654abSrjs 
39868c2654abSrjs        sysctl_createv(clog, 0, NULL, NULL,
39878c2654abSrjs                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
39888c2654abSrjs                        CTLTYPE_INT, "maxburst",
39898c2654abSrjs                        SYSCTL_DESCR("Default max burst for sctp endpoints"),
39908c2654abSrjs                        NULL, 0, &sctp_max_burst_default, 0,
39918c2654abSrjs                        CTL_NET, PF_INET, IPPROTO_SCTP, SCTPCTL_MAXBURST,
39928c2654abSrjs                        CTL_EOL);
39938c2654abSrjs 
39948c2654abSrjs        sysctl_createv(clog, 0, NULL, NULL,
39958c2654abSrjs                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
39968c2654abSrjs                        CTLTYPE_INT, "maxchunks",
39978c2654abSrjs                        SYSCTL_DESCR("Default max chunks on queue per asoc"),
39988c2654abSrjs                        NULL, 0, &sctp_max_chunks_on_queue, 0,
39998c2654abSrjs                        CTL_NET, PF_INET, IPPROTO_SCTP, SCTPCTL_MAXCHUNKONQ,
40008c2654abSrjs                        CTL_EOL);
40018c2654abSrjs #ifdef SCTP_DEBUG
40028c2654abSrjs        sysctl_createv(clog, 0, NULL, NULL,
40038c2654abSrjs                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
40048c2654abSrjs                        CTLTYPE_INT, "debug",
40058c2654abSrjs                        SYSCTL_DESCR("Configure debug output"),
40068c2654abSrjs                        NULL, 0, &sctp_debug_on, 0,
40078c2654abSrjs                        CTL_NET, PF_INET, IPPROTO_SCTP, SCTPCTL_DEBUG,
40088c2654abSrjs                        CTL_EOL);
40098c2654abSrjs #endif
40108c2654abSrjs }
40118c2654abSrjs 
40128c2654abSrjs PR_WRAP_USRREQS(sctp)
40138c2654abSrjs #define	sctp_attach	sctp_attach_wrapper
40148c2654abSrjs #define	sctp_detach	sctp_detach_wrapper
40158c2654abSrjs #define sctp_accept	sctp_accept_wrapper
40168c2654abSrjs #define sctp_bind	sctp_bind_wrapper
40178c2654abSrjs #define sctp_listen	sctp_listen_wrapper
40188c2654abSrjs #define sctp_connect	sctp_connect_wrapper
40198c2654abSrjs #define sctp_connect2	sctp_connect2_wrapper
40208c2654abSrjs #define sctp_disconnect	sctp_disconnect_wrapper
40218c2654abSrjs #define sctp_shutdown	sctp_shutdown_wrapper
40228c2654abSrjs #define sctp_abort	sctp_abort_wrapper
40238c2654abSrjs #define	sctp_ioctl	sctp_ioctl_wrapper
40248c2654abSrjs #define	sctp_stat	sctp_stat_wrapper
40258c2654abSrjs #define sctp_peeraddr	sctp_peeraddr_wrapper
40268c2654abSrjs #define sctp_sockaddr	sctp_sockaddr_wrapper
40278c2654abSrjs #define sctp_rcvd	sctp_rcvd_wrapper
40288c2654abSrjs #define sctp_recvoob	sctp_recvoob_wrapper
40298c2654abSrjs #define sctp_send	sctp_send_wrapper
40308c2654abSrjs #define sctp_sendoob	sctp_sendoob_wrapper
40318c2654abSrjs #define sctp_purgeif	sctp_purgeif_wrapper
40328c2654abSrjs 
40338c2654abSrjs const struct pr_usrreqs sctp_usrreqs = {
40348c2654abSrjs 	.pr_attach	= sctp_attach,
40358c2654abSrjs 	.pr_detach	= sctp_detach,
40368c2654abSrjs 	.pr_accept	= sctp_accept,
40378c2654abSrjs 	.pr_bind	= sctp_bind,
40388c2654abSrjs 	.pr_listen	= sctp_listen,
40398c2654abSrjs 	.pr_connect	= sctp_connect,
40408c2654abSrjs 	.pr_connect2	= sctp_connect2,
40418c2654abSrjs 	.pr_disconnect	= sctp_disconnect,
40428c2654abSrjs 	.pr_shutdown	= sctp_shutdown,
40438c2654abSrjs 	.pr_abort	= sctp_abort,
40448c2654abSrjs 	.pr_ioctl	= sctp_ioctl,
40458c2654abSrjs 	.pr_stat	= sctp_stat,
40468c2654abSrjs 	.pr_peeraddr	= sctp_peeraddr,
40478c2654abSrjs 	.pr_sockaddr	= sctp_sockaddr,
40488c2654abSrjs 	.pr_rcvd	= sctp_rcvd,
40498c2654abSrjs 	.pr_recvoob	= sctp_recvoob,
40508c2654abSrjs 	.pr_send	= sctp_send,
40518c2654abSrjs 	.pr_sendoob	= sctp_sendoob,
40528c2654abSrjs 	.pr_purgeif	= sctp_purgeif,
40538c2654abSrjs };
4054